[gtk/nested-popover-menu] Fix up keynav in popover menus



commit e7974f35fda282ad01fb8345399cb09c16b2eeea
Author: Matthias Clasen <mclasen redhat com>
Date:   Mon Sep 2 09:13:33 2019 +0100

    Fix up keynav in popover menus
    
    Both arrow keys and activating a submenu-bearing
    model button works as expected now.

 gtk/gtkmodelbutton.c    | 68 ++++++++++++++++++++++++++++++++++---------------
 gtk/gtkpopover.c        | 16 +++++++++++-
 gtk/gtkpopovermenu.c    | 22 +++++++++++++---
 gtk/gtkpopovermenubar.c |  6 ++++-
 4 files changed, 87 insertions(+), 25 deletions(-)
---
diff --git a/gtk/gtkmodelbutton.c b/gtk/gtkmodelbutton.c
index c798b1d42d..90518252f1 100644
--- a/gtk/gtkmodelbutton.c
+++ b/gtk/gtkmodelbutton.c
@@ -935,6 +935,8 @@ close_menu (GtkModelButton *button)
     }
 }
 
+static void open_submenu (GtkPopover *popover);
+
 static void
 gtk_model_button_clicked (GtkButton *button)
 {
@@ -946,7 +948,14 @@ gtk_model_button_clicked (GtkButton *button)
     }
   else if (model_button->popover != NULL)
     {
-      gtk_popover_popup (GTK_POPOVER (model_button->popover));
+      GtkPopoverMenu *menu;
+      GtkWidget *submenu;
+
+      menu = (GtkPopoverMenu *)gtk_widget_get_ancestor (GTK_WIDGET (button), GTK_TYPE_POPOVER_MENU);
+      submenu = model_button->popover;
+      gtk_popover_popup (GTK_POPOVER (submenu));
+      gtk_popover_menu_set_open_submenu (menu, submenu);
+      gtk_popover_menu_set_parent_menu (GTK_POPOVER_MENU (submenu), GTK_WIDGET (menu));
     }
   else if (model_button->role == GTK_BUTTON_ROLE_NORMAL)
     {
@@ -1031,7 +1040,14 @@ gtk_model_button_focus (GtkWidget        *widget,
                button->role == GTK_BUTTON_ROLE_NORMAL &&
                button->popover != NULL)
         {
-          gtk_popover_popup (GTK_POPOVER (button->popover));
+          GtkPopoverMenu *menu;
+          GtkWidget *submenu;
+
+          menu = GTK_POPOVER_MENU (gtk_widget_get_ancestor (GTK_WIDGET (button), GTK_TYPE_POPOVER_MENU));
+          submenu = button->popover;
+          gtk_popover_popup (GTK_POPOVER (submenu));
+          gtk_popover_menu_set_open_submenu (menu, submenu);
+          gtk_popover_menu_set_parent_menu (GTK_POPOVER_MENU (submenu), GTK_WIDGET (menu));
           return TRUE;
         }
     }
@@ -1191,34 +1207,46 @@ gtk_model_button_class_init (GtkModelButtonClass *class)
 }
 
 static void
-close_submenus (GtkPopoverMenu *menu)
+close_submenus (GtkPopover *popover)
 {
-  GtkWidget *submenu;
+  GtkPopoverMenu *menu;
 
-  submenu = gtk_popover_menu_get_open_submenu (menu);
-  if (submenu)
+  if (GTK_IS_POPOVER_MENU (popover))
     {
-      close_submenus (GTK_POPOVER_MENU (submenu));
-      gtk_popover_popdown (GTK_POPOVER (submenu));
-      gtk_popover_menu_set_open_submenu (menu, NULL);
+      GtkWidget *submenu;
+
+      menu = GTK_POPOVER_MENU (popover);
+      submenu = gtk_popover_menu_get_open_submenu (menu);
+      if (submenu)
+        {
+          close_submenus (GTK_POPOVER (submenu));
+          gtk_popover_popdown (GTK_POPOVER (submenu));
+          gtk_popover_menu_set_open_submenu (menu, NULL);
+        }
     }
 }
 
 static void
-open_submenu (GtkPopoverMenu *menu)
+open_submenu (GtkPopover *popover)
 {
   GtkWidget *active_item;
+  GtkPopoverMenu *menu;
 
-  active_item = gtk_popover_menu_get_active_item (menu);
-  if (GTK_IS_MODEL_BUTTON (active_item) &&
-      GTK_MODEL_BUTTON (active_item)->popover)
+  if (GTK_IS_POPOVER_MENU (popover))
     {
-      GtkWidget *submenu;
+      menu = GTK_POPOVER_MENU (popover);
 
-      submenu = GTK_MODEL_BUTTON (active_item)->popover;
-      gtk_popover_popup (GTK_POPOVER (submenu));
-      gtk_popover_menu_set_open_submenu (menu, submenu);
-      gtk_popover_menu_set_parent_menu (GTK_POPOVER_MENU (submenu), GTK_WIDGET (menu));
+      active_item = gtk_popover_menu_get_active_item (menu);
+      if (GTK_IS_MODEL_BUTTON (active_item) &&
+          GTK_MODEL_BUTTON (active_item)->popover)
+        {
+          GtkWidget *submenu;
+
+          submenu = GTK_MODEL_BUTTON (active_item)->popover;
+          gtk_popover_popup (GTK_POPOVER (submenu));
+          gtk_popover_menu_set_open_submenu (menu, submenu);
+          gtk_popover_menu_set_parent_menu (GTK_POPOVER_MENU (submenu), GTK_WIDGET (menu));
+        }
     }
 }
 
@@ -1247,11 +1275,11 @@ enter_cb (GtkEventController *controller,
   active_item = gtk_popover_menu_get_active_item (GTK_POPOVER_MENU (popover));
   if (popover && (is || contains) && active_item != target)
     {
-      close_submenus (GTK_POPOVER_MENU (popover));
+      close_submenus (GTK_POPOVER (popover));
 
       gtk_popover_menu_set_active_item (GTK_POPOVER_MENU (popover), target);
 
-      open_submenu (GTK_POPOVER_MENU (popover));
+      open_submenu (GTK_POPOVER (popover));
     }
 }
 
diff --git a/gtk/gtkpopover.c b/gtk/gtkpopover.c
index 031e606c4c..db23eef002 100644
--- a/gtk/gtkpopover.c
+++ b/gtk/gtkpopover.c
@@ -107,6 +107,7 @@
 #include "config.h"
 
 #include "gtkpopoverprivate.h"
+#include "gtkpopovermenuprivate.h"
 #include "gtknative.h"
 #include "gtkwidgetprivate.h"
 #include "gtkeventcontrollerkey.h"
@@ -362,6 +363,19 @@ gtk_popover_focus_out (GtkWidget *widget)
 {
 }
 
+static void
+close_menu (GtkPopover *popover)
+{
+  while (popover)
+    {
+      gtk_popover_popdown (popover);
+      if (GTK_IS_POPOVER_MENU (popover))
+        popover = gtk_popover_menu_get_parent_menu (GTK_POPOVER_MENU (popover));
+      else
+        popover = NULL;
+    }
+}
+
 static gboolean
 gtk_popover_key_pressed (GtkWidget       *widget,
                          guint            keyval,
@@ -370,7 +384,7 @@ gtk_popover_key_pressed (GtkWidget       *widget,
 {
   if (keyval == GDK_KEY_Escape)
     {
-      gtk_popover_popdown (GTK_POPOVER (widget));
+      close_menu (GTK_POPOVER (widget));
       return TRUE;
     }
 
diff --git a/gtk/gtkpopovermenu.c b/gtk/gtkpopovermenu.c
index bf3b701217..e059024460 100644
--- a/gtk/gtkpopovermenu.c
+++ b/gtk/gtkpopovermenu.c
@@ -203,14 +203,19 @@ static void
 focus_out (GtkEventController *controller,
            GdkCrossingMode     mode,
            GdkNotifyType       detail,
-           GtkPopover         *popover)
+           GtkPopoverMenu     *menu)
 {
   gboolean contains_focus;
 
   g_object_get (controller, "contains-focus", &contains_focus, NULL);
 
   if (!contains_focus)
-    gtk_popover_popdown (popover);
+    {
+      if (menu->parent_menu &&
+          GTK_POPOVER_MENU (menu->parent_menu)->open_submenu == menu)
+        GTK_POPOVER_MENU (menu->parent_menu)->open_submenu = NULL;
+      gtk_popover_popdown (GTK_POPOVER (menu));
+    }
 }
 
 static void
@@ -345,10 +350,21 @@ gtk_popover_menu_focus (GtkWidget        *widget,
     }
   else
     {
+      if (GTK_POPOVER_MENU (widget)->open_submenu)
+        {
+          if (gtk_widget_child_focus (GTK_POPOVER_MENU (widget)->open_submenu, direction))
+            return TRUE;
+          return FALSE;
+        }
+
       if (gtk_widget_focus_move (widget, direction))
         return TRUE;
 
-      if (direction == GTK_DIR_UP || direction == GTK_DIR_DOWN)
+      if (direction == GTK_DIR_LEFT || direction == GTK_DIR_RIGHT)
+        {
+          return FALSE;
+        }
+      else if (direction == GTK_DIR_UP || direction == GTK_DIR_DOWN)
         {
           GtkWidget *p;
 
diff --git a/gtk/gtkpopovermenubar.c b/gtk/gtkpopovermenubar.c
index a406b24956..031bb60c80 100644
--- a/gtk/gtkpopovermenubar.c
+++ b/gtk/gtkpopovermenubar.c
@@ -314,7 +314,11 @@ gtk_popover_menu_bar_item_size_allocate (GtkWidget *widget,
 static void
 gtk_popover_menu_bar_item_activate (GtkPopoverMenuBarItem *item)
 {
-  gtk_popover_popup (GTK_POPOVER (item->popover));
+  GtkPopoverMenuBar *bar;
+
+  bar = GTK_POPOVER_MENU_BAR (gtk_widget_get_ancestor (GTK_WIDGET (item), GTK_TYPE_POPOVER_MENU_BAR));
+
+  set_active_item (bar, item, TRUE);
 }
 
 static void


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]