2
Copyright 2011 Canonical Ltd.
5
Conor Curran <conor.curran@canonical.com>
6
Mirco Müller <mirco.mueller@canonical.com>
8
This program is free software: you can redistribute it and/or modify it
9
under the terms of the GNU General Public License version 3, as published
10
by the Free Software Foundation.
12
This program is distributed in the hope that it will be useful, but
13
WITHOUT ANY WARRANTY; without even the implied warranties of
14
MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
15
PURPOSE. See the GNU General Public License for more details.
17
You should have received a copy of the GNU General Public License along
18
with this program. If not, see <http://www.gnu.org/licenses/>.
25
#include <glib/gi18n.h>
29
#include <libindicator/indicator-image-helper.h>
30
#include "user-widget.h"
31
#include "dbus-shared-names.h"
34
typedef struct _UserWidgetPrivate UserWidgetPrivate;
36
struct _UserWidgetPrivate
38
DbusmenuMenuitem* twin_item;
39
GtkWidget* user_image;
40
gboolean using_personal_icon;
45
gboolean sessions_active;
48
#define USER_WIDGET_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), USER_WIDGET_TYPE, UserWidgetPrivate))
58
static void user_widget_class_init (UserWidgetClass *klass);
59
static void user_widget_init (UserWidget *self);
60
static void user_widget_dispose (GObject *object);
61
static void user_widget_finalize (GObject *object);
63
static void user_widget_set_twin_item (UserWidget* self,
64
DbusmenuMenuitem* twin_item);
66
static gboolean user_widget_button_release_event (GtkWidget *menuitem,
67
GdkEventButton *event);
68
// Dbusmenuitem properties update callback
69
static void user_widget_property_update (DbusmenuMenuitem* item,
75
static void _color_shade (const CairoColorRGB *a,
79
static void draw_album_border (GtkWidget *widget, gboolean selected);
81
#if GTK_CHECK_VERSION(3, 0, 0)
82
static gboolean user_widget_primitive_draw_cb_gtk_3 (GtkWidget *image,
85
static gboolean user_widget_draw_usericon_gtk_3 (GtkWidget *widget,
90
static gboolean user_widget_primitive_draw_cb (GtkWidget *image,
91
GdkEventExpose *event,
93
static gboolean user_widget_draw_usericon_gtk_2 (GtkWidget *widget,
94
GdkEventExpose *event,
99
G_DEFINE_TYPE (UserWidget, user_widget, GTK_TYPE_MENU_ITEM);
102
user_widget_class_init (UserWidgetClass *klass)
104
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
105
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
107
widget_class->button_release_event = user_widget_button_release_event;
109
g_type_class_add_private (klass, sizeof (UserWidgetPrivate));
111
gobject_class->dispose = user_widget_dispose;
112
gobject_class->finalize = user_widget_finalize;
116
user_widget_init (UserWidget *self)
118
UserWidgetPrivate * priv = USER_WIDGET_GET_PRIVATE(self);
121
gtk_widget_style_get (GTK_WIDGET(self),
122
"horizontal-padding",
126
priv->user_image = NULL;
127
priv->user_name = NULL;
128
priv->logged_in = FALSE;
129
priv->sessions_active = FALSE;
130
priv->container = NULL;
131
priv->tick_icon = NULL;
133
// Create the UI elements.
134
priv->user_image = gtk_image_new ();
135
gtk_misc_set_alignment(GTK_MISC(priv->user_image), 0.0, 0.0);
136
gtk_misc_set_padding (GTK_MISC(priv->user_image),0, 4.0);
138
priv->user_name = gtk_label_new ("");
141
priv->container = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
143
priv->container = gtk_hbox_new (FALSE, 0);
146
priv->tick_icon = gtk_image_new_from_icon_name ("account-logged-in",
148
gtk_misc_set_alignment(GTK_MISC(priv->tick_icon), 1.0, 0.5);
151
gtk_box_pack_start (GTK_BOX (priv->container),
156
gtk_box_pack_start (GTK_BOX (priv->container),
161
gtk_box_pack_start (GTK_BOX(priv->container),
166
gtk_widget_show_all (priv->container);
167
gtk_container_add (GTK_CONTAINER (self), priv->container);
168
gtk_widget_show_all (priv->tick_icon);
169
gtk_widget_set_no_show_all (priv->tick_icon, TRUE);
170
gtk_widget_hide (priv->tick_icon);
173
// Fetch the drawing context.
174
#if GTK_CHECK_VERSION(3, 0, 0)
175
g_signal_connect_after (GTK_WIDGET(self), "draw",
176
G_CALLBACK(user_widget_primitive_draw_cb_gtk_3),
179
g_signal_connect_after (GTK_WIDGET(priv->user_image), "draw",
180
G_CALLBACK(user_widget_draw_usericon_gtk_3),
184
g_signal_connect_after (GTK_WIDGET(self), "expose-event",
185
G_CALLBACK(user_widget_primitive_draw_cb),
187
g_signal_connect_after (GTK_WIDGET(priv->user_image), "expose-event",
188
G_CALLBACK(user_widget_draw_usericon_gtk_2),
194
user_widget_dispose (GObject *object)
196
G_OBJECT_CLASS (user_widget_parent_class)->dispose (object);
199
// TODO tidy up image and name
201
user_widget_finalize (GObject *object)
203
G_OBJECT_CLASS (user_widget_parent_class)->finalize (object);
207
/*****************************************************************/
209
#if GTK_CHECK_VERSION(3, 0, 0)
211
// TODO handle drawing of green check mark
213
user_widget_primitive_draw_cb_gtk_3 (GtkWidget *widget,
218
g_return_val_if_fail(IS_USER_WIDGET(user_data), FALSE);
219
UserWidget* meta = USER_WIDGET(user_data);
220
UserWidgetPrivate * priv = USER_WIDGET_GET_PRIVATE(meta);
222
// Draw dot only when user is the current user.
223
if (!dbusmenu_menuitem_property_get_bool (priv->twin_item,
224
USER_ITEM_PROP_IS_CURRENT_USER)){
230
style = gtk_widget_get_style (widget);
232
GtkAllocation allocation;
233
gtk_widget_get_allocation (widget, &allocation);
234
x = allocation.x + 13;
235
y = allocation.height / 2;
237
cairo_arc (cr, x, y, 3.0, 0.0, 2 * G_PI);;
239
cairo_set_source_rgb (cr, style->fg[gtk_widget_get_state(widget)].red/65535.0,
240
style->fg[gtk_widget_get_state(widget)].green/65535.0,
241
style->fg[gtk_widget_get_state(widget)].blue/65535.0);
248
user_widget_draw_usericon_gtk_3 (GtkWidget *widget,
252
g_return_val_if_fail(IS_USER_WIDGET(user_data), FALSE);
253
UserWidget* meta = USER_WIDGET(user_data);
254
UserWidgetPrivate * priv = USER_WIDGET_GET_PRIVATE(meta);
256
if (priv->using_personal_icon == FALSE)
259
draw_album_border (widget, FALSE);
266
// GTK 2 Expose handler
270
user_widget_draw_usericon_gtk_2 (GtkWidget *widget,
271
GdkEventExpose *event,
274
g_return_val_if_fail(IS_USER_WIDGET(user_data), FALSE);
275
UserWidget* meta = USER_WIDGET(user_data);
276
UserWidgetPrivate * priv = USER_WIDGET_GET_PRIVATE(meta);
278
if (priv->using_personal_icon == FALSE)
281
draw_album_border (widget, FALSE);
286
user_widget_primitive_draw_cb (GtkWidget *widget,
287
GdkEventExpose *event,
290
g_return_val_if_fail(IS_USER_WIDGET(user_data), FALSE);
291
UserWidget* meta = USER_WIDGET(user_data);
292
UserWidgetPrivate * priv = USER_WIDGET_GET_PRIVATE(meta);
294
// Draw dot only when user is the current user.
295
if (!dbusmenu_menuitem_property_get_bool (priv->twin_item,
296
USER_ITEM_PROP_IS_CURRENT_USER)){
302
cr = (cairo_t*) gdk_cairo_create (gtk_widget_get_window (widget));
305
style = gtk_widget_get_style (widget);
307
GtkAllocation allocation;
309
gtk_widget_get_allocation (widget, &allocation);
310
x = allocation.x + 13;
311
y = allocation.y + allocation.height/2;
313
cairo_arc (cr, x, y, 3.0, 0.0, 2 * G_PI);;
315
cairo_set_source_rgb (cr, style->fg[gtk_widget_get_state(widget)].red/65535.0,
316
style->fg[gtk_widget_get_state(widget)].green/65535.0,
317
style->fg[gtk_widget_get_state(widget)].blue/65535.0);
327
draw_album_border(GtkWidget *widg, gboolean selected)
330
cr = gdk_cairo_create (gtk_widget_get_window (widg));
331
#if GTK_CHECK_VERSION(3, 0, 0)
332
gtk_style_context_add_class (gtk_widget_get_style_context (widg),
337
style = gtk_widget_get_style (widg);
340
gtk_widget_get_allocation (widg, &alloc);
344
alloc.width = alloc.width + (offset * 2);
345
alloc.height = alloc.height - v_offset - 2;
346
alloc.x = alloc.x - offset;
347
alloc.y = alloc.y + v_offset/2 +1;
349
CairoColorRGB bg_normal, fg_normal;
351
bg_normal.r = style->bg[0].red/65535.0;
352
bg_normal.g = style->bg[0].green/65535.0;
353
bg_normal.b = style->bg[0].blue/65535.0;
355
gint state = selected ? 5 : 0;
357
fg_normal.r = style->fg[state].red/65535.0;
358
fg_normal.g = style->fg[state].green/65535.0;
359
fg_normal.b = style->fg[state].blue/65535.0;
361
CairoColorRGB dark_top_color;
362
CairoColorRGB light_bottom_color;
363
CairoColorRGB background_color;
365
_color_shade ( &bg_normal, 0.93, &background_color );
366
_color_shade ( &bg_normal, 0.23, &dark_top_color );
367
_color_shade ( &fg_normal, 0.55, &light_bottom_color );
371
alloc.width, alloc.height);
373
cairo_set_line_width (cr, 1.0);
377
cairo_move_to (cr, alloc.x, alloc.y );
378
cairo_line_to (cr, alloc.x + alloc.width,
380
cairo_line_to ( cr, alloc.x + alloc.width,
381
alloc.y + alloc.height );
382
cairo_line_to ( cr, alloc.x, alloc.y + alloc.height );
383
cairo_line_to ( cr, alloc.x, alloc.y);
384
cairo_close_path (cr);
386
cairo_set_source_rgba ( cr,
394
cairo_move_to (cr, alloc.x, alloc.y );
395
cairo_line_to (cr, alloc.x + alloc.width,
398
cairo_close_path (cr);
399
cairo_set_source_rgba ( cr,
407
cairo_move_to ( cr, alloc.x + alloc.width,
408
alloc.y + alloc.height );
409
cairo_line_to ( cr, alloc.x, alloc.y + alloc.height );
411
cairo_close_path (cr);
412
cairo_set_source_rgba ( cr,
413
light_bottom_color.r,
414
light_bottom_color.g,
415
light_bottom_color.b,
423
_color_rgb_to_hls (gdouble *r,
466
if (fabs (max-min) < 0.0001)
474
s = (max-min)/(max+min);
476
s = (max-min)/(2-max-min);
478
delta = (max -min) != 0 ? (max -min) : 1;
483
h = (green-blue)/delta;
484
else if (green == max)
485
h = 2+(blue-red)/delta;
486
else if (blue == max)
487
h = 4+(red-green)/delta;
500
_color_hls_to_rgb (gdouble *h,
513
if (lightness <= 0.5)
514
m2 = lightness*(1+saturation);
516
m2 = lightness+saturation-lightness*saturation;
535
r = m1+(m2-m1)*hue/60;
539
r = m1+(m2-m1)*(240-hue)/60;
550
g = m1+(m2-m1)*hue/60;
554
g = m1+(m2-m1)*(240-hue)/60;
565
b = m1+(m2-m1)*hue/60;
569
b = m1+(m2-m1)*(240-hue)/60;
580
_color_shade (const CairoColorRGB *a, float k, CairoColorRGB *b)
598
_color_rgb_to_hls (&red, &green, &blue);
603
else if (green < 0.0)
612
_color_hls_to_rgb (&red, &green, &blue);
620
/*****************************************************************/
622
/* Suppress/consume keyevents */
624
user_widget_button_release_event (GtkWidget *menuitem,
625
GdkEventButton *event)
632
* TODO, be sensitive to UI updates
635
user_widget_property_update (DbusmenuMenuitem* item, gchar* property,
636
GVariant* value, gpointer userdata)
638
g_return_if_fail (IS_USER_WIDGET (userdata));
639
//gtk_widget_queue_redraw (GTK_WIDGET(userdata));
646
user_widget_set_twin_item (UserWidget* self,
647
DbusmenuMenuitem* twin_item)
649
UserWidgetPrivate* priv = USER_WIDGET_GET_PRIVATE(self);
650
priv->twin_item = twin_item;
651
g_signal_connect( G_OBJECT(priv->twin_item), "property-changed",
652
G_CALLBACK(user_widget_property_update), self);
654
const gchar * icon_name = dbusmenu_menuitem_property_get (twin_item,
655
USER_ITEM_PROP_ICON);
656
gtk_label_set_label (GTK_LABEL (priv->user_name),
657
dbusmenu_menuitem_property_get (twin_item, USER_ITEM_PROP_NAME));
659
if (dbusmenu_menuitem_property_get_bool (twin_item, USER_ITEM_PROP_LOGGED_IN)) {
660
g_debug ("%s USER HAS ACTIVE SESSIONS",
661
dbusmenu_menuitem_property_get (twin_item, USER_ITEM_PROP_NAME));
662
gtk_widget_show(priv->tick_icon);
665
g_debug ("%s USER DOESN'T HAVE ACTIVE SESSIONS",
666
dbusmenu_menuitem_property_get (twin_item, USER_ITEM_PROP_NAME));
667
gtk_widget_hide(priv->tick_icon);
670
GdkPixbuf* pixbuf = NULL;
671
GError* error = NULL;
672
pixbuf = gdk_pixbuf_new_from_file_at_size(icon_name, 32, 32, NULL);
674
if (pixbuf == NULL || error != NULL) {
675
g_warning ("Could not load the user image (%s) for some reason",
678
g_object_unref (pixbuf);
682
g_error_free (error);
686
priv->using_personal_icon = FALSE;
688
pixbuf = gtk_icon_theme_load_icon (gtk_icon_theme_get_default (),
689
USER_ITEM_ICON_DEFAULT,
691
GTK_ICON_LOOKUP_FORCE_SIZE,
695
priv->using_personal_icon = TRUE;
698
if (pixbuf == NULL || error != NULL) {
699
g_warning ("Could not load the user image");
701
g_error_free (error);
706
gtk_image_set_from_pixbuf (GTK_IMAGE(priv->user_image), pixbuf);
709
g_object_unref (pixbuf);
716
* @returns: a new #UserWidget.
719
user_widget_new(DbusmenuMenuitem *item)
721
GtkWidget* widget = g_object_new(USER_WIDGET_TYPE, NULL);
722
user_widget_set_twin_item ( USER_WIDGET(widget), item );