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>
28
#include "eggstatusicon.h"
31
#include "eggmarshalers.h"
33
#ifndef EGG_COMPILATION
35
#define _(x) dgettext (GETTEXT_PACKAGE, x)
48
PROP_PIXBUF_ANIMATION,
61
struct _EggStatusIconPrivate
67
GtkTooltips *tooltips;
69
GtkImageType image_type;
74
const gchar *stock_id;
75
GdkPixbufAnimation *animimation;
78
GdkPixbuf *blank_icon;
79
guint blinking_timeout;
85
static void egg_status_icon_class_init (EggStatusIconClass *klass);
86
static void egg_status_icon_init (EggStatusIcon *status_icon);
88
static void egg_status_icon_finalize (GObject *object);
89
static void egg_status_icon_set_property (GObject *object,
93
static void egg_status_icon_get_property (GObject *object,
98
static void egg_status_icon_size_allocate (EggStatusIcon *status_icon,
99
GtkAllocation *allocation);
100
static gboolean egg_status_icon_button_press (EggStatusIcon *status_icon,
101
GdkEventButton *event);
102
static void egg_status_icon_disable_blinking (EggStatusIcon *status_icon);
103
static void egg_status_icon_reset_image_data (EggStatusIcon *status_icon);
106
static GObjectClass *parent_class = NULL;
107
static guint status_icon_signals [LAST_SIGNAL] = { 0 };
110
egg_status_icon_get_type (void)
112
static GType status_icon_type = 0;
114
if (!status_icon_type)
116
static const GTypeInfo status_icon_info =
118
sizeof (EggStatusIconClass),
119
NULL, /* base_init */
120
NULL, /* base_finalize */
121
(GClassInitFunc) egg_status_icon_class_init,
122
NULL, /* class_finalize */
123
NULL, /* class_data */
124
sizeof (EggStatusIcon),
126
(GInstanceInitFunc) egg_status_icon_init,
129
status_icon_type = g_type_register_static (G_TYPE_OBJECT,
131
&status_icon_info, 0);
134
return status_icon_type;
138
egg_status_icon_class_init (EggStatusIconClass *klass)
140
GObjectClass *gobject_class = (GObjectClass *) klass;
142
parent_class = g_type_class_peek_parent (klass);
144
gobject_class->finalize = egg_status_icon_finalize;
145
gobject_class->set_property = egg_status_icon_set_property;
146
gobject_class->get_property = egg_status_icon_get_property;
148
g_object_class_install_property (gobject_class,
150
g_param_spec_object ("pixbuf",
152
_("A GdkPixbuf to display"),
156
g_object_class_install_property (gobject_class,
158
g_param_spec_string ("file",
160
_("Filename to load and display"),
164
g_object_class_install_property (gobject_class,
166
g_param_spec_string ("stock",
168
_("Stock ID for a stock image to display"),
172
g_object_class_install_property (gobject_class,
173
PROP_PIXBUF_ANIMATION,
174
g_param_spec_object ("pixbuf-animation",
176
_("GdkPixbufAnimation to display"),
177
GDK_TYPE_PIXBUF_ANIMATION,
180
g_object_class_install_property (gobject_class,
182
g_param_spec_enum ("image-type",
184
_("The representation being used for image data"),
189
g_object_class_install_property (gobject_class,
191
g_param_spec_int ("size",
193
_("The size of the icon"),
199
g_object_class_install_property (gobject_class,
201
g_param_spec_boolean ("blinking",
203
_("Whether or not the status icon is blinking"),
207
status_icon_signals [ACTIVATE_SIGNAL] =
208
g_signal_new ("activate",
209
G_TYPE_FROM_CLASS (gobject_class),
210
G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
211
G_STRUCT_OFFSET (EggStatusIconClass, activate),
214
g_cclosure_marshal_VOID__VOID,
218
status_icon_signals [POPUP_MENU_SIGNAL] =
219
g_signal_new ("popup-menu",
220
G_TYPE_FROM_CLASS (gobject_class),
221
G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
222
G_STRUCT_OFFSET (EggStatusIconClass, popup_menu),
225
eggmarshalers_VOID__UINT_UINT,
231
status_icon_signals [SIZE_CHANGED_SIGNAL] =
232
g_signal_new ("size-changed",
233
G_TYPE_FROM_CLASS (gobject_class),
235
G_STRUCT_OFFSET (EggStatusIconClass, size_changed),
238
g_cclosure_marshal_VOID__INT,
245
egg_status_icon_is_visible (EggStatusIcon *icon)
247
return(icon->priv->tray_icon && EGG_TRAY_ICON (icon->priv->tray_icon)->manager_window != None);
250
static void egg_status_icon_destroyed (EggStatusIcon *icon);
252
egg_status_icon_allocate (EggStatusIcon *status_icon)
254
status_icon->priv->image_type = GTK_IMAGE_EMPTY;
255
status_icon->priv->size = G_MAXINT;
257
status_icon->priv->tray_icon = GTK_WIDGET (egg_tray_icon_new (NULL));
259
gtk_widget_add_events (GTK_WIDGET (status_icon->priv->tray_icon),
260
GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK);
262
g_signal_connect_swapped (status_icon->priv->tray_icon, "button-press-event",
263
G_CALLBACK (egg_status_icon_button_press), status_icon);
265
status_icon->priv->image = gtk_image_new ();
266
gtk_container_add (GTK_CONTAINER (status_icon->priv->tray_icon),
267
status_icon->priv->image);
269
g_signal_connect_swapped (status_icon->priv->image, "size-allocate",
270
G_CALLBACK (egg_status_icon_size_allocate), status_icon);
272
g_signal_connect_swapped (status_icon->priv->image, "destroy",
273
G_CALLBACK (egg_status_icon_destroyed), status_icon);
275
gtk_widget_show (status_icon->priv->image);
276
gtk_widget_show (status_icon->priv->tray_icon);
278
status_icon->priv->tooltips = gtk_tooltips_new ();
279
g_object_ref (status_icon->priv->tooltips);
280
gtk_object_sink (GTK_OBJECT (status_icon->priv->tooltips));
284
egg_status_icon_create_idle (EggStatusIcon *icon)
286
egg_status_icon_allocate (icon);
291
egg_status_icon_destroyed (EggStatusIcon *icon)
293
g_idle_add ((GSourceFunc) egg_status_icon_create_idle, icon);
297
egg_status_icon_init (EggStatusIcon *status_icon)
299
status_icon->priv = g_new0 (EggStatusIconPrivate, 1);
300
egg_status_icon_allocate (status_icon);
304
egg_status_icon_finalize (GObject *object)
306
EggStatusIcon *status_icon = EGG_STATUS_ICON (object);
308
egg_status_icon_disable_blinking (status_icon);
310
egg_status_icon_reset_image_data (status_icon);
312
if (status_icon->priv->blank_icon)
313
g_object_unref (status_icon->priv->blank_icon);
314
status_icon->priv->blank_icon = NULL;
316
if (status_icon->priv->tooltips)
317
g_object_unref (status_icon->priv->tooltips);
318
status_icon->priv->tooltips = NULL;
320
gtk_widget_destroy (status_icon->priv->tray_icon);
322
g_free (status_icon->priv);
324
G_OBJECT_CLASS (parent_class)->finalize (object);
328
egg_status_icon_set_property (GObject *object,
333
EggStatusIcon *status_icon = EGG_STATUS_ICON (object);
338
egg_status_icon_set_from_pixbuf (status_icon, g_value_get_object (value));
341
egg_status_icon_set_from_file (status_icon, g_value_get_string (value));
344
egg_status_icon_set_from_stock (status_icon, g_value_get_string (value));
346
case PROP_PIXBUF_ANIMATION:
347
egg_status_icon_set_from_animation (status_icon, g_value_get_object (value));
350
egg_status_icon_set_is_blinking (status_icon, g_value_get_boolean (value));
353
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
359
egg_status_icon_get_property (GObject *object,
364
EggStatusIcon *status_icon = EGG_STATUS_ICON (object);
369
g_value_set_object (value, egg_status_icon_get_pixbuf (status_icon));
372
g_value_set_string (value, egg_status_icon_get_stock (status_icon));
374
case PROP_PIXBUF_ANIMATION:
375
g_value_set_object (value, egg_status_icon_get_animation (status_icon));
377
case PROP_STORAGE_TYPE:
378
g_value_set_enum (value, egg_status_icon_get_image_type (status_icon));
381
g_value_set_int (value, status_icon->priv->size);
384
g_value_set_boolean (value, status_icon->priv->blinking);
387
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
393
egg_status_icon_new (void)
395
return g_object_new (EGG_TYPE_STATUS_ICON, NULL);
399
egg_status_icon_new_from_pixbuf (GdkPixbuf *pixbuf)
401
return g_object_new (EGG_TYPE_STATUS_ICON,
407
egg_status_icon_new_from_file (const gchar *filename)
409
return g_object_new (EGG_TYPE_STATUS_ICON,
415
egg_status_icon_new_from_stock (const gchar *stock_id)
417
return g_object_new (EGG_TYPE_STATUS_ICON,
423
egg_status_icon_new_from_animation (GdkPixbufAnimation *animation)
425
return g_object_new (EGG_TYPE_STATUS_ICON,
426
"pixbuf_animation", animation,
431
emit_activate_signal (EggStatusIcon *status_icon)
433
g_signal_emit (status_icon,
434
status_icon_signals [ACTIVATE_SIGNAL], 0);
438
emit_popup_menu_signal (EggStatusIcon *status_icon,
440
guint32 activate_time)
442
g_signal_emit (status_icon,
443
status_icon_signals [POPUP_MENU_SIGNAL], 0,
449
emit_size_changed_signal (EggStatusIcon *status_icon,
452
gboolean handled = FALSE;
454
g_signal_emit (status_icon,
455
status_icon_signals [SIZE_CHANGED_SIGNAL], 0,
463
egg_status_icon_blank_icon (EggStatusIcon *status_icon)
465
if (status_icon->priv->blank_icon)
469
width = gdk_pixbuf_get_width (status_icon->priv->blank_icon);
470
height = gdk_pixbuf_get_width (status_icon->priv->blank_icon);
472
if (width == status_icon->priv->size &&
473
height == status_icon->priv->size)
475
return status_icon->priv->blank_icon;
479
g_object_unref (status_icon->priv->blank_icon);
480
status_icon->priv->blank_icon = NULL;
484
status_icon->priv->blank_icon = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8,
485
status_icon->priv->size,
486
status_icon->priv->size);
487
if (status_icon->priv->blank_icon)
488
gdk_pixbuf_fill (status_icon->priv->blank_icon, 0);
490
return status_icon->priv->blank_icon;
494
egg_status_icon_update_image (EggStatusIcon *status_icon)
496
if (status_icon->priv->blink_off)
498
gtk_image_set_from_pixbuf (GTK_IMAGE (status_icon->priv->image),
499
egg_status_icon_blank_icon (status_icon));
503
switch (status_icon->priv->image_type)
505
case GTK_IMAGE_PIXBUF:
509
pixbuf = status_icon->priv->image_data.pixbuf;
518
size = status_icon->priv->size;
520
width = gdk_pixbuf_get_width (pixbuf);
521
height = gdk_pixbuf_get_height (pixbuf);
523
if (width > size || height > size)
525
scaled = gdk_pixbuf_scale_simple (pixbuf,
528
GDK_INTERP_BILINEAR);
532
scaled = g_object_ref (pixbuf);
535
gtk_image_set_from_pixbuf (GTK_IMAGE (status_icon->priv->image), scaled);
537
g_object_unref (scaled);
541
gtk_image_set_from_pixbuf (GTK_IMAGE (status_icon->priv->image), NULL);
545
case GTK_IMAGE_STOCK:
546
case GTK_IMAGE_ANIMATION:
547
case GTK_IMAGE_EMPTY:
548
gtk_image_set_from_pixbuf (GTK_IMAGE (status_icon->priv->image), NULL);
551
g_assert_not_reached ();
557
egg_status_icon_size_allocate (EggStatusIcon *status_icon,
558
GtkAllocation *allocation)
560
GtkOrientation orientation;
563
orientation = egg_tray_icon_get_orientation (EGG_TRAY_ICON (status_icon->priv->tray_icon));
565
if (orientation == GTK_ORIENTATION_HORIZONTAL)
566
size = allocation->height;
568
size = allocation->width;
570
if (status_icon->priv->size != size)
572
status_icon->priv->size = size;
574
g_object_notify (G_OBJECT (status_icon), "size");
576
if (!emit_size_changed_signal (status_icon, size))
578
egg_status_icon_update_image (status_icon);
584
egg_status_icon_button_press (EggStatusIcon *status_icon,
585
GdkEventButton *event)
587
if (event->button == 1 && event->type == GDK_2BUTTON_PRESS)
589
emit_activate_signal (status_icon);
592
else if (event->button == 3 && event->type == GDK_BUTTON_PRESS)
594
emit_popup_menu_signal (status_icon, event->button, event->time);
602
egg_status_icon_reset_image_data (EggStatusIcon *status_icon)
604
switch (status_icon->priv->image_type)
606
case GTK_IMAGE_PIXBUF:
607
status_icon->priv->image_type = GTK_IMAGE_EMPTY;
609
if (status_icon->priv->image_data.pixbuf)
610
g_object_unref (status_icon->priv->image_data.pixbuf);
611
status_icon->priv->image_data.pixbuf = NULL;
613
g_object_notify (G_OBJECT (status_icon), "image-type");
614
g_object_notify (G_OBJECT (status_icon), "pixbuf");
616
case GTK_IMAGE_STOCK:
617
case GTK_IMAGE_ANIMATION:
618
case GTK_IMAGE_EMPTY:
621
g_assert_not_reached ();
627
egg_status_icon_set_from_pixbuf (EggStatusIcon *status_icon,
630
g_return_if_fail (EGG_IS_STATUS_ICON (status_icon));
631
g_return_if_fail (pixbuf == NULL || GDK_IS_PIXBUF (pixbuf));
634
g_object_ref (pixbuf);
636
g_object_freeze_notify (G_OBJECT (status_icon));
638
egg_status_icon_reset_image_data (status_icon);
640
status_icon->priv->image_type = GTK_IMAGE_PIXBUF;
641
status_icon->priv->image_data.pixbuf = pixbuf;
643
g_object_notify (G_OBJECT (status_icon), "image-type");
644
g_object_notify (G_OBJECT (status_icon), "pixbuf");
646
g_object_thaw_notify (G_OBJECT (status_icon));
648
egg_status_icon_update_image (status_icon);
652
egg_status_icon_set_from_file (EggStatusIcon *status_icon,
653
const gchar *filename)
655
g_return_if_fail (EGG_IS_STATUS_ICON (status_icon));
659
egg_status_icon_set_from_stock (EggStatusIcon *status_icon,
660
const gchar *stock_id)
662
g_return_if_fail (EGG_IS_STATUS_ICON (status_icon));
666
egg_status_icon_set_from_animation (EggStatusIcon *status_icon,
667
GdkPixbufAnimation *animation)
669
g_return_if_fail (EGG_IS_STATUS_ICON (status_icon));
670
g_return_if_fail (animation == NULL || GDK_IS_PIXBUF_ANIMATION (animation));
674
egg_status_icon_get_image_type (EggStatusIcon *status_icon)
676
g_return_val_if_fail (EGG_IS_STATUS_ICON (status_icon), GTK_IMAGE_EMPTY);
678
return status_icon->priv->image_type;
682
egg_status_icon_get_pixbuf (EggStatusIcon *status_icon)
684
g_return_val_if_fail (EGG_IS_STATUS_ICON (status_icon), NULL);
685
g_return_val_if_fail (status_icon->priv->image_type == GTK_IMAGE_PIXBUF ||
686
status_icon->priv->image_type == GTK_IMAGE_EMPTY, NULL);
688
if (status_icon->priv->image_type == GTK_IMAGE_EMPTY)
689
status_icon->priv->image_data.pixbuf = NULL;
691
return status_icon->priv->image_data.pixbuf;
694
G_CONST_RETURN gchar *
695
egg_status_icon_get_stock (EggStatusIcon *status_icon)
697
g_return_val_if_fail (EGG_IS_STATUS_ICON (status_icon), NULL);
703
egg_status_icon_get_animation (EggStatusIcon *status_icon)
705
g_return_val_if_fail (EGG_IS_STATUS_ICON (status_icon), NULL);
711
egg_status_icon_get_size (EggStatusIcon *status_icon)
713
g_return_val_if_fail (EGG_IS_STATUS_ICON (status_icon), -1);
715
return status_icon->priv->size;
719
egg_status_icon_set_tooltip (EggStatusIcon *status_icon,
720
const gchar *tooltip_text,
721
const gchar *tooltip_private)
723
g_return_if_fail (EGG_IS_STATUS_ICON (status_icon));
725
gtk_tooltips_set_tip (status_icon->priv->tooltips,
726
status_icon->priv->tray_icon,
732
egg_status_icon_set_balloon_text (EggStatusIcon *status_icon,
735
g_return_if_fail (EGG_IS_STATUS_ICON (status_icon));
738
G_CONST_RETURN gchar *
739
egg_status_icon_get_balloon_text (EggStatusIcon *status_icon)
741
g_return_val_if_fail (EGG_IS_STATUS_ICON (status_icon), NULL);
747
egg_status_icon_blinker (EggStatusIcon *status_icon)
749
status_icon->priv->blink_off = !status_icon->priv->blink_off;
751
egg_status_icon_update_image (status_icon);
757
egg_status_icon_enable_blinking (EggStatusIcon *status_icon)
759
if (!status_icon->priv->blinking_timeout)
761
egg_status_icon_blinker (status_icon);
763
status_icon->priv->blinking_timeout =
764
g_timeout_add (500, (GSourceFunc) egg_status_icon_blinker, status_icon);
769
egg_status_icon_disable_blinking (EggStatusIcon *status_icon)
771
if (status_icon->priv->blinking_timeout)
773
g_source_remove (status_icon->priv->blinking_timeout);
774
status_icon->priv->blinking_timeout = 0;
775
status_icon->priv->blink_off = FALSE;
777
egg_status_icon_update_image (status_icon);
782
egg_status_icon_set_is_blinking (EggStatusIcon *status_icon,
783
gboolean is_blinking)
785
g_return_if_fail (EGG_IS_STATUS_ICON (status_icon));
787
is_blinking = is_blinking != FALSE;
789
if (status_icon->priv->blinking != is_blinking)
791
status_icon->priv->blinking = is_blinking;
794
egg_status_icon_enable_blinking (status_icon);
796
egg_status_icon_disable_blinking (status_icon);
798
g_object_notify (G_OBJECT (status_icon), "blinking");
803
egg_status_icon_get_is_blinking (EggStatusIcon *status_icon)
805
g_return_val_if_fail (EGG_IS_STATUS_ICON (status_icon), FALSE);
807
return status_icon->priv->blinking;