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