Merge branch 'use-libfm'
[lxde/lxpanel.git] / src / plugins / netstatus / netstatus-icon.c
1 /*
2 * Copyright (C) 2003 Sun Microsystems, Inc.
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
17 * 02111-1307, USA.
18 *
19 * Authors:
20 * Mark McLoughlin <mark@skynet.ie>
21 */
22
23 #include <config.h>
24
25 #include "netstatus-icon.h"
26
27 #include <gtk/gtk.h>
28 #include <glib/gi18n.h>
29 #include <gtk/gtktooltips.h>
30
31 #include "netstatus-util.h"
32 #include "netstatus-enums.h"
33 #include "netstatus-fallback-pixbuf.h"
34
35 typedef enum
36 {
37 NETSTATUS_SIGNAL_0_24 = 0,
38 NETSTATUS_SIGNAL_25_49,
39 NETSTATUS_SIGNAL_50_74,
40 NETSTATUS_SIGNAL_75_100,
41 NETSTATUS_SIGNAL_LAST
42 } NetstatusSignal;
43
44 struct _NetstatusIconPrivate
45 {
46 GtkWidget *image;
47 GtkWidget *signal_image;
48 GtkWidget *error_dialog;
49
50 NetstatusIface *iface;
51 NetstatusState state;
52 NetstatusSignal signal_strength;
53
54 GtkIconTheme *icon_theme;
55 GdkPixbuf *icons [NETSTATUS_STATE_LAST];
56 GdkPixbuf *scaled_icons [NETSTATUS_STATE_LAST];
57
58 GdkPixbuf *signal_icons [NETSTATUS_SIGNAL_LAST];
59 GdkPixbuf *rotated_signal_icons [NETSTATUS_SIGNAL_LAST];
60 GdkPixbuf *scaled_signal_icons [NETSTATUS_SIGNAL_LAST];
61
62 GtkOrientation orientation;
63 int size;
64
65 GtkTooltip *tooltips;
66
67 gulong state_changed_id;
68 gulong name_changed_id;
69 gulong wireless_changed_id;
70 gulong signal_changed_id;
71
72 guint tooltips_enabled : 1;
73 guint show_signal : 1;
74 };
75
76 enum {
77 INVOKED,
78 LAST_SIGNAL
79 };
80
81 enum {
82 PROP_0,
83 PROP_IFACE,
84 PROP_ORIENTATION,
85 PROP_TOOLTIPS_ENABLED,
86 PROP_SHOW_SIGNAL
87 };
88
89 static void netstatus_icon_init_pixbufs (NetstatusIcon *icon);
90 static void netstatus_icon_scale_icons (NetstatusIcon *icon,
91 int height);
92
93 static GObjectClass *parent_class;
94 static guint icon_signals [LAST_SIGNAL] = { 0 };
95
96 static GdkPixbuf *
97 netstatus_icon_get_default_pixbuf (NetstatusIcon *icon __attribute__((unused)))
98 {
99 static GdkPixbuf *fallback_pixbuf = NULL;
100
101 if (!fallback_pixbuf)
102 {
103 fallback_pixbuf = gdk_pixbuf_new_from_inline (-1,
104 fallback_icon_data,
105 FALSE,
106 NULL);
107 g_object_add_weak_pointer (G_OBJECT (fallback_pixbuf),
108 (gpointer) &fallback_pixbuf);
109
110 return fallback_pixbuf;
111 }
112
113 return g_object_ref (fallback_pixbuf);
114 }
115
116 static void
117 netstatus_icon_theme_changed (NetstatusIcon *icon,
118 GtkIconTheme *icon_theme __attribute__((unused)))
119 {
120 int i;
121
122 for (i = 0; i < NETSTATUS_STATE_LAST; i++)
123 {
124 g_object_unref (icon->priv->scaled_icons [i]);
125 icon->priv->scaled_icons [i] = NULL;
126
127 g_object_unref (icon->priv->icons [i]);
128 icon->priv->icons [i] = NULL;
129 }
130
131 for (i = 0; i < NETSTATUS_SIGNAL_LAST; i++)
132 {
133 g_object_unref (icon->priv->scaled_signal_icons [i]);
134 icon->priv->scaled_signal_icons [i] = NULL;
135
136 g_object_unref (icon->priv->signal_icons [i]);
137 icon->priv->signal_icons [i] = NULL;
138 }
139
140 netstatus_icon_init_pixbufs (icon);
141
142 if (icon->priv->size)
143 {
144 netstatus_icon_scale_icons (icon, icon->priv->size);
145 }
146 }
147
148 static GtkIconTheme *
149 netstatus_icon_get_icon_theme (NetstatusIcon *icon)
150 {
151 if (!icon->priv->icon_theme)
152 {
153 GdkScreen *screen;
154
155 screen = gtk_widget_get_screen (GTK_WIDGET (icon));
156 icon->priv->icon_theme = gtk_icon_theme_get_for_screen (screen);
157
158 g_signal_connect_object (icon->priv->icon_theme, "changed",
159 G_CALLBACK (netstatus_icon_theme_changed),
160 icon,
161 G_CONNECT_SWAPPED);
162 }
163
164 return icon->priv->icon_theme;
165 }
166
167 static char *
168 netstatus_icon_lookup_icon_theme (NetstatusIcon *icon,
169 const char *icon_name)
170 {
171 GtkIconTheme *icon_theme;
172 GtkIconInfo *icon_info;
173 char *filename = NULL;
174
175 icon_theme = netstatus_icon_get_icon_theme (icon);
176 if ((icon_info = gtk_icon_theme_lookup_icon (icon_theme, icon_name, 1000, 0)))
177 {
178 filename = g_strdup (gtk_icon_info_get_filename (icon_info));
179
180 gtk_icon_info_free (icon_info);
181 }
182
183 return filename;
184 }
185
186 static void
187 netstatus_icon_init_pixbuf (NetstatusIcon *icon,
188 GdkPixbuf **pixbuf,
189 const char *icon_name)
190 {
191 char *filename;
192
193 g_assert (*pixbuf == NULL);
194
195 if ((filename = netstatus_icon_lookup_icon_theme (icon, icon_name)))
196 {
197 GError *error;
198
199 error = NULL;
200 *pixbuf = gdk_pixbuf_new_from_file (filename, &error);
201 if (error)
202 {
203 netstatus_adopt_error (error, NETSTATUS_ERROR_ICONS);
204 netstatus_iface_set_error (icon->priv->iface, error);
205 g_error_free (error);
206
207 }
208
209 g_free (filename);
210 }
211
212 if (!*pixbuf)
213 {
214 *pixbuf = netstatus_icon_get_default_pixbuf (icon);
215 g_assert (*pixbuf != NULL);
216 }
217 }
218
219 static GdkPixbuf *
220 rotate_pixbuf (GdkPixbuf *pixbuf)
221 {
222 GdkPixbuf *freeme;
223 GdkPixbuf *retval;
224 guint32 *dest;
225 guint32 *src;
226 int width;
227 int height;
228 int x;
229 int y;
230
231 freeme = NULL;
232 if (!gdk_pixbuf_get_has_alpha (pixbuf))
233 pixbuf = freeme = gdk_pixbuf_add_alpha (pixbuf, FALSE, 0, 0, 0);
234
235 width = gdk_pixbuf_get_width (pixbuf);
236 height = gdk_pixbuf_get_height (pixbuf);
237
238 retval = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, height, width);
239
240 dest = (guint32 *) gdk_pixbuf_get_pixels (retval);
241 src = (guint32 *) gdk_pixbuf_get_pixels (pixbuf);
242
243 for (y = 0; y < height; y++)
244 for (x = 0; x < width; x++)
245 dest [(height - y - 1) + height * (width - x - 1)] = src [y * width + x];
246
247 if (freeme)
248 g_object_unref (freeme);
249
250 return retval;
251 }
252
253 static void
254 netstatus_icon_rotate_signal_icons (NetstatusIcon *icon,
255 GtkOrientation orientation)
256 {
257 int i;
258
259 if (!icon->priv->signal_icons [0])
260 return;
261
262 for (i = 0; i < NETSTATUS_SIGNAL_LAST; i++)
263 {
264 GdkPixbuf *pixbuf;
265
266 if (orientation == GTK_ORIENTATION_HORIZONTAL)
267 {
268 pixbuf = g_object_ref (icon->priv->signal_icons [i]);
269 }
270 else /* if (orientation == GTK_ORIENTATION_VERTICAL) */
271 {
272 pixbuf = rotate_pixbuf (icon->priv->signal_icons [i]);
273 }
274
275 if (icon->priv->rotated_signal_icons [i])
276 g_object_unref (icon->priv->rotated_signal_icons [i]);
277 icon->priv->rotated_signal_icons [i] = pixbuf;
278
279 if (icon->priv->scaled_signal_icons [i])
280 g_object_unref (icon->priv->scaled_signal_icons [i]);
281 icon->priv->scaled_signal_icons [i] = NULL;
282 }
283 }
284
285 static void
286 netstatus_icon_init_pixbufs (NetstatusIcon *icon)
287 {
288 netstatus_icon_init_pixbuf (icon,
289 &icon->priv->icons [NETSTATUS_STATE_DISCONNECTED],
290 "gnome-netstatus-disconn");
291 icon->priv->scaled_icons [NETSTATUS_STATE_DISCONNECTED] = NULL;
292
293 netstatus_icon_init_pixbuf (icon,
294 &icon->priv->icons [NETSTATUS_STATE_IDLE],
295 "gnome-netstatus-idle");
296 icon->priv->scaled_icons [NETSTATUS_STATE_IDLE] = NULL;
297
298 netstatus_icon_init_pixbuf (icon,
299 &icon->priv->icons [NETSTATUS_STATE_TX],
300 "gnome-netstatus-tx");
301 icon->priv->scaled_icons [NETSTATUS_STATE_TX] = NULL;
302
303 netstatus_icon_init_pixbuf (icon,
304 &icon->priv->icons [NETSTATUS_STATE_RX],
305 "gnome-netstatus-rx");
306 icon->priv->scaled_icons [NETSTATUS_STATE_RX] = NULL;
307
308 netstatus_icon_init_pixbuf (icon,
309 &icon->priv->icons [NETSTATUS_STATE_TX_RX],
310 "gnome-netstatus-txrx");
311 icon->priv->scaled_icons [NETSTATUS_STATE_TX_RX] = NULL;
312
313 netstatus_icon_init_pixbuf (icon,
314 &icon->priv->icons [NETSTATUS_STATE_ERROR],
315 "gnome-netstatus-error");
316 icon->priv->scaled_icons [NETSTATUS_STATE_ERROR] = NULL;
317
318 netstatus_icon_init_pixbuf (icon,
319 &icon->priv->signal_icons [NETSTATUS_SIGNAL_0_24],
320 "gnome-netstatus-0-24");
321 icon->priv->rotated_signal_icons [NETSTATUS_SIGNAL_0_24] = NULL;
322 icon->priv->scaled_signal_icons [NETSTATUS_SIGNAL_0_24] = NULL;
323
324 netstatus_icon_init_pixbuf (icon,
325 &icon->priv->signal_icons [NETSTATUS_SIGNAL_25_49],
326 "gnome-netstatus-25-49");
327 icon->priv->rotated_signal_icons [NETSTATUS_SIGNAL_25_49] = NULL;
328 icon->priv->scaled_signal_icons [NETSTATUS_SIGNAL_25_49] = NULL;
329
330 netstatus_icon_init_pixbuf (icon,
331 &icon->priv->signal_icons [NETSTATUS_SIGNAL_50_74],
332 "gnome-netstatus-50-74");
333 icon->priv->rotated_signal_icons [NETSTATUS_SIGNAL_50_74] = NULL;
334 icon->priv->scaled_signal_icons [NETSTATUS_SIGNAL_50_74] = NULL;
335
336 netstatus_icon_init_pixbuf (icon,
337 &icon->priv->signal_icons [NETSTATUS_SIGNAL_75_100],
338 "gnome-netstatus-75-100");
339 icon->priv->rotated_signal_icons [NETSTATUS_SIGNAL_75_100] = NULL;
340 icon->priv->scaled_signal_icons [NETSTATUS_SIGNAL_75_100] = NULL;
341
342 netstatus_icon_rotate_signal_icons (icon, icon->priv->orientation);
343 }
344
345 static void
346 netstatus_icon_update_image (NetstatusIcon *icon)
347 {
348 GdkPixbuf *pixbuf;
349
350 if (!icon->priv->icons [icon->priv->state])
351 netstatus_icon_init_pixbufs (icon);
352
353 pixbuf = icon->priv->scaled_icons [icon->priv->state];
354 if (!pixbuf)
355 pixbuf = icon->priv->icons [icon->priv->state];
356
357 if (gtk_image_get_pixbuf (GTK_IMAGE (icon->priv->image)) != pixbuf)
358 gtk_image_set_from_pixbuf (GTK_IMAGE (icon->priv->image), pixbuf);
359
360 pixbuf = icon->priv->scaled_signal_icons [icon->priv->signal_strength];
361 if (!pixbuf)
362 pixbuf = icon->priv->rotated_signal_icons [icon->priv->signal_strength];
363
364 if (gtk_image_get_pixbuf (GTK_IMAGE (icon->priv->signal_image)) != pixbuf)
365 gtk_image_set_from_pixbuf (GTK_IMAGE (icon->priv->signal_image), pixbuf);
366 }
367
368 static void
369 netstatus_icon_name_changed (NetstatusIface *iface __attribute__((unused)),
370 GParamSpec *pspec __attribute__((unused)),
371 NetstatusIcon *icon)
372 {
373 const gchar *iface_name;
374 const gchar *tip;
375 gchar *freeme = NULL;
376
377 iface_name = netstatus_iface_get_name (icon->priv->iface);
378 if (iface_name)
379 {
380 freeme = g_strdup_printf (_("Network Connection: %s"), iface_name);
381 tip = freeme;
382 }
383 else
384 {
385 tip = _("Network Connection");
386 }
387
388 gtk_widget_set_tooltip_text(GTK_WIDGET (icon), tip);
389
390 g_free (freeme);
391 }
392
393 static void
394 netstatus_icon_state_changed (NetstatusIface *iface,
395 GParamSpec *pspec __attribute__((unused)),
396 NetstatusIcon *icon)
397 {
398 NetstatusState state;
399
400 g_return_if_fail (NETSTATUS_IS_ICON (icon));
401
402 state = netstatus_iface_get_state (iface);
403
404 if (icon->priv->state != state)
405 {
406 icon->priv->state = state;
407
408 netstatus_icon_update_image (icon);
409 }
410 }
411
412 static void
413 netstatus_icon_is_wireless_changed (NetstatusIface *iface,
414 GParamSpec *pspec __attribute__((unused)),
415 NetstatusIcon *icon)
416 {
417 if (netstatus_iface_get_is_wireless (iface) && netstatus_icon_get_show_signal(icon))
418 gtk_widget_show (icon->priv->signal_image);
419 else
420 gtk_widget_hide (icon->priv->signal_image);
421 }
422
423 static void
424 netstatus_icon_signal_changed (NetstatusIface *iface,
425 GParamSpec *pspec __attribute__((unused)),
426 NetstatusIcon *icon)
427 {
428 NetstatusSignal signal_strength;
429 int percent;
430
431 percent = netstatus_iface_get_signal_strength (iface);
432
433 if (percent < 25)
434 signal_strength = NETSTATUS_SIGNAL_0_24;
435 else if (percent < 50)
436 signal_strength = NETSTATUS_SIGNAL_25_49;
437 else if (percent < 75)
438 signal_strength = NETSTATUS_SIGNAL_50_74;
439 else
440 signal_strength = NETSTATUS_SIGNAL_75_100;
441
442 if (icon->priv->signal_strength != signal_strength)
443 {
444 icon->priv->signal_strength = signal_strength;
445
446 netstatus_icon_update_image (icon);
447 }
448 }
449
450 static void
451 netstatus_icon_destroy (GtkObject *widget)
452 {
453 NetstatusIcon *icon = (NetstatusIcon *) widget;
454
455 if (icon->priv->error_dialog)
456 gtk_widget_destroy (icon->priv->error_dialog);
457 icon->priv->error_dialog = NULL;
458
459 if (icon->priv->state_changed_id)
460 {
461 g_assert (icon->priv->iface != NULL);
462 g_assert (icon->priv->name_changed_id != 0);
463 g_signal_handler_disconnect (icon->priv->iface,
464 icon->priv->state_changed_id);
465 g_signal_handler_disconnect (icon->priv->iface,
466 icon->priv->name_changed_id);
467 g_signal_handler_disconnect (icon->priv->iface,
468 icon->priv->wireless_changed_id);
469 g_signal_handler_disconnect (icon->priv->iface,
470 icon->priv->signal_changed_id);
471 }
472 icon->priv->state_changed_id = 0;
473 icon->priv->name_changed_id = 0;
474 icon->priv->wireless_changed_id = 0;
475 icon->priv->signal_changed_id = 0;
476
477 #if GLIB_CHECK_VERSION(2,12,0)
478 /* not needed with GTKTooltip API*/
479 #else
480 if (icon->priv->tooltips)
481 g_object_unref (icon->priv->tooltips);
482 icon->priv->tooltips = NULL;
483 #endif
484
485 icon->priv->image = NULL;
486
487 GTK_OBJECT_CLASS (parent_class)->destroy (widget);
488 }
489
490 static GdkPixbuf *
491 scale_pixbuf (GdkPixbuf *pixbuf,
492 GtkOrientation orientation,
493 int size,
494 gboolean retain_aspect)
495 {
496 GdkPixbuf *retval;
497 int orig_size;
498
499 if (orientation == GTK_ORIENTATION_HORIZONTAL)
500 {
501 orig_size = gdk_pixbuf_get_height (pixbuf);
502 }
503 else /* if (orientation == GTK_ORIENTATION_VERTICAL) */
504 {
505 orig_size = gdk_pixbuf_get_width (pixbuf);
506 }
507
508 if (size >= orig_size)
509 {
510 retval = g_object_ref (pixbuf);
511 }
512 else
513 {
514 int orig_width;
515 int orig_height;
516 int scaled_width;
517 int scaled_height;
518 double scale;
519
520 orig_width = gdk_pixbuf_get_width (pixbuf);
521 orig_height = gdk_pixbuf_get_height (pixbuf);
522
523 scale = (double) size / orig_size;
524
525 if (retain_aspect)
526 {
527 scaled_width = orig_width * scale;
528 scaled_height = orig_height * scale;
529 }
530 else
531 {
532 if (orientation == GTK_ORIENTATION_HORIZONTAL)
533 {
534 scaled_width = orig_width;
535 scaled_height = orig_height * scale;
536 }
537 else /* if (orientation == GTK_ORIENTATION_VERTICAL) */
538 {
539 scaled_width = orig_width * scale;
540 scaled_height = orig_height;
541 }
542 }
543
544 retval = gdk_pixbuf_scale_simple (pixbuf,
545 scaled_width,
546 scaled_height,
547 GDK_INTERP_BILINEAR);
548 }
549
550 return retval;
551 }
552
553 static void
554 netstatus_icon_scale_icons (NetstatusIcon *icon,
555 int size)
556 {
557 int i;
558
559 g_return_if_fail (size > 0);
560
561 if (!icon->priv->icons [0])
562 netstatus_icon_init_pixbufs (icon);
563
564 for (i = 0; i < NETSTATUS_STATE_LAST; i++)
565 {
566 if (icon->priv->scaled_icons [i])
567 g_object_unref (icon->priv->scaled_icons [i]);
568 icon->priv->scaled_icons [i] = scale_pixbuf (icon->priv->icons [i],
569 icon->priv->orientation,
570 size,
571 TRUE);
572 }
573
574 for (i = 0; i < NETSTATUS_SIGNAL_LAST; i++)
575 {
576 if (icon->priv->scaled_signal_icons [i])
577 g_object_unref (icon->priv->scaled_signal_icons [i]);
578 icon->priv->scaled_signal_icons [i] = scale_pixbuf (icon->priv->rotated_signal_icons [i],
579 icon->priv->orientation,
580 size,
581 TRUE);
582 }
583
584 netstatus_icon_update_image (icon);
585 }
586
587 static inline GObjectClass *
588 get_box_class (GtkOrientation orientation)
589 {
590 return gtk_type_class (orientation == GTK_ORIENTATION_HORIZONTAL ? GTK_TYPE_HBOX : GTK_TYPE_VBOX);
591 }
592
593 static void
594 netstatus_icon_size_request (GtkWidget *widget,
595 GtkRequisition *requisition)
596 {
597 NetstatusIcon *icon = NETSTATUS_ICON (widget);
598 GObjectClass *klass;
599
600 klass = get_box_class (icon->priv->orientation);
601
602 if (GTK_WIDGET_CLASS (klass)->size_request)
603 GTK_WIDGET_CLASS (klass)->size_request (widget, requisition);
604 }
605
606 static void
607 netstatus_icon_size_allocate (GtkWidget *widget,
608 GtkAllocation *allocation)
609 {
610 NetstatusIcon *icon = (NetstatusIcon *) widget;
611 GtkAllocation child_allocation;
612 GObjectClass *klass;
613 int size;
614 GdkWindow *window = gtk_widget_get_window(widget);
615 guint border_width = gtk_container_get_border_width(GTK_CONTAINER (widget));
616
617 if (icon->priv->orientation == GTK_ORIENTATION_HORIZONTAL)
618 size = allocation->height;
619 else
620 size = allocation->width;
621
622 if (icon->priv->size != size)
623 {
624 icon->priv->size = size;
625
626 netstatus_icon_scale_icons (icon, size);
627 }
628
629 if (GTK_WIDGET_REALIZED (widget))
630 {
631 gdk_window_move_resize (window,
632 allocation->x + border_width,
633 allocation->y + border_width,
634 MAX (allocation->width - border_width * 2, 0),
635 MAX (allocation->height - border_width * 2, 0));
636 }
637
638 klass = get_box_class (icon->priv->orientation);
639
640 child_allocation.x = 0;
641 child_allocation.y = 0;
642 child_allocation.width = MAX (allocation->width - border_width * 2, 0);
643 child_allocation.height = MAX (allocation->height - border_width * 2, 0);
644
645 if (GTK_WIDGET_CLASS (klass)->size_allocate)
646 GTK_WIDGET_CLASS (klass)->size_allocate (widget, &child_allocation);
647
648 #if GTK_CHECK_VERSION(2,18,0)
649 gtk_widget_get_allocation(widget, allocation);
650 #else
651 widget->allocation = *allocation;
652 #endif
653 }
654
655 static void
656 netstatus_icon_realize (GtkWidget *widget)
657 {
658 GdkWindowAttr attributes;
659 int attributes_mask;
660 int border_width;
661
662 GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
663
664 border_width = GTK_CONTAINER (widget)->border_width;
665
666 attributes.x = widget->allocation.x + border_width;
667 attributes.y = widget->allocation.y + border_width;
668 attributes.width = widget->allocation.width - 2 * border_width;
669 attributes.height = widget->allocation.height - 2 * border_width;
670 attributes.window_type = GDK_WINDOW_CHILD;
671 attributes.wclass = GDK_INPUT_OUTPUT;
672 attributes.visual = gtk_widget_get_visual (widget);
673 attributes.colormap = gtk_widget_get_colormap (widget);
674 attributes.event_mask = gtk_widget_get_events (widget) |
675 GDK_BUTTON_MOTION_MASK |
676 GDK_BUTTON_PRESS_MASK |
677 GDK_BUTTON_RELEASE_MASK |
678 GDK_EXPOSURE_MASK |
679 GDK_ENTER_NOTIFY_MASK |
680 GDK_LEAVE_NOTIFY_MASK;
681
682 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
683
684 widget->window = gdk_window_new (gtk_widget_get_parent_window (widget), &attributes, attributes_mask);
685 gdk_window_set_user_data (widget->window, widget);
686
687 widget->style = gtk_style_attach (widget->style, widget->window);
688 gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL);
689 }
690
691 static gboolean
692 netstatus_icon_button_press_event (GtkWidget *widget,
693 GdkEventButton *event)
694 {
695 if (event->button == 1)
696 {
697 netstatus_icon_invoke (NETSTATUS_ICON (widget));
698 return TRUE;
699 }
700
701 return FALSE;
702 }
703 #if 0
704 static void
705 netstatus_icon_set_property (GObject *object,
706 guint prop_id,
707 const GValue *value,
708 GParamSpec *pspec)
709 {
710 NetstatusIcon *icon;
711
712 g_return_if_fail (NETSTATUS_IS_ICON (object));
713
714 icon = NETSTATUS_ICON (object);
715
716 switch (prop_id)
717 {
718 case PROP_IFACE:
719 netstatus_icon_set_iface (icon, g_value_get_object (value));
720 break;
721 case PROP_ORIENTATION:
722 netstatus_icon_set_orientation (icon, g_value_get_enum (value));
723 break;
724 case PROP_TOOLTIPS_ENABLED:
725 netstatus_icon_set_tooltips_enabled (icon, g_value_get_boolean (value));
726 break;
727 case PROP_SHOW_SIGNAL:
728 netstatus_icon_set_show_signal (icon, g_value_get_boolean (value));
729 break;
730 default:
731 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
732 break;
733 }
734 }
735
736 static void
737 netstatus_icon_get_property (GObject *object,
738 guint prop_id,
739 GValue *value,
740 GParamSpec *pspec)
741 {
742 NetstatusIcon *icon;
743
744 g_return_if_fail (NETSTATUS_IS_ICON (object));
745
746 icon = NETSTATUS_ICON (object);
747
748 switch (prop_id)
749 {
750 case PROP_IFACE:
751 g_value_set_object (value, icon->priv->iface);
752 break;
753 case PROP_ORIENTATION:
754 g_value_set_enum (value, icon->priv->orientation);
755 break;
756 case PROP_TOOLTIPS_ENABLED:
757 g_value_set_boolean (value, icon->priv->tooltips_enabled);
758 break;
759 case PROP_SHOW_SIGNAL:
760 g_value_set_boolean (value, icon->priv->show_signal);
761 break;
762 default:
763 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
764 break;
765 }
766 }
767 #endif
768
769 static void
770 netstatus_icon_finalize (GObject *object)
771 {
772 NetstatusIcon *icon = (NetstatusIcon *) object;
773 int i;
774
775 if (icon->priv->iface)
776 g_object_unref (icon->priv->iface);
777 icon->priv->iface = NULL;
778
779 for (i = 0; i < NETSTATUS_STATE_LAST; i++)
780 {
781 if (icon->priv->icons [i])
782 g_object_unref (icon->priv->icons [i]);
783 icon->priv->icons [i] = NULL;
784
785 if (icon->priv->scaled_icons [i])
786 g_object_unref (icon->priv->scaled_icons [i]);
787 icon->priv->scaled_icons [i] = NULL;
788 }
789
790 g_free (icon->priv);
791 icon->priv = NULL;
792
793 parent_class->finalize (object);
794 }
795
796 static void
797 netstatus_icon_class_init (NetstatusIconClass *klass)
798 {
799 GObjectClass *gobject_class = (GObjectClass *) klass;
800 GtkObjectClass *gtkobject_class = (GtkObjectClass *) klass;
801 GtkWidgetClass *widget_class = (GtkWidgetClass *) klass;
802
803 parent_class = g_type_class_peek_parent (klass);
804
805 /*
806 gobject_class->set_property = netstatus_icon_set_property;
807 gobject_class->get_property = netstatus_icon_get_property;
808 */
809
810 gobject_class->finalize = netstatus_icon_finalize;
811
812 gtkobject_class->destroy = netstatus_icon_destroy;
813
814 widget_class->size_request = netstatus_icon_size_request;
815 widget_class->size_allocate = netstatus_icon_size_allocate;
816 widget_class->realize = netstatus_icon_realize;
817 widget_class->button_press_event = netstatus_icon_button_press_event;
818 #if 0
819 g_object_class_install_property (gobject_class,
820 PROP_IFACE,
821 g_param_spec_object ("iface",
822 _("Interface"),
823 _("The current interface the icon is monitoring."),
824 NETSTATUS_TYPE_IFACE,
825 G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
826
827 g_object_class_install_property (gobject_class,
828 PROP_ORIENTATION,
829 g_param_spec_enum ("orientation",
830 _("Orientation"),
831 _("The orientation of the tray."),
832 GTK_TYPE_ORIENTATION,
833 GTK_ORIENTATION_HORIZONTAL,
834 G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
835
836 g_object_class_install_property (gobject_class,
837 PROP_TOOLTIPS_ENABLED,
838 g_param_spec_boolean ("tooltips-enabled",
839 _("Tooltips Enabled"),
840 _("Whether or not the icon's tooltips are enabled."),
841 TRUE,
842 G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
843
844 g_object_class_install_property (gobject_class,
845 PROP_SHOW_SIGNAL,
846 g_param_spec_boolean ("show-signal",
847 _("Show Signal"),
848 _("Whether or not the signal strength should be displayed."),
849 TRUE,
850 G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
851 #endif
852
853 icon_signals [INVOKED] =
854 g_signal_new ("invoked",
855 G_OBJECT_CLASS_TYPE (gobject_class),
856 G_SIGNAL_RUN_FIRST,
857 G_STRUCT_OFFSET (NetstatusIconClass, invoked),
858 NULL, NULL,
859 g_cclosure_marshal_VOID__VOID,
860 G_TYPE_NONE, 0);
861 }
862
863 static void
864 netstatus_icon_instance_init (NetstatusIcon *icon,
865 NetstatusIconClass *klass __attribute__((unused)))
866 {
867 icon->priv = g_new0 (NetstatusIconPrivate, 1);
868
869 GTK_WIDGET_UNSET_FLAGS (icon, GTK_NO_WINDOW);
870
871 icon->priv->iface = NULL;
872 icon->priv->state = NETSTATUS_STATE_DISCONNECTED;
873 icon->priv->orientation = GTK_ORIENTATION_HORIZONTAL;
874 icon->priv->size = 0;
875 icon->priv->state_changed_id = 0;
876
877 gtk_box_set_spacing (GTK_BOX (icon), 3);
878
879 icon->priv->image = gtk_image_new ();
880 gtk_container_add (GTK_CONTAINER (icon), icon->priv->image);
881 gtk_widget_show (icon->priv->image);
882
883 icon->priv->signal_image = gtk_image_new ();
884 gtk_container_add (GTK_CONTAINER (icon), icon->priv->signal_image);
885 gtk_widget_hide (icon->priv->signal_image);
886
887 #if GLIB_CHECK_VERSION(2,12,0)
888 /* not needed with GTKTooltip API*/
889 #else
890 icon->priv->tooltips = gtk_tooltips_new ();
891 g_object_ref (icon->priv->tooltips);
892 gtk_object_sink (GTK_OBJECT (icon->priv->tooltips));
893 #endif
894
895 gtk_widget_add_events (GTK_WIDGET (icon),
896 GDK_BUTTON_PRESS_MASK | GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK);
897 }
898
899 GType
900 netstatus_icon_get_type (void)
901 {
902 static GType type = 0;
903 if (!type)
904 {
905 static const GTypeInfo info =
906 {
907 sizeof (NetstatusIconClass),
908 NULL,
909 NULL,
910 (GClassInitFunc) netstatus_icon_class_init,
911 NULL,
912 NULL,
913 sizeof (NetstatusIcon),
914 0,
915 (GInstanceInitFunc) netstatus_icon_instance_init,
916 NULL
917 };
918 type = g_type_register_static (GTK_TYPE_BOX, "NetstatusIcon", &info, 0);
919 }
920 return type;
921 }
922
923 GtkWidget *
924 netstatus_icon_new (NetstatusIface *iface)
925 {
926 GtkWidget* obj = g_object_new (NETSTATUS_TYPE_ICON,
927 /*"iface", iface,*/
928 NULL);
929 netstatus_icon_set_iface( NETSTATUS_ICON(obj), iface );
930 return obj;
931 }
932
933 void
934 netstatus_icon_invoke (NetstatusIcon *icon)
935 {
936 g_return_if_fail (NETSTATUS_IS_ICON (icon));
937
938 if (netstatus_iface_get_state (icon->priv->iface) != NETSTATUS_STATE_ERROR)
939 {
940 if (icon->priv->error_dialog)
941 gtk_widget_destroy (icon->priv->error_dialog);
942 icon->priv->error_dialog = NULL;
943
944 g_signal_emit (icon, icon_signals [INVOKED], 0);
945 }
946 else
947 {
948 const GError *error;
949
950 error = netstatus_iface_get_error (icon->priv->iface);
951 g_assert (error != NULL);
952
953 if (icon->priv->error_dialog)
954 {
955 gtk_window_set_screen (GTK_WINDOW (icon->priv->error_dialog),
956 gtk_widget_get_screen (GTK_WIDGET (icon)));
957 gtk_window_present (GTK_WINDOW (icon->priv->error_dialog));
958 return;
959 }
960
961 icon->priv->error_dialog =
962 gtk_message_dialog_new (NULL, 0,
963 GTK_MESSAGE_ERROR,
964 GTK_BUTTONS_CLOSE,
965 _("Please contact your system administrator to resolve the following problem:\n\n%s"),
966 error->message);
967
968 gtk_window_set_screen (GTK_WINDOW (icon->priv->error_dialog),
969 gtk_widget_get_screen (GTK_WIDGET (icon)));
970
971 g_signal_connect (icon->priv->error_dialog, "response",
972 G_CALLBACK (gtk_widget_destroy), NULL);
973 g_signal_connect (icon->priv->error_dialog, "destroy",
974 G_CALLBACK (gtk_widget_destroyed),
975 &icon->priv->error_dialog);
976
977 gtk_widget_show (icon->priv->error_dialog);
978 }
979 }
980
981 void
982 netstatus_icon_set_iface (NetstatusIcon *icon,
983 NetstatusIface *iface)
984 {
985
986 g_return_if_fail (NETSTATUS_IS_ICON (icon));
987
988 if (icon->priv->iface != iface)
989 {
990 NetstatusIface *old_iface;
991
992 old_iface = icon->priv->iface;
993
994 if (icon->priv->state_changed_id)
995 {
996 g_assert (icon->priv->iface != NULL);
997 g_assert (icon->priv->name_changed_id != 0);
998 g_signal_handler_disconnect (icon->priv->iface,
999 icon->priv->state_changed_id);
1000 g_signal_handler_disconnect (icon->priv->iface,
1001 icon->priv->name_changed_id);
1002 g_signal_handler_disconnect (icon->priv->iface,
1003 icon->priv->wireless_changed_id);
1004 g_signal_handler_disconnect (icon->priv->iface,
1005 icon->priv->signal_changed_id);
1006 }
1007
1008 if (iface)
1009 g_object_ref (iface);
1010 icon->priv->iface = iface;
1011
1012 if (old_iface)
1013 g_object_unref (old_iface);
1014
1015 icon->priv->state_changed_id = g_signal_connect (icon->priv->iface, "notify::state",
1016 G_CALLBACK (netstatus_icon_state_changed), icon);
1017 icon->priv->name_changed_id = g_signal_connect (icon->priv->iface, "notify::name",
1018 G_CALLBACK (netstatus_icon_name_changed), icon);
1019 icon->priv->wireless_changed_id = g_signal_connect (icon->priv->iface, "notify::wireless",
1020 G_CALLBACK (netstatus_icon_is_wireless_changed), icon);
1021 icon->priv->signal_changed_id = g_signal_connect (icon->priv->iface, "notify::signal-strength",
1022 G_CALLBACK (netstatus_icon_signal_changed), icon);
1023
1024 netstatus_icon_state_changed (icon->priv->iface, NULL, icon);
1025 netstatus_icon_name_changed (icon->priv->iface, NULL, icon);
1026 netstatus_icon_is_wireless_changed (icon->priv->iface, NULL, icon);
1027 netstatus_icon_signal_changed (icon->priv->iface, NULL, icon);
1028
1029 /* g_object_notify (G_OBJECT (icon), "iface"); */
1030 }
1031 }
1032
1033 NetstatusIface *
1034 netstatus_icon_get_iface (NetstatusIcon *icon)
1035 {
1036 g_return_val_if_fail (NETSTATUS_IS_ICON (icon), 0);
1037
1038 return icon->priv->iface;
1039 }
1040
1041 void
1042 netstatus_icon_set_orientation (NetstatusIcon *icon,
1043 GtkOrientation orientation)
1044 {
1045 g_return_if_fail (NETSTATUS_IS_ICON (icon));
1046
1047 if (icon->priv->orientation != orientation)
1048 {
1049 icon->priv->orientation = orientation;
1050
1051 netstatus_icon_rotate_signal_icons (icon, orientation);
1052 netstatus_icon_update_image (icon);
1053
1054 icon->priv->size = -1;
1055
1056 gtk_widget_queue_resize (GTK_WIDGET (icon));
1057
1058 g_object_notify (G_OBJECT (icon), "orientation");
1059 }
1060 }
1061
1062 GtkOrientation
1063 netstatus_icon_get_orientation (NetstatusIcon *icon)
1064 {
1065 g_return_val_if_fail (NETSTATUS_IS_ICON (icon), GTK_ORIENTATION_HORIZONTAL);
1066
1067 return icon->priv->orientation;
1068 }
1069
1070 void
1071 netstatus_icon_set_tooltips_enabled (NetstatusIcon *icon,
1072 gboolean enabled)
1073 {
1074 g_return_if_fail (NETSTATUS_IS_ICON (icon));
1075
1076 enabled = enabled != FALSE;
1077
1078 if (icon->priv->tooltips_enabled != enabled)
1079 {
1080 icon->priv->tooltips_enabled = enabled;
1081
1082 #if GLIB_CHECK_VERSION(2,12,0)
1083 /* not needed with GTKTooltip API*/
1084 #else
1085 if (enabled)
1086 gtk_tooltips_enable (icon->priv->tooltips);
1087 else
1088 gtk_tooltips_disable (icon->priv->tooltips);
1089 #endif
1090
1091 g_object_notify (G_OBJECT (icon), "tooltips-enabled");
1092 }
1093 }
1094
1095 gboolean
1096 netstatus_icon_get_tooltips_enabled (NetstatusIcon *icon)
1097 {
1098 g_return_val_if_fail (NETSTATUS_ICON (icon), TRUE);
1099
1100 return icon->priv->tooltips_enabled;
1101 }
1102
1103 void
1104 netstatus_icon_set_show_signal (NetstatusIcon *icon,
1105 gboolean show_signal)
1106 {
1107 g_return_if_fail (NETSTATUS_IS_ICON (icon));
1108
1109 show_signal = show_signal != FALSE;
1110
1111 if (icon->priv->show_signal != show_signal)
1112 {
1113 icon->priv->show_signal = show_signal;
1114
1115 if (show_signal && netstatus_iface_get_is_wireless (icon->priv->iface))
1116 gtk_widget_show (icon->priv->signal_image);
1117 else
1118 gtk_widget_hide (icon->priv->signal_image);
1119
1120 /* g_object_notify (G_OBJECT (icon), "show-signal"); */
1121 }
1122 }
1123
1124 gboolean
1125 netstatus_icon_get_show_signal (NetstatusIcon *icon)
1126 {
1127 g_return_val_if_fail (NETSTATUS_ICON (icon), TRUE);
1128
1129 return icon->priv->show_signal;
1130 }