diff options
Diffstat (limited to 'applets/notification_area/status-notifier/sn-dbus-menu-item.c')
-rw-r--r-- | applets/notification_area/status-notifier/sn-dbus-menu-item.c | 472 |
1 files changed, 472 insertions, 0 deletions
diff --git a/applets/notification_area/status-notifier/sn-dbus-menu-item.c b/applets/notification_area/status-notifier/sn-dbus-menu-item.c new file mode 100644 index 00000000..3e740b1c --- /dev/null +++ b/applets/notification_area/status-notifier/sn-dbus-menu-item.c @@ -0,0 +1,472 @@ +/* + * 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 (); + gtk_menu_item_set_use_underline (GTK_MENU_ITEM (item->item), TRUE); + } + else if (g_strcmp0 (item->toggle_type, "radio") == 0) + { + item->item = gtk_radio_menu_item_new (NULL); + gtk_menu_item_set_use_underline (GTK_MENU_ITEM (item->item), TRUE); + } + 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); + + g_signal_handler_block (item->item, item->activate_id); + + 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); + + g_signal_handler_unblock (item->item, item->activate_id); + } + } + 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); + } + } +} |