[gnome-panel] status-notifier: add items to panel



commit 9d265f9d69d2b4bfc8bd9bbab9d491515212a7d1
Author: Alberts Muktupāvels <alberts muktupavels gmail com>
Date:   Thu Nov 3 02:30:09 2016 +0200

    status-notifier: add items to panel

 applets/status-notifier/sn-applet.c  |   40 +++++++++-
 applets/status-notifier/sn-host-v0.c |  103 ++++++++++++++++++++------
 applets/status-notifier/sn-host.c    |   33 ++++++++
 applets/status-notifier/sn-host.h    |    8 ++-
 applets/status-notifier/sn-item-v0.c |   85 +++++++++++++++++++++-
 applets/status-notifier/sn-item-v0.h |    3 +
 applets/status-notifier/sn-item.c    |  136 +++++++++++++++++++++++++++++++++-
 applets/status-notifier/sn-item.h    |    3 +
 8 files changed, 382 insertions(+), 29 deletions(-)
---
diff --git a/applets/status-notifier/sn-applet.c b/applets/status-notifier/sn-applet.c
index f6bfa60..65bd141 100644
--- a/applets/status-notifier/sn-applet.c
+++ b/applets/status-notifier/sn-applet.c
@@ -19,27 +19,53 @@
 
 #include "sn-applet.h"
 #include "sn-host-v0.h"
+#include "sn-item.h"
 
 struct _SnApplet
 {
   GpApplet   parent;
 
-  SnHost    *host_v0;
-
   GtkWidget *box;
+
+  GSList    *hosts;
+  GSList    *items;
 };
 
 G_DEFINE_TYPE (SnApplet, sn_applet, GP_TYPE_APPLET)
 
 static void
+item_added_cb (SnHost   *host,
+               SnItem   *item,
+               SnApplet *sn)
+{
+  sn->items = g_slist_prepend (sn->items, item);
+  gtk_box_pack_start (GTK_BOX (sn->box), GTK_WIDGET (item), FALSE, FALSE, 0);
+  gtk_widget_show (GTK_WIDGET (item));
+}
+
+static void
+item_removed_cb (SnHost   *host,
+                 SnItem   *item,
+                 SnApplet *sn)
+{
+  gtk_container_remove (GTK_CONTAINER (sn->box), GTK_WIDGET (item));
+  sn->items = g_slist_remove (sn->items, item);
+}
+
+static void
 sn_applet_constructed (GObject *object)
 {
   SnApplet *sn;
+  SnHost *host;
 
   G_OBJECT_CLASS (sn_applet_parent_class)->constructed (object);
   sn = SN_APPLET (object);
 
-  sn->host_v0 = sn_host_v0_new ();
+  host = sn_host_v0_new ();
+  sn->hosts = g_slist_prepend (sn->hosts, host);
+
+  g_signal_connect (host, "item-added", G_CALLBACK (item_added_cb), sn);
+  g_signal_connect (host, "item-removed", G_CALLBACK (item_removed_cb), sn);
 
   gtk_widget_show (GTK_WIDGET (object));
 }
@@ -51,7 +77,13 @@ sn_applet_dispose (GObject *object)
 
   sn = SN_APPLET (object);
 
-  g_clear_object (&sn->host_v0);
+  if (sn->hosts != NULL)
+    {
+      g_slist_free_full (sn->hosts, g_object_unref);
+      sn->hosts = NULL;
+    }
+
+  g_clear_pointer (&sn->items, g_slist_free);
 
   G_OBJECT_CLASS (sn_applet_parent_class)->dispose (object);
 }
diff --git a/applets/status-notifier/sn-host-v0.c b/applets/status-notifier/sn-host-v0.c
index c43ab1b..3cd6af9 100644
--- a/applets/status-notifier/sn-host-v0.c
+++ b/applets/status-notifier/sn-host-v0.c
@@ -18,6 +18,7 @@
 #include "config.h"
 
 #include "sn-host-v0.h"
+#include "sn-item-v0.h"
 #include "sn-watcher-v0-gen.h"
 
 #define SN_HOST_BUS_NAME "org.kde.StatusNotifierHost"
@@ -36,8 +37,17 @@ struct _SnHostV0
 
   guint                watcher_id;
   SnWatcherV0Gen      *watcher;
+
+  GSList              *items;
 };
 
+static void sn_host_v0_gen_init (SnHostV0GenIface *iface);
+static void sn_host_init        (SnHostInterface  *iface);
+
+G_DEFINE_TYPE_WITH_CODE (SnHostV0, sn_host_v0, SN_TYPE_HOST_V0_GEN_SKELETON,
+                         G_IMPLEMENT_INTERFACE (SN_TYPE_HOST_V0_GEN, sn_host_v0_gen_init)
+                         G_IMPLEMENT_INTERFACE (SN_TYPE_HOST, sn_host_init))
+
 static void
 sn_host_v0_gen_init (SnHostV0GenIface *iface)
 {
@@ -48,10 +58,6 @@ sn_host_init (SnHostInterface *iface)
 {
 }
 
-G_DEFINE_TYPE_WITH_CODE (SnHostV0, sn_host_v0, SN_TYPE_HOST_V0_GEN_SKELETON,
-                         G_IMPLEMENT_INTERFACE (SN_TYPE_HOST_V0_GEN, sn_host_v0_gen_init)
-                         G_IMPLEMENT_INTERFACE (SN_TYPE_HOST, sn_host_init))
-
 static void
 get_bus_name_and_object_path (const gchar  *service,
                               gchar       **bus_name,
@@ -82,29 +88,74 @@ get_bus_name_and_object_path (const gchar  *service,
 }
 
 static void
-item_registered_cb (SnWatcherV0Gen *watcher,
-                    const gchar    *service,
-                    SnHostV0       *v0)
+add_registered_item (SnHostV0    *v0,
+                     const gchar *service)
 {
   gchar *bus_name;
   gchar *object_path;
+  SnItem *item;
 
   bus_name = NULL;
   object_path = NULL;
 
   get_bus_name_and_object_path (service, &bus_name, &object_path);
 
-  g_debug ("item: bus name - %s, object path - %s", bus_name, object_path);
+  item = sn_item_v0_new (bus_name, object_path);
+  g_object_ref_sink (item);
+
+  v0->items = g_slist_prepend (v0->items, item);
+  sn_host_emit_item_added (SN_HOST (v0), item);
 
   g_free (bus_name);
   g_free (object_path);
 }
 
 static void
+item_registered_cb (SnWatcherV0Gen *watcher,
+                    const gchar    *service,
+                    SnHostV0       *v0)
+{
+  add_registered_item (v0, service);
+}
+
+static void
 item_unregistered_cb (SnWatcherV0Gen *watcher,
                       const gchar    *service,
                       SnHostV0       *v0)
 {
+  GSList *l;
+
+  for (l = v0->items; l != NULL; l = g_slist_next (l))
+    {
+      SnItem *item;
+      gboolean found;
+      gchar *bus_name;
+      gchar *object_path;
+
+      item = SN_ITEM (l->data);
+
+      found = FALSE;
+      bus_name = NULL;
+      object_path = NULL;
+
+      get_bus_name_and_object_path (service, &bus_name, &object_path);
+
+      if (g_strcmp0 (sn_item_get_bus_name (item), bus_name) == 0 &&
+          g_strcmp0 (sn_item_get_object_path (item), object_path) == 0)
+        {
+          v0->items = g_slist_remove (v0->items, item);
+          sn_host_emit_item_removed (SN_HOST (v0), item);
+          g_object_unref (item);
+
+          found = TRUE;
+        }
+
+      g_free (bus_name);
+      g_free (object_path);
+
+      if (found)
+        break;
+    }
 }
 
 static void
@@ -139,20 +190,7 @@ register_host_cb (GObject      *source_object,
   items = sn_watcher_v0_gen_dup_registered_items (v0->watcher);
 
   for (i = 0; items[i] != NULL; i++)
-    {
-      gchar *bus_name;
-      gchar *object_path;
-
-      bus_name = NULL;
-      object_path = NULL;
-
-      get_bus_name_and_object_path (items[i], &bus_name, &object_path);
-
-      g_debug ("item: bus name - %s, object path - %s", bus_name, object_path);
-
-      g_free (bus_name);
-      g_free (object_path);
-    }
+    add_registered_item (v0, items[i]);
 
   g_strfreev (items);
 }
@@ -194,6 +232,13 @@ name_appeared_cb (GDBusConnection *connection,
 }
 
 static void
+emit_item_removed_signal (gpointer data,
+                          gpointer user_data)
+{
+  sn_host_emit_item_removed (SN_HOST (user_data), SN_ITEM (data));
+}
+
+static void
 name_vanished_cb (GDBusConnection *connection,
                   const gchar     *name,
                   gpointer         user_data)
@@ -203,6 +248,13 @@ name_vanished_cb (GDBusConnection *connection,
   v0 = SN_HOST_V0 (user_data);
 
   g_clear_object (&v0->watcher);
+
+  if (v0->items)
+    {
+      g_slist_foreach (v0->items, emit_item_removed_signal, v0);
+      g_slist_free_full (v0->items, g_object_unref);
+      v0->items = NULL;
+    }
 }
 
 static void
@@ -256,6 +308,13 @@ sn_host_v0_dispose (GObject *object)
 
   g_clear_object (&v0->watcher);
 
+  if (v0->items)
+    {
+      g_slist_foreach (v0->items, emit_item_removed_signal, v0);
+      g_slist_free_full (v0->items, g_object_unref);
+      v0->items = NULL;
+    }
+
   G_OBJECT_CLASS (sn_host_v0_parent_class)->dispose (object);
 }
 
diff --git a/applets/status-notifier/sn-host.c b/applets/status-notifier/sn-host.c
index 97b8b66..c8fe48c 100644
--- a/applets/status-notifier/sn-host.c
+++ b/applets/status-notifier/sn-host.c
@@ -18,10 +18,43 @@
 #include "config.h"
 
 #include "sn-host.h"
+#include "sn-item.h"
+
+enum
+{
+  SIGNAL_ITEM_ADDED,
+  SIGNAL_ITEM_REMOVED,
+
+  LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL] = { 0 };
 
 G_DEFINE_INTERFACE (SnHost, sn_host, G_TYPE_OBJECT)
 
 static void
 sn_host_default_init (SnHostInterface *iface)
 {
+  signals[SIGNAL_ITEM_ADDED] =
+    g_signal_new ("item-added", G_TYPE_FROM_INTERFACE (iface),
+                  G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL,
+                  G_TYPE_NONE, 1, SN_TYPE_ITEM);
+
+  signals[SIGNAL_ITEM_REMOVED] =
+    g_signal_new ("item-removed", G_TYPE_FROM_INTERFACE (iface),
+                  G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL,
+                  G_TYPE_NONE, 1, SN_TYPE_ITEM);
+}
+
+void
+sn_host_emit_item_added (SnHost *host,
+                         SnItem *item)
+{
+  g_signal_emit (host, signals[SIGNAL_ITEM_ADDED], 0, item);
+}
+
+void sn_host_emit_item_removed (SnHost *host,
+                                SnItem *item)
+{
+  g_signal_emit (host, signals[SIGNAL_ITEM_REMOVED], 0, item);
 }
diff --git a/applets/status-notifier/sn-host.h b/applets/status-notifier/sn-host.h
index 4084363..d21f04e 100644
--- a/applets/status-notifier/sn-host.h
+++ b/applets/status-notifier/sn-host.h
@@ -18,7 +18,7 @@
 #ifndef SN_HOST_H
 #define SN_HOST_H
 
-#include <glib-object.h>
+#include "sn-item.h"
 
 G_BEGIN_DECLS
 
@@ -30,6 +30,12 @@ struct _SnHostInterface
   GTypeInterface parent;
 };
 
+void sn_host_emit_item_added   (SnHost *host,
+                                SnItem *item);
+
+void sn_host_emit_item_removed (SnHost *host,
+                                SnItem *item);
+
 G_END_DECLS
 
 #endif
diff --git a/applets/status-notifier/sn-item-v0.c b/applets/status-notifier/sn-item-v0.c
index 37cdccb..e88df0c 100644
--- a/applets/status-notifier/sn-item-v0.c
+++ b/applets/status-notifier/sn-item-v0.c
@@ -18,20 +18,103 @@
 #include "config.h"
 
 #include "sn-item-v0.h"
+#include "sn-item-v0-gen.h"
 
 struct _SnItemV0
 {
-  SnItem parent;
+  SnItem        parent;
+
+  GCancellable *cancellable;
+  SnItemV0Gen  *proxy;
 };
 
 G_DEFINE_TYPE (SnItemV0, sn_item_v0, SN_TYPE_ITEM)
 
 static void
+proxy_ready_cb (GObject      *source_object,
+                GAsyncResult *res,
+                gpointer      user_data)
+{
+  SnItemV0 *v0;
+  SnItemV0Gen *proxy;
+  GError *error;
+
+  error = NULL;
+  proxy = sn_item_v0_gen_proxy_new_for_bus_finish (res, &error);
+
+  if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
+    {
+      g_error_free (error);
+      return;
+    }
+
+  v0 = SN_ITEM_V0 (user_data);
+  v0->proxy = proxy;
+
+  if (error)
+    {
+      g_warning ("%s", error->message);
+      g_error_free (error);
+      return;
+    }
+}
+
+static void
+sn_item_v0_constructed (GObject *object)
+{
+  SnItemV0 *v0;
+  SnItem *item;
+
+  v0 = SN_ITEM_V0 (object);
+  item = SN_ITEM (v0);
+
+  G_OBJECT_CLASS (sn_item_v0_parent_class)->constructed (object);
+
+  v0->cancellable = g_cancellable_new ();
+  sn_item_v0_gen_proxy_new_for_bus (G_BUS_TYPE_SESSION,
+                                    G_DBUS_PROXY_FLAGS_NONE,
+                                    sn_item_get_bus_name (item),
+                                    sn_item_get_object_path (item),
+                                    v0->cancellable,
+                                    proxy_ready_cb, v0);
+}
+
+static void
+sn_item_v0_dispose (GObject *object)
+{
+  SnItemV0 *v0;
+
+  v0 = SN_ITEM_V0 (object);
+
+  g_cancellable_cancel (v0->cancellable);
+  g_clear_object (&v0->cancellable);
+  g_clear_object (&v0->proxy);
+
+  G_OBJECT_CLASS (sn_item_v0_parent_class)->dispose (object);
+}
+
+static void
 sn_item_v0_class_init (SnItemV0Class *v0_class)
 {
+  GObjectClass *object_class;
+
+  object_class = G_OBJECT_CLASS (v0_class);
+
+  object_class->constructed = sn_item_v0_constructed;
+  object_class->dispose = sn_item_v0_dispose;
 }
 
 static void
 sn_item_v0_init (SnItemV0 *v0)
 {
 }
+
+SnItem *
+sn_item_v0_new (const gchar *bus_name,
+                const gchar *object_path)
+{
+  return g_object_new (SN_TYPE_ITEM_V0,
+                       "bus-name", bus_name,
+                       "object-path", object_path,
+                       NULL);
+}
diff --git a/applets/status-notifier/sn-item-v0.h b/applets/status-notifier/sn-item-v0.h
index 7da2033..87672ad 100644
--- a/applets/status-notifier/sn-item-v0.h
+++ b/applets/status-notifier/sn-item-v0.h
@@ -25,6 +25,9 @@ G_BEGIN_DECLS
 #define SN_TYPE_ITEM_V0 sn_item_v0_get_type ()
 G_DECLARE_FINAL_TYPE (SnItemV0, sn_item_v0, SN, ITEM_V0, SnItem)
 
+SnItem *sn_item_v0_new (const gchar *bus_name,
+                        const gchar *object_path);
+
 G_END_DECLS
 
 #endif
diff --git a/applets/status-notifier/sn-item.c b/applets/status-notifier/sn-item.c
index 10d1bff..0512793 100644
--- a/applets/status-notifier/sn-item.c
+++ b/applets/status-notifier/sn-item.c
@@ -19,14 +19,148 @@
 
 #include "sn-item.h"
 
-G_DEFINE_ABSTRACT_TYPE (SnItem, sn_item, GTK_TYPE_BUTTON)
+typedef struct
+{
+  gchar *bus_name;
+  gchar *object_path;
+} SnItemPrivate;
+
+enum
+{
+  PROP_0,
+
+  PROP_BUS_NAME,
+  PROP_OBJECT_PATH,
+
+  LAST_PROP
+};
+
+static GParamSpec *properties[LAST_PROP] = { NULL };
+
+G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (SnItem, sn_item, GTK_TYPE_BUTTON)
+
+static void
+sn_item_finalize (GObject *object)
+{
+  SnItem *item;
+  SnItemPrivate *priv;
+
+  item = SN_ITEM (object);
+  priv = sn_item_get_instance_private (item);
+
+  g_clear_pointer (&priv->bus_name, g_free);
+  g_clear_pointer (&priv->object_path, g_free);
+
+  G_OBJECT_CLASS (sn_item_parent_class)->finalize (object);
+}
+
+static void
+sn_item_get_property (GObject    *object,
+                      guint       property_id,
+                      GValue     *value,
+                      GParamSpec *pspec)
+{
+  SnItem *item;
+  SnItemPrivate *priv;
+
+  item = SN_ITEM (object);
+  priv = sn_item_get_instance_private (item);
+
+  switch (property_id)
+    {
+      case PROP_BUS_NAME:
+        g_value_set_string (value, priv->bus_name);
+        break;
+
+      case PROP_OBJECT_PATH:
+        g_value_set_string (value, priv->object_path);
+        break;
+
+      default:
+        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+        break;
+    }
+}
+
+static void
+sn_item_set_property (GObject      *object,
+                      guint         property_id,
+                      const GValue *value,
+                      GParamSpec   *pspec)
+{
+  SnItem *item;
+  SnItemPrivate *priv;
+
+  item = SN_ITEM (object);
+  priv = sn_item_get_instance_private (item);
+
+  switch (property_id)
+    {
+      case PROP_BUS_NAME:
+        priv->bus_name = g_value_dup_string (value);
+        break;
+
+      case PROP_OBJECT_PATH:
+        priv->object_path = g_value_dup_string (value);
+        break;
+
+      default:
+        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+        break;
+    }
+}
+
+static void
+install_properties (GObjectClass *object_class)
+{
+  properties[PROP_BUS_NAME] =
+    g_param_spec_string ("bus-name", "bus-name", "bus-name", NULL,
+                         G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE |
+                         G_PARAM_STATIC_STRINGS);
+
+  properties[PROP_OBJECT_PATH] =
+    g_param_spec_string ("object-path", "object-path", "object-path", NULL,
+                         G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE |
+                         G_PARAM_STATIC_STRINGS);
+
+  g_object_class_install_properties (object_class, LAST_PROP, properties);
+}
 
 static void
 sn_item_class_init (SnItemClass *item_class)
 {
+  GObjectClass *object_class;
+
+  object_class = G_OBJECT_CLASS (item_class);
+
+  object_class->finalize = sn_item_finalize;
+  object_class->get_property = sn_item_get_property;
+  object_class->set_property = sn_item_set_property;
+
+  install_properties (object_class);
 }
 
 static void
 sn_item_init (SnItem *item)
 {
 }
+
+const gchar *
+sn_item_get_bus_name (SnItem *item)
+{
+  SnItemPrivate *priv;
+
+  priv = sn_item_get_instance_private (item);
+
+  return priv->bus_name;
+}
+
+const gchar *
+sn_item_get_object_path (SnItem *item)
+{
+  SnItemPrivate *priv;
+
+  priv = sn_item_get_instance_private (item);
+
+  return priv->object_path;
+}
diff --git a/applets/status-notifier/sn-item.h b/applets/status-notifier/sn-item.h
index c3612ca..5985bec 100644
--- a/applets/status-notifier/sn-item.h
+++ b/applets/status-notifier/sn-item.h
@@ -30,6 +30,9 @@ struct _SnItemClass
   GtkButtonClass parent_class;
 };
 
+const gchar *sn_item_get_bus_name    (SnItem *item);
+const gchar *sn_item_get_object_path (SnItem *item);
+
 G_END_DECLS
 
 #endif


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