[gtk+/touch-for-3.4: 7/65] scrolledwindow: Allow selections and DND when kinetic scrolling is on
- From: Matthias Clasen <matthiasc src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk+/touch-for-3.4: 7/65] scrolledwindow: Allow selections and DND when kinetic scrolling is on
- Date: Fri, 24 Feb 2012 15:25:26 +0000 (UTC)
commit f6600be5591a05e5670eb31f17ab3bf103879f49
Author: Matthias Clasen <mclasen redhat com>
Date: Thu Feb 23 17:09:47 2012 -0500
scrolledwindow: Allow selections and DND when kinetic scrolling is on
If the scrolling doesn't start after a long press, the scrolling is
cancelled and events are handled by child widgets normally.
gtk/gtkscrolledwindow.c | 142 +++++++++++++++++++++++++++++++++++++++++-----
1 files changed, 126 insertions(+), 16 deletions(-)
---
diff --git a/gtk/gtkscrolledwindow.c b/gtk/gtkscrolledwindow.c
index 5323576..19f44ef 100644
--- a/gtk/gtkscrolledwindow.c
+++ b/gtk/gtkscrolledwindow.c
@@ -130,6 +130,7 @@
#define FRAME_INTERVAL(fps) (1000. / fps)
#define INTERPOLATION_DURATION 250
#define INTERPOLATION_DURATION_OVERSHOOT(overshoot) (overshoot > 0.0 ? INTERPOLATION_DURATION : 10)
+#define RELEASE_EVENT_TIMEOUT 1000
typedef struct
{
@@ -172,6 +173,7 @@ struct _GtkScrolledWindowPrivate
guint button_press_id;
guint motion_notify_id;
guint button_release_id;
+ guint release_timeout_id;
MotionEventList motion_events;
GtkTimeline *deceleration_timeline;
gdouble dx;
@@ -1097,9 +1099,9 @@ gtk_scrolled_window_set_kinetic_scrolling (GtkScrolledWindow *scrolled_window,
{
motion_event_list_init (&priv->motion_events, 3);
priv->button_press_id =
- g_signal_connect (scrolled_window, "captured_event",
- G_CALLBACK (gtk_scrolled_window_button_press_event),
- NULL);
+ g_signal_connect (scrolled_window, "captured-event",
+ G_CALLBACK (gtk_scrolled_window_button_press_event),
+ NULL);
}
else
{
@@ -1133,6 +1135,11 @@ gtk_scrolled_window_set_kinetic_scrolling (GtkScrolledWindow *scrolled_window,
g_signal_handler_disconnect (scrolled_window, priv->button_release_id);
priv->button_release_id = 0;
}
+ if (priv->release_timeout_id)
+ {
+ g_source_remove (priv->release_timeout_id);
+ priv->release_timeout_id = 0;
+ }
motion_event_list_clear (&priv->motion_events);
}
g_object_notify (G_OBJECT (scrolled_window), "kinetic-scrolling");
@@ -1202,6 +1209,18 @@ gtk_scrolled_window_destroy (GtkWidget *widget)
g_signal_handler_disconnect (widget, priv->button_release_id);
priv->button_release_id = 0;
}
+ if (priv->release_timeout_id)
+ {
+ g_source_remove (priv->release_timeout_id);
+ priv->release_timeout_id = 0;
+ }
+
+ if (priv->button_press_event)
+ {
+ gdk_event_free (priv->button_press_event);
+ priv->button_press_event = NULL;
+ }
+
motion_event_list_clear (&priv->motion_events);
GTK_WIDGET_CLASS (gtk_scrolled_window_parent_class)->destroy (widget);
@@ -2606,6 +2625,49 @@ gtk_scrolled_window_start_deceleration (GtkScrolledWindow *scrolled_window,
}
static gboolean
+gtk_scrolled_window_release_captured_events (GtkScrolledWindow *scrolled_window)
+{
+ GtkScrolledWindowPrivate *priv = scrolled_window->priv;
+ GdkDevice *device;
+
+ /* Cancel the scrolling and send the button press
+ * event to the child widget
+ */
+ if (!priv->button_press_event)
+ return FALSE;
+
+ device = gdk_event_get_device (priv->button_press_event);
+ gdk_device_ungrab (device, GDK_CURRENT_TIME);
+ gtk_device_grab_remove (GTK_WIDGET (scrolled_window), device);
+
+ if (priv->motion_notify_id > 0)
+ {
+ g_signal_handler_disconnect (scrolled_window, priv->motion_notify_id);
+ priv->motion_notify_id = 0;
+ }
+ if (priv->button_release_id > 0)
+ {
+ g_signal_handler_disconnect (scrolled_window, priv->button_release_id);
+ priv->button_release_id = 0;
+ }
+
+ /* We are going to synthesize the button press event so that
+ * it can be handled by child widget, but we don't want to
+ * handle it, so block both button-press and and press-and-hold
+ * during this button press
+ */
+ g_signal_handler_block (scrolled_window, priv->button_press_id);
+
+ gtk_main_do_event (priv->button_press_event);
+
+ g_signal_handler_unblock (scrolled_window, priv->button_press_id);
+ gdk_event_free (priv->button_press_event);
+ priv->button_press_event = NULL;
+
+ return FALSE;
+}
+
+static gboolean
gtk_scrolled_window_button_release_event (GtkWidget *widget,
GdkEvent *_event)
{
@@ -2623,6 +2685,10 @@ gtk_scrolled_window_button_release_event (GtkWidget *widget,
if (event->button != 1)
return FALSE;
+ child = gtk_bin_get_child (GTK_BIN (widget));
+ if (!child)
+ return FALSE;
+
gdk_device_ungrab (gdk_event_get_device (_event), event->time);
if (priv->motion_notify_id > 0)
@@ -2635,13 +2701,38 @@ gtk_scrolled_window_button_release_event (GtkWidget *widget,
g_signal_handler_disconnect (widget, priv->button_release_id);
priv->button_release_id = 0;
}
+ if (priv->release_timeout_id)
+ {
+ g_source_remove (priv->release_timeout_id);
+ priv->release_timeout_id = 0;
+ }
if (!priv->in_drag)
- return FALSE;
+ {
+ /* There hasn't been scrolling at all, so just let the
+ * child widget handle the events normally
+ */
+ if (priv->button_press_event)
+ {
+ g_signal_handler_block (widget, priv->button_press_id);
+ gtk_main_do_event (priv->button_press_event);
+ g_signal_handler_unblock (widget, priv->button_press_id);
+ gdk_event_free (priv->button_press_event);
+ priv->button_press_event = NULL;
+ gtk_main_do_event (_event);
+
+ return TRUE;
+ }
- child = gtk_bin_get_child (GTK_BIN (widget));
- if (!child)
- return FALSE;
+ return FALSE;
+ }
+ priv->in_drag = FALSE;
+
+ if (priv->button_press_event)
+ {
+ gdk_event_free (priv->button_press_event);
+ priv->button_press_event = NULL;
+ }
distance =
gtk_scrolled_window_get_deceleration_distance (scrolled_window,
@@ -2685,11 +2776,24 @@ gtk_scrolled_window_motion_notify_event (GtkWidget *widget,
{
motion = motion_event_list_first (&priv->motion_events);
if (gtk_drag_check_threshold (widget, motion->x, motion->y, event->x_root, event->y_root))
- priv->in_drag = TRUE;
+ {
+ if (priv->release_timeout_id)
+ {
+ g_source_remove (priv->release_timeout_id);
+ priv->release_timeout_id = 0;
+ }
+ priv->in_drag = TRUE;
+ }
else
return TRUE;
}
+ if (priv->button_press_event)
+ {
+ gdk_event_free (priv->button_press_event);
+ priv->button_press_event = NULL;
+ }
+
motion = motion_event_list_last (&priv->motion_events);
if (motion)
@@ -2714,7 +2818,7 @@ gtk_scrolled_window_motion_notify_event (GtkWidget *widget,
motion->y = event->y_root;
motion->time = event->time;
- return TRUE;
+ return FALSE;
}
static gboolean
@@ -2780,17 +2884,23 @@ gtk_scrolled_window_button_press_event (GtkWidget *widget,
}
priv->motion_notify_id =
- g_signal_connect (widget, "captured-event",
- G_CALLBACK (gtk_scrolled_window_motion_notify_event),
- NULL);
+ g_signal_connect (widget, "captured-event",
+ G_CALLBACK (gtk_scrolled_window_motion_notify_event),
+ NULL);
priv->button_release_id =
- g_signal_connect (widget, "captured-event",
- G_CALLBACK (gtk_scrolled_window_button_release_event),
- NULL);
+ g_signal_connect (widget, "captured-event",
+ G_CALLBACK (gtk_scrolled_window_button_release_event),
+ NULL);
+ priv->release_timeout_id =
+ gdk_threads_add_timeout (RELEASE_EVENT_TIMEOUT,
+ (GSourceFunc) gtk_scrolled_window_release_captured_events,
+ scrolled_window);
priv->in_drag = FALSE;
- return FALSE;
+ priv->button_press_event = gdk_event_copy (_event);
+
+ return TRUE;
}
static gboolean
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]