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