From 903fe8e89211a3509b38321fddfbe42e06c2e98c Mon Sep 17 00:00:00 2001 From: Carlos Garnacho Date: Mon, 5 Dec 2011 00:17:58 +0100 Subject: [PATCH] scrolledwindow: Grab only after starting drag This is so the grab doesn't break the implicit grab on the child widget's window, which avoids that the button press and release are possibly sent to different windows, and after the grab was actually broken. --- gtk/gtkscrolledwindow.c | 65 +++++++++++++++++++++++++++++++---------- 1 file changed, 49 insertions(+), 16 deletions(-) diff --git a/gtk/gtkscrolledwindow.c b/gtk/gtkscrolledwindow.c index ab36beecf6..bd57ecb0a0 100644 --- a/gtk/gtkscrolledwindow.c +++ b/gtk/gtkscrolledwindow.c @@ -154,6 +154,7 @@ struct _GtkScrolledWindowPrivate /* Kinetic scrolling */ GdkEvent *button_press_event; GdkWindow *overshoot_window; + GdkDevice *drag_device; guint kinetic_scrolling_enabled : 1; guint in_drag : 1; guint last_button_event_valid : 1; @@ -275,6 +276,8 @@ static void gtk_scrolled_window_realize (GtkWidget *wid static void gtk_scrolled_window_unrealize (GtkWidget *widget); static void gtk_scrolled_window_map (GtkWidget *widget); static void gtk_scrolled_window_unmap (GtkWidget *widget); +static void gtk_scrolled_window_grab_notify (GtkWidget *widget, + gboolean was_grabbed); static gboolean _gtk_scrolled_window_set_adjustment_value (GtkScrolledWindow *scrolled_window, GtkAdjustment *adjustment, @@ -347,6 +350,7 @@ gtk_scrolled_window_class_init (GtkScrolledWindowClass *class) widget_class->unrealize = gtk_scrolled_window_unrealize; widget_class->map = gtk_scrolled_window_map; widget_class->unmap = gtk_scrolled_window_unmap; + widget_class->grab_notify = gtk_scrolled_window_grab_notify; container_class->add = gtk_scrolled_window_add; container_class->remove = gtk_scrolled_window_remove; @@ -2436,9 +2440,8 @@ gtk_scrolled_window_release_captured_events (GtkScrolledWindow *scrolled_window) 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); + gtk_device_grab_remove (GTK_WIDGET (scrolled_window), priv->drag_device); + priv->drag_device = NULL; if (priv->motion_notify_id > 0) { @@ -2488,7 +2491,8 @@ gtk_scrolled_window_button_release_event (GtkWidget *widget, if (!child) return FALSE; - gdk_device_ungrab (gdk_event_get_device (_event), event->time); + gtk_device_grab_remove (widget, priv->drag_device); + priv->drag_device = NULL; if (priv->motion_notify_id > 0) { @@ -2506,7 +2510,9 @@ gtk_scrolled_window_button_release_event (GtkWidget *widget, priv->release_timeout_id = 0; } - if (!priv->in_drag) + if (priv->in_drag) + gdk_device_ungrab (event->device, event->time); + else { /* There hasn't been scrolling at all, so just let the * child widget handle the events normally @@ -2600,6 +2606,14 @@ gtk_scrolled_window_motion_notify_event (GtkWidget *widget, return TRUE; } + gdk_device_grab (priv->drag_device, + gtk_widget_get_window (widget), + GDK_OWNERSHIP_WINDOW, + TRUE, + GDK_BUTTON_RELEASE_MASK | GDK_BUTTON1_MOTION_MASK, + NULL, + event->time); + priv->last_button_event_valid = FALSE; if (priv->button_press_event) @@ -2670,7 +2684,7 @@ gtk_scrolled_window_button_press_event (GtkWidget *widget, GtkWidget *child; GtkWidget *event_widget; GdkEventButton *event; - GdkDevice *device, *source_device; + GdkDevice *source_device; GdkInputSource source; if (_event->type != GDK_BUTTON_PRESS) @@ -2722,15 +2736,8 @@ gtk_scrolled_window_button_press_event (GtkWidget *widget, if (priv->hscrollbar == event_widget || priv->vscrollbar == event_widget) return FALSE; - device = gdk_event_get_device (_event); - gdk_device_grab (device, - gtk_widget_get_window (widget), - GDK_OWNERSHIP_WINDOW, - TRUE, - GDK_BUTTON_RELEASE_MASK | GDK_BUTTON1_MOTION_MASK, - NULL, - event->time); - gtk_device_grab_add (widget, device, TRUE); + priv->drag_device = gdk_event_get_device (_event); + gtk_device_grab_add (widget, priv->drag_device, TRUE); gtk_scrolled_window_cancel_deceleration (scrolled_window); @@ -2846,7 +2853,7 @@ gtk_scrolled_window_adjustment_value_changed (GtkAdjustment *adjustment, GtkScrolledWindowPrivate *priv = scrolled_window->priv; /* Allow overshooting for kinetic scrolling operations */ - if (priv->deceleration_id) + if (priv->drag_device || priv->deceleration_id) return; /* Ensure GtkAdjustment and unclamped values are in sync */ @@ -3261,6 +3268,32 @@ gtk_scrolled_window_unmap (GtkWidget *widget) GTK_WIDGET_CLASS (gtk_scrolled_window_parent_class)->unmap (widget); } +static void +gtk_scrolled_window_grab_notify (GtkWidget *widget, + gboolean was_grabbed) +{ + GtkScrolledWindow *scrolled_window = GTK_SCROLLED_WINDOW (widget); + GtkScrolledWindowPrivate *priv = scrolled_window->priv; + + if (priv->drag_device && + gtk_widget_device_is_shadowed (widget, + priv->drag_device)) + { + gdk_device_ungrab (priv->drag_device, + gtk_get_current_event_time ()); + priv->drag_device = NULL; + priv->in_drag = FALSE; + + if (priv->release_timeout_id) + { + g_source_remove (priv->release_timeout_id); + priv->release_timeout_id = 0; + } + + gtk_scrolled_window_cancel_deceleration (scrolled_window); + } +} + /** * gtk_scrolled_window_get_min_content_width: * @scrolled_window: a #GtkScrolledWindow