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) {