From 05eeb684d1f990a0b5cedf28a65fbe14980f8fcf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Wed, 16 Aug 2023 00:09:09 +0200 Subject: [PATCH] window: Postpone focusing until grab ended if uninteractable When GNOME Shell is in the overview, we don't want windows to steal focus left and right, but once we leave the overview, we do want whatever was mapped with "take_focus" to get focus. Do that, but after the last grab was dismissed. Closes: https://gitlab.gnome.org/GNOME/mutter/-/issues/2690 Part-of: --- src/core/display-private.h | 3 ++ src/core/display.c | 58 ++++++++++++++++++++++++++++++++++++++ src/core/window.c | 14 +++------ 3 files changed, 65 insertions(+), 10 deletions(-) diff --git a/src/core/display-private.h b/src/core/display-private.h index daa12a573..4afd0d5df 100644 --- a/src/core/display-private.h +++ b/src/core/display-private.h @@ -297,6 +297,9 @@ void meta_display_cancel_touch (MetaDisplay *display); gboolean meta_display_windows_are_interactable (MetaDisplay *display); +void meta_display_queue_focus (MetaDisplay *display, + MetaWindow *window); + void meta_display_show_tablet_mapping_notification (MetaDisplay *display, ClutterInputDevice *pad, const gchar *pretty_name); diff --git a/src/core/display.c b/src/core/display.c index 652bd97ef..e9ff7ba55 100644 --- a/src/core/display.c +++ b/src/core/display.c @@ -141,6 +141,11 @@ typedef struct _MetaDisplayPrivate GList *queue_windows[META_N_QUEUE_TYPES]; gboolean enable_input_capture; + + struct { + MetaWindow *window; + gulong unmanaging_handler_id; + } focus_on_grab_dismissed; } MetaDisplayPrivate; G_DEFINE_TYPE_WITH_PRIVATE (MetaDisplay, meta_display, G_TYPE_OBJECT) @@ -209,6 +214,10 @@ meta_display_show_osd (MetaDisplay *display, const gchar *icon_name, const gchar *message); +static void on_is_grabbed_changed (ClutterStage *stage, + GParamSpec *pspec, + MetaDisplay *display); + static MetaBackend * backend_from_display (MetaDisplay *display) { @@ -917,6 +926,7 @@ meta_display_new (MetaContext *context, GError **error) { MetaBackend *backend = meta_context_get_backend (context); + ClutterActor *stage = meta_backend_get_stage (backend); MetaDisplay *display; MetaDisplayPrivate *priv; guint32 timestamp; @@ -1091,6 +1101,8 @@ meta_display_new (MetaContext *context, meta_display_unset_input_focus (display, timestamp); #endif + g_signal_connect (stage, "notify::is-grabbed", + G_CALLBACK (on_is_grabbed_changed), display); display->sound_player = g_object_new (META_TYPE_SOUND_PLAYER, NULL); @@ -1315,6 +1327,52 @@ meta_display_windows_are_interactable (MetaDisplay *display) return TRUE; } +static void +on_is_grabbed_changed (ClutterStage *stage, + GParamSpec *pspec, + MetaDisplay *display) +{ + MetaDisplayPrivate *priv = meta_display_get_instance_private (display); + + if (!priv->focus_on_grab_dismissed.window) + return; + + meta_window_focus (priv->focus_on_grab_dismissed.window, META_CURRENT_TIME); + + g_clear_signal_handler (&priv->focus_on_grab_dismissed.unmanaging_handler_id, + priv->focus_on_grab_dismissed.window); + priv->focus_on_grab_dismissed.window = NULL; +} + +static void +focus_on_grab_dismissed_unmanaging_cb (MetaWindow *window, + MetaDisplay *display) +{ + MetaDisplayPrivate *priv = meta_display_get_instance_private (display); + + g_return_if_fail (priv->focus_on_grab_dismissed.window == window); + + g_clear_signal_handler (&priv->focus_on_grab_dismissed.unmanaging_handler_id, + priv->focus_on_grab_dismissed.window); + priv->focus_on_grab_dismissed.window = NULL; +} + +void +meta_display_queue_focus (MetaDisplay *display, + MetaWindow *window) +{ + MetaDisplayPrivate *priv = meta_display_get_instance_private (display); + + g_clear_signal_handler (&priv->focus_on_grab_dismissed.unmanaging_handler_id, + priv->focus_on_grab_dismissed.window); + + priv->focus_on_grab_dismissed.window = window; + priv->focus_on_grab_dismissed.unmanaging_handler_id = + g_signal_connect (window, "unmanaging", + G_CALLBACK (focus_on_grab_dismissed_unmanaging_cb), + display); +} + /** * meta_display_xserver_time_is_before: * @display: a #MetaDisplay diff --git a/src/core/window.c b/src/core/window.c index 9e1082585..dca30a1c5 100644 --- a/src/core/window.c +++ b/src/core/window.c @@ -1939,15 +1939,6 @@ window_state_on_map (MetaWindow *window, return; } - /* Do not focus window on map if input is already taken by the - * compositor. - */ - if (!meta_display_windows_are_interactable (window->display)) - { - *takes_focus = FALSE; - return; - } - /* When strict focus mode is enabled, prevent new windows from taking * focus unless they are ancestors to the transient. */ @@ -2262,7 +2253,10 @@ meta_window_show (MetaWindow *window) timestamp = meta_display_get_current_time_roundtrip (window->display); - meta_window_focus (window, timestamp); + if (meta_display_windows_are_interactable (window->display)) + meta_window_focus (window, timestamp); + else + meta_display_queue_focus (window->display, window); } else if (display->x11_display) {