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