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)
30 #include "eggstatusicon.h"
33 #include "eggmarshalers.h"
35 #ifndef EGG_COMPILATION
37 #define _(x) dgettext (GETTEXT_PACKAGE, x)
50 PROP_PIXBUF_ANIMATION,
63 struct _EggStatusIconPrivate
69 GtkTooltips *tooltips;
71 GtkImageType image_type;
76 const gchar *stock_id;
77 GdkPixbufAnimation *animimation;
80 GdkPixbuf *blank_icon;
81 guint blinking_timeout;
87 static void egg_status_icon_class_init (EggStatusIconClass *klass);
88 static void egg_status_icon_init (EggStatusIcon *status_icon);
90 static void egg_status_icon_finalize (GObject *object);
91 static void egg_status_icon_set_property (GObject *object,
95 static void egg_status_icon_get_property (GObject *object,
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);
108 static GObjectClass *parent_class = NULL;
109 static guint status_icon_signals [LAST_SIGNAL] = { 0 };
112 egg_status_icon_get_type (void)
114 static GType status_icon_type = 0;
116 if (!status_icon_type)
118 static const GTypeInfo status_icon_info =
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),
128 (GInstanceInitFunc) egg_status_icon_init,
131 status_icon_type = g_type_register_static (G_TYPE_OBJECT,
133 &status_icon_info, (GTypeFlags)0);
136 return status_icon_type;
140 egg_status_icon_class_init (EggStatusIconClass *klass)
142 GObjectClass *gobject_class = (GObjectClass *) klass;
144 parent_class = (GObjectClass*)g_type_class_peek_parent (klass);
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;
150 g_object_class_install_property (gobject_class,
152 g_param_spec_object ("pixbuf",
154 "A GdkPixbuf to display",
156 (GParamFlags)G_PARAM_READWRITE));
158 g_object_class_install_property (gobject_class,
160 g_param_spec_string ("file",
162 "Filename to load and display",
166 g_object_class_install_property (gobject_class,
168 g_param_spec_string ("stock",
170 "Stock ID for a stock image to display",
172 (GParamFlags)G_PARAM_READWRITE));
174 g_object_class_install_property (gobject_class,
175 PROP_PIXBUF_ANIMATION,
176 g_param_spec_object ("pixbuf-animation",
178 "GdkPixbufAnimation to display",
179 GDK_TYPE_PIXBUF_ANIMATION,
180 (GParamFlags)G_PARAM_READWRITE));
182 g_object_class_install_property (gobject_class,
184 g_param_spec_enum ("image-type",
186 "The representation being used for image data",
191 g_object_class_install_property (gobject_class,
193 g_param_spec_int ("size",
195 "The size of the icon",
201 g_object_class_install_property (gobject_class,
203 g_param_spec_boolean ("blinking",
205 "Whether or not the status icon is blinking",
207 (GParamFlags)G_PARAM_READWRITE));
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),
216 g_cclosure_marshal_VOID__VOID,
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),
227 _egg_marshal_VOID__UINT_UINT,
233 status_icon_signals [SIZE_CHANGED_SIGNAL] =
234 g_signal_new ("size-changed",
235 G_TYPE_FROM_CLASS (gobject_class),
237 G_STRUCT_OFFSET (EggStatusIconClass, size_changed),
240 g_cclosure_marshal_VOID__INT,
247 egg_status_icon_init (EggStatusIcon *status_icon)
249 status_icon->priv = g_new0 (EggStatusIconPrivate, 1);
251 status_icon->priv->image_type = GTK_IMAGE_EMPTY;
252 status_icon->priv->size = G_MAXINT;
254 status_icon->priv->tray_icon = GTK_WIDGET (egg_tray_icon_new (NULL));
256 gtk_widget_add_events (GTK_WIDGET (status_icon->priv->tray_icon),
257 GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK);
259 g_signal_connect_swapped (status_icon->priv->tray_icon, "button-release-event",
260 G_CALLBACK (egg_status_icon_button_release), status_icon);
262 status_icon->priv->image = gtk_image_new ();
263 gtk_container_add (GTK_CONTAINER (status_icon->priv->tray_icon),
264 status_icon->priv->image);
266 g_signal_connect_swapped (status_icon->priv->image, "size-allocate",
267 G_CALLBACK (egg_status_icon_size_allocate), status_icon);
269 gtk_widget_show (status_icon->priv->image);
270 gtk_widget_show (status_icon->priv->tray_icon);
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));
278 egg_status_icon_finalize (GObject *object)
280 EggStatusIcon *status_icon = EGG_STATUS_ICON (object);
282 egg_status_icon_disable_blinking (status_icon);
284 egg_status_icon_reset_image_data (status_icon);
286 if (status_icon->priv->blank_icon)
287 g_object_unref (status_icon->priv->blank_icon);
288 status_icon->priv->blank_icon = NULL;
290 if (status_icon->priv->tooltips)
291 g_object_unref (status_icon->priv->tooltips);
292 status_icon->priv->tooltips = NULL;
294 gtk_widget_destroy (status_icon->priv->tray_icon);
296 g_free (status_icon->priv);
298 G_OBJECT_CLASS (parent_class)->finalize (object);
302 egg_status_icon_set_property (GObject *object,
307 EggStatusIcon *status_icon = EGG_STATUS_ICON (object);
312 egg_status_icon_set_from_pixbuf (status_icon, (GdkPixbuf*)g_value_get_object (value));
315 egg_status_icon_set_from_file (status_icon, g_value_get_string (value));
318 egg_status_icon_set_from_stock (status_icon, g_value_get_string (value));
320 case PROP_PIXBUF_ANIMATION:
321 egg_status_icon_set_from_animation (status_icon, (GdkPixbufAnimation*)g_value_get_object (value));
324 egg_status_icon_set_is_blinking (status_icon, g_value_get_boolean (value));
327 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
333 egg_status_icon_get_property (GObject *object,
338 EggStatusIcon *status_icon = EGG_STATUS_ICON (object);
343 g_value_set_object (value, egg_status_icon_get_pixbuf (status_icon));
346 g_value_set_string (value, egg_status_icon_get_stock (status_icon));
348 case PROP_PIXBUF_ANIMATION:
349 g_value_set_object (value, egg_status_icon_get_animation (status_icon));
351 case PROP_STORAGE_TYPE:
352 g_value_set_enum (value, egg_status_icon_get_image_type (status_icon));
355 g_value_set_int (value, status_icon->priv->size);
358 g_value_set_boolean (value, status_icon->priv->blinking);
361 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
367 egg_status_icon_new (void)
369 return (EggStatusIcon*)g_object_new (EGG_TYPE_STATUS_ICON, NULL);
373 egg_status_icon_new_from_pixbuf (GdkPixbuf *pixbuf)
375 return (EggStatusIcon*)g_object_new (EGG_TYPE_STATUS_ICON,
381 egg_status_icon_new_from_file (const gchar *filename)
383 return (EggStatusIcon*)g_object_new (EGG_TYPE_STATUS_ICON,
389 egg_status_icon_new_from_stock (const gchar *stock_id)
391 return (EggStatusIcon*)g_object_new (EGG_TYPE_STATUS_ICON,
397 egg_status_icon_new_from_animation (GdkPixbufAnimation *animation)
399 return (EggStatusIcon*)g_object_new (EGG_TYPE_STATUS_ICON,
400 "pixbuf_animation", animation,
405 emit_activate_signal (EggStatusIcon *status_icon)
407 g_signal_emit (status_icon,
408 status_icon_signals [ACTIVATE_SIGNAL], 0);
412 emit_popup_menu_signal (EggStatusIcon *status_icon,
414 guint32 activate_time)
416 g_signal_emit (status_icon,
417 status_icon_signals [POPUP_MENU_SIGNAL], 0,
423 emit_size_changed_signal (EggStatusIcon *status_icon,
426 gboolean handled = FALSE;
428 g_signal_emit (status_icon,
429 status_icon_signals [SIZE_CHANGED_SIGNAL], 0,
437 egg_status_icon_blank_icon (EggStatusIcon *status_icon)
439 if (status_icon->priv->blank_icon)
443 width = gdk_pixbuf_get_width (status_icon->priv->blank_icon);
444 height = gdk_pixbuf_get_width (status_icon->priv->blank_icon);
446 if (width == status_icon->priv->size &&
447 height == status_icon->priv->size)
449 return status_icon->priv->blank_icon;
453 g_object_unref (status_icon->priv->blank_icon);
454 status_icon->priv->blank_icon = NULL;
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);
464 return status_icon->priv->blank_icon;
468 egg_status_icon_update_image (EggStatusIcon *status_icon)
470 if (status_icon->priv->blink_off)
472 gtk_image_set_from_pixbuf (GTK_IMAGE (status_icon->priv->image),
473 egg_status_icon_blank_icon (status_icon));
477 switch (status_icon->priv->image_type)
479 case GTK_IMAGE_PIXBUF:
483 pixbuf = status_icon->priv->image_data.pixbuf;
492 size = status_icon->priv->size;
494 width = gdk_pixbuf_get_width (pixbuf);
495 height = gdk_pixbuf_get_height (pixbuf);
497 if (width > size || height > size)
499 scaled = gdk_pixbuf_scale_simple (pixbuf,
502 GDK_INTERP_BILINEAR);
506 scaled = (GdkPixbuf*)g_object_ref (pixbuf);
509 gtk_image_set_from_pixbuf (GTK_IMAGE (status_icon->priv->image), scaled);
511 g_object_unref (scaled);
515 gtk_image_set_from_pixbuf (GTK_IMAGE (status_icon->priv->image), NULL);
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);
525 g_assert_not_reached ();
531 egg_status_icon_size_allocate (EggStatusIcon *status_icon,
532 GtkAllocation *allocation)
534 GtkOrientation orientation;
537 orientation = egg_tray_icon_get_orientation (EGG_TRAY_ICON (status_icon->priv->tray_icon));
539 if (orientation == GTK_ORIENTATION_HORIZONTAL)
540 size = allocation->height;
542 size = allocation->width;
544 if (status_icon->priv->size != size)
546 status_icon->priv->size = size;
548 g_object_notify (G_OBJECT (status_icon), "size");
550 if (!emit_size_changed_signal (status_icon, size))
552 egg_status_icon_update_image (status_icon);
558 egg_status_icon_button_release (EggStatusIcon *status_icon,
559 GdkEventButton *event)
561 if (event->button == 1)
563 emit_activate_signal (status_icon);
566 if (event->button == 3)
568 emit_popup_menu_signal (status_icon, event->button, event->time);
576 egg_status_icon_reset_image_data (EggStatusIcon *status_icon)
578 switch (status_icon->priv->image_type)
580 case GTK_IMAGE_PIXBUF:
581 status_icon->priv->image_type = GTK_IMAGE_EMPTY;
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;
587 g_object_notify (G_OBJECT (status_icon), "image-type");
588 g_object_notify (G_OBJECT (status_icon), "pixbuf");
590 case GTK_IMAGE_STOCK:
591 case GTK_IMAGE_ANIMATION:
592 case GTK_IMAGE_EMPTY:
595 g_assert_not_reached ();
601 egg_status_icon_set_from_pixbuf (EggStatusIcon *status_icon,
604 g_return_if_fail (EGG_IS_STATUS_ICON (status_icon));
605 g_return_if_fail (pixbuf == NULL || GDK_IS_PIXBUF (pixbuf));
608 g_object_ref (pixbuf);
610 g_object_freeze_notify (G_OBJECT (status_icon));
612 egg_status_icon_reset_image_data (status_icon);
614 status_icon->priv->image_type = GTK_IMAGE_PIXBUF;
615 status_icon->priv->image_data.pixbuf = pixbuf;
617 g_object_notify (G_OBJECT (status_icon), "image-type");
618 g_object_notify (G_OBJECT (status_icon), "pixbuf");
620 g_object_thaw_notify (G_OBJECT (status_icon));
622 egg_status_icon_update_image (status_icon);
626 egg_status_icon_set_from_file (EggStatusIcon *status_icon,
627 const gchar *filename)
629 g_return_if_fail (EGG_IS_STATUS_ICON (status_icon));
633 egg_status_icon_set_from_stock (EggStatusIcon *status_icon,
634 const gchar *stock_id)
636 g_return_if_fail (EGG_IS_STATUS_ICON (status_icon));
640 egg_status_icon_set_from_animation (EggStatusIcon *status_icon,
641 GdkPixbufAnimation *animation)
643 g_return_if_fail (EGG_IS_STATUS_ICON (status_icon));
644 g_return_if_fail (animation == NULL || GDK_IS_PIXBUF_ANIMATION (animation));
648 egg_status_icon_get_image_type (EggStatusIcon *status_icon)
650 g_return_val_if_fail (EGG_IS_STATUS_ICON (status_icon), GTK_IMAGE_EMPTY);
652 return status_icon->priv->image_type;
656 egg_status_icon_get_pixbuf (EggStatusIcon *status_icon)
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);
662 if (status_icon->priv->image_type == GTK_IMAGE_EMPTY)
663 status_icon->priv->image_data.pixbuf = NULL;
665 return status_icon->priv->image_data.pixbuf;
668 G_CONST_RETURN gchar *
669 egg_status_icon_get_stock (EggStatusIcon *status_icon)
671 g_return_val_if_fail (EGG_IS_STATUS_ICON (status_icon), NULL);
677 egg_status_icon_get_animation (EggStatusIcon *status_icon)
679 g_return_val_if_fail (EGG_IS_STATUS_ICON (status_icon), NULL);
685 egg_status_icon_get_size (EggStatusIcon *status_icon)
687 g_return_val_if_fail (EGG_IS_STATUS_ICON (status_icon), -1);
689 return status_icon->priv->size;
693 egg_status_icon_set_tooltip (EggStatusIcon *status_icon,
694 const gchar *tooltip_text,
695 const gchar *tooltip_private)
697 g_return_if_fail (EGG_IS_STATUS_ICON (status_icon));
699 gtk_tooltips_set_tip (status_icon->priv->tooltips,
700 status_icon->priv->tray_icon,
706 egg_status_icon_set_balloon_text (EggStatusIcon *status_icon,
709 g_return_if_fail (EGG_IS_STATUS_ICON (status_icon));
712 G_CONST_RETURN gchar *
713 egg_status_icon_get_balloon_text (EggStatusIcon *status_icon)
715 g_return_val_if_fail (EGG_IS_STATUS_ICON (status_icon), NULL);
721 egg_status_icon_blinker (EggStatusIcon *status_icon)
723 status_icon->priv->blink_off = !status_icon->priv->blink_off;
725 egg_status_icon_update_image (status_icon);
731 egg_status_icon_enable_blinking (EggStatusIcon *status_icon)
733 if (!status_icon->priv->blinking_timeout)
735 egg_status_icon_blinker (status_icon);
737 status_icon->priv->blinking_timeout =
738 g_timeout_add (500, (GSourceFunc) egg_status_icon_blinker, status_icon);
743 egg_status_icon_disable_blinking (EggStatusIcon *status_icon)
745 if (status_icon->priv->blinking_timeout)
747 g_source_remove (status_icon->priv->blinking_timeout);
748 status_icon->priv->blinking_timeout = 0;
749 status_icon->priv->blink_off = FALSE;
751 egg_status_icon_update_image (status_icon);
756 egg_status_icon_set_is_blinking (EggStatusIcon *status_icon,
759 g_return_if_fail (EGG_IS_STATUS_ICON (status_icon));
761 is_blinking = is_blinking != FALSE;
763 if (status_icon->priv->blinking != is_blinking)
765 status_icon->priv->blinking = is_blinking;
768 egg_status_icon_enable_blinking (status_icon);
770 egg_status_icon_disable_blinking (status_icon);
772 g_object_notify (G_OBJECT (status_icon), "blinking");
777 egg_status_icon_get_is_blinking (EggStatusIcon *status_icon)
779 g_return_val_if_fail (EGG_IS_STATUS_ICON (status_icon), FALSE);
781 return status_icon->priv->blinking;
785 egg_status_icon_get_tray_icon (EggStatusIcon *status_icon)
787 g_return_val_if_fail (EGG_IS_STATUS_ICON (status_icon), NULL);
789 return EGG_TRAY_ICON(status_icon->priv->tray_icon);