From 3f6272f56eb7b7d32aad1979c67a744a14aa02ed Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Fri, 31 May 2019 02:36:34 +0000 Subject: [PATCH] More menu restructuring Make GtkMenuBar use a box as well, and let GtkMenuShell get the items from GtkMenuBar and GtkMenu via a vfunc. Use that to fix the keynav implementation in GtkMenuShell. --- gtk/gtkmenu.c | 24 ++++++ gtk/gtkmenubar.c | 186 ++++++++++++++++----------------------------- gtk/gtkmenushell.c | 56 ++++++++++---- 3 files changed, 131 insertions(+), 135 deletions(-) diff --git a/gtk/gtkmenu.c b/gtk/gtkmenu.c index 6592a909c2..98f1541184 100644 --- a/gtk/gtkmenu.c +++ b/gtk/gtkmenu.c @@ -195,6 +195,8 @@ static void gtk_menu_move_current (GtkMenuShell *menu_shell, static void gtk_menu_deactivate (GtkMenuShell *menu_shell); static void gtk_menu_position (GtkMenu *menu); +static void gtk_menu_add (GtkContainer *menu, + GtkWidget *widget); static void gtk_menu_remove (GtkContainer *menu, GtkWidget *widget); @@ -239,6 +241,14 @@ menu_queue_resize (GtkMenu *menu) gtk_widget_queue_resize (GTK_WIDGET (menu)); } +static GList * +gtk_menu_get_items (GtkMenuShell *menu_shell) +{ + GtkMenuPrivate *priv = GTK_MENU (menu_shell)->priv; + + return gtk_container_get_children (GTK_CONTAINER (priv->box)); +} + static void gtk_menu_class_init (GtkMenuClass *class) { @@ -261,6 +271,7 @@ gtk_menu_class_init (GtkMenuClass *class) widget_class->grab_notify = gtk_menu_grab_notify; widget_class->measure = gtk_menu_measure; + container_class->add = gtk_menu_add; container_class->remove = gtk_menu_remove; menu_shell_class->submenu_placement = GTK_LEFT_RIGHT; @@ -268,6 +279,7 @@ gtk_menu_class_init (GtkMenuClass *class) menu_shell_class->insert = gtk_menu_real_insert; menu_shell_class->get_popup_delay = gtk_menu_get_popup_delay; menu_shell_class->move_current = gtk_menu_move_current; + menu_shell_class->get_items = gtk_menu_get_items; /** * GtkMenu::popped-up: @@ -978,6 +990,18 @@ gtk_menu_detach (GtkMenu *menu) g_object_unref (menu); } +static void +gtk_menu_add (GtkContainer *container, + GtkWidget *widget) +{ + GtkMenu *menu = GTK_MENU (container); + GtkMenuPrivate *priv = menu->priv; + + gtk_container_add (GTK_CONTAINER (priv->box), widget); + + menu_queue_resize (menu); +} + static void gtk_menu_remove (GtkContainer *container, GtkWidget *widget) diff --git a/gtk/gtkmenubar.c b/gtk/gtkmenubar.c index 5ae9f35a7c..165412318f 100644 --- a/gtk/gtkmenubar.c +++ b/gtk/gtkmenubar.c @@ -51,10 +51,12 @@ #include "gtksizerequest.h" #include "gtkwindow.h" #include "gtkcontainerprivate.h" +#include "gtkcheckmenuitem.h" #include "gtkintl.h" #include "gtkprivate.h" #include "gtktypebuiltins.h" #include "gtkwidgetprivate.h" +#include "gtkbox.h" #define MENU_BAR_POPUP_DELAY 0 @@ -65,6 +67,9 @@ typedef struct _GtkMenuBarClass GtkMenuBarClass; struct _GtkMenuBar { GtkMenuShell menu_shell; + + int toggle_size; + GtkWidget *box; }; struct _GtkMenuBarClass @@ -72,6 +77,11 @@ struct _GtkMenuBarClass GtkMenuShellClass parent_class; }; +static void gtk_menu_bar_add (GtkContainer *container, + GtkWidget *widget); +static void gtk_menu_bar_remove (GtkContainer *container, + GtkWidget *widget); + static void gtk_menu_bar_measure (GtkWidget *widget, GtkOrientation orientation, int for_size, @@ -88,13 +98,25 @@ static void gtk_menu_bar_unroot (GtkWidget *widget); static gint gtk_menu_bar_get_popup_delay (GtkMenuShell *menu_shell); static void gtk_menu_bar_move_current (GtkMenuShell *menu_shell, GtkMenuDirectionType direction); +static void gtk_menu_bar_insert (GtkMenuShell *menu_shell, + GtkWidget *child, + gint position); G_DEFINE_TYPE (GtkMenuBar, gtk_menu_bar, GTK_TYPE_MENU_SHELL) +static GList * +gtk_menu_bar_get_items (GtkMenuShell *menu_shell) +{ + GtkMenuBar *menu_bar = GTK_MENU_BAR (menu_shell); + + return gtk_container_get_children (GTK_CONTAINER (menu_bar->box)); +} + static void gtk_menu_bar_class_init (GtkMenuBarClass *class) { GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class); + GtkContainerClass *container_class = GTK_CONTAINER_CLASS (class); GtkMenuShellClass *menu_shell_class = GTK_MENU_SHELL_CLASS (class); GtkBindingSet *binding_set; @@ -104,9 +126,14 @@ gtk_menu_bar_class_init (GtkMenuBarClass *class) widget_class->root = gtk_menu_bar_root; widget_class->unroot = gtk_menu_bar_unroot; + container_class->add = gtk_menu_bar_add; + container_class->remove = gtk_menu_bar_remove; + + menu_shell_class->insert = gtk_menu_bar_insert; menu_shell_class->submenu_placement = GTK_TOP_BOTTOM; menu_shell_class->get_popup_delay = gtk_menu_bar_get_popup_delay; menu_shell_class->move_current = gtk_menu_bar_move_current; + menu_shell_class->get_items = gtk_menu_bar_get_items; binding_set = gtk_binding_set_by_class (class); gtk_binding_entry_add_signal (binding_set, @@ -157,6 +184,8 @@ gtk_menu_bar_class_init (GtkMenuBarClass *class) static void gtk_menu_bar_init (GtkMenuBar *menu_bar) { + menu_bar->box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0); + gtk_widget_set_parent (menu_bar->box, GTK_WIDGET (menu_bar)); } /** @@ -181,58 +210,13 @@ gtk_menu_bar_measure (GtkWidget *widget, int *minimum_baseline, int *natural_baseline) { - GtkMenuShell *menu_shell; - GtkWidget *child; - GList *children; - gboolean use_toggle_size, use_maximize; - gint child_minimum, child_natural; + GtkMenuBar *menu_bar = GTK_MENU_BAR (widget); - *minimum = 0; - *natural = 0; - - menu_shell = GTK_MENU_SHELL (widget); - - children = menu_shell->priv->children; - - use_toggle_size = (orientation == GTK_ORIENTATION_HORIZONTAL); - use_maximize = (orientation == GTK_ORIENTATION_VERTICAL); - - while (children) - { - child = children->data; - children = children->next; - - if (gtk_widget_get_visible (child)) - { - gtk_widget_measure (child, - orientation, - for_size, - &child_minimum, &child_natural, - NULL, NULL); - - if (use_toggle_size) - { - gint toggle_size; - - gtk_menu_item_toggle_size_request (GTK_MENU_ITEM (child), - &toggle_size); - - child_minimum += toggle_size; - child_natural += toggle_size; - } - - if (use_maximize) - { - *minimum = MAX (*minimum, child_minimum); - *natural = MAX (*natural, child_natural); - } - else - { - *minimum += child_minimum; - *natural += child_natural; - } - } - } + gtk_widget_measure (menu_bar->box, + orientation, + for_size, + minimum, natural, + minimum_baseline, natural_baseline); } static void @@ -241,75 +225,11 @@ gtk_menu_bar_size_allocate (GtkWidget *widget, int height, int baseline) { - GtkMenuShell *menu_shell; - GtkWidget *child; - GList *children; - GtkAllocation remaining_space; - GArray *requested_sizes; - gint toggle_size; - guint i; - int size; - gboolean ltr = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_LTR); + GtkMenuBar *menu_bar = GTK_MENU_BAR (widget); - menu_shell = GTK_MENU_SHELL (widget); - - if (!menu_shell->priv->children) - return; - - remaining_space = (GtkAllocation) {0, 0, width, height}; - requested_sizes = g_array_new (FALSE, FALSE, sizeof (GtkRequestedSize)); - size = remaining_space.width; - - for (children = menu_shell->priv->children; children; children = children->next) - { - GtkRequestedSize request; - child = children->data; - - if (!gtk_widget_get_visible (child)) - continue; - - request.data = child; - gtk_widget_measure (child, GTK_ORIENTATION_HORIZONTAL, - remaining_space.height, - &request.minimum_size, &request.natural_size, - NULL, NULL); - gtk_menu_item_toggle_size_request (GTK_MENU_ITEM (child), - &toggle_size); - request.minimum_size += toggle_size; - request.natural_size += toggle_size; - - gtk_menu_item_toggle_size_allocate (GTK_MENU_ITEM (child), toggle_size); - - g_array_append_val (requested_sizes, request); - - size -= request.minimum_size; - } - - size = gtk_distribute_natural_allocation (size, - requested_sizes->len, - (GtkRequestedSize *) requested_sizes->data); - - for (i = 0; i < requested_sizes->len; i++) - { - GtkAllocation child_allocation = remaining_space; - GtkRequestedSize *request = &g_array_index (requested_sizes, GtkRequestedSize, i); - - child_allocation.width = request->minimum_size; - remaining_space.width -= request->minimum_size; - - if (i + 1 == requested_sizes->len && GTK_IS_MENU_ITEM (request->data) && - GTK_MENU_ITEM (request->data)->priv->right_justify) - ltr = !ltr; - - if (ltr) - remaining_space.x += request->minimum_size; - else - child_allocation.x += remaining_space.width; - - gtk_widget_size_allocate (request->data, &child_allocation, -1); - } - - g_array_free (requested_sizes, TRUE); + gtk_widget_size_allocate (menu_bar->box, + &(GtkAllocation) { 0, 0, width, height }, + baseline); } static GList * @@ -503,3 +423,31 @@ gtk_menu_bar_new_from_model (GMenuModel *model) return menubar; } + +static void +gtk_menu_bar_add (GtkContainer *container, + GtkWidget *widget) +{ + GtkMenuBar *menu_bar = GTK_MENU_BAR (container); + + gtk_container_add (GTK_CONTAINER (menu_bar->box), widget); +} + +static void +gtk_menu_bar_remove (GtkContainer *container, + GtkWidget *widget) +{ + GtkMenuBar *menu_bar = GTK_MENU_BAR (container); + + gtk_container_remove (GTK_CONTAINER (menu_bar->box), widget); +} + +static void +gtk_menu_bar_insert (GtkMenuShell *menu_shell, + GtkWidget *child, + gint position) +{ + GtkMenuBar *menu_bar = GTK_MENU_BAR (menu_shell); + + gtk_container_add (GTK_CONTAINER (menu_bar->box), child); +} diff --git a/gtk/gtkmenushell.c b/gtk/gtkmenushell.c index d141c13f42..7ae0a0a1d5 100644 --- a/gtk/gtkmenushell.c +++ b/gtk/gtkmenushell.c @@ -656,13 +656,16 @@ click_pressed (GtkGestureClick *gesture, GtkMenuShellPrivate *priv = menu_shell->priv; GtkWidget *menu_item; GdkEvent *event; + GtkWidget *item_shell; event = gtk_get_current_event (); menu_item = gtk_get_event_target_with_type (event, GTK_TYPE_MENU_ITEM); + if (menu_item) + item_shell = gtk_widget_get_ancestor (GTK_WIDGET (menu_item), GTK_TYPE_MENU_SHELL); if (menu_item && _gtk_menu_item_is_selectable (menu_item) && - gtk_widget_get_parent (menu_item) == GTK_WIDGET (menu_shell)) + item_shell == GTK_WIDGET (menu_shell)) { if (menu_item != menu_shell->priv->active_menu_item) { @@ -699,7 +702,7 @@ click_pressed (GtkGestureClick *gesture, if (menu_item) { if (_gtk_menu_item_is_selectable (menu_item) && - gtk_widget_get_parent (menu_item) == GTK_WIDGET (menu_shell) && + item_shell == GTK_WIDGET (menu_shell) && menu_item != priv->active_menu_item) { priv->active = TRUE; @@ -1194,6 +1197,12 @@ gtk_menu_shell_activate_item (GtkMenuShell *menu_shell, g_object_unref (menu_item); } +static GList * +gtk_menu_shell_get_items (GtkMenuShell *menu_shell) +{ + return GTK_MENU_SHELL_GET_CLASS (menu_shell)->get_items (menu_shell); +} + /* Distance should be +/- 1 */ static gboolean gtk_menu_shell_real_move_selected (GtkMenuShell *menu_shell, @@ -1203,7 +1212,8 @@ gtk_menu_shell_real_move_selected (GtkMenuShell *menu_shell, if (priv->active_menu_item) { - GList *node = g_list_find (priv->children, priv->active_menu_item); + GList *children = gtk_menu_shell_get_items (menu_shell); + GList *node = g_list_find (children, priv->active_menu_item); GList *start_node = node; if (distance > 0) @@ -1215,7 +1225,7 @@ gtk_menu_shell_real_move_selected (GtkMenuShell *menu_shell, if (node) node = node->next; else - node = priv->children; + node = children; } } else @@ -1227,12 +1237,14 @@ gtk_menu_shell_real_move_selected (GtkMenuShell *menu_shell, if (node) node = node->prev; else - node = g_list_last (priv->children); + node = g_list_last (children); } } if (node) gtk_menu_shell_select_item (menu_shell, node->data); + + g_list_free (children); } return TRUE; @@ -1264,14 +1276,13 @@ void gtk_menu_shell_select_first (GtkMenuShell *menu_shell, gboolean search_sensitive) { - GtkMenuShellPrivate *priv; + GList *children; GList *tmp_list; g_return_if_fail (GTK_IS_MENU_SHELL (menu_shell)); - priv = menu_shell->priv; - - tmp_list = priv->children; + children = gtk_menu_shell_get_items (menu_shell); + tmp_list = children; while (tmp_list) { GtkWidget *child = tmp_list->data; @@ -1280,21 +1291,24 @@ gtk_menu_shell_select_first (GtkMenuShell *menu_shell, _gtk_menu_item_is_selectable (child)) { gtk_menu_shell_select_item (menu_shell, child); - return; + break; } tmp_list = tmp_list->next; } + + g_list_free (children); } void _gtk_menu_shell_select_last (GtkMenuShell *menu_shell, gboolean search_sensitive) { - GtkMenuShellPrivate *priv = menu_shell->priv; GList *tmp_list; + GList *children; - tmp_list = g_list_last (priv->children); + children = gtk_menu_shell_get_items (menu_shell); + tmp_list = g_list_last (children); while (tmp_list) { GtkWidget *child = tmp_list->data; @@ -1303,11 +1317,13 @@ _gtk_menu_shell_select_last (GtkMenuShell *menu_shell, _gtk_menu_item_is_selectable (child)) { gtk_menu_shell_select_item (menu_shell, child); - return; + break; } tmp_list = tmp_list->prev; } + + g_list_free (children); } static gboolean @@ -1805,14 +1821,19 @@ gtk_menu_shell_tracker_remove_func (gint position, gpointer user_data) { GtkMenuShell *menu_shell = user_data; + GList *children; GtkWidget *child; - child = g_list_nth_data (menu_shell->priv->children, position); + children = gtk_menu_shell_get_items (menu_shell); + + child = g_list_nth_data (children, position); /* We use destroy here because in the case of an item with a submenu, * the attached-to from the submenu holds a ref on the item and a * simple gtk_container_remove() isn't good enough to break that. */ gtk_widget_destroy (child); + + g_list_free (children); } static void @@ -1956,6 +1977,7 @@ gtk_menu_shell_bind_model (GtkMenuShell *menu_shell, gboolean with_separators) { GtkActionMuxer *muxer; + GList *children, *l; g_return_if_fail (GTK_IS_MENU_SHELL (menu_shell)); g_return_if_fail (model == NULL || G_IS_MENU_MODEL (model)); @@ -1964,8 +1986,10 @@ gtk_menu_shell_bind_model (GtkMenuShell *menu_shell, g_clear_pointer (&menu_shell->priv->tracker, gtk_menu_tracker_free); - while (menu_shell->priv->children) - gtk_container_remove (GTK_CONTAINER (menu_shell), menu_shell->priv->children->data); + children = gtk_menu_shell_get_items (menu_shell); + for (l = children; l; l = l->next) + gtk_widget_destroy (GTK_WIDGET (l->data)); + g_list_free (children); if (model) menu_shell->priv->tracker = gtk_menu_tracker_new (GTK_ACTION_OBSERVABLE (muxer), model,