diff options
author | Ken VanDine <ken.vandine@canonical.com> | 2010-01-08 12:47:52 -0500 |
---|---|---|
committer | Ken VanDine <ken.vandine@canonical.com> | 2010-01-08 12:47:52 -0500 |
commit | f25b2c9f2fb6448506decd9bd89052d3eb94ab4e (patch) | |
tree | dcf63a656d2fb0e26068e800672a00e1c079818d /libdbusmenu-gtk | |
parent | 0ab4e0cd4974e8f2a963b16f9abed2bd6c7eac12 (diff) | |
parent | 214b29a5e3a400b8180bca7f079fbc89ab683644 (diff) | |
download | libdbusmenu-f25b2c9f2fb6448506decd9bd89052d3eb94ab4e.tar.gz libdbusmenu-f25b2c9f2fb6448506decd9bd89052d3eb94ab4e.tar.bz2 libdbusmenu-f25b2c9f2fb6448506decd9bd89052d3eb94ab4e.zip |
* Upstream release 0.2.0
- Remove unused libdbusmenu-qt
- Changing API to be V0.2 for reals
- Adding underline support
- Test suite fixes and automation support
- dbus-dumper tool
- Switch to org.ayatana
- Fixing the handling of typed properties, especially bools.
- Adding GetChildren function for getting a single submenu
- Starting to watch DBus if the proxy builds fail.
- Test suite fixes
- Fixing the consistency between the #defines and what
was used in the code.
* debian/control, debian/libdbusmenu-tools.install: Setting
up a package for the new dbusmenu-dumper tool.
* debian/control: Mentioning nicely that this will cause
indicator-messages << 0.3 and indicator-session << 0.2 to
break.
Diffstat (limited to 'libdbusmenu-gtk')
-rw-r--r-- | libdbusmenu-gtk/Makefile.am | 2 | ||||
-rw-r--r-- | libdbusmenu-gtk/client.c | 157 | ||||
-rw-r--r-- | libdbusmenu-gtk/genericmenuitem.c | 444 | ||||
-rw-r--r-- | libdbusmenu-gtk/genericmenuitem.h | 91 |
4 files changed, 637 insertions, 57 deletions
diff --git a/libdbusmenu-gtk/Makefile.am b/libdbusmenu-gtk/Makefile.am index 87a82a6..97d8563 100644 --- a/libdbusmenu-gtk/Makefile.am +++ b/libdbusmenu-gtk/Makefile.am @@ -15,6 +15,8 @@ libdbusmenu_gtkinclude_HEADERS = \ libdbusmenu_gtk_la_SOURCES = \ client.h \ client.c \ + genericmenuitem.h \ + genericmenuitem.c \ menu.h \ menu.c \ menuitem.h \ diff --git a/libdbusmenu-gtk/client.c b/libdbusmenu-gtk/client.c index fdebc6b..4a8637a 100644 --- a/libdbusmenu-gtk/client.c +++ b/libdbusmenu-gtk/client.c @@ -34,6 +34,7 @@ License version 3 and version 2.1 along with this program. If not, see #include "client.h" #include "menuitem.h" +#include "genericmenuitem.h" /* Prototypes */ static void dbusmenu_gtkclient_class_init (DbusmenuGtkClientClass *klass); @@ -47,10 +48,10 @@ static void move_child (DbusmenuMenuitem * mi, DbusmenuMenuitem * child, guint n static gboolean new_item_normal (DbusmenuMenuitem * newitem, DbusmenuMenuitem * parent, DbusmenuClient * client); 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); +static void process_visible (DbusmenuMenuitem * mi, GtkMenuItem * gmi, const GValue * value); +static void process_sensitive (DbusmenuMenuitem * mi, GtkMenuItem * gmi, const GValue * value); +static void image_property_handle (DbusmenuMenuitem * item, const gchar * property, const GValue * invalue, gpointer userdata); /* GObject Stuff */ G_DEFINE_TYPE (DbusmenuGtkClient, dbusmenu_gtkclient, DBUSMENU_TYPE_CLIENT); @@ -74,7 +75,6 @@ dbusmenu_gtkclient_init (DbusmenuGtkClient *self) { dbusmenu_client_add_type_handler(DBUSMENU_CLIENT(self), DBUSMENU_CLIENT_TYPES_DEFAULT, new_item_normal); dbusmenu_client_add_type_handler(DBUSMENU_CLIENT(self), DBUSMENU_CLIENT_TYPES_SEPARATOR, new_item_seperator); - dbusmenu_client_add_type_handler(DBUSMENU_CLIENT(self), DBUSMENU_CLIENT_TYPES_IMAGE, new_item_image); g_signal_connect(G_OBJECT(self), DBUSMENU_CLIENT_SIGNAL_NEW_MENUITEM, G_CALLBACK(new_menuitem), NULL); @@ -115,9 +115,14 @@ menu_pressed_cb (GtkMenuItem * gmi, DbusmenuMenuitem * mi) /* Process the visible property */ static void -process_visible (GtkMenuItem * gmi, const gchar * value) +process_visible (DbusmenuMenuitem * mi, GtkMenuItem * gmi, const GValue * value) { - if (value == NULL || !g_strcmp0(value, "true")) { + gboolean val = TRUE; + if (value != NULL) { + val = dbusmenu_menuitem_property_get_bool(mi, DBUSMENU_MENUITEM_PROP_VISIBLE); + } + + if (val) { gtk_widget_show(GTK_WIDGET(gmi)); } else { gtk_widget_hide(GTK_WIDGET(gmi)); @@ -127,27 +132,76 @@ process_visible (GtkMenuItem * gmi, const gchar * value) /* Process the sensitive property */ static void -process_sensitive (GtkMenuItem * gmi, const gchar * value) +process_sensitive (DbusmenuMenuitem * mi, GtkMenuItem * gmi, const GValue * 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); + gboolean val = TRUE; + if (value != NULL) { + val = dbusmenu_menuitem_property_get_bool(mi, DBUSMENU_MENUITEM_PROP_SENSITIVE); + } + gtk_widget_set_sensitive(GTK_WIDGET(gmi), val); + return; +} + +/* Process the sensitive property */ +static void +process_toggle_type (DbusmenuMenuitem * mi, GtkMenuItem * gmi, const GValue * value) +{ + if (!IS_GENERICMENUITEM(gmi)) return; + + GenericmenuitemCheckType type = GENERICMENUITEM_CHECK_TYPE_NONE; + + if (value != NULL && G_VALUE_TYPE(value) == G_TYPE_STRING) { + const gchar * strval = g_value_get_string(value); + + if (!g_strcmp0(strval, DBUSMENU_MENUITEM_TOGGLE_CHECK)) { + type = GENERICMENUITEM_CHECK_TYPE_CHECKBOX; + } else if (!g_strcmp0(strval, DBUSMENU_MENUITEM_TOGGLE_RADIO)) { + type = GENERICMENUITEM_CHECK_TYPE_RADIO; + } } + + genericmenuitem_set_check_type(GENERICMENUITEM(gmi), type); + + return; +} + +/* Process the sensitive property */ +static void +process_toggle_checked (DbusmenuMenuitem * mi, GtkMenuItem * gmi, const GValue * value) +{ + if (!IS_GENERICMENUITEM(gmi)) return; + + GenericmenuitemState state = GENERICMENUITEM_STATE_UNCHECKED; + + if (value != NULL && G_VALUE_TYPE(value) == G_TYPE_STRING) { + const gchar * strval = g_value_get_string(value); + + if (!g_strcmp0(strval, DBUSMENU_MENUITEM_TOGGLE_STATE_CHECKED)) { + state = GENERICMENUITEM_STATE_CHECKED; + } else if (!g_strcmp0(strval, DBUSMENU_MENUITEM_TOGGLE_STATE_UNKNOWN)) { + state = GENERICMENUITEM_STATE_INDETERMINATE; + } + } + + genericmenuitem_set_state(GENERICMENUITEM(gmi), state); return; } /* Whenever we have a property change on a DbusmenuMenuitem we need to be responsive to that. */ static void -menu_prop_change_cb (DbusmenuMenuitem * mi, gchar * prop, gchar * value, GtkMenuItem * gmi) +menu_prop_change_cb (DbusmenuMenuitem * mi, gchar * prop, GValue * value, GtkMenuItem * gmi) { if (!g_strcmp0(prop, DBUSMENU_MENUITEM_PROP_LABEL)) { - gtk_menu_item_set_label(gmi, value); + gtk_menu_item_set_label(gmi, g_value_get_string(value)); } else if (!g_strcmp0(prop, DBUSMENU_MENUITEM_PROP_VISIBLE)) { - process_visible(gmi, value); + process_visible(mi, gmi, value); } else if (!g_strcmp0(prop, DBUSMENU_MENUITEM_PROP_SENSITIVE)) { - process_sensitive(gmi, value); + process_sensitive(mi, gmi, value); + } else if (!g_strcmp0(prop, DBUSMENU_MENUITEM_PROP_TOGGLE_TYPE)) { + process_toggle_type(mi, gmi, value); + } else if (!g_strcmp0(prop, DBUSMENU_MENUITEM_PROP_TOGGLE_CHECKED)) { + process_toggle_checked(mi, gmi, value); } return; @@ -228,9 +282,13 @@ dbusmenu_gtkclient_newitem_base (DbusmenuGtkClient * client, DbusmenuMenuitem * /* Life insurance */ 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)); + /* Check our set of props to see if any are set already */ + process_visible(item, gmi, dbusmenu_menuitem_property_get_value(item, DBUSMENU_MENUITEM_PROP_VISIBLE)); + process_sensitive(item, gmi, dbusmenu_menuitem_property_get_value(item, DBUSMENU_MENUITEM_PROP_SENSITIVE)); + process_toggle_type(item, gmi, dbusmenu_menuitem_property_get_value(item, DBUSMENU_MENUITEM_PROP_TOGGLE_TYPE)); + process_toggle_checked(item, gmi, dbusmenu_menuitem_property_get_value(item, DBUSMENU_MENUITEM_PROP_TOGGLE_CHECKED)); + /* Oh, we're a child, let's deal with that */ if (parent != NULL) { new_child(parent, item, dbusmenu_menuitem_get_position(item, parent), DBUSMENU_GTKCLIENT(client)); } @@ -358,8 +416,8 @@ new_item_normal (DbusmenuMenuitem * newitem, DbusmenuMenuitem * parent, Dbusmenu /* Note: not checking parent, it's reasonable for it to be NULL */ GtkMenuItem * gmi; - gmi = GTK_MENU_ITEM(gtk_menu_item_new_with_label(dbusmenu_menuitem_property_get(newitem, DBUSMENU_MENUITEM_PROP_LABEL))); - gtk_menu_item_set_use_underline (gmi, TRUE); + gmi = GTK_MENU_ITEM(g_object_new(GENERICMENUITEM_TYPE, NULL)); + gtk_menu_item_set_label(gmi, dbusmenu_menuitem_property_get(newitem, DBUSMENU_MENUITEM_PROP_LABEL)); if (gmi != NULL) { dbusmenu_gtkclient_newitem_base(DBUSMENU_GTKCLIENT(client), newitem, gmi, parent); @@ -367,6 +425,19 @@ new_item_normal (DbusmenuMenuitem * newitem, DbusmenuMenuitem * parent, Dbusmenu return FALSE; } + image_property_handle(newitem, + DBUSMENU_MENUITEM_PROP_ICON, + dbusmenu_menuitem_property_get_value(newitem, DBUSMENU_MENUITEM_PROP_ICON), + client); + image_property_handle(newitem, + DBUSMENU_MENUITEM_PROP_ICON_DATA, + dbusmenu_menuitem_property_get_value(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; } @@ -394,11 +465,17 @@ new_item_seperator (DbusmenuMenuitem * newitem, DbusmenuMenuitem * parent, Dbusm /* 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) +image_property_handle (DbusmenuMenuitem * item, const gchar * property, const GValue * invalue, 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)); + const gchar * value = NULL; + + if (invalue != NULL && G_VALUE_TYPE(invalue) == G_TYPE_STRING) { + value = g_value_get_string(invalue); + } + if (value == NULL || value[0] == '\0') { /* This means that we're unsetting a value. */ /* Try to use the other one */ @@ -416,12 +493,12 @@ image_property_handle (DbusmenuMenuitem * item, const gchar * property, const gc 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)); + GtkWidget * gtkimage = genericmenuitem_get_image(GENERICMENUITEM(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) { + if (gtkimage != NULL && gtk_image_get_storage_type(GTK_IMAGE(gtkimage)) == GTK_IMAGE_ICON_NAME) { return; } } @@ -474,42 +551,8 @@ image_property_handle (DbusmenuMenuitem * item, const gchar * property, const gc } - gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(gimi), gtkimage); + genericmenuitem_set_image(GENERICMENUITEM(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))); - gtk_menu_item_set_use_underline (gmi, TRUE); - - 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/genericmenuitem.c b/libdbusmenu-gtk/genericmenuitem.c new file mode 100644 index 0000000..f927556 --- /dev/null +++ b/libdbusmenu-gtk/genericmenuitem.c @@ -0,0 +1,444 @@ +/* +A menuitem subclass that has the ability to do lots of different +things depending on it's settings. + +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/> +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "genericmenuitem.h" + +/** + GenericmenuitemPrivate: + @check_type: What type of check we have, or none at all. + @state: What the state of our check is. +*/ +struct _GenericmenuitemPrivate { + GenericmenuitemCheckType check_type; + GenericmenuitemState state; +}; + +/* Private macro */ +#define GENERICMENUITEM_GET_PRIVATE(o) \ +(G_TYPE_INSTANCE_GET_PRIVATE ((o), GENERICMENUITEM_TYPE, GenericmenuitemPrivate)) + +/* Prototypes */ +static void genericmenuitem_class_init (GenericmenuitemClass *klass); +static void genericmenuitem_init (Genericmenuitem *self); +static void genericmenuitem_dispose (GObject *object); +static void genericmenuitem_finalize (GObject *object); +static void draw_indicator (GtkCheckMenuItem *check_menu_item, GdkRectangle *area); +static void set_label (GtkMenuItem * menu_item, const gchar * label); +static const gchar * get_label (GtkMenuItem * menu_item); +static void activate (GtkMenuItem * menu_item); + +/* GObject stuff */ +G_DEFINE_TYPE (Genericmenuitem, genericmenuitem, GTK_TYPE_CHECK_MENU_ITEM); + +/* Globals */ +static void (*parent_draw_indicator) (GtkCheckMenuItem *check_menu_item, GdkRectangle *area) = NULL; + +/* Initializing all of the classes. Most notably we're + disabling the drawing of the check early. */ +static void +genericmenuitem_class_init (GenericmenuitemClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + g_type_class_add_private (klass, sizeof (GenericmenuitemPrivate)); + + object_class->dispose = genericmenuitem_dispose; + object_class->finalize = genericmenuitem_finalize; + + GtkCheckMenuItemClass * check_class = GTK_CHECK_MENU_ITEM_CLASS (klass); + + parent_draw_indicator = check_class->draw_indicator; + check_class->draw_indicator = draw_indicator; + + GtkMenuItemClass * menuitem_class = GTK_MENU_ITEM_CLASS (klass); + menuitem_class->set_label = set_label; + menuitem_class->get_label = get_label; + menuitem_class->activate = activate; + + return; +} + +/* Sets default values for all the class variables. Mostly, + this puts us in a default state. */ +static void +genericmenuitem_init (Genericmenuitem *self) +{ + self->priv = GENERICMENUITEM_GET_PRIVATE(self); + + self->priv->check_type = GENERICMENUITEM_CHECK_TYPE_NONE; + self->priv->state = GENERICMENUITEM_STATE_UNCHECKED; + + return; +} + +/* Clean everything up. Whew, that can be work. */ +static void +genericmenuitem_dispose (GObject *object) +{ + + G_OBJECT_CLASS (genericmenuitem_parent_class)->dispose (object); + return; +} + +/* Now free memory, we no longer need it. */ +static void +genericmenuitem_finalize (GObject *object) +{ + + G_OBJECT_CLASS (genericmenuitem_parent_class)->finalize (object); + return; +} + +/* Checks to see if we should be drawing a little box at + all. If we should be, let's do that, otherwise we're + going suppress the box drawing. */ +static void +draw_indicator (GtkCheckMenuItem *check_menu_item, GdkRectangle *area) +{ + Genericmenuitem * self = GENERICMENUITEM(check_menu_item); + if (self->priv->check_type != GENERICMENUITEM_CHECK_TYPE_NONE) { + parent_draw_indicator(check_menu_item, area); + } + return; +} + +/* A small helper to look through the widgets in the + box and find the one that is the label. */ +static void +set_label_helper (GtkWidget * widget, gpointer data) +{ + GtkWidget ** labelval = (GtkWidget **)data; + if (GTK_IS_LABEL(widget)) { + *labelval = widget; + } + return; +} + +/* Set the label on the item */ +static void +set_label (GtkMenuItem * menu_item, const gchar * label) +{ + GtkWidget * child = gtk_bin_get_child(GTK_BIN(menu_item)); + GtkLabel * labelw = NULL; + gboolean suppress_update = FALSE; + + /* Try to find if we have a label already */ + if (child != NULL) { + if (GTK_IS_LABEL(child)) { + /* We've got a label, let's update it. */ + labelw = GTK_LABEL(child); + } else if (GTK_IS_BOX(child)) { + /* Look for the label in the box */ + gtk_container_foreach(GTK_CONTAINER(child), set_label_helper, &labelw); + } else { + /* We need to put the child into a new box and + make the box the child of the menu item. Basically + we're inserting a box in the middle. */ + GtkWidget * hbox = gtk_hbox_new(FALSE, 0); + g_object_ref(child); + gtk_container_remove(GTK_CONTAINER(menu_item), child); + gtk_box_pack_start(GTK_BOX(hbox), child, FALSE, FALSE, 0); + gtk_container_add(GTK_CONTAINER(menu_item), hbox); + gtk_widget_show(hbox); + g_object_unref(child); + child = hbox; + /* It's important to notice that labelw is not set + by this condition. There was no label to find. */ + } + } + + /* No we can see if we need to ethier build a label or just + update the one that we already have. */ + if (labelw == NULL) { + /* Build it */ + labelw = GTK_LABEL(gtk_label_new(label)); + gtk_label_set_use_underline(GTK_LABEL(labelw), TRUE); + gtk_misc_set_alignment(GTK_MISC(labelw), 0.0, 0.5); + gtk_widget_show(GTK_WIDGET(labelw)); + + /* Check to see if it needs to be in the bin for this + menu item or whether it gets packed in a box. */ + if (child == NULL) { + gtk_container_add(GTK_CONTAINER(menu_item), GTK_WIDGET(labelw)); + } else { + gtk_box_pack_end(GTK_BOX(child), GTK_WIDGET(labelw), TRUE, TRUE, 0); + } + } else { + /* Oh, just an update. No biggie. */ + if (!g_strcmp0(label, gtk_label_get_label(labelw))) { + /* The only reason to suppress the update is if we had + a label and the value was the same as the one we're + getting in. */ + suppress_update = TRUE; + } else { + gtk_label_set_label(labelw, label); + } + } + + /* If we changed the value, tell folks. */ + if (!suppress_update) { + g_object_notify(G_OBJECT(menu_item), "label"); + } + + return; +} + +/* Get the text of the label for the item */ +static const gchar * +get_label (GtkMenuItem * menu_item) +{ + GtkWidget * child = gtk_bin_get_child(GTK_BIN(menu_item)); + GtkLabel * labelw = NULL; + + /* Try to find if we have a label already */ + if (child != NULL) { + if (GTK_IS_LABEL(child)) { + /* We've got a label, let's update it. */ + labelw = GTK_LABEL(child); + } else if (GTK_IS_BOX(child)) { + /* Look for the label in the box */ + gtk_container_foreach(GTK_CONTAINER(child), set_label_helper, &labelw); + } + } + + if (labelw != NULL) { + return gtk_label_get_label(labelw); + } + + return NULL; +} + +/* Make sure we don't toggle when there is an + activate like a normal check menu item. */ +static void +activate (GtkMenuItem * menu_item) +{ + return; +} + +/** + genericmenuitem_set_check_type: + @item: #Genericmenuitem to set the type on + @check_type: Which type of check should be displayed + + This function changes the type of the checkmark that + appears in the left hand gutter for the menuitem. +*/ +void +genericmenuitem_set_check_type (Genericmenuitem * item, GenericmenuitemCheckType check_type) +{ + if (item->priv->check_type == check_type) { + return; + } + + item->priv->check_type = check_type; + GValue value = {0}; + + switch (item->priv->check_type) { + case GENERICMENUITEM_CHECK_TYPE_NONE: + /* We don't need to do anything here as we're queuing the + draw and then when it draws it'll avoid drawing the + check on the item. */ + break; + case GENERICMENUITEM_CHECK_TYPE_CHECKBOX: + g_value_init(&value, G_TYPE_BOOLEAN); + g_value_set_boolean(&value, FALSE); + g_object_set_property(G_OBJECT(item), "draw-as-radio", &value); + break; + case GENERICMENUITEM_CHECK_TYPE_RADIO: + g_value_init(&value, G_TYPE_BOOLEAN); + g_value_set_boolean(&value, TRUE); + g_object_set_property(G_OBJECT(item), "draw-as-radio", &value); + break; + default: + g_warning("Generic Menuitem invalid check type: %d", check_type); + return; + } + + gtk_widget_queue_draw(GTK_WIDGET(item)); + + return; +} + +/** + genericmenuitem_set_state: + @item: #Genericmenuitem to set the type on + @check_type: What is the state of the check + + Sets the state of the check in the menu item. It does + not require, but isn't really useful if the type of + check that the menuitem is set to #GENERICMENUITEM_CHECK_TYPE_NONE. +*/ +void +genericmenuitem_set_state (Genericmenuitem * item, GenericmenuitemState state) +{ + if (item->priv->state == state) { + return; + } + + item->priv->state = state; + + GtkCheckMenuItem * check = GTK_CHECK_MENU_ITEM(item); + + gboolean old_active = check->active; + gboolean old_inconsist = check->inconsistent; + + switch (item->priv->state) { + case GENERICMENUITEM_STATE_UNCHECKED: + check->active = FALSE; + check->inconsistent = FALSE; + break; + case GENERICMENUITEM_STATE_CHECKED: + check->active = TRUE; + check->inconsistent = FALSE; + break; + case GENERICMENUITEM_STATE_INDETERMINATE: + check->active = TRUE; + check->inconsistent = TRUE; + break; + default: + g_warning("Generic Menuitem invalid check state: %d", state); + return; + } + + if (old_active != check->active) { + g_object_notify(G_OBJECT(item), "active"); + } + + if (old_inconsist != check->inconsistent) { + g_object_notify(G_OBJECT(item), "inconsistent"); + } + + gtk_widget_queue_draw(GTK_WIDGET(item)); + + return; +} + +/* A small helper to look through the widgets in the + box and find the one that is the image. */ +static void +set_image_helper (GtkWidget * widget, gpointer data) +{ + GtkWidget ** labelval = (GtkWidget **)data; + if (GTK_IS_IMAGE(widget)) { + *labelval = widget; + } + return; +} + +/** + genericmenuitem_set_image: + @item: A #Genericmenuitem + @image: The image to set as the image of @item + + Sets the image of the menu item. +*/ +void +genericmenuitem_set_image (Genericmenuitem * menu_item, GtkWidget * image) +{ + GtkWidget * child = gtk_bin_get_child(GTK_BIN(menu_item)); + GtkImage * imagew = NULL; + + /* Try to find if we have a label already */ + if (child != NULL) { + if (GTK_IS_IMAGE(child)) { + /* We've got a label, let's update it. */ + imagew = GTK_IMAGE(child); + } else if (GTK_IS_BOX(child)) { + /* Look for the label in the box */ + gtk_container_foreach(GTK_CONTAINER(child), set_image_helper, &imagew); + } else if (image != NULL) { + /* We need to put the child into a new box and + make the box the child of the menu item. Basically + we're inserting a box in the middle. */ + GtkWidget * hbox = gtk_hbox_new(FALSE, 0); + g_object_ref(child); + gtk_container_remove(GTK_CONTAINER(menu_item), child); + gtk_box_pack_end(GTK_BOX(hbox), child, TRUE, TRUE, 0); + gtk_container_add(GTK_CONTAINER(menu_item), hbox); + gtk_widget_show(hbox); + g_object_unref(child); + child = hbox; + /* It's important to notice that imagew is not set + by this condition. There was no label to find. */ + } + } + + /* No we can see if we need to ethier replace and image or + just put ourselves into the structures */ + if (imagew != NULL) { + gtk_widget_destroy(GTK_WIDGET(imagew)); + } + + /* Check to see if it needs to be in the bin for this + menu item or whether it gets packed in a box. */ + if (image != NULL) { + if (child == NULL) { + gtk_container_add(GTK_CONTAINER(menu_item), GTK_WIDGET(image)); + } else { + gtk_box_pack_start(GTK_BOX(child), GTK_WIDGET(image), FALSE, FALSE, 0); + } + + gtk_widget_show(image); + } + + return; +} + +/** + genericmenuitem_get_image: + @item: A #Genericmenuitem + + Returns the image if there is one. + + Return value: A pointer to the image of the item or #NULL + if there isn't one. +*/ +GtkWidget * +genericmenuitem_get_image (Genericmenuitem * menu_item) +{ + GtkWidget * child = gtk_bin_get_child(GTK_BIN(menu_item)); + GtkWidget * imagew = NULL; + + /* Try to find if we have a label already */ + if (child != NULL) { + if (GTK_IS_IMAGE(child)) { + /* We've got a label, let's update it. */ + imagew = child; + } else if (GTK_IS_BOX(child)) { + /* Look for the label in the box */ + gtk_container_foreach(GTK_CONTAINER(child), set_image_helper, &imagew); + } + } + + return imagew; +} diff --git a/libdbusmenu-gtk/genericmenuitem.h b/libdbusmenu-gtk/genericmenuitem.h new file mode 100644 index 0000000..3c4af0c --- /dev/null +++ b/libdbusmenu-gtk/genericmenuitem.h @@ -0,0 +1,91 @@ +/* +A menuitem subclass that has the ability to do lots of different +things depending on it's settings. + +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 __GENERICMENUITEM_H__ +#define __GENERICMENUITEM_H__ + +#include <glib.h> +#include <glib-object.h> +#include <gtk/gtk.h> + +G_BEGIN_DECLS + +#define GENERICMENUITEM_TYPE (genericmenuitem_get_type ()) +#define GENERICMENUITEM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GENERICMENUITEM_TYPE, Genericmenuitem)) +#define GENERICMENUITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GENERICMENUITEM_TYPE, GenericmenuitemClass)) +#define IS_GENERICMENUITEM(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GENERICMENUITEM_TYPE)) +#define IS_GENERICMENUITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GENERICMENUITEM_TYPE)) +#define GENERICMENUITEM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GENERICMENUITEM_TYPE, GenericmenuitemClass)) + +typedef struct _Genericmenuitem Genericmenuitem; +typedef struct _GenericmenuitemClass GenericmenuitemClass; +typedef struct _GenericmenuitemPrivate GenericmenuitemPrivate; +typedef enum _GenericmenuitemCheckType GenericmenuitemCheckType; +typedef enum _GenericmenuitemState GenericmenuitemState; + +/** + GenericmenuitemClass: + @parent_class: Our parent #GtkCheckMenuItemClass +*/ +struct _GenericmenuitemClass { + GtkCheckMenuItemClass parent_class; +}; + +/** + Genericmenuitem: + @parent: Our parent #GtkCheckMenuItem +*/ +struct _Genericmenuitem { + GtkCheckMenuItem parent; + GenericmenuitemPrivate * priv; +}; + +enum _GenericmenuitemCheckType { + GENERICMENUITEM_CHECK_TYPE_NONE, + GENERICMENUITEM_CHECK_TYPE_CHECKBOX, + GENERICMENUITEM_CHECK_TYPE_RADIO +}; + +enum _GenericmenuitemState { + GENERICMENUITEM_STATE_UNCHECKED, + GENERICMENUITEM_STATE_CHECKED, + GENERICMENUITEM_STATE_INDETERMINATE +}; + +GType genericmenuitem_get_type (void); +void genericmenuitem_set_check_type (Genericmenuitem * item, + GenericmenuitemCheckType check_type); +void genericmenuitem_set_state (Genericmenuitem * item, + GenericmenuitemState state); +void genericmenuitem_set_image (Genericmenuitem * item, + GtkWidget * image); +GtkWidget * genericmenuitem_get_image (Genericmenuitem * item); + +G_END_DECLS + +#endif |