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