Adding upstream version 0.8.0.
[debian/lxpanel.git] / 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>
29
30#include "netstatus-util.h"
31#include "netstatus-enums.h"
32#include "netstatus-fallback-pixbuf.h"
33
f7ecd6ce
AG
34#include "gtk-compat.h"
35
6cc5e1a6
DB
36typedef enum
37{
38 NETSTATUS_SIGNAL_0_24 = 0,
39 NETSTATUS_SIGNAL_25_49,
40 NETSTATUS_SIGNAL_50_74,
41 NETSTATUS_SIGNAL_75_100,
42 NETSTATUS_SIGNAL_LAST
43} NetstatusSignal;
44
45struct _NetstatusIconPrivate
46{
47 GtkWidget *image;
48 GtkWidget *signal_image;
49 GtkWidget *error_dialog;
50
51 NetstatusIface *iface;
52 NetstatusState state;
53 NetstatusSignal signal_strength;
54
55 GtkIconTheme *icon_theme;
56 GdkPixbuf *icons [NETSTATUS_STATE_LAST];
57 GdkPixbuf *scaled_icons [NETSTATUS_STATE_LAST];
58
59 GdkPixbuf *signal_icons [NETSTATUS_SIGNAL_LAST];
60 GdkPixbuf *rotated_signal_icons [NETSTATUS_SIGNAL_LAST];
61 GdkPixbuf *scaled_signal_icons [NETSTATUS_SIGNAL_LAST];
62
63 GtkOrientation orientation;
64 int size;
65
cb7f7ba8 66 GtkTooltip *tooltips;
6cc5e1a6
DB
67
68 gulong state_changed_id;
69 gulong name_changed_id;
70 gulong wireless_changed_id;
71 gulong signal_changed_id;
72
73 guint tooltips_enabled : 1;
74 guint show_signal : 1;
75};
76
77enum {
78 INVOKED,
79 LAST_SIGNAL
80};
81
82enum {
83 PROP_0,
84 PROP_IFACE,
85 PROP_ORIENTATION,
86 PROP_TOOLTIPS_ENABLED,
87 PROP_SHOW_SIGNAL
88};
89
90static void netstatus_icon_init_pixbufs (NetstatusIcon *icon);
91static void netstatus_icon_scale_icons (NetstatusIcon *icon,
92 int height);
93
94static GObjectClass *parent_class;
95static guint icon_signals [LAST_SIGNAL] = { 0 };
96
97static GdkPixbuf *
7486d297 98netstatus_icon_get_default_pixbuf (NetstatusIcon *icon __attribute__((unused)))
6cc5e1a6
DB
99{
100 static GdkPixbuf *fallback_pixbuf = NULL;
101
102 if (!fallback_pixbuf)
103 {
104 fallback_pixbuf = gdk_pixbuf_new_from_inline (-1,
105 fallback_icon_data,
106 FALSE,
107 NULL);
108 g_object_add_weak_pointer (G_OBJECT (fallback_pixbuf),
109 (gpointer) &fallback_pixbuf);
110
111 return fallback_pixbuf;
112 }
113
114 return g_object_ref (fallback_pixbuf);
115}
116
117static void
118netstatus_icon_theme_changed (NetstatusIcon *icon,
7486d297 119 GtkIconTheme *icon_theme __attribute__((unused)))
6cc5e1a6
DB
120{
121 int i;
122
123 for (i = 0; i < NETSTATUS_STATE_LAST; i++)
124 {
125 g_object_unref (icon->priv->scaled_icons [i]);
126 icon->priv->scaled_icons [i] = NULL;
127
128 g_object_unref (icon->priv->icons [i]);
129 icon->priv->icons [i] = NULL;
130 }
131
132 for (i = 0; i < NETSTATUS_SIGNAL_LAST; i++)
133 {
134 g_object_unref (icon->priv->scaled_signal_icons [i]);
135 icon->priv->scaled_signal_icons [i] = NULL;
136
137 g_object_unref (icon->priv->signal_icons [i]);
138 icon->priv->signal_icons [i] = NULL;
139 }
140
141 netstatus_icon_init_pixbufs (icon);
142
143 if (icon->priv->size)
144 {
145 netstatus_icon_scale_icons (icon, icon->priv->size);
146 }
147}
148
149static GtkIconTheme *
150netstatus_icon_get_icon_theme (NetstatusIcon *icon)
151{
152 if (!icon->priv->icon_theme)
153 {
154 GdkScreen *screen;
155
156 screen = gtk_widget_get_screen (GTK_WIDGET (icon));
157 icon->priv->icon_theme = gtk_icon_theme_get_for_screen (screen);
158
159 g_signal_connect_object (icon->priv->icon_theme, "changed",
160 G_CALLBACK (netstatus_icon_theme_changed),
161 icon,
162 G_CONNECT_SWAPPED);
163 }
164
165 return icon->priv->icon_theme;
166}
167
168static char *
169netstatus_icon_lookup_icon_theme (NetstatusIcon *icon,
170 const char *icon_name)
171{
172 GtkIconTheme *icon_theme;
173 GtkIconInfo *icon_info;
174 char *filename = NULL;
175
176 icon_theme = netstatus_icon_get_icon_theme (icon);
177 if ((icon_info = gtk_icon_theme_lookup_icon (icon_theme, icon_name, 1000, 0)))
178 {
179 filename = g_strdup (gtk_icon_info_get_filename (icon_info));
180
181 gtk_icon_info_free (icon_info);
182 }
183
184 return filename;
185}
186
187static void
188netstatus_icon_init_pixbuf (NetstatusIcon *icon,
189 GdkPixbuf **pixbuf,
190 const char *icon_name)
191{
192 char *filename;
193
194 g_assert (*pixbuf == NULL);
195
196 if ((filename = netstatus_icon_lookup_icon_theme (icon, icon_name)))
197 {
198 GError *error;
199
200 error = NULL;
201 *pixbuf = gdk_pixbuf_new_from_file (filename, &error);
202 if (error)
203 {
204 netstatus_adopt_error (error, NETSTATUS_ERROR_ICONS);
205 netstatus_iface_set_error (icon->priv->iface, error);
206 g_error_free (error);
207
208 }
209
210 g_free (filename);
211 }
212
213 if (!*pixbuf)
214 {
215 *pixbuf = netstatus_icon_get_default_pixbuf (icon);
216 g_assert (*pixbuf != NULL);
217 }
218}
219
220static GdkPixbuf *
221rotate_pixbuf (GdkPixbuf *pixbuf)
222{
223 GdkPixbuf *freeme;
224 GdkPixbuf *retval;
225 guint32 *dest;
226 guint32 *src;
227 int width;
228 int height;
229 int x;
230 int y;
231
232 freeme = NULL;
233 if (!gdk_pixbuf_get_has_alpha (pixbuf))
234 pixbuf = freeme = gdk_pixbuf_add_alpha (pixbuf, FALSE, 0, 0, 0);
235
236 width = gdk_pixbuf_get_width (pixbuf);
237 height = gdk_pixbuf_get_height (pixbuf);
238
239 retval = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, height, width);
240
241 dest = (guint32 *) gdk_pixbuf_get_pixels (retval);
242 src = (guint32 *) gdk_pixbuf_get_pixels (pixbuf);
243
244 for (y = 0; y < height; y++)
245 for (x = 0; x < width; x++)
246 dest [(height - y - 1) + height * (width - x - 1)] = src [y * width + x];
247
248 if (freeme)
249 g_object_unref (freeme);
250
251 return retval;
252}
253
254static void
255netstatus_icon_rotate_signal_icons (NetstatusIcon *icon,
256 GtkOrientation orientation)
257{
258 int i;
259
260 if (!icon->priv->signal_icons [0])
261 return;
262
263 for (i = 0; i < NETSTATUS_SIGNAL_LAST; i++)
264 {
265 GdkPixbuf *pixbuf;
266
267 if (orientation == GTK_ORIENTATION_HORIZONTAL)
268 {
269 pixbuf = g_object_ref (icon->priv->signal_icons [i]);
270 }
271 else /* if (orientation == GTK_ORIENTATION_VERTICAL) */
272 {
273 pixbuf = rotate_pixbuf (icon->priv->signal_icons [i]);
274 }
275
276 if (icon->priv->rotated_signal_icons [i])
277 g_object_unref (icon->priv->rotated_signal_icons [i]);
278 icon->priv->rotated_signal_icons [i] = pixbuf;
279
280 if (icon->priv->scaled_signal_icons [i])
281 g_object_unref (icon->priv->scaled_signal_icons [i]);
282 icon->priv->scaled_signal_icons [i] = NULL;
283 }
284}
285
286static void
287netstatus_icon_init_pixbufs (NetstatusIcon *icon)
288{
289 netstatus_icon_init_pixbuf (icon,
290 &icon->priv->icons [NETSTATUS_STATE_DISCONNECTED],
291 "gnome-netstatus-disconn");
292 icon->priv->scaled_icons [NETSTATUS_STATE_DISCONNECTED] = NULL;
293
294 netstatus_icon_init_pixbuf (icon,
295 &icon->priv->icons [NETSTATUS_STATE_IDLE],
296 "gnome-netstatus-idle");
297 icon->priv->scaled_icons [NETSTATUS_STATE_IDLE] = NULL;
298
299 netstatus_icon_init_pixbuf (icon,
300 &icon->priv->icons [NETSTATUS_STATE_TX],
301 "gnome-netstatus-tx");
302 icon->priv->scaled_icons [NETSTATUS_STATE_TX] = NULL;
303
304 netstatus_icon_init_pixbuf (icon,
305 &icon->priv->icons [NETSTATUS_STATE_RX],
306 "gnome-netstatus-rx");
307 icon->priv->scaled_icons [NETSTATUS_STATE_RX] = NULL;
308
309 netstatus_icon_init_pixbuf (icon,
310 &icon->priv->icons [NETSTATUS_STATE_TX_RX],
311 "gnome-netstatus-txrx");
312 icon->priv->scaled_icons [NETSTATUS_STATE_TX_RX] = NULL;
313
314 netstatus_icon_init_pixbuf (icon,
315 &icon->priv->icons [NETSTATUS_STATE_ERROR],
316 "gnome-netstatus-error");
317 icon->priv->scaled_icons [NETSTATUS_STATE_ERROR] = NULL;
318
319 netstatus_icon_init_pixbuf (icon,
320 &icon->priv->signal_icons [NETSTATUS_SIGNAL_0_24],
321 "gnome-netstatus-0-24");
322 icon->priv->rotated_signal_icons [NETSTATUS_SIGNAL_0_24] = NULL;
323 icon->priv->scaled_signal_icons [NETSTATUS_SIGNAL_0_24] = NULL;
324
325 netstatus_icon_init_pixbuf (icon,
326 &icon->priv->signal_icons [NETSTATUS_SIGNAL_25_49],
327 "gnome-netstatus-25-49");
328 icon->priv->rotated_signal_icons [NETSTATUS_SIGNAL_25_49] = NULL;
329 icon->priv->scaled_signal_icons [NETSTATUS_SIGNAL_25_49] = NULL;
330
331 netstatus_icon_init_pixbuf (icon,
332 &icon->priv->signal_icons [NETSTATUS_SIGNAL_50_74],
333 "gnome-netstatus-50-74");
334 icon->priv->rotated_signal_icons [NETSTATUS_SIGNAL_50_74] = NULL;
335 icon->priv->scaled_signal_icons [NETSTATUS_SIGNAL_50_74] = NULL;
336
337 netstatus_icon_init_pixbuf (icon,
338 &icon->priv->signal_icons [NETSTATUS_SIGNAL_75_100],
339 "gnome-netstatus-75-100");
340 icon->priv->rotated_signal_icons [NETSTATUS_SIGNAL_75_100] = NULL;
341 icon->priv->scaled_signal_icons [NETSTATUS_SIGNAL_75_100] = NULL;
342
343 netstatus_icon_rotate_signal_icons (icon, icon->priv->orientation);
344}
345
346static void
347netstatus_icon_update_image (NetstatusIcon *icon)
348{
349 GdkPixbuf *pixbuf;
350
351 if (!icon->priv->icons [icon->priv->state])
352 netstatus_icon_init_pixbufs (icon);
353
354 pixbuf = icon->priv->scaled_icons [icon->priv->state];
355 if (!pixbuf)
356 pixbuf = icon->priv->icons [icon->priv->state];
357
358 if (gtk_image_get_pixbuf (GTK_IMAGE (icon->priv->image)) != pixbuf)
359 gtk_image_set_from_pixbuf (GTK_IMAGE (icon->priv->image), pixbuf);
360
361 pixbuf = icon->priv->scaled_signal_icons [icon->priv->signal_strength];
362 if (!pixbuf)
363 pixbuf = icon->priv->rotated_signal_icons [icon->priv->signal_strength];
364
365 if (gtk_image_get_pixbuf (GTK_IMAGE (icon->priv->signal_image)) != pixbuf)
366 gtk_image_set_from_pixbuf (GTK_IMAGE (icon->priv->signal_image), pixbuf);
367}
368
369static void
7486d297
DB
370netstatus_icon_name_changed (NetstatusIface *iface __attribute__((unused)),
371 GParamSpec *pspec __attribute__((unused)),
6cc5e1a6
DB
372 NetstatusIcon *icon)
373{
cb7f7ba8
DB
374 const gchar *iface_name;
375 const gchar *tip;
376 gchar *freeme = NULL;
6cc5e1a6
DB
377
378 iface_name = netstatus_iface_get_name (icon->priv->iface);
379 if (iface_name)
380 {
381 freeme = g_strdup_printf (_("Network Connection: %s"), iface_name);
382 tip = freeme;
383 }
384 else
385 {
386 tip = _("Network Connection");
387 }
388
cb7f7ba8 389 gtk_widget_set_tooltip_text(GTK_WIDGET (icon), tip);
6cc5e1a6
DB
390
391 g_free (freeme);
392}
393
394static void
395netstatus_icon_state_changed (NetstatusIface *iface,
7486d297 396 GParamSpec *pspec __attribute__((unused)),
6cc5e1a6
DB
397 NetstatusIcon *icon)
398{
399 NetstatusState state;
400
401 g_return_if_fail (NETSTATUS_IS_ICON (icon));
402
403 state = netstatus_iface_get_state (iface);
404
405 if (icon->priv->state != state)
406 {
407 icon->priv->state = state;
408
409 netstatus_icon_update_image (icon);
410 }
411}
412
413static void
414netstatus_icon_is_wireless_changed (NetstatusIface *iface,
7486d297 415 GParamSpec *pspec __attribute__((unused)),
6cc5e1a6
DB
416 NetstatusIcon *icon)
417{
cb7f7ba8 418 if (netstatus_iface_get_is_wireless (iface) && netstatus_icon_get_show_signal(icon))
6cc5e1a6
DB
419 gtk_widget_show (icon->priv->signal_image);
420 else
421 gtk_widget_hide (icon->priv->signal_image);
422}
423
424static void
425netstatus_icon_signal_changed (NetstatusIface *iface,
7486d297 426 GParamSpec *pspec __attribute__((unused)),
6cc5e1a6
DB
427 NetstatusIcon *icon)
428{
429 NetstatusSignal signal_strength;
430 int percent;
431
432 percent = netstatus_iface_get_signal_strength (iface);
433
434 if (percent < 25)
435 signal_strength = NETSTATUS_SIGNAL_0_24;
436 else if (percent < 50)
437 signal_strength = NETSTATUS_SIGNAL_25_49;
438 else if (percent < 75)
439 signal_strength = NETSTATUS_SIGNAL_50_74;
440 else
441 signal_strength = NETSTATUS_SIGNAL_75_100;
442
443 if (icon->priv->signal_strength != signal_strength)
444 {
445 icon->priv->signal_strength = signal_strength;
446
447 netstatus_icon_update_image (icon);
448 }
449}
450
451static void
452netstatus_icon_destroy (GtkObject *widget)
453{
454 NetstatusIcon *icon = (NetstatusIcon *) widget;
455
456 if (icon->priv->error_dialog)
457 gtk_widget_destroy (icon->priv->error_dialog);
458 icon->priv->error_dialog = NULL;
459
460 if (icon->priv->state_changed_id)
461 {
462 g_assert (icon->priv->iface != NULL);
463 g_assert (icon->priv->name_changed_id != 0);
464 g_signal_handler_disconnect (icon->priv->iface,
465 icon->priv->state_changed_id);
466 g_signal_handler_disconnect (icon->priv->iface,
467 icon->priv->name_changed_id);
468 g_signal_handler_disconnect (icon->priv->iface,
469 icon->priv->wireless_changed_id);
470 g_signal_handler_disconnect (icon->priv->iface,
471 icon->priv->signal_changed_id);
472 }
473 icon->priv->state_changed_id = 0;
474 icon->priv->name_changed_id = 0;
475 icon->priv->wireless_changed_id = 0;
476 icon->priv->signal_changed_id = 0;
477
6cc5e1a6
DB
478 icon->priv->image = NULL;
479
480 GTK_OBJECT_CLASS (parent_class)->destroy (widget);
481}
482
483static GdkPixbuf *
484scale_pixbuf (GdkPixbuf *pixbuf,
485 GtkOrientation orientation,
486 int size,
487 gboolean retain_aspect)
488{
489 GdkPixbuf *retval;
490 int orig_size;
491
492 if (orientation == GTK_ORIENTATION_HORIZONTAL)
493 {
494 orig_size = gdk_pixbuf_get_height (pixbuf);
495 }
496 else /* if (orientation == GTK_ORIENTATION_VERTICAL) */
497 {
498 orig_size = gdk_pixbuf_get_width (pixbuf);
499 }
500
501 if (size >= orig_size)
502 {
503 retval = g_object_ref (pixbuf);
504 }
505 else
506 {
507 int orig_width;
508 int orig_height;
509 int scaled_width;
510 int scaled_height;
511 double scale;
512
513 orig_width = gdk_pixbuf_get_width (pixbuf);
514 orig_height = gdk_pixbuf_get_height (pixbuf);
515
516 scale = (double) size / orig_size;
517
518 if (retain_aspect)
519 {
520 scaled_width = orig_width * scale;
521 scaled_height = orig_height * scale;
522 }
523 else
524 {
525 if (orientation == GTK_ORIENTATION_HORIZONTAL)
526 {
527 scaled_width = orig_width;
528 scaled_height = orig_height * scale;
529 }
530 else /* if (orientation == GTK_ORIENTATION_VERTICAL) */
531 {
532 scaled_width = orig_width * scale;
533 scaled_height = orig_height;
534 }
535 }
536
537 retval = gdk_pixbuf_scale_simple (pixbuf,
538 scaled_width,
539 scaled_height,
540 GDK_INTERP_BILINEAR);
541 }
542
543 return retval;
544}
545
546static void
547netstatus_icon_scale_icons (NetstatusIcon *icon,
548 int size)
549{
550 int i;
551
552 g_return_if_fail (size > 0);
553
554 if (!icon->priv->icons [0])
555 netstatus_icon_init_pixbufs (icon);
556
557 for (i = 0; i < NETSTATUS_STATE_LAST; i++)
558 {
559 if (icon->priv->scaled_icons [i])
560 g_object_unref (icon->priv->scaled_icons [i]);
561 icon->priv->scaled_icons [i] = scale_pixbuf (icon->priv->icons [i],
562 icon->priv->orientation,
563 size,
564 TRUE);
565 }
566
567 for (i = 0; i < NETSTATUS_SIGNAL_LAST; i++)
568 {
569 if (icon->priv->scaled_signal_icons [i])
570 g_object_unref (icon->priv->scaled_signal_icons [i]);
571 icon->priv->scaled_signal_icons [i] = scale_pixbuf (icon->priv->rotated_signal_icons [i],
572 icon->priv->orientation,
573 size,
574 TRUE);
575 }
576
577 netstatus_icon_update_image (icon);
578}
579
580static inline GObjectClass *
581get_box_class (GtkOrientation orientation)
582{
6b775dbb 583 return g_type_class_peek(orientation == GTK_ORIENTATION_HORIZONTAL ? GTK_TYPE_HBOX : GTK_TYPE_VBOX);
6cc5e1a6
DB
584}
585
586static void
587netstatus_icon_size_request (GtkWidget *widget,
588 GtkRequisition *requisition)
589{
590 NetstatusIcon *icon = NETSTATUS_ICON (widget);
591 GObjectClass *klass;
592
593 klass = get_box_class (icon->priv->orientation);
594
595 if (GTK_WIDGET_CLASS (klass)->size_request)
596 GTK_WIDGET_CLASS (klass)->size_request (widget, requisition);
597}
598
599static void
600netstatus_icon_size_allocate (GtkWidget *widget,
601 GtkAllocation *allocation)
602{
603 NetstatusIcon *icon = (NetstatusIcon *) widget;
604 GtkAllocation child_allocation;
605 GObjectClass *klass;
606 int size;
cb7f7ba8
DB
607 GdkWindow *window = gtk_widget_get_window(widget);
608 guint border_width = gtk_container_get_border_width(GTK_CONTAINER (widget));
6cc5e1a6
DB
609
610 if (icon->priv->orientation == GTK_ORIENTATION_HORIZONTAL)
611 size = allocation->height;
612 else
613 size = allocation->width;
614
19ab5cea 615 if (icon->priv->size != size && size > 1)
6cc5e1a6
DB
616 {
617 icon->priv->size = size;
618
619 netstatus_icon_scale_icons (icon, size);
620 }
621
6b775dbb 622 if (gtk_widget_get_realized(widget))
6cc5e1a6 623 {
cb7f7ba8
DB
624 gdk_window_move_resize (window,
625 allocation->x + border_width,
626 allocation->y + border_width,
627 MAX (allocation->width - border_width * 2, 0),
628 MAX (allocation->height - border_width * 2, 0));
6cc5e1a6
DB
629 }
630
631 klass = get_box_class (icon->priv->orientation);
632
633 child_allocation.x = 0;
634 child_allocation.y = 0;
cb7f7ba8
DB
635 child_allocation.width = MAX (allocation->width - border_width * 2, 0);
636 child_allocation.height = MAX (allocation->height - border_width * 2, 0);
6cc5e1a6
DB
637
638 if (GTK_WIDGET_CLASS (klass)->size_allocate)
639 GTK_WIDGET_CLASS (klass)->size_allocate (widget, &child_allocation);
640
cb7f7ba8 641 gtk_widget_get_allocation(widget, allocation);
6cc5e1a6
DB
642}
643
644static void
645netstatus_icon_realize (GtkWidget *widget)
646{
647 GdkWindowAttr attributes;
648 int attributes_mask;
6b775dbb
AG
649 guint border_width;
650 GtkAllocation allocation;
651 GdkWindow *window;
652 GtkStyle *style;
6cc5e1a6 653
6b775dbb
AG
654#if GTK_CHECK_VERSION(2, 20, 0)
655 gtk_widget_set_realized(widget, TRUE);
656#else
6cc5e1a6 657 GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
6b775dbb
AG
658#endif
659
660 gtk_widget_get_allocation (widget, &allocation);
6cc5e1a6 661
6b775dbb 662 border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
6cc5e1a6 663
6b775dbb
AG
664 attributes.x = allocation.x + border_width;
665 attributes.y = allocation.y + border_width;
666 attributes.width = allocation.width - 2 * border_width;
667 attributes.height = allocation.height - 2 * border_width;
6cc5e1a6
DB
668 attributes.window_type = GDK_WINDOW_CHILD;
669 attributes.wclass = GDK_INPUT_OUTPUT;
670 attributes.visual = gtk_widget_get_visual (widget);
671 attributes.colormap = gtk_widget_get_colormap (widget);
672 attributes.event_mask = gtk_widget_get_events (widget) |
673 GDK_BUTTON_MOTION_MASK |
674 GDK_BUTTON_PRESS_MASK |
675 GDK_BUTTON_RELEASE_MASK |
676 GDK_EXPOSURE_MASK |
677 GDK_ENTER_NOTIFY_MASK |
678 GDK_LEAVE_NOTIFY_MASK;
679
680 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
681
6b775dbb
AG
682 window = gdk_window_new (gtk_widget_get_parent_window (widget), &attributes, attributes_mask);
683 gtk_widget_set_window (widget, window);
684 gdk_window_set_user_data (window, widget);
6cc5e1a6 685
6b775dbb
AG
686 gtk_widget_ensure_style (widget);
687 style = gtk_widget_get_style (widget);
688 gtk_style_set_background (style, window, GTK_STATE_NORMAL);
6cc5e1a6
DB
689}
690
691static gboolean
692netstatus_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
704static void
705netstatus_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
736static void
737netstatus_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
769static void
770netstatus_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
796static void
797netstatus_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
863static void
864netstatus_icon_instance_init (NetstatusIcon *icon,
7486d297 865 NetstatusIconClass *klass __attribute__((unused)))
6cc5e1a6
DB
866{
867 icon->priv = g_new0 (NetstatusIconPrivate, 1);
868
6b775dbb 869 gtk_widget_set_has_window(GTK_WIDGET(icon), TRUE);
6cc5e1a6
DB
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
6cc5e1a6
DB
887 gtk_widget_add_events (GTK_WIDGET (icon),
888 GDK_BUTTON_PRESS_MASK | GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK);
889}
890
891GType
892netstatus_icon_get_type (void)
893{
894 static GType type = 0;
895 if (!type)
896 {
897 static const GTypeInfo info =
898 {
899 sizeof (NetstatusIconClass),
900 NULL,
901 NULL,
902 (GClassInitFunc) netstatus_icon_class_init,
903 NULL,
904 NULL,
905 sizeof (NetstatusIcon),
906 0,
907 (GInstanceInitFunc) netstatus_icon_instance_init,
908 NULL
909 };
910 type = g_type_register_static (GTK_TYPE_BOX, "NetstatusIcon", &info, 0);
911 }
912 return type;
913}
914
915GtkWidget *
916netstatus_icon_new (NetstatusIface *iface)
917{
918 GtkWidget* obj = g_object_new (NETSTATUS_TYPE_ICON,
919 /*"iface", iface,*/
920 NULL);
921 netstatus_icon_set_iface( NETSTATUS_ICON(obj), iface );
922 return obj;
923}
924
925void
926netstatus_icon_invoke (NetstatusIcon *icon)
927{
928 g_return_if_fail (NETSTATUS_IS_ICON (icon));
929
930 if (netstatus_iface_get_state (icon->priv->iface) != NETSTATUS_STATE_ERROR)
931 {
932 if (icon->priv->error_dialog)
933 gtk_widget_destroy (icon->priv->error_dialog);
934 icon->priv->error_dialog = NULL;
935
936 g_signal_emit (icon, icon_signals [INVOKED], 0);
937 }
938 else
939 {
940 const GError *error;
941
942 error = netstatus_iface_get_error (icon->priv->iface);
943 g_assert (error != NULL);
944
945 if (icon->priv->error_dialog)
946 {
947 gtk_window_set_screen (GTK_WINDOW (icon->priv->error_dialog),
948 gtk_widget_get_screen (GTK_WIDGET (icon)));
949 gtk_window_present (GTK_WINDOW (icon->priv->error_dialog));
950 return;
951 }
952
953 icon->priv->error_dialog =
954 gtk_message_dialog_new (NULL, 0,
955 GTK_MESSAGE_ERROR,
956 GTK_BUTTONS_CLOSE,
957 _("Please contact your system administrator to resolve the following problem:\n\n%s"),
958 error->message);
959
960 gtk_window_set_screen (GTK_WINDOW (icon->priv->error_dialog),
961 gtk_widget_get_screen (GTK_WIDGET (icon)));
962
963 g_signal_connect (icon->priv->error_dialog, "response",
964 G_CALLBACK (gtk_widget_destroy), NULL);
965 g_signal_connect (icon->priv->error_dialog, "destroy",
966 G_CALLBACK (gtk_widget_destroyed),
967 &icon->priv->error_dialog);
968
969 gtk_widget_show (icon->priv->error_dialog);
970 }
971}
972
973void
974netstatus_icon_set_iface (NetstatusIcon *icon,
975 NetstatusIface *iface)
976{
977
978 g_return_if_fail (NETSTATUS_IS_ICON (icon));
979
980 if (icon->priv->iface != iface)
981 {
982 NetstatusIface *old_iface;
983
984 old_iface = icon->priv->iface;
985
986 if (icon->priv->state_changed_id)
987 {
988 g_assert (icon->priv->iface != NULL);
989 g_assert (icon->priv->name_changed_id != 0);
990 g_signal_handler_disconnect (icon->priv->iface,
991 icon->priv->state_changed_id);
992 g_signal_handler_disconnect (icon->priv->iface,
993 icon->priv->name_changed_id);
994 g_signal_handler_disconnect (icon->priv->iface,
995 icon->priv->wireless_changed_id);
996 g_signal_handler_disconnect (icon->priv->iface,
997 icon->priv->signal_changed_id);
998 }
999
1000 if (iface)
1001 g_object_ref (iface);
1002 icon->priv->iface = iface;
1003
1004 if (old_iface)
1005 g_object_unref (old_iface);
1006
1007 icon->priv->state_changed_id = g_signal_connect (icon->priv->iface, "notify::state",
1008 G_CALLBACK (netstatus_icon_state_changed), icon);
1009 icon->priv->name_changed_id = g_signal_connect (icon->priv->iface, "notify::name",
1010 G_CALLBACK (netstatus_icon_name_changed), icon);
1011 icon->priv->wireless_changed_id = g_signal_connect (icon->priv->iface, "notify::wireless",
1012 G_CALLBACK (netstatus_icon_is_wireless_changed), icon);
1013 icon->priv->signal_changed_id = g_signal_connect (icon->priv->iface, "notify::signal-strength",
1014 G_CALLBACK (netstatus_icon_signal_changed), icon);
1015
1016 netstatus_icon_state_changed (icon->priv->iface, NULL, icon);
1017 netstatus_icon_name_changed (icon->priv->iface, NULL, icon);
1018 netstatus_icon_is_wireless_changed (icon->priv->iface, NULL, icon);
1019 netstatus_icon_signal_changed (icon->priv->iface, NULL, icon);
1020
1021 /* g_object_notify (G_OBJECT (icon), "iface"); */
1022 }
1023}
1024
1025NetstatusIface *
1026netstatus_icon_get_iface (NetstatusIcon *icon)
1027{
1028 g_return_val_if_fail (NETSTATUS_IS_ICON (icon), 0);
1029
1030 return icon->priv->iface;
1031}
1032
1033void
1034netstatus_icon_set_orientation (NetstatusIcon *icon,
1035 GtkOrientation orientation)
1036{
1037 g_return_if_fail (NETSTATUS_IS_ICON (icon));
1038
1039 if (icon->priv->orientation != orientation)
1040 {
1041 icon->priv->orientation = orientation;
1042
1043 netstatus_icon_rotate_signal_icons (icon, orientation);
1044 netstatus_icon_update_image (icon);
1045
1046 icon->priv->size = -1;
1047
1048 gtk_widget_queue_resize (GTK_WIDGET (icon));
1049
1050 g_object_notify (G_OBJECT (icon), "orientation");
1051 }
1052}
1053
1054GtkOrientation
1055netstatus_icon_get_orientation (NetstatusIcon *icon)
1056{
1057 g_return_val_if_fail (NETSTATUS_IS_ICON (icon), GTK_ORIENTATION_HORIZONTAL);
1058
1059 return icon->priv->orientation;
1060}
1061
1062void
1063netstatus_icon_set_tooltips_enabled (NetstatusIcon *icon,
1064 gboolean enabled)
1065{
1066 g_return_if_fail (NETSTATUS_IS_ICON (icon));
1067
1068 enabled = enabled != FALSE;
1069
1070 if (icon->priv->tooltips_enabled != enabled)
1071 {
1072 icon->priv->tooltips_enabled = enabled;
1073
6cc5e1a6
DB
1074 g_object_notify (G_OBJECT (icon), "tooltips-enabled");
1075 }
1076}
1077
1078gboolean
1079netstatus_icon_get_tooltips_enabled (NetstatusIcon *icon)
1080{
1081 g_return_val_if_fail (NETSTATUS_ICON (icon), TRUE);
1082
1083 return icon->priv->tooltips_enabled;
1084}
1085
1086void
1087netstatus_icon_set_show_signal (NetstatusIcon *icon,
1088 gboolean show_signal)
1089{
1090 g_return_if_fail (NETSTATUS_IS_ICON (icon));
1091
1092 show_signal = show_signal != FALSE;
1093
1094 if (icon->priv->show_signal != show_signal)
1095 {
1096 icon->priv->show_signal = show_signal;
1097
1098 if (show_signal && netstatus_iface_get_is_wireless (icon->priv->iface))
1099 gtk_widget_show (icon->priv->signal_image);
1100 else
1101 gtk_widget_hide (icon->priv->signal_image);
1102
7486d297 1103 /* g_object_notify (G_OBJECT (icon), "show-signal"); */
6cc5e1a6
DB
1104 }
1105}
1106
1107gboolean
1108netstatus_icon_get_show_signal (NetstatusIcon *icon)
1109{
1110 g_return_val_if_fail (NETSTATUS_ICON (icon), TRUE);
1111
1112 return icon->priv->show_signal;
1113}