[gtk+/wip/gmenu: 6/7] Quick-and-dirty GtkBuilder integration



commit f32781e1a305588aca161ad3be01b8ff7d845a29
Author: Matthias Clasen <mclasen redhat com>
Date:   Tue Nov 1 19:53:51 2011 -0400

    Quick-and-dirty GtkBuilder integration
    
    This makes GtkBuilder accept a GMenuMarkup tree at the toplevel
    (ie with <menu id='foo'> being a child of <interface>) and the resulting
    GMenu object can be obtained via gtk_builder_get_object (builder, "foo").

 gtk/gtkbuilder.c        |    7 +++++++
 gtk/gtkbuilderparser.c  |   43 +++++++++++++++++++++++++++++++++++++++++++
 gtk/gtkbuilderprivate.h |    3 +++
 gtk/tests/builder.c     |   43 +++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 96 insertions(+), 0 deletions(-)
---
diff --git a/gtk/gtkbuilder.c b/gtk/gtkbuilder.c
index 10373f6..de24427 100644
--- a/gtk/gtkbuilder.c
+++ b/gtk/gtkbuilder.c
@@ -731,6 +731,13 @@ _gtk_builder_construct (GtkBuilder *builder,
   return obj;
 }
 
+void
+_gtk_builder_add_object (GtkBuilder  *builder,
+                         const gchar *id,
+                         GObject     *object)
+{
+  g_hash_table_insert (builder->priv->objects, g_strdup (id), g_object_ref (object));
+}
 
 void
 _gtk_builder_add (GtkBuilder *builder,
diff --git a/gtk/gtkbuilderparser.c b/gtk/gtkbuilderparser.c
index 5ea15e3..d0071f9 100644
--- a/gtk/gtkbuilderparser.c
+++ b/gtk/gtkbuilderparser.c
@@ -23,6 +23,7 @@
 #include <string.h>
 #include <gmodule.h>
 
+#include <gio/gio.h>
 #include "gtkbuilderprivate.h"
 #include "gtkbuilder.h"
 #include "gtkbuildable.h"
@@ -823,6 +824,34 @@ 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;
+  ObjectInfo *object_info;
+
+  if (!g_markup_collect_attributes (element_name, names, values, error,
+                                    G_MARKUP_COLLECT_STRING, "id", &id,
+                                    G_MARKUP_COLLECT_INVALID))
+    return FALSE;
+
+  object_info = g_slice_new0 (ObjectInfo);
+  object_info->class_name = g_strdup ("GMenu");
+  object_info->id = g_strdup (id);
+  object_info->tag.name = element_name;
+  state_push (data, object_info);
+
+  g_menu_markup_parser_start_menu (context, NULL);
+
+  return TRUE;
+}
+
 static void
 start_element (GMarkupParseContext *context,
                const gchar         *element_name,
@@ -883,6 +912,8 @@ start_element (GMarkupParseContext *context,
     parse_signal (data, element_name, names, values, error);
   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);
   else if (strcmp (element_name, "placeholder") == 0)
     {
       /* placeholder has no special treatmeant, but it needs an
@@ -954,6 +985,18 @@ end_element (GMarkupParseContext *context,
   else if (strcmp (element_name, "interface") == 0)
     {
     }
+  else if (strcmp (element_name, "menu") == 0)
+    {
+      ObjectInfo *object_info;
+      GObject *menu;
+
+      object_info = state_pop_info (data, ObjectInfo);
+      menu = (GObject*)g_menu_markup_parser_end_menu (context);
+      _gtk_builder_add_object (data->builder, object_info->id, menu);
+      g_object_unref (menu);
+
+      free_object_info (object_info);
+    }
   else if (data->requested_objects && !data->inside_requested_object)
     {
       /* If outside a requested object, simply ignore this tag */
diff --git a/gtk/gtkbuilderprivate.h b/gtk/gtkbuilderprivate.h
index e633a28..a7fc500 100644
--- a/gtk/gtkbuilderprivate.h
+++ b/gtk/gtkbuilderprivate.h
@@ -117,6 +117,9 @@ void _gtk_builder_parser_parse_buffer (GtkBuilder *builder,
 GObject * _gtk_builder_construct (GtkBuilder *builder,
                                   ObjectInfo *info,
 				  GError    **error);
+void      _gtk_builder_add_object (GtkBuilder  *builder,
+                                   const gchar *id,
+                                   GObject     *object);
 void      _gtk_builder_add (GtkBuilder *builder,
                             ChildInfo *child_info);
 void      _gtk_builder_add_signals (GtkBuilder *builder,
diff --git a/gtk/tests/builder.c b/gtk/tests/builder.c
index 082b69a..1bbba85 100644
--- a/gtk/tests/builder.c
+++ b/gtk/tests/builder.c
@@ -2572,6 +2572,48 @@ test_message_area (void)
   g_object_unref (builder);
 }
 
+static void
+test_gmenu (void)
+{
+  GtkBuilder *builder;
+  GError *error;
+  GObject *obj, *obj1;
+  const gchar buffer[] =
+    "<interface>"
+    "  <object class=\"GtkWindow\" id=\"window\">"
+    "  </object>"
+    "  <menu id='edit-menu'>"
+    "    <section>"
+    "      <item label='Undo' action='undo'/>"
+    "      <item label='Redo' action='redo'/>"
+    "    </section>"
+    "    <section></section>"
+    "    <section label='Copy &amp; Paste'>"
+    "      <item label='Cut' action='cut'/>"
+    "      <item label='Copy' action='copy'/>"
+    "      <item label='Paste' action='paste'/>"
+    "    </section>"
+    "    <section>"
+    "      <item label='Bold' action='bold'/>"
+    "      <submenu label='Language'>"
+    "        <item label='Latin' action='lang' target='latin'/>"
+    "        <item label='Greek' action='lang' target='greek'/>"
+    "        <item label='Urdu'  action='lang' target='urdu'/>"
+    "      </submenu>"
+    "    </section>"
+    "  </menu>"
+    "</interface>";
+
+  error = NULL;
+  builder = builder_new_from_string (buffer, -1, NULL);
+  g_assert (error == NULL);
+  obj = gtk_builder_get_object (builder, "window");
+  g_assert (GTK_IS_WINDOW (obj));
+  obj1 = gtk_builder_get_object (builder, "edit-menu");
+  g_assert (G_IS_MENU_MODEL (obj1));
+  g_object_unref (builder);
+}
+
 int
 main (int argc, char **argv)
 {
@@ -2618,6 +2660,7 @@ main (int argc, char **argv)
   g_test_add_func ("/Builder/Menus", test_menus);
   g_test_add_func ("/Builder/MessageArea", test_message_area);
   g_test_add_func ("/Builder/MessageDialog", test_message_dialog);
+  g_test_add_func ("/Builder/GMenu", test_gmenu);
 
   return g_test_run();
 }



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