window: Avoid focusing during workspace changes

We can land inside meta_window_focus() in the middle of changing the
window workspace, because some signal handler of MetaWorkspace's
"window-removed" signal triggers a focus. This can cause a crash in
`g_assert (link)` when updating the MRU list because we still think
we're on the old workspace when actually we are already removed from
this workspaces MRU list.

To avoid crashes like this, bail out of meta_window_focus() when we're
in the middle of a workspace change.

Fixes https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/5368

Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2691>
This commit is contained in:
Jonas Dreßler 2022-11-06 12:38:35 +01:00 committed by Marge Bot
parent 098c627f11
commit 1816f21e21
2 changed files with 14 additions and 0 deletions

View File

@ -563,6 +563,8 @@ struct _MetaWindow
/* if TRUE, the we have the new form of sync request counter which /* if TRUE, the we have the new form of sync request counter which
* also handles application frames */ * also handles application frames */
guint extended_sync_request_counter : 1; guint extended_sync_request_counter : 1;
guint in_workspace_change : 1;
}; };
struct _MetaWindowClass struct _MetaWindowClass

View File

@ -4552,6 +4552,14 @@ meta_window_focus (MetaWindow *window,
"Setting input focus to window %s, input: %d focusable: %d", "Setting input focus to window %s, input: %d focusable: %d",
window->desc, window->input, meta_window_is_focusable (window)); window->desc, window->input, meta_window_is_focusable (window));
if (window->in_workspace_change)
{
meta_topic (META_DEBUG_FOCUS,
"Window %s is currently changing workspaces, not focusing it after all",
window->desc);
return;
}
if (window->display->grab_window && if (window->display->grab_window &&
window->display->grab_window != window && window->display->grab_window != window &&
window->display->grab_window->all_keys_grabbed && window->display->grab_window->all_keys_grabbed &&
@ -4671,6 +4679,8 @@ set_workspace_state (MetaWindow *window,
!window->constructing) !window->constructing)
return; return;
window->in_workspace_change = TRUE;
if (window->workspace) if (window->workspace)
meta_workspace_remove_window (window->workspace, window); meta_workspace_remove_window (window->workspace, window);
else if (window->on_all_workspaces) else if (window->on_all_workspaces)
@ -4698,6 +4708,8 @@ set_workspace_state (MetaWindow *window,
} }
} }
window->in_workspace_change = FALSE;
if (!window->constructing) if (!window->constructing)
meta_window_update_appears_focused (window); meta_window_update_appears_focused (window);