[gnome-panel/wip/status-notifier: 13/13] snh: add items to applet



commit caf1272398dfddc4156d9dc7fa4e8d6544cc9959
Author: Alberts Muktupāvels <alberts muktupavels gmail com>
Date:   Sat Jul 4 17:54:26 2015 +0300

    snh: add items to applet

 applets/snh/Makefile.am  |    2 +
 applets/snh/snh-applet.c |   79 ++++++--
 applets/snh/snh-item.c   |  476 ++++++++++++++++++++++++++++++++++++++++++++++
 applets/snh/snh-item.h   |   33 ++++
 4 files changed, 573 insertions(+), 17 deletions(-)
---
diff --git a/applets/snh/Makefile.am b/applets/snh/Makefile.am
index c949cc8..af4e8d9 100644
--- a/applets/snh/Makefile.am
+++ b/applets/snh/Makefile.am
@@ -16,6 +16,8 @@ AM_CFLAGS = \
 SNH_SOURCES = \
        snh-applet.c \
        snh-applet.h \
+       snh-item.c \
+       snh-item.h \
        $(NULL)
 
 SNH_LDADD = \
diff --git a/applets/snh/snh-applet.c b/applets/snh/snh-applet.c
index a795fd5..1870cbf 100644
--- a/applets/snh/snh-applet.c
+++ b/applets/snh/snh-applet.c
@@ -17,9 +17,8 @@
 
 #include "config.h"
 
-#include <libstatus-notifier/sn.h>
-
 #include "snh-applet.h"
+#include "snh-item.h"
 
 struct _SnhApplet
 {
@@ -27,38 +26,54 @@ struct _SnhApplet
 
   SnHost      *host;
 
-  GtkWidget   *label;
+  GtkWidget   *box;
 };
 
 G_DEFINE_TYPE (SnhApplet, snh_applet, PANEL_TYPE_APPLET)
 
 static void
+item_remove (GtkWidget *widget,
+             gpointer   data)
+{
+  gtk_widget_destroy (widget);
+}
+
+static void
 items_changed_cb (SnHost   *host,
                   gpointer  user_data)
 {
   SnhApplet *applet;
   GList *list;
-  gchar *text;
+  GList *l;
 
   applet = SNH_APPLET (user_data);
 
   list = sn_host_get_items (host);
 
-  text = g_strdup_printf ("Items: %d", g_list_length (list));
-  g_list_free (list);
+  gtk_container_foreach (GTK_CONTAINER (applet->box),
+                         (GtkCallback) item_remove, NULL);
+
+  for (l = list; l; l = l->next)
+    {
+      SnItemClient *item_client;
+      GtkWidget *item;
+
+      item_client = SN_ITEM_CLIENT (l->data);
+      item = snh_item_new (item_client);
 
-  gtk_label_set_text (GTK_LABEL (applet->label), text);
-  g_free (text);
+      g_object_bind_property (applet->box, "orientation", item, "orientation",
+                              G_BINDING_DEFAULT);
+
+      gtk_box_pack_start (GTK_BOX (applet->box), item, FALSE, FALSE, 0);
+      gtk_widget_show (item);
+    }
+
+  g_list_free (list);
 }
 
 static gboolean
 snh_applet_fill (SnhApplet *applet)
 {
-  applet->label = gtk_label_new ("Items: 0");
-
-  gtk_container_add (GTK_CONTAINER (applet), applet->label);
-  gtk_widget_show (applet->label);
-
   gtk_widget_show (GTK_WIDGET (applet));
 
   return TRUE;
@@ -76,7 +91,7 @@ snh_applet_factory (PanelApplet *applet,
 }
 
 static void
-snh_applet_finalize (GObject *object)
+snh_applet_dispose (GObject *object)
 {
   SnhApplet *applet;
 
@@ -84,33 +99,63 @@ snh_applet_finalize (GObject *object)
 
   g_clear_object (&applet->host);
 
+  G_OBJECT_CLASS (snh_applet_parent_class)->dispose (object);
+}
+
+static void
+snh_applet_finalize (GObject *object)
+{
   G_OBJECT_CLASS (snh_applet_parent_class)->finalize (object);
 }
 
 static void
+snh_applet_change_orient (PanelApplet       *applet,
+                          PanelAppletOrient  orient)
+{
+  SnhApplet *snh_applet;
+  GtkOrientation orientation;
+
+  snh_applet = SNH_APPLET (applet);
+  orientation = panel_applet_get_gtk_orientation (applet);
+
+  gtk_orientable_set_orientation (GTK_ORIENTABLE (snh_applet->box),
+                                  orientation);
+}
+
+static void
 snh_applet_class_init (SnhAppletClass *applet_class)
 {
   GObjectClass *object_class;
+  PanelAppletClass *panel_applet_class;
 
   object_class = G_OBJECT_CLASS (applet_class);
+  panel_applet_class = PANEL_APPLET_CLASS (applet_class);
 
+  object_class->dispose = snh_applet_dispose;
   object_class->finalize = snh_applet_finalize;
+
+  panel_applet_class->change_orient = snh_applet_change_orient;
 }
 
 static void
 snh_applet_init (SnhApplet *applet)
 {
   PanelApplet *panel_applet;
+  GtkOrientation orientation;
 
   panel_applet = PANEL_APPLET (applet);
+  orientation = panel_applet_get_gtk_orientation (panel_applet);
 
-  applet->host = sn_host_new ();
+  panel_applet_set_flags (panel_applet, PANEL_APPLET_HAS_HANDLE |
+                          PANEL_APPLET_EXPAND_MINOR);
 
+  applet->host = sn_host_new ();
   g_signal_connect (applet->host, "items-changed",
                     G_CALLBACK (items_changed_cb), applet);
 
-  panel_applet_set_flags (panel_applet, PANEL_APPLET_HAS_HANDLE |
-                          PANEL_APPLET_EXPAND_MINOR);
+  applet->box = gtk_box_new (orientation, 0);
+  gtk_container_add (GTK_CONTAINER (applet), applet->box);
+  gtk_widget_show (applet->box);
 }
 
 PANEL_APPLET_IN_PROCESS_FACTORY ("SnhAppletFactory", SNH_TYPE_APPLET,
diff --git a/applets/snh/snh-item.c b/applets/snh/snh-item.c
new file mode 100644
index 0000000..645d32e
--- /dev/null
+++ b/applets/snh/snh-item.c
@@ -0,0 +1,476 @@
+/*
+ * Copyright (C) 2015 Alberts Muktupāvels
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#include "snh-item.h"
+
+#define UPDATE_TIMEOUT 100
+#define UPDATE_ICONS_TIMEOUT 100
+
+struct _SnhItem
+{
+  GtkEventBox     parent;
+
+  SnItemClient   *item;
+
+  GtkOrientation  orientation;
+  gint            size;
+
+  guint           update_id;
+  guint           update_icons_id;
+
+  gchar          *title;
+  gchar          *tooltip_title;
+  gchar          *tooltip_text;
+  gchar          *icon_theme_path;
+
+  GdkPixbuf      *icon;
+  GdkPixbuf      *overlay_icon;
+  GdkPixbuf      *attention_icon;
+  GdkPixbuf      *tooltip_icon;
+
+  SnItemStatus    status;
+
+  GtkWidget      *box;
+  GtkWidget      *image;
+  GtkWidget      *label;
+};
+
+enum
+{
+  PROP_0,
+
+  PROP_ITEM,
+  PROP_ORIENTATION,
+
+  LAST_PROP
+};
+
+static GParamSpec *properties[LAST_PROP] = { NULL };
+
+G_DEFINE_TYPE (SnhItem, snh_item, GTK_TYPE_EVENT_BOX)
+
+static gboolean
+update_cb (gpointer user_data)
+{
+  SnhItem *item;
+  GtkWidget *widget;
+  GdkPixbuf *icon;
+
+  item = SNH_ITEM (user_data);
+  widget = GTK_WIDGET (item);
+
+  if (item->status == SN_ITEM_STATUS_PASSIVE)
+    {
+      gtk_widget_hide (widget);
+
+      item->update_id = 0;
+      return G_SOURCE_REMOVE;
+    }
+
+  if (gtk_widget_is_visible (widget) == FALSE)
+    gtk_widget_show (widget);
+
+  icon = item->icon;
+
+  if (item->status == SN_ITEM_STATUS_NEEDS_ATTENTION && item->attention_icon)
+    icon = item->attention_icon;
+
+  if (icon)
+    {
+      gtk_widget_hide (item->label);
+
+      gtk_image_set_from_pixbuf (GTK_IMAGE (item->image), icon);
+      gtk_widget_show (item->image);
+    }
+  else
+    {
+      gtk_widget_hide (item->image);
+
+      gtk_label_set_text (GTK_LABEL (item->label), item->title);
+      gtk_widget_show (item->label);
+    }
+
+  item->update_id = 0;
+  return G_SOURCE_REMOVE;
+}
+
+static void
+snh_item_update (SnhItem *item)
+{
+  if (item->update_id > 0)
+    g_source_remove (item->update_id);
+
+  item->update_id = g_timeout_add (UPDATE_TIMEOUT,
+                                   (GSourceFunc) update_cb,
+                                   item);
+  g_source_set_name_by_id (item->update_id, "[gnome-panel] update_cb");
+}
+
+static void
+snh_item_update_title (SnhItem *item)
+{
+  const gchar *title;
+
+  title = sn_item_client_get_title (item->item);
+
+  if (g_strcmp0 (item->title, title) == 0)
+    return;
+
+  g_free (item->title);
+  item->title = g_strdup (title);
+
+  snh_item_update (item);
+}
+
+static void
+snh_item_update_tooltip (SnhItem *item)
+{
+}
+
+static void
+snh_item_update_status (SnhItem      *item,
+                        SnItemStatus  status)
+{
+  if (item->status == status)
+    return;
+
+  item->status = status;
+
+  snh_item_update (item);
+}
+
+static void
+update_icon (SnhItem *item)
+{
+  const gchar *icon_name;
+  GdkPixbuf *icon;
+
+  icon = NULL;
+  icon_name = sn_item_client_get_icon_name (item->item);
+
+  if (icon_name)
+    {
+      icon = gtk_icon_theme_load_icon (gtk_icon_theme_get_default (),
+                                       icon_name, item->size,
+                                       GTK_ICON_LOOKUP_FORCE_SIZE, NULL);
+    }
+
+  if (icon == NULL)
+    {
+    }
+
+  g_clear_object (&item->icon);
+  item->icon = icon;
+}
+
+static void
+update_overlay_icon (SnhItem *item)
+{
+}
+
+static void
+update_attention_icon (SnhItem *item)
+{
+}
+
+static void
+update_tooltip_icon (SnhItem *item)
+{
+}
+
+static gboolean
+update_icons_cb (gpointer user_data)
+{
+  SnhItem *item;
+  GtkIconTheme *icon_theme;
+  const gchar *icon_theme_path;
+
+  item = SNH_ITEM (user_data);
+  icon_theme = gtk_icon_theme_get_default ();
+  icon_theme_path = sn_item_client_get_icon_theme_path (item->item);
+
+  if (g_strcmp0 (item->icon_theme_path, icon_theme_path) != 0)
+    {
+      gtk_icon_theme_append_search_path (icon_theme, icon_theme_path);
+
+      g_free (item->icon_theme_path);
+      item->icon_theme_path = g_strdup (icon_theme_path);
+    }
+
+  update_icon (item);
+  update_overlay_icon (item);
+  update_attention_icon (item);
+  update_tooltip_icon (item);
+
+  snh_item_update (item);
+
+  item->update_icons_id = 0;
+  return G_SOURCE_REMOVE;
+}
+
+static void
+snh_item_update_icons (SnhItem *item)
+{
+  if (item->update_icons_id > 0)
+    g_source_remove (item->update_icons_id);
+
+  item->update_icons_id = g_timeout_add (UPDATE_ICONS_TIMEOUT,
+                                         (GSourceFunc) update_icons_cb,
+                                         item);
+  g_source_set_name_by_id (item->update_icons_id,
+                           "[gnome-panel] update_icons_cb");
+}
+
+static void
+new_title_cb (SnItemClient *item_client,
+              gpointer      user_data)
+{
+  SnhItem *item;
+
+  item = SNH_ITEM (user_data);
+
+  snh_item_update_title (item);
+}
+
+static void
+new_icon_cb (SnItemClient *item_client,
+             gpointer      user_data)
+{
+  SnhItem *item;
+
+  item = SNH_ITEM (user_data);
+
+  snh_item_update_icons (item);
+}
+
+static void
+new_tooltip_cb (SnItemClient *item_client,
+                gpointer      user_data)
+{
+  SnhItem *item;
+
+  item = SNH_ITEM (user_data);
+
+  snh_item_update_tooltip (item);
+  snh_item_update_icons (item);
+}
+
+static void
+new_status_cb (SnItemClient *item_client,
+               SnItemStatus  status,
+               gpointer      user_data)
+{
+  SnhItem *item;
+
+  item = SNH_ITEM (user_data);
+
+  snh_item_update_status (item, status);
+}
+
+static void
+new_icon_theme_path_cb (SnItemClient *item_client,
+                        const gchar  *path,
+                        gpointer      user_data)
+{
+  SnhItem *item;
+
+  item = SNH_ITEM (user_data);
+
+  snh_item_update_icons (item);
+}
+
+static void
+snh_item_constructed (GObject *object)
+{
+  SnhItem *item;
+  SnItemStatus status;
+
+  item = SNH_ITEM (object);
+
+  G_OBJECT_CLASS (snh_item_parent_class)->constructed (object);
+
+  g_signal_connect (item->item, "new-title",
+                    G_CALLBACK (new_title_cb), item);
+  g_signal_connect (item->item, "new-icon",
+                    G_CALLBACK (new_icon_cb), item);
+  g_signal_connect (item->item, "new-overlay-icon",
+                    G_CALLBACK (new_icon_cb), item);
+  g_signal_connect (item->item, "new-attention-icon",
+                    G_CALLBACK (new_icon_cb), item);
+  g_signal_connect (item->item, "new-tooltip",
+                    G_CALLBACK (new_tooltip_cb), item);
+  g_signal_connect (item->item, "new-status",
+                    G_CALLBACK (new_status_cb), item);
+  g_signal_connect (item->item, "new-icon-theme-path",
+                    G_CALLBACK (new_icon_theme_path_cb), item);
+
+  snh_item_update_title (item);
+  snh_item_update_tooltip (item);
+
+  status = sn_item_client_get_status (item->item);
+  snh_item_update_status (item, status);
+}
+
+static void
+snh_item_set_property (GObject      *object,
+                       guint         property_id,
+                       const GValue *value,
+                       GParamSpec   *pspec)
+{
+  SnhItem *item;
+  GtkOrientation orientation;
+
+  item = SNH_ITEM (object);
+
+  switch (property_id)
+    {
+      case PROP_ITEM:
+        item->item = g_value_get_object (value);
+        break;
+
+      case PROP_ORIENTATION:
+        orientation = g_value_get_enum (value);
+
+        if (item->orientation != orientation)
+          {
+            item->orientation = orientation;
+
+            snh_item_update_icons (item);
+          }
+        break;
+
+      default:
+        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+        break;
+    }
+}
+
+static void
+snh_item_dispose (GObject *object)
+{
+  SnhItem *item;
+
+  item = SNH_ITEM (object);
+
+  if (item->update_icons_id > 0)
+    {
+      g_source_remove (item->update_icons_id);
+      item->update_icons_id = 0;
+    }
+
+  if (item->update_id > 0)
+    {
+      g_source_remove (item->update_id);
+      item->update_id = 0;
+    }
+
+  g_clear_object (&item->icon);
+  g_clear_object (&item->overlay_icon);
+  g_clear_object (&item->attention_icon);
+  g_clear_object (&item->tooltip_icon);
+
+  G_OBJECT_CLASS (snh_item_parent_class)->dispose (object);
+}
+
+static void
+snh_item_finalize (GObject *object)
+{
+  SnhItem *item;
+
+  item = SNH_ITEM (object);
+
+  g_free (item->title);
+  g_free (item->tooltip_title);
+  g_free (item->tooltip_text);
+  g_free (item->icon_theme_path);
+
+  G_OBJECT_CLASS (snh_item_parent_class)->finalize (object);
+}
+
+static void
+snh_item_size_allocate (GtkWidget     *widget,
+                        GtkAllocation *allocation)
+{
+  SnhItem *item;
+  gint size;
+
+  item = SNH_ITEM (widget);
+
+  GTK_WIDGET_CLASS (snh_item_parent_class)->size_allocate (widget, allocation);
+
+  if (item->orientation == GTK_ORIENTATION_HORIZONTAL)
+    size = allocation->height;
+  else
+    size = allocation->width;
+
+  if (item->size == size)
+    return;
+
+  item->size = size;
+
+  snh_item_update_icons (item);
+}
+
+static void
+snh_item_class_init (SnhItemClass *item_class)
+{
+  GObjectClass *object_class;
+  GtkWidgetClass *widget_class;
+
+  object_class = G_OBJECT_CLASS (item_class);
+  widget_class = GTK_WIDGET_CLASS (item_class);
+
+  object_class->constructed = snh_item_constructed;
+  object_class->set_property = snh_item_set_property;
+  object_class->dispose = snh_item_dispose;
+  object_class->finalize = snh_item_finalize;
+
+  widget_class->size_allocate = snh_item_size_allocate;
+
+  properties[PROP_ITEM] =
+    g_param_spec_object ("item", "item", "item", SN_TYPE_ITEM_CLIENT,
+                         G_PARAM_CONSTRUCT_ONLY | G_PARAM_WRITABLE);
+
+  properties[PROP_ORIENTATION] =
+    g_param_spec_enum ("orientation", "orientation", "orientation",
+                       GTK_TYPE_ORIENTATION, GTK_ORIENTATION_HORIZONTAL,
+                       G_PARAM_WRITABLE);
+
+  g_object_class_install_properties (object_class, LAST_PROP, properties);
+}
+
+static void
+snh_item_init (SnhItem *item)
+{
+  item->box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
+  gtk_container_add (GTK_CONTAINER (item), item->box);
+  gtk_widget_show (item->box);
+
+  item->image = gtk_image_new ();
+  gtk_box_pack_start (GTK_BOX (item->box), item->image, FALSE, FALSE, 0);
+
+  item->label = gtk_label_new (NULL);
+  gtk_box_pack_start (GTK_BOX (item->box), item->label, FALSE, FALSE, 0);
+}
+
+GtkWidget *
+snh_item_new (SnItemClient *item)
+{
+  return g_object_new (SNH_TYPE_ITEM, "item", item, NULL);
+}
diff --git a/applets/snh/snh-item.h b/applets/snh/snh-item.h
new file mode 100644
index 0000000..5a7ce44
--- /dev/null
+++ b/applets/snh/snh-item.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2015 Alberts Muktupāvels
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef SNH_ITEM_H
+#define SNH_ITEM_H
+
+#include <gtk/gtk.h>
+#include <libstatus-notifier/sn.h>
+
+G_BEGIN_DECLS
+
+#define SNH_TYPE_ITEM snh_item_get_type ()
+G_DECLARE_FINAL_TYPE (SnhItem, snh_item, SNH, ITEM, GtkEventBox)
+
+GtkWidget *snh_item_new (SnItemClient *item);
+
+G_END_DECLS
+
+#endif


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