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