]> Pileus Git - ~andy/gtk/commitdiff
Add a GrabBroken event to GDK, and a grab-broken-event signal to
authorMatthias Clasen <mclasen@redhat.com>
Sat, 25 Jun 2005 07:10:40 +0000 (07:10 +0000)
committerMatthias Clasen <matthiasc@src.gnome.org>
Sat, 25 Jun 2005 07:10:40 +0000 (07:10 +0000)
2005-06-25  Matthias Clasen  <mclasen@redhat.com>

Add a GrabBroken event to GDK, and a grab-broken-event
signal to GtkWidget.  (#107320, Simon Cooke, initial patch
by John Ehresman)

* gdk/gdkevents.h: Add a GDK_GRAB_BROKEN event type,
define a GdkEventGrabBroken event struct.

* gdk/win32/gdkevents-win32.c (gdk_event_translate):
Generate GrabBroken events in response to WM_KILLFOCUS.

* gdk/x11/gdkmain-x11.c: Generate GrabBroken events
when a grab is broken by the window becoming unviewable,
or by another grab from the same client.

* gtk/gtkwidget.h (GtkWidgetClass): Add grab_broken_event.

* gtk/gtkwidget.c (gtk_widget_event_internal): Translate
GrabBroken events into grab_broken_event signals.

* gtk/gtkmain.c (gtk_main_do_event): Propagate GrabBroken
events.

* gtk/gtkmenushell.c (gtk_menu_shell_grab_broken): Deactivate
the menu when the grab is broken.

* gtk/gtkcolorsel.c (gtk_color_selection_grab_broken): Stop
the color picker if the grab is broken.

* gtk/gtkpaned.c (gtk_paned_grab_broken): Stop the drag if
the grab is broken.

16 files changed:
ChangeLog
ChangeLog.pre-2-10
ChangeLog.pre-2-8
docs/reference/ChangeLog
docs/reference/gdk/gdk-sections.txt
docs/reference/gdk/tmpl/event_structs.sgml
docs/reference/gdk/tmpl/events.sgml
gdk/gdkevents.h
gdk/win32/gdkevents-win32.c
gdk/x11/gdkmain-x11.c
gtk/gtkcolorsel.c
gtk/gtkmain.c
gtk/gtkmenushell.c
gtk/gtkpaned.c
gtk/gtkwidget.c
gtk/gtkwidget.h

index 28d90c1b02ac31137e508bfe9a400a65e6063707..c4bdfc1c27288ff65285bb5617c38852a948fb20 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,36 @@
+2005-06-25  Matthias Clasen  <mclasen@redhat.com>
+
+       Add a GrabBroken event to GDK, and a grab-broken-event
+       signal to GtkWidget.  (#107320, Simon Cooke, initial patch 
+       by John Ehresman)
+
+       * gdk/gdkevents.h: Add a GDK_GRAB_BROKEN event type,
+       define a GdkEventGrabBroken event struct.
+
+       * gdk/win32/gdkevents-win32.c (gdk_event_translate): 
+       Generate GrabBroken events in response to WM_KILLFOCUS.
+
+       * gdk/x11/gdkmain-x11.c: Generate GrabBroken events
+       when a grab is broken by the window becoming unviewable,
+       or by another grab from the same client.
+       
+       * gtk/gtkwidget.h (GtkWidgetClass): Add grab_broken_event.
+
+       * gtk/gtkwidget.c (gtk_widget_event_internal): Translate
+       GrabBroken events into grab_broken_event signals.
+
+       * gtk/gtkmain.c (gtk_main_do_event): Propagate GrabBroken
+       events.
+
+       * gtk/gtkmenushell.c (gtk_menu_shell_grab_broken): Deactivate
+       the menu when the grab is broken.
+
+       * gtk/gtkcolorsel.c (gtk_color_selection_grab_broken): Stop 
+       the color picker if the grab is broken.
+
+       * gtk/gtkpaned.c (gtk_paned_grab_broken): Stop the drag if
+       the grab is broken.
+
 2005-06-25  Matthias Clasen  <mclasen@redhat.com>
 
        Add some new stock items.  (#166480, Kristof Vansant)
index 28d90c1b02ac31137e508bfe9a400a65e6063707..c4bdfc1c27288ff65285bb5617c38852a948fb20 100644 (file)
@@ -1,3 +1,36 @@
+2005-06-25  Matthias Clasen  <mclasen@redhat.com>
+
+       Add a GrabBroken event to GDK, and a grab-broken-event
+       signal to GtkWidget.  (#107320, Simon Cooke, initial patch 
+       by John Ehresman)
+
+       * gdk/gdkevents.h: Add a GDK_GRAB_BROKEN event type,
+       define a GdkEventGrabBroken event struct.
+
+       * gdk/win32/gdkevents-win32.c (gdk_event_translate): 
+       Generate GrabBroken events in response to WM_KILLFOCUS.
+
+       * gdk/x11/gdkmain-x11.c: Generate GrabBroken events
+       when a grab is broken by the window becoming unviewable,
+       or by another grab from the same client.
+       
+       * gtk/gtkwidget.h (GtkWidgetClass): Add grab_broken_event.
+
+       * gtk/gtkwidget.c (gtk_widget_event_internal): Translate
+       GrabBroken events into grab_broken_event signals.
+
+       * gtk/gtkmain.c (gtk_main_do_event): Propagate GrabBroken
+       events.
+
+       * gtk/gtkmenushell.c (gtk_menu_shell_grab_broken): Deactivate
+       the menu when the grab is broken.
+
+       * gtk/gtkcolorsel.c (gtk_color_selection_grab_broken): Stop 
+       the color picker if the grab is broken.
+
+       * gtk/gtkpaned.c (gtk_paned_grab_broken): Stop the drag if
+       the grab is broken.
+
 2005-06-25  Matthias Clasen  <mclasen@redhat.com>
 
        Add some new stock items.  (#166480, Kristof Vansant)
index 28d90c1b02ac31137e508bfe9a400a65e6063707..c4bdfc1c27288ff65285bb5617c38852a948fb20 100644 (file)
@@ -1,3 +1,36 @@
+2005-06-25  Matthias Clasen  <mclasen@redhat.com>
+
+       Add a GrabBroken event to GDK, and a grab-broken-event
+       signal to GtkWidget.  (#107320, Simon Cooke, initial patch 
+       by John Ehresman)
+
+       * gdk/gdkevents.h: Add a GDK_GRAB_BROKEN event type,
+       define a GdkEventGrabBroken event struct.
+
+       * gdk/win32/gdkevents-win32.c (gdk_event_translate): 
+       Generate GrabBroken events in response to WM_KILLFOCUS.
+
+       * gdk/x11/gdkmain-x11.c: Generate GrabBroken events
+       when a grab is broken by the window becoming unviewable,
+       or by another grab from the same client.
+       
+       * gtk/gtkwidget.h (GtkWidgetClass): Add grab_broken_event.
+
+       * gtk/gtkwidget.c (gtk_widget_event_internal): Translate
+       GrabBroken events into grab_broken_event signals.
+
+       * gtk/gtkmain.c (gtk_main_do_event): Propagate GrabBroken
+       events.
+
+       * gtk/gtkmenushell.c (gtk_menu_shell_grab_broken): Deactivate
+       the menu when the grab is broken.
+
+       * gtk/gtkcolorsel.c (gtk_color_selection_grab_broken): Stop 
+       the color picker if the grab is broken.
+
+       * gtk/gtkpaned.c (gtk_paned_grab_broken): Stop the drag if
+       the grab is broken.
+
 2005-06-25  Matthias Clasen  <mclasen@redhat.com>
 
        Add some new stock items.  (#166480, Kristof Vansant)
index 5b27becfe57a1b59eb101fa1c480bf6aa2292207..7fc72db2c7ade41c85f47e56c02fdcd17467e3eb 100644 (file)
@@ -1,3 +1,7 @@
+2005-06-25  Matthias Clasen  <mclasen@redhat.com>
+
+       * gdk/gdk-sections.txt: Add GdkEventGrabBroken.
+
 2005-06-21  Matthias Clasen  <mclasen@redhat.com>
 
        * gdk/gdk-sections.txt: Add gdk_window_move_region
index 6dcde195e9f78d5308399db46fa513431568e509..09007673d7ab498ef97739eef6789b4e0cb299c6 100644 (file)
@@ -1101,6 +1101,7 @@ GdkEventNoExpose
 GdkEventWindowState
 GdkEventSetting
 GdkEventOwnerChange
+GdkEventGrabBroken
 
 <SUBSECTION>
 GdkScrollDirection
index 732cbeb07bc34d8bdfe852a700d479dc77801b27..438bb6e39f3625bf7db785caaae2fcec4ca2d89e 100644 (file)
@@ -424,6 +424,22 @@ only available if the X server supports the XFIXES extension.
 @selection_time: the time at which the selection ownership was taken over
 @Since: 2.6
 
+<!-- ##### STRUCT GdkEventGrabBroken ##### -->
+<para>
+Generated when a pointer or keyboard grab is broken. On X11, this happens
+when the grab window becomes unviewable (i.e. it or one of its ancestors 
+is unmapped), or if the same application grabs the pointer or keyboard
+again.
+</para>
+
+@type: the type of the event (%GDK_GRAB_BROKEN) 
+@window: the window which received the event, i.e. the window
+ that previously owned the grab
+@send_event: %TRUE if the event was sent explicitly (e.g. using <function>XSendEvent</function>).
+@keyboard: %TRUE if a keyboard grab was broken, %FALSE if a pointer 
+  grab was broken
+@Since: 2.8
+
 <!-- ##### ENUM GdkScrollDirection ##### -->
 <para>
 Specifies the direction for #GdkEventScroll. 
index 9b902f5b547607947b4566aa73916a0c092a1053..b1eb7bcf4681c732cfbc3a971f3fc5710bee2de1 100644 (file)
@@ -90,6 +90,8 @@ for the possible window states
 @GDK_SETTING: a setting has been modified.
 @GDK_OWNER_CHANGE: the owner of a selection has changed. This event type
   was added in 2.6
+@GDK_GRAB_BROKEN: a pointer or keyboard grab was broken. This event type
+  was added in 2.8.
 
 <!-- ##### ENUM GdkEventMask ##### -->
 <para>
index 32873091da1a4b3b80cb386cdb3a8d20e446fe4f..797bee7460e982ed03337c6e5fead1510c8030e8 100644 (file)
@@ -33,6 +33,7 @@ typedef struct _GdkEventClient            GdkEventClient;
 typedef struct _GdkEventDND         GdkEventDND;
 typedef struct _GdkEventWindowState GdkEventWindowState;
 typedef struct _GdkEventSetting     GdkEventSetting;
+typedef struct _GdkEventGrabBroken  GdkEventGrabBroken;
 
 typedef union  _GdkEvent           GdkEvent;
 
@@ -118,7 +119,8 @@ typedef enum
   GDK_SCROLL            = 31,
   GDK_WINDOW_STATE      = 32,
   GDK_SETTING           = 33,
-  GDK_OWNER_CHANGE      = 34
+  GDK_OWNER_CHANGE      = 34,
+  GDK_GRAB_BROKEN       = 35
 } GdkEventType;
 
 /* Event masks. (Used to select what types of events a window
@@ -429,6 +431,13 @@ struct _GdkEventWindowState
   GdkWindowState new_window_state;
 };
 
+struct _GdkEventGrabBroken {
+  GdkEventType type;
+  GdkWindow *window;
+  gint8 send_event;
+  gboolean keyboard;
+};
+
 /* Event types for DND */
 
 struct _GdkEventDND {
@@ -463,6 +472,7 @@ union _GdkEvent
   GdkEventDND               dnd;
   GdkEventWindowState       window_state;
   GdkEventSetting           setting;
+  GdkEventGrabBroken        grab_broken;
 };
 
 GType     gdk_event_get_type            (void) G_GNUC_CONST;
index 47a7eb482098bfa3d74c5c466266d600c72949fd..23f92a241ed1622580f97cf7615d479018ddca42 100644 (file)
@@ -2919,8 +2919,29 @@ gdk_event_translate (GdkDisplay *display,
         }
        break;
 
-    case WM_SETFOCUS:
     case WM_KILLFOCUS:
+      if (p_grab_window != NULL && !GDK_WINDOW_DESTROYED (p_grab_window))
+       {
+         event = gdk_event_new (GDK_GRAB_BROKEN);
+         event->grab_broken.window = p_grab_window;
+         event->grab_broken.send_event = 0;
+         event->grab_broken.keyboard = FALSE;
+         
+          append_event (display, event);
+       }
+      if (k_grab_window != NULL && !GDK_WINDOW_DESTROYED (k_grab_window) 
+         && k_grab_window != p_grab_window)
+       {
+         event = gdk_event_new (GDK_GRAB_BROKEN);
+         event->grab_broken.window = k_grab_window;
+         event->grab_broken.send_event = 0;
+         event->grab_broken.keyboard = TRUE;
+
+          append_event (display, event);
+       }
+
+      /* fallthrough */
+    case WM_SETFOCUS:
       if (k_grab_window != NULL && !k_grab_owner_events)
        break;
 
index 47b06cef77e2ac564fdbfa27c5e6ad738a23eec2..92c9f63a6a78732a797edd0dbce55e34319b2d54 100644 (file)
@@ -137,6 +137,20 @@ gdk_x11_convert_grab_status (gint status)
   return 0;
 }
 
+static void
+generate_grab_broken_event (GdkWindow *window,
+                           gboolean   keyboard)
+{
+  GdkEvent event;
+  
+  event.type = GDK_GRAB_BROKEN;
+  event.grab_broken.window = window;
+  event.grab_broken.send_event = 0;
+  event.grab_broken.keyboard = keyboard;
+  
+  gdk_event_put (&event);
+}
+
 /*
  *--------------------------------------------------------------
  * gdk_pointer_grab
@@ -237,6 +251,10 @@ gdk_pointer_grab (GdkWindow *        window,
   if (return_val == GrabSuccess)
     {
       GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (GDK_WINDOW_DISPLAY (window));
+      if (display_x11->pointer_xgrab_window != NULL)
+       generate_grab_broken_event (GDK_WINDOW (display_x11->pointer_xgrab_window),
+                                   FALSE);
+
       display_x11->pointer_xgrab_window = (GdkWindowObject *)window;
       display_x11->pointer_xgrab_serial = serial;
       display_x11->pointer_xgrab_owner_events = owner_events;
@@ -334,6 +352,11 @@ gdk_keyboard_grab (GdkWindow *        window,
   if (return_val == GrabSuccess)
     {
       GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (gdk_drawable_get_display (window));
+
+      if (display_x11->keyboard_xgrab_window != NULL)
+       generate_grab_broken_event (GDK_WINDOW (display_x11->keyboard_xgrab_window),
+                                   TRUE);
+
       display_x11->keyboard_xgrab_window = (GdkWindowObject *)window;
       display_x11->keyboard_xgrab_serial = serial;
       display_x11->keyboard_xgrab_owner_events = owner_events;
@@ -405,7 +428,11 @@ _gdk_xgrab_check_unmap (GdkWindow *window,
        tmp = tmp->parent;
 
       if (tmp)
-       display_x11->pointer_xgrab_window = NULL;  
+       {         
+         generate_grab_broken_event (GDK_WINDOW (display_x11->pointer_xgrab_window),
+                                     FALSE);
+         display_x11->pointer_xgrab_window = NULL;  
+       }
     }
 
   if (display_x11->keyboard_xgrab_window &&
@@ -419,7 +446,11 @@ _gdk_xgrab_check_unmap (GdkWindow *window,
        tmp = tmp->parent;
 
       if (tmp)
-       display_x11->keyboard_xgrab_window = NULL;  
+       {
+         generate_grab_broken_event (GDK_WINDOW (display_x11->keyboard_xgrab_window),
+                                     TRUE);
+         display_x11->keyboard_xgrab_window = NULL;  
+       }
     }
 }
 
@@ -436,10 +467,18 @@ _gdk_xgrab_check_destroy (GdkWindow *window)
   GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (gdk_drawable_get_display (window));
   
   if ((GdkWindowObject *)window == display_x11->pointer_xgrab_window)
-     display_x11->pointer_xgrab_window = NULL;
+    {
+      generate_grab_broken_event (GDK_WINDOW (display_x11->pointer_xgrab_window),
+                                 FALSE);
+      display_x11->pointer_xgrab_window = NULL;
+    }
 
   if ((GdkWindowObject *)window ==  display_x11->keyboard_xgrab_window)
-     display_x11->keyboard_xgrab_window = NULL;
+    {
+      generate_grab_broken_event (GDK_WINDOW (display_x11->keyboard_xgrab_window),
+                                 TRUE);
+      display_x11->keyboard_xgrab_window = NULL;
+    }
 }
 
 void
index e0199f358620f0b059bef4c53468d04bd01aceb9..92bd24f9fc092a0de3bb735c8d4304ca25f143b8 100644 (file)
@@ -139,6 +139,8 @@ struct _ColorSelectionPrivate
 
   /* Window for grabbing on */
   GtkWidget *dropper_grab_widget;
+  guint32    grab_time;
+  gboolean   has_grab;
 
   /* Connection to settings */
   gulong settings_connection;
@@ -162,6 +164,8 @@ static void gtk_color_selection_get_property    (GObject                 *object
 static void gtk_color_selection_realize         (GtkWidget               *widget);
 static void gtk_color_selection_unrealize       (GtkWidget               *widget);
 static void gtk_color_selection_show_all        (GtkWidget               *widget);
+static gboolean gtk_color_selection_grab_broken (GtkWidget               *widget,
+                                                GdkEventGrabBroken      *event);
 
 static void     gtk_color_selection_set_palette_color   (GtkColorSelection *colorsel,
                                                          gint               index,
@@ -1248,14 +1252,27 @@ shutdown_eyedropper (GtkWidget *widget)
   GtkColorSelection *colorsel;
   ColorSelectionPrivate *priv;
   GdkDisplay *display = gtk_widget_get_display (widget);
-  guint32 time = gtk_get_current_event_time ();
 
   colorsel = GTK_COLOR_SELECTION (widget);
   priv = colorsel->private_data;    
 
-  gdk_display_keyboard_ungrab (display, time);
-  gdk_display_pointer_ungrab (display, time);
-  gtk_grab_remove (priv->dropper_grab_widget);
+  if (priv->has_grab)
+    {
+      gdk_display_keyboard_ungrab (display, priv->grab_time);
+      gdk_display_pointer_ungrab (display, priv->grab_time);
+      gtk_grab_remove (priv->dropper_grab_widget);
+
+      priv->has_grab = FALSE;
+    }
+}
+
+static gboolean 
+gtk_color_selection_grab_broken (GtkWidget          *widget,
+                                GdkEventGrabBroken *event)
+{
+  shutdown_eyedropper (widget);
+
+  return TRUE;
 }
 
 static void
@@ -1410,6 +1427,7 @@ get_screen_color (GtkWidget *button)
   GdkScreen *screen = gtk_widget_get_screen (GTK_WIDGET (button));
   GdkCursor *picker_cursor;
   GdkGrabStatus grab_status;
+  guint32 time = gtk_get_current_event_time ();
   
   if (priv->dropper_grab_widget == NULL)
     {
@@ -1419,11 +1437,14 @@ get_screen_color (GtkWidget *button)
                              GDK_BUTTON_RELEASE_MASK | GDK_BUTTON_PRESS_MASK | GDK_POINTER_MOTION_MASK);
       
       gtk_widget_show (priv->dropper_grab_widget);
+
+      gdk_window_set_user_data (priv->dropper_grab_widget->window, colorsel);
+      gdk_window_reparent (priv->dropper_grab_widget->window, 
+                          GTK_WIDGET (colorsel)->window, 0, 0);
     }
 
   if (gdk_keyboard_grab (priv->dropper_grab_widget->window,
-                         FALSE,
-                         gtk_get_current_event_time ()) != GDK_GRAB_SUCCESS)
+                         FALSE, time) != GDK_GRAB_SUCCESS)
     return;
   
   picker_cursor = make_picker_cursor (screen);
@@ -1432,16 +1453,18 @@ get_screen_color (GtkWidget *button)
                                  GDK_BUTTON_RELEASE_MASK | GDK_BUTTON_PRESS_MASK | GDK_POINTER_MOTION_MASK,
                                  NULL,
                                  picker_cursor,
-                                 gtk_get_current_event_time ());
+                                 time);
   gdk_cursor_unref (picker_cursor);
   
   if (grab_status != GDK_GRAB_SUCCESS)
     {
-      gdk_display_keyboard_ungrab (gtk_widget_get_display (button), GDK_CURRENT_TIME);
+      gdk_display_keyboard_ungrab (gtk_widget_get_display (button), time);
       return;
     }
 
   gtk_grab_add (priv->dropper_grab_widget);
+  priv->grab_time = time;
+  priv->has_grab = TRUE;
   
   g_signal_connect (priv->dropper_grab_widget, "button_press_event",
                     G_CALLBACK (mouse_press), colorsel);
@@ -1843,6 +1866,7 @@ gtk_color_selection_class_init (GtkColorSelectionClass *klass)
   widget_class->realize = gtk_color_selection_realize;
   widget_class->unrealize = gtk_color_selection_unrealize;
   widget_class->show_all = gtk_color_selection_show_all;
+  widget_class->grab_broken_event = gtk_color_selection_grab_broken;
   
   g_object_class_install_property (gobject_class,
                                    PROP_HAS_OPACITY_CONTROL,
index 1d53bf087b575cfd628dbd78f37086ea7a3028e8..bd42c7ea410f9f3a31b7c55c3d07fca3fc8789bf 100644 (file)
@@ -1369,6 +1369,7 @@ gtk_main_do_event (GdkEvent *event)
     case GDK_CLIENT_EVENT:
     case GDK_VISIBILITY_NOTIFY:
     case GDK_WINDOW_STATE:
+    case GDK_GRAB_BROKEN:
       gtk_widget_event (event_widget, event);
       break;
 
index 1febb465305a2255d8be2a08dc50e572af96c32a..123f00911b91523e6bdb5d4b6989b6e7d85d740a 100644 (file)
@@ -166,6 +166,8 @@ static gint gtk_menu_shell_leave_notify      (GtkWidget         *widget,
                                              GdkEventCrossing  *event);
 static void gtk_menu_shell_screen_changed    (GtkWidget         *widget,
                                              GdkScreen         *previous_screen);
+static gboolean gtk_menu_shell_grab_broken       (GtkWidget         *widget,
+                                             GdkEventGrabBroken *event);
 static void gtk_menu_shell_add               (GtkContainer      *container,
                                              GtkWidget         *widget);
 static void gtk_menu_shell_remove            (GtkContainer      *container,
@@ -254,6 +256,7 @@ gtk_menu_shell_class_init (GtkMenuShellClass *klass)
   widget_class->realize = gtk_menu_shell_realize;
   widget_class->button_press_event = gtk_menu_shell_button_press;
   widget_class->button_release_event = gtk_menu_shell_button_release;
+  widget_class->grab_broken_event = gtk_menu_shell_grab_broken;
   widget_class->key_press_event = gtk_menu_shell_key_press;
   widget_class->enter_notify_event = gtk_menu_shell_enter_notify;
   widget_class->leave_notify_event = gtk_menu_shell_leave_notify;
@@ -604,6 +607,27 @@ gtk_menu_shell_button_press (GtkWidget      *widget,
   return TRUE;
 }
 
+static gboolean
+gtk_menu_shell_grab_broken (GtkWidget          *widget,
+                           GdkEventGrabBroken *event)
+{
+  GtkMenuShell *menu_shell;
+  GtkWidget *menu_item;
+  gint deactivate;
+
+  g_return_val_if_fail (GTK_IS_MENU_SHELL (widget), FALSE);
+  g_return_val_if_fail (event != NULL, FALSE);
+
+  menu_shell = GTK_MENU_SHELL (widget);
+  if (menu_shell->active)
+    {
+      gtk_menu_shell_deactivate (menu_shell);
+      g_signal_emit (menu_shell, menu_shell_signals[SELECTION_DONE], 0);
+    }
+
+  return TRUE;
+}
+
 static gint
 gtk_menu_shell_button_release (GtkWidget      *widget,
                               GdkEventButton *event)
index dcf838efb19ab7c279a3e8a83839995585f58f1b..f0fb5f6eab127b697909e30c68a6beca4fdc6302 100644 (file)
@@ -99,6 +99,8 @@ static gboolean gtk_paned_motion                (GtkWidget        *widget,
                                                 GdkEventMotion   *event);
 static gboolean gtk_paned_focus                 (GtkWidget        *widget,
                                                 GtkDirectionType  direction);
+static gboolean gtk_paned_grab_broken           (GtkWidget          *widget,
+                                                GdkEventGrabBroken *event);
 static void     gtk_paned_add                   (GtkContainer     *container,
                                                 GtkWidget        *widget);
 static void     gtk_paned_remove                (GtkContainer     *container,
@@ -127,7 +129,7 @@ static gboolean gtk_paned_accept_position       (GtkPaned         *paned);
 static gboolean gtk_paned_cancel_position       (GtkPaned         *paned);
 static gboolean gtk_paned_toggle_handle_focus   (GtkPaned         *paned);
 
-static GType    gtk_paned_child_type             (GtkContainer     *container);
+static GType    gtk_paned_child_type            (GtkContainer     *container);
 
 static GtkContainerClass *parent_class = NULL;
 
@@ -135,6 +137,7 @@ struct _GtkPanedPrivate
 {
   GtkWidget *saved_focus;
   GtkPaned *first_paned;
+  guint32 grab_time;
 };
 
 GType
@@ -219,6 +222,7 @@ gtk_paned_class_init (GtkPanedClass *class)
   widget_class->button_press_event = gtk_paned_button_press;
   widget_class->button_release_event = gtk_paned_button_release;
   widget_class->motion_notify_event = gtk_paned_motion;
+  widget_class->grab_broken_event = gtk_paned_grab_broken;
   
   container_class->add = gtk_paned_add;
   container_class->remove = gtk_paned_remove;
@@ -882,18 +886,20 @@ gtk_paned_button_press (GtkWidget      *widget,
   if (!paned->in_drag &&
       (event->window == paned->handle) && (event->button == 1))
     {
-      paned->in_drag = TRUE;
-
       /* We need a server grab here, not gtk_grab_add(), since
        * we don't want to pass events on to the widget's children */
-      gdk_pointer_grab (paned->handle, FALSE,
-                       GDK_POINTER_MOTION_HINT_MASK
-                       | GDK_BUTTON1_MOTION_MASK
-                       | GDK_BUTTON_RELEASE_MASK
-                       | GDK_ENTER_NOTIFY_MASK
-                       | GDK_LEAVE_NOTIFY_MASK,
-                       NULL, NULL,
-                       event->time);
+      if (gdk_pointer_grab (paned->handle, FALSE,
+                           GDK_POINTER_MOTION_HINT_MASK
+                           | GDK_BUTTON1_MOTION_MASK
+                           | GDK_BUTTON_RELEASE_MASK
+                           | GDK_ENTER_NOTIFY_MASK
+                           | GDK_LEAVE_NOTIFY_MASK,
+                           NULL, NULL,
+                           event->time) != GDK_GRAB_SUCCESS)
+       return FALSE;
+
+      paned->in_drag = TRUE;
+      paned->priv->grab_time = event->time;
 
       if (paned->orientation == GTK_ORIENTATION_HORIZONTAL)
        paned->drag_pos = event->y;
@@ -906,6 +912,17 @@ gtk_paned_button_press (GtkWidget      *widget,
   return FALSE;
 }
 
+static gboolean
+gtk_paned_grab_broken (GtkWidget          *widget,
+                      GdkEventGrabBroken *event)
+{
+  GtkPaned *paned = GTK_PANED (widget);
+
+  paned->in_drag = FALSE;
+  paned->drag_pos = -1;
+  paned->position_set = TRUE;
+}
+
 static gboolean
 gtk_paned_button_release (GtkWidget      *widget,
                          GdkEventButton *event)
@@ -918,7 +935,7 @@ gtk_paned_button_release (GtkWidget      *widget,
       paned->drag_pos = -1;
       paned->position_set = TRUE;
       gdk_display_pointer_ungrab (gtk_widget_get_display (widget),
-                                 event->time);
+                                 paned->priv->grab_time);
       return TRUE;
     }
 
index 2006789230e32579de948e8110b54390b14af548..ea725f786ac686d1b07a6e70c8b187a3682aabe7 100644 (file)
@@ -120,6 +120,7 @@ enum {
   ACCEL_CLOSURES_CHANGED,
   SCREEN_CHANGED,
   CAN_ACTIVATE_ACCEL,
+  GRAB_BROKEN,
   LAST_SIGNAL
 };
 
@@ -398,6 +399,7 @@ gtk_widget_class_init (GtkWidgetClass *klass)
   klass->drag_data_received = NULL;
   klass->screen_changed = NULL;
   klass->can_activate_accel = gtk_widget_real_can_activate_accel;
+  klass->grab_broken_event = NULL;
 
   klass->show_help = gtk_widget_real_show_help;
   
@@ -1324,6 +1326,32 @@ gtk_widget_class_init (GtkWidgetClass *klass)
                  _gtk_marshal_BOOLEAN__BOXED,
                  G_TYPE_BOOLEAN, 1,
                  GDK_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
+  /**
+   * GtkWidget::grab-broken:
+   * @widget: the object which received the signal
+   * @event: the #GdkEventGrabBroken event
+   *
+   * Emitted when a pointer or keyboard grab on a window belonging 
+   * to @widget gets broken. 
+   * 
+   * On X11, this happens when the grab window becomes unviewable 
+   * (i.e. it or one of its ancestors is unmapped), or if the same 
+   * application grabs the pointer or keyboard again.
+   *
+   * Returns: %TRUE to stop other handlers from being invoked for the event. 
+   *   %FALSE to propagate the event further.
+   *
+   * Since: 2.8
+   */
+  widget_signals[GRAB_BROKEN] =
+    g_signal_new ("grab_broken_event",
+                 G_TYPE_FROM_CLASS (gobject_class),
+                 G_SIGNAL_RUN_LAST,
+                 G_STRUCT_OFFSET (GtkWidgetClass, grab_broken_event),
+                 _gtk_boolean_handled_accumulator, NULL,
+                 _gtk_marshal_BOOLEAN__BOXED,
+                 G_TYPE_BOOLEAN, 1,
+                 GDK_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
 /**
  * GtkWidget::popup-menu
  * @widget: the object which received the signal
@@ -3694,6 +3722,9 @@ gtk_widget_event_internal (GtkWidget *widget,
        case GDK_VISIBILITY_NOTIFY:
          signal_num = VISIBILITY_NOTIFY_EVENT;
          break;
+       case GDK_GRAB_BROKEN:
+         signal_num = GRAB_BROKEN;
+         break;
        default:
          g_warning ("gtk_widget_event(): unhandled event type: %d", event->type);
          signal_num = -1;
index ac8ef52cf26858fb0fc81e5599e595f6ade7ed2c..0c487bcdb12537b2fc07b5dfbcceef8052565fea 100644 (file)
@@ -403,8 +403,11 @@ struct _GtkWidgetClass
   gboolean     (*can_activate_accel) (GtkWidget *widget,
                                       guint      signal_id);
 
+  /* Sent when a grab is broken. */
+  gboolean (*grab_broken_event) (GtkWidget          *widget,
+                                 GdkEventGrabBroken  *event);
+
   /* Padding for future expansion */
-  void (*_gtk_reserved2) (void);
   void (*_gtk_reserved3) (void);
   void (*_gtk_reserved4) (void);
   void (*_gtk_reserved5) (void);