[gtk+] x11: Cancel _NET_WM_MOVERESIZE if we get a matching ButtonRelease



commit db2eb85e4af9d8f191fe1ade53ec85a94b326c9f
Author: Rui Matos <tiagomatos gmail com>
Date:   Wed Feb 1 17:59:23 2012 +0000

    x11: Cancel _NET_WM_MOVERESIZE if we get a matching ButtonRelease
    
    This implements the following part of the EWMH spec:
    
    "The special value _NET_WM_MOVERESIZE_CANCEL also allows clients to cancel the
    operation by sending such message if they detect the release themselves
    (clients should send it if they get the button release after sending the move
    resize message, indicating that the WM did not get a grab in time to get the
    release)."
    
    In particular, it fixes the case of clicking widgets that use
    gdk_window_begin_[resize|move]_drag*() and the click "sticking", i.e. the
    mouse button getting released but the resize or move operation remaining in
    effect.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=669208

 gdk/x11/gdkdisplay-x11.h |    2 +
 gdk/x11/gdkwindow-x11.c  |  150 ++++++++++++++++++++++++++++++++--------------
 2 files changed, 106 insertions(+), 46 deletions(-)
---
diff --git a/gdk/x11/gdkdisplay-x11.h b/gdk/x11/gdkdisplay-x11.h
index 7fdb05e..0c868ed 100644
--- a/gdk/x11/gdkdisplay-x11.h
+++ b/gdk/x11/gdkdisplay-x11.h
@@ -131,6 +131,8 @@ struct _GdkX11Display
   GdkWindow *active_offscreen_window;
 
   GSList *error_traps;
+
+  gint wm_moveresize_button;
 };
 
 struct _GdkX11DisplayClass
diff --git a/gdk/x11/gdkwindow-x11.c b/gdk/x11/gdkwindow-x11.c
index 5d3df85..6084aa7 100644
--- a/gdk/x11/gdkwindow-x11.c
+++ b/gdk/x11/gdkwindow-x11.c
@@ -4020,22 +4020,30 @@ gdk_window_x11_set_static_gravities (GdkWindow *window,
   return TRUE;
 }
 
+/* From the WM spec */
+#define _NET_WM_MOVERESIZE_SIZE_TOPLEFT      0
+#define _NET_WM_MOVERESIZE_SIZE_TOP          1
+#define _NET_WM_MOVERESIZE_SIZE_TOPRIGHT     2
+#define _NET_WM_MOVERESIZE_SIZE_RIGHT        3
+#define _NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT  4
+#define _NET_WM_MOVERESIZE_SIZE_BOTTOM       5
+#define _NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT   6
+#define _NET_WM_MOVERESIZE_SIZE_LEFT         7
+#define _NET_WM_MOVERESIZE_MOVE              8   /* movement only */
+#define _NET_WM_MOVERESIZE_SIZE_KEYBOARD     9   /* size via keyboard */
+#define _NET_WM_MOVERESIZE_MOVE_KEYBOARD    10   /* move via keyboard */
+#define _NET_WM_MOVERESIZE_CANCEL           11   /* cancel operation */
+
 static void
-wmspec_moveresize (GdkWindow *window,
-                   gint       direction,
-                   GdkDevice *device,
-                   gint       button,
-                   gint       root_x,
-                   gint       root_y,
-                   guint32    timestamp)
+wmspec_send_message (GdkDisplay *display,
+                     GdkWindow  *window,
+                     gint        root_x,
+                     gint        root_y,
+                     gint        action,
+                     gint        button)
 {
-  GdkDisplay *display = GDK_WINDOW_DISPLAY (window);
-  
   XClientMessageEvent xclient;
 
-  /* Release passive grab */
-  gdk_device_ungrab (device, timestamp);
-
   memset (&xclient, 0, sizeof (xclient));
   xclient.type = ClientMessage;
   xclient.window = GDK_WINDOW_XID (window);
@@ -4044,49 +4052,70 @@ wmspec_moveresize (GdkWindow *window,
   xclient.format = 32;
   xclient.data.l[0] = root_x;
   xclient.data.l[1] = root_y;
-  xclient.data.l[2] = direction;
+  xclient.data.l[2] = action;
   xclient.data.l[3] = button;
   xclient.data.l[4] = 1;  /* source indication */
 
   XSendEvent (GDK_DISPLAY_XDISPLAY (display), GDK_WINDOW_XROOTWIN (window), False,
-	      SubstructureRedirectMask | SubstructureNotifyMask,
-	      (XEvent *)&xclient);
+              SubstructureRedirectMask | SubstructureNotifyMask,
+              (XEvent *)&xclient);
 }
 
-typedef struct _MoveResizeData MoveResizeData;
+static gboolean
+handle_wmspec_button_release (GdkDisplay *display,
+                              XEvent     *xevent)
+{
+  GdkX11Display *display_x11 = GDK_X11_DISPLAY (display);
+  GdkWindow *window;
 
-struct _MoveResizeData
+#if defined (HAVE_XGENERICEVENTS) && defined (XINPUT_2)
+  XIEvent *xiev = (XIEvent *) xevent->xcookie.data;
+  XIDeviceEvent *xidev = (XIDeviceEvent *) xiev;
+
+  if (xevent->xany.type == GenericEvent)
+    window = gdk_x11_window_lookup_for_display (display, xidev->event);
+  else
+#endif
+    window = gdk_x11_window_lookup_for_display (display, xevent->xany.window);
+
+  if (display_x11->wm_moveresize_button != 0 && window != NULL)
+    {
+      if ((xevent->xany.type == ButtonRelease &&
+           xevent->xbutton.button == display_x11->wm_moveresize_button)
+#if defined (HAVE_XGENERICEVENTS) && defined (XINPUT_2)
+          ||
+          (xevent->xany.type == GenericEvent &&
+           xiev->evtype == XI_ButtonRelease &&
+           xidev->detail == display_x11->wm_moveresize_button)
+#endif
+          )
+        {
+          display_x11->wm_moveresize_button = 0;
+          wmspec_send_message (display, window, 0, 0, _NET_WM_MOVERESIZE_CANCEL, 0);
+          return TRUE;
+        }
+    }
+
+  return FALSE;
+}
+
+static void
+wmspec_moveresize (GdkWindow *window,
+                   gint       direction,
+                   GdkDevice *device,
+                   gint       button,
+                   gint       root_x,
+                   gint       root_y,
+                   guint32    timestamp)
 {
-  GdkDisplay *display;
-  
-  GdkWindow *moveresize_window;
-  GdkWindow *moveresize_emulation_window;
-  gboolean is_resize;
-  GdkWindowEdge resize_edge;
-  GdkDevice *device;
-  gint moveresize_button;
-  gint moveresize_x;
-  gint moveresize_y;
-  gint moveresize_orig_x;
-  gint moveresize_orig_y;
-  gint moveresize_orig_width;
-  gint moveresize_orig_height;
-  GdkWindowHints moveresize_geom_mask;
-  GdkGeometry moveresize_geometry;
-  Time moveresize_process_time;
-  XEvent *moveresize_pending_event;
-};
+  GdkDisplay *display = GDK_WINDOW_DISPLAY (window);
 
-/* From the WM spec */
-#define _NET_WM_MOVERESIZE_SIZE_TOPLEFT      0
-#define _NET_WM_MOVERESIZE_SIZE_TOP          1
-#define _NET_WM_MOVERESIZE_SIZE_TOPRIGHT     2
-#define _NET_WM_MOVERESIZE_SIZE_RIGHT        3
-#define _NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT  4
-#define _NET_WM_MOVERESIZE_SIZE_BOTTOM       5
-#define _NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT   6
-#define _NET_WM_MOVERESIZE_SIZE_LEFT         7
-#define _NET_WM_MOVERESIZE_MOVE              8
+  /* Release passive grab */
+  gdk_device_ungrab (device, timestamp);
+  GDK_X11_DISPLAY (display)->wm_moveresize_button = button;
+
+  wmspec_send_message (display, window, root_x, root_y, direction, button);
+}
 
 static void
 wmspec_resize_drag (GdkWindow     *window,
@@ -4145,6 +4174,30 @@ wmspec_resize_drag (GdkWindow     *window,
   wmspec_moveresize (window, direction, device, button, root_x, root_y, timestamp);
 }
 
+typedef struct _MoveResizeData MoveResizeData;
+
+struct _MoveResizeData
+{
+  GdkDisplay *display;
+
+  GdkWindow *moveresize_window;
+  GdkWindow *moveresize_emulation_window;
+  gboolean is_resize;
+  GdkWindowEdge resize_edge;
+  GdkDevice *device;
+  gint moveresize_button;
+  gint moveresize_x;
+  gint moveresize_y;
+  gint moveresize_orig_x;
+  gint moveresize_orig_y;
+  gint moveresize_orig_width;
+  gint moveresize_orig_height;
+  GdkWindowHints moveresize_geom_mask;
+  GdkGeometry moveresize_geometry;
+  Time moveresize_process_time;
+  XEvent *moveresize_pending_event;
+};
+
 static MoveResizeData *
 get_move_resize_data (GdkDisplay *display,
 		      gboolean    create)
@@ -4324,6 +4377,9 @@ _gdk_x11_moveresize_handle_event (XEvent *event)
   GdkDisplay *display = gdk_x11_lookup_xdisplay (event->xany.display);
   MoveResizeData *mv_resize = get_move_resize_data (display, FALSE);
 
+  if (handle_wmspec_button_release (display, event))
+    return TRUE;
+
   if (!mv_resize || !mv_resize->moveresize_window)
     return FALSE;
 
@@ -4405,6 +4461,8 @@ _gdk_x11_moveresize_configure_done (GdkDisplay *display,
   XEvent *tmp_event;
   MoveResizeData *mv_resize = get_move_resize_data (display, FALSE);
 
+  GDK_X11_DISPLAY (display)->wm_moveresize_button = 0;
+
   if (!mv_resize || window != mv_resize->moveresize_window)
     return FALSE;
 



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]