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