[glib/wip/menus: 30/61] add GMenuExporter
- From: Matthias Clasen <matthiasc src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [glib/wip/menus: 30/61] add GMenuExporter
- Date: Thu, 17 Nov 2011 23:37:14 +0000 (UTC)
commit c1d573c70eb53cb81f3c7e462bcafba2c073f8d3
Author: Ryan Lortie <desrt desrt ca>
Date: Thu Aug 25 01:31:45 2011 -0400
add GMenuExporter
gio/Makefile.am | 2 +
gio/gio.h | 1 +
gio/gio.symbols | 3 +
gio/gmenuexporter.c | 783 +++++++++++++++++++++++++++++++++++++++++++++++++++
gio/gmenuexporter.h | 28 ++
5 files changed, 817 insertions(+), 0 deletions(-)
---
diff --git a/gio/Makefile.am b/gio/Makefile.am
index 7e83fd3..2fa96a6 100644
--- a/gio/Makefile.am
+++ b/gio/Makefile.am
@@ -135,6 +135,7 @@ application_headers = \
gapplication.h \
gmenumodel.h \
gmenu.h \
+ gmenuexporter.h \
gmenumarkup.h
application_sources = \
@@ -150,6 +151,7 @@ application_sources = \
gapplication.c \
gmenumodel.c \
gmenu.c \
+ gmenuexporter.c \
gmenumarkup.c
local_sources = \
diff --git a/gio/gio.h b/gio/gio.h
index 6f91e94..a634c07 100644
--- a/gio/gio.h
+++ b/gio/gio.h
@@ -148,6 +148,7 @@
#include <gio/gdbusactiongroup.h>
#include <gio/gmenumodel.h>
#include <gio/gmenu.h>
+#include <gio/gmenuexporter.h>
#include <gio/gmenumarkup.h>
#undef __GIO_GIO_H_INSIDE__
diff --git a/gio/gio.symbols b/gio/gio.symbols
index ed394f6..d832392 100644
--- a/gio/gio.symbols
+++ b/gio/gio.symbols
@@ -1608,6 +1608,9 @@ g_menu_attribute_iter_get_next
g_menu_attribute_iter_get_type
g_menu_attribute_iter_get_value
g_menu_attribute_iter_next
+g_menu_exporter_export
+g_menu_exporter_query
+g_menu_exporter_stop
g_menu_freeze
g_menu_get_type
g_menu_insert
diff --git a/gio/gmenuexporter.c b/gio/gmenuexporter.c
new file mode 100644
index 0000000..06b147a
--- /dev/null
+++ b/gio/gmenuexporter.c
@@ -0,0 +1,783 @@
+/*
+ * Copyright  2011 Canonical Ltd.
+ * All rights reserved.
+ *
+ * Author: Ryan Lortie <desrt desrt ca>
+ */
+
+#include "gmenuexporter.h"
+
+#include "gdbusmethodinvocation.h"
+#include "gdbusintrospection.h"
+#include "gdbusnamewatching.h"
+#include "gdbuserror.h"
+
+/* {{{1 D-Bus Interface description */
+static GDBusInterfaceInfo *
+org_gtk_Menus_get_interface (void)
+{
+ static GDBusInterfaceInfo *interface_info;
+
+ if (interface_info == NULL)
+ {
+ GError *error = NULL;
+ GDBusNodeInfo *info;
+
+ info = g_dbus_node_info_new_for_xml ("<node>"
+ " <interface name='org.gtk.Menus'>"
+ " <method name='Start'>"
+ " <arg type='au' name='groups' direction='in'/>"
+ " <arg type='a(uuaa{sv})' name='content' direction='out'/>"
+ " </method>"
+ " <method name='End'>"
+ " <arg type='au' name='groups' direction='in'/>"
+ " </method>"
+ " <signal name='Changed'>"
+ " arg type='a(uuuuaa{sv})' name='changes'/>"
+ " </signal>"
+ " </interface>"
+ "</node>", &error);
+ if (info == NULL)
+ g_error ("%s\n", error->message);
+ interface_info = g_dbus_node_info_lookup_interface (info, "org.gtk.Menus");
+ g_assert (interface_info != NULL);
+ g_dbus_interface_info_ref (interface_info);
+ g_dbus_node_info_unref (info);
+ }
+
+ return interface_info;
+}
+
+/* {{{1 Forward declarations */
+typedef struct _GMenuExporterMenu GMenuExporterMenu;
+typedef struct _GMenuExporterLink GMenuExporterLink;
+typedef struct _GMenuExporterGroup GMenuExporterGroup;
+typedef struct _GMenuExporterRemote GMenuExporterRemote;
+typedef struct _GMenuExporterWatch GMenuExporterWatch;
+typedef struct _GMenuExporter GMenuExporter;
+
+static gboolean g_menu_exporter_group_is_subscribed (GMenuExporterGroup *group);
+static guint g_menu_exporter_group_get_id (GMenuExporterGroup *group);
+static GMenuExporter * g_menu_exporter_group_get_exporter (GMenuExporterGroup *group);
+static GMenuExporterMenu * g_menu_exporter_group_add_menu (GMenuExporterGroup *group,
+ GMenuModel *model);
+static void g_menu_exporter_group_remove_menu (GMenuExporterGroup *group,
+ guint id);
+
+static GMenuExporterGroup * g_menu_exporter_create_group (GMenuExporter *exporter);
+static GMenuExporterGroup * g_menu_exporter_lookup_group (GMenuExporter *exporter,
+ guint group_id);
+static void g_menu_exporter_report (GMenuExporter *exporter,
+ GVariant *report);
+static void g_menu_exporter_remove_group (GMenuExporter *exporter,
+ guint id);
+
+/* {{{1 GMenuExporterLink, GMenuExporterMenu */
+
+struct _GMenuExporterMenu
+{
+ GMenuExporterGroup *group;
+ guint id;
+
+ GMenuModel *model;
+ gulong handler_id;
+ GSequence *item_links;
+};
+
+struct _GMenuExporterLink
+{
+ gchar *name;
+ GMenuExporterMenu *menu;
+ GMenuExporterLink *next;
+};
+
+static void
+g_menu_exporter_menu_free (GMenuExporterMenu *menu)
+{
+ g_menu_exporter_group_remove_menu (menu->group, menu->id);
+
+ if (menu->handler_id != 0)
+ g_signal_handler_disconnect (menu->model, menu->handler_id);
+
+ if (menu->item_links != NULL)
+ g_sequence_free (menu->item_links);
+
+ g_object_unref (menu->model);
+
+ g_slice_free (GMenuExporterMenu, menu);
+}
+
+static void
+g_menu_exporter_link_free (gpointer data)
+{
+ GMenuExporterLink *link = data;
+
+ while (link != NULL)
+ {
+ GMenuExporterLink *tmp = link;
+ link = tmp->next;
+
+ g_menu_exporter_menu_free (tmp->menu);
+ g_free (tmp->name);
+
+ g_slice_free (GMenuExporterLink, tmp);
+ }
+}
+
+static GMenuExporterLink *
+g_menu_exporter_menu_create_links (GMenuExporterMenu *menu,
+ gint position)
+{
+ GMenuExporterLink *list = NULL;
+ GMenuLinkIter *iter;
+ const gchar *name;
+ GMenuModel *model;
+
+ iter = g_menu_model_iterate_item_links (menu->model, position);
+
+ while (g_menu_link_iter_get_next (iter, &name, &model))
+ {
+ GMenuExporterGroup *group;
+ GMenuExporterLink *tmp;
+
+ if (0) /* [magic] */
+ group = g_menu_exporter_create_group (g_menu_exporter_group_get_exporter (menu->group));
+ else
+ group = menu->group;
+
+ tmp = g_slice_new (GMenuExporterLink);
+ tmp->name = g_strconcat (":", name, NULL);
+ tmp->menu = g_menu_exporter_group_add_menu (group, model);
+ tmp->next = list;
+ list = tmp;
+
+ g_object_unref (model);
+ }
+
+ g_object_unref (iter);
+
+ return list;
+}
+
+static GVariant *
+g_menu_exporter_menu_describe_item (GMenuExporterMenu *menu,
+ gint position)
+{
+ GMenuAttributeIter *attr_iter;
+ GVariantBuilder builder;
+ GSequenceIter *iter;
+ GMenuExporterLink *link;
+ const gchar *name;
+ GVariant *value;
+
+ g_variant_builder_init (&builder, G_VARIANT_TYPE_VARDICT);
+
+ attr_iter = g_menu_model_iterate_item_attributes (menu->model, position);
+ while (g_menu_attribute_iter_get_next (attr_iter, &name, &value))
+ {
+ g_variant_builder_add (&builder, "{sv}", name, value);
+ g_variant_unref (value);
+ }
+ g_object_unref (attr_iter);
+
+ iter = g_sequence_get_iter_at_pos (menu->item_links, position);
+ for (link = g_sequence_get (iter); link; link = link->next)
+ g_variant_builder_add (&builder, "{sv}", link->name,
+ g_variant_new ("(uu)", g_menu_exporter_group_get_id (link->menu->group), link->menu->id));
+
+ return g_variant_builder_end (&builder);
+}
+
+static GVariant *
+g_menu_exporter_menu_list (GMenuExporterMenu *menu)
+{
+ GVariantBuilder builder;
+ gint i, n;
+
+ g_variant_builder_init (&builder, G_VARIANT_TYPE ("aa{sv}"));
+
+ n = g_sequence_get_length (menu->item_links);
+ for (i = 0; i < n; i++)
+ g_variant_builder_add_value (&builder, g_menu_exporter_menu_describe_item (menu, i));
+
+ return g_variant_builder_end (&builder);
+}
+
+static void
+g_menu_exporter_menu_items_changed (GMenuModel *model,
+ gint position,
+ gint removed,
+ gint added,
+ gpointer user_data)
+{
+ GMenuExporterMenu *menu = user_data;
+ GSequenceIter *point;
+ gint i;
+
+ g_assert (menu->model == model);
+ g_assert (menu->item_links != NULL);
+ g_assert (position + removed <= g_sequence_get_length (menu->item_links));
+
+ point = g_sequence_get_iter_at_pos (menu->item_links, position + removed);
+ g_sequence_remove_range (g_sequence_get_iter_at_pos (menu->item_links, position), point);
+
+ for (i = position; i < position + added; i++)
+ g_sequence_append (menu->item_links, g_menu_exporter_menu_create_links (menu, i));
+
+ if (g_menu_exporter_group_is_subscribed (menu->group))
+ {
+ GVariantBuilder builder;
+
+ g_variant_builder_init (&builder, G_VARIANT_TYPE ("(uuuuaa{sv})"));
+ g_variant_builder_add (&builder, "u", g_menu_exporter_group_get_id (menu->group));
+ g_variant_builder_add (&builder, "u", menu->id);
+ g_variant_builder_add (&builder, "u", position);
+ g_variant_builder_add (&builder, "u", removed);
+
+ g_variant_builder_open (&builder, G_VARIANT_TYPE ("aa{sv}"));
+ for (i = position; i < position + added; i++)
+ g_variant_builder_add_value (&builder, g_menu_exporter_menu_describe_item (menu, i));
+ g_variant_builder_close (&builder);
+
+ g_menu_exporter_report (g_menu_exporter_group_get_exporter (menu->group), g_variant_builder_end (&builder));
+ }
+}
+
+static void
+g_menu_exporter_menu_prepare (GMenuExporterMenu *menu)
+{
+ g_assert (menu->item_links == NULL);
+
+ if (g_menu_model_is_mutable (menu->model))
+ menu->handler_id = g_signal_connect (menu->model, "items-changed",
+ G_CALLBACK (g_menu_exporter_menu_items_changed), menu);
+
+ menu->item_links = g_sequence_new (g_menu_exporter_link_free);
+ g_menu_exporter_menu_items_changed (menu->model, 0, 0, g_menu_model_get_n_items (menu->model), menu);
+}
+
+static GMenuExporterMenu *
+g_menu_exporter_menu_new (GMenuExporterGroup *group,
+ guint id,
+ GMenuModel *model)
+{
+ GMenuExporterMenu *menu;
+
+ menu = g_slice_new0 (GMenuExporterMenu);
+ menu->group = group;
+ menu->id = id;
+ menu->model = g_object_ref (model);
+
+ return menu;
+}
+
+/* {{{1 GMenuExporterGroup */
+
+struct _GMenuExporterGroup
+{
+ GMenuExporter *exporter;
+ guint id;
+
+ GHashTable *menus;
+ GSList *pending;
+ guint next_menu_id;
+
+ gint subscribed;
+};
+
+static void
+g_menu_exporter_group_check_if_useless (GMenuExporterGroup *group)
+{
+ if (g_hash_table_size (group->menus) == 0 && group->subscribed == 0)
+ {
+ g_menu_exporter_remove_group (group->exporter, group->id);
+
+ g_hash_table_unref (group->menus);
+ g_slist_free (group->pending);
+
+ g_slice_free (GMenuExporterGroup, group);
+ }
+}
+
+static void
+g_menu_exporter_group_clear_pending (GMenuExporterGroup *group)
+{
+ while (group->pending)
+ {
+ GMenuExporterMenu *menu;
+
+ menu = g_hash_table_lookup (group->menus, group->pending->data);
+ group->pending = g_slist_delete_link (group->pending, group->pending);
+ g_assert (menu != NULL);
+
+ g_menu_exporter_menu_prepare (menu);
+ }
+}
+
+static void
+g_menu_exporter_group_subscribe (GMenuExporterGroup *group,
+ GVariantBuilder *builder)
+{
+ GHashTableIter iter;
+ gpointer key, val;
+
+ g_menu_exporter_group_clear_pending (group);
+
+ group->subscribed++;
+
+ g_hash_table_iter_init (&iter, group->menus);
+ while (g_hash_table_iter_next (&iter, &key, &val))
+ {
+ guint id = GPOINTER_TO_INT (key);
+ GMenuExporterMenu *menu = val;
+
+ g_variant_builder_open (builder, G_VARIANT_TYPE ("(uuaa{sv})"));
+ g_variant_builder_add (builder, "u", group->id);
+ g_variant_builder_add (builder, "u", id);
+ g_variant_builder_add_value (builder, g_menu_exporter_menu_list (menu));
+ g_variant_builder_close (builder);
+ }
+}
+
+static void
+g_menu_exporter_group_unsubscribe (GMenuExporterGroup *group,
+ gint count)
+{
+ g_assert (group->subscribed >= count);
+
+ group->subscribed -= count;
+
+ g_menu_exporter_group_check_if_useless (group);
+}
+
+static GMenuExporter *
+g_menu_exporter_group_get_exporter (GMenuExporterGroup *group)
+{
+ return group->exporter;
+}
+
+static gboolean
+g_menu_exporter_group_is_subscribed (GMenuExporterGroup *group)
+{
+ return group->subscribed > 0;
+}
+
+static guint
+g_menu_exporter_group_get_id (GMenuExporterGroup *group)
+{
+ return group->id;
+}
+
+static void
+g_menu_exporter_group_remove_menu (GMenuExporterGroup *group,
+ guint id)
+{
+ g_hash_table_remove (group->menus, GINT_TO_POINTER (id));
+
+ g_menu_exporter_group_check_if_useless (group);
+}
+
+static GMenuExporterMenu *
+g_menu_exporter_group_add_menu (GMenuExporterGroup *group,
+ GMenuModel *model)
+{
+ GMenuExporterMenu *menu;
+ guint id;
+
+ id = group->next_menu_id++;
+ menu = g_menu_exporter_menu_new (group, id, model);
+ g_hash_table_insert (group->menus, GINT_TO_POINTER (id), menu);
+ group->pending = g_slist_prepend (group->pending, GINT_TO_POINTER (id));
+
+ return menu;
+}
+
+static GMenuExporterGroup *
+g_menu_exporter_group_new (GMenuExporter *exporter,
+ guint id)
+{
+ GMenuExporterGroup *group;
+
+ group = g_slice_new0 (GMenuExporterGroup);
+ group->menus = g_hash_table_new (NULL, NULL);
+ group->exporter = exporter;
+ group->id = id;
+
+ return group;
+}
+
+/* {{{1 GMenuExporterRemote */
+
+struct _GMenuExporterRemote
+{
+ GMenuExporter *exporter;
+ GHashTable *watches;
+ guint watch_id;
+};
+
+static void
+g_menu_exporter_remote_subscribe (GMenuExporterRemote *remote,
+ guint group_id,
+ GVariantBuilder *builder)
+{
+ GMenuExporterGroup *group;
+ guint count;
+
+ count = (gsize) g_hash_table_lookup (remote->watches, GINT_TO_POINTER (group_id));
+ g_hash_table_insert (remote->watches, GINT_TO_POINTER (group_id), GINT_TO_POINTER (count + 1));
+
+ group = g_menu_exporter_lookup_group (remote->exporter, group_id);
+ g_menu_exporter_group_subscribe (group, builder);
+}
+
+static void
+g_menu_exporter_remote_unsubscribe (GMenuExporterRemote *remote,
+ guint group_id)
+{
+ GMenuExporterGroup *group;
+ guint count;
+
+ count = (gsize) g_hash_table_lookup (remote->watches, GINT_TO_POINTER (group_id));
+
+ if (count == 0)
+ return;
+
+ if (count != 1)
+ g_hash_table_insert (remote->watches, GINT_TO_POINTER (group_id), GINT_TO_POINTER (count - 1));
+ else
+ g_hash_table_remove (remote->watches, GINT_TO_POINTER (group_id));
+
+ group = g_menu_exporter_lookup_group (remote->exporter, group_id);
+ g_menu_exporter_group_unsubscribe (group, 1);
+}
+
+static gboolean
+g_menu_exporter_remote_has_subscriptions (GMenuExporterRemote *remote)
+{
+ return g_hash_table_size (remote->watches) != 0;
+}
+
+static void
+g_menu_exporter_remote_free (gpointer data)
+{
+ GMenuExporterRemote *remote = data;
+ GHashTableIter iter;
+ gpointer key, val;
+
+ g_hash_table_iter_init (&iter, remote->watches);
+ while (g_hash_table_iter_next (&iter, &key, &val))
+ {
+ GMenuExporterGroup *group;
+
+ group = g_menu_exporter_lookup_group (remote->exporter, GPOINTER_TO_INT (key));
+ g_menu_exporter_group_unsubscribe (group, GPOINTER_TO_INT (val));
+ }
+
+ g_bus_unwatch_name (remote->watch_id);
+ g_hash_table_unref (remote->watches);
+
+ g_slice_free (GMenuExporterRemote, remote);
+}
+
+static GMenuExporterRemote *
+g_menu_exporter_remote_new (GMenuExporter *exporter,
+ guint watch_id)
+{
+ GMenuExporterRemote *remote;
+
+ remote = g_slice_new0 (GMenuExporterRemote);
+ remote->exporter = exporter;
+ remote->watches = g_hash_table_new (NULL, NULL);
+ remote->watch_id = watch_id;
+
+ return remote;
+}
+
+/* {{{1 GMenuExporter */
+
+struct _GMenuExporter
+{
+ GDBusConnection *connection;
+ gchar *object_path;
+ guint registration_id;
+ GHashTable *groups;
+ guint next_group_id;
+
+ GMenuExporterMenu *root;
+ GHashTable *remotes;
+};
+
+static void
+g_menu_exporter_name_vanished (GDBusConnection *connection,
+ const gchar *name,
+ gpointer user_data)
+{
+ GMenuExporter *exporter = user_data;
+
+ g_assert (exporter->connection == connection);
+
+ g_hash_table_remove (exporter->remotes, name);
+}
+
+static GVariant *
+g_menu_exporter_subscribe (GMenuExporter *exporter,
+ const gchar *sender,
+ GVariant *group_ids)
+{
+ GMenuExporterRemote *remote;
+ GVariantBuilder builder;
+ GVariantIter iter;
+ guint32 id;
+
+ remote = g_hash_table_lookup (exporter->remotes, sender);
+
+ if (remote == NULL)
+ {
+ guint watch_id;
+
+ watch_id = g_bus_watch_name_on_connection (exporter->connection, sender, G_BUS_NAME_WATCHER_FLAGS_NONE,
+ NULL, g_menu_exporter_name_vanished, exporter, NULL);
+ remote = g_menu_exporter_remote_new (exporter, watch_id);
+ g_hash_table_insert (exporter->remotes, g_strdup (sender), remote);
+ }
+
+ g_variant_builder_init (&builder, G_VARIANT_TYPE ("(a(uuaa{sv}))"));
+
+ g_variant_builder_open (&builder, G_VARIANT_TYPE ("a(uuaa{sv})"));
+
+ g_variant_iter_init (&iter, group_ids);
+ while (g_variant_iter_next (&iter, "u", &id))
+ g_menu_exporter_remote_subscribe (remote, id, &builder);
+
+ g_variant_builder_close (&builder);
+
+ return g_variant_builder_end (&builder);
+}
+
+static void
+g_menu_exporter_unsubscribe (GMenuExporter *exporter,
+ const gchar *sender,
+ GVariant *group_ids)
+{
+ GMenuExporterRemote *remote;
+ GVariantIter iter;
+ guint32 id;
+
+ remote = g_hash_table_lookup (exporter->remotes, sender);
+
+ if (remote == NULL)
+ return;
+
+ g_variant_iter_init (&iter, group_ids);
+ while (g_variant_iter_next (&iter, "u", &id))
+ g_menu_exporter_remote_unsubscribe (remote, id);
+
+ if (!g_menu_exporter_remote_has_subscriptions (remote))
+ g_hash_table_remove (exporter->remotes, sender);
+}
+
+static void
+g_menu_exporter_report (GMenuExporter *exporter,
+ GVariant *report)
+{
+}
+
+static void
+g_menu_exporter_remove_group (GMenuExporter *exporter,
+ guint id)
+{
+ g_hash_table_remove (exporter->groups, GINT_TO_POINTER (id));
+}
+
+static GMenuExporterGroup *
+g_menu_exporter_lookup_group (GMenuExporter *exporter,
+ guint group_id)
+{
+ GMenuExporterGroup *group;
+
+ group = g_hash_table_lookup (exporter->groups, GINT_TO_POINTER (group_id));
+
+ if (group == NULL)
+ {
+ group = g_menu_exporter_group_new (exporter, group_id);
+ g_hash_table_insert (exporter->groups, GINT_TO_POINTER (group_id), group);
+ }
+
+ return group;
+}
+
+static GMenuExporterGroup *
+g_menu_exporter_create_group (GMenuExporter *exporter)
+{
+ GMenuExporterGroup *group;
+ guint id;
+
+ id = exporter->next_group_id++;
+ group = g_menu_exporter_group_new (exporter, id);
+ g_hash_table_insert (exporter->groups, GINT_TO_POINTER (id), group);
+
+ return group;
+}
+
+static void
+g_menu_exporter_free (GMenuExporter *exporter)
+{
+ g_dbus_connection_unregister_object (exporter->connection, exporter->registration_id);
+ g_menu_exporter_menu_free (exporter->root);
+ g_hash_table_unref (exporter->remotes);
+ g_hash_table_unref (exporter->groups);
+ g_object_unref (exporter->connection);
+ g_free (exporter->object_path);
+
+ g_slice_free (GMenuExporter, exporter);
+}
+
+static void
+g_menu_exporter_method_call (GDBusConnection *connection,
+ const gchar *sender,
+ const gchar *object_path,
+ const gchar *interface_name,
+ const gchar *method_name,
+ GVariant *parameters,
+ GDBusMethodInvocation *invocation,
+ gpointer user_data)
+{
+ GMenuExporter *exporter = user_data;
+ GVariant *group_ids;
+
+ group_ids = g_variant_get_child_value (parameters, 0);
+
+ if (g_str_equal (method_name, "Start"))
+ g_dbus_method_invocation_return_value (invocation, g_menu_exporter_subscribe (exporter, sender, group_ids));
+
+ else if (g_str_equal (method_name, "End"))
+ {
+ g_menu_exporter_unsubscribe (exporter, sender, group_ids);
+ g_dbus_method_invocation_return_value (invocation, NULL);
+ }
+
+ else
+ g_assert_not_reached ();
+
+ g_variant_unref (group_ids);
+}
+
+static GDBusConnection *
+g_menu_exporter_get_connection (GMenuExporter *exporter)
+{
+ return exporter->connection;
+}
+
+static const gchar *
+g_menu_exporter_get_object_path (GMenuExporter *exporter)
+{
+ return exporter->object_path;
+}
+
+static GMenuExporter *
+g_menu_exporter_new (GDBusConnection *connection,
+ const gchar *object_path,
+ GMenuModel *model,
+ GError **error)
+{
+ const GDBusInterfaceVTable vtable = {
+ g_menu_exporter_method_call,
+ };
+ GMenuExporter *exporter;
+ guint id;
+
+ exporter = g_slice_new0 (GMenuExporter);
+
+ id = g_dbus_connection_register_object (connection, object_path, org_gtk_Menus_get_interface (),
+ &vtable, exporter, NULL, error);
+
+ if (id == 0)
+ {
+ g_slice_free (GMenuExporter, exporter);
+ return NULL;
+ }
+
+ exporter->connection = g_object_ref (connection);
+ exporter->object_path = g_strdup (object_path);
+ exporter->registration_id = id;
+ exporter->groups = g_hash_table_new (NULL, NULL);
+ exporter->remotes = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_menu_exporter_remote_free);
+ exporter->root = g_menu_exporter_group_add_menu (g_menu_exporter_create_group (exporter), model);
+
+ return exporter;
+}
+
+/* {{{1 Public API */
+
+static GHashTable *g_menu_exporter_exported_menus;
+
+gboolean
+g_menu_exporter_export (GDBusConnection *connection,
+ const gchar *object_path,
+ GMenuModel *menu,
+ GError **error)
+{
+ GMenuExporter *exporter;
+
+ if G_UNLIKELY (g_menu_exporter_exported_menus == NULL)
+ g_menu_exporter_exported_menus = g_hash_table_new (NULL, NULL);
+
+ if G_UNLIKELY (g_hash_table_lookup (g_menu_exporter_exported_menus, menu))
+ {
+ g_set_error (error, G_DBUS_ERROR, G_DBUS_ERROR_FILE_EXISTS, "The given GMenuModel has already been exported");
+ return FALSE;
+ }
+
+ exporter = g_menu_exporter_new (connection, object_path, menu, error);
+
+ if (exporter == NULL)
+ return FALSE;
+
+ g_hash_table_insert (g_menu_exporter_exported_menus, menu, exporter);
+
+ return TRUE;
+}
+
+gboolean
+g_menu_exporter_stop (GMenuModel *menu)
+{
+ GMenuExporter *exporter;
+
+ if G_UNLIKELY (g_menu_exporter_exported_menus == NULL)
+ return FALSE;
+
+ exporter = g_hash_table_lookup (g_menu_exporter_exported_menus, menu);
+ if G_UNLIKELY (exporter == NULL)
+ return FALSE;
+
+ g_hash_table_remove (g_menu_exporter_exported_menus, menu);
+ g_menu_exporter_free (exporter);
+
+ return TRUE;
+}
+
+gboolean
+g_menu_exporter_query (GMenuModel *menu,
+ GDBusConnection **connection,
+ const gchar **object_path)
+{
+ GMenuExporter *exporter;
+
+ if (g_menu_exporter_exported_menus == NULL)
+ return FALSE;
+
+ exporter = g_hash_table_lookup (g_menu_exporter_exported_menus, menu);
+ if (exporter == NULL)
+ return FALSE;
+
+ if (connection)
+ *connection = g_menu_exporter_get_connection (exporter);
+
+ if (object_path)
+ *object_path = g_menu_exporter_get_object_path (exporter);
+
+ return TRUE;
+}
+
+/* {{{1 Epilogue */
+/* vim:set foldmethod=marker: */
diff --git a/gio/gmenuexporter.h b/gio/gmenuexporter.h
new file mode 100644
index 0000000..260406f
--- /dev/null
+++ b/gio/gmenuexporter.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright  2011 Canonical Ltd.
+ * All rights reserved.
+ *
+ * Author: Ryan Lortie <desrt desrt ca>
+ */
+
+#ifndef __G_MENU_EXPORTER_H__
+#define __G_MENU_EXPORTER_H__
+
+#include <gio/gdbusconnection.h>
+#include <gio/gmenumodel.h>
+
+gboolean g_menu_exporter_export (GDBusConnection *connection,
+ const gchar *object_path,
+ GMenuModel *menu,
+ GError **error);
+
+gboolean g_menu_exporter_stop (GMenuModel *menu);
+
+
+
+gboolean g_menu_exporter_query (GMenuModel *menu,
+ GDBusConnection **connection,
+ const gchar **object_path);
+
+
+#endif /* __G_MENU_EXPORTER_H__ */
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]