wayland: add inhibit shortcut mechanism

Add a mechanism to MetaWaylandSurface that inhibits compositor's own
shortcuts when the surface has input focus, so that clients can receive
all key events regardless of the compositor own shortcuts.

This will help with implementing "fake" active grabs in Wayland and
XWayland clients.

https://bugzilla.gnome.org/show_bug.cgi?id=783342
This commit is contained in:
Olivier Fourdan 2017-03-17 13:34:52 +01:00
parent c54377e3ba
commit dd12f569d9
11 changed files with 222 additions and 15 deletions

View File

@ -49,5 +49,9 @@
<default><![CDATA[['<Primary><Alt>F12']]]></default> <default><![CDATA[['<Primary><Alt>F12']]]></default>
<summary>Switch to VT 12</summary> <summary>Switch to VT 12</summary>
</key> </key>
<key name="restore-shortcuts" type="as">
<default><![CDATA[['<Shift><Control>Escape']]]></default>
<summary>Re-enable shortcuts</summary>
</key>
</schema> </schema>
</schemalist> </schemalist>

View File

@ -1716,6 +1716,16 @@ process_event (MetaDisplay *display,
(!window && binding->flags & META_KEY_BINDING_PER_WINDOW)) (!window && binding->flags & META_KEY_BINDING_PER_WINDOW))
goto not_found; goto not_found;
if (display->focus_window &&
!(binding->handler->flags & META_KEY_BINDING_NON_MASKABLE))
{
ClutterInputDevice *source;
source = clutter_event_get_source_device ((ClutterEvent *) event);
if (meta_window_shortcuts_inhibited (display->focus_window, source))
goto not_found;
}
/* If the compositor filtered out the keybindings, that /* If the compositor filtered out the keybindings, that
* means they don't want the binding to trigger, so we do * means they don't want the binding to trigger, so we do
* the same thing as if the binding didn't exist. */ * the same thing as if the binding didn't exist. */
@ -3364,6 +3374,23 @@ handle_rotate_monitor (MetaDisplay *display,
meta_monitor_manager_rotate_monitor (monitor_manager); meta_monitor_manager_rotate_monitor (monitor_manager);
} }
static void
handle_restore_shortcuts (MetaDisplay *display,
MetaScreen *screen,
MetaWindow *window,
ClutterKeyEvent *event,
MetaKeyBinding *binding,
gpointer dummy)
{
ClutterInputDevice *source;
source = clutter_event_get_source_device ((ClutterEvent *) event);
meta_topic (META_DEBUG_KEYBINDINGS, "Restoring normal keyboard shortcuts\n");
meta_window_force_restore_shortcuts (display->focus_window, source);
}
/** /**
* meta_keybindings_set_custom_handler: * meta_keybindings_set_custom_handler:
* @name: The name of the keybinding to set * @name: The name of the keybinding to set
@ -3674,89 +3701,96 @@ init_builtin_key_bindings (MetaDisplay *display)
add_builtin_keybinding (display, add_builtin_keybinding (display,
"switch-to-session-1", "switch-to-session-1",
mutter_wayland_keybindings, mutter_wayland_keybindings,
META_KEY_BINDING_NONE, META_KEY_BINDING_NON_MASKABLE,
META_KEYBINDING_ACTION_NONE, META_KEYBINDING_ACTION_NONE,
handle_switch_vt, 1); handle_switch_vt, 1);
add_builtin_keybinding (display, add_builtin_keybinding (display,
"switch-to-session-2", "switch-to-session-2",
mutter_wayland_keybindings, mutter_wayland_keybindings,
META_KEY_BINDING_NONE, META_KEY_BINDING_NON_MASKABLE,
META_KEYBINDING_ACTION_NONE, META_KEYBINDING_ACTION_NONE,
handle_switch_vt, 2); handle_switch_vt, 2);
add_builtin_keybinding (display, add_builtin_keybinding (display,
"switch-to-session-3", "switch-to-session-3",
mutter_wayland_keybindings, mutter_wayland_keybindings,
META_KEY_BINDING_NONE, META_KEY_BINDING_NON_MASKABLE,
META_KEYBINDING_ACTION_NONE, META_KEYBINDING_ACTION_NONE,
handle_switch_vt, 3); handle_switch_vt, 3);
add_builtin_keybinding (display, add_builtin_keybinding (display,
"switch-to-session-4", "switch-to-session-4",
mutter_wayland_keybindings, mutter_wayland_keybindings,
META_KEY_BINDING_NONE, META_KEY_BINDING_NON_MASKABLE,
META_KEYBINDING_ACTION_NONE, META_KEYBINDING_ACTION_NONE,
handle_switch_vt, 4); handle_switch_vt, 4);
add_builtin_keybinding (display, add_builtin_keybinding (display,
"switch-to-session-5", "switch-to-session-5",
mutter_wayland_keybindings, mutter_wayland_keybindings,
META_KEY_BINDING_NONE, META_KEY_BINDING_NON_MASKABLE,
META_KEYBINDING_ACTION_NONE, META_KEYBINDING_ACTION_NONE,
handle_switch_vt, 5); handle_switch_vt, 5);
add_builtin_keybinding (display, add_builtin_keybinding (display,
"switch-to-session-6", "switch-to-session-6",
mutter_wayland_keybindings, mutter_wayland_keybindings,
META_KEY_BINDING_NONE, META_KEY_BINDING_NON_MASKABLE,
META_KEYBINDING_ACTION_NONE, META_KEYBINDING_ACTION_NONE,
handle_switch_vt, 6); handle_switch_vt, 6);
add_builtin_keybinding (display, add_builtin_keybinding (display,
"switch-to-session-7", "switch-to-session-7",
mutter_wayland_keybindings, mutter_wayland_keybindings,
META_KEY_BINDING_NONE, META_KEY_BINDING_NON_MASKABLE,
META_KEYBINDING_ACTION_NONE, META_KEYBINDING_ACTION_NONE,
handle_switch_vt, 7); handle_switch_vt, 7);
add_builtin_keybinding (display, add_builtin_keybinding (display,
"switch-to-session-8", "switch-to-session-8",
mutter_wayland_keybindings, mutter_wayland_keybindings,
META_KEY_BINDING_NONE, META_KEY_BINDING_NON_MASKABLE,
META_KEYBINDING_ACTION_NONE, META_KEYBINDING_ACTION_NONE,
handle_switch_vt, 8); handle_switch_vt, 8);
add_builtin_keybinding (display, add_builtin_keybinding (display,
"switch-to-session-9", "switch-to-session-9",
mutter_wayland_keybindings, mutter_wayland_keybindings,
META_KEY_BINDING_NONE, META_KEY_BINDING_NON_MASKABLE,
META_KEYBINDING_ACTION_NONE, META_KEYBINDING_ACTION_NONE,
handle_switch_vt, 9); handle_switch_vt, 9);
add_builtin_keybinding (display, add_builtin_keybinding (display,
"switch-to-session-10", "switch-to-session-10",
mutter_wayland_keybindings, mutter_wayland_keybindings,
META_KEY_BINDING_NONE, META_KEY_BINDING_NON_MASKABLE,
META_KEYBINDING_ACTION_NONE, META_KEYBINDING_ACTION_NONE,
handle_switch_vt, 10); handle_switch_vt, 10);
add_builtin_keybinding (display, add_builtin_keybinding (display,
"switch-to-session-11", "switch-to-session-11",
mutter_wayland_keybindings, mutter_wayland_keybindings,
META_KEY_BINDING_NONE, META_KEY_BINDING_NON_MASKABLE,
META_KEYBINDING_ACTION_NONE, META_KEYBINDING_ACTION_NONE,
handle_switch_vt, 11); handle_switch_vt, 11);
add_builtin_keybinding (display, add_builtin_keybinding (display,
"switch-to-session-12", "switch-to-session-12",
mutter_wayland_keybindings, mutter_wayland_keybindings,
META_KEY_BINDING_NONE, META_KEY_BINDING_NON_MASKABLE,
META_KEYBINDING_ACTION_NONE, META_KEYBINDING_ACTION_NONE,
handle_switch_vt, 12); handle_switch_vt, 12);
} }
#endif /* HAVE_NATIVE_BACKEND */ #endif /* HAVE_NATIVE_BACKEND */
add_builtin_keybinding (display,
"restore-shortcuts",
mutter_wayland_keybindings,
META_KEY_BINDING_NON_MASKABLE,
META_KEYBINDING_ACTION_NONE,
handle_restore_shortcuts, 0);
/************************ PER WINDOW BINDINGS ************************/ /************************ PER WINDOW BINDINGS ************************/
/* These take a window as an extra parameter; they have no effect /* These take a window as an extra parameter; they have no effect

View File

@ -535,6 +535,10 @@ struct _MetaWindowClass
gboolean user_op); gboolean user_op);
void (*main_monitor_changed) (MetaWindow *window, void (*main_monitor_changed) (MetaWindow *window,
const MetaLogicalMonitor *old); const MetaLogicalMonitor *old);
void (*force_restore_shortcuts) (MetaWindow *window,
ClutterInputDevice *source);
gboolean (*shortcuts_inhibited) (MetaWindow *window,
ClutterInputDevice *source);
}; };
/* These differ from window->has_foo_func in that they consider /* These differ from window->has_foo_func in that they consider
@ -763,4 +767,9 @@ MetaPlacementRule *meta_window_get_placement_rule (MetaWindow *window);
void meta_window_force_placement (MetaWindow *window); void meta_window_force_placement (MetaWindow *window);
void meta_window_force_restore_shortcuts (MetaWindow *window,
ClutterInputDevice *source);
gboolean meta_window_shortcuts_inhibited (MetaWindow *window,
ClutterInputDevice *source);
#endif #endif

View File

@ -8066,3 +8066,17 @@ meta_window_get_placement_rule (MetaWindow *window)
{ {
return window->placement_rule; return window->placement_rule;
} }
void
meta_window_force_restore_shortcuts (MetaWindow *window,
ClutterInputDevice *source)
{
META_WINDOW_GET_CLASS (window)->force_restore_shortcuts (window, source);
}
gboolean
meta_window_shortcuts_inhibited (MetaWindow *window,
ClutterInputDevice *source)
{
return META_WINDOW_GET_CLASS (window)->shortcuts_inhibited (window, source);
}

View File

@ -370,13 +370,15 @@ typedef enum _MetaKeyBindingAction
* @META_KEY_BINDING_PER_WINDOW: per-window * @META_KEY_BINDING_PER_WINDOW: per-window
* @META_KEY_BINDING_BUILTIN: built-in * @META_KEY_BINDING_BUILTIN: built-in
* @META_KEY_BINDING_IS_REVERSED: is reversed * @META_KEY_BINDING_IS_REVERSED: is reversed
* @META_KEY_BINDING_NON_MASKABLE: always active
*/ */
typedef enum typedef enum
{ {
META_KEY_BINDING_NONE, META_KEY_BINDING_NONE,
META_KEY_BINDING_PER_WINDOW = 1 << 0, META_KEY_BINDING_PER_WINDOW = 1 << 0,
META_KEY_BINDING_BUILTIN = 1 << 1, META_KEY_BINDING_BUILTIN = 1 << 1,
META_KEY_BINDING_IS_REVERSED = 1 << 2, META_KEY_BINDING_IS_REVERSED = 1 << 2,
META_KEY_BINDING_NON_MASKABLE = 1 << 3,
} MetaKeyBindingFlags; } MetaKeyBindingFlags;
/** /**

View File

@ -130,6 +130,8 @@ enum {
SURFACE_DESTROY, SURFACE_DESTROY,
SURFACE_UNMAPPED, SURFACE_UNMAPPED,
SURFACE_CONFIGURE, SURFACE_CONFIGURE,
SURFACE_SHORTCUTS_INHIBITED,
SURFACE_SHORTCUTS_RESTORED,
N_SURFACE_SIGNALS N_SURFACE_SIGNALS
}; };
@ -1334,6 +1336,8 @@ wl_surface_destructor (struct wl_resource *resource)
if (surface->wl_subsurface) if (surface->wl_subsurface)
wl_resource_destroy (surface->wl_subsurface); wl_resource_destroy (surface->wl_subsurface);
g_hash_table_destroy (surface->shortcut_inhibited_seats);
g_object_unref (surface); g_object_unref (surface);
meta_wayland_compositor_repick (compositor); meta_wayland_compositor_repick (compositor);
@ -1385,6 +1389,7 @@ meta_wayland_surface_create (MetaWaylandCompositor *compositor,
sync_drag_dest_funcs (surface); sync_drag_dest_funcs (surface);
surface->outputs_to_destroy_notify_id = g_hash_table_new (NULL, NULL); surface->outputs_to_destroy_notify_id = g_hash_table_new (NULL, NULL);
surface->shortcut_inhibited_seats = g_hash_table_new (NULL, NULL);
return surface; return surface;
} }
@ -1881,6 +1886,22 @@ meta_wayland_surface_class_init (MetaWaylandSurfaceClass *klass)
0, NULL, NULL, 0, NULL, NULL,
g_cclosure_marshal_VOID__VOID, g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE, 0); G_TYPE_NONE, 0);
surface_signals[SURFACE_SHORTCUTS_INHIBITED] =
g_signal_new ("shortcuts-inhibited",
G_TYPE_FROM_CLASS (object_class),
G_SIGNAL_RUN_LAST,
0, NULL, NULL,
g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE, 0);
surface_signals[SURFACE_SHORTCUTS_RESTORED] =
g_signal_new ("shortcuts-restored",
G_TYPE_FROM_CLASS (object_class),
G_SIGNAL_RUN_LAST,
0, NULL, NULL,
g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE, 0);
} }
static void static void
@ -2219,3 +2240,29 @@ meta_wayland_surface_calculate_input_region (MetaWaylandSurface *surface)
return region; return region;
} }
void
meta_wayland_surface_inhibit_shortcuts (MetaWaylandSurface *surface,
MetaWaylandSeat *seat)
{
g_hash_table_add (surface->shortcut_inhibited_seats, seat);
g_signal_emit (surface, surface_signals[SURFACE_SHORTCUTS_INHIBITED], 0);
}
void
meta_wayland_surface_restore_shortcuts (MetaWaylandSurface *surface,
MetaWaylandSeat *seat)
{
g_signal_emit (surface, surface_signals[SURFACE_SHORTCUTS_RESTORED], 0);
g_hash_table_remove (surface->shortcut_inhibited_seats, seat);
}
gboolean
meta_wayland_surface_is_shortcuts_inhibited (MetaWaylandSurface *surface,
MetaWaylandSeat *seat)
{
if (surface->shortcut_inhibited_seats == NULL)
return FALSE;
return g_hash_table_contains (surface->shortcut_inhibited_seats, seat);
}

View File

@ -240,6 +240,9 @@ struct _MetaWaylandSurface
gboolean pending_pos; gboolean pending_pos;
GSList *pending_placement_ops; GSList *pending_placement_ops;
} sub; } sub;
/* table of seats for which shortcuts are inhibited */
GHashTable *shortcut_inhibited_seats;
}; };
void meta_wayland_shell_init (MetaWaylandCompositor *compositor); void meta_wayland_shell_init (MetaWaylandCompositor *compositor);
@ -326,4 +329,13 @@ gboolean meta_wayland_surface_begin_grab_op (MetaWaylandSurface *surf
void meta_wayland_surface_window_managed (MetaWaylandSurface *surface, void meta_wayland_surface_window_managed (MetaWaylandSurface *surface,
MetaWindow *window); MetaWindow *window);
void meta_wayland_surface_inhibit_shortcuts (MetaWaylandSurface *surface,
MetaWaylandSeat *seat);
void meta_wayland_surface_restore_shortcuts (MetaWaylandSurface *surface,
MetaWaylandSeat *seat);
gboolean meta_wayland_surface_is_shortcuts_inhibited (MetaWaylandSurface *surface,
MetaWaylandSeat *seat);
#endif #endif

View File

@ -404,3 +404,40 @@ meta_wayland_finalize (void)
meta_xwayland_stop (&compositor->xwayland_manager); meta_xwayland_stop (&compositor->xwayland_manager);
} }
void
meta_wayland_compositor_restore_shortcuts (MetaWaylandCompositor *compositor,
ClutterInputDevice *source)
{
MetaWaylandKeyboard *keyboard;
/* Clutter is not multi-seat aware yet, use the default seat instead */
keyboard = compositor->seat->keyboard;
if (!keyboard || !keyboard->focus_surface)
return;
if (!meta_wayland_surface_is_shortcuts_inhibited (keyboard->focus_surface,
compositor->seat))
return;
meta_wayland_surface_restore_shortcuts (keyboard->focus_surface,
compositor->seat);
}
gboolean
meta_wayland_compositor_is_shortcuts_inhibited (MetaWaylandCompositor *compositor,
ClutterInputDevice *source)
{
MetaWaylandKeyboard *keyboard;
if (clutter_input_device_get_device_type (source) != CLUTTER_KEYBOARD_DEVICE)
return FALSE;
/* Clutter is not multi-seat aware yet, use the default seat instead */
keyboard = compositor->seat->keyboard;
if (keyboard && keyboard->focus_surface != NULL)
return meta_wayland_surface_is_shortcuts_inhibited (keyboard->focus_surface,
compositor->seat);
return FALSE;
}

View File

@ -58,5 +58,10 @@ void meta_wayland_compositor_destroy_frame_callbacks (MetaWay
const char *meta_wayland_get_wayland_display_name (MetaWaylandCompositor *compositor); const char *meta_wayland_get_wayland_display_name (MetaWaylandCompositor *compositor);
const char *meta_wayland_get_xwayland_display_name (MetaWaylandCompositor *compositor); const char *meta_wayland_get_xwayland_display_name (MetaWaylandCompositor *compositor);
void meta_wayland_compositor_restore_shortcuts (MetaWaylandCompositor *compositor,
ClutterInputDevice *source);
gboolean meta_wayland_compositor_is_shortcuts_inhibited (MetaWaylandCompositor *compositor,
ClutterInputDevice *source);
#endif #endif

View File

@ -520,6 +520,24 @@ meta_window_wayland_init (MetaWindowWayland *wl_window)
G_CALLBACK (appears_focused_changed), NULL); G_CALLBACK (appears_focused_changed), NULL);
} }
static void
meta_window_wayland_force_restore_shortcuts (MetaWindow *window,
ClutterInputDevice *source)
{
MetaWaylandCompositor *compositor = meta_wayland_compositor_get_default ();
meta_wayland_compositor_restore_shortcuts (compositor, source);
}
static gboolean
meta_window_wayland_shortcuts_inhibited (MetaWindow *window,
ClutterInputDevice *source)
{
MetaWaylandCompositor *compositor = meta_wayland_compositor_get_default ();
return meta_wayland_compositor_is_shortcuts_inhibited (compositor, source);
}
static void static void
meta_window_wayland_class_init (MetaWindowWaylandClass *klass) meta_window_wayland_class_init (MetaWindowWaylandClass *klass)
{ {
@ -537,6 +555,8 @@ meta_window_wayland_class_init (MetaWindowWaylandClass *klass)
window_class->update_main_monitor = meta_window_wayland_update_main_monitor; window_class->update_main_monitor = meta_window_wayland_update_main_monitor;
window_class->main_monitor_changed = meta_window_wayland_main_monitor_changed; window_class->main_monitor_changed = meta_window_wayland_main_monitor_changed;
window_class->get_client_pid = meta_window_wayland_get_client_pid; window_class->get_client_pid = meta_window_wayland_get_client_pid;
window_class->force_restore_shortcuts = meta_window_wayland_force_restore_shortcuts;
window_class->shortcuts_inhibited = meta_window_wayland_shortcuts_inhibited;
} }
MetaWindow * MetaWindow *

View File

@ -1504,6 +1504,27 @@ meta_window_x11_get_client_pid (MetaWindow *window)
return pid; return pid;
} }
static void
meta_window_x11_force_restore_shortcuts (MetaWindow *window,
ClutterInputDevice *source)
{
/*
* Not needed on X11 because clients can use a keyboard grab
* to bypass the compositor shortcuts.
*/
}
static gboolean
meta_window_x11_shortcuts_inhibited (MetaWindow *window,
ClutterInputDevice *source)
{
/*
* On X11, we don't use a shortcuts inhibitor, clients just grab
* the keyboard.
*/
return FALSE;
}
static void static void
meta_window_x11_class_init (MetaWindowX11Class *klass) meta_window_x11_class_init (MetaWindowX11Class *klass)
{ {
@ -1525,6 +1546,8 @@ meta_window_x11_class_init (MetaWindowX11Class *klass)
window_class->update_main_monitor = meta_window_x11_update_main_monitor; window_class->update_main_monitor = meta_window_x11_update_main_monitor;
window_class->main_monitor_changed = meta_window_x11_main_monitor_changed; window_class->main_monitor_changed = meta_window_x11_main_monitor_changed;
window_class->get_client_pid = meta_window_x11_get_client_pid; window_class->get_client_pid = meta_window_x11_get_client_pid;
window_class->force_restore_shortcuts = meta_window_x11_force_restore_shortcuts;
window_class->shortcuts_inhibited = meta_window_x11_shortcuts_inhibited;
} }
void void