]> Pileus Git - ~andy/gtk/commitdiff
GtkBuilder: change format of menus
authorRyan Lortie <desrt@desrt.ca>
Wed, 25 Jan 2012 23:23:25 +0000 (18:23 -0500)
committerRyan Lortie <desrt@desrt.ca>
Thu, 26 Jan 2012 00:42:19 +0000 (19:42 -0500)
Change the format of GtkBuilder <menu> to be more in-line with the style
of the rest of GtkBuilder so that we can do translation in a consistent
way.

The format is now substantially more difficult to hand-write, but tools
should be along soon.

There is an xslt program attached to the bug to help you convert your
existing .ui files from the old format to the new one.

https://bugzilla.gnome.org/show_bug.cgi?id=668696

demos/gtk-demo/application.ui
demos/gtk-demo/menus.ui
examples/bloatpad.c
gtk/Makefile.am
gtk/gtkbuilder-menus.c [new file with mode: 0644]
gtk/gtkbuilderparser.c
gtk/gtkbuilderprivate.h

index b99e5ca0d5cbe111f96054cb7752dc459322d848..708513439628a976fccf8cea42c93199d3d8c064 100644 (file)
@@ -18,8 +18,7 @@
           </object>
         </child>
         <child>
-          <object class="GtkSeparatorToolItem" id="sep">
-          </object>
+          <object class="GtkSeparatorToolItem" id="sep"/>
         </child>
         <child>
           <object class="GtkToolButton" id="logo">
@@ -97,6 +96,9 @@
     </child>
   </object>
   <menu id="toolmenu">
-    <item label='File1' action='win.file1'/>
+    <item>
+      <attribute name="label">File1</attribute>
+      <attribute name="action">win.file1</attribute>
+    </item>
   </menu>
 </interface>
index 2f1e105f6beb7e5f6612c8a01af68afaba036b3a..0bbe11a8d96e3ac33d83806fa6b01fb35d18a571 100644 (file)
 <interface>
   <menu id="appmenu">
     <section>
-      <item label="_New" action="app.new" accel="&lt;Primary&gt;n"/>
-      <item label="_Open" action="app.open"/>
-      <item label="_Save" action="app.save" accel="&lt;Primary&gt;s"/>
-      <item label="Save _As..." action="app.save-as" accel="&lt;Primary&gt;s"/>
+      <item>
+        <attribute name="label" translatable="yes">_New</attribute>
+        <attribute name="action">app.new</attribute>
+        <attribute name="accel">&lt;Primary&gt;n</attribute>
+      </item>
+      <item>
+        <attribute name="label" translatable="yes">_Open</attribute>
+        <attribute name="action">app.open</attribute>
+      </item>
+      <item>
+        <attribute name="label" translatable="yes">_Save</attribute>
+        <attribute name="action">app.save</attribute>
+        <attribute name="accel">&lt;Primary&gt;s</attribute>
+      </item>
+      <item>
+        <attribute name="label" translatable="yes">Save _As...</attribute>
+        <attribute name="action">app.save-as</attribute>
+        <attribute name="accel">&lt;Primary&gt;s</attribute>
+      </item>
     </section>
     <section>
-      <item label="_Quit" action="app.quit" accel="&lt;Primary&gt;q"/>
+      <item>
+        <attribute name="label" translatable="yes">_Quit</attribute>
+        <attribute name="action">app.quit</attribute>
+        <attribute name="accel">&lt;Primary&gt;q</attribute>
+      </item>
     </section>
   </menu>
   <menu id="menubar">
-    <submenu label="_Preferences">
+    <submenu>
+      <attribute name="label" translatable="yes">_Preferences</attribute>
       <section>
-        <item label="_Prefer Dark Theme" action="app.dark"/>
-        <item label="_Hide Titlebar when maximized" action="win.titlebar"/>
-        <submenu label="_Color">
+        <item>
+          <attribute name="label" translatable="yes">_Prefer Dark Theme</attribute>
+          <attribute name="action">app.dark</attribute>
+        </item>
+        <item>
+          <attribute name="label" translatable="yes">_Hide Titlebar when maximized</attribute>
+          <attribute name="action">win.titlebar</attribute>
+        </item>
+        <submenu>
+          <attribute name="label" translatable="yes">_Color</attribute>
           <section>
-            <item label="_Red" action="app.color" target="red" accel="&lt;Primary&gt;r"/>
-            <item label="_Green" action="app.color" target="green" accel="&lt;Primary&gt;g"/>
-            <item label="_Blue" action="app.color" target="blue" accel="&lt;Primary&gt;b"/>
+            <item>
+              <attribute name="label" translatable="yes">_Red</attribute>
+              <attribute name="action">app.color</attribute>
+              <attribute name="target">red</attribute>
+              <attribute name="accel">&lt;Primary&gt;r</attribute>
+            </item>
+            <item>
+              <attribute name="label" translatable="yes">_Green</attribute>
+              <attribute name="action">app.color</attribute>
+              <attribute name="target">green</attribute>
+              <attribute name="accel">&lt;Primary&gt;g</attribute>
+            </item>
+            <item>
+              <attribute name="label" translatable="yes">_Blue</attribute>
+              <attribute name="action">app.color</attribute>
+              <attribute name="target">blue</attribute>
+              <attribute name="accel">&lt;Primary&gt;b</attribute>
+            </item>
           </section>
         </submenu>
-        <submenu label="_Shape">
+        <submenu>
+          <attribute name="label" translatable="yes">_Shape</attribute>
           <section>
-            <item label="_Square" action="win.shape" target="square" accel="&lt;Primary&gt;s"/>
-            <item label="_Rectangle" action="win.shape" target="rectangle" accel="&lt;Primary&gt;r"/>
-            <item label="_Oval" action="win.shape" target="oval" accel="&lt;Primary&gt;o"/>
+            <item>
+              <attribute name="label" translatable="yes">_Square</attribute>
+              <attribute name="action">win.shape</attribute>
+              <attribute name="target">square</attribute>
+              <attribute name="accel">&lt;Primary&gt;s</attribute>
+            </item>
+            <item>
+              <attribute name="label" translatable="yes">_Rectangle</attribute>
+              <attribute name="action">win.shape</attribute>
+              <attribute name="target">rectangle</attribute>
+              <attribute name="accel">&lt;Primary&gt;r</attribute>
+            </item>
+            <item>
+              <attribute name="label" translatable="yes">_Oval</attribute>
+              <attribute name="action">win.shape</attribute>
+              <attribute name="target">oval</attribute>
+              <attribute name="accel">&lt;Primary&gt;o</attribute>
+            </item>
           </section>
         </submenu>
-        <item label="_Bold" action="win.bold" accel="&lt;Primary&gt;b"/>
+        <item>
+          <attribute name="label" translatable="yes">_Bold</attribute>
+          <attribute name="action">win.bold</attribute>
+          <attribute name="accel">&lt;Primary&gt;b</attribute>
+        </item>
       </section>
     </submenu>
-    <submenu label="_Help">
-      <item label="_About" action="win.about" accel="&lt;Primary&gt;a"/>
+    <submenu>
+      <attribute name="label" translatable="yes">_Help</attribute>
+      <item>
+        <attribute name="label" translatable="yes">_About</attribute>
+        <attribute name="action">win.about</attribute>
+        <attribute name="accel">&lt;Primary&gt;a</attribute>
+      </item>
     </submenu>
   </menu>
 </interface>
index ba8164a708de901285660d24a0259251848f25c9..417858026203d498d56fa22354d89255338de646 100644 (file)
@@ -275,25 +275,50 @@ bloat_pad_startup (GApplication *application)
                                "<interface>"
                                "  <menu id='app-menu'>"
                                "    <section>"
-                               "      <item label='_New Window' action='app.new' accel='&lt;Primary&gt;n'/>"
+                               "      <item>"
+                               "        <attribute name='label'>_New Window</attribute>"
+                               "        <attribute name='action'>app.new</attribute>"
+                               "        <attribute name='accel'>&lt;Primary&gt;n</attribute>"
+                               "      </item>"
                                "    </section>"
                                "    <section>"
-                               "      <item label='_About Bloatpad' action='app.about'/>"
+                               "      <item>"
+                               "        <attribute name='label'>_About Bloatpad</attribute>"
+                               "        <attribute name='action'>app.about</attribute>"
+                               "      </item>"
                                "    </section>"
                                "    <section>"
-                               "      <item label='_Quit' action='app.quit' accel='&lt;Primary&gt;q'/>"
+                               "      <item>"
+                               "        <attribute name='label'>_Quit</attribute>"
+                               "        <attribute name='action'>app.quit</attribute>"
+                               "        <attribute name='accel'>&lt;Primary&gt;q</attribute>"
+                               "      </item>"
                                "    </section>"
                                "  </menu>"
                                "  <menu id='menubar'>"
-                               "    <submenu label='_Edit'>"
+                               "    <submenu>"
+                               "      <attribute name='label'>_Edit</attribute>"
                                "      <section>"
-                               "        <item label='_Copy' action='win.copy' accel='&lt;Primary&gt;c'/>"
-                               "        <item label='_Paste' action='win.paste' accel='&lt;Primary&gt;v'/>"
+                               "        <item>"
+                               "          <attribute name='label'>_Copy</attribute>"
+                               "          <attribute name='action'>win.copy</attribute>"
+                               "          <attribute name='accel'>&lt;Primary&gt;c</attribute>"
+                               "        </item>"
+                               "        <item>"
+                               "          <attribute name='label'>_Parse</attribute>"
+                               "          <attribute name='action'>win.parse</attribute>"
+                               "          <attribute name='accel'>&lt;Primary&gt;v</attribute>"
+                               "        </item>"
                                "      </section>"
                                "    </submenu>"
-                               "    <submenu label='_View'>"
+                               "    <submenu>"
+                               "      <attribute name='label'>_View</attribute>"
                                "      <section>"
-                               "        <item label='_Fullscreen' action='win.fullscreen'/>"
+                               "        <item>"
+                               "          <attribute name='label'>_Fullscreen</attribute>"
+                               "          <attribute name='action'>win.fullscreen</attribute>"
+                               "          <attribute name='accel'>F11</attribute>"
+                               "        </item>"
                                "      </section>"
                                "    </submenu>"
                                "  </menu>"
index 98cdf3d2b000818cd1a7acac9bd9af413cacf813..6d5f926452f2490d74511ec94ba63e18d3b7eaad 100644 (file)
@@ -567,6 +567,7 @@ gtk_base_c_sources =                \
        gtkbuildable.c          \
        gtkbuilder.c            \
        gtkbuilderparser.c      \
+       gtkbuilder-menus.c      \
        gtkbutton.c             \
        gtkcalendar.c           \
        gtkcellarea.c           \
diff --git a/gtk/gtkbuilder-menus.c b/gtk/gtkbuilder-menus.c
new file mode 100644 (file)
index 0000000..5a32a41
--- /dev/null
@@ -0,0 +1,391 @@
+/*
+ * Copyright © 2011, 2012 Canonical Ltd.
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * licence, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ *
+ * Author: Ryan Lortie <desrt@desrt.ca>
+ */
+
+#include "config.h"
+
+#include "gtkbuilderprivate.h"
+#include "gtkintl.h"
+
+#include <gio/gio.h>
+#include <string.h>
+
+struct frame
+{
+  GMenu        *menu;
+  GMenuItem    *item;
+  struct frame *prev;
+};
+
+typedef struct
+{
+  ParserData *parser_data;
+  struct frame frame;
+
+  /* attributes */
+  gchar        *attribute;
+  GVariantType *type;
+  GString      *string;
+
+  /* translation */
+  gchar        *context;
+  gboolean      translatable;
+} GtkBuilderMenuState;
+
+static void
+gtk_builder_menu_push_frame (GtkBuilderMenuState *state,
+                             GMenu               *menu,
+                             GMenuItem           *item)
+{
+  struct frame *new;
+
+  new = g_slice_new (struct frame);
+  *new = state->frame;
+
+  state->frame.menu = menu;
+  state->frame.item = item;
+  state->frame.prev = new;
+}
+
+static void
+gtk_builder_menu_pop_frame (GtkBuilderMenuState *state)
+{
+  struct frame *prev = state->frame.prev;
+
+  if (state->frame.item)
+    {
+      g_assert (prev->menu != NULL);
+      g_menu_append_item (prev->menu, state->frame.item);
+      g_object_unref (state->frame.item);
+    }
+
+  state->frame = *prev;
+
+  g_slice_free (struct frame, prev);
+}
+
+static void
+gtk_builder_menu_start_element (GMarkupParseContext  *context,
+                                const gchar          *element_name,
+                                const gchar         **attribute_names,
+                                const gchar         **attribute_values,
+                                gpointer              user_data,
+                                GError              **error)
+{
+  GtkBuilderMenuState *state = user_data;
+
+#define COLLECT(first, ...) \
+  g_markup_collect_attributes (element_name,                                 \
+                               attribute_names, attribute_values, error,     \
+                               first, __VA_ARGS__, G_MARKUP_COLLECT_INVALID)
+#define OPTIONAL   G_MARKUP_COLLECT_OPTIONAL
+#define BOOLEAN    G_MARKUP_COLLECT_BOOLEAN
+#define STRING     G_MARKUP_COLLECT_STRING
+
+  if (state->frame.menu)
+    {
+      /* Can have '<item>', '<submenu>' or '<section>' here. */
+      if (g_str_equal (element_name, "item"))
+        {
+          GMenuItem *item;
+
+          item = g_menu_item_new (NULL, NULL);
+          gtk_builder_menu_push_frame (state, NULL, item);
+          return;
+        }
+
+      else if (g_str_equal (element_name, "submenu"))
+        {
+          const gchar *id;
+
+          if (COLLECT (STRING | OPTIONAL, "id", &id))
+            {
+              GMenuItem *item;
+              GMenu *menu;
+
+              menu = g_menu_new ();
+              item = g_menu_item_new_submenu (NULL, G_MENU_MODEL (menu));
+              gtk_builder_menu_push_frame (state, menu, item);
+
+              if (id != NULL)
+                _gtk_builder_add_object (state->parser_data->builder, id, G_OBJECT (menu));
+            }
+
+          return;
+        }
+
+      else if (g_str_equal (element_name, "section"))
+        {
+          const gchar *id;
+
+          if (COLLECT (STRING | OPTIONAL, "id", &id))
+            {
+              GMenuItem *item;
+              GMenu *menu;
+
+              menu = g_menu_new ();
+              item = g_menu_item_new_section (NULL, G_MENU_MODEL (menu));
+              gtk_builder_menu_push_frame (state, menu, item);
+
+              if (id != NULL)
+                _gtk_builder_add_object (state->parser_data->builder, id, G_OBJECT (menu));
+            }
+
+          return;
+        }
+    }
+
+  if (state->frame.item)
+    {
+      /* Can have '<attribute>' or '<link>' here. */
+      if (g_str_equal (element_name, "attribute"))
+        {
+          const gchar *typestr;
+          const gchar *name;
+          const gchar *context;
+
+          if (COLLECT (STRING,             "name", &name,
+                       OPTIONAL | BOOLEAN, "translatable", &state->translatable,
+                       OPTIONAL | STRING,  "context", &context,
+                       OPTIONAL | STRING,  "comments", NULL, /* ignore, just for translators */
+                       OPTIONAL | STRING,  "type", &typestr))
+            {
+              if (typestr && !g_variant_type_string_is_valid (typestr))
+                {
+                  g_set_error (error, G_VARIANT_PARSE_ERROR,
+                               G_VARIANT_PARSE_ERROR_INVALID_TYPE_STRING,
+                               "Invalid GVariant type string '%s'", typestr);
+                  return;
+                }
+
+              state->type = typestr ? g_variant_type_new (typestr) : NULL;
+              state->string = g_string_new (NULL);
+              state->attribute = g_strdup (name);
+              state->context = g_strdup (context);
+
+              gtk_builder_menu_push_frame (state, NULL, NULL);
+            }
+
+          return;
+        }
+
+      if (g_str_equal (element_name, "link"))
+        {
+          const gchar *name;
+          const gchar *id;
+
+          if (COLLECT (STRING,            "name", &name,
+                       STRING | OPTIONAL, "id",   &id))
+            {
+              GMenu *menu;
+
+              menu = g_menu_new ();
+              g_menu_item_set_link (state->frame.item, name, G_MENU_MODEL (menu));
+              gtk_builder_menu_push_frame (state, menu, NULL);
+
+              if (id != NULL)
+                _gtk_builder_add_object (state->parser_data->builder, id, G_OBJECT (menu));
+            }
+
+          return;
+        }
+    }
+
+  {
+    const GSList *element_stack;
+
+    element_stack = g_markup_parse_context_get_element_stack (context);
+
+    if (element_stack->next)
+      g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_UNKNOWN_ELEMENT,
+                   _("Element <%s> not allowed inside <%s>"),
+                   element_name, (const gchar *) element_stack->next->data);
+
+    else
+      g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_UNKNOWN_ELEMENT,
+                   _("Element <%s> not allowed at toplevel"), element_name);
+  }
+}
+
+static void
+gtk_builder_menu_end_element (GMarkupParseContext  *context,
+                              const gchar          *element_name,
+                              gpointer              user_data,
+                              GError              **error)
+{
+  GtkBuilderMenuState *state = user_data;
+
+  gtk_builder_menu_pop_frame (state);
+
+  if (state->string)
+    {
+      GVariant *value;
+      gchar *text;
+
+      text = g_string_free (state->string, FALSE);
+      state->string = NULL;
+
+      /* do the translation if necessary */
+      if (state->translatable && state->parser_data->domain)
+        {
+          const gchar *translated;
+
+          if (state->context)
+            translated = g_dpgettext2 (state->parser_data->domain, state->context, text);
+          else
+            translated = g_dgettext (state->parser_data->domain, text);
+
+         if (translated != text)
+           {
+             /* it's safe because we know that translated != text */
+             g_free (text);
+             text = g_strdup (translated);
+           }
+        }
+
+      if (state->type == NULL)
+        /* No type string specified -> it's a normal string. */
+        g_menu_item_set_attribute (state->frame.item, state->attribute, "s", text);
+
+      /* Else, we try to parse it according to the type string.  If
+       * error is set here, it will follow us out, ending the parse.
+       *
+       * We still need to free everything, though, so ignore it here.
+       */
+      else if ((value = g_variant_parse (state->type, text, NULL, NULL, error)))
+        {
+          g_menu_item_set_attribute_value (state->frame.item, state->attribute, value);
+          g_variant_unref (value);
+        }
+
+      if (state->type)
+        {
+          g_variant_type_free (state->type);
+          state->type = NULL;
+        }
+
+      g_free (state->context);
+      state->context = NULL;
+
+      g_free (state->attribute);
+      state->attribute = NULL;
+
+      g_free (text);
+    }
+}
+
+static void
+gtk_builder_menu_text (GMarkupParseContext  *context,
+                       const gchar          *text,
+                       gsize                 text_len,
+                       gpointer              user_data,
+                       GError              **error)
+{
+  GtkBuilderMenuState *state = user_data;
+  gint i;
+
+  for (i = 0; i < text_len; i++)
+    if (!g_ascii_isspace (text[i]))
+      {
+        if (state->string)
+          g_string_append_len (state->string, text, text_len);
+
+        else
+          g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
+                       _("text may not appear inside <%s>"),
+                       g_markup_parse_context_get_element (context));
+        break;
+      }
+}
+
+static void
+gtk_builder_menu_error (GMarkupParseContext *context,
+                        GError              *error,
+                        gpointer             user_data)
+{
+  GtkBuilderMenuState *state = user_data;
+
+  while (state->frame.prev)
+    {
+      struct frame *prev = state->frame.prev;
+
+      state->frame = *prev;
+
+      g_slice_free (struct frame, prev);
+    }
+
+  if (state->string)
+    g_string_free (state->string, TRUE);
+
+  if (state->type)
+    g_variant_type_free (state->type);
+
+  g_free (state->attribute);
+  g_free (state->context);
+
+  g_slice_free (GtkBuilderMenuState, state);
+}
+
+static GMarkupParser gtk_builder_menu_subparser =
+{
+  gtk_builder_menu_start_element,
+  gtk_builder_menu_end_element,
+  gtk_builder_menu_text,
+  NULL,                            /* passthrough */
+  gtk_builder_menu_error
+};
+
+void
+_gtk_builder_menu_start (ParserData   *parser_data,
+                         const gchar  *element_name,
+                         const gchar **attribute_names,
+                         const gchar **attribute_values,
+                         GError      **error)
+{
+  GtkBuilderMenuState *state;
+  gchar *id;
+
+  state = g_slice_new0 (GtkBuilderMenuState);
+  state->parser_data = parser_data;
+  g_markup_parse_context_push (parser_data->ctx, &gtk_builder_menu_subparser, state);
+
+  if (COLLECT (STRING, "id", &id))
+    {
+      GMenu *menu;
+
+      menu = g_menu_new ();
+      _gtk_builder_add_object (state->parser_data->builder, id, G_OBJECT (menu));
+      gtk_builder_menu_push_frame (state, menu, NULL);
+    }
+}
+
+void
+_gtk_builder_menu_end (ParserData *parser_data)
+{
+  GtkBuilderMenuState *state;
+
+  state = g_markup_parse_context_pop (parser_data->ctx);
+  gtk_builder_menu_pop_frame (state);
+
+  g_assert (state->frame.prev == NULL);
+  g_assert (state->frame.item == NULL);
+  g_assert (state->frame.menu == NULL);
+  g_slice_free (GtkBuilderMenuState, state);
+}
index 6d36140dc1a4a7a856efa06c5c8cb0cd729a7817..09b343cb225fc9e2f22d4613eed4e6ad6f104391 100644 (file)
@@ -832,34 +832,6 @@ parse_custom (GMarkupParseContext *context,
   return TRUE;
 }
 
-static gboolean
-parse_menu (GMarkupParseContext  *context,
-            const gchar          *element_name,
-            const gchar         **names,
-            const gchar         **values,
-            gpointer              user_data,
-            GError              **error)
-{
-  gchar *id;
-  ParserData *data = user_data;
-  MenuInfo *menu_info;
-
-  if (!g_markup_collect_attributes (element_name, names, values, error,
-                                    G_MARKUP_COLLECT_STRING, "id", &id,
-                                    G_MARKUP_COLLECT_INVALID))
-    return FALSE;
-
-  menu_info = g_slice_new0 (MenuInfo);
-  menu_info->tag.name = element_name;
-  menu_info->id = g_strdup (id);
-  menu_info->objects = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref);
-  state_push (data, menu_info);
-
-  g_menu_markup_parser_start_menu (context, data->domain, menu_info->objects);
-
-  return TRUE;
-}
-
 static void
 start_element (GMarkupParseContext *context,
                const gchar         *element_name,
@@ -921,7 +893,7 @@ start_element (GMarkupParseContext *context,
   else if (strcmp (element_name, "interface") == 0)
     parse_interface (data, element_name, names, values, error);
   else if (strcmp (element_name, "menu") == 0)
-    parse_menu (context, element_name, names, values, data, error);
+    _gtk_builder_menu_start (data, element_name, names, values, error);
   else if (strcmp (element_name, "placeholder") == 0)
     {
       /* placeholder has no special treatmeant, but it needs an
@@ -995,23 +967,7 @@ end_element (GMarkupParseContext *context,
     }
   else if (strcmp (element_name, "menu") == 0)
     {
-      MenuInfo *menu_info;
-      GObject *menu;
-      GHashTableIter iter;
-      const gchar *id;
-
-      menu_info = state_pop_info (data, MenuInfo);
-      menu = (GObject*)g_menu_markup_parser_end_menu (context);
-      _gtk_builder_add_object (data->builder, menu_info->id, menu);
-      g_object_unref (menu);
-
-      g_hash_table_iter_init (&iter, menu_info->objects);
-      while (g_hash_table_iter_next (&iter, (gpointer*)&id, (gpointer*)&menu))
-        {
-          _gtk_builder_add_object (data->builder, id, menu);
-        }
-
-      free_menu_info (menu_info);
+      _gtk_builder_menu_end (data);
     }
   else if (data->requested_objects && !data->inside_requested_object)
     {
index e7528bcdb1091d0ea0346fd97687c2044d144d7e..d4e5a29ceaddacea63cc28b325fb75e5011687c8 100644 (file)
@@ -154,4 +154,12 @@ gchar *   _gtk_builder_get_resource_path (GtkBuilder *builder,
 gchar *   _gtk_builder_get_absolute_filename (GtkBuilder *builder,
                                              const gchar *string);
 
+void      _gtk_builder_menu_start (ParserData   *parser_data,
+                                   const gchar  *element_name,
+                                   const gchar **attribute_names,
+                                   const gchar **attribute_values,
+                                   GError      **error);
+void      _gtk_builder_menu_end   (ParserData  *parser_data);
+
+
 #endif /* __GTK_BUILDER_PRIVATE_H__ */