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