Merging upstream version 0.5.9.
[debian/lxpanel.git] / src / plugins / netstatus / netstatus-icon.c
CommitLineData
6cc5e1a6
DB
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>
170c1e2e 29#include <gtk/gtktooltips.h>
6cc5e1a6
DB
30
31#include "netstatus-util.h"
32#include "netstatus-enums.h"
33#include "netstatus-fallback-pixbuf.h"
34
35typedef 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
44struct _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
ca14ea2b 65 GtkTooltip *tooltips;
6cc5e1a6
DB
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
76enum {
77 INVOKED,
78 LAST_SIGNAL
79};
80
81enum {
82 PROP_0,
83 PROP_IFACE,
84 PROP_ORIENTATION,
85 PROP_TOOLTIPS_ENABLED,
86 PROP_SHOW_SIGNAL
87};
88
89static void netstatus_icon_init_pixbufs (NetstatusIcon *icon);
90static void netstatus_icon_scale_icons (NetstatusIcon *icon,
91 int height);
92
93static GObjectClass *parent_class;
94static guint icon_signals [LAST_SIGNAL] = { 0 };
95
96static GdkPixbuf *
10862fa6 97netstatus_icon_get_default_pixbuf (NetstatusIcon *icon __attribute__((unused)))
6cc5e1a6
DB
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
116static void
117netstatus_icon_theme_changed (NetstatusIcon *icon,
10862fa6 118 GtkIconTheme *icon_theme __attribute__((unused)))
6cc5e1a6
DB
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
148static GtkIconTheme *
149netstatus_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
167static char *
168netstatus_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
186static void
187netstatus_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
219static GdkPixbuf *
220rotate_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
253static void
254netstatus_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
285static void
286netstatus_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
345static void
346netstatus_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
368static void
10862fa6
DB
369netstatus_icon_name_changed (NetstatusIface *iface __attribute__((unused)),
370 GParamSpec *pspec __attribute__((unused)),
6cc5e1a6
DB
371 NetstatusIcon *icon)
372{
ca14ea2b
DB
373 const gchar *iface_name;
374 const gchar *tip;
375 gchar *freeme = NULL;
6cc5e1a6
DB
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
ca14ea2b
DB
388#if GTK_CHECK_VERSION(2,12,0)
389 gtk_widget_set_tooltip_text(GTK_WIDGET (icon), tip);
390#else
6cc5e1a6 391 gtk_tooltips_set_tip (icon->priv->tooltips, GTK_WIDGET (icon), tip, NULL);
ca14ea2b 392#endif
6cc5e1a6
DB
393
394 g_free (freeme);
395}
396
397static void
398netstatus_icon_state_changed (NetstatusIface *iface,
10862fa6 399 GParamSpec *pspec __attribute__((unused)),
6cc5e1a6
DB
400 NetstatusIcon *icon)
401{
402 NetstatusState state;
403
404 g_return_if_fail (NETSTATUS_IS_ICON (icon));
405
406 state = netstatus_iface_get_state (iface);
407
408 if (icon->priv->state != state)
409 {
410 icon->priv->state = state;
411
412 netstatus_icon_update_image (icon);
413 }
414}
415
416static void
417netstatus_icon_is_wireless_changed (NetstatusIface *iface,
10862fa6 418 GParamSpec *pspec __attribute__((unused)),
6cc5e1a6
DB
419 NetstatusIcon *icon)
420{
ca14ea2b 421 if (netstatus_iface_get_is_wireless (iface) && netstatus_icon_get_show_signal(icon))
6cc5e1a6
DB
422 gtk_widget_show (icon->priv->signal_image);
423 else
424 gtk_widget_hide (icon->priv->signal_image);
425}
426
427static void
428netstatus_icon_signal_changed (NetstatusIface *iface,
10862fa6 429 GParamSpec *pspec __attribute__((unused)),
6cc5e1a6
DB
430 NetstatusIcon *icon)
431{
432 NetstatusSignal signal_strength;
433 int percent;
434
435 percent = netstatus_iface_get_signal_strength (iface);
436
437 if (percent < 25)
438 signal_strength = NETSTATUS_SIGNAL_0_24;
439 else if (percent < 50)
440 signal_strength = NETSTATUS_SIGNAL_25_49;
441 else if (percent < 75)
442 signal_strength = NETSTATUS_SIGNAL_50_74;
443 else
444 signal_strength = NETSTATUS_SIGNAL_75_100;
445
446 if (icon->priv->signal_strength != signal_strength)
447 {
448 icon->priv->signal_strength = signal_strength;
449
450 netstatus_icon_update_image (icon);
451 }
452}
453
454static void
455netstatus_icon_destroy (GtkObject *widget)
456{
457 NetstatusIcon *icon = (NetstatusIcon *) widget;
458
459 if (icon->priv->error_dialog)
460 gtk_widget_destroy (icon->priv->error_dialog);
461 icon->priv->error_dialog = NULL;
462
463 if (icon->priv->state_changed_id)
464 {
465 g_assert (icon->priv->iface != NULL);
466 g_assert (icon->priv->name_changed_id != 0);
467 g_signal_handler_disconnect (icon->priv->iface,
468 icon->priv->state_changed_id);
469 g_signal_handler_disconnect (icon->priv->iface,
470 icon->priv->name_changed_id);
471 g_signal_handler_disconnect (icon->priv->iface,
472 icon->priv->wireless_changed_id);
473 g_signal_handler_disconnect (icon->priv->iface,
474 icon->priv->signal_changed_id);
475 }
476 icon->priv->state_changed_id = 0;
477 icon->priv->name_changed_id = 0;
478 icon->priv->wireless_changed_id = 0;
479 icon->priv->signal_changed_id = 0;
480
f8c25730
DB
481#if GLIB_CHECK_VERSION(2,12,0)
482/* not needed with GTKTooltip API*/
483#else
6cc5e1a6
DB
484 if (icon->priv->tooltips)
485 g_object_unref (icon->priv->tooltips);
486 icon->priv->tooltips = NULL;
f8c25730 487#endif
6cc5e1a6
DB
488
489 icon->priv->image = NULL;
490
491 GTK_OBJECT_CLASS (parent_class)->destroy (widget);
492}
493
494static GdkPixbuf *
495scale_pixbuf (GdkPixbuf *pixbuf,
496 GtkOrientation orientation,
497 int size,
498 gboolean retain_aspect)
499{
500 GdkPixbuf *retval;
501 int orig_size;
502
503 if (orientation == GTK_ORIENTATION_HORIZONTAL)
504 {
505 orig_size = gdk_pixbuf_get_height (pixbuf);
506 }
507 else /* if (orientation == GTK_ORIENTATION_VERTICAL) */
508 {
509 orig_size = gdk_pixbuf_get_width (pixbuf);
510 }
511
512 if (size >= orig_size)
513 {
514 retval = g_object_ref (pixbuf);
515 }
516 else
517 {
518 int orig_width;
519 int orig_height;
520 int scaled_width;
521 int scaled_height;
522 double scale;
523
524 orig_width = gdk_pixbuf_get_width (pixbuf);
525 orig_height = gdk_pixbuf_get_height (pixbuf);
526
527 scale = (double) size / orig_size;
528
529 if (retain_aspect)
530 {
531 scaled_width = orig_width * scale;
532 scaled_height = orig_height * scale;
533 }
534 else
535 {
536 if (orientation == GTK_ORIENTATION_HORIZONTAL)
537 {
538 scaled_width = orig_width;
539 scaled_height = orig_height * scale;
540 }
541 else /* if (orientation == GTK_ORIENTATION_VERTICAL) */
542 {
543 scaled_width = orig_width * scale;
544 scaled_height = orig_height;
545 }
546 }
547
548 retval = gdk_pixbuf_scale_simple (pixbuf,
549 scaled_width,
550 scaled_height,
551 GDK_INTERP_BILINEAR);
552 }
553
554 return retval;
555}
556
557static void
558netstatus_icon_scale_icons (NetstatusIcon *icon,
559 int size)
560{
561 int i;
562
563 g_return_if_fail (size > 0);
564
565 if (!icon->priv->icons [0])
566 netstatus_icon_init_pixbufs (icon);
567
568 for (i = 0; i < NETSTATUS_STATE_LAST; i++)
569 {
570 if (icon->priv->scaled_icons [i])
571 g_object_unref (icon->priv->scaled_icons [i]);
572 icon->priv->scaled_icons [i] = scale_pixbuf (icon->priv->icons [i],
573 icon->priv->orientation,
574 size,
575 TRUE);
576 }
577
578 for (i = 0; i < NETSTATUS_SIGNAL_LAST; i++)
579 {
580 if (icon->priv->scaled_signal_icons [i])
581 g_object_unref (icon->priv->scaled_signal_icons [i]);
582 icon->priv->scaled_signal_icons [i] = scale_pixbuf (icon->priv->rotated_signal_icons [i],
583 icon->priv->orientation,
584 size,
585 TRUE);
586 }
587
588 netstatus_icon_update_image (icon);
589}
590
591static inline GObjectClass *
592get_box_class (GtkOrientation orientation)
593{
594 return gtk_type_class (orientation == GTK_ORIENTATION_HORIZONTAL ? GTK_TYPE_HBOX : GTK_TYPE_VBOX);
595}
596
597static void
598netstatus_icon_size_request (GtkWidget *widget,
599 GtkRequisition *requisition)
600{
601 NetstatusIcon *icon = NETSTATUS_ICON (widget);
602 GObjectClass *klass;
603
604 klass = get_box_class (icon->priv->orientation);
605
606 if (GTK_WIDGET_CLASS (klass)->size_request)
607 GTK_WIDGET_CLASS (klass)->size_request (widget, requisition);
608}
609
610static void
611netstatus_icon_size_allocate (GtkWidget *widget,
612 GtkAllocation *allocation)
613{
614 NetstatusIcon *icon = (NetstatusIcon *) widget;
615 GtkAllocation child_allocation;
616 GObjectClass *klass;
617 int size;
ca14ea2b
DB
618#if GTK_CHECK_VERSION(2,14,0)
619 GdkWindow *window = gtk_widget_get_window(widget);
620 guint border_width = gtk_container_get_border_width(GTK_CONTAINER (widget));
621#else
622#endif
6cc5e1a6
DB
623
624 if (icon->priv->orientation == GTK_ORIENTATION_HORIZONTAL)
625 size = allocation->height;
626 else
627 size = allocation->width;
628
629 if (icon->priv->size != size)
630 {
631 icon->priv->size = size;
632
633 netstatus_icon_scale_icons (icon, size);
634 }
635
636 if (GTK_WIDGET_REALIZED (widget))
637 {
ca14ea2b
DB
638#if GTK_CHECK_VERSION(2,14,0)
639 gdk_window_move_resize (window,
640 allocation->x + border_width,
641 allocation->y + border_width,
642 MAX (allocation->width - border_width * 2, 0),
643 MAX (allocation->height - border_width * 2, 0));
644#else
6cc5e1a6
DB
645 gdk_window_move_resize (widget->window,
646 allocation->x + GTK_CONTAINER (widget)->border_width,
647 allocation->y + GTK_CONTAINER (widget)->border_width,
648 MAX (allocation->width - GTK_CONTAINER (widget)->border_width * 2, 0),
ca14ea2b
DB
649 MAX (allocation->height - GTK_CONTAINER (widget)->border_width * 2, 0));
650#endif
6cc5e1a6
DB
651 }
652
653 klass = get_box_class (icon->priv->orientation);
654
655 child_allocation.x = 0;
656 child_allocation.y = 0;
ca14ea2b
DB
657#if GTK_CHECK_VERSION(2,14,0)
658 child_allocation.width = MAX (allocation->width - border_width * 2, 0);
659 child_allocation.height = MAX (allocation->height - border_width * 2, 0);
660#else
6cc5e1a6
DB
661 child_allocation.width = MAX (allocation->width - GTK_CONTAINER (widget)->border_width * 2, 0);
662 child_allocation.height = MAX (allocation->height - GTK_CONTAINER (widget)->border_width * 2, 0);
ca14ea2b 663#endif
6cc5e1a6
DB
664
665 if (GTK_WIDGET_CLASS (klass)->size_allocate)
666 GTK_WIDGET_CLASS (klass)->size_allocate (widget, &child_allocation);
667
ca14ea2b
DB
668#if GTK_CHECK_VERSION(2,18,0)
669 gtk_widget_get_allocation(widget, allocation);
670#else
6cc5e1a6 671 widget->allocation = *allocation;
ca14ea2b 672#endif
6cc5e1a6
DB
673}
674
675static void
676netstatus_icon_realize (GtkWidget *widget)
677{
678 GdkWindowAttr attributes;
679 int attributes_mask;
680 int border_width;
681
682 GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
683
684 border_width = GTK_CONTAINER (widget)->border_width;
685
686 attributes.x = widget->allocation.x + border_width;
687 attributes.y = widget->allocation.y + border_width;
688 attributes.width = widget->allocation.width - 2 * border_width;
689 attributes.height = widget->allocation.height - 2 * border_width;
690 attributes.window_type = GDK_WINDOW_CHILD;
691 attributes.wclass = GDK_INPUT_OUTPUT;
692 attributes.visual = gtk_widget_get_visual (widget);
693 attributes.colormap = gtk_widget_get_colormap (widget);
694 attributes.event_mask = gtk_widget_get_events (widget) |
695 GDK_BUTTON_MOTION_MASK |
696 GDK_BUTTON_PRESS_MASK |
697 GDK_BUTTON_RELEASE_MASK |
698 GDK_EXPOSURE_MASK |
699 GDK_ENTER_NOTIFY_MASK |
700 GDK_LEAVE_NOTIFY_MASK;
701
702 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
703
704 widget->window = gdk_window_new (gtk_widget_get_parent_window (widget), &attributes, attributes_mask);
705 gdk_window_set_user_data (widget->window, widget);
706
707 widget->style = gtk_style_attach (widget->style, widget->window);
708 gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL);
709}
710
711static gboolean
712netstatus_icon_button_press_event (GtkWidget *widget,
713 GdkEventButton *event)
714{
715 if (event->button == 1)
716 {
717 netstatus_icon_invoke (NETSTATUS_ICON (widget));
718 return TRUE;
719 }
720
721 return FALSE;
722}
723#if 0
724static void
725netstatus_icon_set_property (GObject *object,
726 guint prop_id,
727 const GValue *value,
728 GParamSpec *pspec)
729{
730 NetstatusIcon *icon;
731
732 g_return_if_fail (NETSTATUS_IS_ICON (object));
733
734 icon = NETSTATUS_ICON (object);
735
736 switch (prop_id)
737 {
738 case PROP_IFACE:
739 netstatus_icon_set_iface (icon, g_value_get_object (value));
740 break;
741 case PROP_ORIENTATION:
742 netstatus_icon_set_orientation (icon, g_value_get_enum (value));
743 break;
744 case PROP_TOOLTIPS_ENABLED:
745 netstatus_icon_set_tooltips_enabled (icon, g_value_get_boolean (value));
746 break;
747 case PROP_SHOW_SIGNAL:
748 netstatus_icon_set_show_signal (icon, g_value_get_boolean (value));
749 break;
750 default:
751 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
752 break;
753 }
754}
755
756static void
757netstatus_icon_get_property (GObject *object,
758 guint prop_id,
759 GValue *value,
760 GParamSpec *pspec)
761{
762 NetstatusIcon *icon;
763
764 g_return_if_fail (NETSTATUS_IS_ICON (object));
765
766 icon = NETSTATUS_ICON (object);
767
768 switch (prop_id)
769 {
770 case PROP_IFACE:
771 g_value_set_object (value, icon->priv->iface);
772 break;
773 case PROP_ORIENTATION:
774 g_value_set_enum (value, icon->priv->orientation);
775 break;
776 case PROP_TOOLTIPS_ENABLED:
777 g_value_set_boolean (value, icon->priv->tooltips_enabled);
778 break;
779 case PROP_SHOW_SIGNAL:
780 g_value_set_boolean (value, icon->priv->show_signal);
781 break;
782 default:
783 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
784 break;
785 }
786}
787#endif
788
789static void
790netstatus_icon_finalize (GObject *object)
791{
792 NetstatusIcon *icon = (NetstatusIcon *) object;
793 int i;
794
795 if (icon->priv->iface)
796 g_object_unref (icon->priv->iface);
797 icon->priv->iface = NULL;
798
799 for (i = 0; i < NETSTATUS_STATE_LAST; i++)
800 {
801 if (icon->priv->icons [i])
802 g_object_unref (icon->priv->icons [i]);
803 icon->priv->icons [i] = NULL;
804
805 if (icon->priv->scaled_icons [i])
806 g_object_unref (icon->priv->scaled_icons [i]);
807 icon->priv->scaled_icons [i] = NULL;
808 }
809
810 g_free (icon->priv);
811 icon->priv = NULL;
812
813 parent_class->finalize (object);
814}
815
816static void
817netstatus_icon_class_init (NetstatusIconClass *klass)
818{
819 GObjectClass *gobject_class = (GObjectClass *) klass;
820 GtkObjectClass *gtkobject_class = (GtkObjectClass *) klass;
821 GtkWidgetClass *widget_class = (GtkWidgetClass *) klass;
822
823 parent_class = g_type_class_peek_parent (klass);
824
825 /*
826 gobject_class->set_property = netstatus_icon_set_property;
827 gobject_class->get_property = netstatus_icon_get_property;
828 */
829
830 gobject_class->finalize = netstatus_icon_finalize;
831
832 gtkobject_class->destroy = netstatus_icon_destroy;
833
834 widget_class->size_request = netstatus_icon_size_request;
835 widget_class->size_allocate = netstatus_icon_size_allocate;
836 widget_class->realize = netstatus_icon_realize;
837 widget_class->button_press_event = netstatus_icon_button_press_event;
838#if 0
839 g_object_class_install_property (gobject_class,
840 PROP_IFACE,
841 g_param_spec_object ("iface",
842 _("Interface"),
843 _("The current interface the icon is monitoring."),
844 NETSTATUS_TYPE_IFACE,
845 G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
846
847 g_object_class_install_property (gobject_class,
848 PROP_ORIENTATION,
849 g_param_spec_enum ("orientation",
850 _("Orientation"),
851 _("The orientation of the tray."),
852 GTK_TYPE_ORIENTATION,
853 GTK_ORIENTATION_HORIZONTAL,
854 G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
855
856 g_object_class_install_property (gobject_class,
857 PROP_TOOLTIPS_ENABLED,
858 g_param_spec_boolean ("tooltips-enabled",
859 _("Tooltips Enabled"),
860 _("Whether or not the icon's tooltips are enabled."),
861 TRUE,
862 G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
863
864 g_object_class_install_property (gobject_class,
865 PROP_SHOW_SIGNAL,
866 g_param_spec_boolean ("show-signal",
867 _("Show Signal"),
868 _("Whether or not the signal strength should be displayed."),
869 TRUE,
870 G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
871#endif
872
873 icon_signals [INVOKED] =
874 g_signal_new ("invoked",
875 G_OBJECT_CLASS_TYPE (gobject_class),
876 G_SIGNAL_RUN_FIRST,
877 G_STRUCT_OFFSET (NetstatusIconClass, invoked),
878 NULL, NULL,
879 g_cclosure_marshal_VOID__VOID,
880 G_TYPE_NONE, 0);
881}
882
883static void
884netstatus_icon_instance_init (NetstatusIcon *icon,
10862fa6 885 NetstatusIconClass *klass __attribute__((unused)))
6cc5e1a6
DB
886{
887 icon->priv = g_new0 (NetstatusIconPrivate, 1);
888
889 GTK_WIDGET_UNSET_FLAGS (icon, GTK_NO_WINDOW);
890
891 icon->priv->iface = NULL;
892 icon->priv->state = NETSTATUS_STATE_DISCONNECTED;
893 icon->priv->orientation = GTK_ORIENTATION_HORIZONTAL;
894 icon->priv->size = 0;
895 icon->priv->state_changed_id = 0;
896
897 gtk_box_set_spacing (GTK_BOX (icon), 3);
898
899 icon->priv->image = gtk_image_new ();
900 gtk_container_add (GTK_CONTAINER (icon), icon->priv->image);
901 gtk_widget_show (icon->priv->image);
902
903 icon->priv->signal_image = gtk_image_new ();
904 gtk_container_add (GTK_CONTAINER (icon), icon->priv->signal_image);
905 gtk_widget_hide (icon->priv->signal_image);
906
f8c25730
DB
907#if GLIB_CHECK_VERSION(2,12,0)
908/* not needed with GTKTooltip API*/
909#else
170c1e2e 910 icon->priv->tooltips = gtk_tooltips_new ();
6cc5e1a6
DB
911 g_object_ref (icon->priv->tooltips);
912 gtk_object_sink (GTK_OBJECT (icon->priv->tooltips));
f8c25730 913#endif
6cc5e1a6
DB
914
915 gtk_widget_add_events (GTK_WIDGET (icon),
916 GDK_BUTTON_PRESS_MASK | GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK);
917}
918
919GType
920netstatus_icon_get_type (void)
921{
922 static GType type = 0;
923 if (!type)
924 {
925 static const GTypeInfo info =
926 {
927 sizeof (NetstatusIconClass),
928 NULL,
929 NULL,
930 (GClassInitFunc) netstatus_icon_class_init,
931 NULL,
932 NULL,
933 sizeof (NetstatusIcon),
934 0,
935 (GInstanceInitFunc) netstatus_icon_instance_init,
936 NULL
937 };
938 type = g_type_register_static (GTK_TYPE_BOX, "NetstatusIcon", &info, 0);
939 }
940 return type;
941}
942
943GtkWidget *
944netstatus_icon_new (NetstatusIface *iface)
945{
946 GtkWidget* obj = g_object_new (NETSTATUS_TYPE_ICON,
947 /*"iface", iface,*/
948 NULL);
949 netstatus_icon_set_iface( NETSTATUS_ICON(obj), iface );
950 return obj;
951}
952
953void
954netstatus_icon_invoke (NetstatusIcon *icon)
955{
956 g_return_if_fail (NETSTATUS_IS_ICON (icon));
957
958 if (netstatus_iface_get_state (icon->priv->iface) != NETSTATUS_STATE_ERROR)
959 {
960 if (icon->priv->error_dialog)
961 gtk_widget_destroy (icon->priv->error_dialog);
962 icon->priv->error_dialog = NULL;
963
964 g_signal_emit (icon, icon_signals [INVOKED], 0);
965 }
966 else
967 {
968 const GError *error;
969
970 error = netstatus_iface_get_error (icon->priv->iface);
971 g_assert (error != NULL);
972
973 if (icon->priv->error_dialog)
974 {
975 gtk_window_set_screen (GTK_WINDOW (icon->priv->error_dialog),
976 gtk_widget_get_screen (GTK_WIDGET (icon)));
977 gtk_window_present (GTK_WINDOW (icon->priv->error_dialog));
978 return;
979 }
980
981 icon->priv->error_dialog =
982 gtk_message_dialog_new (NULL, 0,
983 GTK_MESSAGE_ERROR,
984 GTK_BUTTONS_CLOSE,
985 _("Please contact your system administrator to resolve the following problem:\n\n%s"),
986 error->message);
987
988 gtk_window_set_screen (GTK_WINDOW (icon->priv->error_dialog),
989 gtk_widget_get_screen (GTK_WIDGET (icon)));
990
991 g_signal_connect (icon->priv->error_dialog, "response",
992 G_CALLBACK (gtk_widget_destroy), NULL);
993 g_signal_connect (icon->priv->error_dialog, "destroy",
994 G_CALLBACK (gtk_widget_destroyed),
995 &icon->priv->error_dialog);
996
997 gtk_widget_show (icon->priv->error_dialog);
998 }
999}
1000
1001void
1002netstatus_icon_set_iface (NetstatusIcon *icon,
1003 NetstatusIface *iface)
1004{
1005
1006 g_return_if_fail (NETSTATUS_IS_ICON (icon));
1007
1008 if (icon->priv->iface != iface)
1009 {
1010 NetstatusIface *old_iface;
1011
1012 old_iface = icon->priv->iface;
1013
1014 if (icon->priv->state_changed_id)
1015 {
1016 g_assert (icon->priv->iface != NULL);
1017 g_assert (icon->priv->name_changed_id != 0);
1018 g_signal_handler_disconnect (icon->priv->iface,
1019 icon->priv->state_changed_id);
1020 g_signal_handler_disconnect (icon->priv->iface,
1021 icon->priv->name_changed_id);
1022 g_signal_handler_disconnect (icon->priv->iface,
1023 icon->priv->wireless_changed_id);
1024 g_signal_handler_disconnect (icon->priv->iface,
1025 icon->priv->signal_changed_id);
1026 }
1027
1028 if (iface)
1029 g_object_ref (iface);
1030 icon->priv->iface = iface;
1031
1032 if (old_iface)
1033 g_object_unref (old_iface);
1034
1035 icon->priv->state_changed_id = g_signal_connect (icon->priv->iface, "notify::state",
1036 G_CALLBACK (netstatus_icon_state_changed), icon);
1037 icon->priv->name_changed_id = g_signal_connect (icon->priv->iface, "notify::name",
1038 G_CALLBACK (netstatus_icon_name_changed), icon);
1039 icon->priv->wireless_changed_id = g_signal_connect (icon->priv->iface, "notify::wireless",
1040 G_CALLBACK (netstatus_icon_is_wireless_changed), icon);
1041 icon->priv->signal_changed_id = g_signal_connect (icon->priv->iface, "notify::signal-strength",
1042 G_CALLBACK (netstatus_icon_signal_changed), icon);
1043
1044 netstatus_icon_state_changed (icon->priv->iface, NULL, icon);
1045 netstatus_icon_name_changed (icon->priv->iface, NULL, icon);
1046 netstatus_icon_is_wireless_changed (icon->priv->iface, NULL, icon);
1047 netstatus_icon_signal_changed (icon->priv->iface, NULL, icon);
1048
1049 /* g_object_notify (G_OBJECT (icon), "iface"); */
1050 }
1051}
1052
1053NetstatusIface *
1054netstatus_icon_get_iface (NetstatusIcon *icon)
1055{
1056 g_return_val_if_fail (NETSTATUS_IS_ICON (icon), 0);
1057
1058 return icon->priv->iface;
1059}
1060
1061void
1062netstatus_icon_set_orientation (NetstatusIcon *icon,
1063 GtkOrientation orientation)
1064{
1065 g_return_if_fail (NETSTATUS_IS_ICON (icon));
1066
1067 if (icon->priv->orientation != orientation)
1068 {
1069 icon->priv->orientation = orientation;
1070
1071 netstatus_icon_rotate_signal_icons (icon, orientation);
1072 netstatus_icon_update_image (icon);
1073
1074 icon->priv->size = -1;
1075
1076 gtk_widget_queue_resize (GTK_WIDGET (icon));
1077
1078 g_object_notify (G_OBJECT (icon), "orientation");
1079 }
1080}
1081
1082GtkOrientation
1083netstatus_icon_get_orientation (NetstatusIcon *icon)
1084{
1085 g_return_val_if_fail (NETSTATUS_IS_ICON (icon), GTK_ORIENTATION_HORIZONTAL);
1086
1087 return icon->priv->orientation;
1088}
1089
1090void
1091netstatus_icon_set_tooltips_enabled (NetstatusIcon *icon,
1092 gboolean enabled)
1093{
1094 g_return_if_fail (NETSTATUS_IS_ICON (icon));
1095
1096 enabled = enabled != FALSE;
1097
1098 if (icon->priv->tooltips_enabled != enabled)
1099 {
1100 icon->priv->tooltips_enabled = enabled;
1101
ca14ea2b
DB
1102#if GLIB_CHECK_VERSION(2,12,0)
1103/* not needed with GTKTooltip API*/
1104#else
6cc5e1a6
DB
1105 if (enabled)
1106 gtk_tooltips_enable (icon->priv->tooltips);
1107 else
1108 gtk_tooltips_disable (icon->priv->tooltips);
ca14ea2b 1109#endif
6cc5e1a6
DB
1110
1111 g_object_notify (G_OBJECT (icon), "tooltips-enabled");
1112 }
1113}
1114
1115gboolean
1116netstatus_icon_get_tooltips_enabled (NetstatusIcon *icon)
1117{
1118 g_return_val_if_fail (NETSTATUS_ICON (icon), TRUE);
1119
1120 return icon->priv->tooltips_enabled;
1121}
1122
1123void
1124netstatus_icon_set_show_signal (NetstatusIcon *icon,
1125 gboolean show_signal)
1126{
1127 g_return_if_fail (NETSTATUS_IS_ICON (icon));
1128
1129 show_signal = show_signal != FALSE;
1130
1131 if (icon->priv->show_signal != show_signal)
1132 {
1133 icon->priv->show_signal = show_signal;
1134
1135 if (show_signal && netstatus_iface_get_is_wireless (icon->priv->iface))
1136 gtk_widget_show (icon->priv->signal_image);
1137 else
1138 gtk_widget_hide (icon->priv->signal_image);
1139
10862fa6 1140 /* g_object_notify (G_OBJECT (icon), "show-signal"); */
6cc5e1a6
DB
1141 }
1142}
1143
1144gboolean
1145netstatus_icon_get_show_signal (NetstatusIcon *icon)
1146{
1147 g_return_val_if_fail (NETSTATUS_ICON (icon), TRUE);
1148
1149 return icon->priv->show_signal;
1150}