From 87cafe5b4b10354d4f4225e939efde92c570fec6 Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Thu, 30 Jun 2005 03:35:30 +0000 Subject: [PATCH] Handle broken grabs. 2005-06-29 Matthias Clasen * gtk/gtkbutton.c (gtk_button_grab_broken): Handle broken grabs. * gtk/gtkrange.c (gtk_range_grab_broken): Handle broken grabs. * gdk/gdkevents.h: Add a boolean to specify wether the broken grab was implicit. * gdk/x11/gdkdisplay-x11.c (gdk_display_pointer_is_grabbed): As the documentation states, don't return TRUE for implicit grabs. * gdk/x11/gdkdisplay-x11.h (struct _GdkDisplayX11): Add a boolean field to store wether a pointer grab is implicit. * gdk/x11/gdkmain-x11.c (_gdk_xgrab_check_button_event): Track implicit grabs. * gdk/x11/gdkevents-x11.c (gdk_event_translate): Call _gdk_xgrab_check_button_event for button events. --- ChangeLog | 24 +++++++++++++++ ChangeLog.pre-2-10 | 24 +++++++++++++++ ChangeLog.pre-2-8 | 24 +++++++++++++++ gdk/gdkevents.h | 2 ++ gdk/x11/gdkdisplay-x11.c | 3 +- gdk/x11/gdkdisplay-x11.h | 1 + gdk/x11/gdkevents-x11.c | 5 +++- gdk/x11/gdkmain-x11.c | 65 +++++++++++++++++++++++++++++++++------- gtk/gtkbutton.c | 26 ++++++++++++++++ gtk/gtkrange.c | 22 ++++++++++++++ 10 files changed, 184 insertions(+), 12 deletions(-) diff --git a/ChangeLog b/ChangeLog index 877b9a591a..380371f83f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,27 @@ +2005-06-29 Matthias Clasen + + * gtk/gtkbutton.c (gtk_button_grab_broken): Handle broken + grabs. + + * gtk/gtkrange.c (gtk_range_grab_broken): Handle broken + grabs. + + * gdk/gdkevents.h: Add a boolean to specify wether the broken + grab was implicit. + + * gdk/x11/gdkdisplay-x11.c (gdk_display_pointer_is_grabbed): + As the documentation states, don't return TRUE for + implicit grabs. + + * gdk/x11/gdkdisplay-x11.h (struct _GdkDisplayX11): Add + a boolean field to store wether a pointer grab is implicit. + + * gdk/x11/gdkmain-x11.c (_gdk_xgrab_check_button_event): + Track implicit grabs. + + * gdk/x11/gdkevents-x11.c (gdk_event_translate): Call + _gdk_xgrab_check_button_event for button events. + 2005-06-28 Matthias Clasen * gtk/gtkiconview.c (gtk_icon_view_calculate_item_size2): diff --git a/ChangeLog.pre-2-10 b/ChangeLog.pre-2-10 index 877b9a591a..380371f83f 100644 --- a/ChangeLog.pre-2-10 +++ b/ChangeLog.pre-2-10 @@ -1,3 +1,27 @@ +2005-06-29 Matthias Clasen + + * gtk/gtkbutton.c (gtk_button_grab_broken): Handle broken + grabs. + + * gtk/gtkrange.c (gtk_range_grab_broken): Handle broken + grabs. + + * gdk/gdkevents.h: Add a boolean to specify wether the broken + grab was implicit. + + * gdk/x11/gdkdisplay-x11.c (gdk_display_pointer_is_grabbed): + As the documentation states, don't return TRUE for + implicit grabs. + + * gdk/x11/gdkdisplay-x11.h (struct _GdkDisplayX11): Add + a boolean field to store wether a pointer grab is implicit. + + * gdk/x11/gdkmain-x11.c (_gdk_xgrab_check_button_event): + Track implicit grabs. + + * gdk/x11/gdkevents-x11.c (gdk_event_translate): Call + _gdk_xgrab_check_button_event for button events. + 2005-06-28 Matthias Clasen * gtk/gtkiconview.c (gtk_icon_view_calculate_item_size2): diff --git a/ChangeLog.pre-2-8 b/ChangeLog.pre-2-8 index 877b9a591a..380371f83f 100644 --- a/ChangeLog.pre-2-8 +++ b/ChangeLog.pre-2-8 @@ -1,3 +1,27 @@ +2005-06-29 Matthias Clasen + + * gtk/gtkbutton.c (gtk_button_grab_broken): Handle broken + grabs. + + * gtk/gtkrange.c (gtk_range_grab_broken): Handle broken + grabs. + + * gdk/gdkevents.h: Add a boolean to specify wether the broken + grab was implicit. + + * gdk/x11/gdkdisplay-x11.c (gdk_display_pointer_is_grabbed): + As the documentation states, don't return TRUE for + implicit grabs. + + * gdk/x11/gdkdisplay-x11.h (struct _GdkDisplayX11): Add + a boolean field to store wether a pointer grab is implicit. + + * gdk/x11/gdkmain-x11.c (_gdk_xgrab_check_button_event): + Track implicit grabs. + + * gdk/x11/gdkevents-x11.c (gdk_event_translate): Call + _gdk_xgrab_check_button_event for button events. + 2005-06-28 Matthias Clasen * gtk/gtkiconview.c (gtk_icon_view_calculate_item_size2): diff --git a/gdk/gdkevents.h b/gdk/gdkevents.h index bf4db6ead1..67708682ab 100644 --- a/gdk/gdkevents.h +++ b/gdk/gdkevents.h @@ -1,3 +1,4 @@ + #ifndef __GDK_EVENTS_H__ #define __GDK_EVENTS_H__ @@ -436,6 +437,7 @@ struct _GdkEventGrabBroken { GdkWindow *window; gint8 send_event; gboolean keyboard; + gboolean implicit; GdkWindow *grab_window; }; diff --git a/gdk/x11/gdkdisplay-x11.c b/gdk/x11/gdkdisplay-x11.c index 66cdc82800..133909dd2f 100644 --- a/gdk/x11/gdkdisplay-x11.c +++ b/gdk/x11/gdkdisplay-x11.c @@ -539,7 +539,8 @@ gdk_display_pointer_is_grabbed (GdkDisplay * display) { g_return_val_if_fail (GDK_IS_DISPLAY (display), TRUE); - return (GDK_DISPLAY_X11 (display)->pointer_xgrab_window != NULL); + return (GDK_DISPLAY_X11 (display)->pointer_xgrab_window != NULL && + !GDK_DISPLAY_X11 (display)->pointer_xgrab_implicit); } /** diff --git a/gdk/x11/gdkdisplay-x11.h b/gdk/x11/gdkdisplay-x11.h index 3e69fa5644..24f317788f 100644 --- a/gdk/x11/gdkdisplay-x11.h +++ b/gdk/x11/gdkdisplay-x11.h @@ -88,6 +88,7 @@ struct _GdkDisplayX11 GdkWindowObject *pointer_xgrab_window; gulong pointer_xgrab_serial; gboolean pointer_xgrab_owner_events; + gboolean pointer_xgrab_implicit; guint32 pointer_xgrab_time; GdkWindowObject *keyboard_xgrab_window; diff --git a/gdk/x11/gdkevents-x11.c b/gdk/x11/gdkevents-x11.c index 97b027c870..4a45cf6984 100644 --- a/gdk/x11/gdkevents-x11.c +++ b/gdk/x11/gdkevents-x11.c @@ -1132,6 +1132,8 @@ gdk_event_translate (GdkDisplay *display, } set_user_time (window, event); + + _gdk_xgrab_check_button_event (window, xevent); break; case ButtonRelease: @@ -1170,7 +1172,8 @@ gdk_event_translate (GdkDisplay *display, event->button.device = display->core_pointer; set_screen_from_root (display, event, xevent->xbutton.root); - + + _gdk_xgrab_check_button_event (window, xevent); break; case MotionNotify: diff --git a/gdk/x11/gdkmain-x11.c b/gdk/x11/gdkmain-x11.c index b92bd64330..985b2b5dce 100644 --- a/gdk/x11/gdkmain-x11.c +++ b/gdk/x11/gdkmain-x11.c @@ -139,8 +139,9 @@ gdk_x11_convert_grab_status (gint status) static void generate_grab_broken_event (GdkWindow *window, - GdkWindow *grab_window, - gboolean keyboard) + gboolean keyboard, + gboolean implicit, + GdkWindow *grab_window) { GdkEvent event; @@ -148,6 +149,7 @@ generate_grab_broken_event (GdkWindow *window, event.grab_broken.window = window; event.grab_broken.send_event = 0; event.grab_broken.keyboard = keyboard; + event.grab_broken.implicit = implicit; event.grab_broken.grab_window = grab_window; gdk_event_put (&event); @@ -254,14 +256,16 @@ gdk_pointer_grab (GdkWindow * window, { GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (GDK_WINDOW_DISPLAY (window)); if (display_x11->pointer_xgrab_window != NULL && - display_x11->pointer_xgrab_window != window) + display_x11->pointer_xgrab_window != (GdkWindowObject *)window) generate_grab_broken_event (GDK_WINDOW (display_x11->pointer_xgrab_window), - window, FALSE); + FALSE, display_x11->pointer_xgrab_implicit, + window); display_x11->pointer_xgrab_window = (GdkWindowObject *)window; display_x11->pointer_xgrab_serial = serial; display_x11->pointer_xgrab_owner_events = owner_events; display_x11->pointer_xgrab_time = time; + display_x11->pointer_xgrab_implicit = FALSE; } return gdk_x11_convert_grab_status (return_val); @@ -357,9 +361,9 @@ gdk_keyboard_grab (GdkWindow * window, { GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (gdk_drawable_get_display (window)); if (display_x11->keyboard_xgrab_window != NULL && - display_x11->keyboard_xgrab_window != window) + display_x11->keyboard_xgrab_window != (GdkWindowObject *)window) generate_grab_broken_event (GDK_WINDOW (display_x11->keyboard_xgrab_window), - window, TRUE); + TRUE, FALSE, window); display_x11->keyboard_xgrab_window = (GdkWindowObject *)window; display_x11->keyboard_xgrab_serial = serial; @@ -435,7 +439,8 @@ _gdk_xgrab_check_unmap (GdkWindow *window, if (tmp) { generate_grab_broken_event (GDK_WINDOW (display_x11->pointer_xgrab_window), - NULL, FALSE); + FALSE, display_x11->pointer_xgrab_implicit, + NULL); display_x11->pointer_xgrab_window = NULL; } } @@ -453,7 +458,7 @@ _gdk_xgrab_check_unmap (GdkWindow *window, if (tmp) { generate_grab_broken_event (GDK_WINDOW (display_x11->keyboard_xgrab_window), - NULL, TRUE); + TRUE, FALSE, NULL); display_x11->keyboard_xgrab_window = NULL; } } @@ -474,18 +479,58 @@ _gdk_xgrab_check_destroy (GdkWindow *window) if ((GdkWindowObject *)window == display_x11->pointer_xgrab_window) { generate_grab_broken_event (GDK_WINDOW (display_x11->pointer_xgrab_window), - NULL, FALSE); + FALSE, display_x11->pointer_xgrab_implicit, + NULL); display_x11->pointer_xgrab_window = NULL; } if ((GdkWindowObject *)window == display_x11->keyboard_xgrab_window) { generate_grab_broken_event (GDK_WINDOW (display_x11->keyboard_xgrab_window), - NULL, TRUE); + TRUE, FALSE, NULL); display_x11->keyboard_xgrab_window = NULL; } } +/** + * _gdk_xgrab_check_button_event: + * @window: a #GdkWindow + * @event: an XEvent of type ButtonPress or ButtonRelease + * + * Checks to see if a button event starts or ends an implicit grab. + **/ +void +_gdk_xgrab_check_button_event (GdkWindow *window, + XEvent *xevent) +{ + GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (gdk_drawable_get_display (window)); + + /* track implicit grabs for button presses */ + switch (xevent->type) + { + case ButtonPress: + if (!display_x11->pointer_xgrab_window) + { + display_x11->pointer_xgrab_window = (GdkWindowObject *)window; + display_x11->pointer_xgrab_serial = xevent->xany.serial; + display_x11->pointer_xgrab_owner_events = FALSE; + display_x11->pointer_xgrab_time = xevent->xbutton.time; + display_x11->pointer_xgrab_implicit = TRUE; + } + break; + case ButtonRelease: + if (display_x11->pointer_xgrab_window && + display_x11->pointer_xgrab_implicit && + (xevent->xbutton.state & ~(GDK_BUTTON1_MASK << (xevent->xbutton.button - 1))) == 0) + { + display_x11->pointer_xgrab_window = NULL; + } + break; + default: + g_assert_not_reached (); + } +} + void _gdk_windowing_display_set_sm_client_id (GdkDisplay *display, const gchar *sm_client_id) diff --git a/gtk/gtkbutton.c b/gtk/gtkbutton.c index 984d99adca..dbf34fb144 100644 --- a/gtk/gtkbutton.c +++ b/gtk/gtkbutton.c @@ -112,6 +112,8 @@ static gint gtk_button_button_press (GtkWidget *widget, GdkEventButton *event); static gint gtk_button_button_release (GtkWidget *widget, GdkEventButton *event); +static gint gtk_button_grab_broken (GtkWidget *widget, + GdkEventAny *event); static gint gtk_button_key_release (GtkWidget *widget, GdkEventKey *event); static gint gtk_button_enter_notify (GtkWidget *widget, @@ -201,6 +203,7 @@ gtk_button_class_init (GtkButtonClass *klass) widget_class->expose_event = gtk_button_expose; widget_class->button_press_event = gtk_button_button_press; widget_class->button_release_event = gtk_button_button_release; + widget_class->grab_broken_event = gtk_button_grab_broken; widget_class->key_release_event = gtk_button_key_release; widget_class->enter_notify_event = gtk_button_enter_notify; widget_class->leave_notify_event = gtk_button_leave_notify; @@ -1262,6 +1265,29 @@ gtk_button_button_release (GtkWidget *widget, return TRUE; } +static gboolean +gtk_button_grab_broken (GtkWidget *widget, + GdkEventAny *event) +{ + GtkButton *button = GTK_BUTTON (widget); + gboolean save_in; + + /* Simulate a button release without the pointer in the button */ + if (button->button_down) + { + save_in = button->in_button; + button->in_button = FALSE; + gtk_button_released (button); + if (save_in != button->in_button) + { + button->in_button = save_in; + gtk_button_update_state (button); + } + } + + return TRUE; +} + static gboolean gtk_button_key_release (GtkWidget *widget, GdkEventKey *event) diff --git a/gtk/gtkrange.c b/gtk/gtkrange.c index d8340eb7c5..af337cdf31 100644 --- a/gtk/gtkrange.c +++ b/gtk/gtkrange.c @@ -124,6 +124,8 @@ static gint gtk_range_enter_notify (GtkWidget *widget, GdkEventCrossing *event); static gint gtk_range_leave_notify (GtkWidget *widget, GdkEventCrossing *event); +static gboolean gtk_range_grab_broken (GtkWidget *widget, + GdkEventGrabBroken *event); static void gtk_range_grab_notify (GtkWidget *widget, gboolean was_grabbed); static void gtk_range_state_changed (GtkWidget *widget, @@ -244,6 +246,7 @@ gtk_range_class_init (GtkRangeClass *class) widget_class->scroll_event = gtk_range_scroll_event; widget_class->enter_notify_event = gtk_range_enter_notify; widget_class->leave_notify_event = gtk_range_leave_notify; + widget_class->grab_broken_event = gtk_range_grab_broken; widget_class->grab_notify = gtk_range_grab_notify; widget_class->state_changed = gtk_range_state_changed; widget_class->style_set = gtk_range_style_set; @@ -1378,6 +1381,25 @@ stop_scrolling (GtkRange *range) gtk_widget_queue_draw (GTK_WIDGET (range)); } +static gboolean +gtk_range_grab_broken (GtkWidget *widget, + GdkEventGrabBroken *event) +{ + GtkRange *range = GTK_RANGE (widget); + + if (range->layout->grab_location != MOUSE_OUTSIDE) + { + if (range->layout->grab_location == MOUSE_SLIDER) + update_slider_position (range, range->layout->mouse_x, range->layout->mouse_y); + + stop_scrolling (range); + + return TRUE; + } + + return FALSE; +} + static gint gtk_range_button_release (GtkWidget *widget, GdkEventButton *event)