window: Make default focus window on each workspace appear focused

Makes workspace transitions in gnome-shell look more seamless, since
both outgoing and incoming workspace have focused windows.

This is only done for click focus mode, since it's not known which
window would be focused for the other modes.

Track the state and recompute it when it changes, to avoid redrawing
the windows needlessly.

Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/850>
This commit is contained in:
Alexander Mikhaylenko 2019-10-12 23:55:26 +05:00
parent 7afefbbb61
commit ed391eb06b
3 changed files with 70 additions and 10 deletions

View File

@ -382,6 +382,9 @@ struct _MetaWindow
/* TRUE iff window == window->display->focus_window */ /* TRUE iff window == window->display->focus_window */
guint has_focus : 1; guint has_focus : 1;
/* TRUE if window appears focused at the moment */
guint appears_focused : 1;
/* Have we placed this window? */ /* Have we placed this window? */
guint placed : 1; guint placed : 1;
@ -717,6 +720,8 @@ void meta_window_get_session_geometry (MetaWindow *window,
void meta_window_update_unfocused_button_grabs (MetaWindow *window); void meta_window_update_unfocused_button_grabs (MetaWindow *window);
void meta_window_update_appears_focused (MetaWindow *window);
void meta_window_set_focused_internal (MetaWindow *window, void meta_window_set_focused_internal (MetaWindow *window,
gboolean focused); gboolean focused);

View File

@ -251,6 +251,10 @@ prefs_changed_callback (MetaPreference pref,
meta_window_recalc_features (window); meta_window_recalc_features (window);
meta_window_queue (window, META_QUEUE_MOVE_RESIZE); meta_window_queue (window, META_QUEUE_MOVE_RESIZE);
} }
else if (pref == META_PREF_FOCUS_MODE)
{
meta_window_update_appears_focused (window);
}
} }
static void static void
@ -402,7 +406,7 @@ meta_window_get_property(GObject *object,
g_value_set_string (value, win->mutter_hints); g_value_set_string (value, win->mutter_hints);
break; break;
case PROP_APPEARS_FOCUSED: case PROP_APPEARS_FOCUSED:
g_value_set_boolean (value, meta_window_appears_focused (win)); g_value_set_boolean (value, win->appears_focused);
break; break;
case PROP_WM_CLASS: case PROP_WM_CLASS:
g_value_set_string (value, win->res_class); g_value_set_string (value, win->res_class);
@ -1514,7 +1518,7 @@ meta_window_unmanage (MetaWindow *window,
* on what gets focused, maintaining sloppy focus * on what gets focused, maintaining sloppy focus
* invariants. * invariants.
*/ */
if (meta_window_appears_focused (window)) if (window->appears_focused)
meta_window_propagate_focus_appearance (window, FALSE); meta_window_propagate_focus_appearance (window, FALSE);
if (window->has_focus) if (window->has_focus)
{ {
@ -4911,6 +4915,9 @@ set_workspace_state (MetaWindow *window,
} }
} }
if (!window->constructing)
meta_window_update_appears_focused (window);
/* queue a move_resize since changing workspaces may change /* queue a move_resize since changing workspaces may change
* the relevant struts * the relevant struts
*/ */
@ -5266,9 +5273,26 @@ meta_window_change_workspace_by_index (MetaWindow *window,
meta_window_change_workspace (window, workspace); meta_window_change_workspace (window, workspace);
} }
static void void
meta_window_appears_focused_changed (MetaWindow *window) meta_window_update_appears_focused (MetaWindow *window)
{ {
MetaWorkspaceManager *workspace_manager;
MetaWorkspace *workspace;
gboolean appears_focused;
workspace_manager = window->display->workspace_manager;
workspace = meta_window_get_workspace (window);
if (workspace && workspace != workspace_manager->active_workspace)
appears_focused = window == meta_workspace_get_default_focus_window (workspace);
else
appears_focused = window->has_focus || window->attached_focus_window;
if (window->appears_focused == appears_focused)
return;
window->appears_focused = appears_focused;
set_net_wm_state (window); set_net_wm_state (window);
meta_window_frame_size_changed (window); meta_window_frame_size_changed (window);
@ -5348,7 +5372,7 @@ meta_window_propagate_focus_appearance (MetaWindow *window,
if (child_focus_state_changed && !parent->has_focus) if (child_focus_state_changed && !parent->has_focus)
{ {
meta_window_appears_focused_changed (parent); meta_window_update_appears_focused (parent);
} }
child = parent; child = parent;
@ -5423,7 +5447,7 @@ meta_window_set_focused_internal (MetaWindow *window,
g_signal_emit (window, window_signals[FOCUS], 0); g_signal_emit (window, window_signals[FOCUS], 0);
if (!window->attached_focus_window) if (!window->attached_focus_window)
meta_window_appears_focused_changed (window); meta_window_update_appears_focused (window);
meta_window_propagate_focus_appearance (window, TRUE); meta_window_propagate_focus_appearance (window, TRUE);
} }
@ -5436,7 +5460,7 @@ meta_window_set_focused_internal (MetaWindow *window,
meta_window_propagate_focus_appearance (window, FALSE); meta_window_propagate_focus_appearance (window, FALSE);
if (!window->attached_focus_window) if (!window->attached_focus_window)
meta_window_appears_focused_changed (window); meta_window_update_appears_focused (window);
/* Re-grab for click to focus and raise-on-click, if necessary */ /* Re-grab for click to focus and raise-on-click, if necessary */
if (meta_prefs_get_focus_mode () == G_DESKTOP_FOCUS_MODE_CLICK || if (meta_prefs_get_focus_mode () == G_DESKTOP_FOCUS_MODE_CLICK ||
@ -7361,7 +7385,7 @@ meta_window_get_frame (MetaWindow *window)
gboolean gboolean
meta_window_appears_focused (MetaWindow *window) meta_window_appears_focused (MetaWindow *window)
{ {
return window->has_focus || (window->attached_focus_window != NULL); return window->appears_focused;
} }
gboolean gboolean
@ -8099,7 +8123,7 @@ meta_window_set_transient_for (MetaWindow *window,
return; return;
} }
if (meta_window_appears_focused (window) && window->transient_for != NULL) if (window->appears_focused && window->transient_for != NULL)
meta_window_propagate_focus_appearance (window, FALSE); meta_window_propagate_focus_appearance (window, FALSE);
/* may now be a dialog */ /* may now be a dialog */
@ -8155,7 +8179,7 @@ meta_window_set_transient_for (MetaWindow *window,
if (!window->constructing && !window->override_redirect) if (!window->constructing && !window->override_redirect)
meta_window_queue (window, META_QUEUE_MOVE_RESIZE | META_QUEUE_CALC_SHOWING); meta_window_queue (window, META_QUEUE_MOVE_RESIZE | META_QUEUE_CALC_SHOWING);
if (meta_window_appears_focused (window) && window->transient_for != NULL) if (window->appears_focused && window->transient_for != NULL)
meta_window_propagate_focus_appearance (window, TRUE); meta_window_propagate_focus_appearance (window, TRUE);
} }

View File

@ -365,15 +365,37 @@ meta_workspace_remove (MetaWorkspace *workspace)
*/ */
} }
static void
update_workspace_default_focus (MetaWorkspace *workspace,
MetaWindow *not_this_one)
{
g_autoptr (GSList) windows = NULL;
GSList *l;
windows = meta_display_list_windows (workspace->display, META_LIST_DEFAULT);
for (l = windows; l; l = l->next)
{
MetaWindow *window = META_WINDOW (l->data);
if (meta_window_located_on_workspace (window, workspace) &&
window != not_this_one)
meta_window_update_appears_focused (window);
}
}
void void
meta_workspace_add_window (MetaWorkspace *workspace, meta_workspace_add_window (MetaWorkspace *workspace,
MetaWindow *window) MetaWindow *window)
{ {
MetaWorkspaceManager *workspace_manager;
g_return_if_fail (g_list_find (workspace->mru_list, window) == NULL); g_return_if_fail (g_list_find (workspace->mru_list, window) == NULL);
COGL_TRACE_BEGIN_SCOPED (MetaWorkspaceAddWindow, COGL_TRACE_BEGIN_SCOPED (MetaWorkspaceAddWindow,
"Workspace (add window)"); "Workspace (add window)");
workspace_manager = workspace->display->workspace_manager;
workspace->mru_list = g_list_prepend (workspace->mru_list, window); workspace->mru_list = g_list_prepend (workspace->mru_list, window);
workspace->windows = g_list_prepend (workspace->windows, window); workspace->windows = g_list_prepend (workspace->windows, window);
@ -386,6 +408,9 @@ meta_workspace_add_window (MetaWorkspace *workspace,
meta_workspace_invalidate_work_area (workspace); meta_workspace_invalidate_work_area (workspace);
} }
if (workspace != workspace_manager->active_workspace)
update_workspace_default_focus (workspace, window);
g_signal_emit (workspace, signals[WINDOW_ADDED], 0, window); g_signal_emit (workspace, signals[WINDOW_ADDED], 0, window);
g_object_notify_by_pspec (G_OBJECT (workspace), obj_props[PROP_N_WINDOWS]); g_object_notify_by_pspec (G_OBJECT (workspace), obj_props[PROP_N_WINDOWS]);
} }
@ -394,6 +419,8 @@ void
meta_workspace_remove_window (MetaWorkspace *workspace, meta_workspace_remove_window (MetaWorkspace *workspace,
MetaWindow *window) MetaWindow *window)
{ {
MetaWorkspaceManager *workspace_manager = workspace->display->workspace_manager;
COGL_TRACE_BEGIN_SCOPED (MetaWorkspaceRemoveWindow, COGL_TRACE_BEGIN_SCOPED (MetaWorkspaceRemoveWindow,
"Workspace (remove window)"); "Workspace (remove window)");
@ -410,6 +437,9 @@ meta_workspace_remove_window (MetaWorkspace *workspace,
meta_workspace_invalidate_work_area (workspace); meta_workspace_invalidate_work_area (workspace);
} }
if (workspace != workspace_manager->active_workspace)
update_workspace_default_focus (workspace, window);
g_signal_emit (workspace, signals[WINDOW_REMOVED], 0, window); g_signal_emit (workspace, signals[WINDOW_REMOVED], 0, window);
g_object_notify (G_OBJECT (workspace), "n-windows"); g_object_notify (G_OBJECT (workspace), "n-windows");
} }
@ -658,6 +688,7 @@ meta_workspace_activate_with_focus (MetaWorkspace *workspace,
if (focus_this) if (focus_this)
{ {
meta_window_activate (focus_this, timestamp); meta_window_activate (focus_this, timestamp);
update_workspace_default_focus (workspace, focus_this);
} }
else if (move_window) else if (move_window)
{ {