From d05b750b8dec3825d286e3ae30c41b41bd6aed98 Mon Sep 17 00:00:00 2001 From: Carlos Garnacho Date: Thu, 19 Jun 2014 23:26:15 +0200 Subject: [PATCH] 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 | 90 ++++++++++++++++++++++++++++++++++++++----------- src/ui/frames.h | 6 ++++ src/ui/ui.c | 3 ++ 3 files changed, 80 insertions(+), 19 deletions(-) diff --git a/src/ui/frames.c b/src/ui/frames.c index 3339b1e3f..743e90c1e 100644 --- a/src/ui/frames.c +++ b/src/ui/frames.c @@ -1136,6 +1136,64 @@ meta_frame_right_click_event(MetaUIFrame *frame, return meta_frame_titlebar_event (frame, event, action); } +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) @@ -1190,6 +1248,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 || @@ -1293,16 +1353,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) @@ -1315,16 +1368,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) @@ -1349,6 +1396,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) @@ -1560,6 +1608,10 @@ meta_frames_motion_notify_event (GtkWidget *widget, meta_frames_update_prelit_control (frames, frame, control); } + if ((event->state & GDK_BUTTON1_MASK) && + frames->current_grab_op != META_GRAB_OP_NONE) + meta_frames_retry_grab_op (frames, event->time); + return TRUE; } diff --git a/src/ui/frames.h b/src/ui/frames.h index d0af95d68..3a29ffd31 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 4ca859538..1acb70c44 100644 --- a/src/ui/ui.c +++ b/src/ui/ui.c @@ -221,6 +221,9 @@ maybe_redirect_mouse_event (XEvent *xevent) 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: