display: Establish a separate state variable for routing events

We've long used a switch statement on the grab operation to determine
where events should go. The issue with MetaGrabOp is that it's a mixture
of a few different things, including event routing, state management,
and the behavior to choose during operations.

This leads to poorly defined event routing and hard-to-follow logic,
since it's sometimes unclear what should point where, and our utility
methods for determining grab operations apart can be poorly named.

To fix this, establish the concept of a "event route", which describes
where events should be routed to.
This commit is contained in:
Jasper St. Pierre 2014-08-15 13:12:22 -04:00
parent 64a915a68d
commit 0e758a9e65
6 changed files with 107 additions and 34 deletions

View File

@ -61,7 +61,7 @@ get_displayed_cursor (MetaCursorTracker *tracker)
if (!tracker->is_showing) if (!tracker->is_showing)
return NULL; return NULL;
if (meta_grab_op_windows_are_interactable (display->grab_op)) if (meta_display_windows_are_interactable (display))
{ {
if (tracker->has_window_cursor) if (tracker->has_window_cursor)
return tracker->window_cursor; return tracker->window_cursor;

View File

@ -87,7 +87,7 @@
static gboolean static gboolean
is_modal (MetaDisplay *display) is_modal (MetaDisplay *display)
{ {
return display->grab_op == META_GRAB_OP_COMPOSITOR; return display->event_route == META_EVENT_ROUTE_COMPOSITOR_GRAB;
} }
static void sync_actor_stacking (MetaCompositor *compositor); static void sync_actor_stacking (MetaCompositor *compositor);
@ -343,6 +343,7 @@ meta_begin_modal_for_plugin (MetaCompositor *compositor,
return FALSE; return FALSE;
display->grab_op = META_GRAB_OP_COMPOSITOR; display->grab_op = META_GRAB_OP_COMPOSITOR;
display->event_route = META_EVENT_ROUTE_COMPOSITOR_GRAB;
display->grab_window = NULL; display->grab_window = NULL;
display->grab_have_pointer = TRUE; display->grab_have_pointer = TRUE;
display->grab_have_keyboard = TRUE; display->grab_have_keyboard = TRUE;
@ -375,6 +376,7 @@ meta_end_modal_for_plugin (MetaCompositor *compositor,
display->grab_window, display->grab_op); display->grab_window, display->grab_op);
display->grab_op = META_GRAB_OP_NONE; display->grab_op = META_GRAB_OP_NONE;
display->event_route = META_EVENT_ROUTE_NORMAL;
display->grab_window = NULL; display->grab_window = NULL;
display->grab_have_pointer = FALSE; display->grab_have_pointer = FALSE;
display->grab_have_keyboard = FALSE; display->grab_have_keyboard = FALSE;

View File

@ -79,6 +79,24 @@ typedef enum {
META_TILE_MAXIMIZED META_TILE_MAXIMIZED
} MetaTileMode; } MetaTileMode;
typedef enum {
/* Normal interaction where you're interacting with windows.
* Events go to windows normally. */
META_EVENT_ROUTE_NORMAL,
/* In a compositor grab operation. All events go to the
* compositor plugin. */
META_EVENT_ROUTE_COMPOSITOR_GRAB,
/* A Wayland application has a popup open. All events go to
* the Wayland application. */
META_EVENT_ROUTE_WAYLAND_POPUP,
/* In a window operation like moving or resizing. All events
* goes to MetaWindow, but not to the actual client window. */
META_EVENT_ROUTE_WINDOW_OP,
} MetaEventRoute;
struct _MetaDisplay struct _MetaDisplay
{ {
GObject parent_instance; GObject parent_instance;
@ -174,6 +192,9 @@ struct _MetaDisplay
guint autoraise_timeout_id; guint autoraise_timeout_id;
MetaWindow* autoraise_window; MetaWindow* autoraise_window;
/* Event routing */
MetaEventRoute event_route;
/* current window operation */ /* current window operation */
MetaGrabOp grab_op; MetaGrabOp grab_op;
MetaWindow *grab_window; MetaWindow *grab_window;
@ -380,7 +401,6 @@ gboolean meta_grab_op_is_resizing (MetaGrabOp op);
gboolean meta_grab_op_is_moving_or_resizing (MetaGrabOp op); gboolean meta_grab_op_is_moving_or_resizing (MetaGrabOp op);
gboolean meta_grab_op_is_mouse (MetaGrabOp op); gboolean meta_grab_op_is_mouse (MetaGrabOp op);
gboolean meta_grab_op_is_keyboard (MetaGrabOp op); gboolean meta_grab_op_is_keyboard (MetaGrabOp op);
gboolean meta_grab_op_windows_are_interactable (MetaGrabOp op);
void meta_display_increment_focus_sentinel (MetaDisplay *display); void meta_display_increment_focus_sentinel (MetaDisplay *display);
void meta_display_decrement_focus_sentinel (MetaDisplay *display); void meta_display_decrement_focus_sentinel (MetaDisplay *display);
@ -432,4 +452,6 @@ void meta_restart_finish (void);
void meta_display_cancel_touch (MetaDisplay *display); void meta_display_cancel_touch (MetaDisplay *display);
gboolean meta_display_windows_are_interactable (MetaDisplay *display);
#endif #endif

View File

@ -1264,15 +1264,15 @@ meta_grab_op_is_moving_or_resizing (MetaGrabOp op)
* meta_grab_op_windows_are_interactable: * meta_grab_op_windows_are_interactable:
* @op: A #MetaGrabOp * @op: A #MetaGrabOp
* *
* Whether windows can be interacted with in this grab operation. * Whether windows can be interacted with.
*/ */
gboolean gboolean
meta_grab_op_windows_are_interactable (MetaGrabOp op) meta_display_windows_are_interactable (MetaDisplay *display)
{ {
switch (op) switch (display->event_route)
{ {
case META_GRAB_OP_WAYLAND_POPUP: case META_EVENT_ROUTE_NORMAL:
case META_GRAB_OP_NONE: case META_EVENT_ROUTE_WAYLAND_POPUP:
return TRUE; return TRUE;
default: default:
return FALSE; return FALSE;
@ -1444,7 +1444,7 @@ meta_display_sync_wayland_input_focus (MetaDisplay *display)
MetaWaylandCompositor *compositor = meta_wayland_compositor_get_default (); MetaWaylandCompositor *compositor = meta_wayland_compositor_get_default ();
MetaWindow *focus_window = NULL; MetaWindow *focus_window = NULL;
if (!meta_grab_op_windows_are_interactable (display->grab_op)) if (!meta_display_windows_are_interactable (display))
focus_window = NULL; focus_window = NULL;
else if (meta_display_xwindow_is_a_no_focus_window (display, display->focus_xwindow)) else if (meta_display_xwindow_is_a_no_focus_window (display, display->focus_xwindow))
focus_window = NULL; focus_window = NULL;
@ -1753,6 +1753,48 @@ get_first_freefloating_window (MetaWindow *window)
return window; return window;
} }
static MetaEventRoute
get_event_route_from_grab_op (MetaGrabOp op)
{
switch (op)
{
case META_GRAB_OP_NONE:
/* begin_grab_op shouldn't be called with META_GRAB_OP_NONE. */
g_assert_not_reached ();
case META_GRAB_OP_MOVING:
case META_GRAB_OP_RESIZING_SE:
case META_GRAB_OP_RESIZING_S:
case META_GRAB_OP_RESIZING_SW:
case META_GRAB_OP_RESIZING_N:
case META_GRAB_OP_RESIZING_NE:
case META_GRAB_OP_RESIZING_NW:
case META_GRAB_OP_RESIZING_W:
case META_GRAB_OP_RESIZING_E:
case META_GRAB_OP_KEYBOARD_MOVING:
case META_GRAB_OP_KEYBOARD_RESIZING_UNKNOWN:
case META_GRAB_OP_KEYBOARD_RESIZING_S:
case META_GRAB_OP_KEYBOARD_RESIZING_N:
case META_GRAB_OP_KEYBOARD_RESIZING_W:
case META_GRAB_OP_KEYBOARD_RESIZING_E:
case META_GRAB_OP_KEYBOARD_RESIZING_SE:
case META_GRAB_OP_KEYBOARD_RESIZING_NE:
case META_GRAB_OP_KEYBOARD_RESIZING_SW:
case META_GRAB_OP_KEYBOARD_RESIZING_NW:
return META_EVENT_ROUTE_WINDOW_OP;
case META_GRAB_OP_COMPOSITOR:
/* begin_grab_op shouldn't be called with META_GRAB_OP_COMPOSITOR. */
g_assert_not_reached ();
case META_GRAB_OP_WAYLAND_POPUP:
return META_EVENT_ROUTE_WAYLAND_POPUP;
default:
g_assert_not_reached ();
}
}
gboolean gboolean
meta_display_begin_grab_op (MetaDisplay *display, meta_display_begin_grab_op (MetaDisplay *display,
MetaScreen *screen, MetaScreen *screen,
@ -1768,6 +1810,7 @@ meta_display_begin_grab_op (MetaDisplay *display,
{ {
MetaBackend *backend = meta_get_backend (); MetaBackend *backend = meta_get_backend ();
MetaWindow *grab_window = NULL; MetaWindow *grab_window = NULL;
MetaEventRoute event_route;
g_assert (window != NULL); g_assert (window != NULL);
@ -1784,7 +1827,9 @@ meta_display_begin_grab_op (MetaDisplay *display,
return FALSE; return FALSE;
} }
if (meta_grab_op_is_moving_or_resizing (op)) event_route = get_event_route_from_grab_op (op);
if (event_route == META_EVENT_ROUTE_WINDOW_OP)
{ {
if (meta_prefs_get_raise_on_click ()) if (meta_prefs_get_raise_on_click ())
meta_window_raise (window); meta_window_raise (window);
@ -1830,8 +1875,8 @@ meta_display_begin_grab_op (MetaDisplay *display,
return FALSE; return FALSE;
} }
/* Grab keys for keyboard ops and mouse move/resizes; see #126497 */ /* Grab keys when beginning window ops; see #126497 */
if (meta_grab_op_is_moving_or_resizing (op)) if (event_route == META_EVENT_ROUTE_WINDOW_OP)
{ {
display->grab_have_keyboard = meta_window_grab_all_keys (grab_window, timestamp); display->grab_have_keyboard = meta_window_grab_all_keys (grab_window, timestamp);
@ -1844,6 +1889,7 @@ meta_display_begin_grab_op (MetaDisplay *display,
} }
} }
display->event_route = event_route;
display->grab_op = op; display->grab_op = op;
display->grab_window = grab_window; display->grab_window = grab_window;
display->grab_button = button; display->grab_button = button;
@ -1884,6 +1930,7 @@ meta_display_begin_grab_op (MetaDisplay *display,
g_signal_emit (display, display_signals[GRAB_OP_BEGIN], 0, g_signal_emit (display, display_signals[GRAB_OP_BEGIN], 0,
screen, display->grab_window, display->grab_op); screen, display->grab_window, display->grab_op);
if (display->event_route == META_EVENT_ROUTE_WINDOW_OP)
meta_window_grab_op_began (display->grab_window, display->grab_op); meta_window_grab_op_began (display->grab_window, display->grab_op);
return TRUE; return TRUE;
@ -1899,13 +1946,13 @@ meta_display_end_grab_op (MetaDisplay *display,
meta_topic (META_DEBUG_WINDOW_OPS, meta_topic (META_DEBUG_WINDOW_OPS,
"Ending grab op %u at time %u\n", grab_op, timestamp); "Ending grab op %u at time %u\n", grab_op, timestamp);
if (display->grab_op == META_GRAB_OP_NONE) if (display->event_route == META_EVENT_ROUTE_NORMAL)
return; return;
g_signal_emit (display, display_signals[GRAB_OP_END], 0, g_signal_emit (display, display_signals[GRAB_OP_END], 0,
display->screen, grab_window, grab_op); display->screen, grab_window, grab_op);
if (meta_grab_op_is_moving_or_resizing (grab_op)) if (display->event_route == META_EVENT_ROUTE_WINDOW_OP)
{ {
/* Clear out the edge cache */ /* Clear out the edge cache */
meta_display_cleanup_edges (display); meta_display_cleanup_edges (display);
@ -1919,6 +1966,8 @@ meta_display_end_grab_op (MetaDisplay *display,
if (!meta_prefs_get_raise_on_click () && if (!meta_prefs_get_raise_on_click () &&
display->grab_threshold_movement_reached) display->grab_threshold_movement_reached)
meta_window_raise (display->grab_window); meta_window_raise (display->grab_window);
meta_window_grab_op_ended (grab_window, grab_op);
} }
if (display->grab_have_pointer) if (display->grab_have_pointer)
@ -1934,10 +1983,11 @@ meta_display_end_grab_op (MetaDisplay *display,
meta_window_ungrab_all_keys (grab_window, timestamp); meta_window_ungrab_all_keys (grab_window, timestamp);
} }
display->event_route = META_EVENT_ROUTE_NORMAL;
display->grab_op = META_GRAB_OP_NONE;
display->grab_window = NULL; display->grab_window = NULL;
display->grab_tile_mode = META_TILE_NONE; display->grab_tile_mode = META_TILE_NONE;
display->grab_tile_monitor_number = -1; display->grab_tile_monitor_number = -1;
display->grab_op = META_GRAB_OP_NONE;
meta_display_update_cursor (display); meta_display_update_cursor (display);
@ -1947,8 +1997,6 @@ meta_display_end_grab_op (MetaDisplay *display,
display->grab_resize_timeout_id = 0; display->grab_resize_timeout_id = 0;
} }
meta_window_grab_op_ended (grab_window, grab_op);
if (meta_is_wayland_compositor ()) if (meta_is_wayland_compositor ())
meta_display_sync_wayland_input_focus (display); meta_display_sync_wayland_input_focus (display);
} }

View File

@ -45,9 +45,6 @@ get_window_for_event (MetaDisplay *display,
{ {
ClutterActor *source; ClutterActor *source;
if (display->grab_op != META_GRAB_OP_NONE)
return display->grab_window;
/* Always use the key focused window for key events. */ /* Always use the key focused window for key events. */
switch (event->type) switch (event->type)
{ {
@ -214,8 +211,7 @@ meta_display_handle_event (MetaDisplay *display,
goto out; goto out;
} }
if (display->grab_window == window && if (display->event_route == META_EVENT_ROUTE_WINDOW_OP)
meta_grab_op_is_moving_or_resizing (display->grab_op))
{ {
if (meta_window_handle_mouse_grab_op_event (window, event)) if (meta_window_handle_mouse_grab_op_event (window, event))
{ {
@ -256,8 +252,7 @@ meta_display_handle_event (MetaDisplay *display,
* event, and if it doesn't, replay the event to release our * event, and if it doesn't, replay the event to release our
* own sync grab. */ * own sync grab. */
if (display->grab_window == window && if (display->event_route == META_EVENT_ROUTE_WINDOW_OP)
meta_grab_op_is_moving_or_resizing (display->grab_op))
{ {
bypass_clutter = TRUE; bypass_clutter = TRUE;
bypass_wayland = TRUE; bypass_wayland = TRUE;
@ -285,11 +280,11 @@ meta_display_handle_event (MetaDisplay *display,
out: out:
/* If the compositor has a grab, don't pass that through to Wayland */ /* If the compositor has a grab, don't pass that through to Wayland */
if (display->grab_op == META_GRAB_OP_COMPOSITOR) if (display->event_route == META_EVENT_ROUTE_COMPOSITOR_GRAB)
bypass_wayland = TRUE; bypass_wayland = TRUE;
/* If a Wayland client has a grab, don't pass that through to Clutter */ /* If a Wayland client has a grab, don't pass that through to Clutter */
if (display->grab_op == META_GRAB_OP_WAYLAND_POPUP) if (display->event_route == META_EVENT_ROUTE_WAYLAND_POPUP)
bypass_clutter = TRUE; bypass_clutter = TRUE;
#ifdef HAVE_WAYLAND #ifdef HAVE_WAYLAND

View File

@ -246,14 +246,20 @@ sync_focus_surface (MetaWaylandPointer *pointer)
MetaDisplay *display = meta_get_display (); MetaDisplay *display = meta_get_display ();
MetaWaylandSurface *focus_surface; MetaWaylandSurface *focus_surface;
/* Don't update the focus surface while we have a move/resize grab. */ switch (display->event_route)
if (meta_grab_op_is_moving_or_resizing (display->grab_op)) {
case META_EVENT_ROUTE_WINDOW_OP:
/* Don't update the focus surface while we're grabbing a window. */
return; return;
if (!meta_grab_op_windows_are_interactable (display->grab_op)) case META_EVENT_ROUTE_COMPOSITOR_GRAB:
/* The compositor has focus, so remove our focus... */
focus_surface = NULL; focus_surface = NULL;
else
case META_EVENT_ROUTE_NORMAL:
case META_EVENT_ROUTE_WAYLAND_POPUP:
focus_surface = pointer->current; focus_surface = pointer->current;
}
if (focus_surface != pointer->focus_surface) if (focus_surface != pointer->focus_surface)
{ {