]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/tray-monitor/eggstatusicon.c
ebl move Errors count up to be more easy to parse with Bweb
[bacula/bacula] / bacula / src / tray-monitor / eggstatusicon.c
1 /* eggstatusicon.c:
2  *
3  * Copyright (C) 2003 Sun Microsystems, Inc.
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Library General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Library General Public License for more details.
14  *
15  * You should have received a copy of the GNU Library General Public
16  * License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18  * Boston, MA 02111-1307, USA.
19  *
20  * Authors:
21  *      Mark McLoughlin <mark@skynet.ie>
22  *  Nicolas Boichat <nicolas@boichat.ch> (add access to the underlying EggTrayIcon)
23  */
24
25 extern "C" {
26
27 #include <string.h>
28 #include <libintl.h>
29
30 #include "eggstatusicon.h"
31
32 #include <gtk/gtk.h>
33 #include "eggmarshalers.h"
34
35 #ifndef EGG_COMPILATION
36 #ifndef _
37 #define _(x) dgettext (GETTEXT_PACKAGE, x)
38 #define N_(x) x
39 #endif
40 #else
41 #define _(x) x
42 #define N_(x) x
43 #endif
44
45 enum{
46   PROP_0,
47   PROP_PIXBUF,
48   PROP_FILE,
49   PROP_STOCK,
50   PROP_PIXBUF_ANIMATION,
51   PROP_STORAGE_TYPE,
52   PROP_SIZE,
53   PROP_BLINKING
54 };
55
56 enum {
57   ACTIVATE_SIGNAL,
58   POPUP_MENU_SIGNAL,
59   SIZE_CHANGED_SIGNAL,
60   LAST_SIGNAL
61 };
62
63 struct _EggStatusIconPrivate
64 {
65   GtkWidget    *tray_icon;
66   GtkWidget    *image;
67   gint          size;
68
69   GtkTooltips  *tooltips;
70
71   GtkImageType  image_type;
72
73   union
74     {
75       GdkPixbuf          *pixbuf;
76       const gchar        *stock_id;
77       GdkPixbufAnimation *animimation;
78     } image_data;
79
80   GdkPixbuf    *blank_icon;
81   guint         blinking_timeout;
82
83   guint         blinking : 1;
84   guint         blink_off : 1;
85 };
86
87 static void egg_status_icon_class_init (EggStatusIconClass *klass);
88 static void egg_status_icon_init       (EggStatusIcon      *status_icon);
89
90 static void egg_status_icon_finalize     (GObject      *object);
91 static void egg_status_icon_set_property (GObject      *object,
92                                           guint         prop_id,
93                                           const GValue *value,
94                                           GParamSpec   *pspec);
95 static void egg_status_icon_get_property (GObject      *object,
96                                           guint         prop_id,
97                                           GValue       *value,
98                                           GParamSpec   *pspec);
99
100 static void     egg_status_icon_size_allocate    (EggStatusIcon  *status_icon,
101                                                   GtkAllocation  *allocation);
102 static gboolean egg_status_icon_button_release   (EggStatusIcon  *status_icon,
103                                                   GdkEventButton *event);
104 static void     egg_status_icon_disable_blinking (EggStatusIcon  *status_icon);
105 static void     egg_status_icon_reset_image_data (EggStatusIcon  *status_icon);
106
107
108 static GObjectClass *parent_class = NULL;
109 static guint status_icon_signals [LAST_SIGNAL] = { 0 };
110
111 GType
112 egg_status_icon_get_type (void)
113 {
114   static GType status_icon_type = 0;
115
116   if (!status_icon_type)
117     {
118       static const GTypeInfo status_icon_info =
119       {
120         sizeof (EggStatusIconClass),
121         NULL,           /* base_init */
122         NULL,           /* base_finalize */
123         (GClassInitFunc) egg_status_icon_class_init,
124         NULL,           /* class_finalize */
125         NULL,           /* class_data */
126         sizeof (EggStatusIcon),
127         0,              /* n_preallocs */
128         (GInstanceInitFunc) egg_status_icon_init,
129       };
130
131       status_icon_type = g_type_register_static (G_TYPE_OBJECT,
132                                                  "EggStatusIcon",
133                                                  &status_icon_info, (GTypeFlags)0);
134     }
135
136   return status_icon_type;
137 }
138
139 static void
140 egg_status_icon_class_init (EggStatusIconClass *klass)
141 {
142   GObjectClass *gobject_class = (GObjectClass *) klass;
143
144   parent_class = (GObjectClass*)g_type_class_peek_parent (klass);
145
146   gobject_class->finalize     = egg_status_icon_finalize;
147   gobject_class->set_property = egg_status_icon_set_property;
148   gobject_class->get_property = egg_status_icon_get_property;
149
150   g_object_class_install_property (gobject_class,
151                                    PROP_PIXBUF,
152                                    g_param_spec_object ("pixbuf",
153                                                         "Pixbuf",
154                                                         "A GdkPixbuf to display",
155                                                         GDK_TYPE_PIXBUF,
156                                                         (GParamFlags)G_PARAM_READWRITE));
157
158   g_object_class_install_property (gobject_class,
159                                    PROP_FILE,
160                                    g_param_spec_string ("file",
161                                                         "Filename",
162                                                         "Filename to load and display",
163                                                         NULL,
164                                                         G_PARAM_WRITABLE));
165
166   g_object_class_install_property (gobject_class,
167                                    PROP_STOCK,
168                                    g_param_spec_string ("stock",
169                                                         "Stock ID",
170                                                         "Stock ID for a stock image to display",
171                                                         NULL,
172                                                         (GParamFlags)G_PARAM_READWRITE));
173
174   g_object_class_install_property (gobject_class,
175                                    PROP_PIXBUF_ANIMATION,
176                                    g_param_spec_object ("pixbuf-animation",
177                                                         "Animation",
178                                                         "GdkPixbufAnimation to display",
179                                                         GDK_TYPE_PIXBUF_ANIMATION,
180                                                         (GParamFlags)G_PARAM_READWRITE));
181
182   g_object_class_install_property (gobject_class,
183                                    PROP_STORAGE_TYPE,
184                                    g_param_spec_enum ("image-type",
185                                                       "Image type",
186                                                       "The representation being used for image data",
187                                                       GTK_TYPE_IMAGE_TYPE,
188                                                       GTK_IMAGE_EMPTY,
189                                                       G_PARAM_READABLE));
190
191   g_object_class_install_property (gobject_class,
192                                    PROP_SIZE,
193                                    g_param_spec_int ("size",
194                                                      "Size",
195                                                      "The size of the icon",
196                                                      G_MININT,
197                                                      G_MAXINT,
198                                                      0,
199                                                      G_PARAM_READABLE));
200
201   g_object_class_install_property (gobject_class,
202                                    PROP_BLINKING,
203                                    g_param_spec_boolean ("blinking",
204                                                          "Blinking",
205                                                          "Whether or not the status icon is blinking",
206                                                          FALSE,
207                                                          (GParamFlags)G_PARAM_READWRITE));
208
209   status_icon_signals [ACTIVATE_SIGNAL] =
210     g_signal_new ("activate",
211                   G_TYPE_FROM_CLASS (gobject_class),
212                   (GSignalFlags)(G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION),
213                   G_STRUCT_OFFSET (EggStatusIconClass, activate),
214                   NULL,
215                   NULL,
216                   g_cclosure_marshal_VOID__VOID,
217                   G_TYPE_NONE,
218                   0);
219
220   status_icon_signals [POPUP_MENU_SIGNAL] =
221     g_signal_new ("popup-menu",
222                   G_TYPE_FROM_CLASS (gobject_class),
223                   (GSignalFlags)(G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION),
224                   G_STRUCT_OFFSET (EggStatusIconClass, popup_menu),
225                   NULL,
226                   NULL,
227                   _egg_marshal_VOID__UINT_UINT,
228                   G_TYPE_NONE,
229                   2,
230                   G_TYPE_UINT,
231                   G_TYPE_UINT);
232
233   status_icon_signals [SIZE_CHANGED_SIGNAL] =
234     g_signal_new ("size-changed",
235                   G_TYPE_FROM_CLASS (gobject_class),
236                   G_SIGNAL_RUN_FIRST,
237                   G_STRUCT_OFFSET (EggStatusIconClass, size_changed),
238                   NULL,
239                   NULL,
240                   g_cclosure_marshal_VOID__INT,
241                   G_TYPE_NONE,
242                   1,
243                   G_TYPE_INT);
244 }
245
246 static void
247 egg_status_icon_init (EggStatusIcon *status_icon)
248 {
249   status_icon->priv = g_new0 (EggStatusIconPrivate, 1);
250
251   status_icon->priv->image_type = GTK_IMAGE_EMPTY;
252   status_icon->priv->size       = G_MAXINT;
253
254   status_icon->priv->tray_icon = GTK_WIDGET (egg_tray_icon_new (NULL));
255
256   gtk_widget_add_events (GTK_WIDGET (status_icon->priv->tray_icon),
257                          GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK);
258
259   g_signal_connect_swapped (status_icon->priv->tray_icon, "button-release-event",
260                             G_CALLBACK (egg_status_icon_button_release), status_icon);
261
262   status_icon->priv->image = gtk_image_new ();
263   gtk_container_add (GTK_CONTAINER (status_icon->priv->tray_icon),
264                      status_icon->priv->image);
265
266   g_signal_connect_swapped (status_icon->priv->image, "size-allocate",
267                             G_CALLBACK (egg_status_icon_size_allocate), status_icon);
268
269   gtk_widget_show (status_icon->priv->image);
270   gtk_widget_show (status_icon->priv->tray_icon);
271
272   status_icon->priv->tooltips = gtk_tooltips_new ();
273   g_object_ref (status_icon->priv->tooltips);
274   gtk_object_sink (GTK_OBJECT (status_icon->priv->tooltips));
275 }
276
277 static void
278 egg_status_icon_finalize (GObject *object)
279 {
280   EggStatusIcon *status_icon = EGG_STATUS_ICON (object);
281
282   egg_status_icon_disable_blinking (status_icon);
283
284   egg_status_icon_reset_image_data (status_icon);
285
286   if (status_icon->priv->blank_icon)
287     g_object_unref (status_icon->priv->blank_icon);
288   status_icon->priv->blank_icon = NULL;
289
290   if (status_icon->priv->tooltips)
291     g_object_unref (status_icon->priv->tooltips);
292   status_icon->priv->tooltips = NULL;
293
294   gtk_widget_destroy (status_icon->priv->tray_icon);
295
296   g_free (status_icon->priv);
297
298   G_OBJECT_CLASS (parent_class)->finalize (object);
299 }
300
301 static void
302 egg_status_icon_set_property (GObject      *object,
303                               guint         prop_id,
304                               const GValue *value,
305                               GParamSpec   *pspec)
306 {
307   EggStatusIcon *status_icon = EGG_STATUS_ICON (object);
308
309   switch (prop_id)
310     {
311     case PROP_PIXBUF:
312       egg_status_icon_set_from_pixbuf (status_icon, (GdkPixbuf*)g_value_get_object (value));
313       break;
314     case PROP_FILE:
315       egg_status_icon_set_from_file (status_icon, g_value_get_string (value));
316       break;
317     case PROP_STOCK:
318       egg_status_icon_set_from_stock (status_icon, g_value_get_string (value));
319       break;
320     case PROP_PIXBUF_ANIMATION:
321       egg_status_icon_set_from_animation (status_icon, (GdkPixbufAnimation*)g_value_get_object (value));
322       break;
323     case PROP_BLINKING:
324       egg_status_icon_set_is_blinking (status_icon, g_value_get_boolean (value));
325       break;
326     default:
327       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
328       break;
329     }
330 }
331
332 static void
333 egg_status_icon_get_property (GObject    *object,
334                               guint       prop_id,
335                               GValue     *value,
336                               GParamSpec *pspec)
337 {
338   EggStatusIcon *status_icon = EGG_STATUS_ICON (object);
339
340   switch (prop_id)
341     {
342     case PROP_PIXBUF:
343       g_value_set_object (value, egg_status_icon_get_pixbuf (status_icon));
344       break;
345     case PROP_STOCK:
346       g_value_set_string (value, egg_status_icon_get_stock (status_icon));
347       break;
348     case PROP_PIXBUF_ANIMATION:
349       g_value_set_object (value, egg_status_icon_get_animation (status_icon));
350       break;
351     case PROP_STORAGE_TYPE:
352       g_value_set_enum (value, egg_status_icon_get_image_type (status_icon));
353       break;
354     case PROP_SIZE:
355       g_value_set_int (value, status_icon->priv->size);
356       break;
357     case PROP_BLINKING:
358       g_value_set_boolean (value, status_icon->priv->blinking);
359       break;
360     default:
361       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
362       break;
363     }
364 }
365
366 EggStatusIcon *
367 egg_status_icon_new (void)
368 {
369   return (EggStatusIcon*)g_object_new (EGG_TYPE_STATUS_ICON, NULL);
370 }
371
372 EggStatusIcon *
373 egg_status_icon_new_from_pixbuf (GdkPixbuf *pixbuf)
374 {
375   return (EggStatusIcon*)g_object_new (EGG_TYPE_STATUS_ICON,
376                        "pixbuf", pixbuf,
377                        NULL);
378 }
379
380 EggStatusIcon *
381 egg_status_icon_new_from_file (const gchar *filename)
382 {
383   return (EggStatusIcon*)g_object_new (EGG_TYPE_STATUS_ICON,
384                        "file", filename,
385                        NULL);
386 }
387
388 EggStatusIcon *
389 egg_status_icon_new_from_stock (const gchar *stock_id)
390 {
391   return (EggStatusIcon*)g_object_new (EGG_TYPE_STATUS_ICON,
392                        "stock", stock_id,
393                        NULL);
394 }
395
396 EggStatusIcon *
397 egg_status_icon_new_from_animation (GdkPixbufAnimation *animation)
398 {
399   return (EggStatusIcon*)g_object_new (EGG_TYPE_STATUS_ICON,
400                        "pixbuf_animation", animation,
401                        NULL);
402 }
403
404 static void
405 emit_activate_signal (EggStatusIcon *status_icon)
406 {
407   g_signal_emit (status_icon,
408                  status_icon_signals [ACTIVATE_SIGNAL], 0);
409 }
410
411 static void
412 emit_popup_menu_signal (EggStatusIcon *status_icon,
413                         guint          button,
414                         guint32        activate_time)
415 {
416   g_signal_emit (status_icon,
417                  status_icon_signals [POPUP_MENU_SIGNAL], 0,
418                  button,
419                  activate_time);
420 }
421
422 static gboolean
423 emit_size_changed_signal (EggStatusIcon *status_icon,
424                           gint           size)
425 {
426   gboolean handled = FALSE;
427
428   g_signal_emit (status_icon,
429                  status_icon_signals [SIZE_CHANGED_SIGNAL], 0,
430                  size,
431                  &handled);
432
433   return handled;
434 }
435
436 static GdkPixbuf *
437 egg_status_icon_blank_icon (EggStatusIcon *status_icon)
438 {
439   if (status_icon->priv->blank_icon)
440     {
441       gint width, height;
442
443       width  = gdk_pixbuf_get_width (status_icon->priv->blank_icon);
444       height = gdk_pixbuf_get_width (status_icon->priv->blank_icon);
445
446       if (width  == status_icon->priv->size &&
447           height == status_icon->priv->size)
448         {
449           return status_icon->priv->blank_icon;
450         }
451       else
452         {
453           g_object_unref (status_icon->priv->blank_icon);
454           status_icon->priv->blank_icon = NULL;
455         }
456     }
457
458   status_icon->priv->blank_icon = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8,
459                                                   status_icon->priv->size,
460                                                   status_icon->priv->size);
461   if (status_icon->priv->blank_icon)
462     gdk_pixbuf_fill (status_icon->priv->blank_icon, 0);
463
464   return status_icon->priv->blank_icon;
465 }
466
467 static void
468 egg_status_icon_update_image (EggStatusIcon *status_icon)
469 {
470   if (status_icon->priv->blink_off)
471     {
472       gtk_image_set_from_pixbuf (GTK_IMAGE (status_icon->priv->image),
473                                  egg_status_icon_blank_icon (status_icon));
474       return;
475     }
476
477   switch (status_icon->priv->image_type)
478     {
479     case GTK_IMAGE_PIXBUF:
480       {
481         GdkPixbuf *pixbuf;
482
483         pixbuf = status_icon->priv->image_data.pixbuf;
484
485         if (pixbuf)
486           {
487             GdkPixbuf *scaled;
488             gint size;
489             gint width;
490             gint height;
491
492             size = status_icon->priv->size;
493
494             width  = gdk_pixbuf_get_width  (pixbuf);
495             height = gdk_pixbuf_get_height (pixbuf);
496
497             if (width > size || height > size)
498               {
499                 scaled = gdk_pixbuf_scale_simple (pixbuf,
500                                                   MIN (size, width),
501                                                   MIN (size, height),
502                                                   GDK_INTERP_BILINEAR);
503               }
504             else
505               {
506                 scaled = (GdkPixbuf*)g_object_ref (pixbuf);
507               }
508
509             gtk_image_set_from_pixbuf (GTK_IMAGE (status_icon->priv->image), scaled);
510
511             g_object_unref (scaled);
512           }
513         else
514           {
515             gtk_image_set_from_pixbuf (GTK_IMAGE (status_icon->priv->image), NULL);
516           }
517       }
518       break;
519     case GTK_IMAGE_STOCK:
520     case GTK_IMAGE_ANIMATION:
521     case GTK_IMAGE_EMPTY:
522       gtk_image_set_from_pixbuf (GTK_IMAGE (status_icon->priv->image), NULL);
523       break;
524     default:
525       g_assert_not_reached ();
526       break;
527     }
528 }
529
530 static void
531 egg_status_icon_size_allocate (EggStatusIcon *status_icon,
532                                GtkAllocation *allocation)
533 {
534   GtkOrientation orientation;
535   gint size;
536
537   orientation = egg_tray_icon_get_orientation (EGG_TRAY_ICON (status_icon->priv->tray_icon));
538
539   if (orientation == GTK_ORIENTATION_HORIZONTAL)
540     size = allocation->height;
541   else
542     size = allocation->width;
543
544   if (status_icon->priv->size != size)
545     {
546       status_icon->priv->size = size;
547
548       g_object_notify (G_OBJECT (status_icon), "size");
549
550       if (!emit_size_changed_signal (status_icon, size))
551         {
552           egg_status_icon_update_image (status_icon);
553         }
554     }
555 }
556
557 static gboolean
558 egg_status_icon_button_release (EggStatusIcon  *status_icon,
559                                 GdkEventButton *event)
560 {
561   if (event->button == 1)
562     {
563       emit_activate_signal (status_icon);
564       return TRUE;
565     }
566   if (event->button == 3)
567     {
568       emit_popup_menu_signal (status_icon, event->button, event->time);
569       return TRUE;
570     }
571
572   return FALSE;
573 }
574
575 static void
576 egg_status_icon_reset_image_data (EggStatusIcon *status_icon)
577 {
578   switch (status_icon->priv->image_type)
579   {
580     case GTK_IMAGE_PIXBUF:
581       status_icon->priv->image_type = GTK_IMAGE_EMPTY;
582
583       if (status_icon->priv->image_data.pixbuf)
584         g_object_unref (status_icon->priv->image_data.pixbuf);
585       status_icon->priv->image_data.pixbuf = NULL;
586
587       g_object_notify (G_OBJECT (status_icon), "image-type");
588       g_object_notify (G_OBJECT (status_icon), "pixbuf");
589       break;
590     case GTK_IMAGE_STOCK:
591     case GTK_IMAGE_ANIMATION:
592     case GTK_IMAGE_EMPTY:
593       break;
594     default:
595       g_assert_not_reached ();
596       break;
597   }
598 }
599
600 void
601 egg_status_icon_set_from_pixbuf (EggStatusIcon *status_icon,
602                                  GdkPixbuf     *pixbuf)
603 {
604   g_return_if_fail (EGG_IS_STATUS_ICON (status_icon));
605   g_return_if_fail (pixbuf == NULL || GDK_IS_PIXBUF (pixbuf));
606
607   if (pixbuf)
608     g_object_ref (pixbuf);
609
610   g_object_freeze_notify (G_OBJECT (status_icon));
611
612   egg_status_icon_reset_image_data (status_icon);
613
614   status_icon->priv->image_type = GTK_IMAGE_PIXBUF;
615   status_icon->priv->image_data.pixbuf = pixbuf;
616
617   g_object_notify (G_OBJECT (status_icon), "image-type");
618   g_object_notify (G_OBJECT (status_icon), "pixbuf");
619
620   g_object_thaw_notify (G_OBJECT (status_icon));
621
622   egg_status_icon_update_image (status_icon);
623 }
624
625 void
626 egg_status_icon_set_from_file (EggStatusIcon *status_icon,
627                                const gchar   *filename)
628 {
629   g_return_if_fail (EGG_IS_STATUS_ICON (status_icon));
630 }
631
632 void
633 egg_status_icon_set_from_stock (EggStatusIcon *status_icon,
634                                 const gchar   *stock_id)
635 {
636   g_return_if_fail (EGG_IS_STATUS_ICON (status_icon));
637 }
638
639 void
640 egg_status_icon_set_from_animation (EggStatusIcon      *status_icon,
641                                     GdkPixbufAnimation *animation)
642 {
643   g_return_if_fail (EGG_IS_STATUS_ICON (status_icon));
644   g_return_if_fail (animation == NULL || GDK_IS_PIXBUF_ANIMATION (animation));
645 }
646
647 GtkImageType
648 egg_status_icon_get_image_type (EggStatusIcon *status_icon)
649 {
650   g_return_val_if_fail (EGG_IS_STATUS_ICON (status_icon), GTK_IMAGE_EMPTY);
651
652   return status_icon->priv->image_type;
653 }
654
655 GdkPixbuf *
656 egg_status_icon_get_pixbuf (EggStatusIcon *status_icon)
657 {
658   g_return_val_if_fail (EGG_IS_STATUS_ICON (status_icon), NULL);
659   g_return_val_if_fail (status_icon->priv->image_type == GTK_IMAGE_PIXBUF ||
660                         status_icon->priv->image_type == GTK_IMAGE_EMPTY, NULL);
661
662   if (status_icon->priv->image_type == GTK_IMAGE_EMPTY)
663     status_icon->priv->image_data.pixbuf = NULL;
664
665   return status_icon->priv->image_data.pixbuf;
666 }
667
668 G_CONST_RETURN gchar *
669 egg_status_icon_get_stock (EggStatusIcon *status_icon)
670 {
671   g_return_val_if_fail (EGG_IS_STATUS_ICON (status_icon), NULL);
672
673   return NULL;
674 }
675
676 GdkPixbufAnimation *
677 egg_status_icon_get_animation (EggStatusIcon *status_icon)
678 {
679   g_return_val_if_fail (EGG_IS_STATUS_ICON (status_icon), NULL);
680
681   return NULL;
682 }
683
684 gint
685 egg_status_icon_get_size (EggStatusIcon *status_icon)
686 {
687   g_return_val_if_fail (EGG_IS_STATUS_ICON (status_icon), -1);
688
689   return status_icon->priv->size;
690 }
691
692 void
693 egg_status_icon_set_tooltip (EggStatusIcon *status_icon,
694                              const gchar   *tooltip_text,
695                              const gchar   *tooltip_private)
696 {
697   g_return_if_fail (EGG_IS_STATUS_ICON (status_icon));
698
699   gtk_tooltips_set_tip (status_icon->priv->tooltips,
700                         status_icon->priv->tray_icon,
701                         tooltip_text,
702                         tooltip_private);
703 }
704
705 void
706 egg_status_icon_set_balloon_text (EggStatusIcon *status_icon,
707                                   const gchar   *text)
708 {
709   g_return_if_fail (EGG_IS_STATUS_ICON (status_icon));
710 }
711
712 G_CONST_RETURN gchar *
713 egg_status_icon_get_balloon_text (EggStatusIcon *status_icon)
714 {
715   g_return_val_if_fail (EGG_IS_STATUS_ICON (status_icon), NULL);
716
717   return NULL;
718 }
719
720 static gboolean
721 egg_status_icon_blinker (EggStatusIcon *status_icon)
722 {
723   status_icon->priv->blink_off = !status_icon->priv->blink_off;
724
725   egg_status_icon_update_image (status_icon);
726
727   return TRUE;
728 }
729
730 static void
731 egg_status_icon_enable_blinking (EggStatusIcon *status_icon)
732 {
733   if (!status_icon->priv->blinking_timeout)
734     {
735       egg_status_icon_blinker (status_icon);
736
737       status_icon->priv->blinking_timeout =
738         g_timeout_add (500, (GSourceFunc) egg_status_icon_blinker, status_icon);
739     }
740 }
741
742 static void
743 egg_status_icon_disable_blinking (EggStatusIcon *status_icon)
744 {
745   if (status_icon->priv->blinking_timeout)
746     {
747       g_source_remove (status_icon->priv->blinking_timeout);
748       status_icon->priv->blinking_timeout = 0;
749       status_icon->priv->blink_off = FALSE;
750
751       egg_status_icon_update_image (status_icon);
752     }
753 }
754
755 void
756 egg_status_icon_set_is_blinking (EggStatusIcon *status_icon,
757                                  guint       is_blinking)
758 {
759   g_return_if_fail (EGG_IS_STATUS_ICON (status_icon));
760
761   is_blinking = is_blinking != FALSE;
762
763   if (status_icon->priv->blinking != is_blinking)
764     {
765       status_icon->priv->blinking = is_blinking;
766
767       if (is_blinking)
768         egg_status_icon_enable_blinking (status_icon);
769       else
770         egg_status_icon_disable_blinking (status_icon);
771
772       g_object_notify (G_OBJECT (status_icon), "blinking");
773     }
774 }
775
776 gboolean
777 egg_status_icon_get_is_blinking (EggStatusIcon *status_icon)
778 {
779   g_return_val_if_fail (EGG_IS_STATUS_ICON (status_icon), FALSE);
780
781   return status_icon->priv->blinking;
782 }
783
784 EggTrayIcon*
785 egg_status_icon_get_tray_icon (EggStatusIcon      *status_icon)
786 {
787    g_return_val_if_fail (EGG_IS_STATUS_ICON (status_icon), NULL);
788
789    return EGG_TRAY_ICON(status_icon->priv->tray_icon);
790 }
791
792 } //extern "C"