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: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/3185>
This commit is contained in:
Jonas Ådahl 2023-08-16 00:09:09 +02:00 committed by Marge Bot
parent 03ee48094e
commit 05eeb684d1
3 changed files with 65 additions and 10 deletions

View File

@ -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);

View File

@ -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

View File

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