3 * Copyright (C) 2003 Sun Microsystems, Inc.
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.
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.
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.
21 * Mark McLoughlin <mark@skynet.ie>
22 * Nicolas Boichat <nicolas@boichat.ch> (add access to the underlying EggTrayIcon)
25 Bacula® - The Network Backup Solution
27 Copyright (C) 2004-2006 Free Software Foundation Europe e.V.
29 The main author of Bacula is Kern Sibbald, with contributions from
30 many others, a complete list can be found in the file AUTHORS.
31 This program is Free Software; you can redistribute it and/or
32 modify it under the terms of version two of the GNU General Public
33 License as published by the Free Software Foundation plus additions
34 that are listed in the file LICENSE.
36 This program is distributed in the hope that it will be useful, but
37 WITHOUT ANY WARRANTY; without even the implied warranty of
38 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
39 General Public License for more details.
41 You should have received a copy of the GNU General Public License
42 along with this program; if not, write to the Free Software
43 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
46 Bacula® is a registered trademark of John Walker.
47 The licensor of Bacula is the Free Software Foundation Europe
48 (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
49 Switzerland, email:ftf@fsfeurope.org.
57 #include "eggstatusicon.h"
60 #include "eggmarshalers.h"
62 #ifndef EGG_COMPILATION
64 #define _(x) dgettext (GETTEXT_PACKAGE, x)
77 PROP_PIXBUF_ANIMATION,
90 struct _EggStatusIconPrivate
96 GtkTooltips *tooltips;
98 GtkImageType image_type;
103 const gchar *stock_id;
104 GdkPixbufAnimation *animimation;
107 GdkPixbuf *blank_icon;
108 guint blinking_timeout;
114 static void egg_status_icon_class_init (EggStatusIconClass *klass);
115 static void egg_status_icon_init (EggStatusIcon *status_icon);
117 static void egg_status_icon_finalize (GObject *object);
118 static void egg_status_icon_set_property (GObject *object,
122 static void egg_status_icon_get_property (GObject *object,
127 static void egg_status_icon_size_allocate (EggStatusIcon *status_icon,
128 GtkAllocation *allocation);
129 static gboolean egg_status_icon_button_release (EggStatusIcon *status_icon,
130 GdkEventButton *event);
131 static void egg_status_icon_disable_blinking (EggStatusIcon *status_icon);
132 static void egg_status_icon_reset_image_data (EggStatusIcon *status_icon);
135 static GObjectClass *parent_class = NULL;
136 static guint status_icon_signals [LAST_SIGNAL] = { 0 };
139 egg_status_icon_get_type (void)
141 static GType status_icon_type = 0;
143 if (!status_icon_type)
145 static const GTypeInfo status_icon_info =
147 sizeof (EggStatusIconClass),
148 NULL, /* base_init */
149 NULL, /* base_finalize */
150 (GClassInitFunc) egg_status_icon_class_init,
151 NULL, /* class_finalize */
152 NULL, /* class_data */
153 sizeof (EggStatusIcon),
155 (GInstanceInitFunc) egg_status_icon_init,
158 status_icon_type = g_type_register_static (G_TYPE_OBJECT,
160 &status_icon_info, (GTypeFlags)0);
163 return status_icon_type;
167 egg_status_icon_class_init (EggStatusIconClass *klass)
169 GObjectClass *gobject_class = (GObjectClass *) klass;
171 parent_class = (GObjectClass*)g_type_class_peek_parent (klass);
173 gobject_class->finalize = egg_status_icon_finalize;
174 gobject_class->set_property = egg_status_icon_set_property;
175 gobject_class->get_property = egg_status_icon_get_property;
177 g_object_class_install_property (gobject_class,
179 g_param_spec_object ("pixbuf",
181 "A GdkPixbuf to display",
183 (GParamFlags)G_PARAM_READWRITE));
185 g_object_class_install_property (gobject_class,
187 g_param_spec_string ("file",
189 "Filename to load and display",
193 g_object_class_install_property (gobject_class,
195 g_param_spec_string ("stock",
197 "Stock ID for a stock image to display",
199 (GParamFlags)G_PARAM_READWRITE));
201 g_object_class_install_property (gobject_class,
202 PROP_PIXBUF_ANIMATION,
203 g_param_spec_object ("pixbuf-animation",
205 "GdkPixbufAnimation to display",
206 GDK_TYPE_PIXBUF_ANIMATION,
207 (GParamFlags)G_PARAM_READWRITE));
209 g_object_class_install_property (gobject_class,
211 g_param_spec_enum ("image-type",
213 "The representation being used for image data",
218 g_object_class_install_property (gobject_class,
220 g_param_spec_int ("size",
222 "The size of the icon",
228 g_object_class_install_property (gobject_class,
230 g_param_spec_boolean ("blinking",
232 "Whether or not the status icon is blinking",
234 (GParamFlags)G_PARAM_READWRITE));
236 status_icon_signals [ACTIVATE_SIGNAL] =
237 g_signal_new ("activate",
238 G_TYPE_FROM_CLASS (gobject_class),
239 (GSignalFlags)(G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION),
240 G_STRUCT_OFFSET (EggStatusIconClass, activate),
243 g_cclosure_marshal_VOID__VOID,
247 status_icon_signals [POPUP_MENU_SIGNAL] =
248 g_signal_new ("popup-menu",
249 G_TYPE_FROM_CLASS (gobject_class),
250 (GSignalFlags)(G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION),
251 G_STRUCT_OFFSET (EggStatusIconClass, popup_menu),
254 _egg_marshal_VOID__UINT_UINT,
260 status_icon_signals [SIZE_CHANGED_SIGNAL] =
261 g_signal_new ("size-changed",
262 G_TYPE_FROM_CLASS (gobject_class),
264 G_STRUCT_OFFSET (EggStatusIconClass, size_changed),
267 g_cclosure_marshal_VOID__INT,
274 egg_status_icon_init (EggStatusIcon *status_icon)
276 status_icon->priv = g_new0 (EggStatusIconPrivate, 1);
278 status_icon->priv->image_type = GTK_IMAGE_EMPTY;
279 status_icon->priv->size = G_MAXINT;
281 status_icon->priv->tray_icon = GTK_WIDGET (egg_tray_icon_new (NULL));
283 gtk_widget_add_events (GTK_WIDGET (status_icon->priv->tray_icon),
284 GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK);
286 g_signal_connect_swapped (status_icon->priv->tray_icon, "button-release-event",
287 G_CALLBACK (egg_status_icon_button_release), status_icon);
289 status_icon->priv->image = gtk_image_new ();
290 gtk_container_add (GTK_CONTAINER (status_icon->priv->tray_icon),
291 status_icon->priv->image);
293 g_signal_connect_swapped (status_icon->priv->image, "size-allocate",
294 G_CALLBACK (egg_status_icon_size_allocate), status_icon);
296 gtk_widget_show (status_icon->priv->image);
297 gtk_widget_show (status_icon->priv->tray_icon);
299 status_icon->priv->tooltips = gtk_tooltips_new ();
300 g_object_ref (status_icon->priv->tooltips);
301 gtk_object_sink (GTK_OBJECT (status_icon->priv->tooltips));
305 egg_status_icon_finalize (GObject *object)
307 EggStatusIcon *status_icon = EGG_STATUS_ICON (object);
309 egg_status_icon_disable_blinking (status_icon);
311 egg_status_icon_reset_image_data (status_icon);
313 if (status_icon->priv->blank_icon)
314 g_object_unref (status_icon->priv->blank_icon);
315 status_icon->priv->blank_icon = NULL;
317 if (status_icon->priv->tooltips)
318 g_object_unref (status_icon->priv->tooltips);
319 status_icon->priv->tooltips = NULL;
321 gtk_widget_destroy (status_icon->priv->tray_icon);
323 g_free (status_icon->priv);
325 G_OBJECT_CLASS (parent_class)->finalize (object);
329 egg_status_icon_set_property (GObject *object,
334 EggStatusIcon *status_icon = EGG_STATUS_ICON (object);
339 egg_status_icon_set_from_pixbuf (status_icon, (GdkPixbuf*)g_value_get_object (value));
342 egg_status_icon_set_from_file (status_icon, g_value_get_string (value));
345 egg_status_icon_set_from_stock (status_icon, g_value_get_string (value));
347 case PROP_PIXBUF_ANIMATION:
348 egg_status_icon_set_from_animation (status_icon, (GdkPixbufAnimation*)g_value_get_object (value));
351 egg_status_icon_set_is_blinking (status_icon, g_value_get_boolean (value));
354 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
360 egg_status_icon_get_property (GObject *object,
365 EggStatusIcon *status_icon = EGG_STATUS_ICON (object);
370 g_value_set_object (value, egg_status_icon_get_pixbuf (status_icon));
373 g_value_set_string (value, egg_status_icon_get_stock (status_icon));
375 case PROP_PIXBUF_ANIMATION:
376 g_value_set_object (value, egg_status_icon_get_animation (status_icon));
378 case PROP_STORAGE_TYPE:
379 g_value_set_enum (value, egg_status_icon_get_image_type (status_icon));
382 g_value_set_int (value, status_icon->priv->size);
385 g_value_set_boolean (value, status_icon->priv->blinking);
388 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
394 egg_status_icon_new (void)
396 return (EggStatusIcon*)g_object_new (EGG_TYPE_STATUS_ICON, NULL);
400 egg_status_icon_new_from_pixbuf (GdkPixbuf *pixbuf)
402 return (EggStatusIcon*)g_object_new (EGG_TYPE_STATUS_ICON,
408 egg_status_icon_new_from_file (const gchar *filename)
410 return (EggStatusIcon*)g_object_new (EGG_TYPE_STATUS_ICON,
416 egg_status_icon_new_from_stock (const gchar *stock_id)
418 return (EggStatusIcon*)g_object_new (EGG_TYPE_STATUS_ICON,
424 egg_status_icon_new_from_animation (GdkPixbufAnimation *animation)
426 return (EggStatusIcon*)g_object_new (EGG_TYPE_STATUS_ICON,
427 "pixbuf_animation", animation,
432 emit_activate_signal (EggStatusIcon *status_icon)
434 g_signal_emit (status_icon,
435 status_icon_signals [ACTIVATE_SIGNAL], 0);
439 emit_popup_menu_signal (EggStatusIcon *status_icon,
441 guint32 activate_time)
443 g_signal_emit (status_icon,
444 status_icon_signals [POPUP_MENU_SIGNAL], 0,
450 emit_size_changed_signal (EggStatusIcon *status_icon,
453 gboolean handled = FALSE;
455 g_signal_emit (status_icon,
456 status_icon_signals [SIZE_CHANGED_SIGNAL], 0,
464 egg_status_icon_blank_icon (EggStatusIcon *status_icon)
466 if (status_icon->priv->blank_icon)
470 width = gdk_pixbuf_get_width (status_icon->priv->blank_icon);
471 height = gdk_pixbuf_get_width (status_icon->priv->blank_icon);
473 if (width == status_icon->priv->size &&
474 height == status_icon->priv->size)
476 return status_icon->priv->blank_icon;
480 g_object_unref (status_icon->priv->blank_icon);
481 status_icon->priv->blank_icon = NULL;
485 status_icon->priv->blank_icon = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8,
486 status_icon->priv->size,
487 status_icon->priv->size);
488 if (status_icon->priv->blank_icon)
489 gdk_pixbuf_fill (status_icon->priv->blank_icon, 0);
491 return status_icon->priv->blank_icon;
495 egg_status_icon_update_image (EggStatusIcon *status_icon)
497 if (status_icon->priv->blink_off)
499 gtk_image_set_from_pixbuf (GTK_IMAGE (status_icon->priv->image),
500 egg_status_icon_blank_icon (status_icon));
504 switch (status_icon->priv->image_type)
506 case GTK_IMAGE_PIXBUF:
510 pixbuf = status_icon->priv->image_data.pixbuf;
519 size = status_icon->priv->size;
521 width = gdk_pixbuf_get_width (pixbuf);
522 height = gdk_pixbuf_get_height (pixbuf);
524 if (width > size || height > size)
526 scaled = gdk_pixbuf_scale_simple (pixbuf,
529 GDK_INTERP_BILINEAR);
533 scaled = (GdkPixbuf*)g_object_ref (pixbuf);
536 gtk_image_set_from_pixbuf (GTK_IMAGE (status_icon->priv->image), scaled);
538 g_object_unref (scaled);
542 gtk_image_set_from_pixbuf (GTK_IMAGE (status_icon->priv->image), NULL);
546 case GTK_IMAGE_STOCK:
547 case GTK_IMAGE_ANIMATION:
548 case GTK_IMAGE_EMPTY:
549 gtk_image_set_from_pixbuf (GTK_IMAGE (status_icon->priv->image), NULL);
552 g_assert_not_reached ();
558 egg_status_icon_size_allocate (EggStatusIcon *status_icon,
559 GtkAllocation *allocation)
561 GtkOrientation orientation;
564 orientation = egg_tray_icon_get_orientation (EGG_TRAY_ICON (status_icon->priv->tray_icon));
566 if (orientation == GTK_ORIENTATION_HORIZONTAL)
567 size = allocation->height;
569 size = allocation->width;
571 if (status_icon->priv->size != size)
573 status_icon->priv->size = size;
575 g_object_notify (G_OBJECT (status_icon), "size");
577 if (!emit_size_changed_signal (status_icon, size))
579 egg_status_icon_update_image (status_icon);
585 egg_status_icon_button_release (EggStatusIcon *status_icon,
586 GdkEventButton *event)
588 if (event->button == 1)
590 emit_activate_signal (status_icon);
593 if (event->button == 3)
595 emit_popup_menu_signal (status_icon, event->button, event->time);
603 egg_status_icon_reset_image_data (EggStatusIcon *status_icon)
605 switch (status_icon->priv->image_type)
607 case GTK_IMAGE_PIXBUF:
608 status_icon->priv->image_type = GTK_IMAGE_EMPTY;
610 if (status_icon->priv->image_data.pixbuf)
611 g_object_unref (status_icon->priv->image_data.pixbuf);
612 status_icon->priv->image_data.pixbuf = NULL;
614 g_object_notify (G_OBJECT (status_icon), "image-type");
615 g_object_notify (G_OBJECT (status_icon), "pixbuf");
617 case GTK_IMAGE_STOCK:
618 case GTK_IMAGE_ANIMATION:
619 case GTK_IMAGE_EMPTY:
622 g_assert_not_reached ();
628 egg_status_icon_set_from_pixbuf (EggStatusIcon *status_icon,
631 g_return_if_fail (EGG_IS_STATUS_ICON (status_icon));
632 g_return_if_fail (pixbuf == NULL || GDK_IS_PIXBUF (pixbuf));
635 g_object_ref (pixbuf);
637 g_object_freeze_notify (G_OBJECT (status_icon));
639 egg_status_icon_reset_image_data (status_icon);
641 status_icon->priv->image_type = GTK_IMAGE_PIXBUF;
642 status_icon->priv->image_data.pixbuf = pixbuf;
644 g_object_notify (G_OBJECT (status_icon), "image-type");
645 g_object_notify (G_OBJECT (status_icon), "pixbuf");
647 g_object_thaw_notify (G_OBJECT (status_icon));
649 egg_status_icon_update_image (status_icon);
653 egg_status_icon_set_from_file (EggStatusIcon *status_icon,
654 const gchar *filename)
656 g_return_if_fail (EGG_IS_STATUS_ICON (status_icon));
660 egg_status_icon_set_from_stock (EggStatusIcon *status_icon,
661 const gchar *stock_id)
663 g_return_if_fail (EGG_IS_STATUS_ICON (status_icon));
667 egg_status_icon_set_from_animation (EggStatusIcon *status_icon,
668 GdkPixbufAnimation *animation)
670 g_return_if_fail (EGG_IS_STATUS_ICON (status_icon));
671 g_return_if_fail (animation == NULL || GDK_IS_PIXBUF_ANIMATION (animation));
675 egg_status_icon_get_image_type (EggStatusIcon *status_icon)
677 g_return_val_if_fail (EGG_IS_STATUS_ICON (status_icon), GTK_IMAGE_EMPTY);
679 return status_icon->priv->image_type;
683 egg_status_icon_get_pixbuf (EggStatusIcon *status_icon)
685 g_return_val_if_fail (EGG_IS_STATUS_ICON (status_icon), NULL);
686 g_return_val_if_fail (status_icon->priv->image_type == GTK_IMAGE_PIXBUF ||
687 status_icon->priv->image_type == GTK_IMAGE_EMPTY, NULL);
689 if (status_icon->priv->image_type == GTK_IMAGE_EMPTY)
690 status_icon->priv->image_data.pixbuf = NULL;
692 return status_icon->priv->image_data.pixbuf;
695 G_CONST_RETURN gchar *
696 egg_status_icon_get_stock (EggStatusIcon *status_icon)
698 g_return_val_if_fail (EGG_IS_STATUS_ICON (status_icon), NULL);
704 egg_status_icon_get_animation (EggStatusIcon *status_icon)
706 g_return_val_if_fail (EGG_IS_STATUS_ICON (status_icon), NULL);
712 egg_status_icon_get_size (EggStatusIcon *status_icon)
714 g_return_val_if_fail (EGG_IS_STATUS_ICON (status_icon), -1);
716 return status_icon->priv->size;
720 egg_status_icon_set_tooltip (EggStatusIcon *status_icon,
721 const gchar *tooltip_text,
722 const gchar *tooltip_private)
724 g_return_if_fail (EGG_IS_STATUS_ICON (status_icon));
726 gtk_tooltips_set_tip (status_icon->priv->tooltips,
727 status_icon->priv->tray_icon,
733 egg_status_icon_set_balloon_text (EggStatusIcon *status_icon,
736 g_return_if_fail (EGG_IS_STATUS_ICON (status_icon));
739 G_CONST_RETURN gchar *
740 egg_status_icon_get_balloon_text (EggStatusIcon *status_icon)
742 g_return_val_if_fail (EGG_IS_STATUS_ICON (status_icon), NULL);
748 egg_status_icon_blinker (EggStatusIcon *status_icon)
750 status_icon->priv->blink_off = !status_icon->priv->blink_off;
752 egg_status_icon_update_image (status_icon);
758 egg_status_icon_enable_blinking (EggStatusIcon *status_icon)
760 if (!status_icon->priv->blinking_timeout)
762 egg_status_icon_blinker (status_icon);
764 status_icon->priv->blinking_timeout =
765 g_timeout_add (500, (GSourceFunc) egg_status_icon_blinker, status_icon);
770 egg_status_icon_disable_blinking (EggStatusIcon *status_icon)
772 if (status_icon->priv->blinking_timeout)
774 g_source_remove (status_icon->priv->blinking_timeout);
775 status_icon->priv->blinking_timeout = 0;
776 status_icon->priv->blink_off = FALSE;
778 egg_status_icon_update_image (status_icon);
783 egg_status_icon_set_is_blinking (EggStatusIcon *status_icon,
786 g_return_if_fail (EGG_IS_STATUS_ICON (status_icon));
788 is_blinking = is_blinking != FALSE;
790 if (status_icon->priv->blinking != is_blinking)
792 status_icon->priv->blinking = is_blinking;
795 egg_status_icon_enable_blinking (status_icon);
797 egg_status_icon_disable_blinking (status_icon);
799 g_object_notify (G_OBJECT (status_icon), "blinking");
804 egg_status_icon_get_is_blinking (EggStatusIcon *status_icon)
806 g_return_val_if_fail (EGG_IS_STATUS_ICON (status_icon), FALSE);
808 return status_icon->priv->blinking;
812 egg_status_icon_get_tray_icon (EggStatusIcon *status_icon)
814 g_return_val_if_fail (EGG_IS_STATUS_ICON (status_icon), NULL);
816 return EGG_TRAY_ICON(status_icon->priv->tray_icon);