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.
269 * Return value: %TRUE if the icon was updated for the new
270 * size. Otherwise, GTK+ will scale the icon as necessary.
274 status_icon_signals [SIZE_CHANGED_SIGNAL] =
275 g_signal_new (I_("size-changed"),
276 G_TYPE_FROM_CLASS (gobject_class),
278 G_STRUCT_OFFSET (GtkStatusIconClass, size_changed),
279 g_signal_accumulator_true_handled,
281 _gtk_marshal_BOOLEAN__INT,
286 g_type_class_add_private (class, sizeof (GtkStatusIconPrivate));
289 #ifdef GDK_WINDOWING_WIN32
292 build_button_event (GdkEventButton *e,
297 GdkRectangle monitor0;
299 /* We know that gdk/win32 puts the primary monitor at index 0 */
300 gdk_screen_get_monitor_geometry (gdk_screen_get_default (), 0, &monitor0);
302 e->window = gdk_get_default_root_window ();
303 e->send_event = TRUE;
304 e->time = GetTickCount ();
306 e->x = pos.x + monitor0.x;
307 e->y = pos.y + monitor0.y;
311 e->device = gdk_display_get_default ()->core_pointer;
316 static LRESULT CALLBACK
322 if (message == WM_GTK_TRAY_NOTIFICATION)
325 GtkStatusIcon *status_icon = GTK_STATUS_ICON (wparam);
331 build_button_event (&e, GDK_BUTTON_PRESS,
332 (lparam == WM_LBUTTONDOWN) ? 1 : 3);
333 gtk_status_icon_button_press (status_icon, &e);
342 return DefWindowProc (hwnd, message, wparam, lparam);
347 create_tray_observer (void)
350 static HWND hwnd = NULL;
352 HINSTANCE hmodule = GetModuleHandle (NULL);
357 memset (&wclass, 0, sizeof(WNDCLASS));
358 wclass.lpszClassName = "gtkstatusicon-observer";
359 wclass.lpfnWndProc = wndproc;
360 wclass.hInstance = hmodule;
362 klass = RegisterClass (&wclass);
366 hwnd = CreateWindow (MAKEINTRESOURCE(klass),
368 0, 0, 1, 1, NULL, NULL,
372 UnregisterClass (MAKEINTRESOURCE(klass), hmodule);
382 gtk_status_icon_init (GtkStatusIcon *status_icon)
384 GtkStatusIconPrivate *priv;
386 priv = G_TYPE_INSTANCE_GET_PRIVATE (status_icon, GTK_TYPE_STATUS_ICON,
387 GtkStatusIconPrivate);
388 status_icon->priv = priv;
390 priv->storage_type = GTK_IMAGE_EMPTY;
391 priv->visible = TRUE;
393 #ifdef GDK_WINDOWING_X11
395 priv->image_width = 0;
396 priv->image_height = 0;
398 priv->tray_icon = GTK_WIDGET (_gtk_tray_icon_new (NULL));
400 gtk_widget_add_events (GTK_WIDGET (priv->tray_icon),
401 GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK);
403 g_signal_connect_swapped (priv->tray_icon, "button-press-event",
404 G_CALLBACK (gtk_status_icon_button_press), status_icon);
405 priv->image = gtk_image_new ();
406 gtk_container_add (GTK_CONTAINER (priv->tray_icon), priv->image);
408 g_signal_connect_swapped (priv->image, "size-allocate",
409 G_CALLBACK (gtk_status_icon_size_allocate), status_icon);
411 gtk_widget_show (priv->image);
412 gtk_widget_show (priv->tray_icon);
414 status_icon->priv->tooltips = gtk_tooltips_new ();
415 g_object_ref_sink (priv->tooltips);
418 #ifdef GDK_WINDOWING_WIN32
420 /* Code to get position and orientation of Windows taskbar. Not needed
421 * currently, kept for reference.
427 abd.cbSize = sizeof (abd);
428 SHAppBarMessage (ABM_GETTASKBARPOS, &abd);
429 if (abd.rc.bottom - abd.rc.top > abd.rc.right - abd.rc.left)
430 orientation = GTK_ORIENTATION_VERTICAL;
432 orientation = GTK_ORIENTATION_HORIZONTAL;
436 /* Are the system tray icons always 16 pixels square? */
438 priv->image_width = 16;
439 priv->image_height = 16;
441 priv->dummy_widget = gtk_label_new ("");
443 memset (&priv->nid, 0, sizeof (priv->nid));
445 priv->nid.hWnd = create_tray_observer ();
446 priv->nid.uID = GPOINTER_TO_UINT (status_icon);
447 priv->nid.uCallbackMessage = WM_GTK_TRAY_NOTIFICATION;
448 priv->nid.uFlags = NIF_MESSAGE;
450 if (!Shell_NotifyIconW (NIM_ADD, &priv->nid))
452 g_warning ("%s:%d:Shell_NotifyIcon(NIM_ADD) failed", __FILE__, __LINE__-2);
453 priv->nid.hWnd = NULL;
459 gtk_status_icon_finalize (GObject *object)
461 GtkStatusIcon *status_icon = GTK_STATUS_ICON (object);
462 GtkStatusIconPrivate *priv = status_icon->priv;
464 gtk_status_icon_disable_blinking (status_icon);
466 gtk_status_icon_reset_image_data (status_icon);
468 if (priv->blank_icon)
469 g_object_unref (priv->blank_icon);
470 priv->blank_icon = NULL;
472 #ifdef GDK_WINDOWING_X11
474 g_object_unref (priv->tooltips);
475 priv->tooltips = NULL;
477 gtk_widget_destroy (priv->tray_icon);
480 #ifdef GDK_WINDOWING_WIN32
481 if (priv->nid.hWnd != NULL && priv->visible)
482 Shell_NotifyIconW (NIM_DELETE, &priv->nid);
484 gtk_widget_destroy (priv->dummy_widget);
487 G_OBJECT_CLASS (gtk_status_icon_parent_class)->finalize (object);
491 gtk_status_icon_set_property (GObject *object,
496 GtkStatusIcon *status_icon = GTK_STATUS_ICON (object);
501 gtk_status_icon_set_from_pixbuf (status_icon, g_value_get_object (value));
504 gtk_status_icon_set_from_file (status_icon, g_value_get_string (value));
507 gtk_status_icon_set_from_stock (status_icon, g_value_get_string (value));
510 gtk_status_icon_set_from_icon_name (status_icon, g_value_get_string (value));
513 gtk_status_icon_set_blinking (status_icon, g_value_get_boolean (value));
516 gtk_status_icon_set_visible (status_icon, g_value_get_boolean (value));
519 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
525 gtk_status_icon_get_property (GObject *object,
530 GtkStatusIcon *status_icon = GTK_STATUS_ICON (object);
531 GtkStatusIconPrivate *priv = status_icon->priv;
533 /* The "getter" functions whine if you try to get the wrong
534 * storage type. This function is instead robust against that,
535 * so that GUI builders don't have to jump through hoops
542 if (priv->storage_type != GTK_IMAGE_PIXBUF)
543 g_value_set_object (value, NULL);
545 g_value_set_object (value, gtk_status_icon_get_pixbuf (status_icon));
548 if (priv->storage_type != GTK_IMAGE_STOCK)
549 g_value_set_string (value, NULL);
551 g_value_set_string (value, gtk_status_icon_get_stock (status_icon));
554 if (priv->storage_type != GTK_IMAGE_ICON_NAME)
555 g_value_set_string (value, NULL);
557 g_value_set_string (value, gtk_status_icon_get_icon_name (status_icon));
559 case PROP_STORAGE_TYPE:
560 g_value_set_enum (value, gtk_status_icon_get_storage_type (status_icon));
563 g_value_set_int (value, gtk_status_icon_get_size (status_icon));
566 g_value_set_boolean (value, gtk_status_icon_get_blinking (status_icon));
569 g_value_set_boolean (value, gtk_status_icon_get_visible (status_icon));
572 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
578 * gtk_status_icon_new:
580 * Creates an empty status icon object.
582 * Return value: a new #GtkStatusIcon
587 gtk_status_icon_new (void)
589 return g_object_new (GTK_TYPE_STATUS_ICON, NULL);
593 * gtk_status_icon_new_from_pixbuf:
594 * @pixbuf: a #GdkPixbuf
596 * Creates a status icon displaying @pixbuf.
598 * The image will be scaled down to fit in the available
599 * space in the notification area, if necessary.
601 * Return value: a new #GtkStatusIcon
606 gtk_status_icon_new_from_pixbuf (GdkPixbuf *pixbuf)
608 return g_object_new (GTK_TYPE_STATUS_ICON,
614 * gtk_status_icon_new_from_file:
615 * @filename: a filename
617 * Creates a status icon displaying the file @filename.
619 * The image will be scaled down to fit in the available
620 * space in the notification area, if necessary.
622 * Return value: a new #GtkStatusIcon
627 gtk_status_icon_new_from_file (const gchar *filename)
629 return g_object_new (GTK_TYPE_STATUS_ICON,
635 * gtk_status_icon_new_from_stock:
636 * @stock_id: a stock icon id
638 * Creates a status icon displaying a stock icon. Sample stock icon
639 * names are #GTK_STOCK_OPEN, #GTK_STOCK_QUIT. You can register your
640 * own stock icon names, see gtk_icon_factory_add_default() and
641 * gtk_icon_factory_add().
643 * Return value: a new #GtkStatusIcon
648 gtk_status_icon_new_from_stock (const gchar *stock_id)
650 return g_object_new (GTK_TYPE_STATUS_ICON,
656 * gtk_status_icon_new_from_icon_name:
657 * @icon_name: an icon name
659 * Creates a status icon displaying an icon from the current icon theme.
660 * If the current icon theme is changed, the icon will be updated
663 * Return value: a new #GtkStatusIcon
668 gtk_status_icon_new_from_icon_name (const gchar *icon_name)
670 return g_object_new (GTK_TYPE_STATUS_ICON,
671 "icon-name", icon_name,
676 emit_activate_signal (GtkStatusIcon *status_icon)
678 g_signal_emit (status_icon,
679 status_icon_signals [ACTIVATE_SIGNAL], 0);
683 emit_popup_menu_signal (GtkStatusIcon *status_icon,
685 guint32 activate_time)
687 g_signal_emit (status_icon,
688 status_icon_signals [POPUP_MENU_SIGNAL], 0,
693 #ifdef GDK_WINDOWING_X11
696 emit_size_changed_signal (GtkStatusIcon *status_icon,
699 gboolean handled = FALSE;
701 g_signal_emit (status_icon,
702 status_icon_signals [SIZE_CHANGED_SIGNAL], 0,
712 gtk_status_icon_blank_icon (GtkStatusIcon *status_icon)
714 GtkStatusIconPrivate *priv = status_icon->priv;
716 if (priv->blank_icon)
720 width = gdk_pixbuf_get_width (priv->blank_icon);
721 height = gdk_pixbuf_get_height (priv->blank_icon);
724 if (width == priv->image_width && height == priv->image_height)
725 return priv->blank_icon;
728 g_object_unref (priv->blank_icon);
729 priv->blank_icon = NULL;
733 priv->blank_icon = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8,
736 if (priv->blank_icon)
737 gdk_pixbuf_fill (priv->blank_icon, 0);
739 return priv->blank_icon;
742 #ifdef GDK_WINDOWING_X11
745 find_icon_size (GtkWidget *widget,
749 GtkSettings *settings;
753 screen = gtk_widget_get_screen (widget);
756 return GTK_ICON_SIZE_MENU;
758 settings = gtk_settings_get_for_screen (screen);
761 size = GTK_ICON_SIZE_MENU;
763 for (s = GTK_ICON_SIZE_MENU; s < GTK_ICON_SIZE_DIALOG; s++)
765 if (gtk_icon_size_lookup_for_settings (settings, s, &w, &h) &&
766 w <= pixel_size && h <= pixel_size)
768 d = MAX (pixel_size - w, pixel_size - h);
783 gtk_status_icon_update_image (GtkStatusIcon *status_icon)
785 GtkStatusIconPrivate *priv = status_icon->priv;
789 #ifdef GDK_WINDOWING_X11
790 gtk_image_set_from_pixbuf (GTK_IMAGE (priv->image),
791 gtk_status_icon_blank_icon (status_icon));
793 #ifdef GDK_WINDOWING_WIN32
794 priv->nid.hIcon = gdk_win32_pixbuf_to_hicon_libgtk_only (gtk_status_icon_blank_icon (status_icon));
795 priv->nid.uFlags |= NIF_ICON;
796 if (priv->nid.hWnd != NULL && priv->visible)
797 if (!Shell_NotifyIconW (NIM_MODIFY, &priv->nid))
798 g_warning ("%s:%d:Shell_NotifyIcon(NIM_MODIFY) failed", __FILE__, __LINE__-1);
803 switch (priv->storage_type)
805 case GTK_IMAGE_PIXBUF:
809 pixbuf = priv->image_data.pixbuf;
820 width = gdk_pixbuf_get_width (pixbuf);
821 height = gdk_pixbuf_get_height (pixbuf);
823 if (width > size || height > size)
824 scaled = gdk_pixbuf_scale_simple (pixbuf,
827 GDK_INTERP_BILINEAR);
829 scaled = g_object_ref (pixbuf);
831 #ifdef GDK_WINDOWING_X11
832 gtk_image_set_from_pixbuf (GTK_IMAGE (priv->image), scaled);
834 #ifdef GDK_WINDOWING_WIN32
835 priv->nid.hIcon = gdk_win32_pixbuf_to_hicon_libgtk_only (scaled);
836 priv->nid.uFlags |= NIF_ICON;
837 if (priv->nid.hWnd != NULL && priv->visible)
838 if (!Shell_NotifyIconW (NIM_MODIFY, &priv->nid))
839 g_warning ("%s:%d:Shell_NotifyIcon(NIM_MODIFY) failed", __FILE__, __LINE__-1);
841 g_object_unref (scaled);
845 #ifdef GDK_WINDOWING_X11
846 gtk_image_set_from_pixbuf (GTK_IMAGE (priv->image), NULL);
848 #ifdef GDK_WINDOWING_WIN32
849 priv->nid.uFlags &= ~NIF_ICON;
850 if (priv->nid.hWnd != NULL && priv->visible)
851 if (!Shell_NotifyIconW (NIM_MODIFY, &priv->nid))
852 g_warning ("%s:%d:Shell_NotifyIcon(NIM_MODIFY) failed", __FILE__, __LINE__-1);
858 case GTK_IMAGE_STOCK:
860 #ifdef GDK_WINDOWING_X11
861 GtkIconSize size = find_icon_size (priv->image, priv->size);
862 gtk_image_set_from_stock (GTK_IMAGE (priv->image),
863 priv->image_data.stock_id,
866 #ifdef GDK_WINDOWING_WIN32
869 gtk_widget_render_icon (priv->dummy_widget,
870 priv->image_data.stock_id,
871 GTK_ICON_SIZE_SMALL_TOOLBAR,
873 priv->nid.hIcon = gdk_win32_pixbuf_to_hicon_libgtk_only (pixbuf);
874 priv->nid.uFlags |= NIF_ICON;
875 if (priv->nid.hWnd != NULL && priv->visible)
876 if (!Shell_NotifyIconW (NIM_MODIFY, &priv->nid))
877 g_warning ("%s:%d:Shell_NotifyIcon(NIM_MODIFY) failed", __FILE__, __LINE__-1);
878 g_object_unref (pixbuf);
884 case GTK_IMAGE_ICON_NAME:
886 #ifdef GDK_WINDOWING_X11
887 GtkIconSize size = find_icon_size (priv->image, priv->size);
888 gtk_image_set_from_icon_name (GTK_IMAGE (priv->image),
889 priv->image_data.icon_name,
892 #ifdef GDK_WINDOWING_WIN32
895 gtk_icon_theme_load_icon (gtk_icon_theme_get_default (),
896 priv->image_data.icon_name,
900 priv->nid.hIcon = gdk_win32_pixbuf_to_hicon_libgtk_only (pixbuf);
901 priv->nid.uFlags |= NIF_ICON;
902 if (priv->nid.hWnd != NULL && priv->visible)
903 if (!Shell_NotifyIconW (NIM_MODIFY, &priv->nid))
904 g_warning ("%s:%d:Shell_NotifyIcon(NIM_MODIFY) failed", __FILE__, __LINE__-1);
905 g_object_unref (pixbuf);
911 case GTK_IMAGE_EMPTY:
912 #ifdef GDK_WINDOWING_X11
913 gtk_image_set_from_pixbuf (GTK_IMAGE (priv->image), NULL);
915 #ifdef GDK_WINDOWING_WIN32
916 priv->nid.uFlags &= ~NIF_ICON;
917 if (priv->nid.hWnd != NULL && priv->visible)
918 if (!Shell_NotifyIconW (NIM_MODIFY, &priv->nid))
919 g_warning ("%s:%d:Shell_NotifyIcon(NIM_MODIFY) failed", __FILE__, __LINE__-1);
923 g_assert_not_reached ();
928 #ifdef GDK_WINDOWING_X11
931 gtk_status_icon_size_allocate (GtkStatusIcon *status_icon,
932 GtkAllocation *allocation)
934 GtkStatusIconPrivate *priv = status_icon->priv;
935 GtkOrientation orientation;
938 orientation = _gtk_tray_icon_get_orientation (GTK_TRAY_ICON (priv->tray_icon));
940 if (orientation == GTK_ORIENTATION_HORIZONTAL)
941 size = allocation->height;
943 size = allocation->width;
945 priv->image_width = allocation->width - GTK_MISC (priv->image)->xpad * 2;
946 priv->image_height = allocation->height - GTK_MISC (priv->image)->ypad * 2;
948 if (priv->size != size)
952 g_object_notify (G_OBJECT (status_icon), "size");
954 if (!emit_size_changed_signal (status_icon, size))
955 gtk_status_icon_update_image (status_icon);
962 gtk_status_icon_button_press (GtkStatusIcon *status_icon,
963 GdkEventButton *event)
965 if (event->button == 1 && event->type == GDK_BUTTON_PRESS)
967 emit_activate_signal (status_icon);
970 else if (event->button == 3 && event->type == GDK_BUTTON_PRESS)
972 emit_popup_menu_signal (status_icon, event->button, event->time);
980 gtk_status_icon_reset_image_data (GtkStatusIcon *status_icon)
982 GtkStatusIconPrivate *priv = status_icon->priv;
984 priv->storage_type = GTK_IMAGE_EMPTY;
985 g_object_notify (G_OBJECT (status_icon), "storage-type");
987 switch (priv->storage_type)
989 case GTK_IMAGE_PIXBUF:
990 if (priv->image_data.pixbuf)
991 g_object_unref (priv->image_data.pixbuf);
992 priv->image_data.pixbuf = NULL;
993 g_object_notify (G_OBJECT (status_icon), "pixbuf");
996 case GTK_IMAGE_STOCK:
997 g_free (priv->image_data.stock_id);
998 priv->image_data.stock_id = NULL;
1000 g_object_notify (G_OBJECT (status_icon), "stock");
1003 case GTK_IMAGE_ICON_NAME:
1004 g_free (priv->image_data.icon_name);
1005 priv->image_data.icon_name = NULL;
1007 g_object_notify (G_OBJECT (status_icon), "icon-name");
1010 case GTK_IMAGE_EMPTY:
1013 g_assert_not_reached ();
1019 gtk_status_icon_set_image (GtkStatusIcon *status_icon,
1020 GtkImageType storage_type,
1023 GtkStatusIconPrivate *priv = status_icon->priv;
1025 g_object_freeze_notify (G_OBJECT (status_icon));
1027 gtk_status_icon_reset_image_data (status_icon);
1029 priv->storage_type = storage_type;
1030 g_object_notify (G_OBJECT (status_icon), "storage-type");
1032 switch (storage_type)
1034 case GTK_IMAGE_PIXBUF:
1035 priv->image_data.pixbuf = (GdkPixbuf *)data;
1036 g_object_notify (G_OBJECT (status_icon), "pixbuf");
1038 case GTK_IMAGE_STOCK:
1039 priv->image_data.stock_id = g_strdup ((const gchar *)data);
1040 g_object_notify (G_OBJECT (status_icon), "stock");
1042 case GTK_IMAGE_ICON_NAME:
1043 priv->image_data.icon_name = g_strdup ((const gchar *)data);
1044 g_object_notify (G_OBJECT (status_icon), "icon-name");
1047 g_warning ("Image type %d not handled by GtkStatusIcon", storage_type);
1050 g_object_thaw_notify (G_OBJECT (status_icon));
1052 gtk_status_icon_update_image (status_icon);
1056 * gtk_status_icon_set_from_pixbuf:
1057 * @status_icon: a #GtkStatusIcon
1058 * @pixbuf: a #GdkPixbuf or %NULL
1060 * Makes @status_icon display @pixbuf.
1061 * See gtk_status_icon_new_from_pixbuf() for details.
1066 gtk_status_icon_set_from_pixbuf (GtkStatusIcon *status_icon,
1069 g_return_if_fail (GTK_IS_STATUS_ICON (status_icon));
1070 g_return_if_fail (pixbuf == NULL || GDK_IS_PIXBUF (pixbuf));
1073 g_object_ref (pixbuf);
1075 gtk_status_icon_set_image (status_icon, GTK_IMAGE_PIXBUF,
1080 * gtk_status_icon_set_from_file:
1081 * @status_icon: a #GtkStatusIcon
1082 * @filename: a filename
1084 * Makes @status_icon display the file @filename.
1085 * See gtk_status_icon_new_from_file() for details.
1090 gtk_status_icon_set_from_file (GtkStatusIcon *status_icon,
1091 const gchar *filename)
1095 g_return_if_fail (GTK_IS_STATUS_ICON (status_icon));
1096 g_return_if_fail (filename != NULL);
1098 pixbuf = gdk_pixbuf_new_from_file (filename, NULL);
1100 gtk_status_icon_set_from_pixbuf (status_icon, pixbuf);
1103 g_object_unref (pixbuf);
1107 * gtk_status_icon_set_from_stock:
1108 * @status_icon: a #GtkStatusIcon
1109 * @stock_id: a stock icon id
1111 * Makes @status_icon display the stock icon with the id @stock_id.
1112 * See gtk_status_icon_new_from_stock() for details.
1117 gtk_status_icon_set_from_stock (GtkStatusIcon *status_icon,
1118 const gchar *stock_id)
1120 g_return_if_fail (GTK_IS_STATUS_ICON (status_icon));
1121 g_return_if_fail (stock_id != NULL);
1123 gtk_status_icon_set_image (status_icon, GTK_IMAGE_STOCK,
1124 (gpointer) stock_id);
1128 * gtk_status_icon_set_from_icon_name:
1129 * @status_icon: a #GtkStatusIcon
1130 * @icon_name: an icon name
1132 * Makes @status_icon display the icon named @icon_name from the
1133 * current icon theme.
1134 * See gtk_status_icon_new_from_icon_name() for details.
1139 gtk_status_icon_set_from_icon_name (GtkStatusIcon *status_icon,
1140 const gchar *icon_name)
1142 g_return_if_fail (GTK_IS_STATUS_ICON (status_icon));
1143 g_return_if_fail (icon_name != NULL);
1145 gtk_status_icon_set_image (status_icon, GTK_IMAGE_ICON_NAME,
1146 (gpointer) icon_name);
1150 * gtk_status_icon_get_storage_type:
1151 * @status_icon: a #GtkStatusIcon
1153 * Gets the type of representation being used by the #GtkStatusIcon
1154 * to store image data. If the #GtkStatusIcon has no image data,
1155 * the return value will be %GTK_IMAGE_EMPTY.
1157 * Return value: the image representation being used
1162 gtk_status_icon_get_storage_type (GtkStatusIcon *status_icon)
1164 g_return_val_if_fail (GTK_IS_STATUS_ICON (status_icon), GTK_IMAGE_EMPTY);
1166 return status_icon->priv->storage_type;
1169 * gtk_status_icon_get_pixbuf:
1170 * @status_icon: a #GtkStatusIcon
1172 * Gets the #GdkPixbuf being displayed by the #GtkStatusIcon.
1173 * The storage type of the status icon must be %GTK_IMAGE_EMPTY or
1174 * %GTK_IMAGE_PIXBUF (see gtk_status_icon_get_storage_type()).
1175 * The caller of this function does not own a reference to the
1178 * Return value: the displayed pixbuf, or %NULL if the image is empty.
1183 gtk_status_icon_get_pixbuf (GtkStatusIcon *status_icon)
1185 GtkStatusIconPrivate *priv;
1187 g_return_val_if_fail (GTK_IS_STATUS_ICON (status_icon), NULL);
1189 priv = status_icon->priv;
1191 g_return_val_if_fail (priv->storage_type == GTK_IMAGE_PIXBUF ||
1192 priv->storage_type == GTK_IMAGE_EMPTY, NULL);
1194 if (priv->storage_type == GTK_IMAGE_EMPTY)
1195 priv->image_data.pixbuf = NULL;
1197 return priv->image_data.pixbuf;
1201 * gtk_status_icon_get_stock:
1202 * @status_icon: a #GtkStatusIcon
1204 * Gets the id of the stock icon being displayed by the #GtkStatusIcon.
1205 * The storage type of the status icon must be %GTK_IMAGE_EMPTY or
1206 * %GTK_IMAGE_STOCK (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: stock id of the displayed stock icon,
1211 * or %NULL if the image is empty.
1215 G_CONST_RETURN gchar *
1216 gtk_status_icon_get_stock (GtkStatusIcon *status_icon)
1218 GtkStatusIconPrivate *priv;
1220 g_return_val_if_fail (GTK_IS_STATUS_ICON (status_icon), NULL);
1222 priv = status_icon->priv;
1224 g_return_val_if_fail (priv->storage_type == GTK_IMAGE_STOCK ||
1225 priv->storage_type == GTK_IMAGE_EMPTY, NULL);
1227 if (priv->storage_type == GTK_IMAGE_EMPTY)
1228 priv->image_data.stock_id = NULL;
1230 return priv->image_data.stock_id;
1234 * gtk_status_icon_get_icon_name:
1235 * @status_icon: a #GtkStatusIcon
1237 * Gets the name of the icon being displayed by the #GtkStatusIcon.
1238 * The storage type of the status icon must be %GTK_IMAGE_EMPTY or
1239 * %GTK_IMAGE_ICON_NAME (see gtk_status_icon_get_storage_type()).
1240 * The returned string is owned by the #GtkStatusIcon and should not
1241 * be freed or modified.
1243 * Return value: name of the displayed icon, or %NULL if the image is empty.
1247 G_CONST_RETURN gchar *
1248 gtk_status_icon_get_icon_name (GtkStatusIcon *status_icon)
1250 GtkStatusIconPrivate *priv;
1252 g_return_val_if_fail (GTK_IS_STATUS_ICON (status_icon), NULL);
1254 priv = status_icon->priv;
1256 g_return_val_if_fail (priv->storage_type == GTK_IMAGE_ICON_NAME ||
1257 priv->storage_type == GTK_IMAGE_EMPTY, NULL);
1259 if (priv->storage_type == GTK_IMAGE_EMPTY)
1260 priv->image_data.icon_name = NULL;
1262 return priv->image_data.icon_name;
1266 * gtk_status_icon_get_size:
1267 * @status_icon: a #GtkStatusIcon
1269 * Gets the size in pixels that is available for the image.
1270 * Stock icons and named icons adapt their size automatically
1271 * if the size of the notification area changes. For other
1272 * storage types, the size-changed signal can be used to
1273 * react to size changes.
1275 * Return value: the size that is available for the image
1280 gtk_status_icon_get_size (GtkStatusIcon *status_icon)
1282 g_return_val_if_fail (GTK_IS_STATUS_ICON (status_icon), 0);
1284 return status_icon->priv->size;
1288 * gtk_status_icon_set_tooltip:
1289 * @status_icon: a #GtkStatusIcon
1290 * @tooltip_text: the tooltip text, or %NULL
1292 * Sets the tooltip of the status icon.
1297 gtk_status_icon_set_tooltip (GtkStatusIcon *status_icon,
1298 const gchar *tooltip_text)
1300 GtkStatusIconPrivate *priv;
1302 g_return_if_fail (GTK_IS_STATUS_ICON (status_icon));
1304 priv = status_icon->priv;
1306 #ifdef GDK_WINDOWING_X11
1307 gtk_tooltips_set_tip (priv->tooltips, priv->tray_icon,
1308 tooltip_text, NULL);
1310 #ifdef GDK_WINDOWING_WIN32
1311 if (tooltip_text == NULL)
1312 priv->nid.uFlags &= ~NIF_TIP;
1315 WCHAR *wcs = g_utf8_to_utf16 (tooltip_text, -1, NULL, NULL, NULL);
1317 priv->nid.uFlags |= NIF_TIP;
1318 wcsncpy (priv->nid.szTip, wcs, G_N_ELEMENTS (priv->nid.szTip) - 1);
1319 priv->nid.szTip[G_N_ELEMENTS (priv->nid.szTip) - 1] = 0;
1322 if (priv->nid.hWnd != NULL && priv->visible)
1323 if (!Shell_NotifyIconW (NIM_MODIFY, &priv->nid))
1324 g_warning ("%s:%d:Shell_NotifyIconW(NIM_MODIFY) failed", __FILE__, __LINE__-1);
1329 gtk_status_icon_blinker (GtkStatusIcon *status_icon)
1331 GtkStatusIconPrivate *priv = status_icon->priv;
1333 priv->blink_off = !priv->blink_off;
1335 gtk_status_icon_update_image (status_icon);
1341 gtk_status_icon_enable_blinking (GtkStatusIcon *status_icon)
1343 GtkStatusIconPrivate *priv = status_icon->priv;
1345 if (!priv->blinking_timeout)
1347 gtk_status_icon_blinker (status_icon);
1349 priv->blinking_timeout =
1350 g_timeout_add (BLINK_TIMEOUT,
1351 (GSourceFunc) gtk_status_icon_blinker,
1357 gtk_status_icon_disable_blinking (GtkStatusIcon *status_icon)
1359 GtkStatusIconPrivate *priv = status_icon->priv;
1361 if (priv->blinking_timeout)
1363 g_source_remove (priv->blinking_timeout);
1364 priv->blinking_timeout = 0;
1365 priv->blink_off = FALSE;
1367 gtk_status_icon_update_image (status_icon);
1372 * gtk_status_icon_set_visible:
1373 * @status_icon: a #GtkStatusIcon
1374 * @visible: %TRUE to show the status icon, %FALSE to hide it
1376 * Shows or hides a status icon.
1381 gtk_status_icon_set_visible (GtkStatusIcon *status_icon,
1384 GtkStatusIconPrivate *priv;
1386 g_return_if_fail (GTK_IS_STATUS_ICON (status_icon));
1388 priv = status_icon->priv;
1390 visible = visible != FALSE;
1392 if (priv->visible != visible)
1394 priv->visible = visible;
1396 #ifdef GDK_WINDOWING_X11
1398 gtk_widget_show (priv->tray_icon);
1400 gtk_widget_hide (priv->tray_icon);
1402 #ifdef GDK_WINDOWING_WIN32
1403 if (priv->nid.hWnd != NULL)
1406 Shell_NotifyIconW (NIM_ADD, &priv->nid);
1408 Shell_NotifyIconW (NIM_DELETE, &priv->nid);
1411 g_object_notify (G_OBJECT (status_icon), "visible");
1416 * gtk_status_icon_get_visible:
1417 * @status_icon: a #GtkStatusIcon
1419 * Returns whether the status icon is visible or not.
1420 * Note that being visible does not guarantee that
1421 * the user can actually see the icon, see also
1422 * gtk_status_icon_is_embedded().
1424 * Return value: %TRUE if the status icon is visible
1429 gtk_status_icon_get_visible (GtkStatusIcon *status_icon)
1431 g_return_val_if_fail (GTK_IS_STATUS_ICON (status_icon), FALSE);
1433 return status_icon->priv->visible;
1437 * gtk_status_icon_set_blinking:
1438 * @status_icon: a #GtkStatusIcon
1439 * @blinking: %TRUE to turn blinking on, %FALSE to turn it off
1441 * Makes the status icon start or stop blinking.
1442 * Note that blinking user interface elements may be problematic
1443 * for some users, and thus may be turned off, in which case
1444 * this setting has no effect.
1449 gtk_status_icon_set_blinking (GtkStatusIcon *status_icon,
1452 GtkStatusIconPrivate *priv;
1454 g_return_if_fail (GTK_IS_STATUS_ICON (status_icon));
1456 priv = status_icon->priv;
1458 blinking = blinking != FALSE;
1460 if (priv->blinking != blinking)
1462 priv->blinking = blinking;
1465 gtk_status_icon_enable_blinking (status_icon);
1467 gtk_status_icon_disable_blinking (status_icon);
1469 g_object_notify (G_OBJECT (status_icon), "blinking");
1474 * gtk_status_icon_get_blinking:
1475 * @status_icon: a #GtkStatusIcon
1477 * Returns whether the icon is blinking, see
1478 * gtk_status_icon_set_blinking().
1480 * Return value: %TRUE if the icon is blinking
1485 gtk_status_icon_get_blinking (GtkStatusIcon *status_icon)
1487 g_return_val_if_fail (GTK_IS_STATUS_ICON (status_icon), FALSE);
1489 return status_icon->priv->blinking;
1493 * gtk_status_icon_is_embedded:
1494 * @status_icon: a #GtkStatusIcon
1496 * Returns whether the status icon is embedded in a notification
1499 * Return value: %TRUE if the status icon is embedded in
1500 * a notification area.
1505 gtk_status_icon_is_embedded (GtkStatusIcon *status_icon)
1507 #ifdef GDK_WINDOWING_X11
1511 g_return_val_if_fail (GTK_IS_STATUS_ICON (status_icon), FALSE);
1513 #ifdef GDK_WINDOWING_X11
1514 plug = GTK_PLUG (status_icon->priv->tray_icon);
1516 if (plug->socket_window)
1521 #ifdef GDK_WINDOWING_WIN32
1527 * gtk_status_icon_position_menu:
1528 * @menu: the #GtkMenu
1529 * @x: return location for the x position
1530 * @y: return location for the y position
1531 * @push_in: return location for whether the menu should be pushed in
1532 * to be completely inside the screen instead of just clamped to the
1533 * size to the screen.
1534 * @user_data: the status icon to position the menu on
1536 * Menu positioning function to use with gtk_menu_popup()
1537 * to position @menu aligned to the status icon @user_data.
1542 gtk_status_icon_position_menu (GtkMenu *menu,
1548 #ifdef GDK_WINDOWING_X11
1549 GtkStatusIcon *status_icon;
1550 GtkStatusIconPrivate *priv;
1551 GtkTrayIcon *tray_icon;
1554 GtkTextDirection direction;
1555 GtkRequisition menu_req;
1556 GdkRectangle monitor;
1557 gint monitor_num, height, width, xoffset, yoffset;
1559 g_return_if_fail (GTK_IS_MENU (menu));
1560 g_return_if_fail (GTK_IS_STATUS_ICON (user_data));
1562 status_icon = GTK_STATUS_ICON (user_data);
1563 priv = status_icon->priv;
1564 tray_icon = GTK_TRAY_ICON (priv->tray_icon);
1565 widget = priv->tray_icon;
1567 direction = gtk_widget_get_direction (widget);
1569 screen = gtk_widget_get_screen (widget);
1570 gtk_menu_set_screen (menu, screen);
1572 monitor_num = gdk_screen_get_monitor_at_window (screen, widget->window);
1573 if (monitor_num < 0)
1575 gtk_menu_set_monitor (menu, monitor_num);
1577 gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor);
1579 gdk_window_get_origin (widget->window, x, y);
1581 gtk_widget_size_request (GTK_WIDGET (menu), &menu_req);
1583 if (_gtk_tray_icon_get_orientation (tray_icon) == GTK_ORIENTATION_VERTICAL)
1586 height = widget->allocation.height;
1587 xoffset = widget->allocation.width;
1592 width = widget->allocation.width;
1595 yoffset = widget->allocation.height;
1598 if (direction == GTK_TEXT_DIR_RTL)
1600 if ((*x - (menu_req.width - width)) >= monitor.x)
1601 *x -= menu_req.width - width;
1602 else if ((*x + xoffset + menu_req.width) < (monitor.x + monitor.width))
1604 else if ((monitor.x + monitor.width - (*x + xoffset)) < *x)
1605 *x -= menu_req.width - width;
1611 if ((*x + xoffset + menu_req.width) < (monitor.x + monitor.width))
1613 else if ((*x - (menu_req.width - width)) >= monitor.x)
1614 *x -= menu_req.width - width;
1615 else if ((monitor.x + monitor.width - (*x + xoffset)) > *x)
1618 *x -= menu_req.width - width;
1621 if ((*y + yoffset + menu_req.height) < (monitor.y + monitor.height))
1623 else if ((*y - (menu_req.height - height)) >= monitor.y)
1624 *y -= menu_req.height - height;
1625 else if (monitor.y + monitor.height - (*y + yoffset) > *y)
1628 *y -= menu_req.height - height;
1631 #endif /* GDK_WINDOWING_X11 */
1635 * gtk_status_icon_get_geometry:
1636 * @status_icon: a #GtkStatusIcon
1637 * @screen: return location for the screen
1638 * @area: return location for the area occupied by the status icon
1639 * @orientation: return location for the orientation of the panel
1640 * in which the status icon is embedded. A panel at the top or
1641 * bottom of the screen is horizontal, a panel at the left or
1642 * right is vertical.
1644 * Obtains information about the location of the status icon
1645 * on screen. This information can be used to e.g. position
1646 * popups like notification bubbles.
1647 * See gtk_status_icon_position_menu() for a more convenient
1648 * alternative for positioning menus.
1650 * Note that some platforms do not allow GTK+ to provide
1653 * Return value: %TRUE if the location information has
1659 gtk_status_icon_get_geometry (GtkStatusIcon *status_icon,
1662 GtkOrientation *orientation)
1664 #ifdef GDK_WINDOWING_X11
1666 GtkStatusIconPrivate *priv;
1669 g_return_if_fail (GTK_IS_STATUS_ICON (status_icon));
1671 priv = status_icon->priv;
1672 widget = priv->tray_icon;
1674 *screen = gtk_widget_get_screen (widget);
1675 gdk_window_get_origin (widget->window, &x, &y);
1678 area->width = widget->allocation.width;
1679 area->height = widget->allocation.height;
1680 *orientation = _gtk_tray_icon_get_orientation (GTK_TRAY_ICON (widget));
1685 #endif /* GDK_WINDOWING_X11 */
1689 #define __GTK_STATUS_ICON_C__
1690 #include "gtkaliasdef.c"