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