[mutter/wayland] Support X button events again
- From: Jasper St. Pierre <jstpierre src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [mutter/wayland] Support X button events again
- Date: Thu, 5 Dec 2013 22:45:54 +0000 (UTC)
commit fa65c380dbdd79f9849b3c70a5037743f8f88341
Author: Jasper St. Pierre <jstpierre mecheye net>
Date: Thu Dec 5 16:13:03 2013 -0500
Support X button events again
Do this by duplicating the current code and porting it to use
X again. A better approach would involve our own event structures,
and I really don't want to do that right now. We can clean this up
later.
src/core/display.c | 236 +++++++++++++++++++++++++++++++++++++++++++++
src/core/window-private.h | 6 +-
src/core/window.c | 217 ++++++++++++++++++++++++++++++++++++-----
3 files changed, 430 insertions(+), 29 deletions(-)
---
diff --git a/src/core/display.c b/src/core/display.c
index 5f9a536..f809caa 100644
--- a/src/core/display.c
+++ b/src/core/display.c
@@ -2229,9 +2229,11 @@ handle_input_xevent (MetaDisplay *display,
XIEvent *input_event,
gulong serial)
{
+ XIDeviceEvent *device_event = (XIDeviceEvent *) input_event;
XIEnterEvent *enter_event = (XIEnterEvent *) input_event;
Window modified;
MetaWindow *window;
+ gboolean frame_was_receiver;
if (input_event == NULL)
return FALSE;
@@ -2239,8 +2241,242 @@ handle_input_xevent (MetaDisplay *display,
modified = xievent_get_modified_window (display, input_event);
window = modified != None ? meta_display_lookup_x_window (display, modified) : NULL;
+ frame_was_receiver = FALSE;
+ if (window &&
+ window->frame &&
+ modified == window->frame->xwindow)
+ {
+ /* Note that if the frame and the client both have an
+ * XGrabButton (as is normal with our setup), the event
+ * goes to the frame.
+ */
+ frame_was_receiver = TRUE;
+ meta_topic (META_DEBUG_EVENTS, "Frame was receiver of event for %s\n",
+ window->desc);
+ }
+
+ if (window && !window->override_redirect &&
+ (input_event->evtype == XI_KeyPress || input_event->evtype == XI_ButtonPress))
+ {
+ if (CurrentTime == display->current_time)
+ {
+ /* We can't use missing (i.e. invalid) timestamps to set user time,
+ * nor do we want to use them to sanity check other timestamps.
+ * See bug 313490 for more details.
+ */
+ meta_warning ("Event has no timestamp! You may be using a broken "
+ "program such as xse. Please ask the authors of that "
+ "program to fix it.\n");
+ }
+ else
+ {
+ meta_window_set_user_time (window, display->current_time);
+ sanity_check_timestamps (display, display->current_time);
+ }
+ }
+
switch (input_event->evtype)
{
+ case XI_ButtonPress:
+ if (display->grab_op == META_GRAB_OP_COMPOSITOR)
+ break;
+
+ display->overlay_key_only_pressed = FALSE;
+
+ if (device_event->detail == 4 || device_event->detail == 5)
+ /* Scrollwheel event, do nothing and deliver event to compositor below */
+ break;
+
+ if ((window &&
+ meta_grab_op_is_mouse (display->grab_op) &&
+ (device_event->mods.effective & display->window_grab_modifiers) &&
+ display->grab_button != device_event->detail &&
+ display->grab_window == window) ||
+ grab_op_is_keyboard (display->grab_op))
+ {
+ meta_topic (META_DEBUG_WINDOW_OPS,
+ "Ending grab op %u on window %s due to button press\n",
+ display->grab_op,
+ (display->grab_window ?
+ display->grab_window->desc :
+ "none"));
+ if (GRAB_OP_IS_WINDOW_SWITCH (display->grab_op))
+ {
+ MetaScreen *screen;
+ meta_topic (META_DEBUG_WINDOW_OPS,
+ "Syncing to old stack positions.\n");
+ screen =
+ meta_display_screen_for_root (display, device_event->event);
+
+ if (screen!=NULL)
+ meta_stack_set_positions (screen->stack,
+ display->grab_old_window_stacking);
+ }
+ meta_display_end_grab_op (display,
+ device_event->time);
+ }
+ else if (window && display->grab_op == META_GRAB_OP_NONE)
+ {
+ gboolean begin_move = FALSE;
+ unsigned int grab_mask;
+ gboolean unmodified;
+
+ grab_mask = display->window_grab_modifiers;
+ if (g_getenv ("MUTTER_DEBUG_BUTTON_GRABS"))
+ grab_mask |= ControlMask;
+
+ /* Two possible sources of an unmodified event; one is a
+ * client that's letting button presses pass through to the
+ * frame, the other is our focus_window_grab on unmodified
+ * button 1. So for all such events we focus the window.
+ */
+ unmodified = (device_event->mods.effective & grab_mask) == 0;
+
+ if (unmodified ||
+ device_event->detail == 1)
+ {
+ /* don't focus if frame received, will be lowered in
+ * frames.c or special-cased if the click was on a
+ * minimize/close button.
+ */
+ if (!frame_was_receiver)
+ {
+ if (meta_prefs_get_raise_on_click ())
+ meta_window_raise (window);
+ else
+ meta_topic (META_DEBUG_FOCUS,
+ "Not raising window on click due to don't-raise-on-click option\n");
+
+ /* Don't focus panels--they must explicitly request focus.
+ * See bug 160470
+ */
+ if (window->type != META_WINDOW_DOCK)
+ {
+ meta_topic (META_DEBUG_FOCUS,
+ "Focusing %s due to unmodified button %u press (display.c)\n",
+ window->desc, device_event->detail);
+ meta_window_focus (window, device_event->time);
+ }
+ else
+ /* However, do allow terminals to lose focus due to new
+ * window mappings after the user clicks on a panel.
+ */
+ display->allow_terminal_deactivation = TRUE;
+ }
+
+ /* you can move on alt-click but not on
+ * the click-to-focus
+ */
+ if (!unmodified)
+ begin_move = TRUE;
+ }
+ else if (!unmodified && device_event->detail == meta_prefs_get_mouse_button_resize())
+ {
+ if (window->has_resize_func)
+ {
+ gboolean north, south;
+ gboolean west, east;
+ MetaRectangle frame_rect;
+ MetaGrabOp op;
+
+ meta_window_get_frame_rect (window, &frame_rect);
+
+ west = device_event->root_x < (frame_rect.x + 1 * frame_rect.width / 3);
+ east = device_event->root_x > (frame_rect.x + 2 * frame_rect.width / 3);
+ north = device_event->root_y < (frame_rect.y + 1 * frame_rect.height / 3);
+ south = device_event->root_y > (frame_rect.y + 2 * frame_rect.height / 3);
+
+ if (north && west)
+ op = META_GRAB_OP_RESIZING_NW;
+ else if (north && east)
+ op = META_GRAB_OP_RESIZING_NE;
+ else if (south && west)
+ op = META_GRAB_OP_RESIZING_SW;
+ else if (south && east)
+ op = META_GRAB_OP_RESIZING_SE;
+ else if (north)
+ op = META_GRAB_OP_RESIZING_N;
+ else if (west)
+ op = META_GRAB_OP_RESIZING_W;
+ else if (east)
+ op = META_GRAB_OP_RESIZING_E;
+ else if (south)
+ op = META_GRAB_OP_RESIZING_S;
+ else /* Middle region is no-op to avoid user triggering wrong action */
+ op = META_GRAB_OP_NONE;
+
+ if (op != META_GRAB_OP_NONE)
+ meta_display_begin_grab_op (display,
+ window->screen,
+ window,
+ op,
+ TRUE,
+ FALSE,
+ device_event->detail,
+ 0,
+ device_event->time,
+ device_event->root_x,
+ device_event->root_y);
+ }
+ }
+ else if (device_event->detail == meta_prefs_get_mouse_button_menu())
+ {
+ if (meta_prefs_get_raise_on_click ())
+ meta_window_raise (window);
+ meta_window_show_menu (window,
+ device_event->root_x,
+ device_event->root_y,
+ device_event->detail,
+ device_event->time);
+ }
+
+ if (!frame_was_receiver && unmodified)
+ {
+ /* This is from our synchronous grab since
+ * it has no modifiers and was on the client window
+ */
+
+ meta_verbose ("Allowing events time %u\n",
+ (unsigned int)device_event->time);
+
+ XIAllowEvents (display->xdisplay, device_event->deviceid,
+ XIReplayDevice, device_event->time);
+ }
+
+ if (begin_move && window->has_move_func)
+ {
+ meta_display_begin_grab_op (display,
+ window->screen,
+ window,
+ META_GRAB_OP_MOVING,
+ TRUE,
+ FALSE,
+ device_event->detail,
+ 0,
+ device_event->time,
+ device_event->root_x,
+ device_event->root_y);
+ }
+ }
+ break;
+ case XI_ButtonRelease:
+ if (display->grab_op == META_GRAB_OP_COMPOSITOR)
+ break;
+
+ display->overlay_key_only_pressed = FALSE;
+
+ if (display->grab_window == window &&
+ meta_grab_op_is_mouse (display->grab_op))
+ meta_window_handle_mouse_grab_op_xevent (window, device_event);
+ break;
+ case XI_Motion:
+ if (display->grab_op == META_GRAB_OP_COMPOSITOR)
+ break;
+
+ if (display->grab_window == window &&
+ meta_grab_op_is_mouse (display->grab_op))
+ meta_window_handle_mouse_grab_op_xevent (window, device_event);
+ break;
case XI_Enter:
if (display->grab_op == META_GRAB_OP_COMPOSITOR)
break;
diff --git a/src/core/window-private.h b/src/core/window-private.h
index 0f1630a..307129c 100644
--- a/src/core/window-private.h
+++ b/src/core/window-private.h
@@ -648,8 +648,10 @@ void meta_window_update_sync_request_counter (MetaWindow *window,
gint64 new_counter_value);
#endif /* HAVE_XSYNC */
-void meta_window_handle_mouse_grab_op_event (MetaWindow *window,
- const ClutterEvent *event);
+void meta_window_handle_mouse_grab_op_event (MetaWindow *window,
+ const ClutterEvent *event);
+void meta_window_handle_mouse_grab_op_xevent (MetaWindow *window,
+ XIDeviceEvent *xevent);
GList* meta_window_get_workspaces (MetaWindow *window);
diff --git a/src/core/window.c b/src/core/window.c
index bb334f3..3a3fde0 100644
--- a/src/core/window.c
+++ b/src/core/window.c
@@ -10029,20 +10029,96 @@ update_resize (MetaWindow *window,
g_get_current_time (&window->display->grab_last_moveresize_time);
}
+typedef struct
+{
+ Window window;
+ int count;
+ guint32 last_time;
+} EventScannerData;
+
+static Bool
+find_last_time_predicate (Display *display,
+ XEvent *ev,
+ XPointer arg)
+{
+ EventScannerData *esd = (void*) arg;
+ XIEvent *xev;
+
+ if (ev->type != GenericEvent)
+ return False;
+
+ /* We are peeking into events not yet handled by GDK,
+ * Allocate cookie events here so we can handle XI2.
+ *
+ * GDK will handle later these events, and eventually
+ * free the cookie data itself.
+ */
+ XGetEventData (display, &ev->xcookie);
+ xev = (XIEvent *) ev->xcookie.data;
+
+ if (xev->evtype != XI_Motion)
+ return False;
+
+ if (esd->window != ((XIDeviceEvent *) xev)->event)
+ return False;
+
+ esd->count += 1;
+ esd->last_time = xev->time;
+
+ return False;
+}
+
static gboolean
-check_use_this_motion_notify (MetaWindow *window,
- const ClutterEvent *event)
-{
- /* XXX: Previously this code would walk through the X event queue
- and filter out motion events that are followed by a later motion
- event. There currently isn't any API to do the equivalent
- procedure with the Clutter event queue so this function does
- nothing. Clutter does its own motion event squashing so it may be
- the case that this function isn't necessary. If it turns out that
- we do need additional motion event squashing we could add some
- extra API to the Clutter event queue and implement this function
- properly. */
- return TRUE;
+check_use_this_motion_notify (MetaWindow *window,
+ XIDeviceEvent *xev)
+{
+ EventScannerData esd;
+ XEvent useless;
+
+ /* This code is copied from Owen's GDK code. */
+
+ if (window->display->grab_motion_notify_time != 0)
+ {
+ /* == is really the right test, but I'm all for paranoia */
+ if (window->display->grab_motion_notify_time <=
+ xev->time)
+ {
+ meta_topic (META_DEBUG_RESIZING,
+ "Arrived at event with time %u (waiting for %u), using it\n",
+ (unsigned int)xev->time,
+ window->display->grab_motion_notify_time);
+ window->display->grab_motion_notify_time = 0;
+ return TRUE;
+ }
+ else
+ return FALSE; /* haven't reached the saved timestamp yet */
+ }
+
+ esd.window = xev->event;
+ esd.count = 0;
+ esd.last_time = 0;
+
+ /* "useless" isn't filled in because the predicate never returns True */
+ XCheckIfEvent (window->display->xdisplay,
+ &useless,
+ find_last_time_predicate,
+ (XPointer) &esd);
+
+ if (esd.count > 0)
+ meta_topic (META_DEBUG_RESIZING,
+ "Will skip %d motion events and use the event with time %u\n",
+ esd.count, (unsigned int) esd.last_time);
+
+ if (esd.last_time == 0)
+ return TRUE;
+ else
+ {
+ /* Save this timestamp, and ignore all motion notify
+ * until we get to the one with this stamp.
+ */
+ window->display->grab_motion_notify_time = esd.last_time;
+ return FALSE;
+ }
}
static void
@@ -10116,8 +10192,98 @@ meta_window_update_sync_request_counter (MetaWindow *window,
#endif /* HAVE_XSYNC */
void
-meta_window_handle_mouse_grab_op_event (MetaWindow *window,
- const ClutterEvent *event)
+meta_window_handle_mouse_grab_op_xevent (MetaWindow *window,
+ XIDeviceEvent *xevent)
+{
+ gboolean is_window_root = (xevent->root == window->screen->xroot);
+
+ switch (xevent->evtype)
+ {
+ case XI_ButtonRelease:
+ if (xevent->detail == 1 ||
+ xevent->detail == meta_prefs_get_mouse_button_resize ())
+ {
+ meta_display_check_threshold_reached (window->display,
+ xevent->root_x,
+ xevent->root_y);
+ /* If the user was snap moving then ignore the button
+ * release because they may have let go of shift before
+ * releasing the mouse button and they almost certainly do
+ * not want a non-snapped movement to occur from the button
+ * release.
+ */
+ if (!window->display->grab_last_user_action_was_snap)
+ {
+ if (meta_grab_op_is_moving (window->display->grab_op))
+ {
+ if (window->tile_mode != META_TILE_NONE)
+ meta_window_tile (window);
+ else if (is_window_root)
+ update_move (window,
+ xevent->mods.effective & ShiftMask,
+ xevent->root_x,
+ xevent->root_y);
+ }
+ else if (meta_grab_op_is_resizing (window->display->grab_op))
+ {
+ if (is_window_root)
+ update_resize (window,
+ xevent->mods.effective & ShiftMask,
+ xevent->root_x,
+ xevent->root_y,
+ TRUE);
+
+ /* If a tiled window has been dragged free with a
+ * mouse resize without snapping back to the tiled
+ * state, it will end up with an inconsistent tile
+ * mode on mouse release; cleaning the mode earlier
+ * would break the ability to snap back to the tiled
+ * state, so we wait until mouse release.
+ */
+ update_tile_mode (window);
+ }
+ meta_display_end_grab_op (window->display, xevent->time);
+ }
+ }
+ break;
+
+ case XI_Motion:
+ meta_display_check_threshold_reached (window->display,
+ xevent->root_x,
+ xevent->root_y);
+ if (meta_grab_op_is_moving (window->display->grab_op))
+ {
+ if (is_window_root)
+ {
+ if (check_use_this_motion_notify (window, xevent))
+ update_move (window,
+ xevent->mods.effective & ShiftMask,
+ xevent->root_x,
+ xevent->root_y);
+ }
+ }
+ else if (meta_grab_op_is_resizing (window->display->grab_op))
+ {
+ if (is_window_root)
+ {
+ if (check_use_this_motion_notify (window, xevent))
+ update_resize (window,
+ xevent->mods.effective & ShiftMask,
+ xevent->root_x,
+ xevent->root_y,
+ FALSE);
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+void
+meta_window_handle_mouse_grab_op_event (MetaWindow *window,
+ const ClutterEvent *event)
{
gboolean is_window_root = (event->any.stage != NULL &&
window &&
@@ -10170,7 +10336,6 @@ meta_window_handle_mouse_grab_op_event (MetaWindow *window,
*/
update_tile_mode (window);
}
-
meta_display_end_grab_op (window->display, event->any.time);
}
}
@@ -10184,23 +10349,21 @@ meta_window_handle_mouse_grab_op_event (MetaWindow *window,
{
if (is_window_root)
{
- if (check_use_this_motion_notify (window, event))
- update_move (window,
- event->button.modifier_state & CLUTTER_SHIFT_MASK,
- event->motion.x,
- event->motion.y);
+ update_move (window,
+ event->button.modifier_state & CLUTTER_SHIFT_MASK,
+ event->motion.x,
+ event->motion.y);
}
}
else if (meta_grab_op_is_resizing (window->display->grab_op))
{
if (is_window_root)
{
- if (check_use_this_motion_notify (window, event))
- update_resize (window,
- event->button.modifier_state & CLUTTER_SHIFT_MASK,
- event->motion.x,
- event->motion.y,
- FALSE);
+ update_resize (window,
+ event->button.modifier_state & CLUTTER_SHIFT_MASK,
+ event->motion.x,
+ event->motion.y,
+ FALSE);
}
}
break;
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]