window-slot: Rework and document grab_focus() call

We'v been relying on a gtk_widget_grab_focus() call to avoid broken
focus states after view (re)loading.

But there is one particular case where we must not do it: if the
popover menu is shown. This is a rare situation which is currently
only possible to trigger by pressing [Spacebar] while the "Show
Hidden Files" menu item has focus.

But this currently relies on the slot calling a NautilusWindow method,
which is a layer violation which is getting in the way of reusing
NautilusWindowSlot in the FileChooser window[4].

Let's use generic GTK/GDK API to assess wether the menu is shown,
and drop the NautilusWindow method.

Originally I've just removed the grab_focus() call, but came to
realize it was still needed, so let's also document my findings here.

Part of: https://gitlab.gnome.org/GNOME/nautilus/-/work_items/3402
This commit is contained in:
António Fernandes 2024-04-27 13:08:52 +01:00
parent c960cfa439
commit 6bd4e06faa
4 changed files with 41 additions and 23 deletions

View file

@ -2502,6 +2502,24 @@ nautilus_window_slot_update_for_new_location (NautilusWindowSlot *self)
nautilus_location_banner_load (self->banner, new_location);
}
static gboolean
focus_is_on_popup (GtkRoot *window)
{
GtkWidget *focus = gtk_root_get_focus (window);
if (focus != NULL)
{
GtkNative *native = gtk_widget_get_native (focus);
if (native != NULL)
{
return GDK_IS_POPUP (gtk_native_get_surface (native));
}
}
return FALSE;
}
static void
view_started_loading (NautilusWindowSlot *self,
NautilusView *view)
@ -2511,12 +2529,29 @@ view_started_loading (NautilusWindowSlot *self,
nautilus_window_slot_set_allow_stop (self, TRUE);
}
/* Only grab focus if the menu isn't showing. Otherwise the menu disappears
* e.g. when the user toggles Show Hidden Files
*/
if (!nautilus_window_is_menu_visible (self->window))
GtkRoot *window = gtk_widget_get_root (GTK_WIDGET (self));
if (!focus_is_on_popup (window))
{
gtk_widget_grab_focus (GTK_WIDGET (self->window));
/* This mysterious gtk_widget_grab_focus() call has been carried over
* many refactorings, along the way having been wrapped in multiple ways
* (nautilus_view_grab_focus(), nautilus_window_pane_grab_focus(),
* nautilus_view_grab_focus()). It's been added in a series of bugfixes
* related to extra pane.[0] If I had to guess, I'd say it was to deal
* with side effects of the grandparent commit[1], which removed a much
* older bugfix[2].
*
* Regardless of its original purpose, we still rely on this call to
* prevent a "lost focus" situation. This is easily reproduced, in a
* build where this call is removed, by refreshing a view where nothing
* is selected. This "lost focus" state means, e.g., some keybindings,
* such as Ctrl+A, won't work.
*
* [0] Commit c69f3a2ba2d0bd23de5a218b8ce13d256481213a
* [1] Commit 4efd42312584b46f248e2839582a87776a7baebe
* [2] Commit 4f7ae827f7e13cf06965cc72ca60cf7801906a33
*/
gtk_widget_grab_focus (GTK_WIDGET (window));
}
nautilus_window_slot_set_loading (self, TRUE);

View file

@ -95,7 +95,6 @@ struct _NautilusWindow
{
AdwApplicationWindow parent_instance;
GtkWidget *app_button;
GMenuModel *undo_redo_section;
AdwTabView *tab_view;
@ -2506,7 +2505,6 @@ nautilus_window_class_init (NautilusWindowClass *class)
gtk_widget_class_set_template_from_resource (wclass,
"/org/gnome/nautilus/ui/nautilus-window.ui");
gtk_widget_class_bind_template_child (wclass, NautilusWindow, app_button);
gtk_widget_class_bind_template_child (wclass, NautilusWindow, undo_redo_section);
gtk_widget_class_bind_template_child (wclass, NautilusWindow, toolbar);
gtk_widget_class_bind_template_child (wclass, NautilusWindow, split_view);
@ -2632,16 +2630,3 @@ nautilus_window_search (NautilusWindow *window,
g_warning ("Trying search on a slot but no active slot present");
}
}
gboolean
nautilus_window_is_menu_visible (NautilusWindow *self)
{
GtkWidget *menu;
g_return_val_if_fail (NAUTILUS_IS_WINDOW (self), FALSE);
menu = GTK_WIDGET (gtk_menu_button_get_popover (GTK_MENU_BUTTON (self->app_button)));
g_return_val_if_fail (menu != NULL, FALSE);
return gtk_widget_is_visible (menu);
}

View file

@ -89,8 +89,6 @@ AdwTabView * nautilus_window_get_tab_view (NautilusWindow *window);
void nautilus_window_show_about_dialog (NautilusWindow *window);
gboolean nautilus_window_is_menu_visible (NautilusWindow *toolbar);
/* sync window GUI with current slot. Used when changing slots,
* and when updating the slot state.
*/

View file

@ -136,7 +136,7 @@
</object>
</property>
<child type="end">
<object class="GtkMenuButton" id="app_button">
<object class="GtkMenuButton">
<property name="tooltip-text" translatable="yes">Main Menu</property>
<property name="icon_name">open-menu-symbolic</property>
<property name="popover">