[mutter/wip/gestures: 13/14] frames: Keep information about the ongoing grab operation, and retry if needed.



commit 712f5df93e73102fd08fa362f2f57b1d56d9a0ad
Author: Carlos Garnacho <carlosg gnome org>
Date:   Thu Jun 19 23:26:15 2014 +0200

    frames: Keep information about the ongoing grab operation, and retry if needed.
    
    When a passive touch grab is rejected over the frame, management is punted to
    the frame itself, and pointer events emulated, but the attempt to transfer the
    grab from the GDK connection to the Clutter one fails with AlreadyGrabbed, and
    will fail until the Clutter connection receives the XI_TouchEnd resulting from
    XIRejectTouch, gotten after the XI_ButtonPress on the GDK connection.
    
    In order to bypass this shortcoming, store the current grab operation on the
    frame as long as the button is pressed, so it is retried once on the next
    motion event happening during frame dragging, that will have a recent enough
    timestamp to succeed. If no grabbing succeeded, the current grab operation
    data will be reset on GDK_BUTTON_RELEASE.

 src/ui/frames.c |   92 +++++++++++++++++++++++++++++++++++++++++++-----------
 src/ui/frames.h |    6 +++
 src/ui/ui.c     |    6 +++
 3 files changed, 85 insertions(+), 19 deletions(-)
---
diff --git a/src/ui/frames.c b/src/ui/frames.c
index e88c704..79c535e 100644
--- a/src/ui/frames.c
+++ b/src/ui/frames.c
@@ -1139,6 +1139,64 @@ meta_frame_right_click_event(MetaUIFrame     *frame,
 }
 
 static gboolean
+meta_frames_try_grab_op (MetaFrames  *frames,
+                         MetaUIFrame *frame,
+                         MetaGrabOp   op,
+                         gdouble      grab_x,
+                         gdouble      grab_y,
+                         guint32      time)
+{
+  Display *display;
+  gboolean ret;
+
+  display = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ());
+  ret = meta_core_begin_grab_op (display,
+                                 frame->xwindow,
+                                 op,
+                                 FALSE,
+                                 TRUE,
+                                 frame->grab_button,
+                                 0,
+                                 time,
+                                 grab_x, grab_y);
+  if (!ret)
+    {
+      frames->current_grab_op = op;
+      frames->grab_frame = frame;
+      frames->grab_x = grab_x;
+      frames->grab_y = grab_y;
+    }
+
+  return ret;
+}
+
+static gboolean
+meta_frames_retry_grab_op (MetaFrames *frames,
+                           guint       time)
+{
+  Display *display;
+  MetaGrabOp op;
+
+  if (frames->current_grab_op == META_GRAB_OP_NONE)
+    return TRUE;
+
+  op = frames->current_grab_op;
+  frames->current_grab_op = META_GRAB_OP_NONE;
+  display = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ());
+
+  return meta_core_begin_grab_op (display,
+                                  frames->grab_frame->xwindow,
+                                  op,
+                                  FALSE,
+                                  TRUE,
+                                  frames->grab_frame->grab_button,
+                                  0,
+                                  time,
+                                  frames->grab_x,
+                                  frames->grab_y);
+}
+
+static gboolean
 meta_frames_button_press_event (GtkWidget      *widget,
                                 GdkEventButton *event)
 {
@@ -1192,6 +1250,8 @@ meta_frames_button_press_event (GtkWidget      *widget,
   if (meta_core_get_grab_op (display) != META_GRAB_OP_NONE)
     return FALSE; /* already up to something */
 
+  frame->grab_button = event->button;
+
   if (event->button == 1 &&
       (control == META_FRAME_CONTROL_MAXIMIZE ||
        control == META_FRAME_CONTROL_UNMAXIMIZE ||
@@ -1295,16 +1355,9 @@ meta_frames_button_press_event (GtkWidget      *widget,
           break;
         }
 
-      meta_core_begin_grab_op (display,
-                               frame->xwindow,
-                               op,
-                               TRUE,
-                               TRUE,
-                               event->button,
-                               0,
-                               event->time,
-                               event->x_root,
-                               event->y_root);
+      meta_frames_try_grab_op (frames, frame, op,
+                               event->x_root, event->y_root,
+                               event->time);
     }
   else if (control == META_FRAME_CONTROL_TITLE &&
            event->button == 1)
@@ -1317,16 +1370,10 @@ meta_frames_button_press_event (GtkWidget      *widget,
 
       if (flags & META_FRAME_ALLOWS_MOVE)
         {
-          meta_core_begin_grab_op (display,
-                                   frame->xwindow,
+          meta_frames_try_grab_op (frames, frame,
                                    META_GRAB_OP_MOVING,
-                                   TRUE,
-                                   TRUE,
-                                   event->button,
-                                   0,
-                                   event->time,
-                                   event->x_root,
-                                   event->y_root);
+                                   event->x_root, event->y_root,
+                                   event->time);
         }
     }
   else if (event->button == 2)
@@ -1351,6 +1398,7 @@ meta_frames_button_release_event    (GtkWidget           *widget,
 
   frames = META_FRAMES (widget);
   display = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ());
+  frames->current_grab_op = META_GRAB_OP_NONE;
 
   frame = meta_frames_lookup_window (frames, GDK_WINDOW_XID (event->window));
   if (frame == NULL)
@@ -1546,6 +1594,12 @@ meta_frames_motion_notify_event     (GtkWidget           *widget,
                                   &x, &y, NULL);
   control = get_control (frames, frame, x, y);
 
+  if (event->state & GDK_BUTTON1_MASK)
+    {
+      meta_frames_retry_grab_op (frames, event->time);
+      return TRUE;
+    }
+
   if (frame->button_state == META_BUTTON_STATE_PRESSED)
     {
       /* If the user leaves the frame button, set the state
diff --git a/src/ui/frames.h b/src/ui/frames.h
index d0af95d..3a29ffd 100644
--- a/src/ui/frames.h
+++ b/src/ui/frames.h
@@ -100,6 +100,12 @@ struct _MetaFrames
   GtkStyleContext *normal_style;
   GHashTable *style_variants;
 
+  MetaGrabOp current_grab_op;
+  MetaUIFrame *grab_frame;
+  guint grab_button;
+  gdouble grab_x;
+  gdouble grab_y;
+
   Window grab_xwindow;
 };
 
diff --git a/src/ui/ui.c b/src/ui/ui.c
index bc89a19..96f4994 100644
--- a/src/ui/ui.c
+++ b/src/ui/ui.c
@@ -205,6 +205,12 @@ maybe_redirect_mouse_event (XEvent *xevent)
       gevent = gdk_event_new (GDK_MOTION_NOTIFY);
       gevent->motion.type = GDK_MOTION_NOTIFY;
       gevent->motion.window = g_object_ref (gdk_window);
+      gevent->motion.time = xev_d->time;
+      gevent->motion.x_root = xev_d->root_x;
+      gevent->motion.y_root = xev_d->root_y;
+
+      if (XIMaskIsSet (xev_d->buttons.mask, 1))
+        gevent->motion.state |= GDK_BUTTON1_MASK;
       break;
     case XI_Enter:
     case XI_Leave:


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