[gtk+/origin/wip/csoriano/cloud-providers: 1/2] f



commit 19f74cb5677f29a87d26346535833382c0c48877
Author: Carlos Soriano <csoriano gnome org>
Date:   Sun Jul 5 19:54:35 2015 +0200

    f

 gtk/gtkcloudprovider.c          |  201 ++++++++++++++++++++++++++++++----
 gtk/gtkcloudprovider.h          |    5 +-
 gtk/gtkcloudprovidermanager.c   |   10 ++
 tests/testcloudproviderclient.c |   67 +++++++++--
 tests/testcloudproviderserver.c |  231 +++++++++++++++++++++++++++++++++++++--
 5 files changed, 466 insertions(+), 48 deletions(-)
---
diff --git a/gtk/gtkcloudprovider.c b/gtk/gtkcloudprovider.c
index 9e29d9e..ebc22de 100644
--- a/gtk/gtkcloudprovider.c
+++ b/gtk/gtkcloudprovider.c
@@ -29,6 +29,12 @@ static const gchar provider_xml[] =
   "    <method name='GetStatus'>"
   "      <arg type='i' name='name' direction='out'/>"
   "    </method>"
+  "    <method name='GetIcon'>"
+  "      <arg type='v' name='icon' direction='out'/>"
+  "    </method>"
+  "    <method name='GetPath'>"
+  "      <arg type='s' name='path' direction='out'/>"
+  "    </method>"
   "  </interface>"
   "</node>";
 
@@ -38,11 +44,14 @@ typedef struct
   gchar *name;
   GtkCloudProviderStatus status;
   GIcon *icon;
-  GMenuModel *menu;
+  GMenuModel *menu_model;
+  GActionGroup *action_group;
 
+  GDBusConnection *bus;
   GDBusProxy *proxy;
   gchar *bus_name;
   gchar *object_path;
+  GCancellable *cancellable;
 } GtkCloudProviderPrivate;
 
 G_DEFINE_TYPE_WITH_PRIVATE (GtkCloudProvider, gtk_cloud_provider, G_TYPE_OBJECT)
@@ -54,6 +63,42 @@ enum {
 
 static guint gSignals [LAST_SIGNAL];
 
+static void connect_to_items_changed (GMenuModel *model,
+                                      GCallback   callback,
+                                      gpointer    data);
+static void
+on_get_icon (GObject      *source_object,
+             GAsyncResult *res,
+             gpointer      user_data)
+{
+  GtkCloudProvider *self = GTK_CLOUD_PROVIDER (user_data);
+  GtkCloudProviderPrivate *priv = gtk_cloud_provider_get_instance_private (self);
+  GError *error = NULL;
+  GVariant *variant_tuple;
+  GVariant *variant_dict;
+  GVariant *variant;
+
+  g_clear_object (&priv->icon);
+
+  variant_tuple = g_dbus_proxy_call_finish (priv->proxy, res, &error);
+  g_print ("variant tuple %s\n", g_variant_print (variant_tuple, TRUE));
+  if (error != NULL)
+    {
+      g_warning ("Error getting the provider icon %s", error->message);
+      goto out;
+    }
+
+  variant_dict = g_variant_get_child_value (variant_tuple, 0);
+  variant = g_variant_get_child_value (variant_dict, 0);
+  priv->icon = g_icon_deserialize (variant);
+  g_variant_unref (variant);
+  g_variant_unref (variant_dict);
+
+out:
+  g_variant_unref (variant_tuple);
+  g_signal_emit_by_name (self, "changed");
+}
+
 static void
 on_get_name (GObject      *source_object,
              GAsyncResult *res,
@@ -65,6 +110,9 @@ on_get_name (GObject      *source_object,
   GVariant *variant_tuple;
   GVariant *variant;
 
+  if (priv->name != NULL)
+    g_free (priv->name);
+
   variant_tuple = g_dbus_proxy_call_finish (priv->proxy, res, &error);
   if (error != NULL)
     {
@@ -108,6 +156,48 @@ out:
   g_signal_emit_by_name (self, "changed");
 }
 
+static void
+on_items_changed (GMenuModel *model,
+                  gint        position,
+                  gint        removed,
+                  gint        added,
+                  gpointer    user_data)
+{
+  GtkCloudProvider *self = GTK_CLOUD_PROVIDER (user_data);
+  GtkCloudProviderPrivate *priv = gtk_cloud_provider_get_instance_private (self);
+
+  g_print ("items changed\n");
+  connect_to_items_changed (model, G_CALLBACK (on_items_changed), self);
+  g_signal_emit_by_name (self, "changed");
+}
+
+static void
+connect_to_items_changed (GMenuModel *model,
+                          GCallback   callback,
+                          gpointer    data)
+{
+  gint i;
+  GMenuModel *m;
+  GMenuLinkIter *iter;
+
+  if (!g_object_get_data (G_OBJECT (model), "handler-connected"))
+    {
+      g_signal_connect (model, "items-changed", callback, data);
+      g_object_set_data (G_OBJECT (model), "handler-connected", GINT_TO_POINTER (1));
+    }
+  for (i = 0; i < g_menu_model_get_n_items (model); i++)
+    {
+      iter = g_menu_model_iterate_item_links (model, i);
+      while (g_menu_link_iter_next (iter))
+        {
+          m = g_menu_link_iter_get_value (iter);
+          connect_to_items_changed (m, callback, data);
+          g_object_unref (m);
+        }
+      g_object_unref (iter);
+    }
+}
+
 void
 gtk_cloud_provider_update (GtkCloudProvider *self)
 {
@@ -132,6 +222,28 @@ gtk_cloud_provider_update (GtkCloudProvider *self)
                          NULL,
                          (GAsyncReadyCallback) on_get_status,
                          self);
+
+      g_dbus_proxy_call (priv->proxy,
+                         "GetIcon",
+                         g_variant_new ("()"),
+                         G_DBUS_CALL_FLAGS_NONE,
+                         -1,
+                         NULL,
+                         (GAsyncReadyCallback) on_get_icon,
+                         self);
+
+      priv->menu_model = (GMenuModel*) g_dbus_menu_model_get (priv->bus,
+                                                              priv->bus_name,
+                                                              priv->object_path);
+      connect_to_items_changed (priv->menu_model,
+                                G_CALLBACK (on_items_changed),
+                                self);
+
+      g_print ("n items %d\n", g_menu_model_get_n_items (priv->menu_model));
+      priv->action_group = (GActionGroup*) g_dbus_action_group_get (priv->bus,
+                                                                    priv->bus_name,
+                                                                    priv->object_path);
+
     }
 }
 
@@ -141,45 +253,81 @@ on_proxy_created (GObject      *source_object,
                   gpointer      user_data)
 {
   GError *error = NULL;
-  GtkCloudProvider *self = GTK_CLOUD_PROVIDER (user_data);
-  GtkCloudProviderPrivate *priv = gtk_cloud_provider_get_instance_private (self);
+  GtkCloudProvider *self;
+  GtkCloudProviderPrivate *priv;
+  GDBusProxy *proxy;
 
-  priv->proxy = g_dbus_proxy_new_for_bus_finish (res, &error);
+  proxy = g_dbus_proxy_new_for_bus_finish (res, &error);
   if (error != NULL)
     {
-      g_warning ("Error creating proxy for cloud provider %s", error->message);
+      if (error->code != G_IO_ERROR_CANCELLED)
+        g_warning ("Error creating proxy for cloud provider %s", error->message);
       return;
     }
+  self = GTK_CLOUD_PROVIDER (user_data);
+  priv = gtk_cloud_provider_get_instance_private (self);
+
+  priv->proxy = proxy;
 
   gtk_cloud_provider_update (self);
 }
 
+static void
+on_bus_acquired (GObject      *source_object,
+                 GAsyncResult *res,
+                 gpointer      user_data)
+{
+  GError *error = NULL;
+  GtkCloudProvider *self;
+  GDBusConnection *bus;
+  GtkCloudProviderPrivate *priv;
+  GDBusInterfaceInfo *interface_info;
+  GDBusNodeInfo *proxy_info;
+
+  bus = g_bus_get_finish (res, &error);
+  if (error != NULL)
+    {
+      if (error->code != G_IO_ERROR_CANCELLED)
+        g_warning ("Error acdquiring bus for cloud provider %s", error->message);
+      return;
+    }
+
+  self = GTK_CLOUD_PROVIDER (user_data);
+  priv = gtk_cloud_provider_get_instance_private (user_data);
+  priv->bus = bus;
+  proxy_info = g_dbus_node_info_new_for_xml (provider_xml, &error);
+  interface_info = g_dbus_node_info_lookup_interface (proxy_info, "org.gtk.CloudProvider");
+  g_clear_object (&priv->cancellable);
+  priv->cancellable = g_cancellable_new ();
+  g_dbus_proxy_new (priv->bus,
+                    G_DBUS_PROXY_FLAGS_NONE,
+                    interface_info,
+                    priv->bus_name,
+                    priv->object_path,
+                    "org.gtk.CloudProvider",
+                    priv->cancellable,
+                    on_proxy_created,
+                    self);
+}
+
 GtkCloudProvider*
 gtk_cloud_provider_new (const gchar *bus_name,
                         const gchar *object_path)
 {
   GtkCloudProvider *self;
   GtkCloudProviderPrivate *priv;
-  GDBusNodeInfo *proxy_info;
-  GDBusInterfaceInfo *interface_info;
-  GError *error = NULL;
 
   self = g_object_new (GTK_TYPE_CLOUD_PROVIDER, NULL);
   priv = gtk_cloud_provider_get_instance_private (self);
 
-  proxy_info = g_dbus_node_info_new_for_xml (provider_xml, &error);
-  interface_info = g_dbus_node_info_lookup_interface (proxy_info, "org.gtk.CloudProvider");
   priv->bus_name = g_strdup (bus_name);
   priv->object_path = g_strdup (object_path);
-  g_dbus_proxy_new_for_bus (G_BUS_TYPE_SESSION,
-                            G_DBUS_PROXY_FLAGS_NONE,
-                            interface_info,
-                            bus_name,
-                            object_path,
-                            "org.gtk.CloudProvider",
-                            NULL,
-                            on_proxy_created,
-                            self);
+  priv->cancellable = g_cancellable_new ();
+  priv->status = GTK_CLOUD_PROVIDER_STATUS_INVALID;
+  g_bus_get (G_BUS_TYPE_SESSION,
+             priv->cancellable,
+             on_bus_acquired,
+             self);
 
   return self;
 }
@@ -190,9 +338,13 @@ gtk_cloud_provider_finalize (GObject *object)
   GtkCloudProvider *self = (GtkCloudProvider *)object;
   GtkCloudProviderPrivate *priv = gtk_cloud_provider_get_instance_private (self);
 
+  g_cancellable_cancel (priv->cancellable);
+  g_clear_object (&priv->cancellable);
   g_free (priv->name);
   g_clear_object (&priv->icon);
-  g_clear_object (&priv->menu);
+  g_clear_object (&priv->menu_model);
+  g_clear_object (&priv->action_group);
+  g_clear_object (&priv->bus);
   g_clear_object (&priv->proxy);
   g_free (priv->bus_name);
   g_free (priv->object_path);
@@ -222,9 +374,12 @@ gtk_cloud_provider_class_init (GtkCloudProviderClass *klass)
 static void
 gtk_cloud_provider_init (GtkCloudProvider *self)
 {
+  GtkCloudProviderPrivate *priv = gtk_cloud_provider_get_instance_private (self);
+
+  priv->status = GTK_CLOUD_PROVIDER_STATUS_INVALID;
 }
 
-const gchar*
+gchar*
 gtk_cloud_provider_get_name (GtkCloudProvider *self)
 {
   GtkCloudProviderPrivate *priv = gtk_cloud_provider_get_instance_private (self);
@@ -249,10 +404,10 @@ gtk_cloud_provider_get_icon (GtkCloudProvider *self)
 }
 
 GMenuModel*
-gtk_cloud_provider_get_menu (GtkCloudProvider *self)
+gtk_cloud_provider_get_menu_model (GtkCloudProvider *self)
 {
   GtkCloudProviderPrivate *priv = gtk_cloud_provider_get_instance_private (self);
 
-  return priv->menu;
+  return priv->menu_model;
 }
 
diff --git a/gtk/gtkcloudprovider.h b/gtk/gtkcloudprovider.h
index 198a321..0e02c01 100644
--- a/gtk/gtkcloudprovider.h
+++ b/gtk/gtkcloudprovider.h
@@ -29,6 +29,7 @@
 G_BEGIN_DECLS
 
 typedef enum {
+  GTK_CLOUD_PROVIDER_STATUS_INVALID,
   GTK_CLOUD_PROVIDER_STATUS_IDLE,
   GTK_CLOUD_PROVIDER_STATUS_SYNCING,
   GTK_CLOUD_PROVIDER_STATUS_ERROR
@@ -61,13 +62,13 @@ GDK_AVAILABLE_IN_3_18
 GtkCloudProvider *gtk_cloud_provider_new (const gchar *bus_name,
                                           const gchar *object_path);
 GDK_AVAILABLE_IN_3_18
-const gchar* gtk_cloud_provider_get_name (GtkCloudProvider *self);
+gchar* gtk_cloud_provider_get_name (GtkCloudProvider *self);
 GDK_AVAILABLE_IN_3_18
 GtkCloudProviderStatus gtk_cloud_provider_get_status (GtkCloudProvider *self);
 GDK_AVAILABLE_IN_3_18
 GIcon *gtk_cloud_provider_get_icon (GtkCloudProvider *self);
 GDK_AVAILABLE_IN_3_18
-GMenuModel *gtk_cloud_provider_get_menu (GtkCloudProvider *self);
+GMenuModel *gtk_cloud_provider_get_menu_model (GtkCloudProvider *self);
 
 G_END_DECLS
 
diff --git a/gtk/gtkcloudprovidermanager.c b/gtk/gtkcloudprovidermanager.c
index 09d81d6..9a161b6 100644
--- a/gtk/gtkcloudprovidermanager.c
+++ b/gtk/gtkcloudprovidermanager.c
@@ -199,6 +199,16 @@ static void
 on_cloud_provider_changed (GtkCloudProvider        *cloud_provider,
                            GtkCloudProviderManager *self)
 {
+  GIcon *icon;
+  gchar *name;
+  guint status;
+
+  name = gtk_cloud_provider_get_name (cloud_provider);
+  icon = gtk_cloud_provider_get_icon (cloud_provider);
+  status = gtk_cloud_provider_get_status (cloud_provider);
+  if (name == NULL || icon == NULL || status == GTK_CLOUD_PROVIDER_STATUS_INVALID)
+    return;
+
   g_signal_emit_by_name (self, "changed", NULL);
 }
 
diff --git a/tests/testcloudproviderclient.c b/tests/testcloudproviderclient.c
index 0cabf6c..8b9882c 100644
--- a/tests/testcloudproviderclient.c
+++ b/tests/testcloudproviderclient.c
@@ -2,11 +2,40 @@
 #include <glib.h>
 #include <gtk/gtk.h>
 
-enum {
-  IDLE,
-  SYNCING,
-  ERROR
-};
+static void
+print_gmenu_model (GMenuModel  *model)
+{
+  gint i, n_items;
+  GMenuModel *submodel = NULL;
+  gchar *label;
+
+  n_items = g_menu_model_get_n_items (model);
+  g_print ("n items %d\n", n_items);
+
+  for (i = 0; i < n_items; i++)
+    {
+      label = NULL;
+      if (g_menu_model_get_item_attribute (model, i, G_MENU_ATTRIBUTE_LABEL, "s", &label))
+        {
+          g_print ("Menu item - %s\n", label);
+          if (label != NULL)
+            g_free (label);
+        }
+
+      submodel = g_menu_model_get_item_link (model, i, G_MENU_LINK_SECTION);
+      if (!submodel)
+       submodel = g_menu_model_get_item_link (model, i, G_MENU_LINK_SUBMENU);
+
+      if (!submodel)
+        {
+          g_print ("no submodel\n");
+          continue;
+        }
+
+      print_gmenu_model (submodel);
+      g_clear_object (&submodel);
+  }
+}
 
 static void
 on_manager_changed (GtkCloudProviderManager *manager)
@@ -15,6 +44,9 @@ on_manager_changed (GtkCloudProviderManager *manager)
   GList *l;
   gint provider_status;
   gchar *status_string;
+  GIcon *icon;
+  gchar *icon_representation;
+  GMenuModel *menu_model;
 
   providers = gtk_cloud_provider_manager_get_providers (manager);
   g_print ("Providers data\n");
@@ -24,15 +56,19 @@ on_manager_changed (GtkCloudProviderManager *manager)
       provider_status = gtk_cloud_provider_get_status (GTK_CLOUD_PROVIDER (l->data));
       switch (provider_status)
         {
-        case IDLE:
+        case GTK_CLOUD_PROVIDER_STATUS_INVALID:
+          status_string = "invalid";
+          break;
+
+        case GTK_CLOUD_PROVIDER_STATUS_IDLE:
           status_string = "idle";
           break;
 
-        case SYNCING:
+        case GTK_CLOUD_PROVIDER_STATUS_SYNCING:
           status_string = "syncing";
           break;
 
-        case ERROR:
+        case GTK_CLOUD_PROVIDER_STATUS_ERROR:
           status_string = "error";
           break;
 
@@ -40,9 +76,18 @@ on_manager_changed (GtkCloudProviderManager *manager)
           g_assert_not_reached ();
         }
 
-      g_print ("Name - %s Status - %s\n",
+      icon = gtk_cloud_provider_get_icon (l->data);
+      icon_representation = g_icon_to_string (icon);
+
+      g_print ("Name - %s Status - %s Icon - %s\n",
                gtk_cloud_provider_get_name (GTK_CLOUD_PROVIDER (l->data)),
-               status_string);
+               status_string,
+               icon_representation);
+
+      g_free (icon_representation);
+
+      menu_model = gtk_cloud_provider_get_menu_model (l->data);
+      print_gmenu_model (menu_model);
     }
   g_print ("\n");
 }
@@ -59,9 +104,7 @@ main (gint   argc,
   //gtk_cloud_provider_manager_update (manager);
 
   loop = g_main_loop_new (NULL, FALSE);
-  g_print ("before loop\n");
   g_main_loop_run (loop);
-  g_print ("after\n");
 
   return 0;
 }
diff --git a/tests/testcloudproviderserver.c b/tests/testcloudproviderserver.c
index 3b61e1e..926f9af 100644
--- a/tests/testcloudproviderserver.c
+++ b/tests/testcloudproviderserver.c
@@ -1,13 +1,8 @@
 #include <gio/gio.h>
 #include <stdlib.h>
+#include <gtk/gtk.h>
 
-#define TIMEOUT 1000
-
-enum {
-  IDLE,
-  SYNCING,
-  ERROR
-};
+#define TIMEOUT 2000
 
 typedef struct _CloudProviderClass CloudProviderClass;
 typedef struct _CloudProvider CloudProvider;
@@ -23,6 +18,7 @@ struct _CloudProvider
 
   gchar *name;
   gint status;
+  GIcon *icon;
   GDBusProxy *manager_proxy;
   guint timeout_handler;
 };
@@ -37,6 +33,8 @@ cloud_provider_finalize (GObject *object)
   CloudProvider *self = (CloudProvider*)object;
 
   g_free (self->name);
+  g_clear_object (&self->icon);
+  g_clear_object (&self->manager_proxy);
 
   G_OBJECT_CLASS (cloud_provider_parent_class)->finalize (object);
 }
@@ -44,8 +42,17 @@ cloud_provider_finalize (GObject *object)
 static void
 cloud_provider_init (CloudProvider *self)
 {
+  GFile *icon_file;
+  gchar *uri;
+
   self->name = "MyCloud";
-  self->status = SYNCING;
+  self->status = GTK_CLOUD_PROVIDER_STATUS_INVALID;
+  uri = g_build_filename (g_get_current_dir (), "apple-red.png", NULL);
+  icon_file = g_file_new_for_uri (uri);
+  self->icon = g_file_icon_new (icon_file);
+
+  g_object_unref (icon_file);
+  g_free (uri);
 }
 
 static void
@@ -60,7 +67,7 @@ static void
 cloud_provider_set_status (CloudProvider *self,
                            gint           status)
 {
-  /* Inform manager that the provider changed */
+  /* Inform the manager that the provider changed */
   self->status = status;
   g_dbus_proxy_call (self->manager_proxy,
                      "CloudProviderChanged",
@@ -86,6 +93,9 @@ static const gchar provider_xml[] =
   "    <method name='GetStatus'>"
   "      <arg type='i' name='status' direction='out'/>"
   "    </method>"
+  "    <method name='GetIcon'>"
+  "      <arg type='v' name='icon' direction='out'/>"
+  "    </method>"
   "  </interface>"
   "</node>";
 
@@ -97,6 +107,196 @@ static const gchar manager_xml[] =
   "  </interface>"
   "</node>";
 
+static const gchar menu_markup[] =
+  "<interface>\n"
+  "<menu id='menu'>\n"
+  "  <section>\n"
+  "    <item>\n"
+  "      <attribute name='label' translatable='yes'>MyCloud website</attribute>\n"
+  "      <attribute name='action'>website</attribute>\n"
+  "    </item>\n"
+  "    <item>\n"
+  "      <attribute name='label' translatable='yes'>MyCloud Photos</attribute>\n"
+  "      <attribute name='action'>photos</attribute>\n"
+  "    </item>\n"
+  "    <item>\n"
+  "      <attribute name='label' translatable='yes'>MyCloud Notes</attribute>\n"
+  "      <attribute name='action'>notes</attribute>\n"
+  "    </item>\n"
+  "  </section>\n"
+  "  <section>\n"
+  "    <item>\n"
+  "      <attribute name='label' translatable='yes'>Allow Synchronization</attribute>\n"
+  "      <attribute name='action'>allow-sync</attribute>\n"
+  "    </item>\n"
+  "    <submenu>\n"
+  "      <attribute name='label' translatable='yes'>Buy Storage</attribute>\n"
+  "      <item>\n"
+  "        <attribute name='label' translatable='yes'>5GB for 200CZK</attribute>\n"
+  "        <attribute name='action'>buy</attribute>\n"
+  "        <attribute name='target'>5</attribute>\n"
+  "      </item>\n"
+  "      <item>\n"
+  "        <attribute name='label' translatable='yes'>10GB for 500CZK</attribute>\n"
+  "        <attribute name='action'>buy</attribute>\n"
+  "        <attribute name='target'>10</attribute>\n"
+  "      </item>\n"
+  "      <item>\n"
+  "        <attribute name='label' translatable='yes'>30GB for 600CZK</attribute>\n"
+  "        <attribute name='action'>buy</attribute>\n"
+  "        <attribute name='target'>30</attribute>\n"
+  "      </item>\n"
+  "    </submenu>\n"
+  "  </section>\n"
+  "</menu>\n"
+  "</interface>\n";
+
+static void
+activate_action (GSimpleAction *action,
+                 GVariant      *parameter,
+                 gpointer       user_data)
+{
+  g_print ("Action %s activated\n", g_action_get_name (G_ACTION (action)));
+}
+
+static void
+activate_toggle (GSimpleAction *action,
+                 GVariant      *parameter,
+                 gpointer       user_data)
+{
+  GVariant *old_state, *new_state;
+
+  old_state = g_action_get_state (G_ACTION (action));
+  new_state = g_variant_new_boolean (!g_variant_get_boolean (old_state));
+
+  g_print ("Toggle action %s activated, state changes from %d to %d\n",
+           g_action_get_name (G_ACTION (action)),
+           g_variant_get_boolean (old_state),
+           g_variant_get_boolean (new_state));
+
+  g_simple_action_set_state (action, new_state);
+  g_variant_unref (old_state);
+}
+
+static void
+activate_radio (GSimpleAction *action,
+                GVariant      *parameter,
+                gpointer       user_data)
+{
+  GVariant *old_state, *new_state;
+
+  old_state = g_action_get_state (G_ACTION (action));
+  new_state = g_variant_new_string (g_variant_get_string (parameter, NULL));
+
+  g_print ("Radio action %s activated, state changes from %s to %s\n",
+           g_action_get_name (G_ACTION (action)),
+           g_variant_get_string (old_state, NULL),
+           g_variant_get_string (new_state, NULL));
+
+  g_simple_action_set_state (action, new_state);
+  g_variant_unref (old_state);
+}
+
+static GActionEntry actions[] = {
+  { "website",  activate_action, NULL, NULL, NULL },
+  { "photos",  activate_action, NULL, NULL, NULL },
+  { "notes",   activate_action, NULL, NULL, NULL },
+  { "allow-sync",  activate_toggle, NULL, "true", NULL },
+  { "buy",  activate_radio,  "s",  NULL, NULL },
+};
+
+static void
+print_gmenu_model (GMenuModel  *model)
+{
+  gint i, n_items;
+  GMenuModel *submodel = NULL;
+  gchar *label;
+
+  n_items = g_menu_model_get_n_items (model);
+  g_print ("n items %d\n", n_items);
+
+  for (i = 0; i < n_items; i++)
+    {
+      label = NULL;
+      if (g_menu_model_get_item_attribute (model, i, G_MENU_ATTRIBUTE_LABEL, "s", &label))
+        {
+          g_print ("Menu item - %s\n", label);
+          if (label != NULL)
+            g_free (label);
+        }
+
+      submodel = g_menu_model_get_item_link (model, i, G_MENU_LINK_SECTION);
+      if (!submodel)
+       submodel = g_menu_model_get_item_link (model, i, G_MENU_LINK_SUBMENU);
+
+      if (!submodel)
+        {
+          g_print ("no submodel\n");
+          continue;
+        }
+
+      print_gmenu_model (submodel);
+      g_clear_object (&submodel);
+  }
+}
+
+static GMenuModel *
+get_model (void)
+{
+  GError *error = NULL;
+  GtkBuilder *builder;
+  GMenuModel *menu;
+
+  builder = gtk_builder_new ();
+  gtk_builder_add_from_string (builder, menu_markup, -1, &error);
+  g_assert_no_error (error);
+
+  menu = g_object_ref (gtk_builder_get_object (builder, "menu"));
+  g_object_unref (builder);
+
+  return menu;
+}
+
+static GActionGroup *
+get_action_group (void)
+{
+  GSimpleActionGroup *group;
+
+  group = g_simple_action_group_new ();
+
+  g_action_map_add_action_entries (G_ACTION_MAP (group),
+                                   actions,
+                                   G_N_ELEMENTS (actions), NULL);
+
+  return G_ACTION_GROUP (group);
+}
+
+static void
+export_menu (GDBusConnection *bus,
+             gchar *object_path)
+{
+  GMenuModel *model;
+  GActionGroup *action_group;
+  GError *error;
+
+  model = get_model ();
+  action_group = get_action_group ();
+  print_gmenu_model (model);
+
+  g_print ("Exporting menus on the bus...\n");
+  if (!g_dbus_connection_export_menu_model (bus, object_path, model, &error))
+    {
+      g_warning ("Menu export failed: %s", error->message);
+      exit (1);
+    }
+  g_print ("Exporting actions on the bus...\n");
+  if (!g_dbus_connection_export_action_group (bus, object_path, action_group, &error))
+    {
+      g_warning ("Action export failed: %s", error->message);
+      exit (1);
+    }
+}
+
 static void
 handle_method_call (GDBusConnection       *connection,
                     const gchar           *sender,
@@ -120,6 +320,11 @@ handle_method_call (GDBusConnection       *connection,
       g_dbus_method_invocation_return_value (invocation,
                                              g_variant_new ("(i)", cloud_provider->status));
     }
+  else if (g_strcmp0 (method_name, "GetIcon") == 0)
+    {
+      g_dbus_method_invocation_return_value (invocation,
+                                             g_variant_new ("(v)", g_icon_serialize (cloud_provider->icon)));
+    }
 }
 
 static const GDBusInterfaceVTable interface_vtable =
@@ -135,7 +340,7 @@ on_bus_acquired (GDBusConnection *connection,
   CloudProvider *cloud_provider = user_data;
   guint registration_id;
 
-  g_print ("Registering cloud provider server 'MyCloud'\n");
+  g_debug ("Registering cloud provider server 'MyCloud'\n");
   registration_id = g_dbus_connection_register_object (connection,
                                                        "/org/gtk/CloudProviderServerExample",
                                                        introspection_data->interfaces[0],
@@ -144,6 +349,8 @@ on_bus_acquired (GDBusConnection *connection,
                                                        NULL,  /* user_data_free_func */
                                                        NULL); /* GError** */
   g_assert (registration_id > 0);
+  /* Export a menu for our own application */
+  export_menu (connection, "/org/gtk/CloudProviderServerExample");
 }
 
 static void
@@ -169,7 +376,9 @@ change_provider (gpointer user_data)
   gint new_status;
 
   rand = g_rand_new ();
-  new_status = g_rand_int_range (rand, IDLE, ERROR + 1);
+  new_status = g_rand_int_range (rand,
+                                 GTK_CLOUD_PROVIDER_STATUS_IDLE,
+                                 GTK_CLOUD_PROVIDER_STATUS_ERROR + 1);
 
   cloud_provider_set_status (cloud_provider, new_status);
 


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