From 64bfd86b5b532b07af0225d9983f713b7982b06a Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Sun, 19 Jun 2005 03:20:07 +0000 Subject: [PATCH] Allow to construct menu tool buttons. 2005-06-18 Matthias Clasen * gtk/gtkuimanager.c: Allow to construct menu tool buttons. * demos/gtk-demo/appwindow.c: Demonstrate menu tool buttons constructed with GtkUIManager. --- ChangeLog | 5 ++ ChangeLog.pre-2-10 | 5 ++ ChangeLog.pre-2-8 | 5 ++ demos/gtk-demo/appwindow.c | 47 ++++++++++-- docs/reference/ChangeLog | 3 + docs/reference/gtk/tmpl/gtkuimanager.sgml | 5 +- gtk/gtkuimanager.c | 91 +++++++++++++++++------ 7 files changed, 129 insertions(+), 32 deletions(-) diff --git a/ChangeLog b/ChangeLog index 98ecaf8076..825d2dec2a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,10 @@ 2005-06-18 Matthias Clasen + * gtk/gtkuimanager.c: Allow to construct menu tool buttons. + + * demos/gtk-demo/appwindow.c: Demonstrate menu tool buttons + constructed with GtkUIManager. + * gtk/gtk.symbols: * gtk/gtkimage.h: * gtk/gtkimage.c (gtk_image_clear): Make this function diff --git a/ChangeLog.pre-2-10 b/ChangeLog.pre-2-10 index 98ecaf8076..825d2dec2a 100644 --- a/ChangeLog.pre-2-10 +++ b/ChangeLog.pre-2-10 @@ -1,5 +1,10 @@ 2005-06-18 Matthias Clasen + * gtk/gtkuimanager.c: Allow to construct menu tool buttons. + + * demos/gtk-demo/appwindow.c: Demonstrate menu tool buttons + constructed with GtkUIManager. + * gtk/gtk.symbols: * gtk/gtkimage.h: * gtk/gtkimage.c (gtk_image_clear): Make this function diff --git a/ChangeLog.pre-2-8 b/ChangeLog.pre-2-8 index 98ecaf8076..825d2dec2a 100644 --- a/ChangeLog.pre-2-8 +++ b/ChangeLog.pre-2-8 @@ -1,5 +1,10 @@ 2005-06-18 Matthias Clasen + * gtk/gtkuimanager.c: Allow to construct menu tool buttons. + + * demos/gtk-demo/appwindow.c: Demonstrate menu tool buttons + constructed with GtkUIManager. + * gtk/gtk.symbols: * gtk/gtkimage.h: * gtk/gtkimage.c (gtk_image_clear): Make this function diff --git a/demos/gtk-demo/appwindow.c b/demos/gtk-demo/appwindow.c index 5cf00815d3..7f2d7986a9 100644 --- a/demos/gtk-demo/appwindow.c +++ b/demos/gtk-demo/appwindow.c @@ -1,6 +1,6 @@ /* Application main window * - * Demonstrates a typical application window, with menubar, toolbar, statusbar. + * Demonstrates a typical application window with menubar, toolbar, statusbar. */ #include @@ -144,9 +144,32 @@ about_cb (GtkAction *action, g_object_unref (transparent); } +typedef struct +{ + GtkAction action; +} ToolMenuAction; + +typedef struct +{ + GtkActionClass parent_class; +} ToolMenuActionClass; + +G_DEFINE_TYPE(ToolMenuAction, tool_menu_action, GTK_TYPE_ACTION); + +static void +tool_menu_action_class_init (ToolMenuActionClass *class) +{ + GTK_ACTION_CLASS (class)->toolbar_item_type = GTK_TYPE_MENU_TOOL_BUTTON; +} + +static void +tool_menu_action_init (ToolMenuAction *action) +{ +} static GtkActionEntry entries[] = { { "FileMenu", NULL, "_File" }, /* name, stock id, label */ + { "OpenMenu", NULL, "_Open" }, /* name, stock id, label */ { "PreferencesMenu", NULL, "_Preferences" }, /* name, stock id, label */ { "ColorMenu", NULL, "_Color" }, /* name, stock id, label */ { "ShapeMenu", NULL, "_Shape" }, /* name, stock id, label */ @@ -155,9 +178,9 @@ static GtkActionEntry entries[] = { "_New", "N", /* label, accelerator */ "Create a new file", /* tooltip */ G_CALLBACK (activate_action) }, - { "Open", GTK_STOCK_OPEN, /* name, stock id */ - "_Open","O", /* label, accelerator */ - "Open a file", /* tooltip */ + { "File1", NULL, /* name, stock id */ + "File1", NULL, /* label, accelerator */ + "Open first file", /* tooltip */ G_CALLBACK (activate_action) }, { "Save", GTK_STOCK_SAVE, /* name, stock id */ "_Save","S", /* label, accelerator */ @@ -258,8 +281,12 @@ static const gchar *ui_info = " " " " " " -" " -" " +" " +" " +" " +" " +" " +" " " " " " " " @@ -394,6 +421,7 @@ do_appwindow (GtkWidget *do_widget) GtkWidget *bar; GtkTextBuffer *buffer; GtkActionGroup *action_group; + GtkAction *open_action; GtkUIManager *merge; GError *error = NULL; @@ -421,6 +449,13 @@ do_appwindow (GtkWidget *do_widget) */ action_group = gtk_action_group_new ("AppWindowActions"); + open_action = g_object_new (tool_menu_action_get_type (), + "name", "Open", + "label", "_Open", + "tooltip", "Open a file", + "stock-id", GTK_STOCK_OPEN, + NULL); + gtk_action_group_add_action (action_group, open_action); gtk_action_group_add_actions (action_group, entries, n_entries, window); diff --git a/docs/reference/ChangeLog b/docs/reference/ChangeLog index 42d5fdcd5a..ad452d8d38 100644 --- a/docs/reference/ChangeLog +++ b/docs/reference/ChangeLog @@ -1,5 +1,8 @@ 2005-06-18 Matthias Clasen + * gtk/tmpl/gtkuimanager.sgml: Document that + toolitem elements may have menu subelements. + * gtk/gtk-sections.txt: Updates 2005-06-17 Matthias Clasen diff --git a/docs/reference/gtk/tmpl/gtkuimanager.sgml b/docs/reference/gtk/tmpl/gtkuimanager.sgml index ac3b5aa995..956617f290 100644 --- a/docs/reference/gtk/tmpl/gtkuimanager.sgml +++ b/docs/reference/gtk/tmpl/gtkuimanager.sgml @@ -22,7 +22,7 @@ roughly described by the following DTD. <!ELEMENT toolbar (toolitem|separator|placeholder)* > <!ELEMENT placeholder (menuitem|toolitem|separator|placeholder|menu)* > <!ELEMENT menuitem EMPTY > -<!ELEMENT toolitem EMPTY > +<!ELEMENT toolitem (menu?) > <!ELEMENT separator EMPTY > <!ELEMENT accelerator EMPTY > <!ATTLIST menubar name #IMPLIED @@ -115,7 +115,8 @@ action toolitem a #GtkToolItem subclass, the exact type depends on the -action +action. Note that toolitem elements may contain a menu element, but only +if their associated action specifies a #GtkMenuToolButton as proxy. separator a #GtkSeparatorMenuItem or diff --git a/gtk/gtkuimanager.c b/gtk/gtkuimanager.c index d5e759c59d..ee690925bc 100644 --- a/gtk/gtkuimanager.c +++ b/gtk/gtkuimanager.c @@ -36,6 +36,7 @@ #include "gtkmenu.h" #include "gtkmenubar.h" #include "gtkmenushell.h" +#include "gtkmenutoolbutton.h" #include "gtkseparatormenuitem.h" #include "gtkseparatortoolitem.h" #include "gtktearoffmenuitem.h" @@ -859,11 +860,6 @@ get_child_node (GtkUIManager *self, { GNode *child = NULL; - g_return_val_if_fail (parent == NULL || - (NODE_INFO (parent)->type != NODE_TYPE_MENUITEM && - NODE_INFO (parent)->type != NODE_TYPE_TOOLITEM), - NULL); - if (parent) { if (childname) @@ -1213,6 +1209,21 @@ start_element_handler (GMarkupParseContext *context, node_prepend_ui_reference (ctx->current, ctx->merge_id, action_quark); + raise_error = FALSE; + } + else if (ctx->state == STATE_TOOLITEM && !strcmp (element_name, "menu")) + { + ctx->state = STATE_MENU; + + ctx->current = get_child_node (self, g_node_last_child (ctx->current), + node_name, strlen (node_name), + NODE_TYPE_MENU, + TRUE, top); + if (NODE_INFO (ctx->current)->action_name == 0) + NODE_INFO (ctx->current)->action_name = action_quark; + + node_prepend_ui_reference (ctx->current, ctx->merge_id, action_quark); + raise_error = FALSE; } else if (ctx->state == STATE_MENU && !strcmp (element_name, "menuitem")) @@ -1373,6 +1384,11 @@ end_element_handler (GMarkupParseContext *context, ctx->current = ctx->current->parent; if (NODE_INFO (ctx->current)->type == NODE_TYPE_ROOT) ctx->state = STATE_ROOT; + else if (NODE_INFO (ctx->current)->type == NODE_TYPE_TOOLITEM) + { + ctx->current = ctx->current->parent; + ctx->state = STATE_TOOLITEM; + } /* else, stay in same state */ break; case STATE_MENUITEM: @@ -2141,7 +2157,10 @@ update_node (GtkUIManager *self, GtkWidget *menu; GList *siblings; - menu = gtk_menu_item_get_submenu (GTK_MENU_ITEM (info->proxy)); + if (GTK_IS_MENU (info->proxy)) + menu = info->proxy; + else + menu = gtk_menu_item_get_submenu (GTK_MENU_ITEM (info->proxy)); siblings = gtk_container_get_children (GTK_CONTAINER (menu)); if (siblings != NULL && GTK_IS_TEAROFF_MENU_ITEM (siblings->data)) { @@ -2187,12 +2206,16 @@ update_node (GtkUIManager *self, if (info->proxy && G_OBJECT_TYPE (info->proxy) != GTK_ACTION_GET_CLASS (action)->menu_item_type) { - prev_submenu = gtk_menu_item_get_submenu (GTK_MENU_ITEM (info->proxy)); - if (prev_submenu) + if (GTK_IS_MENU_ITEM (info->proxy)) { - g_object_ref (prev_submenu); - gtk_menu_item_set_submenu (GTK_MENU_ITEM (info->proxy), NULL); + prev_submenu = gtk_menu_item_get_submenu (GTK_MENU_ITEM (info->proxy)); + if (prev_submenu) + { + g_object_ref (prev_submenu); + gtk_menu_item_set_submenu (GTK_MENU_ITEM (info->proxy), NULL); + } } + gtk_action_disconnect_proxy (info->action, info->proxy); gtk_container_remove (GTK_CONTAINER (info->proxy->parent), info->proxy); @@ -2205,16 +2228,13 @@ update_node (GtkUIManager *self, GtkWidget *menushell; gint pos; - if (find_menu_position (node, &menushell, &pos)) + if (NODE_INFO (node->parent)->type == NODE_TYPE_TOOLITEM || + find_menu_position (node, &menushell, &pos)) { GtkWidget *tearoff; GtkWidget *filler; - info->proxy = gtk_action_create_menu_item (action); - g_object_ref (info->proxy); - gtk_object_sink (GTK_OBJECT (info->proxy)); menu = gtk_menu_new (); - gtk_widget_set_name (info->proxy, info->name); gtk_widget_set_name (menu, info->name); tearoff = gtk_tearoff_menu_item_new (); gtk_widget_set_no_show_all (tearoff, TRUE); @@ -2226,10 +2246,27 @@ update_node (GtkUIManager *self, gtk_widget_set_sensitive (filler, FALSE); gtk_widget_set_no_show_all (filler, TRUE); gtk_menu_shell_append (GTK_MENU_SHELL (menu), filler); - gtk_menu_item_set_submenu (GTK_MENU_ITEM (info->proxy), menu); - gtk_menu_shell_insert (GTK_MENU_SHELL (menushell), info->proxy, pos); - g_signal_connect (info->proxy, "notify::visible", - G_CALLBACK (update_smart_separators), NULL); + + if (NODE_INFO (node->parent)->type == NODE_TYPE_TOOLITEM) + { + info->proxy = menu; + g_object_ref (info->proxy); + gtk_object_sink (GTK_OBJECT (info->proxy)); + gtk_menu_tool_button_set_menu (GTK_MENU_TOOL_BUTTON (NODE_INFO (node->parent)->proxy), + menu); + } + else + { + info->proxy = gtk_action_create_menu_item (action); + g_object_ref (info->proxy); + gtk_object_sink (GTK_OBJECT (info->proxy)); + g_signal_connect (info->proxy, "notify::visible", + G_CALLBACK (update_smart_separators), NULL); + gtk_widget_set_name (info->proxy, info->name); + + gtk_menu_item_set_submenu (GTK_MENU_ITEM (info->proxy), menu); + gtk_menu_shell_insert (GTK_MENU_SHELL (menushell), info->proxy, pos); + } } } else @@ -2241,7 +2278,11 @@ update_node (GtkUIManager *self, prev_submenu); g_object_unref (prev_submenu); } - menu = gtk_menu_item_get_submenu (GTK_MENU_ITEM (info->proxy)); + + if (GTK_IS_MENU (info->proxy)) + menu = info->proxy; + else + menu = gtk_menu_item_get_submenu (GTK_MENU_ITEM (info->proxy)); siblings = gtk_container_get_children (GTK_CONTAINER (menu)); if (siblings != NULL && GTK_IS_TEAROFF_MENU_ITEM (siblings->data)) { @@ -2422,7 +2463,7 @@ update_node (GtkUIManager *self, break; case NODE_TYPE_TOOLITEM: /* remove the proxy if it is of the wrong type ... */ - if (info->proxy && + if (info->proxy && G_OBJECT_TYPE (info->proxy) != GTK_ACTION_GET_CLASS (action)->toolbar_item_type) { g_signal_handlers_disconnect_by_func (info->proxy, @@ -2454,7 +2495,7 @@ update_node (GtkUIManager *self, * tooltips on toolitems can't be set before the toolitem * is added to the toolbar. */ - g_object_notify (G_OBJECT (action), "tooltip"); + g_object_notify (G_OBJECT (action), "tooltip"); } } else @@ -2560,9 +2601,11 @@ update_node (GtkUIManager *self, if (info->proxy) { - if (info->type == NODE_TYPE_MENU) + if (info->type == NODE_TYPE_MENU && GTK_IS_MENU_ITEM (info->proxy)) update_smart_separators (gtk_menu_item_get_submenu (GTK_MENU_ITEM (info->proxy))); - else if (info->type == NODE_TYPE_TOOLBAR || info->type == NODE_TYPE_POPUP) + else if (info->type == NODE_TYPE_MENU || + info->type == NODE_TYPE_TOOLBAR || + info->type == NODE_TYPE_POPUP) update_smart_separators (info->proxy); }