]> Pileus Git - ~andy/gtk/blob - gtk/gtkstatusicon.c
Replace gtk_misc_set_padding() with GtkWidget:margin properties
[~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     {
1683       gtk_widget_set_margin_left (priv->image, padding);
1684       gtk_widget_set_margin_right (priv->image, padding);
1685     }
1686   else
1687     {
1688       gtk_widget_set_margin_bottom (priv->image, padding);
1689       gtk_widget_set_margin_top (priv->image, padding);
1690     }
1691 }
1692
1693 static void
1694 gtk_status_icon_icon_size_changed (GtkStatusIcon *status_icon)
1695 {
1696   GtkStatusIconPrivate *priv = status_icon->priv;
1697   gint icon_size;
1698
1699   icon_size = _gtk_tray_icon_get_icon_size (GTK_TRAY_ICON (priv->tray_icon));
1700
1701   if (icon_size != 0)
1702     gtk_image_set_pixel_size (GTK_IMAGE (priv->image), icon_size);
1703   else
1704     gtk_image_set_pixel_size (GTK_IMAGE (priv->image), -1);
1705 }
1706
1707 static void
1708 gtk_status_icon_embedded_changed (GtkStatusIcon *status_icon)
1709 {
1710   gtk_status_icon_padding_changed (status_icon);
1711   gtk_status_icon_icon_size_changed (status_icon);
1712   g_object_notify (G_OBJECT (status_icon), "embedded");
1713 }
1714
1715 static void
1716 gtk_status_icon_orientation_changed (GtkStatusIcon *status_icon)
1717 {
1718   gtk_status_icon_padding_changed (status_icon);
1719   g_object_notify (G_OBJECT (status_icon), "orientation");
1720 }
1721
1722 static void
1723 gtk_status_icon_fg_changed (GtkStatusIcon *status_icon)
1724 {
1725   GtkStatusIconPrivate *priv = status_icon->priv;
1726   GdkRGBA *rgba;
1727
1728   g_object_get (priv->tray_icon, "fg-color", &rgba, NULL);
1729
1730   gtk_widget_override_color (priv->image, GTK_STATE_FLAG_NORMAL, rgba);
1731
1732   gdk_rgba_free (rgba);
1733 }
1734
1735 static void
1736 gtk_status_icon_color_changed (GtkTrayIcon   *tray,
1737                                GParamSpec    *pspec,
1738                                GtkStatusIcon *status_icon)
1739 {
1740   GtkStatusIconPrivate *priv = status_icon->priv;
1741   const gchar *name;
1742
1743   switch (pspec->name[0])
1744     {
1745     case 'e':
1746       name = "error";
1747       break;
1748     case 'w':
1749       name = "warning";
1750       break;
1751     case 's':
1752       name = "success";
1753       break;
1754     default:
1755       name = NULL;
1756       break;
1757     }
1758
1759   if (name)
1760     {
1761       GdkRGBA rgba;
1762
1763       g_object_get (priv->tray_icon, pspec->name, &rgba, NULL);
1764
1765       rgba.alpha = 1;
1766
1767       gtk_widget_override_symbolic_color (priv->image, name, &rgba);
1768     }
1769 }
1770
1771 static gboolean
1772 gtk_status_icon_key_press (GtkStatusIcon  *status_icon,
1773                            GdkEventKey    *event)
1774 {
1775   guint state, keyval;
1776
1777   state = event->state & gtk_accelerator_get_default_mod_mask ();
1778   keyval = event->keyval;
1779   if (state == 0 &&
1780       (keyval == GDK_KEY_Return ||
1781        keyval == GDK_KEY_KP_Enter ||
1782        keyval == GDK_KEY_ISO_Enter ||
1783        keyval == GDK_KEY_space ||
1784        keyval == GDK_KEY_KP_Space))
1785     {
1786       emit_activate_signal (status_icon);
1787       return TRUE;
1788     }
1789
1790   return FALSE;
1791 }
1792
1793 static void
1794 gtk_status_icon_popup_menu (GtkStatusIcon  *status_icon)
1795 {
1796   emit_popup_menu_signal (status_icon, 0, gtk_get_current_event_time ());
1797 }
1798
1799 #endif
1800
1801 static gboolean
1802 gtk_status_icon_button_press (GtkStatusIcon  *status_icon,
1803                               GdkEventButton *event)
1804 {
1805   gboolean handled = FALSE;
1806
1807   g_signal_emit (status_icon,
1808                  status_icon_signals [BUTTON_PRESS_EVENT_SIGNAL], 0,
1809                  event, &handled);
1810   if (handled)
1811     return TRUE;
1812
1813   if (event->button == 1 && event->type == GDK_BUTTON_PRESS)
1814     {
1815       emit_activate_signal (status_icon);
1816       return TRUE;
1817     }
1818   else if (event->button == 3 && event->type == GDK_BUTTON_PRESS)
1819     {
1820       emit_popup_menu_signal (status_icon, event->button, event->time);
1821       return TRUE;
1822     }
1823
1824   return FALSE;
1825 }
1826
1827 static gboolean
1828 gtk_status_icon_button_release (GtkStatusIcon  *status_icon,
1829                                 GdkEventButton *event)
1830 {
1831   gboolean handled = FALSE;
1832   g_signal_emit (status_icon,
1833                  status_icon_signals [BUTTON_RELEASE_EVENT_SIGNAL], 0,
1834                  event, &handled);
1835   return handled;
1836 }
1837
1838 #ifdef GDK_WINDOWING_X11
1839 static gboolean
1840 gtk_status_icon_scroll (GtkStatusIcon  *status_icon,
1841                         GdkEventScroll *event)
1842 {
1843   gboolean handled = FALSE;
1844   g_signal_emit (status_icon,
1845                  status_icon_signals [SCROLL_EVENT_SIGNAL], 0,
1846                  event, &handled);
1847   return handled;
1848 }
1849
1850 static gboolean
1851 gtk_status_icon_query_tooltip (GtkStatusIcon *status_icon,
1852                                gint           x,
1853                                gint           y,
1854                                gboolean       keyboard_tip,
1855                                GtkTooltip    *tooltip)
1856 {
1857   gboolean handled = FALSE;
1858   g_signal_emit (status_icon,
1859                  status_icon_signals [QUERY_TOOLTIP_SIGNAL], 0,
1860                  x, y, keyboard_tip, tooltip, &handled);
1861   return handled;
1862 }
1863 #endif /* GDK_WINDOWING_X11 */
1864
1865 static void
1866 gtk_status_icon_reset_image_data (GtkStatusIcon *status_icon)
1867 {
1868   GtkStatusIconPrivate *priv = status_icon->priv;
1869
1870   switch (priv->storage_type)
1871   {
1872     case GTK_IMAGE_PIXBUF:
1873       if (priv->image_data.pixbuf)
1874         g_object_unref (priv->image_data.pixbuf);
1875       priv->image_data.pixbuf = NULL;
1876       g_object_notify (G_OBJECT (status_icon), "pixbuf");
1877       break;
1878
1879     case GTK_IMAGE_STOCK:
1880       g_free (priv->image_data.stock_id);
1881       priv->image_data.stock_id = NULL;
1882
1883       g_object_notify (G_OBJECT (status_icon), "stock");
1884       break;
1885       
1886     case GTK_IMAGE_ICON_NAME:
1887       g_free (priv->image_data.icon_name);
1888       priv->image_data.icon_name = NULL;
1889
1890       g_object_notify (G_OBJECT (status_icon), "icon-name");
1891       break;
1892
1893     case GTK_IMAGE_GICON:
1894       if (priv->image_data.gicon)
1895         g_object_unref (priv->image_data.gicon);
1896       priv->image_data.gicon = NULL;
1897
1898       g_object_notify (G_OBJECT (status_icon), "gicon");
1899       break;
1900
1901     case GTK_IMAGE_EMPTY:
1902       break;
1903     default:
1904       g_assert_not_reached ();
1905       break;
1906   }
1907
1908   priv->storage_type = GTK_IMAGE_EMPTY;
1909   g_object_notify (G_OBJECT (status_icon), "storage-type");
1910 }
1911
1912 static void
1913 gtk_status_icon_set_image (GtkStatusIcon *status_icon,
1914                            GtkImageType   storage_type,
1915                            gpointer       data)
1916 {
1917   GtkStatusIconPrivate *priv = status_icon->priv;
1918
1919   g_object_freeze_notify (G_OBJECT (status_icon));
1920
1921   gtk_status_icon_reset_image_data (status_icon);
1922
1923   priv->storage_type = storage_type;
1924   g_object_notify (G_OBJECT (status_icon), "storage-type");
1925
1926   switch (storage_type) 
1927     {
1928     case GTK_IMAGE_PIXBUF:
1929       priv->image_data.pixbuf = (GdkPixbuf *)data;
1930       g_object_notify (G_OBJECT (status_icon), "pixbuf");
1931       break;
1932     case GTK_IMAGE_STOCK:
1933       priv->image_data.stock_id = g_strdup ((const gchar *)data);
1934       g_object_notify (G_OBJECT (status_icon), "stock");
1935       break;
1936     case GTK_IMAGE_ICON_NAME:
1937       priv->image_data.icon_name = g_strdup ((const gchar *)data);
1938       g_object_notify (G_OBJECT (status_icon), "icon-name");
1939       break;
1940     case GTK_IMAGE_GICON:
1941       priv->image_data.gicon = (GIcon *)data;
1942       g_object_notify (G_OBJECT (status_icon), "gicon");
1943       break;
1944     default:
1945       g_warning ("Image type %u not handled by GtkStatusIcon", storage_type);
1946     }
1947
1948   g_object_thaw_notify (G_OBJECT (status_icon));
1949
1950   gtk_status_icon_update_image (status_icon);
1951 }
1952
1953 /**
1954  * gtk_status_icon_set_from_pixbuf:
1955  * @status_icon: a #GtkStatusIcon
1956  * @pixbuf: (allow-none): a #GdkPixbuf or %NULL
1957  *
1958  * Makes @status_icon display @pixbuf.
1959  * See gtk_status_icon_new_from_pixbuf() for details.
1960  *
1961  * Since: 2.10
1962  **/
1963 void
1964 gtk_status_icon_set_from_pixbuf (GtkStatusIcon *status_icon,
1965                                  GdkPixbuf     *pixbuf)
1966 {
1967   g_return_if_fail (GTK_IS_STATUS_ICON (status_icon));
1968   g_return_if_fail (pixbuf == NULL || GDK_IS_PIXBUF (pixbuf));
1969
1970   if (pixbuf)
1971     g_object_ref (pixbuf);
1972
1973   gtk_status_icon_set_image (status_icon, GTK_IMAGE_PIXBUF,
1974                              (gpointer) pixbuf);
1975 }
1976
1977 /**
1978  * gtk_status_icon_set_from_file:
1979  * @status_icon: a #GtkStatusIcon
1980  * @filename: (type filename): a filename
1981  * 
1982  * Makes @status_icon display the file @filename.
1983  * See gtk_status_icon_new_from_file() for details.
1984  *
1985  * Since: 2.10 
1986  **/
1987 void
1988 gtk_status_icon_set_from_file (GtkStatusIcon *status_icon,
1989                                const gchar   *filename)
1990 {
1991   GdkPixbuf *pixbuf;
1992   
1993   g_return_if_fail (GTK_IS_STATUS_ICON (status_icon));
1994   g_return_if_fail (filename != NULL);
1995   
1996   pixbuf = gdk_pixbuf_new_from_file (filename, NULL);
1997   
1998   gtk_status_icon_set_from_pixbuf (status_icon, pixbuf);
1999   
2000   if (pixbuf)
2001     g_object_unref (pixbuf);
2002 }
2003
2004 /**
2005  * gtk_status_icon_set_from_stock:
2006  * @status_icon: a #GtkStatusIcon
2007  * @stock_id: a stock icon id
2008  * 
2009  * Makes @status_icon display the stock icon with the id @stock_id.
2010  * See gtk_status_icon_new_from_stock() for details.
2011  *
2012  * Since: 2.10 
2013  **/
2014 void
2015 gtk_status_icon_set_from_stock (GtkStatusIcon *status_icon,
2016                                 const gchar   *stock_id)
2017 {
2018   g_return_if_fail (GTK_IS_STATUS_ICON (status_icon));
2019   g_return_if_fail (stock_id != NULL);
2020
2021   gtk_status_icon_set_image (status_icon, GTK_IMAGE_STOCK,
2022                              (gpointer) stock_id);
2023 }
2024
2025 /**
2026  * gtk_status_icon_set_from_icon_name:
2027  * @status_icon: a #GtkStatusIcon
2028  * @icon_name: an icon name
2029  * 
2030  * Makes @status_icon display the icon named @icon_name from the 
2031  * current icon theme.
2032  * See gtk_status_icon_new_from_icon_name() for details.
2033  *
2034  * Since: 2.10 
2035  **/
2036 void
2037 gtk_status_icon_set_from_icon_name (GtkStatusIcon *status_icon,
2038                                     const gchar   *icon_name)
2039 {
2040   g_return_if_fail (GTK_IS_STATUS_ICON (status_icon));
2041   g_return_if_fail (icon_name != NULL);
2042
2043   gtk_status_icon_set_image (status_icon, GTK_IMAGE_ICON_NAME,
2044                              (gpointer) icon_name);
2045 }
2046
2047 /**
2048  * gtk_status_icon_set_from_gicon:
2049  * @status_icon: a #GtkStatusIcon
2050  * @icon: a GIcon
2051  *
2052  * Makes @status_icon display the #GIcon.
2053  * See gtk_status_icon_new_from_gicon() for details.
2054  *
2055  * Since: 2.14
2056  **/
2057 void
2058 gtk_status_icon_set_from_gicon (GtkStatusIcon *status_icon,
2059                                 GIcon         *icon)
2060 {
2061   g_return_if_fail (GTK_IS_STATUS_ICON (status_icon));
2062   g_return_if_fail (icon != NULL);
2063
2064   if (icon)
2065     g_object_ref (icon);
2066
2067   gtk_status_icon_set_image (status_icon, GTK_IMAGE_GICON,
2068                              (gpointer) icon);
2069 }
2070
2071 /**
2072  * gtk_status_icon_get_storage_type:
2073  * @status_icon: a #GtkStatusIcon
2074  * 
2075  * Gets the type of representation being used by the #GtkStatusIcon
2076  * to store image data. If the #GtkStatusIcon has no image data,
2077  * the return value will be %GTK_IMAGE_EMPTY. 
2078  * 
2079  * Return value: the image representation being used
2080  *
2081  * Since: 2.10
2082  **/
2083 GtkImageType
2084 gtk_status_icon_get_storage_type (GtkStatusIcon *status_icon)
2085 {
2086   g_return_val_if_fail (GTK_IS_STATUS_ICON (status_icon), GTK_IMAGE_EMPTY);
2087
2088   return status_icon->priv->storage_type;
2089 }
2090 /**
2091  * gtk_status_icon_get_pixbuf:
2092  * @status_icon: a #GtkStatusIcon
2093  * 
2094  * Gets the #GdkPixbuf being displayed by the #GtkStatusIcon.
2095  * The storage type of the status icon must be %GTK_IMAGE_EMPTY or
2096  * %GTK_IMAGE_PIXBUF (see gtk_status_icon_get_storage_type()).
2097  * The caller of this function does not own a reference to the
2098  * returned pixbuf.
2099  * 
2100  * Return value: (transfer none): the displayed pixbuf,
2101  *     or %NULL if the image is empty.
2102  *
2103  * Since: 2.10
2104  **/
2105 GdkPixbuf *
2106 gtk_status_icon_get_pixbuf (GtkStatusIcon *status_icon)
2107 {
2108   GtkStatusIconPrivate *priv;
2109
2110   g_return_val_if_fail (GTK_IS_STATUS_ICON (status_icon), NULL);
2111
2112   priv = status_icon->priv;
2113
2114   g_return_val_if_fail (priv->storage_type == GTK_IMAGE_PIXBUF ||
2115                         priv->storage_type == GTK_IMAGE_EMPTY, NULL);
2116
2117   if (priv->storage_type == GTK_IMAGE_EMPTY)
2118     priv->image_data.pixbuf = NULL;
2119
2120   return priv->image_data.pixbuf;
2121 }
2122
2123 /**
2124  * gtk_status_icon_get_stock:
2125  * @status_icon: a #GtkStatusIcon
2126  * 
2127  * Gets the id of the stock icon being displayed by the #GtkStatusIcon.
2128  * The storage type of the status icon must be %GTK_IMAGE_EMPTY or
2129  * %GTK_IMAGE_STOCK (see gtk_status_icon_get_storage_type()).
2130  * The returned string is owned by the #GtkStatusIcon and should not
2131  * be freed or modified.
2132  * 
2133  * Return value: stock id of the displayed stock icon,
2134  *   or %NULL if the image is empty.
2135  *
2136  * Since: 2.10
2137  **/
2138 G_CONST_RETURN gchar *
2139 gtk_status_icon_get_stock (GtkStatusIcon *status_icon)
2140 {
2141   GtkStatusIconPrivate *priv;
2142
2143   g_return_val_if_fail (GTK_IS_STATUS_ICON (status_icon), NULL);
2144
2145   priv = status_icon->priv;
2146
2147   g_return_val_if_fail (priv->storage_type == GTK_IMAGE_STOCK ||
2148                         priv->storage_type == GTK_IMAGE_EMPTY, NULL);
2149   
2150   if (priv->storage_type == GTK_IMAGE_EMPTY)
2151     priv->image_data.stock_id = NULL;
2152
2153   return priv->image_data.stock_id;
2154 }
2155
2156 /**
2157  * gtk_status_icon_get_icon_name:
2158  * @status_icon: a #GtkStatusIcon
2159  * 
2160  * Gets the name of the icon being displayed by the #GtkStatusIcon.
2161  * The storage type of the status icon must be %GTK_IMAGE_EMPTY or
2162  * %GTK_IMAGE_ICON_NAME (see gtk_status_icon_get_storage_type()).
2163  * The returned string is owned by the #GtkStatusIcon and should not
2164  * be freed or modified.
2165  * 
2166  * Return value: name of the displayed icon, or %NULL if the image is empty.
2167  *
2168  * Since: 2.10
2169  **/
2170 G_CONST_RETURN gchar *
2171 gtk_status_icon_get_icon_name (GtkStatusIcon *status_icon)
2172 {
2173   GtkStatusIconPrivate *priv;
2174   
2175   g_return_val_if_fail (GTK_IS_STATUS_ICON (status_icon), NULL);
2176
2177   priv = status_icon->priv;
2178
2179   g_return_val_if_fail (priv->storage_type == GTK_IMAGE_ICON_NAME ||
2180                         priv->storage_type == GTK_IMAGE_EMPTY, NULL);
2181
2182   if (priv->storage_type == GTK_IMAGE_EMPTY)
2183     priv->image_data.icon_name = NULL;
2184
2185   return priv->image_data.icon_name;
2186 }
2187
2188 /**
2189  * gtk_status_icon_get_gicon:
2190  * @status_icon: a #GtkStatusIcon
2191  *
2192  * Retrieves the #GIcon being displayed by the #GtkStatusIcon.
2193  * The storage type of the status icon must be %GTK_IMAGE_EMPTY or
2194  * %GTK_IMAGE_GICON (see gtk_status_icon_get_storage_type()).
2195  * The caller of this function does not own a reference to the
2196  * returned #GIcon.
2197  *
2198  * If this function fails, @icon is left unchanged;
2199  *
2200  * Returns: (transfer none): the displayed icon, or %NULL if the image is empty
2201  *
2202  * Since: 2.14
2203  **/
2204 GIcon *
2205 gtk_status_icon_get_gicon (GtkStatusIcon *status_icon)
2206 {
2207   GtkStatusIconPrivate *priv;
2208
2209   g_return_val_if_fail (GTK_IS_STATUS_ICON (status_icon), NULL);
2210
2211   priv = status_icon->priv;
2212
2213   g_return_val_if_fail (priv->storage_type == GTK_IMAGE_GICON ||
2214                         priv->storage_type == GTK_IMAGE_EMPTY, NULL);
2215
2216   if (priv->storage_type == GTK_IMAGE_EMPTY)
2217     priv->image_data.gicon = NULL;
2218
2219   return priv->image_data.gicon;
2220 }
2221
2222 /**
2223  * gtk_status_icon_get_size:
2224  * @status_icon: a #GtkStatusIcon
2225  * 
2226  * Gets the size in pixels that is available for the image. 
2227  * Stock icons and named icons adapt their size automatically
2228  * if the size of the notification area changes. For other
2229  * storage types, the size-changed signal can be used to
2230  * react to size changes.
2231  *
2232  * Note that the returned size is only meaningful while the 
2233  * status icon is embedded (see gtk_status_icon_is_embedded()).
2234  * 
2235  * Return value: the size that is available for the image
2236  *
2237  * Since: 2.10
2238  **/
2239 gint
2240 gtk_status_icon_get_size (GtkStatusIcon *status_icon)
2241 {
2242   g_return_val_if_fail (GTK_IS_STATUS_ICON (status_icon), 0);
2243
2244   return status_icon->priv->size;
2245 }
2246
2247 /**
2248  * gtk_status_icon_set_screen:
2249  * @status_icon: a #GtkStatusIcon
2250  * @screen: a #GdkScreen
2251  *
2252  * Sets the #GdkScreen where @status_icon is displayed; if
2253  * the icon is already mapped, it will be unmapped, and
2254  * then remapped on the new screen.
2255  *
2256  * Since: 2.12
2257  */
2258 void
2259 gtk_status_icon_set_screen (GtkStatusIcon *status_icon,
2260                             GdkScreen     *screen)
2261 {
2262   g_return_if_fail (GDK_IS_SCREEN (screen));
2263
2264 #ifdef GDK_WINDOWING_X11
2265   gtk_window_set_screen (GTK_WINDOW (status_icon->priv->tray_icon), screen);
2266 #endif
2267 }
2268
2269 /**
2270  * gtk_status_icon_get_screen:
2271  * @status_icon: a #GtkStatusIcon
2272  *
2273  * Returns the #GdkScreen associated with @status_icon.
2274  *
2275  * Return value: (transfer none): a #GdkScreen.
2276  *
2277  * Since: 2.12
2278  */
2279 GdkScreen *
2280 gtk_status_icon_get_screen (GtkStatusIcon *status_icon)
2281 {
2282   g_return_val_if_fail (GTK_IS_STATUS_ICON (status_icon), NULL);
2283
2284 #ifdef GDK_WINDOWING_X11
2285   return gtk_window_get_screen (GTK_WINDOW (status_icon->priv->tray_icon));
2286 #else
2287   return gdk_screen_get_default ();
2288 #endif
2289 }
2290
2291 /**
2292  * gtk_status_icon_set_visible:
2293  * @status_icon: a #GtkStatusIcon
2294  * @visible: %TRUE to show the status icon, %FALSE to hide it
2295  * 
2296  * Shows or hides a status icon.
2297  *
2298  * Since: 2.10
2299  **/
2300 void
2301 gtk_status_icon_set_visible (GtkStatusIcon *status_icon,
2302                              gboolean       visible)
2303 {
2304   GtkStatusIconPrivate *priv;
2305
2306   g_return_if_fail (GTK_IS_STATUS_ICON (status_icon));
2307
2308   priv = status_icon->priv;
2309
2310   visible = visible != FALSE;
2311
2312   if (priv->visible != visible)
2313     {
2314       priv->visible = visible;
2315
2316 #ifdef GDK_WINDOWING_X11
2317       if (visible)
2318         gtk_widget_show (priv->tray_icon);
2319       else if (gtk_widget_get_realized (priv->tray_icon))
2320         {
2321           gtk_widget_hide (priv->tray_icon);
2322           gtk_widget_unrealize (priv->tray_icon);
2323         }
2324 #endif
2325 #ifdef GDK_WINDOWING_WIN32
2326       if (priv->nid.hWnd != NULL)
2327         {
2328           if (visible)
2329             Shell_NotifyIconW (NIM_ADD, &priv->nid);
2330           else
2331             Shell_NotifyIconW (NIM_DELETE, &priv->nid);
2332         }
2333 #endif
2334 #ifdef GDK_WINDOWING_QUARTZ
2335       QUARTZ_POOL_ALLOC;
2336       [priv->status_item setVisible:visible];
2337       QUARTZ_POOL_RELEASE;
2338 #endif
2339       g_object_notify (G_OBJECT (status_icon), "visible");
2340     }
2341 }
2342
2343 /**
2344  * gtk_status_icon_get_visible:
2345  * @status_icon: a #GtkStatusIcon
2346  * 
2347  * Returns whether the status icon is visible or not. 
2348  * Note that being visible does not guarantee that 
2349  * the user can actually see the icon, see also 
2350  * gtk_status_icon_is_embedded().
2351  * 
2352  * Return value: %TRUE if the status icon is visible
2353  *
2354  * Since: 2.10
2355  **/
2356 gboolean
2357 gtk_status_icon_get_visible (GtkStatusIcon *status_icon)
2358 {
2359   g_return_val_if_fail (GTK_IS_STATUS_ICON (status_icon), FALSE);
2360
2361   return status_icon->priv->visible;
2362 }
2363
2364 /**
2365  * gtk_status_icon_is_embedded:
2366  * @status_icon: a #GtkStatusIcon
2367  * 
2368  * Returns whether the status icon is embedded in a notification
2369  * area. 
2370  * 
2371  * Return value: %TRUE if the status icon is embedded in
2372  *   a notification area.
2373  *
2374  * Since: 2.10
2375  **/
2376 gboolean
2377 gtk_status_icon_is_embedded (GtkStatusIcon *status_icon)
2378 {
2379 #ifdef GDK_WINDOWING_X11
2380   GtkPlug *plug;
2381 #endif
2382
2383   g_return_val_if_fail (GTK_IS_STATUS_ICON (status_icon), FALSE);
2384
2385 #ifdef GDK_WINDOWING_X11
2386   plug = GTK_PLUG (status_icon->priv->tray_icon);
2387
2388   if (gtk_plug_get_embedded (plug))
2389     return TRUE;
2390   else
2391     return FALSE;
2392 #endif
2393 #ifdef GDK_WINDOWING_WIN32
2394   return TRUE;
2395 #endif
2396 #ifdef GDK_WINDOWING_QUARTZ
2397   return TRUE;
2398 #endif
2399 }
2400
2401 /**
2402  * gtk_status_icon_position_menu:
2403  * @menu: the #GtkMenu
2404  * @x: (out): return location for the x position
2405  * @y: (out): return location for the y position
2406  * @push_in: (out): whether the first menu item should be offset
2407  *           (pushed in) to be aligned with the menu popup position
2408  *           (only useful for GtkOptionMenu).
2409  * @user_data: (type GtkStatusIcon): the status icon to position the menu on
2410  *
2411  * Menu positioning function to use with gtk_menu_popup()
2412  * to position @menu aligned to the status icon @user_data.
2413  * 
2414  * Since: 2.10
2415  **/
2416 void
2417 gtk_status_icon_position_menu (GtkMenu  *menu,
2418                                gint     *x,
2419                                gint     *y,
2420                                gboolean *push_in,
2421                                gpointer  user_data)
2422 {
2423 #ifdef GDK_WINDOWING_X11
2424   GtkAllocation allocation;
2425   GtkStatusIcon *status_icon;
2426   GtkStatusIconPrivate *priv;
2427   GtkTrayIcon *tray_icon;
2428   GtkWidget *widget;
2429   GdkScreen *screen;
2430   GtkTextDirection direction;
2431   GtkRequisition menu_req;
2432   GdkRectangle monitor;
2433   GdkWindow *window;
2434   gint monitor_num, height, width, xoffset, yoffset;
2435   
2436   g_return_if_fail (GTK_IS_MENU (menu));
2437   g_return_if_fail (GTK_IS_STATUS_ICON (user_data));
2438
2439   status_icon = GTK_STATUS_ICON (user_data);
2440   priv = status_icon->priv;
2441   tray_icon = GTK_TRAY_ICON (priv->tray_icon);
2442   widget = priv->tray_icon;
2443
2444   direction = gtk_widget_get_direction (widget);
2445
2446   screen = gtk_widget_get_screen (widget);
2447   gtk_menu_set_screen (menu, screen);
2448
2449   window = gtk_widget_get_window (widget);
2450   monitor_num = gdk_screen_get_monitor_at_window (screen, window);
2451   if (monitor_num < 0)
2452     monitor_num = 0;
2453   gtk_menu_set_monitor (menu, monitor_num);
2454
2455   gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor);
2456
2457   gdk_window_get_origin (window, x, y);
2458
2459   gtk_widget_get_preferred_size (GTK_WIDGET (menu),
2460                                  &menu_req, NULL);
2461
2462   gtk_widget_get_allocation (widget, &allocation);
2463   if (_gtk_tray_icon_get_orientation (tray_icon) == GTK_ORIENTATION_VERTICAL)
2464     {
2465       width = 0;
2466       height = allocation.height;
2467       xoffset = allocation.width;
2468       yoffset = 0;
2469     }
2470   else
2471     {
2472       width = allocation.width;
2473       height = 0;
2474       xoffset = 0;
2475       yoffset = allocation.height;
2476     }
2477
2478   if (direction == GTK_TEXT_DIR_RTL)
2479     {
2480       if ((*x - (menu_req.width - width)) >= monitor.x)
2481         *x -= menu_req.width - width;
2482       else if ((*x + xoffset + menu_req.width) < (monitor.x + monitor.width))
2483         *x += xoffset;
2484       else if ((monitor.x + monitor.width - (*x + xoffset)) < *x)
2485         *x -= menu_req.width - width;
2486       else
2487         *x += xoffset;
2488     }
2489   else
2490     {
2491       if ((*x + xoffset + menu_req.width) < (monitor.x + monitor.width))
2492         *x += xoffset;
2493       else if ((*x - (menu_req.width - width)) >= monitor.x)
2494         *x -= menu_req.width - width;
2495       else if ((monitor.x + monitor.width - (*x + xoffset)) > *x)
2496         *x += xoffset;
2497       else 
2498         *x -= menu_req.width - width;
2499     }
2500
2501   if ((*y + yoffset + menu_req.height) < (monitor.y + monitor.height))
2502     *y += yoffset;
2503   else if ((*y - (menu_req.height - height)) >= monitor.y)
2504     *y -= menu_req.height - height;
2505   else if (monitor.y + monitor.height - (*y + yoffset) > *y)
2506     *y += yoffset;
2507   else 
2508     *y -= menu_req.height - height;
2509
2510   *push_in = FALSE;
2511 #endif /* GDK_WINDOWING_X11 */
2512
2513 #ifdef GDK_WINDOWING_WIN32
2514   GtkStatusIcon *status_icon;
2515   GtkStatusIconPrivate *priv;
2516   
2517   g_return_if_fail (GTK_IS_MENU (menu));
2518   g_return_if_fail (GTK_IS_STATUS_ICON (user_data));
2519
2520   status_icon = GTK_STATUS_ICON (user_data);
2521   priv = status_icon->priv;
2522
2523   *x = priv->last_click_x;
2524   *y = priv->last_click_y;
2525   *push_in = TRUE;
2526 #endif
2527 }
2528
2529 /**
2530  * gtk_status_icon_get_geometry:
2531  * @status_icon: a #GtkStatusIcon
2532  * @screen: (out) (transfer none) (allow-none): return location for
2533  *          the screen, or %NULL if the information is not needed
2534  * @area: (out) (allow-none): return location for the area occupied by
2535  *        the status icon, or %NULL
2536  * @orientation: (out) (allow-none): return location for the
2537  *    orientation of the panel in which the status icon is embedded,
2538  *    or %NULL. A panel at the top or bottom of the screen is
2539  *    horizontal, a panel at the left or right is vertical.
2540  *
2541  * Obtains information about the location of the status icon
2542  * on screen. This information can be used to e.g. position 
2543  * popups like notification bubbles. 
2544  *
2545  * See gtk_status_icon_position_menu() for a more convenient 
2546  * alternative for positioning menus.
2547  *
2548  * Note that some platforms do not allow GTK+ to provide 
2549  * this information, and even on platforms that do allow it,
2550  * the information is not reliable unless the status icon
2551  * is embedded in a notification area, see
2552  * gtk_status_icon_is_embedded().
2553  *
2554  * Return value: %TRUE if the location information has 
2555  *               been filled in
2556  *
2557  * Since: 2.10
2558  */
2559 gboolean  
2560 gtk_status_icon_get_geometry (GtkStatusIcon    *status_icon,
2561                               GdkScreen       **screen,
2562                               GdkRectangle     *area,
2563                               GtkOrientation   *orientation)
2564 {
2565 #ifdef GDK_WINDOWING_X11   
2566   GtkAllocation allocation;
2567   GtkWidget *widget;
2568   GtkStatusIconPrivate *priv;
2569   gint x, y;
2570
2571   g_return_val_if_fail (GTK_IS_STATUS_ICON (status_icon), FALSE);
2572
2573   priv = status_icon->priv;
2574   widget = priv->tray_icon;
2575
2576   if (screen)
2577     *screen = gtk_widget_get_screen (widget);
2578
2579   if (area)
2580     {
2581       gdk_window_get_origin (gtk_widget_get_window (widget),
2582                              &x, &y);
2583
2584       gtk_widget_get_allocation (widget, &allocation);
2585       area->x = x;
2586       area->y = y;
2587       area->width = allocation.width;
2588       area->height = allocation.height;
2589     }
2590
2591   if (orientation)
2592     *orientation = _gtk_tray_icon_get_orientation (GTK_TRAY_ICON (widget));
2593
2594   return TRUE;
2595 #else
2596   return FALSE;
2597 #endif /* GDK_WINDOWING_X11 */
2598 }
2599
2600 /**
2601  * gtk_status_icon_set_has_tooltip:
2602  * @status_icon: a #GtkStatusIcon
2603  * @has_tooltip: whether or not @status_icon has a tooltip
2604  *
2605  * Sets the has-tooltip property on @status_icon to @has_tooltip.
2606  * See #GtkStatusIcon:has-tooltip for more information.
2607  *
2608  * Since: 2.16
2609  */
2610 void
2611 gtk_status_icon_set_has_tooltip (GtkStatusIcon *status_icon,
2612                                  gboolean       has_tooltip)
2613 {
2614   GtkStatusIconPrivate *priv;
2615
2616   g_return_if_fail (GTK_IS_STATUS_ICON (status_icon));
2617
2618   priv = status_icon->priv;
2619
2620 #ifdef GDK_WINDOWING_X11
2621   gtk_widget_set_has_tooltip (priv->tray_icon, has_tooltip);
2622 #endif
2623 #ifdef GDK_WINDOWING_WIN32
2624   if (!has_tooltip && priv->tooltip_text)
2625     gtk_status_icon_set_tooltip_text (status_icon, NULL);
2626 #endif
2627 #ifdef GDK_WINDOWING_QUARTZ
2628   if (!has_tooltip && priv->tooltip_text)
2629     gtk_status_icon_set_tooltip_text (status_icon, NULL);
2630 #endif
2631 }
2632
2633 /**
2634  * gtk_status_icon_get_has_tooltip:
2635  * @status_icon: a #GtkStatusIcon
2636  *
2637  * Returns the current value of the has-tooltip property.
2638  * See #GtkStatusIcon:has-tooltip for more information.
2639  *
2640  * Return value: current value of has-tooltip on @status_icon.
2641  *
2642  * Since: 2.16
2643  */
2644 gboolean
2645 gtk_status_icon_get_has_tooltip (GtkStatusIcon *status_icon)
2646 {
2647   GtkStatusIconPrivate *priv;
2648   gboolean has_tooltip = FALSE;
2649
2650   g_return_val_if_fail (GTK_IS_STATUS_ICON (status_icon), FALSE);
2651
2652   priv = status_icon->priv;
2653
2654 #ifdef GDK_WINDOWING_X11
2655   has_tooltip = gtk_widget_get_has_tooltip (priv->tray_icon);
2656 #endif
2657 #ifdef GDK_WINDOWING_WIN32
2658   has_tooltip = (priv->tooltip_text != NULL);
2659 #endif
2660 #ifdef GDK_WINDOWING_QUARTZ
2661   has_tooltip = (priv->tooltip_text != NULL);
2662 #endif
2663
2664   return has_tooltip;
2665 }
2666
2667 /**
2668  * gtk_status_icon_set_tooltip_text:
2669  * @status_icon: a #GtkStatusIcon
2670  * @text: the contents of the tooltip for @status_icon
2671  *
2672  * Sets @text as the contents of the tooltip.
2673  *
2674  * This function will take care of setting #GtkStatusIcon:has-tooltip to
2675  * %TRUE and of the default handler for the #GtkStatusIcon::query-tooltip
2676  * signal.
2677  *
2678  * See also the #GtkStatusIcon:tooltip-text property and
2679  * gtk_tooltip_set_text().
2680  *
2681  * Since: 2.16
2682  */
2683 void
2684 gtk_status_icon_set_tooltip_text (GtkStatusIcon *status_icon,
2685                                   const gchar   *text)
2686 {
2687   GtkStatusIconPrivate *priv;
2688
2689   g_return_if_fail (GTK_IS_STATUS_ICON (status_icon));
2690
2691   priv = status_icon->priv;
2692
2693 #ifdef GDK_WINDOWING_X11
2694
2695   gtk_widget_set_tooltip_text (priv->tray_icon, text);
2696
2697 #endif
2698 #ifdef GDK_WINDOWING_WIN32
2699   if (text == NULL)
2700     priv->nid.uFlags &= ~NIF_TIP;
2701   else
2702     {
2703       WCHAR *wcs = g_utf8_to_utf16 (text, -1, NULL, NULL, NULL);
2704
2705       priv->nid.uFlags |= NIF_TIP;
2706       wcsncpy (priv->nid.szTip, wcs, G_N_ELEMENTS (priv->nid.szTip) - 1);
2707       priv->nid.szTip[G_N_ELEMENTS (priv->nid.szTip) - 1] = 0;
2708       g_free (wcs);
2709     }
2710   if (priv->nid.hWnd != NULL && priv->visible)
2711     if (!Shell_NotifyIconW (NIM_MODIFY, &priv->nid))
2712       g_warning (G_STRLOC ": Shell_NotifyIconW(NIM_MODIFY) failed");
2713
2714   g_free (priv->tooltip_text);
2715   priv->tooltip_text = g_strdup (text);
2716 #endif
2717 #ifdef GDK_WINDOWING_QUARTZ
2718   QUARTZ_POOL_ALLOC;
2719   [priv->status_item setToolTip:text];
2720   QUARTZ_POOL_RELEASE;
2721
2722   g_free (priv->tooltip_text);
2723   priv->tooltip_text = g_strdup (text);
2724 #endif
2725 }
2726
2727 /**
2728  * gtk_status_icon_get_tooltip_text:
2729  * @status_icon: a #GtkStatusIcon
2730  *
2731  * Gets the contents of the tooltip for @status_icon.
2732  *
2733  * Return value: the tooltip text, or %NULL. You should free the
2734  *   returned string with g_free() when done.
2735  *
2736  * Since: 2.16
2737  */
2738 gchar *
2739 gtk_status_icon_get_tooltip_text (GtkStatusIcon *status_icon)
2740 {
2741   GtkStatusIconPrivate *priv;
2742   gchar *tooltip_text = NULL;
2743
2744   g_return_val_if_fail (GTK_IS_STATUS_ICON (status_icon), NULL);
2745
2746   priv = status_icon->priv;
2747
2748 #ifdef GDK_WINDOWING_X11
2749   tooltip_text = gtk_widget_get_tooltip_text (priv->tray_icon);
2750 #endif
2751 #ifdef GDK_WINDOWING_WIN32
2752   if (priv->tooltip_text)
2753     tooltip_text = g_strdup (priv->tooltip_text);
2754 #endif
2755 #ifdef GDK_WINDOWING_QUARTZ
2756   if (priv->tooltip_text)
2757     tooltip_text = g_strdup (priv->tooltip_text);
2758 #endif
2759
2760   return tooltip_text;
2761 }
2762
2763 /**
2764  * gtk_status_icon_set_tooltip_markup:
2765  * @status_icon: a #GtkStatusIcon
2766  * @markup: (allow-none): the contents of the tooltip for @status_icon, or %NULL
2767  *
2768  * Sets @markup as the contents of the tooltip, which is marked up with
2769  *  the <link linkend="PangoMarkupFormat">Pango text markup language</link>.
2770  *
2771  * This function will take care of setting #GtkStatusIcon:has-tooltip to %TRUE
2772  * and of the default handler for the #GtkStatusIcon::query-tooltip signal.
2773  *
2774  * See also the #GtkStatusIcon:tooltip-markup property and
2775  * gtk_tooltip_set_markup().
2776  *
2777  * Since: 2.16
2778  */
2779 void
2780 gtk_status_icon_set_tooltip_markup (GtkStatusIcon *status_icon,
2781                                     const gchar   *markup)
2782 {
2783   GtkStatusIconPrivate *priv;
2784 #ifndef GDK_WINDOWING_X11
2785   gchar *text = NULL;
2786 #endif
2787
2788   g_return_if_fail (GTK_IS_STATUS_ICON (status_icon));
2789
2790   priv = status_icon->priv;
2791
2792 #ifdef GDK_WINDOWING_X11
2793   gtk_widget_set_tooltip_markup (priv->tray_icon, markup);
2794 #endif
2795 #ifdef GDK_WINDOWING_WIN32
2796   if (markup)
2797     pango_parse_markup (markup, -1, 0, NULL, &text, NULL, NULL);
2798   gtk_status_icon_set_tooltip_text (status_icon, text);
2799   g_free (text);
2800 #endif
2801 #ifdef GDK_WINDOWING_QUARTZ
2802   if (markup)
2803     pango_parse_markup (markup, -1, 0, NULL, &text, NULL, NULL);
2804   gtk_status_icon_set_tooltip_text (status_icon, text);
2805   g_free (text);
2806 #endif
2807 }
2808
2809 /**
2810  * gtk_status_icon_get_tooltip_markup:
2811  * @status_icon: a #GtkStatusIcon
2812  *
2813  * Gets the contents of the tooltip for @status_icon.
2814  *
2815  * Return value: the tooltip text, or %NULL. You should free the
2816  *   returned string with g_free() when done.
2817  *
2818  * Since: 2.16
2819  */
2820 gchar *
2821 gtk_status_icon_get_tooltip_markup (GtkStatusIcon *status_icon)
2822 {
2823   GtkStatusIconPrivate *priv;
2824   gchar *markup = NULL;
2825
2826   g_return_val_if_fail (GTK_IS_STATUS_ICON (status_icon), NULL);
2827
2828   priv = status_icon->priv;
2829
2830 #ifdef GDK_WINDOWING_X11
2831   markup = gtk_widget_get_tooltip_markup (priv->tray_icon);
2832 #endif
2833 #ifdef GDK_WINDOWING_WIN32
2834   if (priv->tooltip_text)
2835     markup = g_markup_escape_text (priv->tooltip_text, -1);
2836 #endif
2837 #ifdef GDK_WINDOWING_QUARTZ
2838   if (priv->tooltip_text)
2839     markup = g_markup_escape_text (priv->tooltip_text, -1);
2840 #endif
2841
2842   return markup;
2843 }
2844
2845 /**
2846  * gtk_status_icon_get_x11_window_id:
2847  * @status_icon: a #GtkStatusIcon
2848  *
2849  * This function is only useful on the X11/freedesktop.org platform.
2850  * It returns a window ID for the widget in the underlying
2851  * status icon implementation.  This is useful for the Galago 
2852  * notification service, which can send a window ID in the protocol 
2853  * in order for the server to position notification windows 
2854  * pointing to a status icon reliably.
2855  *
2856  * This function is not intended for other use cases which are
2857  * more likely to be met by one of the non-X11 specific methods, such
2858  * as gtk_status_icon_position_menu().
2859  *
2860  * Return value: An 32 bit unsigned integer identifier for the 
2861  * underlying X11 Window
2862  *
2863  * Since: 2.14
2864  */
2865 guint32
2866 gtk_status_icon_get_x11_window_id (GtkStatusIcon *status_icon)
2867 {
2868 #ifdef GDK_WINDOWING_X11
2869   gtk_widget_realize (GTK_WIDGET (status_icon->priv->tray_icon));
2870   return GDK_WINDOW_XID (gtk_widget_get_window (GTK_WIDGET (status_icon->priv->tray_icon)));
2871 #else
2872   return 0;
2873 #endif
2874 }
2875
2876 /**
2877  * gtk_status_icon_set_title:
2878  * @status_icon: a #GtkStatusIcon
2879  * @title: the title 
2880  *
2881  * Sets the title of this tray icon.
2882  * This should be a short, human-readable, localized string 
2883  * describing the tray icon. It may be used by tools like screen
2884  * readers to render the tray icon.
2885  *
2886  * Since: 2.18
2887  */
2888 void
2889 gtk_status_icon_set_title (GtkStatusIcon *status_icon,
2890                            const gchar   *title)
2891 {
2892   GtkStatusIconPrivate *priv;
2893
2894   g_return_if_fail (GTK_IS_STATUS_ICON (status_icon));
2895
2896   priv = status_icon->priv;
2897
2898 #ifdef GDK_WINDOWING_X11
2899   gtk_window_set_title (GTK_WINDOW (priv->tray_icon), title);
2900 #endif
2901 #ifdef GDK_WINDOWING_QUARTZ
2902   g_free (priv->title);
2903   priv->title = g_strdup (title);
2904 #endif
2905 #ifdef GDK_WINDOWING_WIN32
2906   g_free (priv->title);
2907   priv->title = g_strdup (title);
2908 #endif
2909
2910   g_object_notify (G_OBJECT (status_icon), "title");
2911 }
2912
2913 /**
2914  * gtk_status_icon_get_title:
2915  * @status_icon: a #GtkStatusIcon
2916  *
2917  * Gets the title of this tray icon. See gtk_status_icon_set_title().
2918  *
2919  * Returns: the title of the status icon
2920  *
2921  * Since: 2.18
2922  */
2923 G_CONST_RETURN gchar *
2924 gtk_status_icon_get_title (GtkStatusIcon *status_icon)
2925 {
2926   GtkStatusIconPrivate *priv;
2927
2928   g_return_val_if_fail (GTK_IS_STATUS_ICON (status_icon), NULL);
2929
2930   priv = status_icon->priv;
2931
2932 #ifdef GDK_WINDOWING_X11
2933   return gtk_window_get_title (GTK_WINDOW (priv->tray_icon));
2934 #endif
2935 #ifdef GDK_WINDOWING_QUARTZ
2936   return priv->title;
2937 #endif
2938 #ifdef GDK_WINDOWING_WIN32
2939   return priv->title;
2940 #endif
2941 }
2942
2943
2944 /**
2945  * gtk_status_icon_set_name:
2946  * @status_icon: a #GtkStatusIcon
2947  * @name: the name
2948  *
2949  * Sets the name of this tray icon.
2950  * This should be a string identifying this icon. It is may be
2951  * used for sorting the icons in the tray and will not be shown to
2952  * the user.
2953  *
2954  * Since: 2.20
2955  */
2956 void
2957 gtk_status_icon_set_name (GtkStatusIcon *status_icon,
2958                           const gchar   *name)
2959 {
2960   GtkStatusIconPrivate *priv;
2961
2962   g_return_if_fail (GTK_IS_STATUS_ICON (status_icon));
2963
2964   priv = status_icon->priv;
2965
2966 #ifdef GDK_WINDOWING_X11
2967   gtk_window_set_wmclass (GTK_WINDOW (priv->tray_icon), name, name);
2968 #endif
2969 }