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)
return NULL;
if (meta_grab_op_windows_are_interactable (display->grab_op))
if (meta_display_windows_are_interactable (display))
{
if (tracker->has_window_cursor)
return tracker->window_cursor;

View File

@ -87,7 +87,7 @@
static gboolean
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);
@ -343,6 +343,7 @@ meta_begin_modal_for_plugin (MetaCompositor *compositor,
return FALSE;
display->grab_op = META_GRAB_OP_COMPOSITOR;
display->event_route = META_EVENT_ROUTE_COMPOSITOR_GRAB;
display->grab_window = NULL;
display->grab_have_pointer = 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_op = META_GRAB_OP_NONE;
display->event_route = META_EVENT_ROUTE_NORMAL;
display->grab_window = NULL;
display->grab_have_pointer = FALSE;
display->grab_have_keyboard = FALSE;

View File

@ -79,6 +79,24 @@ typedef enum {
META_TILE_MAXIMIZED
} 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
{
GObject parent_instance;
@ -174,6 +192,9 @@ struct _MetaDisplay
guint autoraise_timeout_id;
MetaWindow* autoraise_window;
/* Event routing */
MetaEventRoute event_route;
/* current window operation */
MetaGrabOp grab_op;
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_mouse (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_decrement_focus_sentinel (MetaDisplay *display);
@ -432,4 +452,6 @@ void meta_restart_finish (void);
void meta_display_cancel_touch (MetaDisplay *display);
gboolean meta_display_windows_are_interactable (MetaDisplay *display);
#endif

View File

@ -1264,15 +1264,15 @@ meta_grab_op_is_moving_or_resizing (MetaGrabOp op)
* meta_grab_op_windows_are_interactable:
* @op: A #MetaGrabOp
*
* Whether windows can be interacted with in this grab operation.
* Whether windows can be interacted with.
*/
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_GRAB_OP_NONE:
case META_EVENT_ROUTE_NORMAL:
case META_EVENT_ROUTE_WAYLAND_POPUP:
return TRUE;
default:
return FALSE;
@ -1444,7 +1444,7 @@ meta_display_sync_wayland_input_focus (MetaDisplay *display)
MetaWaylandCompositor *compositor = meta_wayland_compositor_get_default ();
MetaWindow *focus_window = NULL;
if (!meta_grab_op_windows_are_interactable (display->grab_op))
if (!meta_display_windows_are_interactable (display))
focus_window = NULL;
else if (meta_display_xwindow_is_a_no_focus_window (display, display->focus_xwindow))
focus_window = NULL;
@ -1753,6 +1753,48 @@ get_first_freefloating_window (MetaWindow *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
meta_display_begin_grab_op (MetaDisplay *display,
MetaScreen *screen,
@ -1768,6 +1810,7 @@ meta_display_begin_grab_op (MetaDisplay *display,
{
MetaBackend *backend = meta_get_backend ();
MetaWindow *grab_window = NULL;
MetaEventRoute event_route;
g_assert (window != NULL);
@ -1784,7 +1827,9 @@ meta_display_begin_grab_op (MetaDisplay *display,
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 ())
meta_window_raise (window);
@ -1830,8 +1875,8 @@ meta_display_begin_grab_op (MetaDisplay *display,
return FALSE;
}
/* Grab keys for keyboard ops and mouse move/resizes; see #126497 */
if (meta_grab_op_is_moving_or_resizing (op))
/* Grab keys when beginning window ops; see #126497 */
if (event_route == META_EVENT_ROUTE_WINDOW_OP)
{
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_window = grab_window;
display->grab_button = button;
@ -1884,7 +1930,8 @@ meta_display_begin_grab_op (MetaDisplay *display,
g_signal_emit (display, display_signals[GRAB_OP_BEGIN], 0,
screen, display->grab_window, display->grab_op);
meta_window_grab_op_began (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);
return TRUE;
}
@ -1899,13 +1946,13 @@ meta_display_end_grab_op (MetaDisplay *display,
meta_topic (META_DEBUG_WINDOW_OPS,
"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;
g_signal_emit (display, display_signals[GRAB_OP_END], 0,
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 */
meta_display_cleanup_edges (display);
@ -1919,6 +1966,8 @@ meta_display_end_grab_op (MetaDisplay *display,
if (!meta_prefs_get_raise_on_click () &&
display->grab_threshold_movement_reached)
meta_window_raise (display->grab_window);
meta_window_grab_op_ended (grab_window, grab_op);
}
if (display->grab_have_pointer)
@ -1934,10 +1983,11 @@ meta_display_end_grab_op (MetaDisplay *display,
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_tile_mode = META_TILE_NONE;
display->grab_tile_monitor_number = -1;
display->grab_op = META_GRAB_OP_NONE;
meta_display_update_cursor (display);
@ -1947,8 +1997,6 @@ meta_display_end_grab_op (MetaDisplay *display,
display->grab_resize_timeout_id = 0;
}
meta_window_grab_op_ended (grab_window, grab_op);
if (meta_is_wayland_compositor ())
meta_display_sync_wayland_input_focus (display);
}

View File

@ -45,9 +45,6 @@ get_window_for_event (MetaDisplay *display,
{
ClutterActor *source;
if (display->grab_op != META_GRAB_OP_NONE)
return display->grab_window;
/* Always use the key focused window for key events. */
switch (event->type)
{
@ -214,8 +211,7 @@ meta_display_handle_event (MetaDisplay *display,
goto out;
}
if (display->grab_window == window &&
meta_grab_op_is_moving_or_resizing (display->grab_op))
if (display->event_route == META_EVENT_ROUTE_WINDOW_OP)
{
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
* own sync grab. */
if (display->grab_window == window &&
meta_grab_op_is_moving_or_resizing (display->grab_op))
if (display->event_route == META_EVENT_ROUTE_WINDOW_OP)
{
bypass_clutter = TRUE;
bypass_wayland = TRUE;
@ -285,11 +280,11 @@ meta_display_handle_event (MetaDisplay *display,
out:
/* 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;
/* 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;
#ifdef HAVE_WAYLAND

View File

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