From dd12f569d90c7d6b524bda72266bf91c5a61d9e4 Mon Sep 17 00:00:00 2001 From: Olivier Fourdan Date: Fri, 17 Mar 2017 13:34:52 +0100 Subject: [PATCH] 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 --- data/org.gnome.mutter.wayland.gschema.xml.in | 4 ++ src/core/keybindings.c | 58 ++++++++++++++++---- src/core/window-private.h | 9 +++ src/core/window.c | 14 +++++ src/meta/prefs.h | 8 ++- src/wayland/meta-wayland-surface.c | 47 ++++++++++++++++ src/wayland/meta-wayland-surface.h | 12 ++++ src/wayland/meta-wayland.c | 37 +++++++++++++ src/wayland/meta-wayland.h | 5 ++ src/wayland/meta-window-wayland.c | 20 +++++++ src/x11/window-x11.c | 23 ++++++++ 11 files changed, 222 insertions(+), 15 deletions(-) diff --git a/data/org.gnome.mutter.wayland.gschema.xml.in b/data/org.gnome.mutter.wayland.gschema.xml.in index 44334d664..e8ee1cca7 100644 --- a/data/org.gnome.mutter.wayland.gschema.xml.in +++ b/data/org.gnome.mutter.wayland.gschema.xml.in @@ -49,5 +49,9 @@ F12']]]> Switch to VT 12 + + Escape']]]> + Re-enable shortcuts + diff --git a/src/core/keybindings.c b/src/core/keybindings.c index 518416ce2..697239232 100644 --- a/src/core/keybindings.c +++ b/src/core/keybindings.c @@ -1716,6 +1716,16 @@ process_event (MetaDisplay *display, (!window && binding->flags & META_KEY_BINDING_PER_WINDOW)) 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 * means they don't want the binding to trigger, so we do * 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); } +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: * @name: The name of the keybinding to set @@ -3674,89 +3701,96 @@ init_builtin_key_bindings (MetaDisplay *display) add_builtin_keybinding (display, "switch-to-session-1", mutter_wayland_keybindings, - META_KEY_BINDING_NONE, + META_KEY_BINDING_NON_MASKABLE, META_KEYBINDING_ACTION_NONE, handle_switch_vt, 1); add_builtin_keybinding (display, "switch-to-session-2", mutter_wayland_keybindings, - META_KEY_BINDING_NONE, + META_KEY_BINDING_NON_MASKABLE, META_KEYBINDING_ACTION_NONE, handle_switch_vt, 2); add_builtin_keybinding (display, "switch-to-session-3", mutter_wayland_keybindings, - META_KEY_BINDING_NONE, + META_KEY_BINDING_NON_MASKABLE, META_KEYBINDING_ACTION_NONE, handle_switch_vt, 3); add_builtin_keybinding (display, "switch-to-session-4", mutter_wayland_keybindings, - META_KEY_BINDING_NONE, + META_KEY_BINDING_NON_MASKABLE, META_KEYBINDING_ACTION_NONE, handle_switch_vt, 4); add_builtin_keybinding (display, "switch-to-session-5", mutter_wayland_keybindings, - META_KEY_BINDING_NONE, + META_KEY_BINDING_NON_MASKABLE, META_KEYBINDING_ACTION_NONE, handle_switch_vt, 5); add_builtin_keybinding (display, "switch-to-session-6", mutter_wayland_keybindings, - META_KEY_BINDING_NONE, + META_KEY_BINDING_NON_MASKABLE, META_KEYBINDING_ACTION_NONE, handle_switch_vt, 6); add_builtin_keybinding (display, "switch-to-session-7", mutter_wayland_keybindings, - META_KEY_BINDING_NONE, + META_KEY_BINDING_NON_MASKABLE, META_KEYBINDING_ACTION_NONE, handle_switch_vt, 7); add_builtin_keybinding (display, "switch-to-session-8", mutter_wayland_keybindings, - META_KEY_BINDING_NONE, + META_KEY_BINDING_NON_MASKABLE, META_KEYBINDING_ACTION_NONE, handle_switch_vt, 8); add_builtin_keybinding (display, "switch-to-session-9", mutter_wayland_keybindings, - META_KEY_BINDING_NONE, + META_KEY_BINDING_NON_MASKABLE, META_KEYBINDING_ACTION_NONE, handle_switch_vt, 9); add_builtin_keybinding (display, "switch-to-session-10", mutter_wayland_keybindings, - META_KEY_BINDING_NONE, + META_KEY_BINDING_NON_MASKABLE, META_KEYBINDING_ACTION_NONE, handle_switch_vt, 10); add_builtin_keybinding (display, "switch-to-session-11", mutter_wayland_keybindings, - META_KEY_BINDING_NONE, + META_KEY_BINDING_NON_MASKABLE, META_KEYBINDING_ACTION_NONE, handle_switch_vt, 11); add_builtin_keybinding (display, "switch-to-session-12", mutter_wayland_keybindings, - META_KEY_BINDING_NONE, + META_KEY_BINDING_NON_MASKABLE, META_KEYBINDING_ACTION_NONE, handle_switch_vt, 12); } #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 ************************/ /* These take a window as an extra parameter; they have no effect diff --git a/src/core/window-private.h b/src/core/window-private.h index 0b667fb8f..521682d0a 100644 --- a/src/core/window-private.h +++ b/src/core/window-private.h @@ -535,6 +535,10 @@ struct _MetaWindowClass gboolean user_op); void (*main_monitor_changed) (MetaWindow *window, 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 @@ -763,4 +767,9 @@ MetaPlacementRule *meta_window_get_placement_rule (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 diff --git a/src/core/window.c b/src/core/window.c index fa01e57c1..ec3083f80 100644 --- a/src/core/window.c +++ b/src/core/window.c @@ -8066,3 +8066,17 @@ meta_window_get_placement_rule (MetaWindow *window) { 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); +} diff --git a/src/meta/prefs.h b/src/meta/prefs.h index 4394f74d1..df3cf6c97 100644 --- a/src/meta/prefs.h +++ b/src/meta/prefs.h @@ -370,13 +370,15 @@ typedef enum _MetaKeyBindingAction * @META_KEY_BINDING_PER_WINDOW: per-window * @META_KEY_BINDING_BUILTIN: built-in * @META_KEY_BINDING_IS_REVERSED: is reversed + * @META_KEY_BINDING_NON_MASKABLE: always active */ typedef enum { META_KEY_BINDING_NONE, - META_KEY_BINDING_PER_WINDOW = 1 << 0, - META_KEY_BINDING_BUILTIN = 1 << 1, - META_KEY_BINDING_IS_REVERSED = 1 << 2, + META_KEY_BINDING_PER_WINDOW = 1 << 0, + META_KEY_BINDING_BUILTIN = 1 << 1, + META_KEY_BINDING_IS_REVERSED = 1 << 2, + META_KEY_BINDING_NON_MASKABLE = 1 << 3, } MetaKeyBindingFlags; /** diff --git a/src/wayland/meta-wayland-surface.c b/src/wayland/meta-wayland-surface.c index 3d02a7301..ddca18f8d 100644 --- a/src/wayland/meta-wayland-surface.c +++ b/src/wayland/meta-wayland-surface.c @@ -130,6 +130,8 @@ enum { SURFACE_DESTROY, SURFACE_UNMAPPED, SURFACE_CONFIGURE, + SURFACE_SHORTCUTS_INHIBITED, + SURFACE_SHORTCUTS_RESTORED, N_SURFACE_SIGNALS }; @@ -1334,6 +1336,8 @@ wl_surface_destructor (struct wl_resource *resource) if (surface->wl_subsurface) wl_resource_destroy (surface->wl_subsurface); + g_hash_table_destroy (surface->shortcut_inhibited_seats); + g_object_unref (surface); meta_wayland_compositor_repick (compositor); @@ -1385,6 +1389,7 @@ meta_wayland_surface_create (MetaWaylandCompositor *compositor, sync_drag_dest_funcs (surface); surface->outputs_to_destroy_notify_id = g_hash_table_new (NULL, NULL); + surface->shortcut_inhibited_seats = g_hash_table_new (NULL, NULL); return surface; } @@ -1881,6 +1886,22 @@ meta_wayland_surface_class_init (MetaWaylandSurfaceClass *klass) 0, NULL, NULL, g_cclosure_marshal_VOID__VOID, 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 @@ -2219,3 +2240,29 @@ meta_wayland_surface_calculate_input_region (MetaWaylandSurface *surface) 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); +} diff --git a/src/wayland/meta-wayland-surface.h b/src/wayland/meta-wayland-surface.h index 09a1dbce2..e4eada963 100644 --- a/src/wayland/meta-wayland-surface.h +++ b/src/wayland/meta-wayland-surface.h @@ -240,6 +240,9 @@ struct _MetaWaylandSurface gboolean pending_pos; GSList *pending_placement_ops; } sub; + + /* table of seats for which shortcuts are inhibited */ + GHashTable *shortcut_inhibited_seats; }; 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, 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 diff --git a/src/wayland/meta-wayland.c b/src/wayland/meta-wayland.c index b5ab1ecf6..d89cac540 100644 --- a/src/wayland/meta-wayland.c +++ b/src/wayland/meta-wayland.c @@ -404,3 +404,40 @@ meta_wayland_finalize (void) 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; +} diff --git a/src/wayland/meta-wayland.h b/src/wayland/meta-wayland.h index af8b086f0..95e796ecd 100644 --- a/src/wayland/meta-wayland.h +++ b/src/wayland/meta-wayland.h @@ -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_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 diff --git a/src/wayland/meta-window-wayland.c b/src/wayland/meta-window-wayland.c index efe299fe3..22da3901d 100644 --- a/src/wayland/meta-window-wayland.c +++ b/src/wayland/meta-window-wayland.c @@ -520,6 +520,24 @@ meta_window_wayland_init (MetaWindowWayland *wl_window) 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 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->main_monitor_changed = meta_window_wayland_main_monitor_changed; 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 * diff --git a/src/x11/window-x11.c b/src/x11/window-x11.c index 07f09223e..ad5058b8a 100644 --- a/src/x11/window-x11.c +++ b/src/x11/window-x11.c @@ -1504,6 +1504,27 @@ meta_window_x11_get_client_pid (MetaWindow *window) 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 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->main_monitor_changed = meta_window_x11_main_monitor_changed; 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