mirror of
https://gitlab.gnome.org/GNOME/gtk.git
synced 2025-01-09 20:20:13 +00:00
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.
This commit is contained in:
parent
13e010deb6
commit
3f6272f56e
@ -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)
|
||||
|
182
gtk/gtkmenubar.c
182
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,
|
||||
gtk_widget_measure (menu_bar->box,
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
@ -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,
|
||||
|
Loading…
Reference in New Issue
Block a user