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