]> Pileus Git - ~andy/gtk/blob - gtk/gtkstatusicon.c
statusicon: fix the build on !X11
[~andy/gtk] / gtk / gtkstatusicon.c
1 /* gtkstatusicon.c:
2  *
3  * Copyright (C) 2003 Sun Microsystems, Inc.
4  * Copyright (C) 2005 Hans Breuer <hans@breuer.org>
5  * Copyright (C) 2005 Novell, Inc.
6  * Copyright (C) 2006 Imendio AB
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Library General Public
10  * License as published by the Free Software Foundation; either
11  * version 2 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Library General Public License for more details.
17  *
18  * You should have received a copy of the GNU Library General Public
19  * License along with this library; if not, write to the
20  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21  * Boston, MA 02111-1307, USA.
22  *
23  * Authors:
24  *      Mark McLoughlin <mark@skynet.ie>
25  *      Hans Breuer <hans@breuer.org>
26  *      Tor Lillqvist <tml@novell.com>
27  *      Mikael Hallendal <micke@imendio.com>
28  */
29
30 #include "config.h"
31
32 #include <string.h>
33
34 #include "gtkstatusicon.h"
35
36 #include "gtkintl.h"
37 #include "gtkiconfactory.h"
38 #include "gtkiconhelperprivate.h"
39 #include "gtkmain.h"
40 #include "gtkmarshalers.h"
41 #include "gtksizerequest.h"
42 #include "gtkprivate.h"
43 #include "gtkwidget.h"
44 #include "gtktooltip.h"
45 #include "gtkicontheme.h"
46 #include "gtklabel.h"
47 #include "gtktypebuiltins.h"
48
49 #ifdef GDK_WINDOWING_X11
50 #include "gdk/x11/gdkx.h"
51 #include "gtktrayicon.h"
52 #endif
53
54 #ifdef GDK_WINDOWING_WIN32
55 #include "gdk/win32/gdkwin32.h"
56 #define WM_GTK_TRAY_NOTIFICATION (WM_USER+1)
57 #endif
58
59
60 /**
61  * SECTION:gtkstatusicon
62  * @Short_description: Display an icon in the system tray
63  * @Title: GtkStatusIcon
64  *
65  * The "system tray" or notification area is normally used for transient icons
66  * that indicate some special state. For example, a system tray icon might
67  * appear to tell the user that they have new mail, or have an incoming instant
68  * message, or something along those lines. The basic idea is that creating an
69  * icon in the notification area is less annoying than popping up a dialog.
70  *
71  * A #GtkStatusIcon object can be used to display an icon in a "system tray".
72  * The icon can have a tooltip, and the user can interact with it by
73  * activating it or popping up a context menu. Critical information should
74  * not solely be displayed in a #GtkStatusIcon, since it may not be
75  * visible (e.g. when the user doesn't have a notification area on his panel).
76  * This can be checked with gtk_status_icon_is_embedded().
77  *
78  * On X11, the implementation follows the freedesktop.org "System Tray"
79  * <ulink url="http://www.freedesktop.org/wiki/Specifications/systemtray-spec">specification</ulink>.
80  * Implementations of the "tray" side of this specification can
81  * be found e.g. in the GNOME 2 and KDE panel applications.
82  *
83  * Note that a GtkStatusIcon is <emphasis>not</emphasis> a widget, but just
84  * a #GObject. Making it a widget would be impractical, since the system tray
85  * on Win32 doesn't allow to embed arbitrary widgets.
86  */
87
88
89 #define BLINK_TIMEOUT 500
90
91 enum
92 {
93   PROP_0,
94   PROP_PIXBUF,
95   PROP_FILE,
96   PROP_STOCK,
97   PROP_ICON_NAME,
98   PROP_GICON,
99   PROP_STORAGE_TYPE,
100   PROP_SIZE,
101   PROP_SCREEN,
102   PROP_VISIBLE,
103   PROP_ORIENTATION,
104   PROP_EMBEDDED,
105   PROP_BLINKING,
106   PROP_HAS_TOOLTIP,
107   PROP_TOOLTIP_TEXT,
108   PROP_TOOLTIP_MARKUP,
109   PROP_TITLE
110 };
111
112 enum 
113 {
114   ACTIVATE_SIGNAL,
115   POPUP_MENU_SIGNAL,
116   SIZE_CHANGED_SIGNAL,
117   BUTTON_PRESS_EVENT_SIGNAL,
118   BUTTON_RELEASE_EVENT_SIGNAL,
119   SCROLL_EVENT_SIGNAL,
120   QUERY_TOOLTIP_SIGNAL,
121   LAST_SIGNAL
122 };
123
124 static guint status_icon_signals [LAST_SIGNAL] = { 0 };
125
126 #ifdef GDK_WINDOWING_QUARTZ
127 #include "gtkstatusicon-quartz.c"
128 #endif
129
130 struct _GtkStatusIconPrivate
131 {
132 #ifdef GDK_WINDOWING_X11
133   GtkWidget    *tray_icon;
134   GtkWidget    *image;
135 #else
136   GtkWidget    *dummy_widget;
137 #endif
138
139 #ifdef GDK_WINDOWING_WIN32
140   NOTIFYICONDATAW nid;
141   gint          taskbar_top;
142   gint          last_click_x, last_click_y;
143   GtkOrientation orientation;
144   gchar         *tooltip_text;
145   gchar         *title;
146 #endif
147         
148 #ifdef GDK_WINDOWING_QUARTZ
149   GtkQuartzStatusIcon *status_item;
150   gchar         *tooltip_text;
151   gchar         *title;
152 #endif
153
154   gint           size;
155   GtkIconHelper *icon_helper;
156   guint          visible : 1;
157 };
158
159 static GObject* gtk_status_icon_constructor      (GType                  type,
160                                                   guint                  n_construct_properties,
161                                                   GObjectConstructParam *construct_params);
162 static void     gtk_status_icon_finalize         (GObject        *object);
163 static void     gtk_status_icon_set_property     (GObject        *object,
164                                                   guint           prop_id,
165                                                   const GValue   *value,
166                                                   GParamSpec     *pspec);
167 static void     gtk_status_icon_get_property     (GObject        *object,
168                                                   guint           prop_id,
169                                                   GValue         *value,
170                                                   GParamSpec     *pspec);
171
172 #ifdef GDK_WINDOWING_X11
173 static void     gtk_status_icon_size_allocate    (GtkStatusIcon  *status_icon,
174                                                   GtkAllocation  *allocation);
175 static void     gtk_status_icon_screen_changed   (GtkStatusIcon  *status_icon,
176                                                   GdkScreen      *old_screen);
177 static void     gtk_status_icon_embedded_changed (GtkStatusIcon *status_icon);
178 static void     gtk_status_icon_orientation_changed (GtkStatusIcon *status_icon);
179 static void     gtk_status_icon_padding_changed  (GtkStatusIcon *status_icon);
180 static void     gtk_status_icon_icon_size_changed(GtkStatusIcon *status_icon);
181 static void     gtk_status_icon_fg_changed       (GtkStatusIcon *status_icon);
182 static void     gtk_status_icon_color_changed    (GtkTrayIcon   *tray,
183                                                   GParamSpec    *pspec,
184                                                   GtkStatusIcon *status_icon);
185 static gboolean gtk_status_icon_scroll           (GtkStatusIcon  *status_icon,
186                                                   GdkEventScroll *event);
187 static gboolean gtk_status_icon_query_tooltip    (GtkStatusIcon *status_icon,
188                                                   gint           x,
189                                                   gint           y,
190                                                   gboolean       keyboard_tip,
191                                                   GtkTooltip    *tooltip);
192
193 static gboolean gtk_status_icon_key_press        (GtkStatusIcon  *status_icon,
194                                                   GdkEventKey    *event);
195 static void     gtk_status_icon_popup_menu       (GtkStatusIcon  *status_icon);
196 #endif
197 static gboolean gtk_status_icon_button_press     (GtkStatusIcon  *status_icon,
198                                                   GdkEventButton *event);
199 static gboolean gtk_status_icon_button_release   (GtkStatusIcon  *status_icon,
200                                                   GdkEventButton *event);
201 static void     gtk_status_icon_reset_image_data (GtkStatusIcon  *status_icon);
202 static void     gtk_status_icon_update_image    (GtkStatusIcon *status_icon);
203
204 G_DEFINE_TYPE (GtkStatusIcon, gtk_status_icon, G_TYPE_OBJECT)
205
206 static void
207 gtk_status_icon_class_init (GtkStatusIconClass *class)
208 {
209   GObjectClass *gobject_class = (GObjectClass *) class;
210
211   gobject_class->constructor  = gtk_status_icon_constructor;
212   gobject_class->finalize     = gtk_status_icon_finalize;
213   gobject_class->set_property = gtk_status_icon_set_property;
214   gobject_class->get_property = gtk_status_icon_get_property;
215
216   class->button_press_event   = NULL;
217   class->button_release_event = NULL;
218   class->scroll_event         = NULL;
219   class->query_tooltip        = NULL;
220
221   g_object_class_install_property (gobject_class,
222                                    PROP_PIXBUF,
223                                    g_param_spec_object ("pixbuf",
224                                                         P_("Pixbuf"),
225                                                         P_("A GdkPixbuf to display"),
226                                                         GDK_TYPE_PIXBUF,
227                                                         GTK_PARAM_READWRITE));
228
229   g_object_class_install_property (gobject_class,
230                                    PROP_FILE,
231                                    g_param_spec_string ("file",
232                                                         P_("Filename"),
233                                                         P_("Filename to load and display"),
234                                                         NULL,
235                                                         GTK_PARAM_WRITABLE));
236
237   g_object_class_install_property (gobject_class,
238                                    PROP_STOCK,
239                                    g_param_spec_string ("stock",
240                                                         P_("Stock ID"),
241                                                         P_("Stock ID for a stock image to display"),
242                                                         NULL,
243                                                         GTK_PARAM_READWRITE));
244   
245   g_object_class_install_property (gobject_class,
246                                    PROP_ICON_NAME,
247                                    g_param_spec_string ("icon-name",
248                                                         P_("Icon Name"),
249                                                         P_("The name of the icon from the icon theme"),
250                                                         NULL,
251                                                         GTK_PARAM_READWRITE));
252
253   /**
254    * GtkStatusIcon:gicon:
255    *
256    * The #GIcon displayed in the #GtkStatusIcon. For themed icons,
257    * the image will be updated automatically if the theme changes.
258    *
259    * Since: 2.14
260    */
261   g_object_class_install_property (gobject_class,
262                                    PROP_GICON,
263                                    g_param_spec_object ("gicon",
264                                                         P_("GIcon"),
265                                                         P_("The GIcon being displayed"),
266                                                         G_TYPE_ICON,
267                                                         GTK_PARAM_READWRITE));
268
269   g_object_class_install_property (gobject_class,
270                                    PROP_STORAGE_TYPE,
271                                    g_param_spec_enum ("storage-type",
272                                                       P_("Storage type"),
273                                                       P_("The representation being used for image data"),
274                                                       GTK_TYPE_IMAGE_TYPE,
275                                                       GTK_IMAGE_EMPTY,
276                                                       GTK_PARAM_READABLE));
277
278   g_object_class_install_property (gobject_class,
279                                    PROP_SIZE,
280                                    g_param_spec_int ("size",
281                                                      P_("Size"),
282                                                      P_("The size of the icon"),
283                                                      0,
284                                                      G_MAXINT,
285                                                      0,
286                                                      GTK_PARAM_READABLE));
287
288   g_object_class_install_property (gobject_class,
289                                    PROP_SCREEN,
290                                    g_param_spec_object ("screen",
291                                                         P_("Screen"),
292                                                         P_("The screen where this status icon will be displayed"),
293                                                         GDK_TYPE_SCREEN,
294                                                         GTK_PARAM_READWRITE));
295
296   g_object_class_install_property (gobject_class,
297                                    PROP_VISIBLE,
298                                    g_param_spec_boolean ("visible",
299                                                          P_("Visible"),
300                                                          P_("Whether the status icon is visible"),
301                                                          TRUE,
302                                                          GTK_PARAM_READWRITE));
303
304
305   /**
306    * GtkStatusIcon:embedded: 
307    *
308    * %TRUE if the statusicon is embedded in a notification area.
309    *
310    * Since: 2.12
311    */
312   g_object_class_install_property (gobject_class,
313                                    PROP_EMBEDDED,
314                                    g_param_spec_boolean ("embedded",
315                                                          P_("Embedded"),
316                                                          P_("Whether the status icon is embedded"),
317                                                          FALSE,
318                                                          GTK_PARAM_READABLE));
319
320   /**
321    * GtkStatusIcon:orientation:
322    *
323    * The orientation of the tray in which the statusicon 
324    * is embedded. 
325    *
326    * Since: 2.12
327    */
328   g_object_class_install_property (gobject_class,
329                                    PROP_ORIENTATION,
330                                    g_param_spec_enum ("orientation",
331                                                       P_("Orientation"),
332                                                       P_("The orientation of the tray"),
333                                                       GTK_TYPE_ORIENTATION,
334                                                       GTK_ORIENTATION_HORIZONTAL,
335                                                       GTK_PARAM_READABLE));
336
337 /**
338  * GtkStatusIcon:has-tooltip:
339  *
340  * Enables or disables the emission of #GtkStatusIcon::query-tooltip on
341  * @status_icon.  A value of %TRUE indicates that @status_icon can have a
342  * tooltip, in this case the status icon will be queried using
343  * #GtkStatusIcon::query-tooltip to determine whether it will provide a
344  * tooltip or not.
345  *
346  * Note that setting this property to %TRUE for the first time will change
347  * the event masks of the windows of this status icon to include leave-notify
348  * and motion-notify events. This will not be undone when the property is set
349  * to %FALSE again.
350  *
351  * Whether this property is respected is platform dependent.
352  * For plain text tooltips, use #GtkStatusIcon:tooltip-text in preference.
353  *
354  * Since: 2.16
355  */
356   g_object_class_install_property (gobject_class,
357                                    PROP_HAS_TOOLTIP,
358                                    g_param_spec_boolean ("has-tooltip",
359                                                          P_("Has tooltip"),
360                                                          P_("Whether this tray icon has a tooltip"),
361                                                          FALSE,
362                                                          GTK_PARAM_READWRITE));
363   /**
364    * GtkStatusIcon:tooltip-text:
365    *
366    * Sets the text of tooltip to be the given string.
367    *
368    * Also see gtk_tooltip_set_text().
369    *
370    * This is a convenience property which will take care of getting the
371    * tooltip shown if the given string is not %NULL.
372    * #GtkStatusIcon:has-tooltip will automatically be set to %TRUE and
373    * the default handler for the #GtkStatusIcon::query-tooltip signal
374    * will take care of displaying the tooltip.
375    *
376    * Note that some platforms have limitations on the length of tooltips
377    * that they allow on status icons, e.g. Windows only shows the first
378    * 64 characters.
379    *
380    * Since: 2.16
381    */
382   g_object_class_install_property (gobject_class,
383                                    PROP_TOOLTIP_TEXT,
384                                    g_param_spec_string ("tooltip-text",
385                                                         P_("Tooltip Text"),
386                                                         P_("The contents of the tooltip for this widget"),
387                                                         NULL,
388                                                         GTK_PARAM_READWRITE));
389   /**
390    * GtkStatusIcon:tooltip-markup:
391    *
392    * Sets the text of tooltip to be the given string, which is marked up
393    * with the <link linkend="PangoMarkupFormat">Pango text markup 
394    * language</link>. Also see gtk_tooltip_set_markup().
395    *
396    * This is a convenience property which will take care of getting the
397    * tooltip shown if the given string is not %NULL.
398    * #GtkStatusIcon:has-tooltip will automatically be set to %TRUE and
399    * the default handler for the #GtkStatusIcon::query-tooltip signal
400    * will take care of displaying the tooltip.
401    *
402    * On some platforms, embedded markup will be ignored.
403    *
404    * Since: 2.16
405    */
406   g_object_class_install_property (gobject_class,
407                                    PROP_TOOLTIP_MARKUP,
408                                    g_param_spec_string ("tooltip-markup",
409                                                         P_("Tooltip markup"),
410                                                         P_("The contents of the tooltip for this tray icon"),
411                                                         NULL,
412                                                         GTK_PARAM_READWRITE));
413
414
415   /**
416    * GtkStatusIcon:title:
417    *
418    * The title of this tray icon. This should be a short, human-readable,
419    * localized string describing the tray icon. It may be used by tools
420    * like screen readers to render the tray icon.
421    *
422    * Since: 2.18
423    */
424   g_object_class_install_property (gobject_class,
425                                    PROP_TITLE,
426                                    g_param_spec_string ("title",
427                                                         P_("Title"),
428                                                         P_("The title of this tray icon"),
429                                                         NULL,
430                                                         GTK_PARAM_READWRITE));
431
432   /**
433    * GtkStatusIcon::activate:
434    * @status_icon: the object which received the signal
435    *
436    * Gets emitted when the user activates the status icon. 
437    * If and how status icons can activated is platform-dependent.
438    *
439    * Unlike most G_SIGNAL_ACTION signals, this signal is meant to 
440    * be used by applications and should be wrapped by language bindings.
441    *
442    * Since: 2.10
443    */
444   status_icon_signals [ACTIVATE_SIGNAL] =
445     g_signal_new (I_("activate"),
446                   G_TYPE_FROM_CLASS (gobject_class),
447                   G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
448                   G_STRUCT_OFFSET (GtkStatusIconClass, activate),
449                   NULL,
450                   NULL,
451                   g_cclosure_marshal_VOID__VOID,
452                   G_TYPE_NONE,
453                   0);
454
455   /**
456    * GtkStatusIcon::popup-menu:
457    * @status_icon: the object which received the signal
458    * @button: the button that was pressed, or 0 if the 
459    *   signal is not emitted in response to a button press event
460    * @activate_time: the timestamp of the event that
461    *   triggered the signal emission
462    *
463    * Gets emitted when the user brings up the context menu
464    * of the status icon. Whether status icons can have context 
465    * menus and how these are activated is platform-dependent.
466    *
467    * The @button and @activate_time parameters should be 
468    * passed as the last to arguments to gtk_menu_popup().
469    *
470    * Unlike most G_SIGNAL_ACTION signals, this signal is meant to 
471    * be used by applications and should be wrapped by language bindings.
472    *
473    * Since: 2.10
474    */
475   status_icon_signals [POPUP_MENU_SIGNAL] =
476     g_signal_new (I_("popup-menu"),
477                   G_TYPE_FROM_CLASS (gobject_class),
478                   G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
479                   G_STRUCT_OFFSET (GtkStatusIconClass, popup_menu),
480                   NULL,
481                   NULL,
482                   _gtk_marshal_VOID__UINT_UINT,
483                   G_TYPE_NONE,
484                   2,
485                   G_TYPE_UINT,
486                   G_TYPE_UINT);
487
488   /**
489    * GtkStatusIcon::size-changed:
490    * @status_icon: the object which received the signal
491    * @size: the new size
492    *
493    * Gets emitted when the size available for the image
494    * changes, e.g. because the notification area got resized.
495    *
496    * Return value: %TRUE if the icon was updated for the new
497    * size. Otherwise, GTK+ will scale the icon as necessary.
498    *
499    * Since: 2.10
500    */
501   status_icon_signals [SIZE_CHANGED_SIGNAL] =
502     g_signal_new (I_("size-changed"),
503                   G_TYPE_FROM_CLASS (gobject_class),
504                   G_SIGNAL_RUN_LAST,
505                   G_STRUCT_OFFSET (GtkStatusIconClass, size_changed),
506                   g_signal_accumulator_true_handled,
507                   NULL,
508                   _gtk_marshal_BOOLEAN__INT,
509                   G_TYPE_BOOLEAN,
510                   1,
511                   G_TYPE_INT);
512
513   /**
514    * GtkStatusIcon::button-press-event:
515    * @status_icon: the object which received the signal
516    * @event: (type Gdk.EventButton): the #GdkEventButton which triggered 
517    *                                 this signal
518    *
519    * The ::button-press-event signal will be emitted when a button
520    * (typically from a mouse) is pressed.
521    *
522    * Whether this event is emitted is platform-dependent.  Use the ::activate
523    * and ::popup-menu signals in preference.
524    *
525    * Return value: %TRUE to stop other handlers from being invoked
526    * for the event. %FALSE to propagate the event further.
527    *
528    * Since: 2.14
529    */
530   status_icon_signals [BUTTON_PRESS_EVENT_SIGNAL] =
531     g_signal_new (I_("button_press_event"),
532                   G_TYPE_FROM_CLASS (gobject_class),
533                   G_SIGNAL_RUN_LAST,
534                   G_STRUCT_OFFSET (GtkStatusIconClass, button_press_event),
535                   g_signal_accumulator_true_handled, NULL,
536                   _gtk_marshal_BOOLEAN__BOXED,
537                   G_TYPE_BOOLEAN, 1,
538                   GDK_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
539
540   /**
541    * GtkStatusIcon::button-release-event:
542    * @status_icon: the object which received the signal
543    * @event: (type Gdk.EventButton): the #GdkEventButton which triggered 
544    *                                 this signal
545    *
546    * The ::button-release-event signal will be emitted when a button
547    * (typically from a mouse) is released.
548    *
549    * Whether this event is emitted is platform-dependent.  Use the ::activate
550    * and ::popup-menu signals in preference.
551    *
552    * Return value: %TRUE to stop other handlers from being invoked
553    * for the event. %FALSE to propagate the event further.
554    *
555    * Since: 2.14
556    */
557   status_icon_signals [BUTTON_RELEASE_EVENT_SIGNAL] =
558     g_signal_new (I_("button_release_event"),
559                   G_TYPE_FROM_CLASS (gobject_class),
560                   G_SIGNAL_RUN_LAST,
561                   G_STRUCT_OFFSET (GtkStatusIconClass, button_release_event),
562                   g_signal_accumulator_true_handled, NULL,
563                   _gtk_marshal_BOOLEAN__BOXED,
564                   G_TYPE_BOOLEAN, 1,
565                   GDK_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
566
567   /**
568    * GtkStatusIcon::scroll-event:
569    * @status_icon: the object which received the signal.
570    * @event: (type Gdk.EventScroll): the #GdkEventScroll which triggered 
571    *                                 this signal
572    *
573    * The ::scroll-event signal is emitted when a button in the 4 to 7
574    * range is pressed. Wheel mice are usually configured to generate
575    * button press events for buttons 4 and 5 when the wheel is turned.
576    *
577    * Whether this event is emitted is platform-dependent.
578    *
579    * Returns: %TRUE to stop other handlers from being invoked for the event.
580    *   %FALSE to propagate the event further.
581    *
582    * Since: 2.16
583    */
584   status_icon_signals[SCROLL_EVENT_SIGNAL] =
585     g_signal_new (I_("scroll_event"),
586                   G_TYPE_FROM_CLASS (gobject_class),
587                   G_SIGNAL_RUN_LAST,
588                   G_STRUCT_OFFSET (GtkStatusIconClass, scroll_event),
589                   g_signal_accumulator_true_handled, NULL,
590                   _gtk_marshal_BOOLEAN__BOXED,
591                   G_TYPE_BOOLEAN, 1,
592                   GDK_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
593
594   /**
595    * GtkStatusIcon::query-tooltip:
596    * @status_icon: the object which received the signal
597    * @x: the x coordinate of the cursor position where the request has been
598    *     emitted, relative to @status_icon
599    * @y: the y coordinate of the cursor position where the request has been
600    *     emitted, relative to @status_icon
601    * @keyboard_mode: %TRUE if the tooltip was trigged using the keyboard
602    * @tooltip: a #GtkTooltip
603    *
604    * Emitted when the #GtkSettings:gtk-tooltip-timeout has expired with the
605    * cursor hovering above @status_icon; or emitted when @status_icon got
606    * focus in keyboard mode.
607    *
608    * Using the given coordinates, the signal handler should determine
609    * whether a tooltip should be shown for @status_icon. If this is
610    * the case %TRUE should be returned, %FALSE otherwise. Note that if
611    * @keyboard_mode is %TRUE, the values of @x and @y are undefined and
612    * should not be used.
613    *
614    * The signal handler is free to manipulate @tooltip with the therefore
615    * destined function calls.
616    *
617    * Whether this signal is emitted is platform-dependent.
618    * For plain text tooltips, use #GtkStatusIcon:tooltip-text in preference.
619    *
620    * Returns: %TRUE if @tooltip should be shown right now, %FALSE otherwise.
621    *
622    * Since: 2.16
623    */
624   status_icon_signals [QUERY_TOOLTIP_SIGNAL] =
625     g_signal_new (I_("query_tooltip"),
626                   G_TYPE_FROM_CLASS (gobject_class),
627                   G_SIGNAL_RUN_LAST,
628                   G_STRUCT_OFFSET (GtkStatusIconClass, query_tooltip),
629                   g_signal_accumulator_true_handled, NULL,
630                   _gtk_marshal_BOOLEAN__INT_INT_BOOLEAN_OBJECT,
631                   G_TYPE_BOOLEAN, 4,
632                   G_TYPE_INT,
633                   G_TYPE_INT,
634                   G_TYPE_BOOLEAN,
635                   GTK_TYPE_TOOLTIP);
636
637   g_type_class_add_private (class, sizeof (GtkStatusIconPrivate));
638 }
639
640 #ifdef GDK_WINDOWING_WIN32
641
642 static void
643 build_button_event (GtkStatusIconPrivate *priv,
644                     GdkEventButton       *e,
645                     guint                 button)
646 {
647   POINT pos;
648   GdkRectangle monitor0;
649
650   /* We know that gdk/win32 puts the primary monitor at index 0 */
651   gdk_screen_get_monitor_geometry (gdk_screen_get_default (), 0, &monitor0);
652   e->window = g_object_ref (gdk_get_default_root_window ());
653   e->send_event = TRUE;
654   e->time = GetTickCount ();
655   GetCursorPos (&pos);
656   priv->last_click_x = e->x = pos.x + monitor0.x;
657   priv->last_click_y = e->y = pos.y + monitor0.y;
658   e->axes = NULL;
659   e->state = 0;
660   e->button = button;
661   //FIXME: e->device = gdk_display_get_default ()->core_pointer;
662   e->x_root = e->x;
663   e->y_root = e->y;
664 }
665
666 typedef struct
667 {
668   GtkStatusIcon *status_icon;
669   GdkEventButton *event;
670 } ButtonCallbackData;
671
672 static gboolean
673 button_callback (gpointer data)
674 {
675   ButtonCallbackData *bc = (ButtonCallbackData *) data;
676
677   if (bc->event->type == GDK_BUTTON_PRESS)
678     gtk_status_icon_button_press (bc->status_icon, bc->event);
679   else
680     gtk_status_icon_button_release (bc->status_icon, bc->event);
681
682   gdk_event_free ((GdkEvent *) bc->event);
683   g_free (data);
684
685   return FALSE;
686 }
687
688 static UINT taskbar_created_msg = 0;
689 static GSList *status_icons = NULL;
690
691 static LRESULT CALLBACK
692 wndproc (HWND   hwnd,
693          UINT   message,
694          WPARAM wparam,
695          LPARAM lparam)
696 {
697   if (message == taskbar_created_msg)
698     {
699       GSList *rover;
700
701       for (rover = status_icons; rover != NULL; rover = rover->next)
702         {
703           GtkStatusIcon *status_icon = GTK_STATUS_ICON (rover->data);
704           GtkStatusIconPrivate *priv = status_icon->priv;
705
706           priv->nid.hWnd = hwnd;
707           priv->nid.uID = GPOINTER_TO_UINT (status_icon);
708           priv->nid.uCallbackMessage = WM_GTK_TRAY_NOTIFICATION;
709           priv->nid.uFlags = NIF_MESSAGE;
710
711           if (!Shell_NotifyIconW (NIM_ADD, &priv->nid))
712             {
713               g_warning (G_STRLOC ": Shell_NotifyIcon(NIM_ADD) failed");
714               priv->nid.hWnd = NULL;
715               continue;
716             }
717
718           gtk_status_icon_update_image (status_icon);
719         }
720       return 0;
721     }
722
723   if (message == WM_GTK_TRAY_NOTIFICATION)
724     {
725       ButtonCallbackData *bc;
726       guint button;
727       
728       switch (lparam)
729         {
730         case WM_LBUTTONDOWN:
731           button = 1;
732           goto buttondown0;
733
734         case WM_MBUTTONDOWN:
735           button = 2;
736           goto buttondown0;
737
738         case WM_RBUTTONDOWN:
739           button = 3;
740           goto buttondown0;
741
742         case WM_XBUTTONDOWN:
743           if (HIWORD (wparam) == XBUTTON1)
744             button = 4;
745           else
746             button = 5;
747
748         buttondown0:
749           bc = g_new (ButtonCallbackData, 1);
750           bc->event = (GdkEventButton *) gdk_event_new (GDK_BUTTON_PRESS);
751           bc->status_icon = GTK_STATUS_ICON (wparam);
752           build_button_event (bc->status_icon->priv, bc->event, button);
753           g_idle_add (button_callback, bc);
754           break;
755
756         case WM_LBUTTONUP:
757           button = 1;
758           goto buttonup0;
759
760         case WM_MBUTTONUP:
761           button = 2;
762           goto buttonup0;
763
764         case WM_RBUTTONUP:
765           button = 3;
766           goto buttonup0;
767
768         case WM_XBUTTONUP:
769           if (HIWORD (wparam) == XBUTTON1)
770             button = 4;
771           else
772             button = 5;
773
774         buttonup0:
775           bc = g_new (ButtonCallbackData, 1);
776           bc->event = (GdkEventButton *) gdk_event_new (GDK_BUTTON_RELEASE);
777           bc->status_icon = GTK_STATUS_ICON (wparam);
778           build_button_event (bc->status_icon->priv, bc->event, button);
779           g_idle_add (button_callback, bc);
780           break;
781
782         default :
783           break;
784         }
785         return 0;
786     }
787   else
788     {
789       return DefWindowProc (hwnd, message, wparam, lparam);
790     }
791 }
792
793 static HWND
794 create_tray_observer (void)
795 {
796   WNDCLASS    wclass;
797   static HWND hwnd = NULL;
798   ATOM        klass;
799   HINSTANCE   hmodule = GetModuleHandle (NULL);
800
801   if (hwnd)
802     return hwnd;
803
804   taskbar_created_msg = RegisterWindowMessage("TaskbarCreated");
805
806   memset (&wclass, 0, sizeof(WNDCLASS));
807   wclass.lpszClassName = "gtkstatusicon-observer";
808   wclass.lpfnWndProc   = wndproc;
809   wclass.hInstance     = hmodule;
810
811   klass = RegisterClass (&wclass);
812   if (!klass)
813     return NULL;
814
815   hwnd = CreateWindow (MAKEINTRESOURCE (klass),
816                        NULL, WS_POPUP,
817                        0, 0, 1, 1, NULL, NULL,
818                        hmodule, NULL);
819   if (!hwnd)
820     {
821       UnregisterClass (MAKEINTRESOURCE(klass), hmodule);
822       return NULL;
823     }
824
825   return hwnd;
826 }
827
828 #endif
829
830 static void
831 gtk_status_icon_init (GtkStatusIcon *status_icon)
832 {
833   GtkStatusIconPrivate *priv;
834
835   priv = G_TYPE_INSTANCE_GET_PRIVATE (status_icon, GTK_TYPE_STATUS_ICON,
836                                       GtkStatusIconPrivate);
837   status_icon->priv = priv;
838
839   priv->icon_helper = _gtk_icon_helper_new ();
840   priv->visible      = TRUE;
841
842 #ifdef GDK_WINDOWING_X11
843   priv->size         = 0;
844   priv->tray_icon = GTK_WIDGET (_gtk_tray_icon_new (NULL));
845
846   gtk_widget_add_events (GTK_WIDGET (priv->tray_icon),
847                          GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
848                          GDK_SCROLL_MASK);
849
850   g_signal_connect_swapped (priv->tray_icon, "key-press-event",
851                             G_CALLBACK (gtk_status_icon_key_press), status_icon);
852   g_signal_connect_swapped (priv->tray_icon, "popup-menu",
853                             G_CALLBACK (gtk_status_icon_popup_menu), status_icon);
854   g_signal_connect_swapped (priv->tray_icon, "notify::embedded",
855                             G_CALLBACK (gtk_status_icon_embedded_changed), status_icon);
856   g_signal_connect_swapped (priv->tray_icon, "notify::orientation",
857                             G_CALLBACK (gtk_status_icon_orientation_changed), status_icon);
858   g_signal_connect_swapped (priv->tray_icon, "notify::padding",
859                             G_CALLBACK (gtk_status_icon_padding_changed), status_icon);
860   g_signal_connect_swapped (priv->tray_icon, "notify::icon-size",
861                             G_CALLBACK (gtk_status_icon_icon_size_changed), status_icon);
862   g_signal_connect_swapped (priv->tray_icon, "notify::fg-color",
863                             G_CALLBACK (gtk_status_icon_fg_changed), status_icon);
864   g_signal_connect (priv->tray_icon, "notify::error-color",
865                     G_CALLBACK (gtk_status_icon_color_changed), status_icon);
866   g_signal_connect (priv->tray_icon, "notify::warning-color",
867                     G_CALLBACK (gtk_status_icon_color_changed), status_icon);
868   g_signal_connect (priv->tray_icon, "notify::success-color",
869                     G_CALLBACK (gtk_status_icon_color_changed), status_icon);
870   g_signal_connect_swapped (priv->tray_icon, "button-press-event",
871                             G_CALLBACK (gtk_status_icon_button_press), status_icon);
872   g_signal_connect_swapped (priv->tray_icon, "button-release-event",
873                             G_CALLBACK (gtk_status_icon_button_release), status_icon);
874   g_signal_connect_swapped (priv->tray_icon, "scroll-event",
875                             G_CALLBACK (gtk_status_icon_scroll), status_icon);
876   g_signal_connect_swapped (priv->tray_icon, "query-tooltip",
877                             G_CALLBACK (gtk_status_icon_query_tooltip), status_icon);
878   g_signal_connect_swapped (priv->tray_icon, "screen-changed",
879                             G_CALLBACK (gtk_status_icon_screen_changed), status_icon);
880   priv->image = gtk_image_new ();
881   gtk_widget_set_can_focus (priv->image, TRUE);
882   gtk_container_add (GTK_CONTAINER (priv->tray_icon), priv->image);
883   gtk_widget_show (priv->image);
884
885   /* Force-initialize the symbolic colors */
886   g_object_notify (G_OBJECT (priv->tray_icon), "fg-color");
887   g_object_notify (G_OBJECT (priv->tray_icon), "error-color");
888   g_object_notify (G_OBJECT (priv->tray_icon), "warning-color");
889   g_object_notify (G_OBJECT (priv->tray_icon), "success-color");
890
891   g_signal_connect_swapped (priv->image, "size-allocate",
892                             G_CALLBACK (gtk_status_icon_size_allocate), status_icon);
893
894 #else /* !GDK_WINDOWING_X11 */
895   priv->dummy_widget = gtk_label_new ("");
896 #endif
897
898 #ifdef GDK_WINDOWING_WIN32
899
900   /* Get position and orientation of Windows taskbar. */
901   {
902     APPBARDATA abd;
903     
904     abd.cbSize = sizeof (abd);
905     SHAppBarMessage (ABM_GETTASKBARPOS, &abd);
906     if (abd.rc.bottom - abd.rc.top > abd.rc.right - abd.rc.left)
907       priv->orientation = GTK_ORIENTATION_VERTICAL;
908     else
909       priv->orientation = GTK_ORIENTATION_HORIZONTAL;
910
911     priv->taskbar_top = abd.rc.top;
912   }
913
914   priv->last_click_x = priv->last_click_y = 0;
915
916   /* Are the system tray icons always 16 pixels square? */
917   priv->size         = 16;
918
919   memset (&priv->nid, 0, sizeof (priv->nid));
920
921   priv->nid.hWnd = create_tray_observer ();
922   priv->nid.uID = GPOINTER_TO_UINT (status_icon);
923   priv->nid.uCallbackMessage = WM_GTK_TRAY_NOTIFICATION;
924   priv->nid.uFlags = NIF_MESSAGE;
925
926   /* To help win7 identify the icon create it with an application "unique" tip */
927   if (g_get_prgname ())
928   {
929     WCHAR *wcs = g_utf8_to_utf16 (g_get_prgname (), -1, NULL, NULL, NULL);
930
931     priv->nid.uFlags |= NIF_TIP;
932     wcsncpy (priv->nid.szTip, wcs, G_N_ELEMENTS (priv->nid.szTip) - 1);
933     priv->nid.szTip[G_N_ELEMENTS (priv->nid.szTip) - 1] = 0;
934     g_free (wcs);
935   }
936
937   if (!Shell_NotifyIconW (NIM_ADD, &priv->nid))
938     {
939       g_warning (G_STRLOC ": Shell_NotifyIcon(NIM_ADD) failed");
940       priv->nid.hWnd = NULL;
941     }
942
943   status_icons = g_slist_append (status_icons, status_icon);
944
945 #endif
946         
947 #ifdef GDK_WINDOWING_QUARTZ
948   QUARTZ_POOL_ALLOC;
949
950   priv->status_item = [[GtkQuartzStatusIcon alloc] initWithStatusIcon:status_icon];
951   priv->size = [priv->status_item getHeight];
952
953   QUARTZ_POOL_RELEASE;
954
955 #endif 
956 }
957
958 static GObject*
959 gtk_status_icon_constructor (GType                  type,
960                              guint                  n_construct_properties,
961                              GObjectConstructParam *construct_params)
962 {
963   GObject *object;
964 #ifdef GDK_WINDOWING_X11
965   GtkStatusIcon *status_icon;
966   GtkStatusIconPrivate *priv;
967 #endif
968
969   object = G_OBJECT_CLASS (gtk_status_icon_parent_class)->constructor (type,
970                                                                        n_construct_properties,
971                                                                        construct_params);
972
973 #ifdef GDK_WINDOWING_X11
974   status_icon = GTK_STATUS_ICON (object);
975   priv = status_icon->priv;
976   
977   if (priv->visible)
978     gtk_widget_show (priv->tray_icon);
979 #endif
980
981   return object;
982 }
983
984 static void
985 gtk_status_icon_finalize (GObject *object)
986 {
987   GtkStatusIcon *status_icon = GTK_STATUS_ICON (object);
988   GtkStatusIconPrivate *priv = status_icon->priv;
989
990   gtk_status_icon_reset_image_data (status_icon);
991   g_clear_object (&priv->icon_helper);
992
993 #ifdef GDK_WINDOWING_X11
994   g_signal_handlers_disconnect_by_func (priv->tray_icon,
995                                         gtk_status_icon_key_press, status_icon);
996   g_signal_handlers_disconnect_by_func (priv->tray_icon,
997                                         gtk_status_icon_popup_menu, status_icon);
998   g_signal_handlers_disconnect_by_func (priv->tray_icon,
999                                         gtk_status_icon_embedded_changed, status_icon);
1000   g_signal_handlers_disconnect_by_func (priv->tray_icon,
1001                                         gtk_status_icon_orientation_changed, status_icon);
1002   g_signal_handlers_disconnect_by_func (priv->tray_icon,
1003                                         gtk_status_icon_padding_changed, status_icon);
1004   g_signal_handlers_disconnect_by_func (priv->tray_icon,
1005                                         gtk_status_icon_icon_size_changed, status_icon);
1006   g_signal_handlers_disconnect_by_func (priv->tray_icon,
1007                                         gtk_status_icon_fg_changed, status_icon);
1008   g_signal_handlers_disconnect_by_func (priv->tray_icon,
1009                                         gtk_status_icon_color_changed, status_icon);
1010   g_signal_handlers_disconnect_by_func (priv->tray_icon,
1011                                         gtk_status_icon_button_press, status_icon);
1012   g_signal_handlers_disconnect_by_func (priv->tray_icon,
1013                                         gtk_status_icon_button_release, status_icon);
1014   g_signal_handlers_disconnect_by_func (priv->tray_icon,
1015                                         gtk_status_icon_scroll, status_icon);
1016   g_signal_handlers_disconnect_by_func (priv->tray_icon,
1017                                         gtk_status_icon_query_tooltip, status_icon);
1018   g_signal_handlers_disconnect_by_func (priv->tray_icon,
1019                                         gtk_status_icon_screen_changed, status_icon);
1020   gtk_widget_destroy (priv->image);
1021   gtk_widget_destroy (priv->tray_icon);
1022 #else /* !GDK_WINDOWING_X11 */
1023   gtk_widget_destroy (priv->dummy_widget);
1024 #endif
1025
1026 #ifdef GDK_WINDOWING_WIN32
1027   if (priv->nid.hWnd != NULL && priv->visible)
1028     Shell_NotifyIconW (NIM_DELETE, &priv->nid);
1029   if (priv->nid.hIcon)
1030     DestroyIcon (priv->nid.hIcon);
1031   g_free (priv->tooltip_text);
1032
1033   status_icons = g_slist_remove (status_icons, status_icon);
1034 #endif
1035         
1036 #ifdef GDK_WINDOWING_QUARTZ
1037   QUARTZ_POOL_ALLOC;
1038   [priv->status_item release];
1039   QUARTZ_POOL_RELEASE;
1040   g_free (priv->tooltip_text);
1041 #endif
1042
1043   G_OBJECT_CLASS (gtk_status_icon_parent_class)->finalize (object);
1044 }
1045
1046 static void
1047 gtk_status_icon_set_property (GObject      *object,
1048                               guint         prop_id,
1049                               const GValue *value,
1050                               GParamSpec   *pspec)
1051 {
1052   GtkStatusIcon *status_icon = GTK_STATUS_ICON (object);
1053
1054   switch (prop_id)
1055     {
1056     case PROP_PIXBUF:
1057       gtk_status_icon_set_from_pixbuf (status_icon, g_value_get_object (value));
1058       break;
1059     case PROP_FILE:
1060       gtk_status_icon_set_from_file (status_icon, g_value_get_string (value));
1061       break;
1062     case PROP_STOCK:
1063       gtk_status_icon_set_from_stock (status_icon, g_value_get_string (value));
1064       break;
1065     case PROP_ICON_NAME:
1066       gtk_status_icon_set_from_icon_name (status_icon, g_value_get_string (value));
1067       break;
1068     case PROP_GICON:
1069       gtk_status_icon_set_from_gicon (status_icon, g_value_get_object (value));
1070       break;
1071     case PROP_SCREEN:
1072       gtk_status_icon_set_screen (status_icon, g_value_get_object (value));
1073       break;
1074     case PROP_VISIBLE:
1075       gtk_status_icon_set_visible (status_icon, g_value_get_boolean (value));
1076       break;
1077     case PROP_HAS_TOOLTIP:
1078       gtk_status_icon_set_has_tooltip (status_icon, g_value_get_boolean (value));
1079       break;
1080     case PROP_TOOLTIP_TEXT:
1081       gtk_status_icon_set_tooltip_text (status_icon, g_value_get_string (value));
1082       break;
1083     case PROP_TOOLTIP_MARKUP:
1084       gtk_status_icon_set_tooltip_markup (status_icon, g_value_get_string (value));
1085       break;
1086     case PROP_TITLE:
1087       gtk_status_icon_set_title (status_icon, g_value_get_string (value));
1088       break;
1089     default:
1090       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1091       break;
1092     }
1093 }
1094
1095 static void
1096 gtk_status_icon_get_property (GObject    *object,
1097                               guint       prop_id,
1098                               GValue     *value,
1099                               GParamSpec *pspec)
1100 {
1101   GtkStatusIcon *status_icon = GTK_STATUS_ICON (object);
1102
1103   switch (prop_id)
1104     {
1105     case PROP_PIXBUF:
1106       g_value_set_object (value, gtk_status_icon_get_pixbuf (status_icon));
1107       break;
1108     case PROP_STOCK:
1109       g_value_set_string (value, gtk_status_icon_get_stock (status_icon));
1110       break;
1111     case PROP_ICON_NAME:
1112       g_value_set_string (value, gtk_status_icon_get_icon_name (status_icon));
1113       break;
1114     case PROP_GICON:
1115       g_value_set_object (value, gtk_status_icon_get_gicon (status_icon));
1116       break;
1117     case PROP_STORAGE_TYPE:
1118       g_value_set_enum (value, gtk_status_icon_get_storage_type (status_icon));
1119       break;
1120     case PROP_SIZE:
1121       g_value_set_int (value, gtk_status_icon_get_size (status_icon));
1122       break;
1123     case PROP_SCREEN:
1124       g_value_set_object (value, gtk_status_icon_get_screen (status_icon));
1125       break;
1126     case PROP_VISIBLE:
1127       g_value_set_boolean (value, gtk_status_icon_get_visible (status_icon));
1128       break;
1129     case PROP_EMBEDDED:
1130       g_value_set_boolean (value, gtk_status_icon_is_embedded (status_icon));
1131       break;
1132     case PROP_ORIENTATION:
1133 #ifdef GDK_WINDOWING_X11
1134       g_value_set_enum (value, _gtk_tray_icon_get_orientation (GTK_TRAY_ICON (status_icon->priv->tray_icon)));
1135 #endif
1136 #ifdef GDK_WINDOWING_WIN32
1137       g_value_set_enum (value, status_icon->priv->orientation);
1138 #endif
1139       break;
1140     case PROP_HAS_TOOLTIP:
1141       g_value_set_boolean (value, gtk_status_icon_get_has_tooltip (status_icon));
1142       break;
1143     case PROP_TOOLTIP_TEXT:
1144       g_value_set_string (value, gtk_status_icon_get_tooltip_text (status_icon));
1145       break;
1146     case PROP_TOOLTIP_MARKUP:
1147       g_value_set_string (value, gtk_status_icon_get_tooltip_markup (status_icon));
1148       break;
1149     case PROP_TITLE:
1150       g_value_set_string (value, gtk_status_icon_get_title (status_icon));
1151       break;
1152     default:
1153       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1154       break;
1155     }
1156 }
1157
1158 /**
1159  * gtk_status_icon_new:
1160  * 
1161  * Creates an empty status icon object.
1162  * 
1163  * Return value: a new #GtkStatusIcon
1164  *
1165  * Since: 2.10
1166  **/
1167 GtkStatusIcon *
1168 gtk_status_icon_new (void)
1169 {
1170   return g_object_new (GTK_TYPE_STATUS_ICON, NULL);
1171 }
1172
1173 /**
1174  * gtk_status_icon_new_from_pixbuf:
1175  * @pixbuf: a #GdkPixbuf
1176  * 
1177  * Creates a status icon displaying @pixbuf. 
1178  *
1179  * The image will be scaled down to fit in the available 
1180  * space in the notification area, if necessary.
1181  * 
1182  * Return value: a new #GtkStatusIcon
1183  *
1184  * Since: 2.10
1185  **/
1186 GtkStatusIcon *
1187 gtk_status_icon_new_from_pixbuf (GdkPixbuf *pixbuf)
1188 {
1189   return g_object_new (GTK_TYPE_STATUS_ICON,
1190                        "pixbuf", pixbuf,
1191                        NULL);
1192 }
1193
1194 /**
1195  * gtk_status_icon_new_from_file:
1196  * @filename: (type filename): a filename
1197  * 
1198  * Creates a status icon displaying the file @filename. 
1199  *
1200  * The image will be scaled down to fit in the available 
1201  * space in the notification area, if necessary.
1202  * 
1203  * Return value: a new #GtkStatusIcon
1204  *
1205  * Since: 2.10
1206  **/
1207 GtkStatusIcon *
1208 gtk_status_icon_new_from_file (const gchar *filename)
1209 {
1210   return g_object_new (GTK_TYPE_STATUS_ICON,
1211                        "file", filename,
1212                        NULL);
1213 }
1214
1215 /**
1216  * gtk_status_icon_new_from_stock:
1217  * @stock_id: a stock icon id
1218  * 
1219  * Creates a status icon displaying a stock icon. Sample stock icon
1220  * names are #GTK_STOCK_OPEN, #GTK_STOCK_QUIT. You can register your 
1221  * own stock icon names, see gtk_icon_factory_add_default() and 
1222  * gtk_icon_factory_add(). 
1223  *
1224  * Return value: a new #GtkStatusIcon
1225  *
1226  * Since: 2.10
1227  **/
1228 GtkStatusIcon *
1229 gtk_status_icon_new_from_stock (const gchar *stock_id)
1230 {
1231   return g_object_new (GTK_TYPE_STATUS_ICON,
1232                        "stock", stock_id,
1233                        NULL);
1234 }
1235
1236 /**
1237  * gtk_status_icon_new_from_icon_name:
1238  * @icon_name: an icon name
1239  * 
1240  * Creates a status icon displaying an icon from the current icon theme.
1241  * If the current icon theme is changed, the icon will be updated 
1242  * appropriately.
1243  * 
1244  * Return value: a new #GtkStatusIcon
1245  *
1246  * Since: 2.10
1247  **/
1248 GtkStatusIcon *
1249 gtk_status_icon_new_from_icon_name (const gchar *icon_name)
1250 {
1251   return g_object_new (GTK_TYPE_STATUS_ICON,
1252                        "icon-name", icon_name,
1253                        NULL);
1254 }
1255
1256 /**
1257  * gtk_status_icon_new_from_gicon:
1258  * @icon: a #GIcon
1259  *
1260  * Creates a status icon displaying a #GIcon. If the icon is a
1261  * themed icon, it will be updated when the theme changes.
1262  *
1263  * Return value: a new #GtkStatusIcon
1264  *
1265  * Since: 2.14
1266  **/
1267 GtkStatusIcon *
1268 gtk_status_icon_new_from_gicon (GIcon *icon)
1269 {
1270   return g_object_new (GTK_TYPE_STATUS_ICON,
1271                        "gicon", icon,
1272                        NULL);
1273 }
1274
1275 static void
1276 emit_activate_signal (GtkStatusIcon *status_icon)
1277 {
1278   g_signal_emit (status_icon,
1279                  status_icon_signals [ACTIVATE_SIGNAL], 0);
1280 }
1281
1282 static void
1283 emit_popup_menu_signal (GtkStatusIcon *status_icon,
1284                         guint          button,
1285                         guint32        activate_time)
1286 {
1287   g_signal_emit (status_icon,
1288                  status_icon_signals [POPUP_MENU_SIGNAL], 0,
1289                  button,
1290                  activate_time);
1291 }
1292
1293 #ifdef GDK_WINDOWING_X11
1294
1295 static gboolean
1296 emit_size_changed_signal (GtkStatusIcon *status_icon,
1297                           gint           size)
1298 {
1299   gboolean handled = FALSE;
1300   
1301   g_signal_emit (status_icon,
1302                  status_icon_signals [SIZE_CHANGED_SIGNAL], 0,
1303                  size,
1304                  &handled);
1305
1306   return handled;
1307 }
1308
1309 #endif
1310
1311 /* rounds the pixel size to the nearest size avaiable in the theme */
1312 static gint
1313 round_pixel_size (GtkWidget *widget, 
1314                   gint       pixel_size)
1315 {
1316   GdkScreen *screen;
1317   GtkSettings *settings;
1318   GtkIconSize s;
1319   gint w, h, d, dist, size;
1320
1321   screen = gtk_widget_get_screen (widget);
1322
1323   if (!screen)
1324     return GTK_ICON_SIZE_MENU;
1325
1326   settings = gtk_settings_get_for_screen (screen);
1327
1328   dist = G_MAXINT;
1329   size = 0;
1330
1331   for (s = GTK_ICON_SIZE_MENU; s <= GTK_ICON_SIZE_DIALOG; s++)
1332     {
1333       if (gtk_icon_size_lookup_for_settings (settings, s, &w, &h) &&
1334           w <= pixel_size && h <= pixel_size)
1335         {
1336           d = MAX (pixel_size - w, pixel_size - h);
1337           if (d < dist)
1338             {
1339               dist = d;
1340               size = MAX (w, h);
1341             }
1342         }
1343     }
1344   
1345   return size;
1346 }
1347
1348 static void
1349 gtk_status_icon_update_image (GtkStatusIcon *status_icon)
1350 {
1351   GtkStatusIconPrivate *priv = status_icon->priv;
1352 #ifdef GDK_WINDOWING_WIN32
1353   HICON prev_hicon;
1354 #endif
1355   GtkStyleContext *context;
1356   GtkWidget *widget;
1357   GtkImageType storage_type = _gtk_icon_helper_get_storage_type (priv->icon_helper);
1358   GdkPixbuf *pixbuf;
1359   gint round_size;
1360
1361 #ifdef GDK_WINDOWING_X11
1362   widget = priv->image;
1363 #else
1364   widget = priv->dummy_widget;
1365 #endif
1366
1367   context = gtk_widget_get_style_context (widget);
1368   round_size = round_pixel_size (widget, priv->size);
1369
1370   if (storage_type == GTK_IMAGE_PIXBUF)
1371     {
1372       GdkPixbuf *scaled;
1373       gint width;
1374       gint height;
1375
1376       pixbuf = _gtk_icon_helper_ensure_pixbuf (priv->icon_helper, context);
1377
1378       width  = gdk_pixbuf_get_width  (pixbuf);
1379       height = gdk_pixbuf_get_height (pixbuf);
1380
1381       if (width > round_size || height > round_size)
1382         {
1383           scaled = gdk_pixbuf_scale_simple (pixbuf,
1384                                             MIN (round_size, width),
1385                                             MIN (round_size, height),
1386                                             GDK_INTERP_BILINEAR);
1387           g_object_unref (pixbuf);
1388           pixbuf = scaled;
1389         }
1390     }
1391   else
1392     {
1393       _gtk_icon_helper_set_pixel_size (priv->icon_helper, round_size);
1394       pixbuf = _gtk_icon_helper_ensure_pixbuf (priv->icon_helper, context);
1395     }
1396
1397   if (pixbuf != NULL)
1398     {
1399 #ifdef GDK_WINDOWING_X11
1400       gtk_image_set_from_pixbuf (GTK_IMAGE (priv->image), pixbuf);
1401 #endif
1402 #ifdef GDK_WINDOWING_WIN32
1403       prev_hicon = priv->nid.hIcon;
1404       priv->nid.hIcon = gdk_win32_pixbuf_to_hicon_libgtk_only (pixbuf);
1405       priv->nid.uFlags |= NIF_ICON;
1406       if (priv->nid.hWnd != NULL && priv->visible)
1407         if (!Shell_NotifyIconW (NIM_MODIFY, &priv->nid))
1408           g_warning (G_STRLOC ": Shell_NotifyIcon(NIM_MODIFY) failed");
1409       if (prev_hicon)
1410         DestroyIcon (prev_hicon);
1411 #endif
1412 #ifdef GDK_WINDOWING_QUARTZ
1413       QUARTZ_POOL_ALLOC;
1414       [priv->status_item setImage:pixbuf];
1415       QUARTZ_POOL_RELEASE;
1416 #endif
1417     }
1418   else
1419     {
1420 #ifdef GDK_WINDOWING_X11
1421       gtk_image_set_from_pixbuf (GTK_IMAGE (priv->image), NULL);
1422 #endif
1423 #ifdef GDK_WINDOWING_WIN32
1424       priv->nid.uFlags &= ~NIF_ICON;
1425       if (priv->nid.hWnd != NULL && priv->visible)
1426         if (!Shell_NotifyIconW (NIM_MODIFY, &priv->nid))
1427           g_warning (G_STRLOC ": Shell_NotifyIcon(NIM_MODIFY) failed");
1428 #endif
1429 #ifdef GDK_WINDOWING_QUARTZ
1430       [priv->status_item setImage:NULL];
1431 #endif
1432     }
1433
1434   g_clear_object (&pixbuf);
1435 }
1436
1437 #ifdef GDK_WINDOWING_X11
1438
1439 static void
1440 gtk_status_icon_size_allocate (GtkStatusIcon *status_icon,
1441                                GtkAllocation *allocation)
1442 {
1443   GtkStatusIconPrivate *priv = status_icon->priv;
1444   GtkOrientation orientation;
1445   gint size;
1446
1447   orientation = _gtk_tray_icon_get_orientation (GTK_TRAY_ICON (priv->tray_icon));
1448
1449   if (orientation == GTK_ORIENTATION_HORIZONTAL)
1450     size = allocation->height;
1451   else
1452     size = allocation->width;
1453
1454   if (priv->size != size)
1455     {
1456       priv->size = size;
1457
1458       g_object_notify (G_OBJECT (status_icon), "size");
1459
1460       if (!emit_size_changed_signal (status_icon, size))
1461         gtk_status_icon_update_image (status_icon);
1462     }
1463 }
1464
1465 static void
1466 gtk_status_icon_screen_changed (GtkStatusIcon *status_icon,
1467                                 GdkScreen *old_screen)
1468 {
1469   GtkStatusIconPrivate *priv = status_icon->priv;
1470
1471   if (gtk_widget_get_screen (priv->tray_icon) != old_screen)
1472     {
1473       g_object_notify (G_OBJECT (status_icon), "screen");
1474     }
1475 }
1476
1477 #endif
1478
1479 #ifdef GDK_WINDOWING_X11
1480
1481 static void
1482 gtk_status_icon_padding_changed (GtkStatusIcon *status_icon)
1483 {
1484   GtkStatusIconPrivate *priv = status_icon->priv;
1485   GtkOrientation orientation;
1486   gint padding;
1487
1488   orientation = _gtk_tray_icon_get_orientation (GTK_TRAY_ICON (priv->tray_icon));
1489   padding = _gtk_tray_icon_get_padding (GTK_TRAY_ICON (priv->tray_icon));
1490
1491   if (orientation == GTK_ORIENTATION_HORIZONTAL)
1492     {
1493       gtk_widget_set_margin_left (priv->image, padding);
1494       gtk_widget_set_margin_right (priv->image, padding);
1495     }
1496   else
1497     {
1498       gtk_widget_set_margin_bottom (priv->image, padding);
1499       gtk_widget_set_margin_top (priv->image, padding);
1500     }
1501 }
1502
1503 static void
1504 gtk_status_icon_icon_size_changed (GtkStatusIcon *status_icon)
1505 {
1506   GtkStatusIconPrivate *priv = status_icon->priv;
1507   gint icon_size;
1508
1509   icon_size = _gtk_tray_icon_get_icon_size (GTK_TRAY_ICON (priv->tray_icon));
1510
1511   if (icon_size != 0)
1512     gtk_image_set_pixel_size (GTK_IMAGE (priv->image), icon_size);
1513   else
1514     gtk_image_set_pixel_size (GTK_IMAGE (priv->image), -1);
1515 }
1516
1517 static void
1518 gtk_status_icon_embedded_changed (GtkStatusIcon *status_icon)
1519 {
1520   gtk_status_icon_padding_changed (status_icon);
1521   gtk_status_icon_icon_size_changed (status_icon);
1522   g_object_notify (G_OBJECT (status_icon), "embedded");
1523 }
1524
1525 static void
1526 gtk_status_icon_orientation_changed (GtkStatusIcon *status_icon)
1527 {
1528   gtk_status_icon_padding_changed (status_icon);
1529   g_object_notify (G_OBJECT (status_icon), "orientation");
1530 }
1531
1532 static void
1533 gtk_status_icon_fg_changed (GtkStatusIcon *status_icon)
1534 {
1535   GtkStatusIconPrivate *priv = status_icon->priv;
1536   GdkRGBA *rgba;
1537
1538   g_object_get (priv->tray_icon, "fg-color", &rgba, NULL);
1539
1540   gtk_widget_override_color (priv->image, GTK_STATE_FLAG_NORMAL, rgba);
1541
1542   gdk_rgba_free (rgba);
1543 }
1544
1545 static void
1546 gtk_status_icon_color_changed (GtkTrayIcon   *tray,
1547                                GParamSpec    *pspec,
1548                                GtkStatusIcon *status_icon)
1549 {
1550   GtkStatusIconPrivate *priv = status_icon->priv;
1551   const gchar *name;
1552
1553   switch (pspec->name[0])
1554     {
1555     case 'e':
1556       name = "error";
1557       break;
1558     case 'w':
1559       name = "warning";
1560       break;
1561     case 's':
1562       name = "success";
1563       break;
1564     default:
1565       name = NULL;
1566       break;
1567     }
1568
1569   if (name)
1570     {
1571       GdkRGBA rgba;
1572
1573       g_object_get (priv->tray_icon, pspec->name, &rgba, NULL);
1574
1575       rgba.alpha = 1;
1576
1577       gtk_widget_override_symbolic_color (priv->image, name, &rgba);
1578     }
1579 }
1580
1581 static gboolean
1582 gtk_status_icon_key_press (GtkStatusIcon  *status_icon,
1583                            GdkEventKey    *event)
1584 {
1585   guint state, keyval;
1586
1587   state = event->state & gtk_accelerator_get_default_mod_mask ();
1588   keyval = event->keyval;
1589   if (state == 0 &&
1590       (keyval == GDK_KEY_Return ||
1591        keyval == GDK_KEY_KP_Enter ||
1592        keyval == GDK_KEY_ISO_Enter ||
1593        keyval == GDK_KEY_space ||
1594        keyval == GDK_KEY_KP_Space))
1595     {
1596       emit_activate_signal (status_icon);
1597       return TRUE;
1598     }
1599
1600   return FALSE;
1601 }
1602
1603 static void
1604 gtk_status_icon_popup_menu (GtkStatusIcon  *status_icon)
1605 {
1606   emit_popup_menu_signal (status_icon, 0, gtk_get_current_event_time ());
1607 }
1608
1609 #endif
1610
1611 static gboolean
1612 gtk_status_icon_button_press (GtkStatusIcon  *status_icon,
1613                               GdkEventButton *event)
1614 {
1615   gboolean handled = FALSE;
1616
1617   g_signal_emit (status_icon,
1618                  status_icon_signals [BUTTON_PRESS_EVENT_SIGNAL], 0,
1619                  event, &handled);
1620   if (handled)
1621     return TRUE;
1622
1623   if (gdk_event_triggers_context_menu ((GdkEvent *) event))
1624     {
1625       emit_popup_menu_signal (status_icon, event->button, event->time);
1626       return TRUE;
1627     }
1628   else if (event->button == 1 && event->type == GDK_BUTTON_PRESS)
1629     {
1630       emit_activate_signal (status_icon);
1631       return TRUE;
1632     }
1633
1634   return FALSE;
1635 }
1636
1637 static gboolean
1638 gtk_status_icon_button_release (GtkStatusIcon  *status_icon,
1639                                 GdkEventButton *event)
1640 {
1641   gboolean handled = FALSE;
1642   g_signal_emit (status_icon,
1643                  status_icon_signals [BUTTON_RELEASE_EVENT_SIGNAL], 0,
1644                  event, &handled);
1645   return handled;
1646 }
1647
1648 #ifdef GDK_WINDOWING_X11
1649 static gboolean
1650 gtk_status_icon_scroll (GtkStatusIcon  *status_icon,
1651                         GdkEventScroll *event)
1652 {
1653   gboolean handled = FALSE;
1654   g_signal_emit (status_icon,
1655                  status_icon_signals [SCROLL_EVENT_SIGNAL], 0,
1656                  event, &handled);
1657   return handled;
1658 }
1659
1660 static gboolean
1661 gtk_status_icon_query_tooltip (GtkStatusIcon *status_icon,
1662                                gint           x,
1663                                gint           y,
1664                                gboolean       keyboard_tip,
1665                                GtkTooltip    *tooltip)
1666 {
1667   gboolean handled = FALSE;
1668   g_signal_emit (status_icon,
1669                  status_icon_signals [QUERY_TOOLTIP_SIGNAL], 0,
1670                  x, y, keyboard_tip, tooltip, &handled);
1671   return handled;
1672 }
1673 #endif /* GDK_WINDOWING_X11 */
1674
1675 static void
1676 gtk_status_icon_reset_image_data (GtkStatusIcon *status_icon)
1677 {
1678   GtkStatusIconPrivate *priv = status_icon->priv;
1679   GtkImageType storage_type = _gtk_icon_helper_get_storage_type (priv->icon_helper);
1680
1681   switch (storage_type)
1682   {
1683     case GTK_IMAGE_PIXBUF:
1684       g_object_notify (G_OBJECT (status_icon), "pixbuf");
1685       break;
1686     case GTK_IMAGE_STOCK:
1687       g_object_notify (G_OBJECT (status_icon), "stock");
1688       break;    
1689     case GTK_IMAGE_ICON_NAME:
1690       g_object_notify (G_OBJECT (status_icon), "icon-name");
1691       break;
1692     case GTK_IMAGE_GICON:
1693       g_object_notify (G_OBJECT (status_icon), "gicon");
1694       break;
1695     case GTK_IMAGE_EMPTY:
1696       break;
1697     default:
1698       g_assert_not_reached ();
1699       break;
1700   }
1701
1702   _gtk_icon_helper_clear (priv->icon_helper);
1703   g_object_notify (G_OBJECT (status_icon), "storage-type");
1704 }
1705
1706 static void
1707 gtk_status_icon_set_image (GtkStatusIcon *status_icon,
1708                            GtkImageType   storage_type,
1709                            gpointer       data)
1710 {
1711   GtkStatusIconPrivate *priv = status_icon->priv;
1712
1713   g_object_freeze_notify (G_OBJECT (status_icon));
1714
1715   gtk_status_icon_reset_image_data (status_icon);
1716
1717   g_object_notify (G_OBJECT (status_icon), "storage-type");
1718
1719   /* the icon size we pass here doesn't really matter, since
1720    * we force a pixel size before doing the actual rendering anyway.
1721    */
1722   switch (storage_type) 
1723     {
1724     case GTK_IMAGE_PIXBUF:
1725       _gtk_icon_helper_set_pixbuf (priv->icon_helper, data);
1726       g_object_notify (G_OBJECT (status_icon), "pixbuf");
1727       break;
1728     case GTK_IMAGE_STOCK:
1729       _gtk_icon_helper_set_stock_id (priv->icon_helper, data, GTK_ICON_SIZE_SMALL_TOOLBAR);
1730       g_object_notify (G_OBJECT (status_icon), "stock");
1731       break;
1732     case GTK_IMAGE_ICON_NAME:
1733       _gtk_icon_helper_set_icon_name (priv->icon_helper, data, GTK_ICON_SIZE_SMALL_TOOLBAR);
1734       g_object_notify (G_OBJECT (status_icon), "icon-name");
1735       break;
1736     case GTK_IMAGE_GICON:
1737       _gtk_icon_helper_set_gicon (priv->icon_helper, data, GTK_ICON_SIZE_SMALL_TOOLBAR);
1738       g_object_notify (G_OBJECT (status_icon), "gicon");
1739       break;
1740     default:
1741       g_warning ("Image type %u not handled by GtkStatusIcon", storage_type);
1742     }
1743
1744   g_object_thaw_notify (G_OBJECT (status_icon));
1745
1746   gtk_status_icon_update_image (status_icon);
1747 }
1748
1749 /**
1750  * gtk_status_icon_set_from_pixbuf:
1751  * @status_icon: a #GtkStatusIcon
1752  * @pixbuf: (allow-none): a #GdkPixbuf or %NULL
1753  *
1754  * Makes @status_icon display @pixbuf.
1755  * See gtk_status_icon_new_from_pixbuf() for details.
1756  *
1757  * Since: 2.10
1758  **/
1759 void
1760 gtk_status_icon_set_from_pixbuf (GtkStatusIcon *status_icon,
1761                                  GdkPixbuf     *pixbuf)
1762 {
1763   g_return_if_fail (GTK_IS_STATUS_ICON (status_icon));
1764   g_return_if_fail (pixbuf == NULL || GDK_IS_PIXBUF (pixbuf));
1765
1766   gtk_status_icon_set_image (status_icon, GTK_IMAGE_PIXBUF,
1767                              (gpointer) pixbuf);
1768 }
1769
1770 /**
1771  * gtk_status_icon_set_from_file:
1772  * @status_icon: a #GtkStatusIcon
1773  * @filename: (type filename): a filename
1774  * 
1775  * Makes @status_icon display the file @filename.
1776  * See gtk_status_icon_new_from_file() for details.
1777  *
1778  * Since: 2.10 
1779  **/
1780 void
1781 gtk_status_icon_set_from_file (GtkStatusIcon *status_icon,
1782                                const gchar   *filename)
1783 {
1784   GdkPixbuf *pixbuf;
1785   
1786   g_return_if_fail (GTK_IS_STATUS_ICON (status_icon));
1787   g_return_if_fail (filename != NULL);
1788   
1789   pixbuf = gdk_pixbuf_new_from_file (filename, NULL);
1790   
1791   gtk_status_icon_set_from_pixbuf (status_icon, pixbuf);
1792   
1793   if (pixbuf)
1794     g_object_unref (pixbuf);
1795 }
1796
1797 /**
1798  * gtk_status_icon_set_from_stock:
1799  * @status_icon: a #GtkStatusIcon
1800  * @stock_id: a stock icon id
1801  * 
1802  * Makes @status_icon display the stock icon with the id @stock_id.
1803  * See gtk_status_icon_new_from_stock() for details.
1804  *
1805  * Since: 2.10 
1806  **/
1807 void
1808 gtk_status_icon_set_from_stock (GtkStatusIcon *status_icon,
1809                                 const gchar   *stock_id)
1810 {
1811   g_return_if_fail (GTK_IS_STATUS_ICON (status_icon));
1812   g_return_if_fail (stock_id != NULL);
1813
1814   gtk_status_icon_set_image (status_icon, GTK_IMAGE_STOCK,
1815                              (gpointer) stock_id);
1816 }
1817
1818 /**
1819  * gtk_status_icon_set_from_icon_name:
1820  * @status_icon: a #GtkStatusIcon
1821  * @icon_name: an icon name
1822  * 
1823  * Makes @status_icon display the icon named @icon_name from the 
1824  * current icon theme.
1825  * See gtk_status_icon_new_from_icon_name() for details.
1826  *
1827  * Since: 2.10 
1828  **/
1829 void
1830 gtk_status_icon_set_from_icon_name (GtkStatusIcon *status_icon,
1831                                     const gchar   *icon_name)
1832 {
1833   g_return_if_fail (GTK_IS_STATUS_ICON (status_icon));
1834   g_return_if_fail (icon_name != NULL);
1835
1836   gtk_status_icon_set_image (status_icon, GTK_IMAGE_ICON_NAME,
1837                              (gpointer) icon_name);
1838 }
1839
1840 /**
1841  * gtk_status_icon_set_from_gicon:
1842  * @status_icon: a #GtkStatusIcon
1843  * @icon: a GIcon
1844  *
1845  * Makes @status_icon display the #GIcon.
1846  * See gtk_status_icon_new_from_gicon() for details.
1847  *
1848  * Since: 2.14
1849  **/
1850 void
1851 gtk_status_icon_set_from_gicon (GtkStatusIcon *status_icon,
1852                                 GIcon         *icon)
1853 {
1854   g_return_if_fail (GTK_IS_STATUS_ICON (status_icon));
1855   g_return_if_fail (icon != NULL);
1856
1857   gtk_status_icon_set_image (status_icon, GTK_IMAGE_GICON,
1858                              (gpointer) icon);
1859 }
1860
1861 /**
1862  * gtk_status_icon_get_storage_type:
1863  * @status_icon: a #GtkStatusIcon
1864  * 
1865  * Gets the type of representation being used by the #GtkStatusIcon
1866  * to store image data. If the #GtkStatusIcon has no image data,
1867  * the return value will be %GTK_IMAGE_EMPTY. 
1868  * 
1869  * Return value: the image representation being used
1870  *
1871  * Since: 2.10
1872  **/
1873 GtkImageType
1874 gtk_status_icon_get_storage_type (GtkStatusIcon *status_icon)
1875 {
1876   g_return_val_if_fail (GTK_IS_STATUS_ICON (status_icon), GTK_IMAGE_EMPTY);
1877
1878   return _gtk_icon_helper_get_storage_type (status_icon->priv->icon_helper);
1879 }
1880 /**
1881  * gtk_status_icon_get_pixbuf:
1882  * @status_icon: a #GtkStatusIcon
1883  * 
1884  * Gets the #GdkPixbuf being displayed by the #GtkStatusIcon.
1885  * The storage type of the status icon must be %GTK_IMAGE_EMPTY or
1886  * %GTK_IMAGE_PIXBUF (see gtk_status_icon_get_storage_type()).
1887  * The caller of this function does not own a reference to the
1888  * returned pixbuf.
1889  * 
1890  * Return value: (transfer none): the displayed pixbuf,
1891  *     or %NULL if the image is empty.
1892  *
1893  * Since: 2.10
1894  **/
1895 GdkPixbuf *
1896 gtk_status_icon_get_pixbuf (GtkStatusIcon *status_icon)
1897 {
1898   GtkStatusIconPrivate *priv;
1899
1900   g_return_val_if_fail (GTK_IS_STATUS_ICON (status_icon), NULL);
1901
1902   priv = status_icon->priv;
1903
1904   return _gtk_icon_helper_peek_pixbuf (priv->icon_helper);
1905 }
1906
1907 /**
1908  * gtk_status_icon_get_stock:
1909  * @status_icon: a #GtkStatusIcon
1910  * 
1911  * Gets the id of the stock icon being displayed by the #GtkStatusIcon.
1912  * The storage type of the status icon must be %GTK_IMAGE_EMPTY or
1913  * %GTK_IMAGE_STOCK (see gtk_status_icon_get_storage_type()).
1914  * The returned string is owned by the #GtkStatusIcon and should not
1915  * be freed or modified.
1916  * 
1917  * Return value: stock id of the displayed stock icon,
1918  *   or %NULL if the image is empty.
1919  *
1920  * Since: 2.10
1921  **/
1922 const gchar *
1923 gtk_status_icon_get_stock (GtkStatusIcon *status_icon)
1924 {
1925   GtkStatusIconPrivate *priv;
1926
1927   g_return_val_if_fail (GTK_IS_STATUS_ICON (status_icon), NULL);
1928
1929   priv = status_icon->priv;
1930
1931   return _gtk_icon_helper_get_stock_id (priv->icon_helper);
1932 }
1933
1934 /**
1935  * gtk_status_icon_get_icon_name:
1936  * @status_icon: a #GtkStatusIcon
1937  * 
1938  * Gets the name of the icon being displayed by the #GtkStatusIcon.
1939  * The storage type of the status icon must be %GTK_IMAGE_EMPTY or
1940  * %GTK_IMAGE_ICON_NAME (see gtk_status_icon_get_storage_type()).
1941  * The returned string is owned by the #GtkStatusIcon and should not
1942  * be freed or modified.
1943  * 
1944  * Return value: name of the displayed icon, or %NULL if the image is empty.
1945  *
1946  * Since: 2.10
1947  **/
1948 const gchar *
1949 gtk_status_icon_get_icon_name (GtkStatusIcon *status_icon)
1950 {
1951   GtkStatusIconPrivate *priv;
1952   
1953   g_return_val_if_fail (GTK_IS_STATUS_ICON (status_icon), NULL);
1954
1955   priv = status_icon->priv;
1956
1957   return _gtk_icon_helper_get_icon_name (priv->icon_helper);
1958 }
1959
1960 /**
1961  * gtk_status_icon_get_gicon:
1962  * @status_icon: a #GtkStatusIcon
1963  *
1964  * Retrieves the #GIcon being displayed by the #GtkStatusIcon.
1965  * The storage type of the status icon must be %GTK_IMAGE_EMPTY or
1966  * %GTK_IMAGE_GICON (see gtk_status_icon_get_storage_type()).
1967  * The caller of this function does not own a reference to the
1968  * returned #GIcon.
1969  *
1970  * If this function fails, @icon is left unchanged;
1971  *
1972  * Returns: (transfer none): the displayed icon, or %NULL if the image is empty
1973  *
1974  * Since: 2.14
1975  **/
1976 GIcon *
1977 gtk_status_icon_get_gicon (GtkStatusIcon *status_icon)
1978 {
1979   GtkStatusIconPrivate *priv;
1980
1981   g_return_val_if_fail (GTK_IS_STATUS_ICON (status_icon), NULL);
1982
1983   priv = status_icon->priv;
1984
1985   return _gtk_icon_helper_peek_gicon (priv->icon_helper);
1986 }
1987
1988 /**
1989  * gtk_status_icon_get_size:
1990  * @status_icon: a #GtkStatusIcon
1991  * 
1992  * Gets the size in pixels that is available for the image. 
1993  * Stock icons and named icons adapt their size automatically
1994  * if the size of the notification area changes. For other
1995  * storage types, the size-changed signal can be used to
1996  * react to size changes.
1997  *
1998  * Note that the returned size is only meaningful while the 
1999  * status icon is embedded (see gtk_status_icon_is_embedded()).
2000  * 
2001  * Return value: the size that is available for the image
2002  *
2003  * Since: 2.10
2004  **/
2005 gint
2006 gtk_status_icon_get_size (GtkStatusIcon *status_icon)
2007 {
2008   g_return_val_if_fail (GTK_IS_STATUS_ICON (status_icon), 0);
2009
2010   return status_icon->priv->size;
2011 }
2012
2013 /**
2014  * gtk_status_icon_set_screen:
2015  * @status_icon: a #GtkStatusIcon
2016  * @screen: a #GdkScreen
2017  *
2018  * Sets the #GdkScreen where @status_icon is displayed; if
2019  * the icon is already mapped, it will be unmapped, and
2020  * then remapped on the new screen.
2021  *
2022  * Since: 2.12
2023  */
2024 void
2025 gtk_status_icon_set_screen (GtkStatusIcon *status_icon,
2026                             GdkScreen     *screen)
2027 {
2028   g_return_if_fail (GDK_IS_SCREEN (screen));
2029
2030 #ifdef GDK_WINDOWING_X11
2031   gtk_window_set_screen (GTK_WINDOW (status_icon->priv->tray_icon), screen);
2032 #endif
2033 }
2034
2035 /**
2036  * gtk_status_icon_get_screen:
2037  * @status_icon: a #GtkStatusIcon
2038  *
2039  * Returns the #GdkScreen associated with @status_icon.
2040  *
2041  * Return value: (transfer none): a #GdkScreen.
2042  *
2043  * Since: 2.12
2044  */
2045 GdkScreen *
2046 gtk_status_icon_get_screen (GtkStatusIcon *status_icon)
2047 {
2048   g_return_val_if_fail (GTK_IS_STATUS_ICON (status_icon), NULL);
2049
2050 #ifdef GDK_WINDOWING_X11
2051   return gtk_window_get_screen (GTK_WINDOW (status_icon->priv->tray_icon));
2052 #else
2053   return gdk_screen_get_default ();
2054 #endif
2055 }
2056
2057 /**
2058  * gtk_status_icon_set_visible:
2059  * @status_icon: a #GtkStatusIcon
2060  * @visible: %TRUE to show the status icon, %FALSE to hide it
2061  * 
2062  * Shows or hides a status icon.
2063  *
2064  * Since: 2.10
2065  **/
2066 void
2067 gtk_status_icon_set_visible (GtkStatusIcon *status_icon,
2068                              gboolean       visible)
2069 {
2070   GtkStatusIconPrivate *priv;
2071
2072   g_return_if_fail (GTK_IS_STATUS_ICON (status_icon));
2073
2074   priv = status_icon->priv;
2075
2076   visible = visible != FALSE;
2077
2078   if (priv->visible != visible)
2079     {
2080       priv->visible = visible;
2081
2082 #ifdef GDK_WINDOWING_X11
2083       if (visible)
2084         gtk_widget_show (priv->tray_icon);
2085       else if (gtk_widget_get_realized (priv->tray_icon))
2086         {
2087           gtk_widget_hide (priv->tray_icon);
2088           gtk_widget_unrealize (priv->tray_icon);
2089         }
2090 #endif
2091 #ifdef GDK_WINDOWING_WIN32
2092       if (priv->nid.hWnd != NULL)
2093         {
2094           if (visible)
2095             Shell_NotifyIconW (NIM_ADD, &priv->nid);
2096           else
2097             Shell_NotifyIconW (NIM_DELETE, &priv->nid);
2098         }
2099 #endif
2100 #ifdef GDK_WINDOWING_QUARTZ
2101       QUARTZ_POOL_ALLOC;
2102       [priv->status_item setVisible:visible];
2103       QUARTZ_POOL_RELEASE;
2104 #endif
2105       g_object_notify (G_OBJECT (status_icon), "visible");
2106     }
2107 }
2108
2109 /**
2110  * gtk_status_icon_get_visible:
2111  * @status_icon: a #GtkStatusIcon
2112  * 
2113  * Returns whether the status icon is visible or not. 
2114  * Note that being visible does not guarantee that 
2115  * the user can actually see the icon, see also 
2116  * gtk_status_icon_is_embedded().
2117  * 
2118  * Return value: %TRUE if the status icon is visible
2119  *
2120  * Since: 2.10
2121  **/
2122 gboolean
2123 gtk_status_icon_get_visible (GtkStatusIcon *status_icon)
2124 {
2125   g_return_val_if_fail (GTK_IS_STATUS_ICON (status_icon), FALSE);
2126
2127   return status_icon->priv->visible;
2128 }
2129
2130 /**
2131  * gtk_status_icon_is_embedded:
2132  * @status_icon: a #GtkStatusIcon
2133  * 
2134  * Returns whether the status icon is embedded in a notification
2135  * area. 
2136  * 
2137  * Return value: %TRUE if the status icon is embedded in
2138  *   a notification area.
2139  *
2140  * Since: 2.10
2141  **/
2142 gboolean
2143 gtk_status_icon_is_embedded (GtkStatusIcon *status_icon)
2144 {
2145 #ifdef GDK_WINDOWING_X11
2146   GtkPlug *plug;
2147 #endif
2148
2149   g_return_val_if_fail (GTK_IS_STATUS_ICON (status_icon), FALSE);
2150
2151 #ifdef GDK_WINDOWING_X11
2152   plug = GTK_PLUG (status_icon->priv->tray_icon);
2153
2154   if (gtk_plug_get_embedded (plug))
2155     return TRUE;
2156   else
2157     return FALSE;
2158 #endif
2159 #ifdef GDK_WINDOWING_WIN32
2160   return TRUE;
2161 #endif
2162 #ifdef GDK_WINDOWING_QUARTZ
2163   return TRUE;
2164 #endif
2165 }
2166
2167 /**
2168  * gtk_status_icon_position_menu:
2169  * @menu: the #GtkMenu
2170  * @x: (out): return location for the x position
2171  * @y: (out): return location for the y position
2172  * @push_in: (out): whether the first menu item should be offset
2173  *           (pushed in) to be aligned with the menu popup position
2174  *           (only useful for GtkOptionMenu).
2175  * @user_data: (type GtkStatusIcon): the status icon to position the menu on
2176  *
2177  * Menu positioning function to use with gtk_menu_popup()
2178  * to position @menu aligned to the status icon @user_data.
2179  * 
2180  * Since: 2.10
2181  **/
2182 void
2183 gtk_status_icon_position_menu (GtkMenu  *menu,
2184                                gint     *x,
2185                                gint     *y,
2186                                gboolean *push_in,
2187                                gpointer  user_data)
2188 {
2189 #ifdef GDK_WINDOWING_X11
2190   GtkAllocation allocation;
2191   GtkStatusIcon *status_icon;
2192   GtkStatusIconPrivate *priv;
2193   GtkTrayIcon *tray_icon;
2194   GtkWidget *widget;
2195   GdkScreen *screen;
2196   GtkTextDirection direction;
2197   GtkRequisition menu_req;
2198   GdkRectangle monitor;
2199   GdkWindow *window;
2200   gint monitor_num, height, width, xoffset, yoffset;
2201   
2202   g_return_if_fail (GTK_IS_MENU (menu));
2203   g_return_if_fail (GTK_IS_STATUS_ICON (user_data));
2204
2205   status_icon = GTK_STATUS_ICON (user_data);
2206   priv = status_icon->priv;
2207   tray_icon = GTK_TRAY_ICON (priv->tray_icon);
2208   widget = priv->tray_icon;
2209
2210   direction = gtk_widget_get_direction (widget);
2211
2212   screen = gtk_widget_get_screen (widget);
2213   gtk_menu_set_screen (menu, screen);
2214
2215   window = gtk_widget_get_window (widget);
2216   monitor_num = gdk_screen_get_monitor_at_window (screen, window);
2217   if (monitor_num < 0)
2218     monitor_num = 0;
2219   gtk_menu_set_monitor (menu, monitor_num);
2220
2221   gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor);
2222
2223   gdk_window_get_origin (window, x, y);
2224
2225   gtk_widget_get_preferred_size (GTK_WIDGET (menu),
2226                                  &menu_req, NULL);
2227
2228   gtk_widget_get_allocation (widget, &allocation);
2229   if (_gtk_tray_icon_get_orientation (tray_icon) == GTK_ORIENTATION_VERTICAL)
2230     {
2231       width = 0;
2232       height = allocation.height;
2233       xoffset = allocation.width;
2234       yoffset = 0;
2235     }
2236   else
2237     {
2238       width = allocation.width;
2239       height = 0;
2240       xoffset = 0;
2241       yoffset = allocation.height;
2242     }
2243
2244   if (direction == GTK_TEXT_DIR_RTL)
2245     {
2246       if ((*x - (menu_req.width - width)) >= monitor.x)
2247         *x -= menu_req.width - width;
2248       else if ((*x + xoffset + menu_req.width) < (monitor.x + monitor.width))
2249         *x += xoffset;
2250       else if ((monitor.x + monitor.width - (*x + xoffset)) < *x)
2251         *x -= menu_req.width - width;
2252       else
2253         *x += xoffset;
2254     }
2255   else
2256     {
2257       if ((*x + xoffset + menu_req.width) < (monitor.x + monitor.width))
2258         *x += xoffset;
2259       else if ((*x - (menu_req.width - width)) >= monitor.x)
2260         *x -= menu_req.width - width;
2261       else if ((monitor.x + monitor.width - (*x + xoffset)) > *x)
2262         *x += xoffset;
2263       else 
2264         *x -= menu_req.width - width;
2265     }
2266
2267   if ((*y + yoffset + menu_req.height) < (monitor.y + monitor.height))
2268     *y += yoffset;
2269   else if ((*y - (menu_req.height - height)) >= monitor.y)
2270     *y -= menu_req.height - height;
2271   else if (monitor.y + monitor.height - (*y + yoffset) > *y)
2272     *y += yoffset;
2273   else 
2274     *y -= menu_req.height - height;
2275
2276   *push_in = FALSE;
2277 #endif /* GDK_WINDOWING_X11 */
2278
2279 #ifdef GDK_WINDOWING_WIN32
2280   GtkStatusIcon *status_icon;
2281   GtkStatusIconPrivate *priv;
2282   GtkRequisition menu_req;
2283   
2284   g_return_if_fail (GTK_IS_MENU (menu));
2285   g_return_if_fail (GTK_IS_STATUS_ICON (user_data));
2286
2287   status_icon = GTK_STATUS_ICON (user_data);
2288   priv = status_icon->priv;
2289
2290   gtk_widget_size_request (GTK_WIDGET (menu), &menu_req);
2291
2292   *x = priv->last_click_x;
2293   *y = priv->taskbar_top - menu_req.height;
2294
2295   *push_in = TRUE;
2296 #endif
2297 }
2298
2299 /**
2300  * gtk_status_icon_get_geometry:
2301  * @status_icon: a #GtkStatusIcon
2302  * @screen: (out) (transfer none) (allow-none): return location for
2303  *          the screen, or %NULL if the information is not needed
2304  * @area: (out) (allow-none): return location for the area occupied by
2305  *        the status icon, or %NULL
2306  * @orientation: (out) (allow-none): return location for the
2307  *    orientation of the panel in which the status icon is embedded,
2308  *    or %NULL. A panel at the top or bottom of the screen is
2309  *    horizontal, a panel at the left or right is vertical.
2310  *
2311  * Obtains information about the location of the status icon
2312  * on screen. This information can be used to e.g. position 
2313  * popups like notification bubbles. 
2314  *
2315  * See gtk_status_icon_position_menu() for a more convenient 
2316  * alternative for positioning menus.
2317  *
2318  * Note that some platforms do not allow GTK+ to provide 
2319  * this information, and even on platforms that do allow it,
2320  * the information is not reliable unless the status icon
2321  * is embedded in a notification area, see
2322  * gtk_status_icon_is_embedded().
2323  *
2324  * Return value: %TRUE if the location information has 
2325  *               been filled in
2326  *
2327  * Since: 2.10
2328  */
2329 gboolean  
2330 gtk_status_icon_get_geometry (GtkStatusIcon    *status_icon,
2331                               GdkScreen       **screen,
2332                               GdkRectangle     *area,
2333                               GtkOrientation   *orientation)
2334 {
2335 #ifdef GDK_WINDOWING_X11   
2336   GtkAllocation allocation;
2337   GtkWidget *widget;
2338   GtkStatusIconPrivate *priv;
2339   gint x, y;
2340
2341   g_return_val_if_fail (GTK_IS_STATUS_ICON (status_icon), FALSE);
2342
2343   priv = status_icon->priv;
2344   widget = priv->tray_icon;
2345
2346   if (screen)
2347     *screen = gtk_widget_get_screen (widget);
2348
2349   if (area)
2350     {
2351       gdk_window_get_origin (gtk_widget_get_window (widget),
2352                              &x, &y);
2353
2354       gtk_widget_get_allocation (widget, &allocation);
2355       area->x = x;
2356       area->y = y;
2357       area->width = allocation.width;
2358       area->height = allocation.height;
2359     }
2360
2361   if (orientation)
2362     *orientation = _gtk_tray_icon_get_orientation (GTK_TRAY_ICON (widget));
2363
2364   return TRUE;
2365 #else
2366   return FALSE;
2367 #endif /* GDK_WINDOWING_X11 */
2368 }
2369
2370 /**
2371  * gtk_status_icon_set_has_tooltip:
2372  * @status_icon: a #GtkStatusIcon
2373  * @has_tooltip: whether or not @status_icon has a tooltip
2374  *
2375  * Sets the has-tooltip property on @status_icon to @has_tooltip.
2376  * See #GtkStatusIcon:has-tooltip for more information.
2377  *
2378  * Since: 2.16
2379  */
2380 void
2381 gtk_status_icon_set_has_tooltip (GtkStatusIcon *status_icon,
2382                                  gboolean       has_tooltip)
2383 {
2384   GtkStatusIconPrivate *priv;
2385
2386   g_return_if_fail (GTK_IS_STATUS_ICON (status_icon));
2387
2388   priv = status_icon->priv;
2389
2390 #ifdef GDK_WINDOWING_X11
2391   gtk_widget_set_has_tooltip (priv->tray_icon, has_tooltip);
2392 #endif
2393 #ifdef GDK_WINDOWING_WIN32
2394   if (!has_tooltip && priv->tooltip_text)
2395     gtk_status_icon_set_tooltip_text (status_icon, NULL);
2396 #endif
2397 #ifdef GDK_WINDOWING_QUARTZ
2398   if (!has_tooltip && priv->tooltip_text)
2399     gtk_status_icon_set_tooltip_text (status_icon, NULL);
2400 #endif
2401 }
2402
2403 /**
2404  * gtk_status_icon_get_has_tooltip:
2405  * @status_icon: a #GtkStatusIcon
2406  *
2407  * Returns the current value of the has-tooltip property.
2408  * See #GtkStatusIcon:has-tooltip for more information.
2409  *
2410  * Return value: current value of has-tooltip on @status_icon.
2411  *
2412  * Since: 2.16
2413  */
2414 gboolean
2415 gtk_status_icon_get_has_tooltip (GtkStatusIcon *status_icon)
2416 {
2417   GtkStatusIconPrivate *priv;
2418   gboolean has_tooltip = FALSE;
2419
2420   g_return_val_if_fail (GTK_IS_STATUS_ICON (status_icon), FALSE);
2421
2422   priv = status_icon->priv;
2423
2424 #ifdef GDK_WINDOWING_X11
2425   has_tooltip = gtk_widget_get_has_tooltip (priv->tray_icon);
2426 #endif
2427 #ifdef GDK_WINDOWING_WIN32
2428   has_tooltip = (priv->tooltip_text != NULL);
2429 #endif
2430 #ifdef GDK_WINDOWING_QUARTZ
2431   has_tooltip = (priv->tooltip_text != NULL);
2432 #endif
2433
2434   return has_tooltip;
2435 }
2436
2437 /**
2438  * gtk_status_icon_set_tooltip_text:
2439  * @status_icon: a #GtkStatusIcon
2440  * @text: the contents of the tooltip for @status_icon
2441  *
2442  * Sets @text as the contents of the tooltip.
2443  *
2444  * This function will take care of setting #GtkStatusIcon:has-tooltip to
2445  * %TRUE and of the default handler for the #GtkStatusIcon::query-tooltip
2446  * signal.
2447  *
2448  * See also the #GtkStatusIcon:tooltip-text property and
2449  * gtk_tooltip_set_text().
2450  *
2451  * Since: 2.16
2452  */
2453 void
2454 gtk_status_icon_set_tooltip_text (GtkStatusIcon *status_icon,
2455                                   const gchar   *text)
2456 {
2457   GtkStatusIconPrivate *priv;
2458
2459   g_return_if_fail (GTK_IS_STATUS_ICON (status_icon));
2460
2461   priv = status_icon->priv;
2462
2463 #ifdef GDK_WINDOWING_X11
2464
2465   gtk_widget_set_tooltip_text (priv->tray_icon, text);
2466
2467 #endif
2468 #ifdef GDK_WINDOWING_WIN32
2469   if (text == NULL)
2470     priv->nid.uFlags &= ~NIF_TIP;
2471   else
2472     {
2473       WCHAR *wcs = g_utf8_to_utf16 (text, -1, NULL, NULL, NULL);
2474
2475       priv->nid.uFlags |= NIF_TIP;
2476       wcsncpy (priv->nid.szTip, wcs, G_N_ELEMENTS (priv->nid.szTip) - 1);
2477       priv->nid.szTip[G_N_ELEMENTS (priv->nid.szTip) - 1] = 0;
2478       g_free (wcs);
2479     }
2480   if (priv->nid.hWnd != NULL && priv->visible)
2481     if (!Shell_NotifyIconW (NIM_MODIFY, &priv->nid))
2482       g_warning (G_STRLOC ": Shell_NotifyIconW(NIM_MODIFY) failed");
2483
2484   g_free (priv->tooltip_text);
2485   priv->tooltip_text = g_strdup (text);
2486 #endif
2487 #ifdef GDK_WINDOWING_QUARTZ
2488   QUARTZ_POOL_ALLOC;
2489   [priv->status_item setToolTip:text];
2490   QUARTZ_POOL_RELEASE;
2491
2492   g_free (priv->tooltip_text);
2493   priv->tooltip_text = g_strdup (text);
2494 #endif
2495 }
2496
2497 /**
2498  * gtk_status_icon_get_tooltip_text:
2499  * @status_icon: a #GtkStatusIcon
2500  *
2501  * Gets the contents of the tooltip for @status_icon.
2502  *
2503  * Return value: the tooltip text, or %NULL. You should free the
2504  *   returned string with g_free() when done.
2505  *
2506  * Since: 2.16
2507  */
2508 gchar *
2509 gtk_status_icon_get_tooltip_text (GtkStatusIcon *status_icon)
2510 {
2511   GtkStatusIconPrivate *priv;
2512   gchar *tooltip_text = NULL;
2513
2514   g_return_val_if_fail (GTK_IS_STATUS_ICON (status_icon), NULL);
2515
2516   priv = status_icon->priv;
2517
2518 #ifdef GDK_WINDOWING_X11
2519   tooltip_text = gtk_widget_get_tooltip_text (priv->tray_icon);
2520 #endif
2521 #ifdef GDK_WINDOWING_WIN32
2522   if (priv->tooltip_text)
2523     tooltip_text = g_strdup (priv->tooltip_text);
2524 #endif
2525 #ifdef GDK_WINDOWING_QUARTZ
2526   if (priv->tooltip_text)
2527     tooltip_text = g_strdup (priv->tooltip_text);
2528 #endif
2529
2530   return tooltip_text;
2531 }
2532
2533 /**
2534  * gtk_status_icon_set_tooltip_markup:
2535  * @status_icon: a #GtkStatusIcon
2536  * @markup: (allow-none): the contents of the tooltip for @status_icon, or %NULL
2537  *
2538  * Sets @markup as the contents of the tooltip, which is marked up with
2539  *  the <link linkend="PangoMarkupFormat">Pango text markup language</link>.
2540  *
2541  * This function will take care of setting #GtkStatusIcon:has-tooltip to %TRUE
2542  * and of the default handler for the #GtkStatusIcon::query-tooltip signal.
2543  *
2544  * See also the #GtkStatusIcon:tooltip-markup property and
2545  * gtk_tooltip_set_markup().
2546  *
2547  * Since: 2.16
2548  */
2549 void
2550 gtk_status_icon_set_tooltip_markup (GtkStatusIcon *status_icon,
2551                                     const gchar   *markup)
2552 {
2553   GtkStatusIconPrivate *priv;
2554 #ifndef GDK_WINDOWING_X11
2555   gchar *text = NULL;
2556 #endif
2557
2558   g_return_if_fail (GTK_IS_STATUS_ICON (status_icon));
2559
2560   priv = status_icon->priv;
2561
2562 #ifdef GDK_WINDOWING_X11
2563   gtk_widget_set_tooltip_markup (priv->tray_icon, markup);
2564 #endif
2565 #ifdef GDK_WINDOWING_WIN32
2566   if (markup)
2567     pango_parse_markup (markup, -1, 0, NULL, &text, NULL, NULL);
2568   gtk_status_icon_set_tooltip_text (status_icon, text);
2569   g_free (text);
2570 #endif
2571 #ifdef GDK_WINDOWING_QUARTZ
2572   if (markup)
2573     pango_parse_markup (markup, -1, 0, NULL, &text, NULL, NULL);
2574   gtk_status_icon_set_tooltip_text (status_icon, text);
2575   g_free (text);
2576 #endif
2577 }
2578
2579 /**
2580  * gtk_status_icon_get_tooltip_markup:
2581  * @status_icon: a #GtkStatusIcon
2582  *
2583  * Gets the contents of the tooltip for @status_icon.
2584  *
2585  * Return value: the tooltip text, or %NULL. You should free the
2586  *   returned string with g_free() when done.
2587  *
2588  * Since: 2.16
2589  */
2590 gchar *
2591 gtk_status_icon_get_tooltip_markup (GtkStatusIcon *status_icon)
2592 {
2593   GtkStatusIconPrivate *priv;
2594   gchar *markup = NULL;
2595
2596   g_return_val_if_fail (GTK_IS_STATUS_ICON (status_icon), NULL);
2597
2598   priv = status_icon->priv;
2599
2600 #ifdef GDK_WINDOWING_X11
2601   markup = gtk_widget_get_tooltip_markup (priv->tray_icon);
2602 #endif
2603 #ifdef GDK_WINDOWING_WIN32
2604   if (priv->tooltip_text)
2605     markup = g_markup_escape_text (priv->tooltip_text, -1);
2606 #endif
2607 #ifdef GDK_WINDOWING_QUARTZ
2608   if (priv->tooltip_text)
2609     markup = g_markup_escape_text (priv->tooltip_text, -1);
2610 #endif
2611
2612   return markup;
2613 }
2614
2615 /**
2616  * gtk_status_icon_get_x11_window_id:
2617  * @status_icon: a #GtkStatusIcon
2618  *
2619  * This function is only useful on the X11/freedesktop.org platform.
2620  * It returns a window ID for the widget in the underlying
2621  * status icon implementation.  This is useful for the Galago 
2622  * notification service, which can send a window ID in the protocol 
2623  * in order for the server to position notification windows 
2624  * pointing to a status icon reliably.
2625  *
2626  * This function is not intended for other use cases which are
2627  * more likely to be met by one of the non-X11 specific methods, such
2628  * as gtk_status_icon_position_menu().
2629  *
2630  * Return value: An 32 bit unsigned integer identifier for the 
2631  * underlying X11 Window
2632  *
2633  * Since: 2.14
2634  */
2635 guint32
2636 gtk_status_icon_get_x11_window_id (GtkStatusIcon *status_icon)
2637 {
2638 #ifdef GDK_WINDOWING_X11
2639   gtk_widget_realize (GTK_WIDGET (status_icon->priv->tray_icon));
2640   return GDK_WINDOW_XID (gtk_widget_get_window (GTK_WIDGET (status_icon->priv->tray_icon)));
2641 #else
2642   return 0;
2643 #endif
2644 }
2645
2646 /**
2647  * gtk_status_icon_set_title:
2648  * @status_icon: a #GtkStatusIcon
2649  * @title: the title 
2650  *
2651  * Sets the title of this tray icon.
2652  * This should be a short, human-readable, localized string 
2653  * describing the tray icon. It may be used by tools like screen
2654  * readers to render the tray icon.
2655  *
2656  * Since: 2.18
2657  */
2658 void
2659 gtk_status_icon_set_title (GtkStatusIcon *status_icon,
2660                            const gchar   *title)
2661 {
2662   GtkStatusIconPrivate *priv;
2663
2664   g_return_if_fail (GTK_IS_STATUS_ICON (status_icon));
2665
2666   priv = status_icon->priv;
2667
2668 #ifdef GDK_WINDOWING_X11
2669   gtk_window_set_title (GTK_WINDOW (priv->tray_icon), title);
2670 #endif
2671 #ifdef GDK_WINDOWING_QUARTZ
2672   g_free (priv->title);
2673   priv->title = g_strdup (title);
2674 #endif
2675 #ifdef GDK_WINDOWING_WIN32
2676   g_free (priv->title);
2677   priv->title = g_strdup (title);
2678 #endif
2679
2680   g_object_notify (G_OBJECT (status_icon), "title");
2681 }
2682
2683 /**
2684  * gtk_status_icon_get_title:
2685  * @status_icon: a #GtkStatusIcon
2686  *
2687  * Gets the title of this tray icon. See gtk_status_icon_set_title().
2688  *
2689  * Returns: the title of the status icon
2690  *
2691  * Since: 2.18
2692  */
2693 const gchar *
2694 gtk_status_icon_get_title (GtkStatusIcon *status_icon)
2695 {
2696   GtkStatusIconPrivate *priv;
2697
2698   g_return_val_if_fail (GTK_IS_STATUS_ICON (status_icon), NULL);
2699
2700   priv = status_icon->priv;
2701
2702 #ifdef GDK_WINDOWING_X11
2703   return gtk_window_get_title (GTK_WINDOW (priv->tray_icon));
2704 #endif
2705 #ifdef GDK_WINDOWING_QUARTZ
2706   return priv->title;
2707 #endif
2708 #ifdef GDK_WINDOWING_WIN32
2709   return priv->title;
2710 #endif
2711 }
2712
2713
2714 /**
2715  * gtk_status_icon_set_name:
2716  * @status_icon: a #GtkStatusIcon
2717  * @name: the name
2718  *
2719  * Sets the name of this tray icon.
2720  * This should be a string identifying this icon. It is may be
2721  * used for sorting the icons in the tray and will not be shown to
2722  * the user.
2723  *
2724  * Since: 2.20
2725  */
2726 void
2727 gtk_status_icon_set_name (GtkStatusIcon *status_icon,
2728                           const gchar   *name)
2729 {
2730   GtkStatusIconPrivate *priv;
2731
2732   g_return_if_fail (GTK_IS_STATUS_ICON (status_icon));
2733
2734   priv = status_icon->priv;
2735
2736 #ifdef GDK_WINDOWING_X11
2737   if (gtk_widget_get_realized (priv->tray_icon))
2738     {
2739       /* gtk_window_set_wmclass() only operates on non-realized windows,
2740        * so temporarily unrealize the tray here
2741        */
2742       gtk_widget_hide (priv->tray_icon);
2743       gtk_widget_unrealize (priv->tray_icon);
2744       gtk_window_set_wmclass (GTK_WINDOW (priv->tray_icon), name, name);
2745       gtk_widget_show (priv->tray_icon);
2746     }
2747   else
2748     gtk_window_set_wmclass (GTK_WINDOW (priv->tray_icon), name, name);
2749 #endif
2750 }