aboutsummaryrefslogtreecommitdiff
path: root/libdbusmenu-gtk
diff options
context:
space:
mode:
Diffstat (limited to 'libdbusmenu-gtk')
-rw-r--r--libdbusmenu-gtk/Makefile.am7
-rw-r--r--libdbusmenu-gtk/client.c138
-rw-r--r--libdbusmenu-gtk/menuitem.c130
-rw-r--r--libdbusmenu-gtk/menuitem.h39
4 files changed, 312 insertions, 2 deletions
diff --git a/libdbusmenu-gtk/Makefile.am b/libdbusmenu-gtk/Makefile.am
index c375428..918d071 100644
--- a/libdbusmenu-gtk/Makefile.am
+++ b/libdbusmenu-gtk/Makefile.am
@@ -9,13 +9,16 @@ libdbusmenu_gtkincludedir=$(includedir)/libdbusmenu-0.1/libdbusmenu-gtk/
libdbusmenu_gtkinclude_HEADERS = \
client.h \
- menu.h
+ menu.h \
+ menuitem.h
libdbusmenu_gtk_la_SOURCES = \
client.h \
client.c \
menu.h \
- menu.c
+ menu.c \
+ menuitem.h \
+ menuitem.c
libdbusmenu_gtk_la_LDFLAGS = \
-version-info $(LIBDBUSMENU_CURRENT):$(LIBDBUSMENU_REVISION):$(LIBDBUSMENU_AGE) \
diff --git a/libdbusmenu-gtk/client.c b/libdbusmenu-gtk/client.c
index 7271c37..44d952d 100644
--- a/libdbusmenu-gtk/client.c
+++ b/libdbusmenu-gtk/client.c
@@ -33,6 +33,7 @@ License version 3 and version 2.1 along with this program. If not, see
#include <gtk/gtk.h>
#include "client.h"
+#include "menuitem.h"
/* Prototypes */
static void dbusmenu_gtkclient_class_init (DbusmenuGtkClientClass *klass);
@@ -48,6 +49,9 @@ static gboolean new_item_normal (DbusmenuMenuitem * newitem, DbusmenuMenuite
static gboolean new_item_seperator (DbusmenuMenuitem * newitem, DbusmenuMenuitem * parent, DbusmenuClient * client);
static gboolean new_item_image (DbusmenuMenuitem * newitem, DbusmenuMenuitem * parent, DbusmenuClient * client);
+static void process_visible (GtkMenuItem * gmi, const gchar * value);
+static void process_sensitive (GtkMenuItem * gmi, const gchar * value);
+
/* GObject Stuff */
G_DEFINE_TYPE (DbusmenuGtkClient, dbusmenu_gtkclient, DBUSMENU_TYPE_CLIENT);
@@ -116,6 +120,18 @@ process_visible (GtkMenuItem * gmi, const gchar * value)
return;
}
+/* Process the sensitive property */
+static void
+process_sensitive (GtkMenuItem * gmi, const gchar * value)
+{
+ if (value == NULL || !g_strcmp0(value, "true")) {
+ gtk_widget_set_sensitive(GTK_WIDGET(gmi), TRUE);
+ } else {
+ gtk_widget_set_sensitive(GTK_WIDGET(gmi), FALSE);
+ }
+ return;
+}
+
/* Whenever we have a property change on a DbusmenuMenuitem
we need to be responsive to that. */
static void
@@ -125,6 +141,8 @@ menu_prop_change_cb (DbusmenuMenuitem * mi, gchar * prop, gchar * value, GtkMenu
gtk_menu_item_set_label(gmi, value);
} else if (!g_strcmp0(prop, DBUSMENU_MENUITEM_PROP_VISIBLE)) {
process_visible(gmi, value);
+ } else if (!g_strcmp0(prop, DBUSMENU_MENUITEM_PROP_SENSITIVE)) {
+ process_sensitive(gmi, value);
}
return;
@@ -171,6 +189,7 @@ dbusmenu_gtkclient_newitem_base (DbusmenuGtkClient * client, DbusmenuMenuitem *
g_object_weak_ref(G_OBJECT(item), destoryed_dbusmenuitem_cb, gmi);
process_visible(gmi, dbusmenu_menuitem_property_get(item, DBUSMENU_MENUITEM_PROP_VISIBLE));
+ process_sensitive(gmi, dbusmenu_menuitem_property_get(item, DBUSMENU_MENUITEM_PROP_SENSITIVE));
if (parent != NULL) {
new_child(parent, item, dbusmenu_menuitem_get_position(item, parent), DBUSMENU_GTKCLIENT(client));
@@ -284,6 +303,8 @@ dbusmenu_gtkclient_menuitem_get (DbusmenuGtkClient * client, DbusmenuMenuitem *
return mi;
}
+/* The base type handler that builds a plain ol'
+ GtkMenuItem to represent, well, the GtkMenuItem */
static gboolean
new_item_normal (DbusmenuMenuitem * newitem, DbusmenuMenuitem * parent, DbusmenuClient * client)
{
@@ -303,6 +324,8 @@ new_item_normal (DbusmenuMenuitem * newitem, DbusmenuMenuitem * parent, Dbusmenu
return TRUE;
}
+/* Type handler for the seperators where it builds
+ a GtkSeparator to act as the GtkMenuItem */
static gboolean
new_item_seperator (DbusmenuMenuitem * newitem, DbusmenuMenuitem * parent, DbusmenuClient * client)
{
@@ -322,9 +345,124 @@ new_item_seperator (DbusmenuMenuitem * newitem, DbusmenuMenuitem * parent, Dbusm
return TRUE;
}
+/* This handler looks at property changes for items that are
+ image menu items. */
+static void
+image_property_handle (DbusmenuMenuitem * item, const gchar * property, const gchar * value, gpointer userdata)
+{
+ /* We're only looking at these two properties here */
+ g_return_if_fail(!g_strcmp0(property, DBUSMENU_MENUITEM_PROP_ICON) || !g_strcmp0(property, DBUSMENU_MENUITEM_PROP_ICON_DATA));
+
+ if (value == NULL || value[0] == '\0') {
+ /* This means that we're unsetting a value. */
+ /* Try to use the other one */
+ if (g_strcmp0(property, DBUSMENU_MENUITEM_PROP_ICON)) {
+ property = DBUSMENU_MENUITEM_PROP_ICON_DATA;
+ } else {
+ property = DBUSMENU_MENUITEM_PROP_ICON;
+ }
+ }
+
+ /* Grab the data of the items that we've got, so that
+ we can know how things need to change. */
+ GtkMenuItem * gimi = dbusmenu_gtkclient_menuitem_get (DBUSMENU_GTKCLIENT(userdata), item);
+ if (gimi == NULL) {
+ g_warning("Oddly we're handling image properties on a menuitem that doesn't have any GTK structures associated with it.");
+ return;
+ }
+ GtkWidget * gtkimage = gtk_image_menu_item_get_image(GTK_IMAGE_MENU_ITEM(gimi));
+
+ if (!g_strcmp0(property, DBUSMENU_MENUITEM_PROP_ICON_DATA)) {
+ /* If we have an image already built from a name that is
+ way better than a pixbuf. Keep it. */
+ if (gtk_image_get_storage_type(GTK_IMAGE(gtkimage)) == GTK_IMAGE_ICON_NAME) {
+ return;
+ }
+ }
+
+ /* Now figure out what to change */
+ if (!g_strcmp0(property, DBUSMENU_MENUITEM_PROP_ICON)) {
+ const gchar * iconname = dbusmenu_menuitem_property_get(item, property);
+ if (iconname == NULL) {
+ /* If there is no name, by golly we want no
+ icon either. */
+ gtkimage = NULL;
+ } else {
+ /* If we don't have an image, we need to build
+ one so that we can set the name. Otherwise we
+ can just convert it to this name. */
+ if (gtkimage == NULL) {
+ gtkimage = gtk_image_new_from_icon_name(iconname, GTK_ICON_SIZE_MENU);
+ } else {
+ gtk_image_set_from_icon_name(GTK_IMAGE(gtkimage), iconname, GTK_ICON_SIZE_MENU);
+ }
+ }
+ } else {
+ GdkPixbuf * image = dbusmenu_menuitem_property_get_image(item, property);
+ if (image == NULL) {
+ /* If there is no pixbuf, by golly we want no
+ icon either. */
+ gtkimage = NULL;
+ } else {
+ /* Resize the pixbuf */
+ gint width, height;
+ gtk_icon_size_lookup(GTK_ICON_SIZE_MENU, &width, &height);
+ if (gdk_pixbuf_get_width(image) > width ||
+ gdk_pixbuf_get_height(image) > height) {
+ GdkPixbuf * newimage = gdk_pixbuf_scale_simple(image,
+ width,
+ height,
+ GDK_INTERP_BILINEAR);
+ g_object_unref(image);
+ image = newimage;
+ }
+
+ /* If we don't have an image, we need to build
+ one so that we can set the pixbuf. */
+ if (gtkimage == NULL) {
+ gtkimage = gtk_image_new_from_pixbuf(image);
+ } else {
+ gtk_image_set_from_pixbuf(GTK_IMAGE(gtkimage), image);
+ }
+ }
+
+ }
+
+ gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(gimi), gtkimage);
+
+ return;
+}
+
+/* This is a type call back for the image type where
+ it uses the GtkImageMenuitem to create the menu item. */
static gboolean
new_item_image (DbusmenuMenuitem * newitem, DbusmenuMenuitem * parent, DbusmenuClient * client)
{
+ g_return_val_if_fail(DBUSMENU_IS_MENUITEM(newitem), FALSE);
+ g_return_val_if_fail(DBUSMENU_IS_GTKCLIENT(client), FALSE);
+ /* Note: not checking parent, it's reasonable for it to be NULL */
+
+ GtkMenuItem * gmi;
+ gmi = GTK_MENU_ITEM(gtk_image_menu_item_new_with_label(dbusmenu_menuitem_property_get(newitem, DBUSMENU_MENUITEM_PROP_LABEL)));
+
+ if (gmi != NULL) {
+ dbusmenu_gtkclient_newitem_base(DBUSMENU_GTKCLIENT(client), newitem, gmi, parent);
+ } else {
+ return FALSE;
+ }
+
+ image_property_handle(newitem,
+ DBUSMENU_MENUITEM_PROP_ICON,
+ dbusmenu_menuitem_property_get(newitem, DBUSMENU_MENUITEM_PROP_ICON),
+ client);
+ image_property_handle(newitem,
+ DBUSMENU_MENUITEM_PROP_ICON_DATA,
+ dbusmenu_menuitem_property_get(newitem, DBUSMENU_MENUITEM_PROP_ICON_DATA),
+ client);
+ g_signal_connect(G_OBJECT(newitem),
+ DBUSMENU_MENUITEM_SIGNAL_PROPERTY_CHANGED,
+ G_CALLBACK(image_property_handle),
+ client);
return TRUE;
}
diff --git a/libdbusmenu-gtk/menuitem.c b/libdbusmenu-gtk/menuitem.c
new file mode 100644
index 0000000..deded06
--- /dev/null
+++ b/libdbusmenu-gtk/menuitem.c
@@ -0,0 +1,130 @@
+/*
+A library to take the object model made consistent by libdbusmenu-glib
+and visualize it in GTK.
+
+Copyright 2009 Canonical Ltd.
+
+Authors:
+ Ted Gould <ted@canonical.com>
+
+This program is free software: you can redistribute it and/or modify it
+under the terms of either or both of the following licenses:
+
+1) the GNU Lesser General Public License version 3, as published by the
+Free Software Foundation; and/or
+2) the GNU Lesser General Public License version 2.1, as published by
+the Free Software Foundation.
+
+This program is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranties of
+MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR
+PURPOSE. See the applicable version of the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of both the GNU Lesser General Public
+License version 3 and version 2.1 along with this program. If not, see
+<http://www.gnu.org/licenses/>
+*/
+
+#include "menuitem.h"
+
+/**
+ dbusmenu_menuitem_property_set_image:
+ @menuitem: The #DbusmenuMenuitem to set the property on.
+ @property: Name of the property to set.
+ @data: The image to place on the property.
+
+ This function takes the pixbuf that is stored in @data and
+ turns it into a base64 encoded PNG so that it can be placed
+ onto a standard #DbusmenuMenuitem property.
+
+ Return value: Whether the function was able to set the property
+ or not.
+*/
+gboolean
+dbusmenu_menuitem_property_set_image (DbusmenuMenuitem * menuitem, const gchar * property, const GdkPixbuf * data)
+{
+ g_return_val_if_fail(GDK_IS_PIXBUF(data), FALSE);
+ g_return_val_if_fail(DBUSMENU_IS_MENUITEM(menuitem), FALSE);
+ g_return_val_if_fail(property != NULL && property[0] != '\0', FALSE);
+
+ GError * error = NULL;
+ gchar * png_data;
+ gsize png_data_len;
+
+ if (!gdk_pixbuf_save_to_buffer((GdkPixbuf *)data, &png_data, &png_data_len, "png", &error, NULL)) {
+ if (error == NULL) {
+ g_warning("Unable to create pixbuf data stream: %d", png_data_len);
+ } else {
+ g_warning("Unable to create pixbuf data stream: %s", error->message);
+ g_error_free(error);
+ error = NULL;
+ }
+
+ return FALSE;
+ }
+
+ gchar * prop_str = g_base64_encode((guchar *)png_data, png_data_len);
+ gboolean propreturn = FALSE;
+ propreturn = dbusmenu_menuitem_property_set(menuitem, property, prop_str);
+
+ g_free(prop_str);
+ g_free(png_data);
+
+ return propreturn;
+}
+
+/**
+ dbusmenu_menuitem_property_get_image:
+ @menuitem: The #DbusmenuMenuite to look for the property on
+ @property: The name of the property to look for.
+
+ This function looks on the menu item for a property by the
+ name of @property. If one exists it tries to turn it into
+ a #GdkPixbuf. It assumes that the property is a base64 encoded
+ PNG file like the one created by #dbusmenu_menuite_property_set_image.
+
+ Return value: A pixbuf or #NULL to signal error.
+*/
+GdkPixbuf *
+dbusmenu_menuitem_property_get_image (DbusmenuMenuitem * menuitem, const gchar * property)
+{
+ g_return_val_if_fail(DBUSMENU_IS_MENUITEM(menuitem), NULL);
+ g_return_val_if_fail(property != NULL && property[0] != '\0', NULL);
+
+ const gchar * value = dbusmenu_menuitem_property_get(menuitem, property);
+
+ /* There is no icon */
+ if (value == NULL || value[0] == '\0') {
+ return NULL;
+ }
+
+ gsize length = 0;
+ guchar * icondata = g_base64_decode(value, &length);
+
+ GInputStream * input = g_memory_input_stream_new_from_data(icondata, length, NULL);
+ if (input == NULL) {
+ g_warning("Cound not create input stream from icon property data");
+ g_free(icondata);
+ return NULL;
+ }
+
+ GError * error = NULL;
+ GdkPixbuf * icon = gdk_pixbuf_new_from_stream(input, NULL, &error);
+
+ if (error != NULL) {
+ g_warning("Unable to build Pixbuf from icon data: %s", error->message);
+ g_error_free(error);
+ }
+
+ error = NULL;
+ g_input_stream_close(input, NULL, &error);
+ if (error != NULL) {
+ g_warning("Unable to close input stream: %s", error->message);
+ g_error_free(error);
+ }
+ g_free(icondata);
+
+ return icon;
+}
+
diff --git a/libdbusmenu-gtk/menuitem.h b/libdbusmenu-gtk/menuitem.h
new file mode 100644
index 0000000..ff458de
--- /dev/null
+++ b/libdbusmenu-gtk/menuitem.h
@@ -0,0 +1,39 @@
+/*
+A library to take the object model made consistent by libdbusmenu-glib
+and visualize it in GTK.
+
+Copyright 2009 Canonical Ltd.
+
+Authors:
+ Ted Gould <ted@canonical.com>
+
+This program is free software: you can redistribute it and/or modify it
+under the terms of either or both of the following licenses:
+
+1) the GNU Lesser General Public License version 3, as published by the
+Free Software Foundation; and/or
+2) the GNU Lesser General Public License version 2.1, as published by
+the Free Software Foundation.
+
+This program is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranties of
+MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR
+PURPOSE. See the applicable version of the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of both the GNU Lesser General Public
+License version 3 and version 2.1 along with this program. If not, see
+<http://www.gnu.org/licenses/>
+*/
+
+#ifndef __DBUSMENU_GTKMENUITEM_H__
+#define __DBUSMENU_GTKMENUITEM_H__ 1
+
+#include <glib.h>
+#include <gdk-pixbuf/gdk-pixbuf.h>
+#include <libdbusmenu-glib/menuitem.h>
+
+gboolean dbusmenu_menuitem_property_set_image (DbusmenuMenuitem * menuitem, const gchar * property, const GdkPixbuf * data);
+GdkPixbuf * dbusmenu_menuitem_property_get_image (DbusmenuMenuitem * menuitem, const gchar * property);
+
+#endif