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