[gnome-panel] status-notifier: add SnDBusMenuItem



commit b1df78adba638695b5c688cc4054bfc0008ea370
Author: Alberts Muktupāvels <alberts muktupavels gmail com>
Date:   Fri Nov 4 15:32:17 2016 +0200

    status-notifier: add SnDBusMenuItem

 applets/status-notifier/Makefile.am         |    2 +
 applets/status-notifier/sn-dbus-menu-item.c |  466 +++++++++++++++++++++++++++
 applets/status-notifier/sn-dbus-menu-item.h |   62 ++++
 3 files changed, 530 insertions(+), 0 deletions(-)
---
diff --git a/applets/status-notifier/Makefile.am b/applets/status-notifier/Makefile.am
index 4ce5ddc..303f921 100644
--- a/applets/status-notifier/Makefile.am
+++ b/applets/status-notifier/Makefile.am
@@ -21,6 +21,8 @@ status_notifier_la_CFLAGS = \
 status_notifier_la_SOURCES = \
        sn-applet.c \
        sn-applet.h \
+       sn-dbus-menu-item.c \
+       sn-dbus-menu-item.h \
        sn-host.c \
        sn-host.h \
        sn-host-v0.c \
diff --git a/applets/status-notifier/sn-dbus-menu-item.c b/applets/status-notifier/sn-dbus-menu-item.c
new file mode 100644
index 0000000..455bb35
--- /dev/null
+++ b/applets/status-notifier/sn-dbus-menu-item.c
@@ -0,0 +1,466 @@
+/*
+ * Copyright (C) 2016 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/>.
+ */
+
+#include "config.h"
+
+#include "sn-dbus-menu-item.h"
+#include "sn-image-menu-item.h"
+
+static GdkPixbuf *
+pxibuf_new (GVariant *variant)
+{
+  gsize length;
+  const guchar *data;
+  GInputStream *stream;
+  GdkPixbuf *pixbuf;
+  GError *error;
+
+  data = g_variant_get_fixed_array (variant, &length, sizeof (guchar));
+
+  if (length == 0)
+    return NULL;
+
+  stream = g_memory_input_stream_new_from_data (data, length, NULL);
+
+  if (stream == NULL)
+    return NULL;
+
+  error = NULL;
+  pixbuf = gdk_pixbuf_new_from_stream (stream, NULL, &error);
+  g_object_unref (stream);
+
+  if (error != NULL)
+    {
+      g_warning ("Unable to build GdkPixbuf from icon data: %s", error->message);
+      g_error_free (error);
+    }
+
+  return pixbuf;
+}
+
+static SnShortcut *
+sn_shortcut_new (guint           key,
+                 GdkModifierType mask)
+{
+  SnShortcut *shortcut;
+
+  shortcut = g_new0 (SnShortcut, 1);
+
+  shortcut->key = key;
+  shortcut->mask = mask;
+
+  return shortcut;
+}
+
+static SnShortcut **
+sn_shortcuts_new (GVariant *variant)
+{
+  GPtrArray *array;
+  GVariantIter shortcuts;
+  GVariantIter *shortcut;
+
+  if (variant == NULL || g_variant_iter_init (&shortcuts, variant) == 0)
+    return NULL;
+
+  array = g_ptr_array_new ();
+  while (g_variant_iter_next (&shortcuts, "as", &shortcut))
+    {
+      guint key;
+      GdkModifierType mask;
+      const gchar *string;
+
+      key = 0;
+      mask = 0;
+
+      while (g_variant_iter_next (shortcut, "&s", &string))
+        {
+          if (g_strcmp0 (string, "Control") == 0)
+            mask |= GDK_CONTROL_MASK;
+          else if (g_strcmp0 (string, "Alt") == 0)
+            mask |= GDK_MOD1_MASK;
+          else if (g_strcmp0 (string, "Shift") == 0)
+            mask |= GDK_SHIFT_MASK;
+          else if (g_strcmp0 (string, "Super") == 0)
+            mask |= GDK_SUPER_MASK;
+          else
+            gtk_accelerator_parse (string, &key, NULL);
+        }
+
+      g_ptr_array_add (array,sn_shortcut_new (key, mask));
+      g_variant_iter_free (shortcut);
+    }
+
+  g_ptr_array_add (array, NULL);
+  return (SnShortcut **) g_ptr_array_free (array, FALSE);
+}
+
+static void
+sn_shortcuts_free (SnShortcut **shortcuts)
+{
+  guint i;
+
+  if (shortcuts == NULL)
+    return;
+
+  for (i = 0; shortcuts[i] != NULL; i++)
+    g_free (shortcuts[i]);
+
+  g_free (shortcuts);
+}
+
+SnDBusMenuItem *
+sn_dbus_menu_item_new (GVariant *props)
+{
+  SnDBusMenuItem *item;
+  GVariantIter iter;
+  const gchar *prop;
+  GVariant *value;
+
+  item = g_new0 (SnDBusMenuItem, 1);
+
+  item->enabled = TRUE;
+  item->toggle_state = -1;
+  item->visible = TRUE;
+
+  g_variant_iter_init (&iter, props);
+  while (g_variant_iter_next (&iter, "{&sv}", &prop, &value))
+    {
+      if (g_strcmp0 (prop, "accessible-desc") == 0)
+        item->accessible_desc = g_variant_dup_string (value, NULL);
+      else if (g_strcmp0 (prop, "children-display") == 0)
+        item->children_display = g_variant_dup_string (value, NULL);
+      else if (g_strcmp0 (prop, "disposition") == 0)
+        item->disposition = g_variant_dup_string (value, NULL);
+      else if (g_strcmp0 (prop, "enabled") == 0)
+        item->enabled = g_variant_get_boolean (value);
+      else if (g_strcmp0 (prop, "icon-name") == 0)
+        item->icon_name = g_variant_dup_string (value, NULL);
+      else if (g_strcmp0 (prop, "icon-data") == 0)
+        item->icon_data = pxibuf_new (value);
+      else if (g_strcmp0 (prop, "label") == 0)
+        item->label = g_variant_dup_string (value, NULL);
+      else if (g_strcmp0 (prop, "shortcut") == 0)
+        item->shortcuts = sn_shortcuts_new (value);
+      else if (g_strcmp0 (prop, "toggle-type") == 0)
+        item->toggle_type = g_variant_dup_string (value, NULL);
+      else if (g_strcmp0 (prop, "toggle-state") == 0)
+        item->toggle_state = g_variant_get_int32 (value);
+      else if (g_strcmp0 (prop, "type") == 0)
+        item->type = g_variant_dup_string (value, NULL);
+      else if (g_strcmp0 (prop, "visible") == 0)
+        item->visible = g_variant_get_boolean (value);
+      else
+        g_debug ("unknown property '%s'", prop);
+
+      g_variant_unref (value);
+    }
+
+  if (g_strcmp0 (item->type, "separator") == 0)
+    {
+      item->item = gtk_separator_menu_item_new ();
+    }
+  else
+    {
+      if (g_strcmp0 (item->toggle_type, "checkmark") == 0)
+        {
+          item->item = gtk_check_menu_item_new ();
+        }
+      else if (g_strcmp0 (item->toggle_type, "radio") == 0)
+        {
+          item->item = gtk_radio_menu_item_new (NULL);
+        }
+      else
+        {
+          SnImageMenuItem *image_item;
+
+          item->item = sn_image_menu_item_new ();
+          image_item = SN_IMAGE_MENU_ITEM (item->item);
+
+          if (item->icon_name)
+            {
+              sn_image_menu_item_set_image_from_icon_name (image_item,
+                                                           item->icon_name);
+            }
+          else if (item->icon_data)
+            {
+              sn_image_menu_item_set_image_from_icon_pixbuf (image_item,
+                                                             item->icon_data);
+            }
+        }
+
+      if (g_strcmp0 (item->children_display, "submenu") == 0)
+        {
+          GtkWidget *submenu;
+
+          submenu = gtk_menu_new ();
+          gtk_menu_item_set_submenu (GTK_MENU_ITEM (item->item), submenu);
+
+          item->submenu = GTK_MENU (submenu);
+          g_object_ref_sink (item->submenu);
+        }
+
+      gtk_menu_item_set_label (GTK_MENU_ITEM (item->item), item->label);
+
+      if (item->shortcuts)
+        {
+          guint i;
+
+          for (i = 0; item->shortcuts[i] != NULL; i++)
+            {
+            }
+        }
+
+      if (item->toggle_state != -1 && GTK_IS_CHECK_MENU_ITEM (item->item))
+        {
+          GtkCheckMenuItem *check;
+
+          check = GTK_CHECK_MENU_ITEM (item->item);
+
+          if (item->toggle_state == 1)
+            gtk_check_menu_item_set_active (check, TRUE);
+          else if (item->toggle_state == 0)
+            gtk_check_menu_item_set_active (check, FALSE);
+        }
+    }
+
+  gtk_widget_set_sensitive (item->item, item->enabled);
+  gtk_widget_set_visible (item->item, item->visible);
+
+  g_object_ref_sink (item->item);
+  return item;
+}
+
+void
+sn_dubs_menu_item_free (gpointer data)
+{
+  SnDBusMenuItem *item;
+
+  item = (SnDBusMenuItem *) data;
+  if (item == NULL)
+    return;
+
+  g_clear_pointer (&item->accessible_desc, g_free);
+  g_clear_pointer (&item->children_display, g_free);
+  g_clear_pointer (&item->disposition, g_free);
+  g_clear_pointer (&item->icon_name, g_free);
+  g_clear_object (&item->icon_data);
+  g_clear_pointer (&item->label, g_free);
+  g_clear_pointer (&item->shortcuts, sn_shortcuts_free);
+  g_clear_pointer (&item->toggle_type, g_free);
+  g_clear_pointer (&item->type, g_free);
+
+  gtk_widget_destroy (item->item);
+  g_clear_object (&item->item);
+  g_clear_object (&item->submenu);
+
+  g_free (item);
+}
+
+void
+sn_dbus_menu_item_update_props (SnDBusMenuItem *item,
+                                GVariant       *props)
+{
+  GVariantIter iter;
+  const gchar *prop;
+  GVariant *value;
+
+  g_variant_iter_init (&iter, props);
+  while (g_variant_iter_next (&iter, "{&sv}", &prop, &value))
+    {
+      if (g_strcmp0 (prop, "accessible-desc") == 0)
+        {
+          g_free (item->accessible_desc);
+          item->accessible_desc = g_variant_dup_string (value, NULL);
+        }
+      else if (g_strcmp0 (prop, "children-display") == 0)
+        {
+          g_free (item->children_display);
+          item->children_display = g_variant_dup_string (value, NULL);
+        }
+      else if (g_strcmp0 (prop, "disposition") == 0)
+        {
+          g_free (item->disposition);
+          item->disposition = g_variant_dup_string (value, NULL);
+        }
+      else if (g_strcmp0 (prop, "enabled") == 0)
+        {
+          item->enabled = g_variant_get_boolean (value);
+          gtk_widget_set_sensitive (item->item, item->enabled);
+        }
+      else if (g_strcmp0 (prop, "icon-name") == 0)
+        {
+          SnImageMenuItem *image_item;
+
+          g_free (item->icon_name);
+          item->icon_name = g_variant_dup_string (value, NULL);
+
+          image_item = SN_IMAGE_MENU_ITEM (item->item);
+
+          if (item->icon_name)
+            {
+              sn_image_menu_item_set_image_from_icon_name (image_item,
+                                                           item->icon_name);
+            }
+          else
+            {
+              sn_image_menu_item_unset_image (image_item);
+            }
+        }
+      else if (g_strcmp0 (prop, "icon-data") == 0)
+        {
+          SnImageMenuItem *image_item;
+
+          g_clear_object (&item->icon_data);
+          item->icon_data = pxibuf_new (value);
+
+          image_item = SN_IMAGE_MENU_ITEM (item->item);
+
+          if (item->icon_data)
+            {
+              sn_image_menu_item_set_image_from_icon_pixbuf (image_item,
+                                                             item->icon_data);
+            }
+          else
+            {
+              sn_image_menu_item_unset_image (image_item);
+            }
+        }
+      else if (g_strcmp0 (prop, "label") == 0)
+        {
+          g_free (item->label);
+          item->label = g_variant_dup_string (value, NULL);
+
+          if (!GTK_IS_SEPARATOR_MENU_ITEM (item->item))
+            gtk_menu_item_set_label (GTK_MENU_ITEM (item->item), item->label);
+        }
+      else if (g_strcmp0 (prop, "shortcut") == 0)
+        {
+          sn_shortcuts_free (item->shortcuts);
+          item->shortcuts = sn_shortcuts_new (value);
+        }
+      else if (g_strcmp0 (prop, "toggle-type") == 0)
+        {
+          g_free (item->toggle_type);
+          item->toggle_type = g_variant_dup_string (value, NULL);
+        }
+      else if (g_strcmp0 (prop, "toggle-state") == 0)
+        {
+          item->toggle_state = g_variant_get_int32 (value);
+
+          if (item->toggle_state != -1 && GTK_IS_CHECK_MENU_ITEM (item->item))
+            {
+              GtkCheckMenuItem *check;
+
+              check = GTK_CHECK_MENU_ITEM (item->item);
+
+              if (item->toggle_state == 1)
+                gtk_check_menu_item_set_active (check, TRUE);
+              else if (item->toggle_state == 0)
+                gtk_check_menu_item_set_active (check, FALSE);
+            }
+        }
+      else if (g_strcmp0 (prop, "type") == 0)
+        {
+          g_free (item->type);
+          item->type = g_variant_dup_string (value, NULL);
+        }
+      else if (g_strcmp0 (prop, "visible") == 0)
+        {
+          item->visible = g_variant_get_boolean (value);
+          gtk_widget_set_visible (item->item, item->visible);
+        }
+      else
+        {
+          g_debug ("updating unknown property - '%s'", prop);
+        }
+
+      g_variant_unref (value);
+    }
+}
+
+void
+sn_dbus_menu_item_remove_props (SnDBusMenuItem *item,
+                                GVariant       *props)
+{
+  GVariantIter iter;
+  const gchar *prop;
+
+  g_variant_iter_init (&iter, props);
+  while (g_variant_iter_next (&iter, "&s", &prop))
+    {
+      if (g_strcmp0 (prop, "accessible-desc") == 0)
+        {
+          g_clear_pointer (&item->accessible_desc, g_free);
+        }
+      else if (g_strcmp0 (prop, "children-display") == 0)
+        {
+          g_clear_pointer (&item->children_display, g_free);
+        }
+      else if (g_strcmp0 (prop, "disposition") == 0)
+        {
+          g_clear_pointer (&item->disposition, g_free);
+        }
+      else if (g_strcmp0 (prop, "enabled") == 0)
+        {
+          item->enabled = TRUE;
+          gtk_widget_set_sensitive (item->item, item->enabled);
+        }
+      else if (g_strcmp0 (prop, "icon-name") == 0)
+        {
+          g_clear_pointer (&item->icon_name, g_free);
+          if (SN_IS_IMAGE_MENU_ITEM (item->item))
+            sn_image_menu_item_unset_image (SN_IMAGE_MENU_ITEM (item->item));
+        }
+      else if (g_strcmp0 (prop, "icon-data") == 0)
+        {
+          g_clear_object (&item->icon_data);
+          if (SN_IS_IMAGE_MENU_ITEM (item->item))
+            sn_image_menu_item_unset_image (SN_IMAGE_MENU_ITEM (item->item));
+        }
+      else if (g_strcmp0 (prop, "label") == 0)
+        {
+          g_clear_pointer (&item->label, g_free);
+          if (!GTK_IS_SEPARATOR_MENU_ITEM (item->item))
+            gtk_menu_item_set_label (GTK_MENU_ITEM (item->item), item->label);
+        }
+      else if (g_strcmp0 (prop, "shortcut") == 0)
+        {
+          g_clear_pointer (&item->shortcuts, sn_shortcuts_free);
+        }
+      else if (g_strcmp0 (prop, "toggle-type") == 0)
+        {
+          g_clear_pointer (&item->toggle_type, g_free);
+        }
+      else if (g_strcmp0 (prop, "toggle-state") == 0)
+        {
+          item->toggle_state = -1;
+        }
+      else if (g_strcmp0 (prop, "type") == 0)
+        {
+          g_clear_pointer (&item->type, g_free);
+        }
+      else if (g_strcmp0 (prop, "visible") == 0)
+        {
+          item->visible = TRUE;
+          gtk_widget_set_visible (item->item, item->visible);
+        }
+      else
+        {
+          g_debug ("removing unknown property - '%s'", prop);
+        }
+    }
+}
diff --git a/applets/status-notifier/sn-dbus-menu-item.h b/applets/status-notifier/sn-dbus-menu-item.h
new file mode 100644
index 0000000..a5ff995
--- /dev/null
+++ b/applets/status-notifier/sn-dbus-menu-item.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2016 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 SN_DBUS_MENU_ITEM_H
+#define SN_DUBS_MENU_ITEM_H
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+typedef struct
+{
+  guint           key;
+  GdkModifierType mask;
+} SnShortcut;
+
+typedef struct
+{
+  gchar       *accessible_desc;
+  gchar       *children_display;
+  gchar       *disposition;
+  gboolean     enabled;
+  gchar       *icon_name;
+  GdkPixbuf   *icon_data;
+  gchar       *label;
+  SnShortcut **shortcuts;
+  gchar       *toggle_type;
+  gint32       toggle_state;
+  gchar       *type;
+  gboolean     visible;
+
+  GtkWidget   *item;
+  GtkMenu     *submenu;
+} SnDBusMenuItem;
+
+SnDBusMenuItem *sn_dbus_menu_item_new          (GVariant       *props);
+
+void            sn_dubs_menu_item_free         (gpointer        data);
+
+void            sn_dbus_menu_item_update_props (SnDBusMenuItem *item,
+                                                GVariant       *props);
+
+void            sn_dbus_menu_item_remove_props (SnDBusMenuItem *item,
+                                                GVariant       *props);
+
+G_END_DECLS
+
+#endif


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