3 * Copyright (C) 2003 Sun Microsystems, Inc.
4 * Copyright (C) 2005 Hans Breuer <hans@breuer.org>
5 * Copyright (C) 2005 Novell, Inc.
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Library General Public License for more details.
17 * You should have received a copy of the GNU Library General Public
18 * License along with this library; if not, write to the
19 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20 * Boston, MA 02111-1307, USA.
23 * Mark McLoughlin <mark@skynet.ie>
24 * Hans Breuer <hans@breuer.org>
25 * Tor Lillqvist <tml@novell.com>
31 #include "gtkstatusicon.h"
34 #include "gtkiconfactory.h"
35 #include "gtkmarshalers.h"
36 #include "gtktooltips.h"
37 #include "gtktrayicon.h"
39 #include "gtkprivate.h"
40 #include "gtkwidget.h"
44 #ifdef GDK_WINDOWING_WIN32
45 #include "gtkicontheme.h"
48 #include "win32/gdkwin32.h"
49 #define WM_GTK_TRAY_NOTIFICATION (WM_USER+1)
52 #define BLINK_TIMEOUT 500
75 struct _GtkStatusIconPrivate
77 #ifdef GDK_WINDOWING_X11
80 GtkTooltips *tooltips;
83 #ifdef GDK_WINDOWING_WIN32
84 GtkWidget *dummy_widget;
93 GtkImageType storage_type;
102 GdkPixbuf *blank_icon;
103 guint blinking_timeout;
110 static void gtk_status_icon_finalize (GObject *object);
111 static void gtk_status_icon_set_property (GObject *object,
115 static void gtk_status_icon_get_property (GObject *object,
120 #ifdef GDK_WINDOWING_X11
121 static void gtk_status_icon_size_allocate (GtkStatusIcon *status_icon,
122 GtkAllocation *allocation);
124 static gboolean gtk_status_icon_button_press (GtkStatusIcon *status_icon,
125 GdkEventButton *event);
126 static void gtk_status_icon_disable_blinking (GtkStatusIcon *status_icon);
127 static void gtk_status_icon_reset_image_data (GtkStatusIcon *status_icon);
130 static guint status_icon_signals [LAST_SIGNAL] = { 0 };
132 G_DEFINE_TYPE (GtkStatusIcon, gtk_status_icon, G_TYPE_OBJECT);
135 gtk_status_icon_class_init (GtkStatusIconClass *class)
137 GObjectClass *gobject_class = (GObjectClass *) class;
139 gobject_class->finalize = gtk_status_icon_finalize;
140 gobject_class->set_property = gtk_status_icon_set_property;
141 gobject_class->get_property = gtk_status_icon_get_property;
143 g_object_class_install_property (gobject_class,
145 g_param_spec_object ("pixbuf",
147 P_("A GdkPixbuf to display"),
149 GTK_PARAM_READWRITE));
151 g_object_class_install_property (gobject_class,
153 g_param_spec_string ("file",
155 P_("Filename to load and display"),
157 GTK_PARAM_WRITABLE));
159 g_object_class_install_property (gobject_class,
161 g_param_spec_string ("stock",
163 P_("Stock ID for a stock image to display"),
165 GTK_PARAM_READWRITE));
167 g_object_class_install_property (gobject_class,
169 g_param_spec_string ("icon-name",
171 P_("The name of the icon from the icon theme"),
173 GTK_PARAM_READWRITE));
175 g_object_class_install_property (gobject_class,
177 g_param_spec_enum ("storage-type",
179 P_("The representation being used for image data"),
182 GTK_PARAM_READABLE));
184 g_object_class_install_property (gobject_class,
186 g_param_spec_int ("size",
188 P_("The size of the icon"),
192 GTK_PARAM_READABLE));
194 g_object_class_install_property (gobject_class,
196 g_param_spec_boolean ("blinking",
198 P_("Whether or not the status icon is blinking"),
200 GTK_PARAM_READWRITE));
202 g_object_class_install_property (gobject_class,
204 g_param_spec_boolean ("visible",
206 P_("Whether or not the status icon is visible"),
208 GTK_PARAM_READWRITE));
212 * GtkStatusIcon::activate:
213 * @status_icon: the object which received the signal
215 * Gets emitted when the user activates the status icon.
216 * If and how status icons can activated is platform-dependent.
220 status_icon_signals [ACTIVATE_SIGNAL] =
221 g_signal_new (I_("activate"),
222 G_TYPE_FROM_CLASS (gobject_class),
223 G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
224 G_STRUCT_OFFSET (GtkStatusIconClass, activate),
227 g_cclosure_marshal_VOID__VOID,
232 * GtkStatusIcon::popup-menu:
233 * @status_icon: the object which received the signal
234 * @button: the button that was pressed, or 0 if the
235 * signal is not emitted in response to a button press event
236 * @activate_time: the timestamp of the event that
237 * triggered the signal emission
239 * Gets emitted when the user brings up the context menu
240 * of the status icon. Whether status icons can have context
241 * menus and how these are activated is platform-dependent.
243 * The @button and @activate_timeout parameters should be
244 * passed as the last to arguments to gtk_menu_popup().
248 status_icon_signals [POPUP_MENU_SIGNAL] =
249 g_signal_new (I_("popup-menu"),
250 G_TYPE_FROM_CLASS (gobject_class),
251 G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
252 G_STRUCT_OFFSET (GtkStatusIconClass, popup_menu),
255 _gtk_marshal_VOID__UINT_UINT,
262 * GtkStatusIcon::size-changed:
263 * @status_icon: the object which received the signal
264 * @size: the new size
266 * Gets emitted when the size available for the image
267 * changes, e.g. because the notification area got resized.
271 status_icon_signals [SIZE_CHANGED_SIGNAL] =
272 g_signal_new (I_("size-changed"),
273 G_TYPE_FROM_CLASS (gobject_class),
275 G_STRUCT_OFFSET (GtkStatusIconClass, size_changed),
278 _gtk_marshal_BOOLEAN__INT,
283 g_type_class_add_private (class, sizeof (GtkStatusIconPrivate));
286 #ifdef GDK_WINDOWING_WIN32
289 build_button_event (GdkEventButton *e,
294 GdkRectangle monitor0;
296 /* We know that gdk/win32 puts the primary monitor at index 0 */
297 gdk_screen_get_monitor_geometry (gdk_screen_get_default (), 0, &monitor0);
299 e->window = gdk_get_default_root_window ();
300 e->send_event = TRUE;
301 e->time = GetTickCount ();
303 e->x = pos.x + monitor0.x;
304 e->y = pos.y + monitor0.y;
308 e->device = gdk_display_get_default ()->core_pointer;
313 static LRESULT CALLBACK
319 if (message == WM_GTK_TRAY_NOTIFICATION)
322 GtkStatusIcon *status_icon = GTK_STATUS_ICON (wparam);
328 build_button_event (&e, GDK_BUTTON_PRESS,
329 (lparam == WM_LBUTTONDOWN) ? 1 : 3);
330 gtk_status_icon_button_press (status_icon, &e);
339 return DefWindowProc (hwnd, message, wparam, lparam);
344 create_tray_observer (void)
347 static HWND hwnd = NULL;
349 HINSTANCE hmodule = GetModuleHandle (NULL);
354 memset (&wclass, 0, sizeof(WNDCLASS));
355 wclass.lpszClassName = "gtkstatusicon-observer";
356 wclass.lpfnWndProc = wndproc;
357 wclass.hInstance = hmodule;
359 klass = RegisterClass (&wclass);
363 hwnd = CreateWindow (MAKEINTRESOURCE(klass),
365 0, 0, 1, 1, NULL, NULL,
369 UnregisterClass (MAKEINTRESOURCE(klass), hmodule);
379 gtk_status_icon_init (GtkStatusIcon *status_icon)
381 status_icon->priv = G_TYPE_INSTANCE_GET_PRIVATE (status_icon, GTK_TYPE_STATUS_ICON,
382 GtkStatusIconPrivate);
384 status_icon->priv->storage_type = GTK_IMAGE_EMPTY;
385 status_icon->priv->visible = TRUE;
387 #ifdef GDK_WINDOWING_X11
388 status_icon->priv->size = 0;
389 status_icon->priv->image_width = 0;
390 status_icon->priv->image_height = 0;
392 status_icon->priv->tray_icon = GTK_WIDGET (_gtk_tray_icon_new (NULL));
394 gtk_widget_add_events (GTK_WIDGET (status_icon->priv->tray_icon),
395 GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK);
397 g_signal_connect_swapped (status_icon->priv->tray_icon, "button-press-event",
398 G_CALLBACK (gtk_status_icon_button_press), status_icon);
399 status_icon->priv->image = gtk_image_new ();
400 gtk_container_add (GTK_CONTAINER (status_icon->priv->tray_icon),
401 status_icon->priv->image);
403 g_signal_connect_swapped (status_icon->priv->image, "size-allocate",
404 G_CALLBACK (gtk_status_icon_size_allocate), status_icon);
406 gtk_widget_show (status_icon->priv->image);
407 gtk_widget_show (status_icon->priv->tray_icon);
409 status_icon->priv->tooltips = gtk_tooltips_new ();
410 g_object_ref_sink (status_icon->priv->tooltips);
413 #ifdef GDK_WINDOWING_WIN32
415 /* Code to get position and orientation of Windows taskbar. Not needed
416 * currently, kept for reference.
422 abd.cbSize = sizeof (abd);
423 SHAppBarMessage (ABM_GETTASKBARPOS, &abd);
424 if (abd.rc.bottom - abd.rc.top > abd.rc.right - abd.rc.left)
425 orientation = GTK_ORIENTATION_VERTICAL;
427 orientation = GTK_ORIENTATION_HORIZONTAL;
431 /* Are the system tray icons always 16 pixels square? */
432 status_icon->priv->size = 16;
433 status_icon->priv->image_width = 16;
434 status_icon->priv->image_height = 16;
436 status_icon->priv->dummy_widget = gtk_label_new ("");
438 memset (&status_icon->priv->nid, 0, sizeof (status_icon->priv->nid));
440 status_icon->priv->nid.hWnd = create_tray_observer ();
441 status_icon->priv->nid.uID = GPOINTER_TO_UINT (status_icon);
442 status_icon->priv->nid.uCallbackMessage = WM_GTK_TRAY_NOTIFICATION;
443 status_icon->priv->nid.uFlags = NIF_MESSAGE;
445 if (!Shell_NotifyIconW (NIM_ADD, &status_icon->priv->nid))
447 g_warning ("%s:%d:Shell_NotifyIcon(NIM_ADD) failed", __FILE__, __LINE__-2);
448 status_icon->priv->nid.hWnd = NULL;
454 gtk_status_icon_finalize (GObject *object)
456 GtkStatusIcon *status_icon = GTK_STATUS_ICON (object);
458 gtk_status_icon_disable_blinking (status_icon);
460 gtk_status_icon_reset_image_data (status_icon);
462 if (status_icon->priv->blank_icon)
463 g_object_unref (status_icon->priv->blank_icon);
464 status_icon->priv->blank_icon = NULL;
466 #ifdef GDK_WINDOWING_X11
467 if (status_icon->priv->tooltips)
468 g_object_unref (status_icon->priv->tooltips);
469 status_icon->priv->tooltips = NULL;
471 gtk_widget_destroy (status_icon->priv->tray_icon);
474 #ifdef GDK_WINDOWING_WIN32
475 if (status_icon->priv->nid.hWnd != NULL && status_icon->priv->visible)
476 Shell_NotifyIconW (NIM_DELETE, &status_icon->priv->nid);
478 gtk_widget_destroy (status_icon->priv->dummy_widget);
481 G_OBJECT_CLASS (gtk_status_icon_parent_class)->finalize (object);
485 gtk_status_icon_set_property (GObject *object,
490 GtkStatusIcon *status_icon = GTK_STATUS_ICON (object);
495 gtk_status_icon_set_from_pixbuf (status_icon, g_value_get_object (value));
498 gtk_status_icon_set_from_file (status_icon, g_value_get_string (value));
501 gtk_status_icon_set_from_stock (status_icon, g_value_get_string (value));
504 gtk_status_icon_set_from_icon_name (status_icon, g_value_get_string (value));
507 gtk_status_icon_set_blinking (status_icon, g_value_get_boolean (value));
510 gtk_status_icon_set_visible (status_icon, g_value_get_boolean (value));
513 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
519 gtk_status_icon_get_property (GObject *object,
524 GtkStatusIcon *status_icon = GTK_STATUS_ICON (object);
529 g_value_set_object (value, gtk_status_icon_get_pixbuf (status_icon));
532 g_value_set_string (value, gtk_status_icon_get_stock (status_icon));
535 g_value_set_string (value, gtk_status_icon_get_icon_name (status_icon));
537 case PROP_STORAGE_TYPE:
538 g_value_set_enum (value, gtk_status_icon_get_storage_type (status_icon));
541 g_value_set_int (value, gtk_status_icon_get_size (status_icon));
544 g_value_set_boolean (value, gtk_status_icon_get_blinking (status_icon));
547 g_value_set_boolean (value, gtk_status_icon_get_visible (status_icon));
550 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
556 * gtk_status_icon_new:
558 * Creates an empty status icon object.
560 * Return value: a new #GtkStatusIcon
565 gtk_status_icon_new (void)
567 return g_object_new (GTK_TYPE_STATUS_ICON, NULL);
571 * gtk_status_icon_new_from_pixbuf:
572 * @pixbuf: a #GdkPixbuf
574 * Creates a status icon displaying @pixbuf.
576 * The image will be scaled down to fit in the available
577 * space in the notification area, if necessary.
579 * Return value: a new #GtkStatusIcon
584 gtk_status_icon_new_from_pixbuf (GdkPixbuf *pixbuf)
586 return g_object_new (GTK_TYPE_STATUS_ICON,
592 * gtk_status_icon_new_from_file:
593 * @filename: a filename
595 * Creates a status icon displaying the file @filename.
597 * The image will be scaled down to fit in the available
598 * space in the notification area, if necessary.
600 * Return value: a new #GtkStatusIcon
605 gtk_status_icon_new_from_file (const gchar *filename)
607 return g_object_new (GTK_TYPE_STATUS_ICON,
613 * gtk_status_icon_new_from_stock:
614 * @stock_id: a stock icon id
616 * Creates a status icon displaying a stock icon. Sample stock icon
617 * names are #GTK_STOCK_OPEN, #GTK_STOCK_QUIT. You can register your
618 * own stock icon names, see gtk_icon_factory_add_default() and
619 * gtk_icon_factory_add().
621 * Return value: a new #GtkStatusIcon
626 gtk_status_icon_new_from_stock (const gchar *stock_id)
628 return g_object_new (GTK_TYPE_STATUS_ICON,
634 * gtk_status_icon_new_from_icon_name:
635 * @icon_name: an icon name
637 * Creates a status icon displaying an icon from the current icon theme.
638 * If the current icon theme is changed, the icon will be updated
641 * Return value: a new #GtkStatusIcon
646 gtk_status_icon_new_from_icon_name (const gchar *icon_name)
648 return g_object_new (GTK_TYPE_STATUS_ICON,
649 "icon-name", icon_name,
654 emit_activate_signal (GtkStatusIcon *status_icon)
656 g_signal_emit (status_icon,
657 status_icon_signals [ACTIVATE_SIGNAL], 0);
661 emit_popup_menu_signal (GtkStatusIcon *status_icon,
663 guint32 activate_time)
665 g_signal_emit (status_icon,
666 status_icon_signals [POPUP_MENU_SIGNAL], 0,
671 #ifdef GDK_WINDOWING_X11
674 emit_size_changed_signal (GtkStatusIcon *status_icon,
677 gboolean handled = FALSE;
679 g_signal_emit (status_icon,
680 status_icon_signals [SIZE_CHANGED_SIGNAL], 0,
690 gtk_status_icon_blank_icon (GtkStatusIcon *status_icon)
692 if (status_icon->priv->blank_icon)
696 width = gdk_pixbuf_get_width (status_icon->priv->blank_icon);
697 height = gdk_pixbuf_get_height (status_icon->priv->blank_icon);
700 if (width == status_icon->priv->image_width &&
701 height == status_icon->priv->image_height)
703 return status_icon->priv->blank_icon;
707 g_object_unref (status_icon->priv->blank_icon);
708 status_icon->priv->blank_icon = NULL;
712 status_icon->priv->blank_icon = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8,
713 status_icon->priv->image_width,
714 status_icon->priv->image_height);
715 if (status_icon->priv->blank_icon)
716 gdk_pixbuf_fill (status_icon->priv->blank_icon, 0);
718 return status_icon->priv->blank_icon;
721 #ifdef GDK_WINDOWING_X11
724 find_icon_size (GtkWidget *widget,
728 GtkSettings *settings;
732 screen = gtk_widget_get_screen (widget);
735 return GTK_ICON_SIZE_MENU;
737 settings = gtk_settings_get_for_screen (screen);
740 size = GTK_ICON_SIZE_MENU;
742 for (s = GTK_ICON_SIZE_MENU; s < GTK_ICON_SIZE_DIALOG; s++)
744 if (gtk_icon_size_lookup_for_settings (settings, s, &w, &h) &&
745 w <= pixel_size && h <= pixel_size)
747 d = MAX (pixel_size - w, pixel_size - h);
762 gtk_status_icon_update_image (GtkStatusIcon *status_icon)
764 if (status_icon->priv->blink_off)
766 #ifdef GDK_WINDOWING_X11
767 gtk_image_set_from_pixbuf (GTK_IMAGE (status_icon->priv->image),
768 gtk_status_icon_blank_icon (status_icon));
770 #ifdef GDK_WINDOWING_WIN32
771 status_icon->priv->nid.hIcon = gdk_win32_pixbuf_to_hicon_libgtk_only (gtk_status_icon_blank_icon (status_icon));
772 status_icon->priv->nid.uFlags |= NIF_ICON;
773 if (status_icon->priv->nid.hWnd != NULL && status_icon->priv->visible)
774 if (!Shell_NotifyIconW (NIM_MODIFY, &status_icon->priv->nid))
775 g_warning ("%s:%d:Shell_NotifyIcon(NIM_MODIFY) failed", __FILE__, __LINE__-1);
780 switch (status_icon->priv->storage_type)
782 case GTK_IMAGE_PIXBUF:
786 pixbuf = status_icon->priv->image_data.pixbuf;
795 size = status_icon->priv->size;
797 width = gdk_pixbuf_get_width (pixbuf);
798 height = gdk_pixbuf_get_height (pixbuf);
800 if (width > size || height > size)
802 scaled = gdk_pixbuf_scale_simple (pixbuf,
805 GDK_INTERP_BILINEAR);
809 scaled = g_object_ref (pixbuf);
812 #ifdef GDK_WINDOWING_X11
813 gtk_image_set_from_pixbuf (GTK_IMAGE (status_icon->priv->image), scaled);
815 #ifdef GDK_WINDOWING_WIN32
816 status_icon->priv->nid.hIcon = gdk_win32_pixbuf_to_hicon_libgtk_only (scaled);
817 status_icon->priv->nid.uFlags |= NIF_ICON;
818 if (status_icon->priv->nid.hWnd != NULL && status_icon->priv->visible)
819 if (!Shell_NotifyIconW (NIM_MODIFY, &status_icon->priv->nid))
820 g_warning ("%s:%d:Shell_NotifyIcon(NIM_MODIFY) failed", __FILE__, __LINE__-1);
822 g_object_unref (scaled);
826 #ifdef GDK_WINDOWING_X11
827 gtk_image_set_from_pixbuf (GTK_IMAGE (status_icon->priv->image), NULL);
829 #ifdef GDK_WINDOWING_WIN32
830 status_icon->priv->nid.uFlags &= ~NIF_ICON;
831 if (status_icon->priv->nid.hWnd != NULL && status_icon->priv->visible)
832 if (!Shell_NotifyIconW (NIM_MODIFY, &status_icon->priv->nid))
833 g_warning ("%s:%d:Shell_NotifyIcon(NIM_MODIFY) failed", __FILE__, __LINE__-1);
839 case GTK_IMAGE_STOCK:
841 #ifdef GDK_WINDOWING_X11
842 GtkIconSize size = find_icon_size (status_icon->priv->image, status_icon->priv->size);
843 gtk_image_set_from_stock (GTK_IMAGE (status_icon->priv->image),
844 status_icon->priv->image_data.stock_id,
847 #ifdef GDK_WINDOWING_WIN32
850 gtk_widget_render_icon (status_icon->priv->dummy_widget,
851 status_icon->priv->image_data.stock_id,
852 GTK_ICON_SIZE_SMALL_TOOLBAR,
854 status_icon->priv->nid.hIcon = gdk_win32_pixbuf_to_hicon_libgtk_only (pixbuf);
855 status_icon->priv->nid.uFlags |= NIF_ICON;
856 if (status_icon->priv->nid.hWnd != NULL && status_icon->priv->visible)
857 if (!Shell_NotifyIconW (NIM_MODIFY, &status_icon->priv->nid))
858 g_warning ("%s:%d:Shell_NotifyIcon(NIM_MODIFY) failed", __FILE__, __LINE__-1);
859 g_object_unref (pixbuf);
865 case GTK_IMAGE_ICON_NAME:
867 #ifdef GDK_WINDOWING_X11
868 GtkIconSize size = find_icon_size (status_icon->priv->image, status_icon->priv->size);
869 gtk_image_set_from_icon_name (GTK_IMAGE (status_icon->priv->image),
870 status_icon->priv->image_data.icon_name,
873 #ifdef GDK_WINDOWING_WIN32
876 gtk_icon_theme_load_icon (gtk_icon_theme_get_default (),
877 status_icon->priv->image_data.icon_name,
878 status_icon->priv->size,
881 status_icon->priv->nid.hIcon = gdk_win32_pixbuf_to_hicon_libgtk_only (pixbuf);
882 status_icon->priv->nid.uFlags |= NIF_ICON;
883 if (status_icon->priv->nid.hWnd != NULL && status_icon->priv->visible)
884 if (!Shell_NotifyIconW (NIM_MODIFY, &status_icon->priv->nid))
885 g_warning ("%s:%d:Shell_NotifyIcon(NIM_MODIFY) failed", __FILE__, __LINE__-1);
886 g_object_unref (pixbuf);
892 case GTK_IMAGE_EMPTY:
893 #ifdef GDK_WINDOWING_X11
894 gtk_image_set_from_pixbuf (GTK_IMAGE (status_icon->priv->image), NULL);
896 #ifdef GDK_WINDOWING_WIN32
897 status_icon->priv->nid.uFlags &= ~NIF_ICON;
898 if (status_icon->priv->nid.hWnd != NULL && status_icon->priv->visible)
899 if (!Shell_NotifyIconW (NIM_MODIFY, &status_icon->priv->nid))
900 g_warning ("%s:%d:Shell_NotifyIcon(NIM_MODIFY) failed", __FILE__, __LINE__-1);
904 g_assert_not_reached ();
909 #ifdef GDK_WINDOWING_X11
912 gtk_status_icon_size_allocate (GtkStatusIcon *status_icon,
913 GtkAllocation *allocation)
915 GtkOrientation orientation;
918 orientation = _gtk_tray_icon_get_orientation (GTK_TRAY_ICON (status_icon->priv->tray_icon));
920 if (orientation == GTK_ORIENTATION_HORIZONTAL)
921 size = allocation->height;
923 size = allocation->width;
925 status_icon->priv->image_width = allocation->width - GTK_MISC (status_icon->priv->image)->xpad * 2;
926 status_icon->priv->image_height = allocation->height - GTK_MISC (status_icon->priv->image)->ypad * 2;
928 if (status_icon->priv->size != size)
930 status_icon->priv->size = size;
932 g_object_notify (G_OBJECT (status_icon), "size");
934 if (!emit_size_changed_signal (status_icon, size))
936 gtk_status_icon_update_image (status_icon);
944 gtk_status_icon_button_press (GtkStatusIcon *status_icon,
945 GdkEventButton *event)
947 if (event->button == 1 && event->type == GDK_BUTTON_PRESS)
949 emit_activate_signal (status_icon);
952 else if (event->button == 3 && event->type == GDK_BUTTON_PRESS)
954 emit_popup_menu_signal (status_icon, event->button, event->time);
962 gtk_status_icon_reset_image_data (GtkStatusIcon *status_icon)
964 status_icon->priv->storage_type = GTK_IMAGE_EMPTY;
965 g_object_notify (G_OBJECT (status_icon), "storage-type");
967 switch (status_icon->priv->storage_type)
969 case GTK_IMAGE_PIXBUF:
970 if (status_icon->priv->image_data.pixbuf)
971 g_object_unref (status_icon->priv->image_data.pixbuf);
972 status_icon->priv->image_data.pixbuf = NULL;
973 g_object_notify (G_OBJECT (status_icon), "pixbuf");
976 case GTK_IMAGE_STOCK:
977 g_free (status_icon->priv->image_data.stock_id);
978 status_icon->priv->image_data.stock_id = NULL;
980 g_object_notify (G_OBJECT (status_icon), "stock");
983 case GTK_IMAGE_ICON_NAME:
984 g_free (status_icon->priv->image_data.icon_name);
985 status_icon->priv->image_data.icon_name = NULL;
987 g_object_notify (G_OBJECT (status_icon), "icon-name");
990 case GTK_IMAGE_EMPTY:
993 g_assert_not_reached ();
999 gtk_status_icon_set_image (GtkStatusIcon *status_icon,
1000 GtkImageType storage_type,
1003 g_object_freeze_notify (G_OBJECT (status_icon));
1005 gtk_status_icon_reset_image_data (status_icon);
1007 status_icon->priv->storage_type = storage_type;
1008 g_object_notify (G_OBJECT (status_icon), "storage-type");
1010 switch (storage_type)
1012 case GTK_IMAGE_PIXBUF:
1013 status_icon->priv->image_data.pixbuf = (GdkPixbuf *)data;
1014 g_object_notify (G_OBJECT (status_icon), "pixbuf");
1016 case GTK_IMAGE_STOCK:
1017 status_icon->priv->image_data.stock_id = g_strdup ((const gchar *)data);
1018 g_object_notify (G_OBJECT (status_icon), "stock");
1020 case GTK_IMAGE_ICON_NAME:
1021 status_icon->priv->image_data.icon_name = g_strdup ((const gchar *)data);
1022 g_object_notify (G_OBJECT (status_icon), "icon-name");
1025 g_warning ("Image type %d not handled by GtkStatusIcon", storage_type);
1028 g_object_thaw_notify (G_OBJECT (status_icon));
1030 gtk_status_icon_update_image (status_icon);
1034 * gtk_status_icon_set_from_pixbuf:
1035 * @status_icon: a #GtkStatusIcon
1036 * @pixbuf: a #GdkPixbuf or %NULL
1038 * Makes @status_icon display @pixbuf.
1039 * See gtk_status_icon_new_from_pixbuf() for details.
1044 gtk_status_icon_set_from_pixbuf (GtkStatusIcon *status_icon,
1047 g_return_if_fail (GTK_IS_STATUS_ICON (status_icon));
1048 g_return_if_fail (pixbuf == NULL || GDK_IS_PIXBUF (pixbuf));
1051 g_object_ref (pixbuf);
1053 gtk_status_icon_set_image (status_icon, GTK_IMAGE_PIXBUF,
1058 * gtk_status_icon_set_from_file:
1059 * @status_icon: a #GtkStatusIcon
1060 * @filename: a filename
1062 * Makes @status_icon display the file @filename.
1063 * See gtk_status_icon_new_from_file() for details.
1068 gtk_status_icon_set_from_file (GtkStatusIcon *status_icon,
1069 const gchar *filename)
1073 g_return_if_fail (GTK_IS_STATUS_ICON (status_icon));
1074 g_return_if_fail (filename != NULL);
1076 pixbuf = gdk_pixbuf_new_from_file (filename, NULL);
1078 gtk_status_icon_set_from_pixbuf (status_icon, pixbuf);
1081 g_object_unref (pixbuf);
1085 * gtk_status_icon_set_from_stock:
1086 * @status_icon: a #GtkStatusIcon
1087 * @stock_id: a stock icon id
1089 * Makes @status_icon display the stock icon with the id @stock_id.
1090 * See gtk_status_icon_new_from_stock() for details.
1095 gtk_status_icon_set_from_stock (GtkStatusIcon *status_icon,
1096 const gchar *stock_id)
1098 g_return_if_fail (GTK_IS_STATUS_ICON (status_icon));
1099 g_return_if_fail (stock_id != NULL);
1101 gtk_status_icon_set_image (status_icon, GTK_IMAGE_STOCK,
1102 (gpointer) stock_id);
1106 * gtk_status_icon_set_from_icon_name:
1107 * @status_icon: a #GtkStatusIcon
1108 * @icon_name: an icon name
1110 * Makes @status_icon display the icon named @icon_name from the
1111 * current icon theme.
1112 * See gtk_status_icon_new_from_icon_name() for details.
1117 gtk_status_icon_set_from_icon_name (GtkStatusIcon *status_icon,
1118 const gchar *icon_name)
1120 g_return_if_fail (GTK_IS_STATUS_ICON (status_icon));
1121 g_return_if_fail (icon_name != NULL);
1123 gtk_status_icon_set_image (status_icon, GTK_IMAGE_ICON_NAME,
1124 (gpointer) icon_name);
1128 * gtk_status_icon_get_storage_type:
1129 * @status_icon: a #GtkStatusIcon
1131 * Gets the type of representation being used by the #GtkStatusIcon
1132 * to store image data. If the #GtkStatusIcon has no image data,
1133 * the return value will be %GTK_IMAGE_EMPTY.
1135 * Return value: the image representation being used
1140 gtk_status_icon_get_storage_type (GtkStatusIcon *status_icon)
1142 g_return_val_if_fail (GTK_IS_STATUS_ICON (status_icon), GTK_IMAGE_EMPTY);
1144 return status_icon->priv->storage_type;
1147 * gtk_status_icon_get_pixbuf:
1148 * @status_icon: a #GtkStatusIcon
1150 * Gets the #GdkPixbuf being displayed by the #GtkStatusIcon.
1151 * The storage type of the status icon must be %GTK_IMAGE_EMPTY or
1152 * %GTK_IMAGE_PIXBUF (see gtk_status_icon_get_storage_type()).
1153 * The caller of this function does not own a reference to the
1156 * Return value: the displayed pixbuf, or %NULL if the image is empty.
1161 gtk_status_icon_get_pixbuf (GtkStatusIcon *status_icon)
1163 g_return_val_if_fail (GTK_IS_STATUS_ICON (status_icon), NULL);
1164 g_return_val_if_fail (status_icon->priv->storage_type == GTK_IMAGE_PIXBUF ||
1165 status_icon->priv->storage_type == GTK_IMAGE_EMPTY, NULL);
1166 if (status_icon->priv->storage_type == GTK_IMAGE_EMPTY)
1167 status_icon->priv->image_data.pixbuf = NULL;
1169 return status_icon->priv->image_data.pixbuf;
1173 * gtk_status_icon_get_stock:
1174 * @status_icon: a #GtkStatusIcon
1176 * Gets the id of the stock icon being displayed by the #GtkStatusIcon.
1177 * The storage type of the status icon must be %GTK_IMAGE_EMPTY or
1178 * %GTK_IMAGE_STOCK (see gtk_status_icon_get_storage_type()).
1179 * The returned string is owned by the #GtkStatusIcon and should not
1180 * be freed or modified.
1182 * Return value: stock id of the displayed stock icon,
1183 * or %NULL if the image is empty.
1187 G_CONST_RETURN gchar *
1188 gtk_status_icon_get_stock (GtkStatusIcon *status_icon)
1190 g_return_val_if_fail (GTK_IS_STATUS_ICON (status_icon), NULL);
1191 g_return_val_if_fail (status_icon->priv->storage_type == GTK_IMAGE_STOCK ||
1192 status_icon->priv->storage_type == GTK_IMAGE_EMPTY, NULL);
1194 if (status_icon->priv->storage_type == GTK_IMAGE_EMPTY)
1195 status_icon->priv->image_data.stock_id = NULL;
1197 return status_icon->priv->image_data.stock_id;
1201 * gtk_status_icon_get_icon_name:
1202 * @status_icon: a #GtkStatusIcon
1204 * Gets the name of the icon being displayed by the #GtkStatusIcon.
1205 * The storage type of the status icon must be %GTK_IMAGE_EMPTY or
1206 * %GTK_IMAGE_ICON_NAME (see gtk_status_icon_get_storage_type()).
1207 * The returned string is owned by the #GtkStatusIcon and should not
1208 * be freed or modified.
1210 * Return value: name of the displayed icon, or %NULL if the image is empty.
1214 G_CONST_RETURN gchar *
1215 gtk_status_icon_get_icon_name (GtkStatusIcon *status_icon)
1217 g_return_val_if_fail (GTK_IS_STATUS_ICON (status_icon), NULL);
1218 g_return_val_if_fail (status_icon->priv->storage_type == GTK_IMAGE_ICON_NAME ||
1219 status_icon->priv->storage_type == GTK_IMAGE_EMPTY, NULL);
1221 if (status_icon->priv->storage_type == GTK_IMAGE_EMPTY)
1222 status_icon->priv->image_data.icon_name = NULL;
1224 return status_icon->priv->image_data.icon_name;
1228 * gtk_status_icon_get_size:
1229 * @status_icon: a #GtkStatusIcon
1231 * Gets the size in pixels that is available for the image.
1232 * Stock icons and named icons adapt their size automatically
1233 * if the size of the notification area changes. For other
1234 * storage types, the size-changed signal can be used to
1235 * react to size changes.
1237 * Return value: the size that is available for the image
1242 gtk_status_icon_get_size (GtkStatusIcon *status_icon)
1244 g_return_val_if_fail (GTK_IS_STATUS_ICON (status_icon), 0);
1246 return status_icon->priv->size;
1250 * gtk_status_icon_set_tooltip:
1251 * @status_icon: a #GtkStatusIcon
1252 * @tooltip_text: the tooltip text, or %NULL
1254 * Sets the tooltip of the status icon.
1259 gtk_status_icon_set_tooltip (GtkStatusIcon *status_icon,
1260 const gchar *tooltip_text)
1262 g_return_if_fail (GTK_IS_STATUS_ICON (status_icon));
1264 #ifdef GDK_WINDOWING_X11
1265 gtk_tooltips_set_tip (status_icon->priv->tooltips,
1266 status_icon->priv->tray_icon,
1267 tooltip_text, NULL);
1269 #ifdef GDK_WINDOWING_WIN32
1270 if (tooltip_text == NULL)
1271 status_icon->priv->nid.uFlags &= ~NIF_TIP;
1274 WCHAR *wcs = g_utf8_to_utf16 (tooltip_text, -1, NULL, NULL, NULL);
1276 status_icon->priv->nid.uFlags |= NIF_TIP;
1277 wcsncpy (status_icon->priv->nid.szTip, wcs,
1278 G_N_ELEMENTS (status_icon->priv->nid.szTip) - 1);
1279 status_icon->priv->nid.szTip[G_N_ELEMENTS (status_icon->priv->nid.szTip) - 1] = 0;
1282 if (status_icon->priv->nid.hWnd != NULL && status_icon->priv->visible)
1283 if (!Shell_NotifyIconW (NIM_MODIFY, &status_icon->priv->nid))
1284 g_warning ("%s:%d:Shell_NotifyIconW(NIM_MODIFY) failed", __FILE__, __LINE__-1);
1289 gtk_status_icon_blinker (GtkStatusIcon *status_icon)
1291 status_icon->priv->blink_off = !status_icon->priv->blink_off;
1293 gtk_status_icon_update_image (status_icon);
1299 gtk_status_icon_enable_blinking (GtkStatusIcon *status_icon)
1301 if (!status_icon->priv->blinking_timeout)
1303 gtk_status_icon_blinker (status_icon);
1305 status_icon->priv->blinking_timeout =
1306 g_timeout_add (BLINK_TIMEOUT,
1307 (GSourceFunc) gtk_status_icon_blinker,
1313 gtk_status_icon_disable_blinking (GtkStatusIcon *status_icon)
1315 if (status_icon->priv->blinking_timeout)
1317 g_source_remove (status_icon->priv->blinking_timeout);
1318 status_icon->priv->blinking_timeout = 0;
1319 status_icon->priv->blink_off = FALSE;
1321 gtk_status_icon_update_image (status_icon);
1326 * gtk_status_icon_set_visible:
1327 * @status_icon: a #GtkStatusIcon
1328 * @visible: %TRUE to show the status icon, %FALSE to hide it
1330 * Shows or hides a status icon.
1335 gtk_status_icon_set_visible (GtkStatusIcon *status_icon,
1338 g_return_if_fail (GTK_IS_STATUS_ICON (status_icon));
1340 visible = visible != FALSE;
1342 if (status_icon->priv->visible != visible)
1344 status_icon->priv->visible = visible;
1346 #ifdef GDK_WINDOWING_X11
1348 gtk_widget_show (status_icon->priv->tray_icon);
1350 gtk_widget_hide (status_icon->priv->tray_icon);
1352 #ifdef GDK_WINDOWING_WIN32
1353 if (status_icon->priv->nid.hWnd != NULL)
1356 Shell_NotifyIconW (NIM_ADD, &status_icon->priv->nid);
1358 Shell_NotifyIconW (NIM_DELETE, &status_icon->priv->nid);
1361 g_object_notify (G_OBJECT (status_icon), "visible");
1366 * gtk_status_icon_get_visible:
1367 * @status_icon: a #GtkStatusIcon
1369 * Returns whether the status icon is visible or not.
1370 * Note that being visible does not guarantee that
1371 * the user can actually see the icon, see also
1372 * gtk_status_icon_is_embedded().
1374 * Return value: %TRUE if the status icon is visible
1379 gtk_status_icon_get_visible (GtkStatusIcon *status_icon)
1381 g_return_val_if_fail (GTK_IS_STATUS_ICON (status_icon), FALSE);
1383 return status_icon->priv->visible;
1387 * gtk_status_icon_set_blinking:
1388 * @status_icon: a #GtkStatusIcon
1389 * @blinking: %TRUE to turn blinking on, %FALSE to turn it off
1391 * Makes the status icon start or stop blinking.
1392 * Note that blinking user interface elements may be problematic
1393 * for some users, and thus may be turned off, in which case
1394 * this setting has no effect.
1399 gtk_status_icon_set_blinking (GtkStatusIcon *status_icon,
1402 g_return_if_fail (GTK_IS_STATUS_ICON (status_icon));
1404 blinking = blinking != FALSE;
1406 if (status_icon->priv->blinking != blinking)
1408 status_icon->priv->blinking = blinking;
1411 gtk_status_icon_enable_blinking (status_icon);
1413 gtk_status_icon_disable_blinking (status_icon);
1415 g_object_notify (G_OBJECT (status_icon), "blinking");
1420 * gtk_status_icon_get_blinking:
1421 * @status_icon: a #GtkStatusIcon
1423 * Returns whether the icon is blinking, see
1424 * gtk_status_icon_set_blinking().
1426 * Return value: %TRUE if the icon is blinking
1431 gtk_status_icon_get_blinking (GtkStatusIcon *status_icon)
1433 g_return_val_if_fail (GTK_IS_STATUS_ICON (status_icon), FALSE);
1435 return status_icon->priv->blinking;
1439 * gtk_status_icon_is_embedded:
1440 * @status_icon: a #GtkStatusIcon
1442 * Returns whether the status icon is embedded in a notification
1445 * Return value: %TRUE if the status icon is embedded in
1446 * a notification area.
1451 gtk_status_icon_is_embedded (GtkStatusIcon *status_icon)
1453 #ifdef GDK_WINDOWING_X11
1457 g_return_val_if_fail (GTK_IS_STATUS_ICON (status_icon), FALSE);
1459 #ifdef GDK_WINDOWING_X11
1460 plug = GTK_PLUG (status_icon->priv->tray_icon);
1462 if (plug->socket_window)
1467 #ifdef GDK_WINDOWING_WIN32
1472 #define __GTK_STATUS_ICON_C__
1473 #include "gtkaliasdef.c"