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