popovermenu: Cycle around focus also with (Shift+)Tab
authorvanadiae <vanadiae35@gmail.com>
Mon, 5 Jul 2021 17:20:58 +0000 (19:20 +0200)
committervanadiae <vanadiae35@gmail.com>
Wed, 4 Aug 2021 10:11:44 +0000 (12:11 +0200)
Currently when moving the focus with (Shift+)Tab, it also traverses the window's
widgets, although it would be expected that the focus stays within the popover,
as it's (almost) like it's a separate window. This would be consistent with
the behaviour of the Up/down arrows, which do cycle around the focus once it
reaches the end.

So this commit makes the popovermenu cycle around focus in any direction, apart
from left/right because they are used to open and close submenus and it wouldn't
make sense anyway to cycle horizontally as there's usually only one widget per
line.

gtk/gtkpopovermenu.c

index 3f999fa90fd60402fc6036aff82da2dd6b6ffaa6..9a3458584f974233c3e1b28dc151596b74834747 100644 (file)
@@ -480,12 +480,21 @@ gtk_popover_menu_focus (GtkWidget        *widget,
           else
             return TRUE;
         }
-      else if (direction == GTK_DIR_UP || direction == GTK_DIR_DOWN)
+      /* Cycle around with up/down arrows and (Shift+)Tab when modal */
+      else if (gtk_popover_get_autohide (GTK_POPOVER (menu)))
         {
-          GtkWidget *p;
+          GtkWidget *p = gtk_root_get_focus (gtk_widget_get_root (widget));
+
+          /* In the case where the popover doesn't have any focusable child, if
+           * the menu doesn't have any item for example, then the focus will end
+           * up out of the popover, hence creating an infinite loop below. To
+           * avoid this, just say we had focus and stop here.
+           */
+          if (!gtk_widget_is_ancestor (p, widget) && p != widget)
+            return TRUE;
 
           /* cycle around */
-          for (p = gtk_root_get_focus (gtk_widget_get_root (widget));
+          for (;
                p != widget;
                p = gtk_widget_get_parent (p))
             {
@@ -493,7 +502,7 @@ gtk_popover_menu_focus (GtkWidget        *widget,
             }
           if (gtk_widget_focus_move (widget, direction))
             return TRUE;
-       }
+        }
     }
 
   return FALSE;