From bf3b14f5c5105c63816b9555dffb3bf3e273c602 Mon Sep 17 00:00:00 2001 From: Charles Kerr Date: Tue, 26 Mar 2013 15:05:06 -0500 Subject: add user-widget.[ch] from indicator-session's trunk --- src/user-widget.c | 292 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/user-widget.h | 55 ++++++++++ 2 files changed, 347 insertions(+) create mode 100644 src/user-widget.c create mode 100644 src/user-widget.h diff --git a/src/user-widget.c b/src/user-widget.c new file mode 100644 index 0000000..79b87b0 --- /dev/null +++ b/src/user-widget.c @@ -0,0 +1,292 @@ +/* +Copyright 2011 Canonical Ltd. + +Authors: + Conor Curran + Mirco Müller + Charles Kerr + +This program is free software: you can redistribute it and/or modify it +under the terms of the GNU General Public License version 3, 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 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 . +*/ + +#ifdef HAVE_CONFIG_H + #include "config.h" +#endif + +#include + +#include + +#include "shared-names.h" +#include "user-widget.h" + + +typedef struct _UserWidgetPrivate UserWidgetPrivate; + +struct _UserWidgetPrivate +{ + DbusmenuMenuitem* twin_item; + GtkWidget* user_image; + GtkWidget* user_name; + GtkWidget* container; + GtkWidget* tick_icon; + gboolean logged_in; + gboolean sessions_active; +}; + +#define USER_WIDGET_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), USER_WIDGET_TYPE, UserWidgetPrivate)) + +/* Prototypes */ +static void user_widget_class_init (UserWidgetClass *klass); +static void user_widget_init (UserWidget *self); +static void user_widget_dispose (GObject *object); +static void user_widget_finalize (GObject *object); + +static void user_widget_set_twin_item (UserWidget* self, + DbusmenuMenuitem* twin_item); + +static gboolean user_widget_primitive_draw_cb_gtk_3 (GtkWidget *image, + cairo_t* cr, + gpointer user_data); + +G_DEFINE_TYPE (UserWidget, user_widget, GTK_TYPE_MENU_ITEM); + +static void +user_widget_class_init (UserWidgetClass *klass) +{ + GObjectClass * gobject_class = G_OBJECT_CLASS (klass); + + g_type_class_add_private (klass, sizeof (UserWidgetPrivate)); + + gobject_class->dispose = user_widget_dispose; + gobject_class->finalize = user_widget_finalize; +} + +static void +user_widget_init (UserWidget *self) +{ + self->priv = USER_WIDGET_GET_PRIVATE(self); + + UserWidgetPrivate * priv = self->priv; + + priv->user_image = NULL; + priv->user_name = NULL; + priv->logged_in = FALSE; + priv->sessions_active = FALSE; + priv->container = NULL; + priv->tick_icon = NULL; + + // Create the UI elements. + priv->user_image = gtk_image_new (); + gtk_misc_set_alignment(GTK_MISC(priv->user_image), 0.0, 0.0); + + priv->user_name = gtk_label_new (NULL); + + priv->container = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 4); + + priv->tick_icon = gtk_image_new_from_icon_name ("account-logged-in", + GTK_ICON_SIZE_MENU); + gtk_misc_set_alignment(GTK_MISC(priv->tick_icon), 1.0, 0.5); + + // Pack it together + gtk_box_pack_start (GTK_BOX (priv->container), + priv->user_image, + FALSE, + FALSE, + 0); + gtk_box_pack_start (GTK_BOX (priv->container), + priv->user_name, + FALSE, + FALSE, + 3); + gtk_box_pack_end (GTK_BOX(priv->container), + priv->tick_icon, + FALSE, + FALSE, 5); + + gtk_widget_show_all (priv->container); + gtk_container_add (GTK_CONTAINER (self), priv->container); + gtk_widget_show_all (priv->tick_icon); + gtk_widget_set_no_show_all (priv->tick_icon, TRUE); + gtk_widget_hide (priv->tick_icon); + + + // Fetch the drawing context. + g_signal_connect_after (GTK_WIDGET(self), "draw", + G_CALLBACK(user_widget_primitive_draw_cb_gtk_3), + GTK_WIDGET(self)); +} + +static void +user_widget_dispose (GObject *object) +{ + G_OBJECT_CLASS (user_widget_parent_class)->dispose (object); +} + +// TODO tidy up image and name +static void +user_widget_finalize (GObject *object) +{ + G_OBJECT_CLASS (user_widget_parent_class)->finalize (object); +} + + +/*****************************************************************/ + +// TODO handle drawing of green check mark +static gboolean +user_widget_primitive_draw_cb_gtk_3 (GtkWidget *widget, + cairo_t* cr, + gpointer user_data) +{ + g_return_val_if_fail(IS_USER_WIDGET(user_data), FALSE); + UserWidget* meta = USER_WIDGET(user_data); + UserWidgetPrivate * priv = USER_WIDGET_GET_PRIVATE(meta); + + // Draw dot only when user is the current user. + if (dbusmenu_menuitem_property_get_bool (priv->twin_item, USER_ITEM_PROP_IS_CURRENT_USER)) + { + gdouble x, y; + GtkStyle * style = gtk_widget_get_style (widget); + + GtkAllocation allocation; + gtk_widget_get_allocation (widget, &allocation); + x = allocation.x + 13; + y = allocation.height / 2; + + cairo_arc (cr, x, y, 3.0, 0.0, 2 * G_PI); + + cairo_set_source_rgb (cr, style->fg[gtk_widget_get_state(widget)].red/65535.0, + style->fg[gtk_widget_get_state(widget)].green/65535.0, + style->fg[gtk_widget_get_state(widget)].blue/65535.0); + cairo_fill (cr); + } + + return FALSE; +} + +/*** +**** +***/ + +static void +update_icon (UserWidget * self, DbusmenuMenuitem * mi) +{ + gboolean updated = FALSE; + GtkImage * image = GTK_IMAGE(self->priv->user_image); + + /* first try the menuitem's icon property */ + const gchar * icon_name = dbusmenu_menuitem_property_get (mi, USER_ITEM_PROP_ICON); + if (icon_name != NULL) + { + int width = 18; /* arbitrary default values */ + int height = 18; + GError * err = NULL; + GdkPixbuf * pixbuf = NULL; + + /* load the image */ + gtk_icon_size_lookup (GTK_ICON_SIZE_MENU, &width, &height); + pixbuf = gdk_pixbuf_new_from_file_at_size (icon_name, width, height, &err); + if (err == NULL) + { + gtk_image_set_from_pixbuf (image, pixbuf); + g_object_unref (pixbuf); + updated = TRUE; + } + else + { + g_warning ("Couldn't load the image \"%s\": %s", icon_name, err->message); + g_clear_error (&err); + } + } + + /* as a fallback, use the default user icon */ + if (!updated) + { + gtk_image_set_from_icon_name (image, + USER_ITEM_ICON_DEFAULT, + GTK_ICON_SIZE_MENU); + } +} + +static void +update_logged_in (UserWidget * self, DbusmenuMenuitem * mi) +{ + const gboolean b = dbusmenu_menuitem_property_get_bool (mi, USER_ITEM_PROP_LOGGED_IN); + + g_debug ("User \"%s\" %s active sessions", + dbusmenu_menuitem_property_get (mi, USER_ITEM_PROP_NAME), + b ? "has" : "doesn't have"); + + gtk_widget_set_visible (self->priv->tick_icon, b); +} + +static void +update_name (UserWidget * self, DbusmenuMenuitem * mi) +{ + gtk_label_set_label (GTK_LABEL(self->priv->user_name), + dbusmenu_menuitem_property_get (mi, USER_ITEM_PROP_NAME)); +} + +static void +user_widget_property_update (DbusmenuMenuitem * mi, + const gchar * property, + GVariant * value, + UserWidget * self) +{ + g_return_if_fail (IS_USER_WIDGET (self)); + + if (!g_strcmp0 (property, USER_ITEM_PROP_LOGGED_IN)) + { + update_logged_in (self, mi); + } + else if (!g_strcmp0 (property, USER_ITEM_PROP_ICON)) + { + update_icon (self, mi); + } + else if (!g_strcmp0 (property, USER_ITEM_PROP_NAME)) + { + update_name (self, mi); + } + else + { + g_debug ("%s FIXME: unhandled property change %s", G_STRFUNC, property); + } +} + +static void +user_widget_set_twin_item (UserWidget * self, DbusmenuMenuitem * mi) +{ + self->priv->twin_item = mi; + + update_icon (self, mi); + update_name (self, mi); + update_logged_in (self, mi); + + g_signal_connect (G_OBJECT(mi), "property-changed", + G_CALLBACK(user_widget_property_update), self); +} + + /** + * user_widget_new: + * @item: the #DbusmenuMenuitem this widget will render. + * + * Returns: (transfer full): a new #UserWidget. + **/ +GtkWidget* +user_widget_new (DbusmenuMenuitem *item) +{ + GtkWidget* widget = g_object_new(USER_WIDGET_TYPE, NULL); + user_widget_set_twin_item ( USER_WIDGET(widget), item ); + return widget; +} diff --git a/src/user-widget.h b/src/user-widget.h new file mode 100644 index 0000000..0953e6c --- /dev/null +++ b/src/user-widget.h @@ -0,0 +1,55 @@ +/* +Copyright 2011 Canonical Ltd. + +Authors: + Conor Curran + +This program is free software: you can redistribute it and/or modify it +under the terms of the GNU General Public License version 3, 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 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 . +*/ +#ifndef __USER_WIDGET_H__ +#define __USER_WIDGET_H__ + +#include +#include + +G_BEGIN_DECLS + +#define USER_WIDGET_TYPE (user_widget_get_type ()) +#define USER_WIDGET(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), USER_WIDGET_TYPE, UserWidget)) +#define USER_WIDGET_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), USER_WIDGET_TYPE, UserWidgetClass)) +#define IS_USER_WIDGET(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), USER_WIDGET_TYPE)) +#define IS_USER_WIDGET_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), USER_WIDGET_TYPE)) +#define USER_WIDGET_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), USER_WIDGET_TYPE, UserWidgetClass)) + +typedef struct _UserWidget UserWidget; +typedef struct _UserWidgetClass UserWidgetClass; +typedef struct _UserWidgetPrivate UserWidgetPrivate; + +struct _UserWidgetClass +{ + GtkMenuItemClass parent_class; +}; + +struct _UserWidget +{ + /*< private >*/ + GtkMenuItem parent; + UserWidgetPrivate * priv; +}; + +GType user_widget_get_type (void) G_GNUC_CONST; +GtkWidget* user_widget_new(DbusmenuMenuitem *twin_item); + +G_END_DECLS + +#endif -- cgit v1.2.3 From 2d8eac6ae37a5615c846953410e1576faf5bc677 Mon Sep 17 00:00:00 2001 From: Charles Kerr Date: Tue, 26 Mar 2013 15:14:33 -0500 Subject: rename user-widget.[ch] to idousermenuitem.[ch]. Not building yet, next step is to decouple from dbusmenu. --- src/Makefile.am | 2 + src/idousermenuitem.c | 289 +++++++++++++++++++++++++++++++++++++++++++++++++ src/idousermenuitem.h | 55 ++++++++++ src/user-widget.c | 292 -------------------------------------------------- src/user-widget.h | 55 ---------- 5 files changed, 346 insertions(+), 347 deletions(-) create mode 100644 src/idousermenuitem.c create mode 100644 src/idousermenuitem.h delete mode 100644 src/user-widget.c delete mode 100644 src/user-widget.h diff --git a/src/Makefile.am b/src/Makefile.am index e14efbf..6e1d813 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -17,6 +17,7 @@ sources_h = \ idorange.h \ idoscalemenuitem.h \ idoswitchmenuitem.h \ + idousermenuitem.h \ idotimeline.h \ libido.h @@ -66,6 +67,7 @@ libido_0_1_la_SOURCES = \ idorange.c \ idoscalemenuitem.c \ idoswitchmenuitem.c \ + idousermenuitem.c \ idotimeline.c libido3_0_1_la_SOURCES = $(libido_0_1_la_SOURCES) diff --git a/src/idousermenuitem.c b/src/idousermenuitem.c new file mode 100644 index 0000000..620df8d --- /dev/null +++ b/src/idousermenuitem.c @@ -0,0 +1,289 @@ +/* +Copyright 2011 Canonical Ltd. + +Authors: + Conor Curran + Mirco Müller + Charles Kerr + +This program is free software: you can redistribute it and/or modify it +under the terms of the GNU General Public License version 3, 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 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 . +*/ + +#ifdef HAVE_CONFIG_H + #include "config.h" +#endif + +#include + +#include "idousermenuitem.h" + + +typedef struct _IdoUserMenuItemPrivate IdoUserMenuItemPrivate; + +struct _IdoUserMenuItemPrivate +{ + DbusmenuMenuitem* twin_item; + GtkWidget* user_image; + GtkWidget* user_name; + GtkWidget* container; + GtkWidget* tick_icon; + gboolean logged_in; + gboolean sessions_active; +}; + +#define USER_WIDGET_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), USER_WIDGET_TYPE, IdoUserMenuItemPrivate)) + +/* Prototypes */ +static void user_widget_class_init (IdoUserMenuItemClass *klass); +static void user_widget_init (IdoUserMenuItem *self); +static void user_widget_dispose (GObject *object); +static void user_widget_finalize (GObject *object); + +static void user_widget_set_twin_item (IdoUserMenuItem* self, + DbusmenuMenuitem* twin_item); + +static gboolean user_widget_primitive_draw_cb_gtk_3 (GtkWidget *image, + cairo_t* cr, + gpointer user_data); + +G_DEFINE_TYPE (IdoUserMenuItem, user_widget, GTK_TYPE_MENU_ITEM); + +static void +user_widget_class_init (IdoUserMenuItemClass *klass) +{ + GObjectClass * gobject_class = G_OBJECT_CLASS (klass); + + g_type_class_add_private (klass, sizeof (IdoUserMenuItemPrivate)); + + gobject_class->dispose = user_widget_dispose; + gobject_class->finalize = user_widget_finalize; +} + +static void +user_widget_init (IdoUserMenuItem *self) +{ + self->priv = USER_WIDGET_GET_PRIVATE(self); + + IdoUserMenuItemPrivate * priv = self->priv; + + priv->user_image = NULL; + priv->user_name = NULL; + priv->logged_in = FALSE; + priv->sessions_active = FALSE; + priv->container = NULL; + priv->tick_icon = NULL; + + // Create the UI elements. + priv->user_image = gtk_image_new (); + gtk_misc_set_alignment(GTK_MISC(priv->user_image), 0.0, 0.0); + + priv->user_name = gtk_label_new (NULL); + + priv->container = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 4); + + priv->tick_icon = gtk_image_new_from_icon_name ("account-logged-in", + GTK_ICON_SIZE_MENU); + gtk_misc_set_alignment(GTK_MISC(priv->tick_icon), 1.0, 0.5); + + // Pack it together + gtk_box_pack_start (GTK_BOX (priv->container), + priv->user_image, + FALSE, + FALSE, + 0); + gtk_box_pack_start (GTK_BOX (priv->container), + priv->user_name, + FALSE, + FALSE, + 3); + gtk_box_pack_end (GTK_BOX(priv->container), + priv->tick_icon, + FALSE, + FALSE, 5); + + gtk_widget_show_all (priv->container); + gtk_container_add (GTK_CONTAINER (self), priv->container); + gtk_widget_show_all (priv->tick_icon); + gtk_widget_set_no_show_all (priv->tick_icon, TRUE); + gtk_widget_hide (priv->tick_icon); + + + // Fetch the drawing context. + g_signal_connect_after (GTK_WIDGET(self), "draw", + G_CALLBACK(user_widget_primitive_draw_cb_gtk_3), + GTK_WIDGET(self)); +} + +static void +user_widget_dispose (GObject *object) +{ + G_OBJECT_CLASS (user_widget_parent_class)->dispose (object); +} + +// TODO tidy up image and name +static void +user_widget_finalize (GObject *object) +{ + G_OBJECT_CLASS (user_widget_parent_class)->finalize (object); +} + + +/*****************************************************************/ + +// TODO handle drawing of green check mark +static gboolean +user_widget_primitive_draw_cb_gtk_3 (GtkWidget *widget, + cairo_t* cr, + gpointer user_data) +{ + g_return_val_if_fail(IS_USER_WIDGET(user_data), FALSE); + IdoUserMenuItem* meta = USER_WIDGET(user_data); + IdoUserMenuItemPrivate * priv = USER_WIDGET_GET_PRIVATE(meta); + + // Draw dot only when user is the current user. + if (dbusmenu_menuitem_property_get_bool (priv->twin_item, USER_ITEM_PROP_IS_CURRENT_USER)) + { + gdouble x, y; + GtkStyle * style = gtk_widget_get_style (widget); + + GtkAllocation allocation; + gtk_widget_get_allocation (widget, &allocation); + x = allocation.x + 13; + y = allocation.height / 2; + + cairo_arc (cr, x, y, 3.0, 0.0, 2 * G_PI); + + cairo_set_source_rgb (cr, style->fg[gtk_widget_get_state(widget)].red/65535.0, + style->fg[gtk_widget_get_state(widget)].green/65535.0, + style->fg[gtk_widget_get_state(widget)].blue/65535.0); + cairo_fill (cr); + } + + return FALSE; +} + +/*** +**** +***/ + +static void +update_icon (IdoUserMenuItem * self, DbusmenuMenuitem * mi) +{ + gboolean updated = FALSE; + GtkImage * image = GTK_IMAGE(self->priv->user_image); + + /* first try the menuitem's icon property */ + const gchar * icon_name = dbusmenu_menuitem_property_get (mi, USER_ITEM_PROP_ICON); + if (icon_name != NULL) + { + int width = 18; /* arbitrary default values */ + int height = 18; + GError * err = NULL; + GdkPixbuf * pixbuf = NULL; + + /* load the image */ + gtk_icon_size_lookup (GTK_ICON_SIZE_MENU, &width, &height); + pixbuf = gdk_pixbuf_new_from_file_at_size (icon_name, width, height, &err); + if (err == NULL) + { + gtk_image_set_from_pixbuf (image, pixbuf); + g_object_unref (pixbuf); + updated = TRUE; + } + else + { + g_warning ("Couldn't load the image \"%s\": %s", icon_name, err->message); + g_clear_error (&err); + } + } + + /* as a fallback, use the default user icon */ + if (!updated) + { + gtk_image_set_from_icon_name (image, + USER_ITEM_ICON_DEFAULT, + GTK_ICON_SIZE_MENU); + } +} + +static void +update_logged_in (IdoUserMenuItem * self, DbusmenuMenuitem * mi) +{ + const gboolean b = dbusmenu_menuitem_property_get_bool (mi, USER_ITEM_PROP_LOGGED_IN); + + g_debug ("User \"%s\" %s active sessions", + dbusmenu_menuitem_property_get (mi, USER_ITEM_PROP_NAME), + b ? "has" : "doesn't have"); + + gtk_widget_set_visible (self->priv->tick_icon, b); +} + +static void +update_name (IdoUserMenuItem * self, DbusmenuMenuitem * mi) +{ + gtk_label_set_label (GTK_LABEL(self->priv->user_name), + dbusmenu_menuitem_property_get (mi, USER_ITEM_PROP_NAME)); +} + +static void +user_widget_property_update (DbusmenuMenuitem * mi, + const gchar * property, + GVariant * value, + IdoUserMenuItem * self) +{ + g_return_if_fail (IS_USER_WIDGET (self)); + + if (!g_strcmp0 (property, USER_ITEM_PROP_LOGGED_IN)) + { + update_logged_in (self, mi); + } + else if (!g_strcmp0 (property, USER_ITEM_PROP_ICON)) + { + update_icon (self, mi); + } + else if (!g_strcmp0 (property, USER_ITEM_PROP_NAME)) + { + update_name (self, mi); + } + else + { + g_debug ("%s FIXME: unhandled property change %s", G_STRFUNC, property); + } +} + +static void +user_widget_set_twin_item (IdoUserMenuItem * self, DbusmenuMenuitem * mi) +{ + self->priv->twin_item = mi; + + update_icon (self, mi); + update_name (self, mi); + update_logged_in (self, mi); + + g_signal_connect (G_OBJECT(mi), "property-changed", + G_CALLBACK(user_widget_property_update), self); +} + + /** + * user_widget_new: + * @item: the #DbusmenuMenuitem this widget will render. + * + * Returns: (transfer full): a new #IdoUserMenuItem. + **/ +GtkWidget* +user_widget_new (DbusmenuMenuitem *item) +{ + GtkWidget* widget = g_object_new(USER_WIDGET_TYPE, NULL); + user_widget_set_twin_item ( USER_WIDGET(widget), item ); + return widget; +} diff --git a/src/idousermenuitem.h b/src/idousermenuitem.h new file mode 100644 index 0000000..ac115a8 --- /dev/null +++ b/src/idousermenuitem.h @@ -0,0 +1,55 @@ +/* +Copyright 2011 Canonical Ltd. + +Authors: + Conor Curran + +This program is free software: you can redistribute it and/or modify it +under the terms of the GNU General Public License version 3, 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 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 . +*/ +#ifndef __IDO_USER_MENU_ITEM_H__ +#define __IDO_USER_MENU_ITEM_H__ + +#include +#include + +G_BEGIN_DECLS + +#define IDO_USER_MENU_ITEM_TYPE (ido_user_menu_item_get_type ()) +#define IDO_USER_MENU_ITEM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), IDO_USER_MENU_ITEM_TYPE, IdoUserMenuItem)) +#define IDO_USER_MENU_ITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), IDO_USER_MENU_ITEM_TYPE, IdoUserMenuItemClass)) +#define IS_IDO_USER_MENU_ITEM(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), IDO_USER_MENU_ITEM_TYPE)) +#define IS_IDO_USER_MENU_ITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), IDO_USER_MENU_ITEM_TYPE)) +#define IDO_USER_MENU_ITEM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), IDO_USER_MENU_ITEM_TYPE, IdoUserMenuItemClass)) + +typedef struct _IdoUserMenuItem IdoUserMenuItem; +typedef struct _IdoUserMenuItemClass IdoUserMenuItemClass; +typedef struct _IdoUserMenuItemPrivate IdoUserMenuItemPrivate; + +struct _IdoUserMenuItemClass +{ + GtkMenuItemClass parent_class; +}; + +struct _IdoUserMenuItem +{ + /*< private >*/ + GtkMenuItem parent; + IdoUserMenuItemPrivate * priv; +}; + +GType ido_user_menu_item_get_type (void) G_GNUC_CONST; +GtkWidget* ido_user_menu_item_new(DbusmenuMenuitem *twin_item); + +G_END_DECLS + +#endif diff --git a/src/user-widget.c b/src/user-widget.c deleted file mode 100644 index 79b87b0..0000000 --- a/src/user-widget.c +++ /dev/null @@ -1,292 +0,0 @@ -/* -Copyright 2011 Canonical Ltd. - -Authors: - Conor Curran - Mirco Müller - Charles Kerr - -This program is free software: you can redistribute it and/or modify it -under the terms of the GNU General Public License version 3, 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 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 . -*/ - -#ifdef HAVE_CONFIG_H - #include "config.h" -#endif - -#include - -#include - -#include "shared-names.h" -#include "user-widget.h" - - -typedef struct _UserWidgetPrivate UserWidgetPrivate; - -struct _UserWidgetPrivate -{ - DbusmenuMenuitem* twin_item; - GtkWidget* user_image; - GtkWidget* user_name; - GtkWidget* container; - GtkWidget* tick_icon; - gboolean logged_in; - gboolean sessions_active; -}; - -#define USER_WIDGET_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), USER_WIDGET_TYPE, UserWidgetPrivate)) - -/* Prototypes */ -static void user_widget_class_init (UserWidgetClass *klass); -static void user_widget_init (UserWidget *self); -static void user_widget_dispose (GObject *object); -static void user_widget_finalize (GObject *object); - -static void user_widget_set_twin_item (UserWidget* self, - DbusmenuMenuitem* twin_item); - -static gboolean user_widget_primitive_draw_cb_gtk_3 (GtkWidget *image, - cairo_t* cr, - gpointer user_data); - -G_DEFINE_TYPE (UserWidget, user_widget, GTK_TYPE_MENU_ITEM); - -static void -user_widget_class_init (UserWidgetClass *klass) -{ - GObjectClass * gobject_class = G_OBJECT_CLASS (klass); - - g_type_class_add_private (klass, sizeof (UserWidgetPrivate)); - - gobject_class->dispose = user_widget_dispose; - gobject_class->finalize = user_widget_finalize; -} - -static void -user_widget_init (UserWidget *self) -{ - self->priv = USER_WIDGET_GET_PRIVATE(self); - - UserWidgetPrivate * priv = self->priv; - - priv->user_image = NULL; - priv->user_name = NULL; - priv->logged_in = FALSE; - priv->sessions_active = FALSE; - priv->container = NULL; - priv->tick_icon = NULL; - - // Create the UI elements. - priv->user_image = gtk_image_new (); - gtk_misc_set_alignment(GTK_MISC(priv->user_image), 0.0, 0.0); - - priv->user_name = gtk_label_new (NULL); - - priv->container = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 4); - - priv->tick_icon = gtk_image_new_from_icon_name ("account-logged-in", - GTK_ICON_SIZE_MENU); - gtk_misc_set_alignment(GTK_MISC(priv->tick_icon), 1.0, 0.5); - - // Pack it together - gtk_box_pack_start (GTK_BOX (priv->container), - priv->user_image, - FALSE, - FALSE, - 0); - gtk_box_pack_start (GTK_BOX (priv->container), - priv->user_name, - FALSE, - FALSE, - 3); - gtk_box_pack_end (GTK_BOX(priv->container), - priv->tick_icon, - FALSE, - FALSE, 5); - - gtk_widget_show_all (priv->container); - gtk_container_add (GTK_CONTAINER (self), priv->container); - gtk_widget_show_all (priv->tick_icon); - gtk_widget_set_no_show_all (priv->tick_icon, TRUE); - gtk_widget_hide (priv->tick_icon); - - - // Fetch the drawing context. - g_signal_connect_after (GTK_WIDGET(self), "draw", - G_CALLBACK(user_widget_primitive_draw_cb_gtk_3), - GTK_WIDGET(self)); -} - -static void -user_widget_dispose (GObject *object) -{ - G_OBJECT_CLASS (user_widget_parent_class)->dispose (object); -} - -// TODO tidy up image and name -static void -user_widget_finalize (GObject *object) -{ - G_OBJECT_CLASS (user_widget_parent_class)->finalize (object); -} - - -/*****************************************************************/ - -// TODO handle drawing of green check mark -static gboolean -user_widget_primitive_draw_cb_gtk_3 (GtkWidget *widget, - cairo_t* cr, - gpointer user_data) -{ - g_return_val_if_fail(IS_USER_WIDGET(user_data), FALSE); - UserWidget* meta = USER_WIDGET(user_data); - UserWidgetPrivate * priv = USER_WIDGET_GET_PRIVATE(meta); - - // Draw dot only when user is the current user. - if (dbusmenu_menuitem_property_get_bool (priv->twin_item, USER_ITEM_PROP_IS_CURRENT_USER)) - { - gdouble x, y; - GtkStyle * style = gtk_widget_get_style (widget); - - GtkAllocation allocation; - gtk_widget_get_allocation (widget, &allocation); - x = allocation.x + 13; - y = allocation.height / 2; - - cairo_arc (cr, x, y, 3.0, 0.0, 2 * G_PI); - - cairo_set_source_rgb (cr, style->fg[gtk_widget_get_state(widget)].red/65535.0, - style->fg[gtk_widget_get_state(widget)].green/65535.0, - style->fg[gtk_widget_get_state(widget)].blue/65535.0); - cairo_fill (cr); - } - - return FALSE; -} - -/*** -**** -***/ - -static void -update_icon (UserWidget * self, DbusmenuMenuitem * mi) -{ - gboolean updated = FALSE; - GtkImage * image = GTK_IMAGE(self->priv->user_image); - - /* first try the menuitem's icon property */ - const gchar * icon_name = dbusmenu_menuitem_property_get (mi, USER_ITEM_PROP_ICON); - if (icon_name != NULL) - { - int width = 18; /* arbitrary default values */ - int height = 18; - GError * err = NULL; - GdkPixbuf * pixbuf = NULL; - - /* load the image */ - gtk_icon_size_lookup (GTK_ICON_SIZE_MENU, &width, &height); - pixbuf = gdk_pixbuf_new_from_file_at_size (icon_name, width, height, &err); - if (err == NULL) - { - gtk_image_set_from_pixbuf (image, pixbuf); - g_object_unref (pixbuf); - updated = TRUE; - } - else - { - g_warning ("Couldn't load the image \"%s\": %s", icon_name, err->message); - g_clear_error (&err); - } - } - - /* as a fallback, use the default user icon */ - if (!updated) - { - gtk_image_set_from_icon_name (image, - USER_ITEM_ICON_DEFAULT, - GTK_ICON_SIZE_MENU); - } -} - -static void -update_logged_in (UserWidget * self, DbusmenuMenuitem * mi) -{ - const gboolean b = dbusmenu_menuitem_property_get_bool (mi, USER_ITEM_PROP_LOGGED_IN); - - g_debug ("User \"%s\" %s active sessions", - dbusmenu_menuitem_property_get (mi, USER_ITEM_PROP_NAME), - b ? "has" : "doesn't have"); - - gtk_widget_set_visible (self->priv->tick_icon, b); -} - -static void -update_name (UserWidget * self, DbusmenuMenuitem * mi) -{ - gtk_label_set_label (GTK_LABEL(self->priv->user_name), - dbusmenu_menuitem_property_get (mi, USER_ITEM_PROP_NAME)); -} - -static void -user_widget_property_update (DbusmenuMenuitem * mi, - const gchar * property, - GVariant * value, - UserWidget * self) -{ - g_return_if_fail (IS_USER_WIDGET (self)); - - if (!g_strcmp0 (property, USER_ITEM_PROP_LOGGED_IN)) - { - update_logged_in (self, mi); - } - else if (!g_strcmp0 (property, USER_ITEM_PROP_ICON)) - { - update_icon (self, mi); - } - else if (!g_strcmp0 (property, USER_ITEM_PROP_NAME)) - { - update_name (self, mi); - } - else - { - g_debug ("%s FIXME: unhandled property change %s", G_STRFUNC, property); - } -} - -static void -user_widget_set_twin_item (UserWidget * self, DbusmenuMenuitem * mi) -{ - self->priv->twin_item = mi; - - update_icon (self, mi); - update_name (self, mi); - update_logged_in (self, mi); - - g_signal_connect (G_OBJECT(mi), "property-changed", - G_CALLBACK(user_widget_property_update), self); -} - - /** - * user_widget_new: - * @item: the #DbusmenuMenuitem this widget will render. - * - * Returns: (transfer full): a new #UserWidget. - **/ -GtkWidget* -user_widget_new (DbusmenuMenuitem *item) -{ - GtkWidget* widget = g_object_new(USER_WIDGET_TYPE, NULL); - user_widget_set_twin_item ( USER_WIDGET(widget), item ); - return widget; -} diff --git a/src/user-widget.h b/src/user-widget.h deleted file mode 100644 index 0953e6c..0000000 --- a/src/user-widget.h +++ /dev/null @@ -1,55 +0,0 @@ -/* -Copyright 2011 Canonical Ltd. - -Authors: - Conor Curran - -This program is free software: you can redistribute it and/or modify it -under the terms of the GNU General Public License version 3, 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 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 . -*/ -#ifndef __USER_WIDGET_H__ -#define __USER_WIDGET_H__ - -#include -#include - -G_BEGIN_DECLS - -#define USER_WIDGET_TYPE (user_widget_get_type ()) -#define USER_WIDGET(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), USER_WIDGET_TYPE, UserWidget)) -#define USER_WIDGET_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), USER_WIDGET_TYPE, UserWidgetClass)) -#define IS_USER_WIDGET(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), USER_WIDGET_TYPE)) -#define IS_USER_WIDGET_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), USER_WIDGET_TYPE)) -#define USER_WIDGET_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), USER_WIDGET_TYPE, UserWidgetClass)) - -typedef struct _UserWidget UserWidget; -typedef struct _UserWidgetClass UserWidgetClass; -typedef struct _UserWidgetPrivate UserWidgetPrivate; - -struct _UserWidgetClass -{ - GtkMenuItemClass parent_class; -}; - -struct _UserWidget -{ - /*< private >*/ - GtkMenuItem parent; - UserWidgetPrivate * priv; -}; - -GType user_widget_get_type (void) G_GNUC_CONST; -GtkWidget* user_widget_new(DbusmenuMenuitem *twin_item); - -G_END_DECLS - -#endif -- cgit v1.2.3 From 259c7ad0334a5c04873e4b62eb04890c76813fd0 Mon Sep 17 00:00:00 2001 From: Charles Kerr Date: Tue, 26 Mar 2013 16:24:47 -0500 Subject: add properties to IdoUserMenuItem and remove its dependencies on DbusmenuMenuitem --- src/idousermenuitem.c | 301 ++++++++++++++++++++++++++++++-------------------- src/idousermenuitem.h | 15 ++- 2 files changed, 194 insertions(+), 122 deletions(-) diff --git a/src/idousermenuitem.c b/src/idousermenuitem.c index 620df8d..a6fd9f0 100644 --- a/src/idousermenuitem.c +++ b/src/idousermenuitem.c @@ -27,61 +27,176 @@ with this program. If not, see . #include "idousermenuitem.h" +#define FALLBACK_ICON_NAME "avatar-default" -typedef struct _IdoUserMenuItemPrivate IdoUserMenuItemPrivate; +enum +{ + PROP_0, + PROP_LABEL, + PROP_ICON, + PROP_IS_LOGGED_IN, + PROP_IS_CURRENT_USER, + PROP_LAST +}; + +static GParamSpec *properties[PROP_LAST]; struct _IdoUserMenuItemPrivate { - DbusmenuMenuitem* twin_item; GtkWidget* user_image; GtkWidget* user_name; GtkWidget* container; GtkWidget* tick_icon; - gboolean logged_in; - gboolean sessions_active; + gboolean is_logged_in; + gboolean is_current_user; + gchar * label; + gchar * icon_name; }; -#define USER_WIDGET_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), USER_WIDGET_TYPE, IdoUserMenuItemPrivate)) +G_DEFINE_TYPE (IdoUserMenuItem, ido_user_menu_item, GTK_TYPE_MENU_ITEM); /* Prototypes */ -static void user_widget_class_init (IdoUserMenuItemClass *klass); -static void user_widget_init (IdoUserMenuItem *self); -static void user_widget_dispose (GObject *object); -static void user_widget_finalize (GObject *object); +static gboolean ido_user_menu_item_primitive_draw_cb_gtk_3 (GtkWidget * image, + cairo_t * cr, + gpointer gself); + + +static void +my_get_property (GObject * o, + guint property_id, + GValue * value, + GParamSpec * pspec) +{ + IdoUserMenuItem * self = IDO_USER_MENU_ITEM (o); + + switch (property_id) + { + case PROP_LABEL: + g_value_set_string (value, self->priv->label); + break; + + case PROP_ICON: + g_value_set_string (value, self->priv->icon_name); + break; -static void user_widget_set_twin_item (IdoUserMenuItem* self, - DbusmenuMenuitem* twin_item); + case PROP_IS_LOGGED_IN: + g_value_set_boolean (value, self->priv->is_logged_in); + break; -static gboolean user_widget_primitive_draw_cb_gtk_3 (GtkWidget *image, - cairo_t* cr, - gpointer user_data); + case PROP_IS_CURRENT_USER: + g_value_set_boolean (value, self->priv->is_current_user); + break; -G_DEFINE_TYPE (IdoUserMenuItem, user_widget, GTK_TYPE_MENU_ITEM); + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (o, property_id, pspec); + break; + } +} static void -user_widget_class_init (IdoUserMenuItemClass *klass) +my_set_property (GObject * o, + guint property_id, + const GValue * value, + GParamSpec * pspec) { + IdoUserMenuItem * self = IDO_USER_MENU_ITEM (o); + + switch (property_id) + { + case PROP_LABEL: + ido_user_menu_item_set_label (self, g_value_get_string (value)); + break; + + case PROP_ICON: + ido_user_menu_item_set_icon (self, g_value_get_string (value)); + break; + + case PROP_IS_LOGGED_IN: + ido_user_menu_item_set_logged_in (self, g_value_get_boolean (value)); + break; + + case PROP_IS_CURRENT_USER: + self->priv->is_current_user = g_value_get_boolean (value); + gtk_widget_queue_draw (GTK_WIDGET(self)); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (o, property_id, pspec); + break; + } +} + +static void +my_dispose (GObject *object) +{ + G_OBJECT_CLASS (ido_user_menu_item_parent_class)->dispose (object); +} + +static void +my_finalize (GObject *object) +{ + IdoUserMenuItem * self = IDO_USER_MENU_ITEM (object); + + g_free (self->priv->label); + g_free (self->priv->icon_name); + + G_OBJECT_CLASS (ido_user_menu_item_parent_class)->finalize (object); +} + +static void +ido_user_menu_item_class_init (IdoUserMenuItemClass *klass) +{ + GParamFlags prop_flags; GObjectClass * gobject_class = G_OBJECT_CLASS (klass); g_type_class_add_private (klass, sizeof (IdoUserMenuItemPrivate)); - gobject_class->dispose = user_widget_dispose; - gobject_class->finalize = user_widget_finalize; + gobject_class->get_property = my_get_property; + gobject_class->set_property = my_set_property; + gobject_class->dispose = my_dispose; + gobject_class->finalize = my_finalize; + + prop_flags = G_PARAM_CONSTRUCT + | G_PARAM_READWRITE + | G_PARAM_STATIC_STRINGS; + + properties[PROP_LABEL] = g_param_spec_string ("label", + "The user's name", + "The name to display", + "J. Random User", + prop_flags); + + properties[PROP_ICON] = g_param_spec_string ("icon", + "The icon's name", + "The icon to display", + NULL, + prop_flags); + + properties[PROP_IS_LOGGED_IN] = g_param_spec_boolean ("is-logged-in", + "is logged in", + "is user logged in?", + FALSE, + prop_flags); + + properties[PROP_IS_CURRENT_USER] = g_param_spec_boolean ("is-current-user", + "is current user", + "is user current?", + FALSE, + prop_flags); + + g_object_class_install_properties (gobject_class, PROP_LAST, properties); } static void -user_widget_init (IdoUserMenuItem *self) +ido_user_menu_item_init (IdoUserMenuItem *self) { - self->priv = USER_WIDGET_GET_PRIVATE(self); + IdoUserMenuItemPrivate * priv; - IdoUserMenuItemPrivate * priv = self->priv; + self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, + IDO_USER_MENU_ITEM_TYPE, + IdoUserMenuItemPrivate); - priv->user_image = NULL; - priv->user_name = NULL; - priv->logged_in = FALSE; - priv->sessions_active = FALSE; - priv->container = NULL; - priv->tick_icon = NULL; + priv = self->priv; // Create the UI elements. priv->user_image = gtk_image_new (); @@ -120,41 +235,30 @@ user_widget_init (IdoUserMenuItem *self) // Fetch the drawing context. g_signal_connect_after (GTK_WIDGET(self), "draw", - G_CALLBACK(user_widget_primitive_draw_cb_gtk_3), + G_CALLBACK(ido_user_menu_item_primitive_draw_cb_gtk_3), GTK_WIDGET(self)); } -static void -user_widget_dispose (GObject *object) -{ - G_OBJECT_CLASS (user_widget_parent_class)->dispose (object); -} - -// TODO tidy up image and name -static void -user_widget_finalize (GObject *object) -{ - G_OBJECT_CLASS (user_widget_parent_class)->finalize (object); -} - /*****************************************************************/ -// TODO handle drawing of green check mark static gboolean -user_widget_primitive_draw_cb_gtk_3 (GtkWidget *widget, - cairo_t* cr, - gpointer user_data) +ido_user_menu_item_primitive_draw_cb_gtk_3 (GtkWidget * widget, + cairo_t * cr, + gpointer user_data) { - g_return_val_if_fail(IS_USER_WIDGET(user_data), FALSE); - IdoUserMenuItem* meta = USER_WIDGET(user_data); - IdoUserMenuItemPrivate * priv = USER_WIDGET_GET_PRIVATE(meta); + IdoUserMenuItemPrivate * priv; + + g_return_val_if_fail(IS_IDO_USER_MENU_ITEM(user_data), FALSE); + + priv = IDO_USER_MENU_ITEM(user_data)->priv; - // Draw dot only when user is the current user. - if (dbusmenu_menuitem_property_get_bool (priv->twin_item, USER_ITEM_PROP_IS_CURRENT_USER)) + /* Draw dot only when user is the current user. */ + if (priv->is_current_user) { gdouble x, y; GtkStyle * style = gtk_widget_get_style (widget); + const GtkStateType state = gtk_widget_get_state (widget); GtkAllocation allocation; gtk_widget_get_allocation (widget, &allocation); @@ -163,9 +267,9 @@ user_widget_primitive_draw_cb_gtk_3 (GtkWidget *widget, cairo_arc (cr, x, y, 3.0, 0.0, 2 * G_PI); - cairo_set_source_rgb (cr, style->fg[gtk_widget_get_state(widget)].red/65535.0, - style->fg[gtk_widget_get_state(widget)].green/65535.0, - style->fg[gtk_widget_get_state(widget)].blue/65535.0); + cairo_set_source_rgb (cr, style->fg[state].red/65535.0, + style->fg[state].green/65535.0, + style->fg[state].blue/65535.0); cairo_fill (cr); } @@ -173,18 +277,22 @@ user_widget_primitive_draw_cb_gtk_3 (GtkWidget *widget, } /*** -**** +**** PUBLIC API ***/ -static void -update_icon (IdoUserMenuItem * self, DbusmenuMenuitem * mi) +void +ido_user_menu_item_set_icon (IdoUserMenuItem * self, const char * icon_name) { gboolean updated = FALSE; - GtkImage * image = GTK_IMAGE(self->priv->user_image); + IdoUserMenuItemPrivate * p = self->priv; + GtkImage * image = GTK_IMAGE (p->user_image); + + /* make a private copy of the icon name */ + g_free (p->icon_name); + self->priv->icon_name = g_strdup (icon_name); - /* first try the menuitem's icon property */ - const gchar * icon_name = dbusmenu_menuitem_property_get (mi, USER_ITEM_PROP_ICON); - if (icon_name != NULL) + /* now try to use it */ + if (icon_name && *icon_name) { int width = 18; /* arbitrary default values */ int height = 18; @@ -211,79 +319,32 @@ update_icon (IdoUserMenuItem * self, DbusmenuMenuitem * mi) if (!updated) { gtk_image_set_from_icon_name (image, - USER_ITEM_ICON_DEFAULT, + FALLBACK_ICON_NAME, GTK_ICON_SIZE_MENU); } } -static void -update_logged_in (IdoUserMenuItem * self, DbusmenuMenuitem * mi) -{ - const gboolean b = dbusmenu_menuitem_property_get_bool (mi, USER_ITEM_PROP_LOGGED_IN); - - g_debug ("User \"%s\" %s active sessions", - dbusmenu_menuitem_property_get (mi, USER_ITEM_PROP_NAME), - b ? "has" : "doesn't have"); - - gtk_widget_set_visible (self->priv->tick_icon, b); -} - -static void -update_name (IdoUserMenuItem * self, DbusmenuMenuitem * mi) +void +ido_user_menu_item_set_logged_in (IdoUserMenuItem * self, gboolean is_logged_in) { - gtk_label_set_label (GTK_LABEL(self->priv->user_name), - dbusmenu_menuitem_property_get (mi, USER_ITEM_PROP_NAME)); + gtk_widget_set_visible (self->priv->tick_icon, is_logged_in); } -static void -user_widget_property_update (DbusmenuMenuitem * mi, - const gchar * property, - GVariant * value, - IdoUserMenuItem * self) +void +ido_user_menu_item_set_current_user (IdoUserMenuItem * self, gboolean is_current_user) { - g_return_if_fail (IS_USER_WIDGET (self)); - - if (!g_strcmp0 (property, USER_ITEM_PROP_LOGGED_IN)) - { - update_logged_in (self, mi); - } - else if (!g_strcmp0 (property, USER_ITEM_PROP_ICON)) - { - update_icon (self, mi); - } - else if (!g_strcmp0 (property, USER_ITEM_PROP_NAME)) - { - update_name (self, mi); - } - else - { - g_debug ("%s FIXME: unhandled property change %s", G_STRFUNC, property); - } + self->priv->is_current_user = is_current_user; + gtk_widget_queue_draw (GTK_WIDGET (self)); } -static void -user_widget_set_twin_item (IdoUserMenuItem * self, DbusmenuMenuitem * mi) +void +ido_user_menu_item_set_label (IdoUserMenuItem * self, const char * label) { - self->priv->twin_item = mi; - - update_icon (self, mi); - update_name (self, mi); - update_logged_in (self, mi); - - g_signal_connect (G_OBJECT(mi), "property-changed", - G_CALLBACK(user_widget_property_update), self); + gtk_label_set_label (GTK_LABEL(self->priv->user_name), label); } - /** - * user_widget_new: - * @item: the #DbusmenuMenuitem this widget will render. - * - * Returns: (transfer full): a new #IdoUserMenuItem. - **/ GtkWidget* -user_widget_new (DbusmenuMenuitem *item) +ido_user_menu_item_new (void) { - GtkWidget* widget = g_object_new(USER_WIDGET_TYPE, NULL); - user_widget_set_twin_item ( USER_WIDGET(widget), item ); - return widget; + return GTK_WIDGET (g_object_new (IDO_USER_MENU_ITEM_TYPE, NULL)); } diff --git a/src/idousermenuitem.h b/src/idousermenuitem.h index ac115a8..7826718 100644 --- a/src/idousermenuitem.h +++ b/src/idousermenuitem.h @@ -20,7 +20,6 @@ with this program. If not, see . #define __IDO_USER_MENU_ITEM_H__ #include -#include G_BEGIN_DECLS @@ -35,6 +34,12 @@ typedef struct _IdoUserMenuItem IdoUserMenuItem; typedef struct _IdoUserMenuItemClass IdoUserMenuItemClass; typedef struct _IdoUserMenuItemPrivate IdoUserMenuItemPrivate; +/* property keys */ +#define IDO_USER_MENU_ITEM_PROP_LABEL "label" +#define IDO_USER_MENU_ITEM_PROP_ICON "icon" +#define IDO_USER_MENU_ITEM_PROP_IS_LOGGED_IN "is-logged-in" +#define IDO_USER_MENU_ITEM_PROP_IS_CURRENT_USER "is-current-user" + struct _IdoUserMenuItemClass { GtkMenuItemClass parent_class; @@ -48,7 +53,13 @@ struct _IdoUserMenuItem }; GType ido_user_menu_item_get_type (void) G_GNUC_CONST; -GtkWidget* ido_user_menu_item_new(DbusmenuMenuitem *twin_item); + +GtkWidget* ido_user_menu_item_new(void); + +void ido_user_menu_item_set_icon (IdoUserMenuItem * self, const char * icon_name); +void ido_user_menu_item_set_logged_in (IdoUserMenuItem * self, gboolean is_logged_in); +void ido_user_menu_item_set_current_user (IdoUserMenuItem * self, gboolean is_current_user); +void ido_user_menu_item_set_label (IdoUserMenuItem * self, const char * label); G_END_DECLS -- cgit v1.2.3 From 49c57fdc547b91bdad22ad4c7b36d6000ff023ee Mon Sep 17 00:00:00 2001 From: Charles Kerr Date: Tue, 26 Mar 2013 16:25:04 -0500 Subject: add idousermenuitem to the examples --- example/menus.c | 45 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 44 insertions(+), 1 deletion(-) diff --git a/example/menus.c b/example/menus.c index 5687b8e..b303cf5 100644 --- a/example/menus.c +++ b/example/menus.c @@ -4,6 +4,7 @@ #include "idocalendarmenuitem.h" #include "idoentrymenuitem.h" #include "idoswitchmenuitem.h" +#include "idousermenuitem.h" #include "config.h" static void @@ -92,10 +93,52 @@ main (int argc, char *argv[]) image = ido_scale_menu_item_get_secondary_image (IDO_SCALE_MENU_ITEM (menuitem)); gtk_image_set_from_stock (GTK_IMAGE (image), GTK_STOCK_OPEN, GTK_ICON_SIZE_MENU); gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem); - g_signal_connect (menuitem, "slider-grabbed", G_CALLBACK (slider_grabbed), NULL); g_signal_connect (menuitem, "slider-released", G_CALLBACK (slider_released), NULL); + /** + *** Users + **/ + + menuitem = gtk_separator_menu_item_new (); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem); + + menuitem = ido_user_menu_item_new (); + g_object_set (menuitem, + "label", "Guest", + "icon", NULL, + "is-logged-in", FALSE, + "is-current-user", FALSE, + NULL); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem); + + menuitem = ido_user_menu_item_new (); + g_object_set (menuitem, + "label", "Bobby Fischer", + "icon", "/usr/share/pixmaps/faces/chess.jpg", + "is-logged-in", FALSE, + "is-current-user", FALSE, + NULL); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem); + + menuitem = ido_user_menu_item_new (); + g_object_set (menuitem, + "label", "Linus Torvalds", + "icon", "/usr/share/pixmaps/faces/penguin.jpg", + "is-logged-in", TRUE, + "is-current-user", FALSE, + NULL); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem); + + menuitem = ido_user_menu_item_new (); + g_object_set (menuitem, "label", "Mark Shuttleworth", + "icon", "/usr/share/pixmaps/faces/astronaut.jpg", + "is-logged-in", TRUE, + "is-current-user", TRUE, + NULL); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem); + + /* Add the menubar */ gtk_menu_shell_append (GTK_MENU_SHELL (menubar), root); -- cgit v1.2.3 From 0430322cec5472c4cbac20e2869f3aab9218c3d7 Mon Sep 17 00:00:00 2001 From: Charles Kerr Date: Tue, 26 Mar 2013 16:30:46 -0500 Subject: in ido_user_menu_item_primitive_draw_cb_gtk_3(), remove deprecated use of gtk_widget_get_style(), gtk_widget_get_state() --- src/idousermenuitem.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/idousermenuitem.c b/src/idousermenuitem.c index a6fd9f0..5677065 100644 --- a/src/idousermenuitem.c +++ b/src/idousermenuitem.c @@ -256,9 +256,15 @@ ido_user_menu_item_primitive_draw_cb_gtk_3 (GtkWidget * widget, /* Draw dot only when user is the current user. */ if (priv->is_current_user) { + GtkStyleContext * style_context; + GtkStateFlags state_flags; + GdkRGBA color; gdouble x, y; - GtkStyle * style = gtk_widget_get_style (widget); - const GtkStateType state = gtk_widget_get_state (widget); + + /* get the foreground color */ + style_context = gtk_widget_get_style_context (widget); + state_flags = gtk_widget_get_state_flags (widget); + gtk_style_context_get_color (style_context, state_flags, &color); GtkAllocation allocation; gtk_widget_get_allocation (widget, &allocation); @@ -267,9 +273,8 @@ ido_user_menu_item_primitive_draw_cb_gtk_3 (GtkWidget * widget, cairo_arc (cr, x, y, 3.0, 0.0, 2 * G_PI); - cairo_set_source_rgb (cr, style->fg[state].red/65535.0, - style->fg[state].green/65535.0, - style->fg[state].blue/65535.0); + gdk_cairo_set_source_rgba (cr, &color); + cairo_fill (cr); } -- cgit v1.2.3 From e9c82c3904642003b47f3d2bc13343894e6750d8 Mon Sep 17 00:00:00 2001 From: Charles Kerr Date: Wed, 27 Mar 2013 08:30:38 -0500 Subject: rename idousermenuitem's "icon" property as "icon-filename" for a little more clarity. --- example/menus.c | 8 ++++---- src/idousermenuitem.c | 36 +++++++++++++++++++----------------- src/idousermenuitem.h | 2 +- 3 files changed, 24 insertions(+), 22 deletions(-) diff --git a/example/menus.c b/example/menus.c index b303cf5..1675f45 100644 --- a/example/menus.c +++ b/example/menus.c @@ -106,7 +106,7 @@ main (int argc, char *argv[]) menuitem = ido_user_menu_item_new (); g_object_set (menuitem, "label", "Guest", - "icon", NULL, + "icon-filename", NULL, "is-logged-in", FALSE, "is-current-user", FALSE, NULL); @@ -115,7 +115,7 @@ main (int argc, char *argv[]) menuitem = ido_user_menu_item_new (); g_object_set (menuitem, "label", "Bobby Fischer", - "icon", "/usr/share/pixmaps/faces/chess.jpg", + "icon-filename", "/usr/share/pixmaps/faces/chess.jpg", "is-logged-in", FALSE, "is-current-user", FALSE, NULL); @@ -124,7 +124,7 @@ main (int argc, char *argv[]) menuitem = ido_user_menu_item_new (); g_object_set (menuitem, "label", "Linus Torvalds", - "icon", "/usr/share/pixmaps/faces/penguin.jpg", + "icon-filename", "/usr/share/pixmaps/faces/penguin.jpg", "is-logged-in", TRUE, "is-current-user", FALSE, NULL); @@ -132,7 +132,7 @@ main (int argc, char *argv[]) menuitem = ido_user_menu_item_new (); g_object_set (menuitem, "label", "Mark Shuttleworth", - "icon", "/usr/share/pixmaps/faces/astronaut.jpg", + "icon-filename", "/usr/share/pixmaps/faces/astronaut.jpg", "is-logged-in", TRUE, "is-current-user", TRUE, NULL); diff --git a/src/idousermenuitem.c b/src/idousermenuitem.c index 5677065..cb405e8 100644 --- a/src/idousermenuitem.c +++ b/src/idousermenuitem.c @@ -33,7 +33,7 @@ enum { PROP_0, PROP_LABEL, - PROP_ICON, + PROP_ICON_FILENAME, PROP_IS_LOGGED_IN, PROP_IS_CURRENT_USER, PROP_LAST @@ -50,7 +50,7 @@ struct _IdoUserMenuItemPrivate gboolean is_logged_in; gboolean is_current_user; gchar * label; - gchar * icon_name; + gchar * icon_filename; }; G_DEFINE_TYPE (IdoUserMenuItem, ido_user_menu_item, GTK_TYPE_MENU_ITEM); @@ -75,8 +75,8 @@ my_get_property (GObject * o, g_value_set_string (value, self->priv->label); break; - case PROP_ICON: - g_value_set_string (value, self->priv->icon_name); + case PROP_ICON_FILENAME: + g_value_set_string (value, self->priv->icon_filename); break; case PROP_IS_LOGGED_IN: @@ -107,7 +107,7 @@ my_set_property (GObject * o, ido_user_menu_item_set_label (self, g_value_get_string (value)); break; - case PROP_ICON: + case PROP_ICON_FILENAME: ido_user_menu_item_set_icon (self, g_value_get_string (value)); break; @@ -138,7 +138,7 @@ my_finalize (GObject *object) IdoUserMenuItem * self = IDO_USER_MENU_ITEM (object); g_free (self->priv->label); - g_free (self->priv->icon_name); + g_free (self->priv->icon_filename); G_OBJECT_CLASS (ido_user_menu_item_parent_class)->finalize (object); } @@ -166,11 +166,11 @@ ido_user_menu_item_class_init (IdoUserMenuItemClass *klass) "J. Random User", prop_flags); - properties[PROP_ICON] = g_param_spec_string ("icon", - "The icon's name", - "The icon to display", - NULL, - prop_flags); + properties[PROP_ICON_FILENAME] = g_param_spec_string ("icon-filename", + "The icon's filename", + "The icon to display", + NULL, + prop_flags); properties[PROP_IS_LOGGED_IN] = g_param_spec_boolean ("is-logged-in", "is logged in", @@ -286,18 +286,18 @@ ido_user_menu_item_primitive_draw_cb_gtk_3 (GtkWidget * widget, ***/ void -ido_user_menu_item_set_icon (IdoUserMenuItem * self, const char * icon_name) +ido_user_menu_item_set_icon (IdoUserMenuItem * self, const char * icon_filename) { gboolean updated = FALSE; IdoUserMenuItemPrivate * p = self->priv; GtkImage * image = GTK_IMAGE (p->user_image); /* make a private copy of the icon name */ - g_free (p->icon_name); - self->priv->icon_name = g_strdup (icon_name); + g_free (p->icon_filename); + self->priv->icon_filename = g_strdup (icon_filename); /* now try to use it */ - if (icon_name && *icon_name) + if (icon_filename && *icon_filename) { int width = 18; /* arbitrary default values */ int height = 18; @@ -306,7 +306,8 @@ ido_user_menu_item_set_icon (IdoUserMenuItem * self, const char * icon_name) /* load the image */ gtk_icon_size_lookup (GTK_ICON_SIZE_MENU, &width, &height); - pixbuf = gdk_pixbuf_new_from_file_at_size (icon_name, width, height, &err); + pixbuf = gdk_pixbuf_new_from_file_at_size (icon_filename, + width, height, &err); if (err == NULL) { gtk_image_set_from_pixbuf (image, pixbuf); @@ -315,7 +316,8 @@ ido_user_menu_item_set_icon (IdoUserMenuItem * self, const char * icon_name) } else { - g_warning ("Couldn't load the image \"%s\": %s", icon_name, err->message); + g_warning ("Couldn't load the image \"%s\": %s", + icon_filename, err->message); g_clear_error (&err); } } diff --git a/src/idousermenuitem.h b/src/idousermenuitem.h index 7826718..b9a3d00 100644 --- a/src/idousermenuitem.h +++ b/src/idousermenuitem.h @@ -36,7 +36,7 @@ typedef struct _IdoUserMenuItemPrivate IdoUserMenuItemPrivate; /* property keys */ #define IDO_USER_MENU_ITEM_PROP_LABEL "label" -#define IDO_USER_MENU_ITEM_PROP_ICON "icon" +#define IDO_USER_MENU_ITEM_PROP_ICON_FILENAME "icon-filename" #define IDO_USER_MENU_ITEM_PROP_IS_LOGGED_IN "is-logged-in" #define IDO_USER_MENU_ITEM_PROP_IS_CURRENT_USER "is-current-user" -- cgit v1.2.3 From 3f3aa147ac8ee224f40d9c4e9800b4c5825fde59 Mon Sep 17 00:00:00 2001 From: Lars Uebernickel Date: Wed, 22 May 2013 22:51:19 -0400 Subject: Add IdoMenuItemFactory It's implementing the GtkMenuItemFactory extension point (only available in Ubuntu's version of gtk+). It doesn't create any menu items yet. The extension point must be registered before calling gtk_menu_new_from_model() with a menu model that references any of the custom menu items ido will provide. Registering means the type must exist in the type system. This patch adds an ido_init() which does that. Consumers of libido are required to call this function from now on. --- src/Makefile.am | 6 +++-- src/idomenuitemfactory.c | 60 ++++++++++++++++++++++++++++++++++++++++++++++++ src/libido.c | 36 +++++++++++++++++++++++++++++ src/libido.h | 2 ++ 4 files changed, 102 insertions(+), 2 deletions(-) create mode 100644 src/idomenuitemfactory.c create mode 100644 src/libido.c diff --git a/src/Makefile.am b/src/Makefile.am index e14efbf..d6012f1 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -18,7 +18,7 @@ sources_h = \ idoscalemenuitem.h \ idoswitchmenuitem.h \ idotimeline.h \ - libido.h + libido.h EXTRA_DIST = \ ido.list \ @@ -59,6 +59,7 @@ AM_CFLAGS = \ $(COVERAGE_CFLAGS) libido_0_1_la_SOURCES = \ + libido.c \ idotypebuiltins.c \ idocalendarmenuitem.c \ idoentrymenuitem.c \ @@ -66,7 +67,8 @@ libido_0_1_la_SOURCES = \ idorange.c \ idoscalemenuitem.c \ idoswitchmenuitem.c \ - idotimeline.c + idotimeline.c \ + idomenuitemfactory.c libido3_0_1_la_SOURCES = $(libido_0_1_la_SOURCES) diff --git a/src/idomenuitemfactory.c b/src/idomenuitemfactory.c new file mode 100644 index 0000000..3eb8049 --- /dev/null +++ b/src/idomenuitemfactory.c @@ -0,0 +1,60 @@ +/* + * Copyright 2013 Canonical Ltd. + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, 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 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 . + * + * Authors: + * Lars Uebernickel + */ + +#include + +#define IDO_TYPE_MENU_ITEM_FACTORY (ido_menu_item_factory_get_type ()) +#define IDO_MENU_ITEM_FACTORY(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), IDO_TYPE_MENU_ITEM_FACTORY, IdoMenuItemFactory)) +#define IDO_IS_MENU_ITEM_FACTORY(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), IDO_TYPE_MENU_ITEM_FACTORY)) + +typedef GObject IdoMenuItemFactory; +typedef GObjectClass IdoMenuItemFactoryClass; + +GType ido_menu_item_factory_get_type (void); +static void ido_menu_item_factory_interface_init (GtkMenuItemFactoryInterface *iface); + +G_DEFINE_TYPE_WITH_CODE (IdoMenuItemFactory, ido_menu_item_factory, G_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE (GTK_TYPE_MENU_ITEM_FACTORY, ido_menu_item_factory_interface_init) + g_io_extension_point_implement (GTK_MENU_ITEM_FACTORY_EXTENSION_POINT_NAME, + g_define_type_id, "ido", 0);) + +static GtkMenuItem * +ido_menu_item_factory_create_menu_item (GtkMenuItemFactory *factory, + const gchar *type, + GMenuItem *menuitem, + GActionGroup *actions) +{ + return NULL; +} + +static void +ido_menu_item_factory_class_init (IdoMenuItemFactoryClass *class) +{ +} + +static void +ido_menu_item_factory_interface_init (GtkMenuItemFactoryInterface *iface) +{ + iface->create_menu_item = ido_menu_item_factory_create_menu_item; +} + +static void +ido_menu_item_factory_init (IdoMenuItemFactory *factory) +{ +} diff --git a/src/libido.c b/src/libido.c new file mode 100644 index 0000000..0c90213 --- /dev/null +++ b/src/libido.c @@ -0,0 +1,36 @@ +/* + * Copyright 2013 Canonical Ltd. + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, 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 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 . + * + * Authors: + * Lars Uebernickel + */ + +#include + +/** + * ido_init: + * + * Initializes ido. It has to be called after gtk_init(), but before any + * other calls into ido are made. + */ +void +ido_init (void) +{ + GType ido_menu_item_factory_get_type (void); + + /* make sure this extension point is registered so that gtk calls it + * when finding custom menu items */ + g_type_ensure (ido_menu_item_factory_get_type ()); +} diff --git a/src/libido.h b/src/libido.h index 4c4f68b..43a8168 100644 --- a/src/libido.h +++ b/src/libido.h @@ -31,4 +31,6 @@ #include #include +void ido_init (void); + #endif /* __IDO__ */ -- cgit v1.2.3 From 12a5f15581d2c8ba5e6b4ec4baa19bd436e4fd8d Mon Sep 17 00:00:00 2001 From: Lars Uebernickel Date: Wed, 22 May 2013 23:19:50 -0400 Subject: Add IdoActionHelper This class contains some functionality that all menu items that are bound to an action need. It listens for action additions and removals, changes in enabled state, and state changes. It is _not_ intended to be used by specific menu items, but rather as the glue in IdoMenuItemFactory, to bind a widget to an action. An alternative way to reach the same goal is to have an IdoMenuItem base class which contains the common functionality. This would have required touching all existing menu items (slider, user menu item, media player items) and would have added more complexity to them. It is similar in spirit to GtkActionHelper (a private class in gtk), but very different in API and implementation. --- src/Makefile.am | 6 +- src/idoactionhelper.c | 364 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/idoactionhelper.h | 44 ++++++ 3 files changed, 412 insertions(+), 2 deletions(-) create mode 100644 src/idoactionhelper.c create mode 100644 src/idoactionhelper.h diff --git a/src/Makefile.am b/src/Makefile.am index d6012f1..a2a82da 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -18,7 +18,8 @@ sources_h = \ idoscalemenuitem.h \ idoswitchmenuitem.h \ idotimeline.h \ - libido.h + libido.h \ + idoactionhelper.h EXTRA_DIST = \ ido.list \ @@ -68,7 +69,8 @@ libido_0_1_la_SOURCES = \ idoscalemenuitem.c \ idoswitchmenuitem.c \ idotimeline.c \ - idomenuitemfactory.c + idomenuitemfactory.c \ + idoactionhelper.c libido3_0_1_la_SOURCES = $(libido_0_1_la_SOURCES) diff --git a/src/idoactionhelper.c b/src/idoactionhelper.c new file mode 100644 index 0000000..b68423a --- /dev/null +++ b/src/idoactionhelper.c @@ -0,0 +1,364 @@ +/* +* Copyright 2013 Canonical Ltd. +* +* This program is free software: you can redistribute it and/or modify it +* under the terms of the GNU General Public License version 3, 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 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 . +* +* Authors: +* Lars Uebernickel +*/ + +#include "idoactionhelper.h" + +typedef GObjectClass IdoActionHelperClass; + +struct _IdoActionHelper +{ + GObject parent; + + GtkWidget *widget; + GActionGroup *actions; + gchar *action_name; + GVariant *action_target; +}; + +G_DEFINE_TYPE (IdoActionHelper, ido_action_helper, G_TYPE_OBJECT) + +enum +{ + PROP_0, + PROP_WIDGET, + PROP_ACTION_GROUP, + PROP_ACTION_NAME, + PROP_ACTION_TARGET, + NUM_PROPERTIES +}; + +enum +{ + ACTION_STATE_CHANGED, + NUM_SIGNALS +}; + +static GParamSpec *properties[NUM_PROPERTIES]; +static guint signals[NUM_SIGNALS]; + +static void +ido_action_helper_action_added (GActionGroup *actions, + const gchar *action_name, + gpointer user_data) +{ + IdoActionHelper *helper = user_data; + gboolean enabled; + GVariant *state; + + if (!g_str_equal (action_name, helper->action_name)) + return; + + if (g_action_group_query_action (actions, action_name, + &enabled, NULL, NULL, NULL, &state)) + { + gtk_widget_set_sensitive (helper->widget, enabled); + + if (state) + { + g_signal_emit (helper, signals[ACTION_STATE_CHANGED], 0, state); + g_variant_unref (state); + } + } + else + { + gtk_widget_set_sensitive (helper->widget, FALSE); + } +} + +static void +ido_action_helper_action_removed (GActionGroup *action_group, + gchar *action_name, + gpointer user_data) +{ + IdoActionHelper *helper = user_data; + + if (g_str_equal (action_name, helper->action_name)) + gtk_widget_set_sensitive (helper->widget, FALSE); +} + +static void +ido_action_helper_action_enabled_changed (GActionGroup *action_group, + gchar *action_name, + gboolean enabled, + gpointer user_data) +{ + IdoActionHelper *helper = user_data; + + if (g_str_equal (action_name, helper->action_name)) + gtk_widget_set_sensitive (helper->widget, enabled); +} + +static void +ido_action_helper_action_state_changed (GActionGroup *action_group, + gchar *action_name, + GVariant *value, + gpointer user_data) +{ + IdoActionHelper *helper = user_data; + + if (g_str_equal (action_name, helper->action_name)) + g_signal_emit (helper, signals[ACTION_STATE_CHANGED], 0, value); +} + +static gboolean +call_action_added (gpointer user_data) +{ + IdoActionHelper *helper = user_data; + + ido_action_helper_action_added (helper->actions, helper->action_name, helper); + + return G_SOURCE_REMOVE; +} + +static void +ido_action_helper_constructed (GObject *object) +{ + IdoActionHelper *helper = IDO_ACTION_HELPER (object); + + g_signal_connect (helper->actions, "action-added", + G_CALLBACK (ido_action_helper_action_added), helper); + g_signal_connect (helper->actions, "action-removed", + G_CALLBACK (ido_action_helper_action_removed), helper); + g_signal_connect (helper->actions, "action-enabled-changed", + G_CALLBACK (ido_action_helper_action_enabled_changed), helper); + g_signal_connect (helper->actions, "action-state-changed", + G_CALLBACK (ido_action_helper_action_state_changed), helper); + + if (g_action_group_has_action (helper->actions, helper->action_name)) + { + /* call action_added in an idle, so that we don't fire the + * state-changed signal during construction (nobody could have + * connected by then). + */ + g_idle_add (call_action_added, helper); + } + + G_OBJECT_CLASS (ido_action_helper_parent_class)->constructed (object); +} + +static void +ido_action_helper_get_property (GObject *object, + guint id, + GValue *value, + GParamSpec *pspec) +{ + IdoActionHelper *helper = IDO_ACTION_HELPER (object); + + switch (id) + { + case PROP_WIDGET: + g_value_set_object (value, helper->widget); + break; + + case PROP_ACTION_GROUP: + g_value_set_object (value, helper->actions); + break; + + case PROP_ACTION_NAME: + g_value_set_string (value, helper->action_name); + break; + + case PROP_ACTION_TARGET: + g_value_set_variant (value, helper->action_target); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, id, pspec); + } +} + +static void +ido_action_helper_set_property (GObject *object, + guint id, + const GValue *value, + GParamSpec *pspec) +{ + IdoActionHelper *helper = IDO_ACTION_HELPER (object); + + switch (id) + { + case PROP_WIDGET: /* construct-only */ + helper->widget = g_value_dup_object (value); + break; + + case PROP_ACTION_GROUP: /* construct-only */ + helper->actions = g_value_dup_object (value); + break; + + case PROP_ACTION_NAME: /* construct-only */ + helper->action_name = g_value_dup_string (value); + break; + + case PROP_ACTION_TARGET: /* construct-only */ + helper->action_target = g_value_dup_variant (value); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, id, pspec); + } +} + +static void +ido_action_helper_finalize (GObject *object) +{ + IdoActionHelper *helper = IDO_ACTION_HELPER (object); + + g_object_unref (helper->widget); + + g_signal_handlers_disconnect_by_data (helper->actions, helper); + g_object_unref (helper->actions); + + g_free (helper->action_name); + + if (helper->action_target) + g_variant_unref (helper->action_target); + + G_OBJECT_CLASS (ido_action_helper_parent_class)->finalize (object); +} + +static void +ido_action_helper_class_init (IdoActionHelperClass *class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (class); + + object_class->constructed = ido_action_helper_constructed; + object_class->get_property = ido_action_helper_get_property; + object_class->set_property = ido_action_helper_set_property; + object_class->finalize = ido_action_helper_finalize; + + signals[ACTION_STATE_CHANGED] = g_signal_new ("action-state-changed", + IDO_TYPE_ACTION_HELPER, + G_SIGNAL_RUN_FIRST, + 0, NULL, NULL, + g_cclosure_marshal_VOID__VARIANT, + G_TYPE_NONE, 1, G_TYPE_VARIANT); + + properties[PROP_WIDGET] = g_param_spec_object ("widget", "", "", + GTK_TYPE_WIDGET, + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS); + + properties[PROP_ACTION_GROUP] = g_param_spec_object ("action-group", "", "", + G_TYPE_ACTION_GROUP, + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS); + + properties[PROP_ACTION_NAME] = g_param_spec_string ("action-name", "", "", NULL, + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS); + + properties[PROP_ACTION_TARGET] = g_param_spec_variant ("action-target", "", "", + G_VARIANT_TYPE_ANY, NULL, + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS); + + g_object_class_install_properties (object_class, NUM_PROPERTIES, properties); +} + +static void +ido_action_helper_init (IdoActionHelper *helper) +{ +} + +/** + * ido_action_helper_new: + * @widget: a #GtkWidget + * @action_group: a #GActionGroup + * @action_name: the name of an action in @action_group + * @target: the target of the action + * + * Creates a new #IdoActionHelper. This helper ties @widget to an action + * (and a target), and performs some common tasks: + * + * @widget will be set to insensitive whenever @action_group does not + * contain an action with the name @action_name, or the action with that + * name is disabled. + * + * Also, the helper emits the "action-state-changed" signal whenever the + * widget must be updated from the action's state. This includes once + * when the action was added, and every time the action changes its + * state. + * + * Returns: (transfer full): a new #IdoActionHelper + */ +IdoActionHelper * +ido_action_helper_new (GtkWidget *widget, + GActionGroup *action_group, + const gchar *action_name, + GVariant *target) +{ + g_return_val_if_fail (widget != NULL, NULL); + g_return_val_if_fail (action_group != NULL, NULL); + g_return_val_if_fail (action_name != NULL, NULL); + + return g_object_new (IDO_TYPE_ACTION_HELPER, + "widget", widget, + "action-group", action_group, + "action-name", action_name, + "action-target", target, + NULL); +} + +/** + * ido_action_helper_get_widget: + * @helper: an #IdoActionHelper + * + * Returns: (transfer none): the #GtkWidget associated with @helper + */ +GtkWidget * +ido_action_helper_get_widget (IdoActionHelper *helper) +{ + g_return_val_if_fail (IDO_IS_ACTION_HELPER (helper), NULL); + + return helper->widget; +} + +/** + * ido_action_helper_get_action_target: + * @helper: an #IdoActionHelper + * + * Returns: (transfer none): the action target that was set in + * ido_action_helper_new() as a #GVariant + */ +GVariant * +ido_action_helper_get_action_target (IdoActionHelper *helper) +{ + g_return_val_if_fail (IDO_IS_ACTION_HELPER (helper), NULL); + + return helper->action_target; +} + +/** + * ido_action_helper_activate: + * @helper: an #IdoActionHelper + * + * Activates the action that is associated with this helper. + */ +void +ido_action_helper_activate (IdoActionHelper *helper) +{ + g_return_if_fail (IDO_IS_ACTION_HELPER (helper)); + + if (helper->actions && helper->action_name) + g_action_group_activate_action (helper->actions, helper->action_name, helper->action_target); +} diff --git a/src/idoactionhelper.h b/src/idoactionhelper.h new file mode 100644 index 0000000..22cdcae --- /dev/null +++ b/src/idoactionhelper.h @@ -0,0 +1,44 @@ +/* +* Copyright 2013 Canonical Ltd. +* +* This program is free software: you can redistribute it and/or modify it +* under the terms of the GNU General Public License version 3, 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 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 . +* +* Authors: +* Lars Uebernickel +*/ + +#ifndef __IDO_ACTION_HELPER_H__ +#define __IDO_ACTION_HELPER_H__ + +#include + +#define IDO_TYPE_ACTION_HELPER (ido_action_helper_get_type ()) +#define IDO_ACTION_HELPER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), IDO_TYPE_ACTION_HELPER, IdoActionHelper)) +#define IDO_IS_ACTION_HELPER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), IDO_TYPE_ACTION_HELPER)) + +typedef struct _IdoActionHelper IdoActionHelper; + +GType ido_menu_item_get_type (void); + +IdoActionHelper * ido_action_helper_new (GtkWidget *widget, + GActionGroup *action_group, + const gchar *action_name, + GVariant *target); + +GtkWidget * ido_action_helper_get_widget (IdoActionHelper *helper); + +GVariant * ido_action_helper_get_action_target (IdoActionHelper *helper); + +void ido_action_helper_activate (IdoActionHelper *helper); + +#endif -- cgit v1.2.3 From 424d5f429eb4a85943ce318aa5041d96e9f8731a Mon Sep 17 00:00:00 2001 From: Lars Uebernickel Date: Thu, 23 May 2013 08:58:55 -0400 Subject: Create IdoUserMenuItems for indicator.user-menu-item Only used by the indicator-session/ng branch right now. Doesn't create guest menu items yet. --- src/idomenuitemfactory.c | 106 ++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 105 insertions(+), 1 deletion(-) diff --git a/src/idomenuitemfactory.c b/src/idomenuitemfactory.c index 3eb8049..7f8273d 100644 --- a/src/idomenuitemfactory.c +++ b/src/idomenuitemfactory.c @@ -19,6 +19,9 @@ #include +#include "idoactionhelper.h" +#include "idousermenuitem.h" + #define IDO_TYPE_MENU_ITEM_FACTORY (ido_menu_item_factory_get_type ()) #define IDO_MENU_ITEM_FACTORY(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), IDO_TYPE_MENU_ITEM_FACTORY, IdoMenuItemFactory)) #define IDO_IS_MENU_ITEM_FACTORY(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), IDO_TYPE_MENU_ITEM_FACTORY)) @@ -34,13 +37,114 @@ G_DEFINE_TYPE_WITH_CODE (IdoMenuItemFactory, ido_menu_item_factory, G_TYPE_OBJEC g_io_extension_point_implement (GTK_MENU_ITEM_FACTORY_EXTENSION_POINT_NAME, g_define_type_id, "ido", 0);) +/** + * user_menu_item_state_changed: + * + * Updates an IdoUserMenuItem from @state. The state contains a + * dictionary with keys 'active-user' (for the user that the current + * session belongs too) and 'logged-in-users' (a list of all currently + * logged in users). + */ +static void +user_menu_item_state_changed (IdoActionHelper *helper, + GVariant *state, + gpointer user_data) +{ + IdoUserMenuItem *item; + GVariant *target; + GVariant *v; + + item = IDO_USER_MENU_ITEM (ido_action_helper_get_widget (helper)); + + ido_user_menu_item_set_current_user (item, FALSE); + ido_user_menu_item_set_logged_in (item, FALSE); + + target = ido_action_helper_get_action_target (helper); + g_return_if_fail (g_variant_is_of_type (target, G_VARIANT_TYPE_STRING)); + + if ((v = g_variant_lookup_value (state, "active-user", G_VARIANT_TYPE_STRING))) + { + if (g_variant_equal (v, target)) + ido_user_menu_item_set_current_user (item, TRUE); + + g_variant_unref (v); + } + + if ((v = g_variant_lookup_value (state, "logged-in-users", G_VARIANT_TYPE_STRING_ARRAY))) + { + GVariantIter it; + GVariant *user; + + g_variant_iter_init (&it, v); + while ((user = g_variant_iter_next_value (&it))) + { + if (g_variant_equal (user, target)) + ido_user_menu_item_set_logged_in (item, TRUE); + g_variant_unref (user); + } + + g_variant_unref (v); + } +} + +/** + * create_user_menu_item: + * + * Creates an IdoUserMenuItem. If @menuitem contains an action, the + * widget is bound to that action in @actions. + */ +static GtkMenuItem * +create_user_menu_item (GMenuItem *menuitem, + GActionGroup *actions) +{ + IdoUserMenuItem *item; + gchar *label; + gchar *action; + + item = IDO_USER_MENU_ITEM (ido_user_menu_item_new ()); + + if (g_menu_item_get_attribute (menuitem, "label", "s", &label)) + { + ido_user_menu_item_set_label (item, label); + g_free (label); + } + + if (g_menu_item_get_attribute (menuitem, "action", "s", &action)) + { + IdoActionHelper *helper; + GVariant *target; + + target = g_menu_item_get_attribute_value (menuitem, "target", G_VARIANT_TYPE_ANY); + + helper = ido_action_helper_new (GTK_WIDGET (item), actions, action, target); + g_signal_connect (helper, "action-state-changed", + G_CALLBACK (user_menu_item_state_changed), NULL); + + g_signal_connect_object (item, "activate", + G_CALLBACK (ido_action_helper_activate), + helper, G_CONNECT_SWAPPED); + g_signal_connect_swapped (item, "destroy", G_CALLBACK (g_object_unref), helper); + + if (target) + g_variant_unref (target); + g_free (action); + } + + return GTK_MENU_ITEM (item); +} + static GtkMenuItem * ido_menu_item_factory_create_menu_item (GtkMenuItemFactory *factory, const gchar *type, GMenuItem *menuitem, GActionGroup *actions) { - return NULL; + GtkMenuItem *item = NULL; + + if (g_str_equal (type, "indicator.user-menu-item")) + item = create_user_menu_item (menuitem, actions); + + return item; } static void -- cgit v1.2.3 From 725c0adef66ff7c25ad683cf78304196c868aff3 Mon Sep 17 00:00:00 2001 From: Lars Uebernickel Date: Thu, 23 May 2013 18:41:17 -0400 Subject: Bumb version to 13.10 --- configure.ac | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index 2219ff0..4b6591f 100644 --- a/configure.ac +++ b/configure.ac @@ -1,9 +1,9 @@ # # shamelessly stolen from clutter-gtk # -m4_define([ido_major_version], [12]) +m4_define([ido_major_version], [13]) m4_define([ido_minor_version], [10]) -m4_define([ido_micro_version], [2]) +m4_define([ido_micro_version], [0]) m4_define([ido_api_version], [ido_major_version.ido_minor_version]) -- cgit v1.2.3 From 2c0fa18b2452ab23f70ffb3feae21a88b8f05053 Mon Sep 17 00:00:00 2001 From: Lars Uebernickel Date: Fri, 24 May 2013 15:17:47 -0400 Subject: GtkMenuItemFactory -> UbuntuMenuItemFactory --- src/idomenuitemfactory.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/idomenuitemfactory.c b/src/idomenuitemfactory.c index 7f8273d..c8e61f4 100644 --- a/src/idomenuitemfactory.c +++ b/src/idomenuitemfactory.c @@ -18,6 +18,7 @@ */ #include +#include #include "idoactionhelper.h" #include "idousermenuitem.h" @@ -30,11 +31,11 @@ typedef GObject IdoMenuItemFactory; typedef GObjectClass IdoMenuItemFactoryClass; GType ido_menu_item_factory_get_type (void); -static void ido_menu_item_factory_interface_init (GtkMenuItemFactoryInterface *iface); +static void ido_menu_item_factory_interface_init (UbuntuMenuItemFactoryInterface *iface); G_DEFINE_TYPE_WITH_CODE (IdoMenuItemFactory, ido_menu_item_factory, G_TYPE_OBJECT, - G_IMPLEMENT_INTERFACE (GTK_TYPE_MENU_ITEM_FACTORY, ido_menu_item_factory_interface_init) - g_io_extension_point_implement (GTK_MENU_ITEM_FACTORY_EXTENSION_POINT_NAME, + G_IMPLEMENT_INTERFACE (UBUNTU_TYPE_MENU_ITEM_FACTORY, ido_menu_item_factory_interface_init) + g_io_extension_point_implement (UBUNTU_MENU_ITEM_FACTORY_EXTENSION_POINT_NAME, g_define_type_id, "ido", 0);) /** @@ -134,10 +135,10 @@ create_user_menu_item (GMenuItem *menuitem, } static GtkMenuItem * -ido_menu_item_factory_create_menu_item (GtkMenuItemFactory *factory, - const gchar *type, - GMenuItem *menuitem, - GActionGroup *actions) +ido_menu_item_factory_create_menu_item (UbuntuMenuItemFactory *factory, + const gchar *type, + GMenuItem *menuitem, + GActionGroup *actions) { GtkMenuItem *item = NULL; @@ -153,7 +154,7 @@ ido_menu_item_factory_class_init (IdoMenuItemFactoryClass *class) } static void -ido_menu_item_factory_interface_init (GtkMenuItemFactoryInterface *iface) +ido_menu_item_factory_interface_init (UbuntuMenuItemFactoryInterface *iface) { iface->create_menu_item = ido_menu_item_factory_create_menu_item; } -- cgit v1.2.3 From d447489787ee1e6a8203842ad0a8e7518136db43 Mon Sep 17 00:00:00 2001 From: Lars Uebernickel Date: Mon, 27 May 2013 11:10:39 -0400 Subject: debian/changelog: bump version --- debian/changelog | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/debian/changelog b/debian/changelog index 217d98b..d5204f4 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,9 @@ +ido (13.10.0-0ubuntu1) UNRELEASED; urgency=low + + * New upstream release + + -- Lars Uebernickel Mon, 27 May 2013 10:56:11 -0400 + ido (12.10.3daily13.03.01-0ubuntu1) raring; urgency=low [ Mathieu Trudel-Lapierre ] -- cgit v1.2.3 From 07f79077388bda20a28fcd38a9e5b60631794ffe Mon Sep 17 00:00:00 2001 From: Lars Uebernickel Date: Mon, 27 May 2013 11:11:02 -0400 Subject: IdoActionHelper: document signals and properties --- src/idoactionhelper.c | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/src/idoactionhelper.c b/src/idoactionhelper.c index b68423a..fdd9479 100644 --- a/src/idoactionhelper.c +++ b/src/idoactionhelper.c @@ -242,6 +242,15 @@ ido_action_helper_class_init (IdoActionHelperClass *class) object_class->set_property = ido_action_helper_set_property; object_class->finalize = ido_action_helper_finalize; + /** + * IdoActionHelper::action-state-changed: + * @helper: the #IdoActionHelper watching the action + * @state: the new state of the action + * + * Emitted when the widget must be updated from the action's state, + * which happens every time the action appears in the group and when + * the action changes its state. + */ signals[ACTION_STATE_CHANGED] = g_signal_new ("action-state-changed", IDO_TYPE_ACTION_HELPER, G_SIGNAL_RUN_FIRST, @@ -249,23 +258,53 @@ ido_action_helper_class_init (IdoActionHelperClass *class) g_cclosure_marshal_VOID__VARIANT, G_TYPE_NONE, 1, G_TYPE_VARIANT); + /** + * IdoActionHelper:widget: + * + * The widget that is associated with this action helper. The action + * helper updates the widget's "sensitive" property to reflect whether + * the action #IdoActionHelper:action-name exists in + * #IdoActionHelper:action-group. + */ properties[PROP_WIDGET] = g_param_spec_object ("widget", "", "", GTK_TYPE_WIDGET, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + /** + * IdoActionHelper:action-group: + * + * The action group that eventually contains the action that + * #IdoActionHelper:widget should be bound to. + */ properties[PROP_ACTION_GROUP] = g_param_spec_object ("action-group", "", "", G_TYPE_ACTION_GROUP, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + /** + * IdoActionHelper:action-name: + * + * The name of the action in #IdoActionHelper:action-group that + * should be bound to #IdoActionHelper:widget + */ properties[PROP_ACTION_NAME] = g_param_spec_string ("action-name", "", "", NULL, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + /** + * IdoActionHelper:action-target: + * + * The target of #IdoActionHelper:widget. ido_action_helper_activate() + * passes the target as parameter when activating the action. + * + * The handler of #IdoActionHelper:action-state-changed is responsible + * for comparing this target with the action's state and updating the + * #IdoActionHelper:widget appropriately. + */ properties[PROP_ACTION_TARGET] = g_param_spec_variant ("action-target", "", "", G_VARIANT_TYPE_ANY, NULL, G_PARAM_CONSTRUCT_ONLY | -- cgit v1.2.3 From e863f12e806f60b3592ca09211d8dd96d6dde810 Mon Sep 17 00:00:00 2001 From: Lars Uebernickel Date: Mon, 27 May 2013 12:04:11 -0400 Subject: Move crate_user_menu_item into idousermenuitem.c We expect to have quite a few custom widgets. Having them all in idomenuitemfactory.c would clutter that file up too much. --- src/idomenuitemfactory.c | 99 +----------------------------------------------- src/idousermenuitem.c | 98 +++++++++++++++++++++++++++++++++++++++++++++++ src/idousermenuitem.h | 3 ++ 3 files changed, 102 insertions(+), 98 deletions(-) diff --git a/src/idomenuitemfactory.c b/src/idomenuitemfactory.c index c8e61f4..59f3630 100644 --- a/src/idomenuitemfactory.c +++ b/src/idomenuitemfactory.c @@ -20,7 +20,6 @@ #include #include -#include "idoactionhelper.h" #include "idousermenuitem.h" #define IDO_TYPE_MENU_ITEM_FACTORY (ido_menu_item_factory_get_type ()) @@ -38,102 +37,6 @@ G_DEFINE_TYPE_WITH_CODE (IdoMenuItemFactory, ido_menu_item_factory, G_TYPE_OBJEC g_io_extension_point_implement (UBUNTU_MENU_ITEM_FACTORY_EXTENSION_POINT_NAME, g_define_type_id, "ido", 0);) -/** - * user_menu_item_state_changed: - * - * Updates an IdoUserMenuItem from @state. The state contains a - * dictionary with keys 'active-user' (for the user that the current - * session belongs too) and 'logged-in-users' (a list of all currently - * logged in users). - */ -static void -user_menu_item_state_changed (IdoActionHelper *helper, - GVariant *state, - gpointer user_data) -{ - IdoUserMenuItem *item; - GVariant *target; - GVariant *v; - - item = IDO_USER_MENU_ITEM (ido_action_helper_get_widget (helper)); - - ido_user_menu_item_set_current_user (item, FALSE); - ido_user_menu_item_set_logged_in (item, FALSE); - - target = ido_action_helper_get_action_target (helper); - g_return_if_fail (g_variant_is_of_type (target, G_VARIANT_TYPE_STRING)); - - if ((v = g_variant_lookup_value (state, "active-user", G_VARIANT_TYPE_STRING))) - { - if (g_variant_equal (v, target)) - ido_user_menu_item_set_current_user (item, TRUE); - - g_variant_unref (v); - } - - if ((v = g_variant_lookup_value (state, "logged-in-users", G_VARIANT_TYPE_STRING_ARRAY))) - { - GVariantIter it; - GVariant *user; - - g_variant_iter_init (&it, v); - while ((user = g_variant_iter_next_value (&it))) - { - if (g_variant_equal (user, target)) - ido_user_menu_item_set_logged_in (item, TRUE); - g_variant_unref (user); - } - - g_variant_unref (v); - } -} - -/** - * create_user_menu_item: - * - * Creates an IdoUserMenuItem. If @menuitem contains an action, the - * widget is bound to that action in @actions. - */ -static GtkMenuItem * -create_user_menu_item (GMenuItem *menuitem, - GActionGroup *actions) -{ - IdoUserMenuItem *item; - gchar *label; - gchar *action; - - item = IDO_USER_MENU_ITEM (ido_user_menu_item_new ()); - - if (g_menu_item_get_attribute (menuitem, "label", "s", &label)) - { - ido_user_menu_item_set_label (item, label); - g_free (label); - } - - if (g_menu_item_get_attribute (menuitem, "action", "s", &action)) - { - IdoActionHelper *helper; - GVariant *target; - - target = g_menu_item_get_attribute_value (menuitem, "target", G_VARIANT_TYPE_ANY); - - helper = ido_action_helper_new (GTK_WIDGET (item), actions, action, target); - g_signal_connect (helper, "action-state-changed", - G_CALLBACK (user_menu_item_state_changed), NULL); - - g_signal_connect_object (item, "activate", - G_CALLBACK (ido_action_helper_activate), - helper, G_CONNECT_SWAPPED); - g_signal_connect_swapped (item, "destroy", G_CALLBACK (g_object_unref), helper); - - if (target) - g_variant_unref (target); - g_free (action); - } - - return GTK_MENU_ITEM (item); -} - static GtkMenuItem * ido_menu_item_factory_create_menu_item (UbuntuMenuItemFactory *factory, const gchar *type, @@ -143,7 +46,7 @@ ido_menu_item_factory_create_menu_item (UbuntuMenuItemFactory *factory, GtkMenuItem *item = NULL; if (g_str_equal (type, "indicator.user-menu-item")) - item = create_user_menu_item (menuitem, actions); + item = ido_user_menu_item_new_from_model (menuitem, actions); return item; } diff --git a/src/idousermenuitem.c b/src/idousermenuitem.c index cb405e8..42b3c7b 100644 --- a/src/idousermenuitem.c +++ b/src/idousermenuitem.c @@ -26,6 +26,7 @@ with this program. If not, see . #include #include "idousermenuitem.h" +#include "idoactionhelper.h" #define FALLBACK_ICON_NAME "avatar-default" @@ -355,3 +356,100 @@ ido_user_menu_item_new (void) { return GTK_WIDGET (g_object_new (IDO_USER_MENU_ITEM_TYPE, NULL)); } + +/** + * user_menu_item_state_changed: + * + * Updates an IdoUserMenuItem from @state. The state contains a + * dictionary with keys 'active-user' (for the user that the current + * session belongs too) and 'logged-in-users' (a list of all currently + * logged in users). + */ +static void +user_menu_item_state_changed (IdoActionHelper *helper, + GVariant *state, + gpointer user_data) +{ + IdoUserMenuItem *item; + GVariant *target; + GVariant *v; + + item = IDO_USER_MENU_ITEM (ido_action_helper_get_widget (helper)); + + ido_user_menu_item_set_current_user (item, FALSE); + ido_user_menu_item_set_logged_in (item, FALSE); + + target = ido_action_helper_get_action_target (helper); + g_return_if_fail (g_variant_is_of_type (target, G_VARIANT_TYPE_STRING)); + + if ((v = g_variant_lookup_value (state, "active-user", G_VARIANT_TYPE_STRING))) + { + if (g_variant_equal (v, target)) + ido_user_menu_item_set_current_user (item, TRUE); + + g_variant_unref (v); + } + + if ((v = g_variant_lookup_value (state, "logged-in-users", G_VARIANT_TYPE_STRING_ARRAY))) + { + GVariantIter it; + GVariant *user; + + g_variant_iter_init (&it, v); + while ((user = g_variant_iter_next_value (&it))) + { + if (g_variant_equal (user, target)) + ido_user_menu_item_set_logged_in (item, TRUE); + g_variant_unref (user); + } + + g_variant_unref (v); + } +} + +/** + * ido_user_menu_item_create: + * + * Creates an IdoUserMenuItem. If @menuitem contains an action, the + * widget is bound to that action in @actions. + */ +GtkMenuItem * +ido_user_menu_item_new_from_model (GMenuItem *menuitem, + GActionGroup *actions) +{ + IdoUserMenuItem *item; + gchar *label; + gchar *action; + + item = IDO_USER_MENU_ITEM (ido_user_menu_item_new ()); + + if (g_menu_item_get_attribute (menuitem, "label", "s", &label)) + { + ido_user_menu_item_set_label (item, label); + g_free (label); + } + + if (g_menu_item_get_attribute (menuitem, "action", "s", &action)) + { + IdoActionHelper *helper; + GVariant *target; + + target = g_menu_item_get_attribute_value (menuitem, "target", G_VARIANT_TYPE_ANY); + + helper = ido_action_helper_new (GTK_WIDGET (item), actions, action, target); + g_signal_connect (helper, "action-state-changed", + G_CALLBACK (user_menu_item_state_changed), NULL); + + g_signal_connect_object (item, "activate", + G_CALLBACK (ido_action_helper_activate), + helper, G_CONNECT_SWAPPED); + g_signal_connect_swapped (item, "destroy", G_CALLBACK (g_object_unref), helper); + + if (target) + g_variant_unref (target); + g_free (action); + } + + return GTK_MENU_ITEM (item); +} + diff --git a/src/idousermenuitem.h b/src/idousermenuitem.h index b9a3d00..d51f6c7 100644 --- a/src/idousermenuitem.h +++ b/src/idousermenuitem.h @@ -61,6 +61,9 @@ void ido_user_menu_item_set_logged_in (IdoUserMenuItem * self, gboolean i void ido_user_menu_item_set_current_user (IdoUserMenuItem * self, gboolean is_current_user); void ido_user_menu_item_set_label (IdoUserMenuItem * self, const char * label); +GtkMenuItem * ido_user_menu_item_new_from_model (GMenuItem *menuitem, + GActionGroup *actions); + G_END_DECLS #endif -- cgit v1.2.3 From 3578bb3ac7407a051e26797043e7c3089f92d438 Mon Sep 17 00:00:00 2001 From: Lars Uebernickel Date: Fri, 31 May 2013 11:15:39 -0400 Subject: ido_user_menu_item_new_from_model: fix docstring --- src/idousermenuitem.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/idousermenuitem.c b/src/idousermenuitem.c index 42b3c7b..4c6e81d 100644 --- a/src/idousermenuitem.c +++ b/src/idousermenuitem.c @@ -408,10 +408,12 @@ user_menu_item_state_changed (IdoActionHelper *helper, } /** - * ido_user_menu_item_create: + * ido_user_menu_item_new_from_model: * - * Creates an IdoUserMenuItem. If @menuitem contains an action, the + * Creates an #IdoUserMenuItem. If @menuitem contains an action, the * widget is bound to that action in @actions. + * + * Returns: (transfer full): a new #IdoUserMenuItem */ GtkMenuItem * ido_user_menu_item_new_from_model (GMenuItem *menuitem, -- cgit v1.2.3 From 52b6ef7b96aa4ededb49284d9f3d84de6eda313f Mon Sep 17 00:00:00 2001 From: Lars Uebernickel Date: Fri, 31 May 2013 14:02:40 -0400 Subject: Bump glib and gtk dependencies --- configure.ac | 6 +++--- debian/control | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/configure.ac b/configure.ac index 4b6591f..706919f 100644 --- a/configure.ac +++ b/configure.ac @@ -79,11 +79,11 @@ AC_FUNC_MMAP AC_CHECK_FUNCS([memset munmap strcasecmp strdup]) AC_CHECK_LIBM -GLIB_REQUIRED_VERSION=2.32.0 -GTK_REQUIRED_VERSION=3.4.0 +GIO_REQUIRED_VERSION=2.37.0 +GTK_REQUIRED_VERSION=3.8.2 PKG_CHECK_MODULES(GTK,[gtk+-3.0 >= $GTK_REQUIRED_VERSION - glib-2.0 >= $GLIB_REQUIRED_VERSION]) + gio-2.0 >= $GIO_REQUIRED_VERSION]) AC_SUBST(GTK_CFLAGS) AC_SUBST(GTK_LIBS) diff --git a/debian/control b/debian/control index c706502..f9f385b 100644 --- a/debian/control +++ b/debian/control @@ -10,7 +10,7 @@ Build-Depends: debhelper (>= 9), libx11-dev, libgtest-dev, libglib2.0-dev (>=2.14.0), - libgtk-3-dev (>= 3.0), + libgtk-3-dev (>= 3.8.2-0ubuntu2), gtk-doc-tools, gobject-introspection, libgirepository1.0-dev, @@ -45,7 +45,7 @@ Depends: ${shlibs:Depends}, libido3-0.1-0 (= ${binary:Version}), pkg-config, libglib2.0-dev (>=2.14.0), - libgtk-3-dev (>= 3.0), + libgtk-3-dev (>= 3.8.2-0ubuntu2), Description: Shared library providing extra gtk menu items for display in system indicators . -- cgit v1.2.3 From 18f2ca9e20c5ea1ac895f7892ae9d652153333ad Mon Sep 17 00:00:00 2001 From: Lars Uebernickel Date: Fri, 31 May 2013 14:42:41 -0400 Subject: debian: add new symbols --- debian/libido3-0.1-0.symbols | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/debian/libido3-0.1-0.symbols b/debian/libido3-0.1-0.symbols index 2ddb354..342ee31 100644 --- a/debian/libido3-0.1-0.symbols +++ b/debian/libido3-0.1-0.symbols @@ -58,3 +58,17 @@ libido3-0.1.so.0 libido3-0.1-0 #MINVER# ido_timeline_set_progress@Base 0.1.10 ido_timeline_set_screen@Base 0.1.8 ido_timeline_start@Base 0.1.8 + ido_action_helper_activate@Base 0replaceme + ido_action_helper_get_action_target@Base 0replaceme + ido_action_helper_get_type@Base 0replaceme + ido_action_helper_get_widget@Base 0replaceme + ido_action_helper_new@Base 0replaceme + ido_user_menu_item_get_type@Base 0replaceme + ido_user_menu_item_new@Base 0replaceme + ido_user_menu_item_set_current_user@Base 0replaceme + ido_user_menu_item_set_icon@Base 0replaceme + ido_user_menu_item_set_label@Base 0replaceme + ido_user_menu_item_set_logged_in@Base 0replaceme + ido_user_menu_item_new_from_model@Base 0replaceme + ido_init@Base 0replaceme + ido_menu_item_factory_get_type@Base 0replaceme -- cgit v1.2.3