aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/user-widget.c292
-rw-r--r--src/user-widget.h55
2 files changed, 347 insertions, 0 deletions
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 <conor.curran@canonical.com>
+ Mirco Müller <mirco.mueller@canonical.com>
+ Charles Kerr <charles.kerr@canonical.com>
+
+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 <http://www.gnu.org/licenses/>.
+*/
+
+#ifdef HAVE_CONFIG_H
+ #include "config.h"
+#endif
+
+#include <gtk/gtk.h>
+
+#include <libindicator/indicator-image-helper.h>
+
+#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 <conor.curran@canonical.com>
+
+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 <http://www.gnu.org/licenses/>.
+*/
+#ifndef __USER_WIDGET_H__
+#define __USER_WIDGET_H__
+
+#include <gtk/gtk.h>
+#include <libdbusmenu-gtk/menuitem.h>
+
+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