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