[glib/wip/menus: 14/35] introduce GMenuModel and friends
- From: Ryan Lortie <ryanl src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [glib/wip/menus: 14/35] introduce GMenuModel and friends
- Date: Sat, 22 Oct 2011 02:54:22 +0000 (UTC)
commit 1de61cce505cbe325bbe46d8a62e44edd77fd783
Author: Ryan Lortie <desrt desrt ca>
Date: Mon Jul 11 02:02:27 2011 +0200
introduce GMenuModel and friends
gio/Makefile.am | 10 +-
gio/gio.h | 3 +
gio/gmenu.c | 674 +++++++++++++++++++++++++++++++++++++++++
gio/gmenu.h | 177 +++++++++++
gio/gmenumarkup.c | 482 +++++++++++++++++++++++++++++
gio/gmenumarkup.h | 23 ++
gio/gmenumodel.c | 873 +++++++++++++++++++++++++++++++++++++++++++++++++++++
gio/gmenumodel.h | 243 +++++++++++++++
8 files changed, 2483 insertions(+), 2 deletions(-)
---
diff --git a/gio/Makefile.am b/gio/Makefile.am
index d2774cc..25e34b0 100644
--- a/gio/Makefile.am
+++ b/gio/Makefile.am
@@ -130,7 +130,10 @@ application_headers = \
gdbusactiongroup.h \
gactiongroupexporter.h \
gapplicationcommandline.h \
- gapplication.h
+ gapplication.h \
+ gmenumodel.h \
+ gmenu.h \
+ gmenumarkup.h
application_sources = \
gactiongroup.c \
@@ -142,7 +145,10 @@ application_sources = \
gapplicationcommandline.c \
gapplicationimpl.h \
gapplicationimpl-dbus.c \
- gapplication.c
+ gapplication.c \
+ gmenumodel.c \
+ gmenu.c \
+ gmenumarkup.c
local_sources = \
glocaldirectorymonitor.c \
diff --git a/gio/gio.h b/gio/gio.h
index f5a44a1..52e1388 100644
--- a/gio/gio.h
+++ b/gio/gio.h
@@ -143,6 +143,9 @@
#include <gio/gdbusobjectmanagerserver.h>
#include <gio/gactiongroupexporter.h>
#include <gio/gdbusactiongroup.h>
+#include <gio/gmenumodel.h>
+#include <gio/gmenu.h>
+#include <gio/gmenumarkup.h>
#undef __GIO_GIO_H_INSIDE__
diff --git a/gio/gmenu.c b/gio/gmenu.c
new file mode 100644
index 0000000..c7e5df7
--- /dev/null
+++ b/gio/gmenu.c
@@ -0,0 +1,674 @@
+/*
+ * Copyright  2011 Canonical Ltd.
+ * All rights reserved.
+ *
+ * Author: Ryan Lortie <desrt desrt ca>
+ */
+
+#include "config.h"
+
+#include "gmenu.h"
+
+#include <string.h>
+
+struct _GMenuItem
+{
+ GObject parent_instance;
+
+ GHashTable *attributes;
+ GHashTable *links;
+ gboolean cow;
+};
+
+typedef GObjectClass GMenuItemClass;
+
+G_DEFINE_TYPE (GMenu, g_menu, G_TYPE_MENU_MODEL)
+G_DEFINE_TYPE (GMenuItem, g_menu_item, G_TYPE_OBJECT)
+
+struct item
+{
+ GHashTable *attributes;
+ GHashTable *links;
+};
+
+struct _GMenuPrivate
+{
+ GArray *items;
+ gboolean mutable;
+};
+
+static gboolean
+g_menu_is_mutable (GMenuModel *model)
+{
+ GMenu *menu = G_MENU (model);
+
+ return menu->priv->mutable;
+}
+
+static gint
+g_menu_get_n_items (GMenuModel *model)
+{
+ GMenu *menu = G_MENU (model);
+
+ return menu->priv->items->len;
+}
+
+static void
+g_menu_get_item_attributes (GMenuModel *model,
+ gint index_,
+ GHashTable **quark_table,
+ GHashTable **string_table,
+ GVariant **dictionary)
+{
+ GMenu *menu = G_MENU (model);
+
+ *quark_table = g_array_index (menu->priv->items, struct item, index_).attributes;
+}
+
+static void
+g_menu_get_item_links (GMenuModel *model,
+ gint index_,
+ GHashTable **quark_table,
+ GHashTable **string_table)
+{
+ GMenu *menu = G_MENU (model);
+
+ *quark_table = g_array_index (menu->priv->items, struct item, index_).links;
+}
+
+void
+g_menu_insert_item (GMenu *menu,
+ gint index_,
+ GMenuItem *item)
+{
+ struct item new_item;
+
+ g_return_if_fail (G_IS_MENU (menu));
+ g_return_if_fail (G_IS_MENU_ITEM (item));
+
+ if (index_ < 0 || index_ > menu->priv->items->len)
+ index_ = menu->priv->items->len;
+
+
+ new_item.attributes = g_hash_table_ref (item->attributes);
+ new_item.links = g_hash_table_ref (item->links);
+ item->cow = TRUE;
+
+ g_array_insert_val (menu->priv->items, index_, new_item);
+ g_menu_model_items_changed (G_MENU_MODEL (menu), index_, 0, 1);
+}
+
+void
+g_menu_prepend_item (GMenu *menu,
+ GMenuItem *item)
+{
+ g_menu_insert_item (menu, 0, item);
+}
+
+void
+g_menu_append_item (GMenu *menu,
+ GMenuItem *item)
+{
+ g_menu_insert_item (menu, -1, item);
+}
+
+void
+g_menu_freeze (GMenu *menu)
+{
+ g_return_if_fail (G_IS_MENU (menu));
+
+ menu->priv->mutable = FALSE;
+}
+
+GMenu *
+g_menu_new (void)
+{
+ return g_object_new (G_TYPE_MENU, NULL);
+}
+
+void
+g_menu_insert (GMenu *menu,
+ gint index_,
+ const gchar *label,
+ const gchar *detailed_action)
+{
+ GMenuItem *menu_item;
+
+ menu_item = g_menu_item_new (label, detailed_action);
+ g_menu_insert_item (menu, index_, menu_item);
+ g_object_unref (menu_item);
+}
+
+
+void
+g_menu_prepend (GMenu *menu,
+ const gchar *label,
+ const gchar *detailed_action)
+{
+ g_menu_insert (menu, 0, label, detailed_action);
+}
+
+void
+g_menu_append (GMenu *menu,
+ const gchar *label,
+ const gchar *detailed_action)
+{
+ g_menu_insert (menu, -1, label, detailed_action);
+}
+
+
+void
+g_menu_insert_section (GMenu *menu,
+ gint index_,
+ const gchar *label,
+ GMenuModel *section)
+{
+ GMenuItem *menu_item;
+
+ menu_item = g_menu_item_new_section (label, section);
+ g_menu_insert_item (menu, index_, menu_item);
+ g_object_unref (menu_item);
+}
+
+
+void
+g_menu_prepend_section (GMenu *menu,
+ const gchar *label,
+ GMenuModel *section)
+{
+ g_menu_insert_section (menu, 0, label, section);
+}
+
+void
+g_menu_append_section (GMenu *menu,
+ const gchar *label,
+ GMenuModel *section)
+{
+ g_menu_insert_section (menu, -1, label, section);
+}
+
+void
+g_menu_insert_submenu (GMenu *menu,
+ gint index_,
+ const gchar *label,
+ GMenuModel *submenu)
+{
+ GMenuItem *menu_item;
+
+ menu_item = g_menu_item_new_submenu (label, submenu);
+ g_menu_insert_item (menu, index_, menu_item);
+ g_object_unref (menu_item);
+}
+
+void
+g_menu_prepend_submenu (GMenu *menu,
+ const gchar *label,
+ GMenuModel *submenu)
+{
+ g_menu_insert_submenu (menu, 0, label, submenu);
+}
+
+void
+g_menu_append_submenu (GMenu *menu,
+ const gchar *label,
+ GMenuModel *submenu)
+{
+ g_menu_insert_submenu (menu, -1, label, submenu);
+}
+
+static void
+g_menu_clear_item (struct item *item)
+{
+ if (item->attributes != NULL)
+ g_hash_table_unref (item->attributes);
+ if (item->links != NULL);
+ g_hash_table_unref (item->links);
+}
+
+void
+g_menu_remove (GMenu *menu,
+ gint index_)
+{
+ g_return_if_fail (G_IS_MENU (menu));
+ g_return_if_fail (0 <= index_ && index_ < menu->priv->items->len);
+
+ g_menu_clear_item (&g_array_index (menu->priv->items, struct item, index_));
+ g_array_remove_index (menu->priv->items, index_);
+ g_menu_model_items_changed (G_MENU_MODEL (menu), index_, 1, 0);
+}
+
+static void
+g_menu_finalize (GObject *object)
+{
+ GMenu *menu = G_MENU (object);
+ struct item *items;
+ gint n_items;
+ gint i;
+
+ n_items = menu->priv->items->len;
+ items = (struct item *) g_array_free (menu->priv->items, FALSE);
+ for (i = 0; i < n_items; i++)
+ g_menu_clear_item (&items[i]);
+ g_free (items);
+
+ G_OBJECT_CLASS (g_menu_parent_class)
+ ->finalize (object);
+}
+
+static void
+g_menu_init (GMenu *menu)
+{
+ menu->priv = G_TYPE_INSTANCE_GET_PRIVATE (menu, G_TYPE_MENU, GMenuPrivate);
+ menu->priv->items = g_array_new (FALSE, FALSE, sizeof (struct item));
+ menu->priv->mutable = TRUE;
+}
+
+static void
+g_menu_class_init (GMenuClass *class)
+{
+ GMenuModelClass *model_class = G_MENU_MODEL_CLASS (class);
+ GObjectClass *object_class = G_OBJECT_CLASS (class);
+
+ object_class->finalize = g_menu_finalize;
+
+ model_class->is_mutable = g_menu_is_mutable;
+ model_class->get_n_items = g_menu_get_n_items;
+ model_class->get_item_attributes = g_menu_get_item_attributes;
+ model_class->get_item_links = g_menu_get_item_links;
+
+ g_type_class_add_private (class, sizeof (GMenuPrivate));
+}
+
+
+static void
+g_menu_item_clear_cow (GMenuItem *menu_item)
+{
+ if (menu_item->cow)
+ {
+ GHashTableIter iter;
+ GHashTable *new;
+ gpointer key;
+ gpointer val;
+
+ new = g_hash_table_new_full (NULL, NULL, NULL, (GDestroyNotify) g_variant_unref);
+ g_hash_table_iter_init (&iter, menu_item->attributes);
+ while (g_hash_table_iter_next (&iter, &key, &val))
+ g_hash_table_insert (new, key, g_variant_ref (val));
+ g_hash_table_unref (menu_item->attributes);
+ menu_item->attributes = new;
+
+ new = g_hash_table_new_full (NULL, NULL, NULL, g_object_unref);
+ g_hash_table_iter_init (&iter, menu_item->links);
+ while (g_hash_table_iter_next (&iter, &key, &val))
+ g_hash_table_insert (new, key, g_object_ref (val));
+ g_hash_table_unref (menu_item->links);
+ menu_item->links = new;
+
+ menu_item->cow = FALSE;
+ }
+}
+
+static void
+g_menu_item_finalize (GObject *object)
+{
+ GMenuItem *menu_item = G_MENU_ITEM (object);
+
+ g_hash_table_unref (menu_item->attributes);
+ g_hash_table_unref (menu_item->links);
+
+ G_OBJECT_CLASS (g_menu_item_parent_class)
+ ->finalize (object);
+}
+
+static void
+g_menu_item_init (GMenuItem *menu_item)
+{
+ menu_item->attributes = g_hash_table_new_full (NULL, NULL, NULL, (GDestroyNotify) g_variant_unref);
+ menu_item->links = g_hash_table_new_full (NULL, NULL, NULL, g_object_unref);
+ menu_item->cow = FALSE;
+}
+
+static void
+g_menu_item_class_init (GMenuItemClass *class)
+{
+ class->finalize = g_menu_item_finalize;
+}
+
+GVariant *
+g_menu_item_get_attribute_value (GMenuItem *menu_item,
+ GQuark attribute_quark,
+ const GVariantType *expected_type)
+{
+ GVariant *value = NULL;
+
+ g_return_val_if_fail (G_IS_MENU_ITEM (menu_item), NULL);
+
+ if (menu_item->attributes)
+ {
+ value = g_hash_table_lookup (menu_item->attributes, GINT_TO_POINTER (attribute_quark));
+
+ if (value != NULL)
+ {
+ if (expected_type == NULL || g_variant_is_of_type (value, expected_type))
+ value = g_variant_ref (value);
+ else
+ value = NULL;
+ }
+ }
+
+ return value;
+}
+
+gboolean
+g_menu_item_get_attribute (GMenuItem *menu_item,
+ GQuark attribute_quark,
+ const gchar *format_string,
+ ...)
+{
+ const GVariantType *expected_type;
+ GVariant *value;
+ va_list ap;
+
+ expected_type = NULL; /* XXX devine the type, ensure no '&' */
+
+ value = g_menu_item_get_attribute_value (menu_item, attribute_quark, expected_type);
+ if (value == NULL)
+ return FALSE;
+
+ va_start (ap, format_string);
+ g_variant_get_va (value, format_string, NULL, &ap);
+ g_variant_unref (value);
+ va_end (ap);
+
+ return TRUE;
+}
+
+GVariant *
+g_menu_item_get_attribute_value_by_name (GMenuItem *menu_item,
+ const gchar *attribute_name,
+ const GVariantType *expected_type)
+{
+ return g_menu_item_get_attribute_value (menu_item, g_quark_try_string (attribute_name), expected_type);
+}
+
+gboolean
+g_menu_item_get_attribute_by_name (GMenuItem *menu_item,
+ const gchar *attribute_name,
+ const gchar *format_string,
+ ...)
+{
+ const GVariantType *expected_type;
+ GVariant *value;
+ va_list ap;
+
+ expected_type = NULL; /* XXX devine the type, ensure no '&' */
+
+ value = g_menu_item_get_attribute_value_by_name (menu_item, attribute_name, expected_type);
+ if (value == NULL)
+ return FALSE;
+
+ va_start (ap, format_string);
+ g_variant_get_va (value, format_string, NULL, &ap);
+ g_variant_unref (value);
+ va_end (ap);
+
+ return TRUE;
+}
+
+void
+g_menu_item_set_attribute_value (GMenuItem *menu_item,
+ GQuark attribute_quark,
+ GVariant *value)
+{
+ g_return_if_fail (G_IS_MENU_ITEM (menu_item));
+ g_return_if_fail (attribute_quark != 0);
+ g_return_if_fail (value != NULL);
+
+ g_menu_item_clear_cow (menu_item);
+
+ g_hash_table_insert (menu_item->attributes, GINT_TO_POINTER (attribute_quark), g_variant_ref_sink (value));
+}
+
+void
+g_menu_item_set_attribute (GMenuItem *menu_item,
+ GQuark attribute_quark,
+ const gchar *format_string,
+ ...)
+{
+ GVariant *value;
+ va_list ap;
+
+ va_start (ap, format_string);
+ value = g_variant_new_va (format_string, NULL, &ap);
+ va_end (ap);
+
+ g_menu_item_set_attribute_value (menu_item, attribute_quark, value);
+}
+
+void
+g_menu_item_unset_attribute (GMenuItem *menu_item,
+ GQuark attribute_quark)
+{
+ g_hash_table_remove (menu_item->attributes, GINT_TO_POINTER (attribute_quark));
+}
+
+void
+g_menu_item_set_attribute_value_by_name (GMenuItem *menu_item,
+ const gchar *attribute_name,
+ GVariant *value)
+{
+ g_menu_item_set_attribute_value (menu_item, g_quark_from_string (attribute_name), value);
+}
+
+void
+g_menu_item_set_attribute_by_name (GMenuItem *menu_item,
+ const gchar *attribute_name,
+ const gchar *format_string,
+ ...)
+{
+ GVariant *value;
+ va_list ap;
+
+ va_start (ap, format_string);
+ value = g_variant_new_va (format_string, NULL, &ap);
+ va_end (ap);
+
+ g_menu_item_set_attribute_value (menu_item, g_quark_from_string (attribute_name), value);
+}
+
+void
+g_menu_item_unset_attribute_by_name (GMenuItem *menu_item,
+ const gchar *attribute_name)
+{
+ g_hash_table_remove (menu_item->attributes, GINT_TO_POINTER (g_quark_try_string (attribute_name)));
+}
+
+
+GMenuModel *
+g_menu_item_get_link (GMenuItem *menu_item,
+ GQuark link_quark)
+{
+ GMenuModel *link = NULL;
+
+ g_return_val_if_fail (G_IS_MENU_ITEM (menu_item), NULL);
+
+ if (menu_item->links)
+ link = g_hash_table_lookup (menu_item->links, GINT_TO_POINTER (link_quark));
+
+ return link ? g_object_ref (link) : NULL;
+}
+
+GMenuModel *
+g_menu_item_get_link_by_name (GMenuItem *menu_item,
+ const gchar *link_name)
+{
+ return g_menu_item_get_link (menu_item, g_quark_try_string (link_name));
+}
+
+void
+g_menu_item_set_link (GMenuItem *menu_item,
+ GQuark link_quark,
+ GMenuModel *link)
+{
+ g_return_if_fail (G_IS_MENU_ITEM (menu_item));
+ g_return_if_fail (link_quark != 0);
+ g_return_if_fail (link != NULL);
+
+ g_menu_item_clear_cow (menu_item);
+
+ g_hash_table_insert (menu_item->links, GINT_TO_POINTER (link_quark), g_object_ref (link));
+}
+
+void
+g_menu_item_set_link_by_name (GMenuItem *menu_item,
+ const gchar *link_name,
+ GMenuModel *link)
+{
+ g_menu_item_set_link (menu_item, g_quark_from_string (link_name), link);
+}
+
+void
+g_menu_item_set_label (GMenuItem *menu_item,
+ const gchar *label)
+{
+ g_menu_item_set_attribute (menu_item, G_MENU_ATTRIBUTE_LABEL, "s", label);
+}
+
+void
+g_menu_item_set_submenu (GMenuItem *menu_item,
+ GMenuModel *submenu)
+{
+ g_menu_item_set_link (menu_item, G_MENU_LINK_SUBMENU, submenu);
+}
+
+void
+g_menu_item_set_section (GMenuItem *menu_item,
+ GMenuModel *section)
+{
+ g_menu_item_set_link (menu_item, G_MENU_LINK_SECTION, section);
+}
+
+void
+g_menu_item_set_action (GMenuItem *menu_item,
+ const gchar *action)
+{
+ g_menu_item_set_attribute (menu_item, G_MENU_ATTRIBUTE_ACTION, "s", action);
+ g_menu_item_unset_attribute (menu_item, G_MENU_ATTRIBUTE_TARGET);
+}
+
+void
+g_menu_item_set_target_value (GMenuItem *menu_item,
+ GVariant *target)
+{
+ g_menu_item_set_attribute (menu_item, G_MENU_ATTRIBUTE_TARGET, "v", target);
+}
+
+void
+g_menu_item_set_target (GMenuItem *menu_item,
+ const gchar *format_string,
+ ...)
+{
+ GVariant *value;
+ va_list ap;
+
+ va_start (ap, format_string);
+ value = g_variant_new_va (format_string, NULL, &ap);
+ va_end (ap);
+
+ g_menu_item_set_target_value (menu_item, value);
+}
+
+void
+g_menu_item_set_action_and_target_value (GMenuItem *menu_item,
+ const gchar *action,
+ GVariant *target_value)
+{
+ g_menu_item_set_action (menu_item, action);
+ g_menu_item_set_target_value (menu_item, target_value);
+}
+
+void
+g_menu_item_set_action_and_target (GMenuItem *menu_item,
+ const gchar *action,
+ const gchar *format_string,
+ ...)
+{
+ GVariant *value;
+ va_list ap;
+
+ va_start (ap, format_string);
+ value = g_variant_new_va (format_string, NULL, &ap);
+ va_end (ap);
+
+ g_menu_item_set_action_and_target_value (menu_item, action, value);
+}
+
+void
+g_menu_item_set_detailed_action (GMenuItem *menu_item,
+ const gchar *detailed_action)
+{
+ const gchar *sep;
+
+ sep = strstr (detailed_action, "::");
+
+ if (sep != NULL)
+ {
+ gchar *action;
+
+ action = g_strndup (detailed_action, sep - detailed_action);
+ g_menu_item_set_action_and_target (menu_item, action, "s", sep + 2);
+ g_free (action);
+ }
+
+ else
+ g_menu_item_set_action_and_target_value (menu_item, detailed_action, NULL);
+}
+
+GMenuItem *
+g_menu_item_new (const gchar *label,
+ const gchar *detailed_action)
+{
+ GMenuItem *menu_item;
+
+ menu_item = g_object_new (G_TYPE_MENU_ITEM, NULL);
+
+ if (label != NULL)
+ g_menu_item_set_label (menu_item, label);
+
+ if (detailed_action != NULL)
+ g_menu_item_set_detailed_action (menu_item, detailed_action);
+
+ return menu_item;
+}
+
+GMenuItem *
+g_menu_item_new_submenu (const gchar *label,
+ GMenuModel *submenu)
+{
+ GMenuItem *menu_item;
+
+ menu_item = g_object_new (G_TYPE_MENU_ITEM, NULL);
+
+ if (label != NULL)
+ g_menu_item_set_label (menu_item, label);
+
+ g_menu_item_set_submenu (menu_item, submenu);
+
+ return menu_item;
+}
+
+GMenuItem *
+g_menu_item_new_section (const gchar *label,
+ GMenuModel *section)
+{
+ GMenuItem *menu_item;
+
+ menu_item = g_object_new (G_TYPE_MENU_ITEM, NULL);
+
+ if (label != NULL)
+ g_menu_item_set_label (menu_item, label);
+
+ g_menu_item_set_section (menu_item, section);
+
+ return menu_item;
+}
diff --git a/gio/gmenu.h b/gio/gmenu.h
new file mode 100644
index 0000000..1f54d79
--- /dev/null
+++ b/gio/gmenu.h
@@ -0,0 +1,177 @@
+/*
+ * Copyright  2011 Canonical Ltd.
+ * All rights reserved.
+ *
+ * Author: Ryan Lortie <desrt desrt ca>
+ */
+
+#ifndef __G_MENU_H__
+#define __G_MENU_H__
+
+#include <gio/gmenumodel.h>
+
+G_BEGIN_DECLS
+
+#define G_TYPE_MENU (g_menu_get_type ())
+#define G_MENU(inst) (G_TYPE_CHECK_INSTANCE_CAST ((inst), \
+ G_TYPE_MENU, GMenu))
+#define G_MENU_CLASS(class) (G_TYPE_CHECK_CLASS_CAST ((class), \
+ G_TYPE_MENU, GMenuClass))
+#define G_IS_MENU(inst) (G_TYPE_CHECK_INSTANCE_TYPE ((inst), \
+ G_TYPE_MENU))
+#define G_IS_MENU_CLASS(class) (G_TYPE_CHECK_CLASS_TYPE ((class), \
+ G_TYPE_MENU))
+#define G_MENU_GET_CLASS(inst) (G_TYPE_INSTANCE_GET_CLASS ((inst), \
+ G_TYPE_MENU, GMenuClass))
+
+#define G_TYPE_MENU_ITEM (g_menu_item_get_type ())
+#define G_MENU_ITEM(inst) (G_TYPE_CHECK_INSTANCE_CAST ((inst), \
+ G_TYPE_MENU_ITEM, GMenuItem))
+#define G_MENU_ITEM_CLASS(class) (G_TYPE_CHECK_CLASS_CAST ((class), \
+ G_TYPE_MENU_ITEM, GMenuItemClass))
+#define G_IS_MENU_ITEM(inst) (G_TYPE_CHECK_INSTANCE_TYPE ((inst), \
+ G_TYPE_MENU_ITEM))
+#define G_IS_MENU_ITEM_CLASS(class) (G_TYPE_CHECK_CLASS_TYPE ((class), \
+ G_TYPE_MENU_ITEM))
+#define G_MENU_ITEM_GET_CLASS(inst) (G_TYPE_INSTANCE_GET_CLASS ((inst), \
+ G_TYPE_MENU_ITEM, GMenuItemClass))
+
+typedef struct _GMenuItem GMenuItem;
+
+typedef struct _GMenuPrivate GMenuPrivate;
+typedef struct _GMenuClass GMenuClass;
+typedef struct _GMenu GMenu;
+
+struct _GMenu
+{
+ GMenuModel parent_instance;
+ GMenuPrivate *priv;
+};
+
+struct _GMenuClass
+{
+ GMenuModelClass parent_class;
+};
+
+GType g_menu_get_type (void) G_GNUC_CONST;
+GMenu * g_menu_new (void);
+
+void g_menu_freeze (GMenu *menu);
+
+void g_menu_insert_item (GMenu *menu,
+ gint index,
+ GMenuItem *item);
+void g_menu_prepend_item (GMenu *menu,
+ GMenuItem *item);
+void g_menu_append_item (GMenu *menu,
+ GMenuItem *item);
+void g_menu_remove (GMenu *menu,
+ gint index);
+
+void g_menu_insert (GMenu *menu,
+ gint index,
+ const gchar *label,
+ const gchar *detailed_action);
+void g_menu_prepend (GMenu *menu,
+ const gchar *label,
+ const gchar *detailed_action);
+void g_menu_append (GMenu *menu,
+ const gchar *label,
+ const gchar *detailed_action);
+
+void g_menu_insert_section (GMenu *menu,
+ gint index,
+ const gchar *label,
+ GMenuModel *section);
+void g_menu_prepend_section (GMenu *menu,
+ const gchar *label,
+ GMenuModel *section);
+void g_menu_append_section (GMenu *menu,
+ const gchar *label,
+ GMenuModel *section);
+
+void g_menu_insert_submenu (GMenu *menu,
+ gint index,
+ const gchar *label,
+ GMenuModel *submenu);
+void g_menu_prepend_submenu (GMenu *menu,
+ const gchar *label,
+ GMenuModel *submenu);
+void g_menu_append_submenu (GMenu *menu,
+ const gchar *label,
+ GMenuModel *submenu);
+
+
+GType g_menu_item_get_type (void) G_GNUC_CONST;
+GMenuItem * g_menu_item_new (const gchar *label,
+ const gchar *detailed_action);
+
+GMenuItem * g_menu_item_new_submenu (const gchar *label,
+ GMenuModel *submenu);
+
+GMenuItem * g_menu_item_new_section (const gchar *label,
+ GMenuModel *section);
+
+GVariant * g_menu_item_get_attribute_value (GMenuItem *menu_item,
+ GQuark attribute_quark,
+ const GVariantType *expected_type);
+gboolean g_menu_item_get_attribute (GMenuItem *menu_item,
+ GQuark attribute_quark,
+ const gchar *format_string,
+ ...);
+GVariant * g_menu_item_get_attribute_value_by_name (GMenuItem *menu_item,
+ const gchar *attribute_name,
+ const GVariantType *expected_type);
+gboolean g_menu_item_get_attribute_by_name (GMenuItem *menu_item,
+ const gchar *attribute_name,
+ const gchar *format_string,
+ ...);
+void g_menu_item_set_attribute_value (GMenuItem *menu_item,
+ GQuark attribute_quark,
+ GVariant *value);
+void g_menu_item_set_attribute (GMenuItem *menu_item,
+ GQuark attribute_quark,
+ const gchar *format_string,
+ ...);
+void g_menu_item_set_attribute_value_by_name (GMenuItem *menu_item,
+ const gchar *attribute_name,
+ GVariant *value);
+void g_menu_item_set_attribute_by_name (GMenuItem *menu_item,
+ const gchar *attribute_name,
+ const gchar *format_string,
+ ...);
+GMenuModel * g_menu_item_get_link (GMenuItem *menu_item,
+ GQuark link_quark);
+GMenuModel * g_menu_item_get_link_by_name (GMenuItem *menu_item,
+ const gchar *link_name);
+void g_menu_item_set_link (GMenuItem *menu_item,
+ GQuark link_quark,
+ GMenuModel *link);
+void g_menu_item_set_link_by_name (GMenuItem *menu_item,
+ const gchar *link_name,
+ GMenuModel *link);
+void g_menu_item_set_label (GMenuItem *menu_item,
+ const gchar *label);
+void g_menu_item_set_submenu (GMenuItem *menu_item,
+ GMenuModel *submenu);
+void g_menu_item_set_section (GMenuItem *menu_item,
+ GMenuModel *section);
+void g_menu_item_set_action (GMenuItem *menu_item,
+ const gchar *action);
+void g_menu_item_set_target_value (GMenuItem *menu_item,
+ GVariant *target);
+void g_menu_item_set_target (GMenuItem *menu_item,
+ const gchar *format_string,
+ ...);
+void g_menu_item_set_action_and_target_value (GMenuItem *menu_item,
+ const gchar *action,
+ GVariant *target_value);
+void g_menu_item_set_action_and_target (GMenuItem *menu_item,
+ const gchar *action,
+ const gchar *format_string,
+ ...);
+void g_menu_item_set_detailed_action (GMenuItem *menu_item,
+ const gchar *detailed_action);
+G_END_DECLS
+
+#endif /* __G_MENU_H__ */
diff --git a/gio/gmenumarkup.c b/gio/gmenumarkup.c
new file mode 100644
index 0000000..38cca8e
--- /dev/null
+++ b/gio/gmenumarkup.c
@@ -0,0 +1,482 @@
+/*
+ * Copyright  2011 Canonical Ltd.
+ * All rights reserved.
+ *
+ * Author: Ryan Lortie <desrt desrt ca>
+ */
+
+#include "gmenumarkup.h"
+
+#include <gi18n.h>
+
+struct frame
+{
+ GMenu *menu;
+ GMenuItem *item;
+ struct frame *prev;
+};
+
+typedef struct
+{
+ GHashTable *objects;
+ struct frame frame;
+
+ /* attributes */
+ GVariantType *type;
+ GString *string;
+ gchar *name;
+} GMenuMarkupState;
+
+static void
+g_menu_markup_push_frame (GMenuMarkupState *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
+g_menu_markup_pop_frame (GMenuMarkupState *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);
+ }
+
+ state->frame = *prev;
+
+ g_slice_free (struct frame, prev);
+}
+
+static void
+add_string_attributes (GMenuItem *item,
+ const gchar **names,
+ const gchar **values)
+{
+ gint i;
+
+ for (i = 0; names[i]; i++)
+ {
+ GQuark attribute = g_quark_from_string (names[i]);
+ g_menu_item_set_attribute (item, attribute, "s", values[i]);
+ }
+}
+
+static void
+g_menu_markup_start_element (GMarkupParseContext *context,
+ const gchar *element_name,
+ const gchar **attribute_names,
+ const gchar **attribute_values,
+ gpointer user_data,
+ GError **error)
+{
+ GMenuMarkupState *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 STRDUP G_MARKUP_COLLECT_STRDUP
+#define STRING G_MARKUP_COLLECT_STRING
+#define NO_ATTRS() COLLECT (G_MARKUP_COLLECT_INVALID, NULL)
+
+ if (!(state->frame.menu || state->frame.menu || state->string))
+ {
+ /* Can only have <menu> here. */
+ if (g_str_equal (element_name, "menu"))
+ {
+ gchar *id;
+
+ if (COLLECT (STRDUP, "id", &id))
+ {
+ GMenu *menu;
+
+ menu = g_menu_new ();
+ g_hash_table_insert (state->objects, id, menu);
+ g_menu_markup_push_frame (state, menu, NULL);
+ }
+
+ return;
+ }
+ }
+
+ 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);
+ add_string_attributes (item, attribute_names, attribute_values);
+ g_menu_markup_push_frame (state, NULL, item);
+ return;
+ }
+
+ else if (g_str_equal (element_name, "submenu"))
+ {
+ GMenuItem *item;
+ GMenu *menu;
+
+ menu = g_menu_new ();
+ item = g_menu_item_new_submenu (NULL, G_MENU_MODEL (menu));
+ add_string_attributes (item, attribute_names, attribute_values);
+ g_menu_markup_push_frame (state, menu, item);
+ return;
+ }
+
+ else if (g_str_equal (element_name, "section"))
+ {
+ GMenuItem *item;
+ GMenu *menu;
+
+ menu = g_menu_new ();
+ item = g_menu_item_new_section (NULL, G_MENU_MODEL (menu));
+ add_string_attributes (item, attribute_names, attribute_values);
+ g_menu_markup_push_frame (state, menu, item);
+ return;
+ }
+ }
+
+ if (state->frame.item)
+ {
+ /* Can have '<attribute>' or '<link>' here. */
+ if (g_str_equal (element_name, "attribute"))
+ {
+ const gchar *typestr;
+ const gchar *name;
+
+ if (COLLECT (STRING, "name", &name,
+ 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->name = g_strdup (name);
+ g_menu_markup_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_by_name (state->frame.item, name, G_MENU_MODEL (menu));
+ g_menu_markup_push_frame (state, menu, NULL);
+
+ if (id != NULL)
+ g_hash_table_insert (state->objects, g_strdup (id), g_object_ref (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
+g_menu_markup_end_element (GMarkupParseContext *context,
+ const gchar *element_name,
+ gpointer user_data,
+ GError **error)
+{
+ GMenuMarkupState *state = user_data;
+
+ g_menu_markup_pop_frame (state);
+
+ if (state->string)
+ {
+ GVariant *value;
+ gchar *text;
+
+ text = g_string_free (state->string, FALSE);
+ state->string = NULL;
+
+ /* If error is set here, it will follow us out, ending the parse.
+ * We still need to free everything, though.
+ */
+ if ((value = g_variant_parse (state->type, text, NULL, NULL, error)))
+ {
+ g_menu_item_set_attribute_value_by_name (state->frame.item, state->name, value);
+ g_variant_unref (value);
+ }
+
+ g_free (state->name);
+ state->name = NULL;
+
+ if (state->type)
+ {
+ g_variant_type_free (state->type);
+ state->type = NULL;
+ }
+
+ g_free (text);
+ }
+}
+
+static void
+g_menu_markup_text (GMarkupParseContext *context,
+ const gchar *text,
+ gsize text_len,
+ gpointer user_data,
+ GError **error)
+{
+ GMenuMarkupState *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
+g_menu_markup_error (GMarkupParseContext *context,
+ GError *error,
+ gpointer user_data)
+{
+ GMenuMarkupState *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);
+
+ if (state->name)
+ g_free (state->name);
+
+ if (state->objects)
+ g_hash_table_unref (state->objects);
+
+ g_slice_free (GMenuMarkupState, state);
+}
+
+static GMarkupParser g_menu_subparser =
+{
+ g_menu_markup_start_element,
+ g_menu_markup_end_element,
+ g_menu_markup_text,
+ NULL, /* passthrough */
+ g_menu_markup_error
+};
+
+void
+g_menu_markup_parser_start (GMarkupParseContext *context,
+ GHashTable *objects)
+{
+ GMenuMarkupState *state;
+
+ g_return_if_fail (context != NULL);
+
+ state = g_slice_new0 (GMenuMarkupState);
+
+ if (objects != NULL)
+ state->objects = g_hash_table_ref (objects);
+ else
+ state->objects = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref);
+
+ g_markup_parse_context_push (context, &g_menu_subparser, state);
+}
+
+GHashTable *
+g_menu_markup_parser_end (GMarkupParseContext *context)
+{
+ GMenuMarkupState *state = g_markup_parse_context_pop (context);
+ GHashTable *objects;
+
+ objects = state->objects;
+ g_slice_free (GMenuMarkupState, state);
+
+ return objects;
+}
+
+void
+g_menu_markup_parser_start_menu (GMarkupParseContext *context,
+ GHashTable *objects)
+{
+ GMenuMarkupState *state;
+
+ g_return_if_fail (context != NULL);
+
+ state = g_slice_new0 (GMenuMarkupState);
+
+ if (objects)
+ state->objects = g_hash_table_ref (objects);
+
+ g_markup_parse_context_push (context, &g_menu_subparser, state);
+
+ state->frame.menu = g_menu_new ();
+}
+
+GMenu *
+g_menu_markup_parser_end_menu (GMarkupParseContext *context)
+{
+ GMenuMarkupState *state = g_markup_parse_context_pop (context);
+ GMenu *menu;
+
+ menu = state->frame.menu;
+
+ g_hash_table_unref (state->objects);
+ g_slice_free (GMenuMarkupState, state);
+
+ return menu;
+}
+
+static void
+indent_string (GString *string,
+ gint indent)
+{
+ while (indent--)
+ g_string_append_c (string, ' ');
+}
+
+GString *
+g_menu_markup_print_string (GString *string,
+ GMenuModel *model,
+ gint indent,
+ gint tabstop)
+{
+ gint i, n;
+
+ if G_UNLIKELY (string == NULL)
+ string = g_string_new (NULL);
+
+ n = g_menu_model_get_n_items (model);
+
+ for (i = 0; i < n; i++)
+ {
+ GMenuAttributeIter *attr_iter;
+ GMenuLinkIter *link_iter;
+ GMenuModelItem item;
+ gboolean need_nl;
+
+ if (i > 0)
+ g_string_append (string, "\n");
+
+ g_menu_model_get_item (model, i, &item);
+
+ indent_string (string, indent);
+ g_string_append (string, "<item>\n");
+
+ attr_iter = g_menu_model_item_iterate_attributes (&item);
+ link_iter = g_menu_model_item_iterate_links (&item);
+ need_nl = FALSE;
+
+ while (g_menu_attribute_iter_next (attr_iter))
+ {
+ const gchar *name = g_menu_attribute_iter_get_name (attr_iter);
+ GVariant *value = g_menu_attribute_iter_get_value (attr_iter);
+ gchar *printed;
+ gchar *str;
+
+ printed = g_variant_print (value, TRUE);
+ str = g_markup_printf_escaped ("<attribute name='%s'>%s</attribute>\n", name, printed);
+ indent_string (string, indent + tabstop);
+ g_string_append (string, str);
+ g_variant_unref (value);
+ g_free (printed);
+ g_free (str);
+
+ need_nl = TRUE;
+ }
+ g_object_unref (attr_iter);
+
+ while (g_menu_link_iter_next (link_iter))
+ {
+ const gchar *name = g_menu_link_iter_get_name (link_iter);
+ GMenuModel *menu = g_menu_link_iter_get_value (link_iter);
+ gchar *str;
+
+ if (need_nl)
+ g_string_append_c (string, '\n');
+
+ str = g_markup_printf_escaped ("<link name='%s'>\n", name);
+ indent_string (string, indent + tabstop);
+ g_string_append (string, str);
+ g_free (str);
+
+ g_menu_markup_print_string (string, menu, indent + 2 * tabstop, tabstop);
+
+ indent_string (string, indent + tabstop);
+ g_string_append (string, "</link>\n");
+
+ need_nl = TRUE;
+ }
+ g_object_unref (link_iter);
+
+ indent_string (string, indent);
+ g_string_append (string, "</item>\n");
+ }
+
+ return string;
+}
+
+void
+g_menu_markup_print_stderr (GMenuModel *model)
+{
+ GString *string;
+
+ string = g_string_new ("<menu>\n");
+ g_menu_markup_print_string (string, model, 2, 2);
+ g_printerr ("%s</menu>\n", string->str);
+ g_string_free (string, TRUE);
+}
diff --git a/gio/gmenumarkup.h b/gio/gmenumarkup.h
new file mode 100644
index 0000000..375e653
--- /dev/null
+++ b/gio/gmenumarkup.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright  2011 Canonical Ltd.
+ * All rights reserved.
+ *
+ * Author: Ryan Lortie <desrt desrt ca>
+ */
+
+#ifndef __G_MENU_MARKUP_H__
+#define __G_MENU_MARKUP_H__
+
+#include <gio/gmenu.h>
+
+void g_menu_markup_parser_start (GMarkupParseContext *context,
+ GHashTable *objects);
+GHashTable * g_menu_markup_parser_end (GMarkupParseContext *context);
+
+void g_menu_markup_parser_start_menu (GMarkupParseContext *context,
+ GHashTable *objects);
+GMenu * g_menu_markup_parser_end_menu (GMarkupParseContext *context);
+
+void g_menu_markup_print_stderr (GMenuModel *model);
+
+#endif /* __G_MENU_MARKUP_H__ */
diff --git a/gio/gmenumodel.c b/gio/gmenumodel.c
new file mode 100644
index 0000000..a34ff3a
--- /dev/null
+++ b/gio/gmenumodel.c
@@ -0,0 +1,873 @@
+/*
+ * Copyright  2011 Canonical Ltd.
+ * All rights reserved.
+ *
+ * Author: Ryan Lortie <desrt desrt ca>
+ */
+
+#include "gmenumodel.h"
+
+
+typedef struct
+{
+ GMenuLinkIter parent_instance;
+ GHashTableIter iter;
+ GHashTable *table;
+ gboolean is_quarks;
+} GMenuLinkHashIter;
+
+typedef GMenuLinkIterClass GMenuLinkHashIterClass;
+
+G_DEFINE_TYPE (GMenuLinkHashIter, g_menu_link_hash_iter, G_TYPE_MENU_LINK_ITER)
+
+static gboolean
+g_menu_link_hash_iter_get_next (GMenuLinkIter *link_iter,
+ const gchar **name,
+ GMenuModel **value)
+{
+ GMenuLinkHashIter *iter = (GMenuLinkHashIter *) link_iter;
+ gpointer keyptr, valueptr;
+
+ if (!g_hash_table_iter_next (&iter->iter, &keyptr, &valueptr))
+ return FALSE;
+
+ if (iter->is_quarks)
+ *name = g_quark_to_string (GPOINTER_TO_INT (keyptr));
+ else
+ *name = keyptr;
+
+ *value = g_object_ref (valueptr);
+
+ return TRUE;
+}
+
+static void
+g_menu_link_hash_iter_finalize (GObject *object)
+{
+ GMenuLinkHashIter *iter = (GMenuLinkHashIter *) object;
+
+ g_hash_table_unref (iter->table);
+
+ G_OBJECT_CLASS (g_menu_link_hash_iter_parent_class)
+ ->finalize (object);
+}
+
+static void
+g_menu_link_hash_iter_init (GMenuLinkHashIter *iter)
+{
+}
+
+static void
+g_menu_link_hash_iter_class_init (GMenuLinkHashIterClass *class)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (class);
+
+ object_class->finalize = g_menu_link_hash_iter_finalize;
+ class->get_next = g_menu_link_hash_iter_get_next;
+}
+
+
+typedef struct
+{
+ GMenuAttributeIter parent_instance;
+ GHashTableIter iter;
+ GHashTable *table;
+ gboolean is_quarks;
+} GMenuAttributeHashIter;
+
+typedef GMenuAttributeIterClass GMenuAttributeHashIterClass;
+
+G_DEFINE_TYPE (GMenuAttributeHashIter, g_menu_attribute_hash_iter, G_TYPE_MENU_ATTRIBUTE_ITER)
+
+static gboolean
+g_menu_attribute_hash_iter_get_next (GMenuAttributeIter *attr_iter,
+ const gchar **name,
+ GVariant **value)
+{
+ GMenuAttributeHashIter *iter = (GMenuAttributeHashIter *) attr_iter;
+ gpointer keyptr, valueptr;
+
+ if (!g_hash_table_iter_next (&iter->iter, &keyptr, &valueptr))
+ return FALSE;
+
+ if (iter->is_quarks)
+ *name = g_quark_to_string (GPOINTER_TO_INT (keyptr));
+ else
+ *name = keyptr;
+
+ *value = g_variant_ref (valueptr);
+
+ return TRUE;
+}
+
+static void
+g_menu_attribute_hash_iter_finalize (GObject *object)
+{
+ GMenuAttributeHashIter *iter = (GMenuAttributeHashIter *) object;
+
+ g_hash_table_unref (iter->table);
+
+ G_OBJECT_CLASS (g_menu_attribute_hash_iter_parent_class)
+ ->finalize (object);
+}
+
+static void
+g_menu_attribute_hash_iter_init (GMenuAttributeHashIter *iter)
+{
+}
+
+static void
+g_menu_attribute_hash_iter_class_init (GMenuAttributeHashIterClass *class)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (class);
+
+ object_class->finalize = g_menu_attribute_hash_iter_finalize;
+ class->get_next = g_menu_attribute_hash_iter_get_next;
+}
+
+
+typedef struct
+{
+ GMenuAttributeIter parent_instance;
+ GVariantIter iter;
+ GVariant *dict;
+} GMenuAttributeDictIter;
+
+typedef GMenuAttributeIterClass GMenuAttributeDictIterClass;
+
+G_DEFINE_TYPE (GMenuAttributeDictIter, g_menu_attribute_dict_iter, G_TYPE_MENU_ATTRIBUTE_ITER)
+
+static gboolean
+g_menu_attribute_dict_iter_get_next (GMenuAttributeIter *attr_iter,
+ const gchar **name,
+ GVariant **value)
+{
+ GMenuAttributeDictIter *iter = (GMenuAttributeDictIter *) attr_iter;
+
+ return g_variant_iter_next (&iter->iter, "{&sv}", name, value);
+}
+
+static void
+g_menu_attribute_dict_iter_finalize (GObject *object)
+{
+ GMenuAttributeDictIter *iter = (GMenuAttributeDictIter *) object;
+
+ g_variant_unref (iter->dict);
+
+ G_OBJECT_CLASS (g_menu_attribute_dict_iter_parent_class)
+ ->finalize (object);
+}
+
+static void
+g_menu_attribute_dict_iter_init (GMenuAttributeDictIter *iter)
+{
+}
+
+static void
+g_menu_attribute_dict_iter_class_init (GMenuAttributeDictIterClass *class)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (class);
+
+ object_class->finalize = g_menu_attribute_dict_iter_finalize;
+ class->get_next = g_menu_attribute_dict_iter_get_next;
+}
+
+
+G_DEFINE_ABSTRACT_TYPE (GMenuModel, g_menu_model, G_TYPE_OBJECT)
+
+
+guint g_menu_model_items_changed_signal;
+
+#define MAKE_QUARK(str) \
+ GQuark \
+ g_menu_model_get_ ## str ## _quark (void) \
+ { \
+ static GQuark quark; \
+ if G_UNLIKELY (quark == 0) \
+ quark = g_quark_from_static_string (#str); \
+ return quark; \
+ }
+
+MAKE_QUARK(action)
+MAKE_QUARK(target)
+MAKE_QUARK(label)
+MAKE_QUARK(submenu)
+MAKE_QUARK(section)
+
+static GMenuAttributeIter *
+g_menu_model_real_iterate_item_attributes (GMenuModel *model,
+ gint item_index)
+{
+ GHashTable *string_table = NULL;
+ GHashTable *quark_table = NULL;
+ GVariant *dictionary = NULL;
+ GMenuAttributeIter *result;
+
+ G_MENU_MODEL_GET_CLASS (model)
+ ->get_item_attributes (model, item_index, &quark_table, &string_table, &dictionary);
+
+ if (quark_table)
+ {
+ GMenuAttributeHashIter *iter = g_object_new (g_menu_attribute_hash_iter_get_type (), NULL);
+ g_hash_table_iter_init (&iter->iter, quark_table);
+ iter->table = g_hash_table_ref (quark_table);
+ iter->is_quarks = TRUE;
+ result = G_MENU_ATTRIBUTE_ITER (iter);
+ }
+
+ else if (string_table)
+ {
+ GMenuAttributeHashIter *iter = g_object_new (g_menu_attribute_hash_iter_get_type (), NULL);
+ g_hash_table_iter_init (&iter->iter, string_table);
+ iter->table = g_hash_table_ref (string_table);
+ iter->is_quarks = FALSE;
+ result = G_MENU_ATTRIBUTE_ITER (iter);
+ }
+
+ else if (dictionary)
+ {
+ GMenuAttributeDictIter *iter = g_object_new (g_menu_attribute_dict_iter_get_type (), NULL);
+ g_variant_iter_init (&iter->iter, dictionary);
+ iter->dict = g_variant_ref (dictionary);
+ result = G_MENU_ATTRIBUTE_ITER (iter);
+ }
+
+ else
+ {
+ g_critical ("GMenuModel implementation '%s' doesn't override iterate_item_attributes() "
+ "and fails to return sane values from get_item_attributes()",
+ G_OBJECT_TYPE_NAME (model));
+ result = NULL;
+ }
+
+ if (string_table != NULL)
+ g_hash_table_unref (string_table);
+ if (quark_table != NULL)
+ g_hash_table_unref (quark_table);
+ if (dictionary != NULL)
+ g_variant_unref (dictionary);
+
+ return result;
+}
+
+static GVariant *
+g_menu_model_real_get_item_attribute_value_by_name (GMenuModel *model,
+ gint item_index,
+ const gchar *attribute_name,
+ const GVariantType *expected_type)
+{
+ GHashTable *string_table = NULL;
+ GHashTable *quark_table = NULL;
+ GVariant *dictionary = NULL;
+ GVariant *value = NULL;
+
+ G_MENU_MODEL_GET_CLASS (model)
+ ->get_item_attributes (model, item_index, &quark_table, &string_table, &dictionary);
+
+ if (string_table != NULL)
+ {
+ value = g_hash_table_lookup (string_table, attribute_name);
+
+ if (value != NULL)
+ {
+ if (expected_type == NULL || g_variant_is_of_type (value, expected_type))
+ value = g_variant_ref (value);
+ else
+ value = NULL;
+ }
+ }
+
+ else if (quark_table != NULL)
+ {
+ GQuark quark = g_quark_try_string (attribute_name);
+
+ if (quark != 0)
+ value = g_hash_table_lookup (quark_table, GINT_TO_POINTER (quark));
+
+ if (value != NULL)
+ {
+ if (expected_type == NULL || g_variant_is_of_type (value, expected_type))
+ value = g_variant_ref (value);
+ else
+ value = NULL;
+ }
+ }
+
+ else if (dictionary != NULL)
+ value = g_variant_lookup_value (dictionary, attribute_name, expected_type);
+
+ if (string_table != NULL)
+ g_hash_table_unref (string_table);
+ if (quark_table != NULL)
+ g_hash_table_unref (quark_table);
+ if (dictionary != NULL)
+ g_variant_unref (dictionary);
+
+ return value;
+}
+
+static GVariant *
+g_menu_model_real_get_item_attribute_value (GMenuModel *model,
+ gint item_index,
+ GQuark attribute_quark,
+ const GVariantType *expected_type)
+{
+ GHashTable *string_table = NULL;
+ GHashTable *quark_table = NULL;
+ GVariant *dictionary = NULL;
+ GVariant *value = NULL;
+
+ G_MENU_MODEL_GET_CLASS (model)
+ ->get_item_attributes (model, item_index, &quark_table, &string_table, &dictionary);
+
+ if (quark_table != NULL)
+ {
+ value = g_hash_table_lookup (quark_table, GINT_TO_POINTER (attribute_quark));
+
+ if (value != NULL)
+ {
+ if (expected_type == NULL || g_variant_is_of_type (value, expected_type))
+ value = g_variant_ref (value);
+ else
+ value = NULL;
+ }
+ }
+
+ else if (string_table != NULL)
+ {
+ value = g_hash_table_lookup (string_table, g_quark_to_string (attribute_quark));
+
+ if (value != NULL)
+ {
+ if (expected_type == NULL || g_variant_is_of_type (value, expected_type))
+ value = g_variant_ref (value);
+ else
+ value = NULL;
+ }
+ }
+
+ else if (dictionary != NULL)
+ value = g_variant_lookup_value (dictionary, g_quark_to_string (attribute_quark), expected_type);
+
+ if (string_table != NULL)
+ g_hash_table_unref (string_table);
+ if (quark_table != NULL)
+ g_hash_table_unref (quark_table);
+ if (dictionary != NULL)
+ g_variant_unref (dictionary);
+
+ return value;
+ return NULL;
+}
+
+static GMenuLinkIter *
+g_menu_model_real_iterate_item_links (GMenuModel *model,
+ gint item_index)
+{
+ GHashTable *string_table = NULL;
+ GHashTable *quark_table = NULL;
+ GMenuLinkIter *result;
+
+ G_MENU_MODEL_GET_CLASS (model)
+ ->get_item_links (model, item_index, &quark_table, &string_table);
+
+ if (quark_table)
+ {
+ GMenuLinkHashIter *iter = g_object_new (g_menu_link_hash_iter_get_type (), NULL);
+ g_hash_table_iter_init (&iter->iter, quark_table);
+ iter->table = g_hash_table_ref (quark_table);
+ iter->is_quarks = TRUE;
+ result = G_MENU_LINK_ITER (iter);
+ }
+
+ else if (string_table)
+ {
+ GMenuLinkHashIter *iter = g_object_new (g_menu_link_hash_iter_get_type (), NULL);
+ g_hash_table_iter_init (&iter->iter, string_table);
+ iter->table = g_hash_table_ref (string_table);
+ iter->is_quarks = FALSE;
+ result = G_MENU_LINK_ITER (iter);
+ }
+
+ else
+ {
+ g_critical ("GMenuModel implementation '%s' doesn't override iterate_item_links() "
+ "and fails to return sane values from get_item_links()",
+ G_OBJECT_TYPE_NAME (model));
+ result = NULL;
+ }
+
+ if (string_table != NULL)
+ g_hash_table_unref (string_table);
+ if (quark_table != NULL)
+ g_hash_table_unref (quark_table);
+
+ return result;
+}
+
+static GMenuModel *
+g_menu_model_real_get_item_link_by_name (GMenuModel *model,
+ gint item_index,
+ const gchar *link_name)
+{
+ GHashTable *string_table = NULL;
+ GHashTable *quark_table = NULL;
+ GMenuModel *link = NULL;
+
+ G_MENU_MODEL_GET_CLASS (model)
+ ->get_item_links (model, item_index, &quark_table, &string_table);
+
+ if (string_table != NULL)
+ link = g_hash_table_lookup (string_table, link_name);
+
+ else if (quark_table != NULL)
+ {
+ GQuark quark = g_quark_try_string (link_name);
+
+ if (quark != 0)
+ link = g_hash_table_lookup (quark_table, GINT_TO_POINTER (quark));
+ }
+
+ if (string_table != NULL)
+ g_hash_table_unref (string_table);
+ if (quark_table != NULL)
+ g_hash_table_unref (quark_table);
+
+ return link ? g_object_ref (link) : NULL;
+}
+
+static GMenuModel *
+g_menu_model_real_get_item_link (GMenuModel *model,
+ gint item_index,
+ GQuark link_quark)
+{
+ GHashTable *string_table = NULL;
+ GHashTable *quark_table = NULL;
+ GMenuModel *link = NULL;
+
+ G_MENU_MODEL_GET_CLASS (model)
+ ->get_item_links (model, item_index, &quark_table, &string_table);
+
+ if (quark_table != NULL)
+ link = g_hash_table_lookup (quark_table, GINT_TO_POINTER (link_quark));
+
+ else if (string_table != NULL)
+ link = g_hash_table_lookup (string_table, g_quark_to_string (link_quark));
+
+ if (string_table != NULL)
+ g_hash_table_unref (string_table);
+ if (quark_table != NULL)
+ g_hash_table_unref (quark_table);
+
+ return link ? g_object_ref (link) : NULL;
+}
+
+static void
+g_menu_model_init (GMenuModel *model)
+{
+}
+
+static void
+g_menu_model_class_init (GMenuModelClass *class)
+{
+ class->iterate_item_attributes = g_menu_model_real_iterate_item_attributes;
+ class->get_item_attribute_value_by_name = g_menu_model_real_get_item_attribute_value_by_name;
+ class->get_item_attribute_value = g_menu_model_real_get_item_attribute_value;
+ class->iterate_item_links = g_menu_model_real_iterate_item_links;
+ class->get_item_link_by_name = g_menu_model_real_get_item_link_by_name;
+ class->get_item_link = g_menu_model_real_get_item_link;
+
+ g_menu_model_items_changed_signal =
+ g_signal_new ("items-changed", G_TYPE_MENU_MODEL,
+ G_SIGNAL_RUN_LAST, 0, NULL, NULL,
+ g_cclosure_marshal_generic, G_TYPE_NONE,
+ 3, G_TYPE_INT, G_TYPE_INT, G_TYPE_INT);
+}
+
+
+
+gboolean
+g_menu_model_is_mutable (GMenuModel *model)
+{
+ return G_MENU_MODEL_GET_CLASS (model)
+ ->is_mutable (model);
+}
+
+gint
+g_menu_model_get_n_items (GMenuModel *model)
+{
+ return G_MENU_MODEL_GET_CLASS (model)
+ ->get_n_items (model);
+}
+
+void
+g_menu_model_get_item (GMenuModel *model,
+ gint item_index,
+ GMenuModelItem *item)
+{
+ g_return_if_fail (G_IS_MENU_MODEL (model));
+
+ item->model = model;
+ item->index_ = item_index;
+}
+
+GMenuAttributeIter *
+g_menu_model_iterate_item_attributes (GMenuModel *model,
+ gint item_index)
+{
+ return G_MENU_MODEL_GET_CLASS (model)
+ ->iterate_item_attributes (model, item_index);
+}
+
+GVariant *
+g_menu_model_get_item_attribute_value_by_name (GMenuModel *model,
+ gint item_index,
+ const gchar *attribute_name,
+ const GVariantType *expected_type)
+{
+ return G_MENU_MODEL_GET_CLASS (model)
+ ->get_item_attribute_value_by_name (model, item_index, attribute_name, expected_type);
+}
+
+gboolean
+g_menu_model_get_item_attribute_by_name (GMenuModel *model,
+ gint item_index,
+ const gchar *attribute_name,
+ const gchar *format_string,
+ ...)
+{
+ const GVariantType *expected_type;
+ GVariant *value;
+ va_list ap;
+
+ expected_type = NULL; /* XXX devine the type, ensure no '&' */
+
+ value = g_menu_model_get_item_attribute_value_by_name (model, item_index, attribute_name, expected_type);
+ if (value == NULL)
+ return FALSE;
+
+ va_start (ap, format_string);
+ g_variant_get_va (value, format_string, NULL, &ap);
+ g_variant_unref (value);
+ va_end (ap);
+
+ return TRUE;
+}
+
+GVariant *
+g_menu_model_get_item_attribute_value (GMenuModel *model,
+ gint item_index,
+ GQuark attribute_quark,
+ const GVariantType *expected_type)
+{
+ return G_MENU_MODEL_GET_CLASS (model)
+ ->get_item_attribute_value (model, item_index, attribute_quark, expected_type);
+}
+
+gboolean
+g_menu_model_get_item_attribute (GMenuModel *model,
+ gint item_index,
+ GQuark attribute_quark,
+ const gchar *format_string,
+ ...)
+{
+ const GVariantType *expected_type;
+ GVariant *value;
+ va_list ap;
+
+ expected_type = NULL; /* XXX devine the type, ensure no '&' */
+
+ value = g_menu_model_get_item_attribute_value (model, item_index, attribute_quark, expected_type);
+ if (value == NULL)
+ return FALSE;
+
+ va_start (ap, format_string);
+ g_variant_get_va (value, format_string, NULL, &ap);
+ g_variant_unref (value);
+ va_end (ap);
+
+ return TRUE;
+}
+
+GMenuLinkIter *
+g_menu_model_iterate_item_links (GMenuModel *model,
+ gint item_index)
+{
+ return G_MENU_MODEL_GET_CLASS (model)
+ ->iterate_item_links (model, item_index);
+}
+
+GMenuModel *
+g_menu_model_get_item_link_by_name (GMenuModel *model,
+ gint item_index,
+ const gchar *link_name)
+{
+ return G_MENU_MODEL_GET_CLASS (model)
+ ->get_item_link_by_name (model, item_index, link_name);
+}
+
+GMenuModel *
+g_menu_model_get_item_link (GMenuModel *model,
+ gint item_index,
+ GQuark link_quark)
+{
+ return G_MENU_MODEL_GET_CLASS (model)
+ ->get_item_link (model, item_index, link_quark);
+}
+
+void
+g_menu_model_items_changed (GMenuModel *model,
+ gint index_,
+ gint removed,
+ gint added)
+{
+ g_signal_emit (model, g_menu_model_items_changed_signal, 0, index_, removed, added);
+}
+
+G_DEFINE_ABSTRACT_TYPE (GMenuAttributeIter, g_menu_attribute_iter, G_TYPE_OBJECT)
+
+struct _GMenuAttributeIterPrivate
+{
+ const gchar *name;
+ GVariant *value;
+ gboolean valid;
+};
+
+gboolean
+g_menu_attribute_iter_get_next (GMenuAttributeIter *iter,
+ const gchar **name,
+ GVariant **value)
+{
+ if (iter->priv->value)
+ g_variant_unref (iter->priv->value);
+
+ iter->priv->valid = G_MENU_ATTRIBUTE_ITER_GET_CLASS (iter)
+ ->get_next (iter, &iter->priv->name, &iter->priv->value);
+
+ if (name)
+ *name = iter->priv->name;
+
+ if (value)
+ *value = g_variant_ref (iter->priv->value);
+
+ return iter->priv->valid;
+}
+
+gboolean
+g_menu_attribute_iter_next (GMenuAttributeIter *iter)
+{
+ return g_menu_attribute_iter_get_next (iter, NULL, NULL);
+}
+
+const gchar *
+g_menu_attribute_iter_get_name (GMenuAttributeIter *iter)
+{
+ g_return_val_if_fail (iter->priv->valid, NULL);
+
+ return iter->priv->name;
+}
+
+GVariant *
+g_menu_attribute_iter_get_value (GMenuAttributeIter *iter)
+{
+ g_return_val_if_fail (iter->priv->valid, NULL);
+
+ return g_variant_ref (iter->priv->value);
+}
+
+static void
+g_menu_attribute_iter_finalize (GObject *object)
+{
+ GMenuAttributeIter *iter = G_MENU_ATTRIBUTE_ITER (object);
+
+ if (iter->priv->value)
+ g_variant_unref (iter->priv->value);
+
+ G_OBJECT_CLASS (g_menu_attribute_iter_parent_class)
+ ->finalize (object);
+}
+
+static void
+g_menu_attribute_iter_init (GMenuAttributeIter *iter)
+{
+ iter->priv = G_TYPE_INSTANCE_GET_PRIVATE (iter, G_TYPE_MENU_ATTRIBUTE_ITER, GMenuAttributeIterPrivate);
+}
+
+static void
+g_menu_attribute_iter_class_init (GMenuAttributeIterClass *class)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (class);
+
+ object_class->finalize = g_menu_attribute_iter_finalize;
+
+ g_type_class_add_private (class, sizeof (GMenuAttributeIterPrivate));
+}
+
+G_DEFINE_ABSTRACT_TYPE (GMenuLinkIter, g_menu_link_iter, G_TYPE_OBJECT)
+
+struct _GMenuLinkIterPrivate
+{
+ const gchar *name;
+ GMenuModel *value;
+ gboolean valid;
+};
+
+gboolean
+g_menu_link_iter_get_next (GMenuLinkIter *iter,
+ const gchar **name,
+ GMenuModel **value)
+{
+ if (iter->priv->value)
+ g_object_unref (iter->priv->value);
+
+ iter->priv->valid = G_MENU_LINK_ITER_GET_CLASS (iter)
+ ->get_next (iter, &iter->priv->name, &iter->priv->value);
+
+ if (name)
+ *name = iter->priv->name;
+
+ if (value)
+ *value = g_object_ref (iter->priv->value);
+
+ return iter->priv->valid;
+}
+
+gboolean
+g_menu_link_iter_next (GMenuLinkIter *iter)
+{
+ return g_menu_link_iter_get_next (iter, NULL, NULL);
+}
+
+const gchar *
+g_menu_link_iter_get_name (GMenuLinkIter *iter)
+{
+ g_return_val_if_fail (iter->priv->valid, NULL);
+
+ return iter->priv->name;
+}
+
+GMenuModel *
+g_menu_link_iter_get_value (GMenuLinkIter *iter)
+{
+ g_return_val_if_fail (iter->priv->valid, NULL);
+
+ return g_object_ref (iter->priv->value);
+}
+
+static void
+g_menu_link_iter_finalize (GObject *object)
+{
+ GMenuLinkIter *iter = G_MENU_LINK_ITER (object);
+
+ if (iter->priv->value)
+ g_object_unref (iter->priv->value);
+
+ G_OBJECT_CLASS (g_menu_link_iter_parent_class)
+ ->finalize (object);
+}
+
+static void
+g_menu_link_iter_init (GMenuLinkIter *iter)
+{
+ iter->priv = G_TYPE_INSTANCE_GET_PRIVATE (iter, G_TYPE_MENU_LINK_ITER, GMenuLinkIterPrivate);
+}
+
+static void
+g_menu_link_iter_class_init (GMenuLinkIterClass *class)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (class);
+
+ object_class->finalize = g_menu_link_iter_finalize;
+
+ g_type_class_add_private (class, sizeof (GMenuLinkIterPrivate));
+}
+
+GMenuAttributeIter *
+g_menu_model_item_iterate_attributes (GMenuModelItem *item)
+{
+ return g_menu_model_iterate_item_attributes (item->model, item->index_);
+}
+
+GVariant *
+g_menu_model_item_get_attribute_value_by_name (GMenuModelItem *item,
+ const gchar *attribute_name,
+ const GVariantType *expected_type)
+{
+ return g_menu_model_get_item_attribute_value_by_name (item->model, item->index_, attribute_name, expected_type);
+}
+
+gboolean
+g_menu_model_item_get_attribute_by_name (GMenuModelItem *item,
+ const gchar *attribute_name,
+ const gchar *format_string,
+ ...)
+{
+ const GVariantType *expected_type;
+ GVariant *value;
+ va_list ap;
+
+ expected_type = NULL; /* XXX devine the type, ensure no '&' */
+
+ value = g_menu_model_get_item_attribute_value_by_name (item->model, item->index_, attribute_name, expected_type);
+ if (value == NULL)
+ return FALSE;
+
+ va_start (ap, format_string);
+ g_variant_get_va (value, format_string, NULL, &ap);
+ g_variant_unref (value);
+ va_end (ap);
+
+ return TRUE;
+}
+
+GVariant *
+g_menu_model_item_get_attribute_value (GMenuModelItem *item,
+ GQuark attribute_quark,
+ const GVariantType *expected_type)
+{
+ return g_menu_model_get_item_attribute_value (item->model, item->index_, attribute_quark, expected_type);
+}
+
+gboolean
+g_menu_model_item_get_attribute (GMenuModelItem *item,
+ GQuark attribute_quark,
+ const gchar *format_string,
+ ...)
+{
+ const GVariantType *expected_type;
+ GVariant *value;
+ va_list ap;
+
+ expected_type = NULL; /* XXX devine the type, ensure no '&' */
+
+ value = g_menu_model_get_item_attribute_value (item->model, item->index_, attribute_quark, expected_type);
+ if (value == NULL)
+ return FALSE;
+
+ va_start (ap, format_string);
+ g_variant_get_va (value, format_string, NULL, &ap);
+ g_variant_unref (value);
+ va_end (ap);
+
+ return TRUE;
+}
+
+GMenuLinkIter *
+g_menu_model_item_iterate_links (GMenuModelItem *item)
+{
+ return g_menu_model_iterate_item_links (item->model, item->index_);
+}
+
+GMenuModel *
+g_menu_model_item_get_link_by_name (GMenuModelItem *item,
+ const gchar *link_name)
+{
+ return g_menu_model_get_item_link_by_name (item->model, item->index_, link_name);
+}
+
+GMenuModel *
+g_menu_model_item_get_link (GMenuModelItem *item,
+ GQuark link_quark)
+{
+ return g_menu_model_get_item_link (item->model, item->index_, link_quark);
+}
diff --git a/gio/gmenumodel.h b/gio/gmenumodel.h
new file mode 100644
index 0000000..053e83b
--- /dev/null
+++ b/gio/gmenumodel.h
@@ -0,0 +1,243 @@
+/*
+ * Copyright  2011 Canonical Ltd.
+ * All rights reserved.
+ *
+ * Author: Ryan Lortie <desrt desrt ca>
+ */
+
+#ifndef __G_MENU_MODEL_H__
+#define __G_MENU_MODEL_H__
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define G_MENU_ATTRIBUTE_ACTION (g_menu_model_get_action_quark ())
+#define G_MENU_ATTRIBUTE_TARGET (g_menu_model_get_target_quark ())
+#define G_MENU_ATTRIBUTE_LABEL (g_menu_model_get_label_quark ())
+#define G_MENU_LINK_SUBMENU (g_menu_model_get_submenu_quark ())
+#define G_MENU_LINK_SECTION (g_menu_model_get_section_quark ())
+
+GQuark g_menu_model_get_action_quark (void) G_GNUC_CONST;
+GQuark g_menu_model_get_target_quark (void) G_GNUC_CONST;
+GQuark g_menu_model_get_label_quark (void) G_GNUC_CONST;
+GQuark g_menu_model_get_submenu_quark (void) G_GNUC_CONST;
+GQuark g_menu_model_get_section_quark (void) G_GNUC_CONST;
+
+
+#define G_TYPE_MENU_MODEL (g_menu_model_get_type ())
+#define G_MENU_MODEL(inst) (G_TYPE_CHECK_INSTANCE_CAST ((inst), \
+ G_TYPE_MENU_MODEL, GMenuModel))
+#define G_MENU_MODEL_CLASS(class) (G_TYPE_CHECK_CLASS_CAST ((class), \
+ G_TYPE_MENU_MODEL, GMenuModelClass))
+#define G_IS_MENU_MODEL(inst) (G_TYPE_CHECK_INSTANCE_TYPE ((inst), \
+ G_TYPE_MENU_MODEL))
+#define G_IS_MENU_MODEL_CLASS(class) (G_TYPE_CHECK_CLASS_TYPE ((class), \
+ G_TYPE_MENU_MODEL))
+#define G_MENU_MODEL_GET_CLASS(inst) (G_TYPE_INSTANCE_GET_CLASS ((inst), \
+ G_TYPE_MENU_MODEL, GMenuModelClass))
+
+typedef struct _GMenuModelPrivate GMenuModelPrivate;
+typedef struct _GMenuModelClass GMenuModelClass;
+typedef struct _GMenuModel GMenuModel;
+
+typedef struct _GMenuAttributeIterPrivate GMenuAttributeIterPrivate;
+typedef struct _GMenuAttributeIterClass GMenuAttributeIterClass;
+typedef struct _GMenuAttributeIter GMenuAttributeIter;
+
+typedef struct _GMenuLinkIterPrivate GMenuLinkIterPrivate;
+typedef struct _GMenuLinkIterClass GMenuLinkIterClass;
+typedef struct _GMenuLinkIter GMenuLinkIter;
+
+typedef struct _GMenuModelItem GMenuModelItem;
+
+struct _GMenuModel
+{
+ GObject parent_instance;
+ GMenuModelPrivate *priv;
+};
+
+struct _GMenuModelClass
+{
+ GObjectClass parent_class;
+
+ gboolean (*is_mutable) (GMenuModel *model);
+ gint (*get_n_items) (GMenuModel *model);
+
+ void (*get_item_attributes) (GMenuModel *model,
+ gint item_index,
+ GHashTable **quark_table,
+ GHashTable **string_table,
+ GVariant **dictionary);
+ GMenuAttributeIter * (*iterate_item_attributes) (GMenuModel *model,
+ gint item_index);
+ GVariant * (*get_item_attribute_value_by_name) (GMenuModel *model,
+ gint item_index,
+ const gchar *attribute_name,
+ const GVariantType *expected_type);
+ GVariant * (*get_item_attribute_value) (GMenuModel *model,
+ gint item_index,
+ GQuark attribute_quark,
+ const GVariantType *expected_type);
+
+ void (*get_item_links) (GMenuModel *model,
+ gint item_index,
+ GHashTable **quark_table,
+ GHashTable **string_table);
+ GMenuLinkIter * (*iterate_item_links) (GMenuModel *model,
+ gint item_index);
+ GMenuModel * (*get_item_link_by_name) (GMenuModel *model,
+ gint item_index,
+ const gchar *link_name);
+ GMenuModel * (*get_item_link) (GMenuModel *model,
+ gint item_index,
+ GQuark link_quark);
+};
+
+GType g_menu_model_get_type (void) G_GNUC_CONST;
+
+gboolean g_menu_model_is_mutable (GMenuModel *model);
+gint g_menu_model_get_n_items (GMenuModel *model);
+void g_menu_model_get_item (GMenuModel *model,
+ gint item_index,
+ GMenuModelItem *item);
+
+GMenuAttributeIter * g_menu_model_iterate_item_attributes (GMenuModel *model,
+ gint item_index);
+GVariant * g_menu_model_get_item_attribute_value_by_name (GMenuModel *model,
+ gint item_index,
+ const gchar *attribute_name,
+ const GVariantType *expected_type);
+gboolean g_menu_model_get_item_attribute_by_name (GMenuModel *model,
+ gint item_index,
+ const gchar *attribute_name,
+ const gchar *format_string,
+ ...);
+GVariant * g_menu_model_get_item_attribute_value (GMenuModel *model,
+ gint item_index,
+ GQuark attribute_quark,
+ const GVariantType *expected_type);
+gboolean g_menu_model_get_item_attribute (GMenuModel *model,
+ gint item_index,
+ GQuark attribute_quark,
+ const gchar *format_string,
+ ...);
+GMenuLinkIter * g_menu_model_iterate_item_links (GMenuModel *model,
+ gint item_index);
+GMenuModel * g_menu_model_get_item_link_by_name (GMenuModel *model,
+ gint item_index,
+ const gchar *link_name);
+GMenuModel * g_menu_model_get_item_link (GMenuModel *model,
+ gint item_index,
+ GQuark link_quark);
+
+void g_menu_model_items_changed (GMenuModel *model,
+ gint position,
+ gint removed,
+ gint added);
+
+
+#define G_TYPE_MENU_ATTRIBUTE_ITER (g_menu_attribute_iter_get_type ())
+#define G_MENU_ATTRIBUTE_ITER(inst) (G_TYPE_CHECK_INSTANCE_CAST ((inst), \
+ G_TYPE_MENU_ATTRIBUTE_ITER, GMenuAttributeIter))
+#define G_MENU_ATTRIBUTE_ITER_CLASS(class) (G_TYPE_CHECK_CLASS_CAST ((class), \
+ G_TYPE_MENU_ATTRIBUTE_ITER, GMenuAttributeIterClass))
+#define G_IS_MENU_ATTRIBUTE_ITER(inst) (G_TYPE_CHECK_INSTANCE_TYPE ((inst), \
+ G_TYPE_MENU_ATTRIBUTE_ITER))
+#define G_IS_MENU_ATTRIBUTE_ITER_CLASS(class) (G_TYPE_CHECK_CLASS_TYPE ((class), \
+ G_TYPE_MENU_ATTRIBUTE_ITER))
+#define G_MENU_ATTRIBUTE_ITER_GET_CLASS(inst) (G_TYPE_INSTANCE_GET_CLASS ((inst), \
+ G_TYPE_MENU_ATTRIBUTE_ITER, GMenuAttributeIterClass))
+
+struct _GMenuAttributeIter
+{
+ GObject parent_instance;
+ GMenuAttributeIterPrivate *priv;
+};
+
+struct _GMenuAttributeIterClass
+{
+ GObjectClass parent_class;
+
+ gboolean (*get_next) (GMenuAttributeIter *iter,
+ const gchar **name,
+ GVariant **value);
+};
+
+GType g_menu_attribute_iter_get_type (void) G_GNUC_CONST;
+
+gboolean g_menu_attribute_iter_get_next (GMenuAttributeIter *iter,
+ const gchar **name,
+ GVariant **value);
+gboolean g_menu_attribute_iter_next (GMenuAttributeIter *iter);
+const gchar * g_menu_attribute_iter_get_name (GMenuAttributeIter *iter);
+GVariant * g_menu_attribute_iter_get_value (GMenuAttributeIter *iter);
+
+
+#define G_TYPE_MENU_LINK_ITER (g_menu_link_iter_get_type ())
+#define G_MENU_LINK_ITER(inst) (G_TYPE_CHECK_INSTANCE_CAST ((inst), \
+ G_TYPE_MENU_LINK_ITER, GMenuLinkIter))
+#define G_MENU_LINK_ITER_CLASS(class) (G_TYPE_CHECK_CLASS_CAST ((class), \
+ G_TYPE_MENU_LINK_ITER, GMenuLinkIterClass))
+#define G_IS_MENU_LINK_ITER(inst) (G_TYPE_CHECK_INSTANCE_TYPE ((inst), \
+ G_TYPE_MENU_LINK_ITER))
+#define G_IS_MENU_LINK_ITER_CLASS(class) (G_TYPE_CHECK_CLASS_TYPE ((class), \
+ G_TYPE_MENU_LINK_ITER))
+#define G_MENU_LINK_ITER_GET_CLASS(inst) (G_TYPE_INSTANCE_GET_CLASS ((inst), \
+ G_TYPE_MENU_LINK_ITER, GMenuLinkIterClass))
+
+struct _GMenuLinkIter
+{
+ GObject parent_instance;
+ GMenuLinkIterPrivate *priv;
+};
+
+struct _GMenuLinkIterClass
+{
+ GObjectClass parent_class;
+
+ gboolean (*get_next) (GMenuLinkIter *iter,
+ const gchar **name,
+ GMenuModel **value);
+};
+
+GType g_menu_link_iter_get_type (void) G_GNUC_CONST;
+
+gboolean g_menu_link_iter_get_next (GMenuLinkIter *iter,
+ const gchar **name,
+ GMenuModel **value);
+gboolean g_menu_link_iter_next (GMenuLinkIter *iter);
+const gchar * g_menu_link_iter_get_name (GMenuLinkIter *iter);
+GMenuModel * g_menu_link_iter_get_value (GMenuLinkIter *iter);
+
+struct _GMenuModelItem
+{
+ /*< private >*/
+ GMenuModel *model;
+ gint index_;
+};
+
+GMenuAttributeIter * g_menu_model_item_iterate_attributes (GMenuModelItem *item);
+GVariant * g_menu_model_item_get_attribute_value_by_name (GMenuModelItem *item,
+ const gchar *attribute_name,
+ const GVariantType *expected_type);
+gboolean g_menu_model_item_get_attribute_by_name (GMenuModelItem *item,
+ const gchar *attribute_name,
+ const gchar *format_string,
+ ...);
+GVariant * g_menu_model_item_get_attribute_value (GMenuModelItem *item,
+ GQuark attribute_quark,
+ const GVariantType *expected_type);
+gboolean g_menu_model_item_get_attribute (GMenuModelItem *item,
+ GQuark attribute_quark,
+ const gchar *format_string,
+ ...);
+GMenuLinkIter * g_menu_model_item_iterate_links (GMenuModelItem *item);
+GMenuModel * g_menu_model_item_get_link_by_name (GMenuModelItem *item,
+ const gchar *link_name);
+GMenuModel * g_menu_model_item_get_link (GMenuModelItem *item,
+ GQuark link_quark);
+
+G_END_DECLS
+
+#endif /* __G_MENU_MODEL_H__ */
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]