]> Pileus Git - ~andy/gtk/blob - gtk/gtkstatusicon.c
GtkStatusIcon: Use gtk_widget_render_icon_pixbuf()
[~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   /* To help win7 identify the icon create it with an application "unique" tip */
907   if (g_get_prgname ())
908   {
909     WCHAR *wcs = g_utf8_to_utf16 (g_get_prgname (), -1, NULL, NULL, NULL);
910
911     priv->nid.uFlags |= NIF_TIP;
912     wcsncpy (priv->nid.szTip, wcs, G_N_ELEMENTS (priv->nid.szTip) - 1);
913     priv->nid.szTip[G_N_ELEMENTS (priv->nid.szTip) - 1] = 0;
914     g_free (wcs);
915   }
916
917   if (!Shell_NotifyIconW (NIM_ADD, &priv->nid))
918     {
919       g_warning (G_STRLOC ": Shell_NotifyIcon(NIM_ADD) failed");
920       priv->nid.hWnd = NULL;
921     }
922
923   status_icons = g_slist_append (status_icons, status_icon);
924
925 #endif
926         
927 #ifdef GDK_WINDOWING_QUARTZ
928   priv->dummy_widget = gtk_label_new ("");
929
930   QUARTZ_POOL_ALLOC;
931
932   priv->status_item = [[GtkQuartzStatusIcon alloc] initWithStatusIcon:status_icon];
933
934   priv->image_width = priv->image_height = [priv->status_item getHeight];
935   priv->size = priv->image_height;
936
937   QUARTZ_POOL_RELEASE;
938
939 #endif 
940 }
941
942 static GObject*
943 gtk_status_icon_constructor (GType                  type,
944                              guint                  n_construct_properties,
945                              GObjectConstructParam *construct_params)
946 {
947   GObject *object;
948 #ifdef GDK_WINDOWING_X11
949   GtkStatusIcon *status_icon;
950   GtkStatusIconPrivate *priv;
951 #endif
952
953   object = G_OBJECT_CLASS (gtk_status_icon_parent_class)->constructor (type,
954                                                                        n_construct_properties,
955                                                                        construct_params);
956
957 #ifdef GDK_WINDOWING_X11
958   status_icon = GTK_STATUS_ICON (object);
959   priv = status_icon->priv;
960   
961   if (priv->visible)
962     gtk_widget_show (priv->tray_icon);
963 #endif
964
965   return object;
966 }
967
968 static void
969 gtk_status_icon_finalize (GObject *object)
970 {
971   GtkStatusIcon *status_icon = GTK_STATUS_ICON (object);
972   GtkStatusIconPrivate *priv = status_icon->priv;
973
974   gtk_status_icon_reset_image_data (status_icon);
975
976 #ifdef GDK_WINDOWING_X11
977   g_signal_handlers_disconnect_by_func (priv->tray_icon,
978                                         gtk_status_icon_key_press, status_icon);
979   g_signal_handlers_disconnect_by_func (priv->tray_icon,
980                                         gtk_status_icon_popup_menu, status_icon);
981   g_signal_handlers_disconnect_by_func (priv->tray_icon,
982                                         gtk_status_icon_embedded_changed, status_icon);
983   g_signal_handlers_disconnect_by_func (priv->tray_icon,
984                                         gtk_status_icon_orientation_changed, status_icon);
985   g_signal_handlers_disconnect_by_func (priv->tray_icon,
986                                         gtk_status_icon_padding_changed, status_icon);
987   g_signal_handlers_disconnect_by_func (priv->tray_icon,
988                                         gtk_status_icon_fg_changed, status_icon);
989   g_signal_handlers_disconnect_by_func (priv->tray_icon,
990                                         gtk_status_icon_color_changed, status_icon);
991   g_signal_handlers_disconnect_by_func (priv->tray_icon,
992                                         gtk_status_icon_button_press, status_icon);
993   g_signal_handlers_disconnect_by_func (priv->tray_icon,
994                                         gtk_status_icon_button_release, status_icon);
995   g_signal_handlers_disconnect_by_func (priv->tray_icon,
996                                         gtk_status_icon_scroll, status_icon);
997   g_signal_handlers_disconnect_by_func (priv->tray_icon,
998                                         gtk_status_icon_query_tooltip, status_icon);
999   g_signal_handlers_disconnect_by_func (priv->tray_icon,
1000                                         gtk_status_icon_screen_changed, status_icon);
1001   gtk_widget_destroy (priv->image);
1002   gtk_widget_destroy (priv->tray_icon);
1003 #endif
1004
1005 #ifdef GDK_WINDOWING_WIN32
1006   if (priv->nid.hWnd != NULL && priv->visible)
1007     Shell_NotifyIconW (NIM_DELETE, &priv->nid);
1008   if (priv->nid.hIcon)
1009     DestroyIcon (priv->nid.hIcon);
1010   g_free (priv->tooltip_text);
1011
1012   gtk_widget_destroy (priv->dummy_widget);
1013
1014   status_icons = g_slist_remove (status_icons, status_icon);
1015 #endif
1016         
1017 #ifdef GDK_WINDOWING_QUARTZ
1018   QUARTZ_POOL_ALLOC;
1019   [priv->status_item release];
1020   QUARTZ_POOL_RELEASE;
1021   g_free (priv->tooltip_text);
1022 #endif
1023
1024   G_OBJECT_CLASS (gtk_status_icon_parent_class)->finalize (object);
1025 }
1026
1027 static void
1028 gtk_status_icon_set_property (GObject      *object,
1029                               guint         prop_id,
1030                               const GValue *value,
1031                               GParamSpec   *pspec)
1032 {
1033   GtkStatusIcon *status_icon = GTK_STATUS_ICON (object);
1034
1035   switch (prop_id)
1036     {
1037     case PROP_PIXBUF:
1038       gtk_status_icon_set_from_pixbuf (status_icon, g_value_get_object (value));
1039       break;
1040     case PROP_FILE:
1041       gtk_status_icon_set_from_file (status_icon, g_value_get_string (value));
1042       break;
1043     case PROP_STOCK:
1044       gtk_status_icon_set_from_stock (status_icon, g_value_get_string (value));
1045       break;
1046     case PROP_ICON_NAME:
1047       gtk_status_icon_set_from_icon_name (status_icon, g_value_get_string (value));
1048       break;
1049     case PROP_GICON:
1050       gtk_status_icon_set_from_gicon (status_icon, g_value_get_object (value));
1051       break;
1052     case PROP_SCREEN:
1053       gtk_status_icon_set_screen (status_icon, g_value_get_object (value));
1054       break;
1055     case PROP_VISIBLE:
1056       gtk_status_icon_set_visible (status_icon, g_value_get_boolean (value));
1057       break;
1058     case PROP_HAS_TOOLTIP:
1059       gtk_status_icon_set_has_tooltip (status_icon, g_value_get_boolean (value));
1060       break;
1061     case PROP_TOOLTIP_TEXT:
1062       gtk_status_icon_set_tooltip_text (status_icon, g_value_get_string (value));
1063       break;
1064     case PROP_TOOLTIP_MARKUP:
1065       gtk_status_icon_set_tooltip_markup (status_icon, g_value_get_string (value));
1066       break;
1067     case PROP_TITLE:
1068       gtk_status_icon_set_title (status_icon, g_value_get_string (value));
1069       break;
1070     default:
1071       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1072       break;
1073     }
1074 }
1075
1076 static void
1077 gtk_status_icon_get_property (GObject    *object,
1078                               guint       prop_id,
1079                               GValue     *value,
1080                               GParamSpec *pspec)
1081 {
1082   GtkStatusIcon *status_icon = GTK_STATUS_ICON (object);
1083   GtkStatusIconPrivate *priv = status_icon->priv;
1084
1085   /* The "getter" functions whine if you try to get the wrong
1086    * storage type. This function is instead robust against that,
1087    * so that GUI builders don't have to jump through hoops
1088    * to avoid g_warning
1089    */
1090
1091   switch (prop_id)
1092     {
1093     case PROP_PIXBUF:
1094       if (priv->storage_type != GTK_IMAGE_PIXBUF)
1095         g_value_set_object (value, NULL);
1096       else
1097         g_value_set_object (value, gtk_status_icon_get_pixbuf (status_icon));
1098       break;
1099     case PROP_STOCK:
1100       if (priv->storage_type != GTK_IMAGE_STOCK)
1101         g_value_set_string (value, NULL);
1102       else
1103         g_value_set_string (value, gtk_status_icon_get_stock (status_icon));
1104       break;
1105     case PROP_ICON_NAME:
1106       if (priv->storage_type != GTK_IMAGE_ICON_NAME)
1107         g_value_set_string (value, NULL);
1108       else
1109         g_value_set_string (value, gtk_status_icon_get_icon_name (status_icon));
1110       break;
1111     case PROP_GICON:
1112       if (priv->storage_type != GTK_IMAGE_GICON)
1113         g_value_set_object (value, NULL);
1114       else
1115         g_value_set_object (value, gtk_status_icon_get_gicon (status_icon));
1116       break;
1117     case PROP_STORAGE_TYPE:
1118       g_value_set_enum (value, gtk_status_icon_get_storage_type (status_icon));
1119       break;
1120     case PROP_SIZE:
1121       g_value_set_int (value, gtk_status_icon_get_size (status_icon));
1122       break;
1123     case PROP_SCREEN:
1124       g_value_set_object (value, gtk_status_icon_get_screen (status_icon));
1125       break;
1126     case PROP_VISIBLE:
1127       g_value_set_boolean (value, gtk_status_icon_get_visible (status_icon));
1128       break;
1129     case PROP_EMBEDDED:
1130       g_value_set_boolean (value, gtk_status_icon_is_embedded (status_icon));
1131       break;
1132     case PROP_ORIENTATION:
1133 #ifdef GDK_WINDOWING_X11
1134       g_value_set_enum (value, _gtk_tray_icon_get_orientation (GTK_TRAY_ICON (status_icon->priv->tray_icon)));
1135 #endif
1136 #ifdef GDK_WINDOWING_WIN32
1137       g_value_set_enum (value, status_icon->priv->orientation);
1138 #endif
1139       break;
1140     case PROP_HAS_TOOLTIP:
1141       g_value_set_boolean (value, gtk_status_icon_get_has_tooltip (status_icon));
1142       break;
1143     case PROP_TOOLTIP_TEXT:
1144       g_value_set_string (value, gtk_status_icon_get_tooltip_text (status_icon));
1145       break;
1146     case PROP_TOOLTIP_MARKUP:
1147       g_value_set_string (value, gtk_status_icon_get_tooltip_markup (status_icon));
1148       break;
1149     case PROP_TITLE:
1150       g_value_set_string (value, gtk_status_icon_get_title (status_icon));
1151       break;
1152     default:
1153       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1154       break;
1155     }
1156 }
1157
1158 /**
1159  * gtk_status_icon_new:
1160  * 
1161  * Creates an empty status icon object.
1162  * 
1163  * Return value: a new #GtkStatusIcon
1164  *
1165  * Since: 2.10
1166  **/
1167 GtkStatusIcon *
1168 gtk_status_icon_new (void)
1169 {
1170   return g_object_new (GTK_TYPE_STATUS_ICON, NULL);
1171 }
1172
1173 /**
1174  * gtk_status_icon_new_from_pixbuf:
1175  * @pixbuf: a #GdkPixbuf
1176  * 
1177  * Creates a status icon displaying @pixbuf. 
1178  *
1179  * The image will be scaled down to fit in the available 
1180  * space in the notification area, if necessary.
1181  * 
1182  * Return value: a new #GtkStatusIcon
1183  *
1184  * Since: 2.10
1185  **/
1186 GtkStatusIcon *
1187 gtk_status_icon_new_from_pixbuf (GdkPixbuf *pixbuf)
1188 {
1189   return g_object_new (GTK_TYPE_STATUS_ICON,
1190                        "pixbuf", pixbuf,
1191                        NULL);
1192 }
1193
1194 /**
1195  * gtk_status_icon_new_from_file:
1196  * @filename: a filename
1197  * 
1198  * Creates a status icon displaying the file @filename. 
1199  *
1200  * The image will be scaled down to fit in the available 
1201  * space in the notification area, if necessary.
1202  * 
1203  * Return value: a new #GtkStatusIcon
1204  *
1205  * Since: 2.10
1206  **/
1207 GtkStatusIcon *
1208 gtk_status_icon_new_from_file (const gchar *filename)
1209 {
1210   return g_object_new (GTK_TYPE_STATUS_ICON,
1211                        "file", filename,
1212                        NULL);
1213 }
1214
1215 /**
1216  * gtk_status_icon_new_from_stock:
1217  * @stock_id: a stock icon id
1218  * 
1219  * Creates a status icon displaying a stock icon. Sample stock icon
1220  * names are #GTK_STOCK_OPEN, #GTK_STOCK_QUIT. You can register your 
1221  * own stock icon names, see gtk_icon_factory_add_default() and 
1222  * gtk_icon_factory_add(). 
1223  *
1224  * Return value: a new #GtkStatusIcon
1225  *
1226  * Since: 2.10
1227  **/
1228 GtkStatusIcon *
1229 gtk_status_icon_new_from_stock (const gchar *stock_id)
1230 {
1231   return g_object_new (GTK_TYPE_STATUS_ICON,
1232                        "stock", stock_id,
1233                        NULL);
1234 }
1235
1236 /**
1237  * gtk_status_icon_new_from_icon_name:
1238  * @icon_name: an icon name
1239  * 
1240  * Creates a status icon displaying an icon from the current icon theme.
1241  * If the current icon theme is changed, the icon will be updated 
1242  * appropriately.
1243  * 
1244  * Return value: a new #GtkStatusIcon
1245  *
1246  * Since: 2.10
1247  **/
1248 GtkStatusIcon *
1249 gtk_status_icon_new_from_icon_name (const gchar *icon_name)
1250 {
1251   return g_object_new (GTK_TYPE_STATUS_ICON,
1252                        "icon-name", icon_name,
1253                        NULL);
1254 }
1255
1256 /**
1257  * gtk_status_icon_new_from_gicon:
1258  * @icon: a #GIcon
1259  *
1260  * Creates a status icon displaying a #GIcon. If the icon is a
1261  * themed icon, it will be updated when the theme changes.
1262  *
1263  * Return value: a new #GtkStatusIcon
1264  *
1265  * Since: 2.14
1266  **/
1267 GtkStatusIcon *
1268 gtk_status_icon_new_from_gicon (GIcon *icon)
1269 {
1270   return g_object_new (GTK_TYPE_STATUS_ICON,
1271                        "gicon", icon,
1272                        NULL);
1273 }
1274
1275 static void
1276 emit_activate_signal (GtkStatusIcon *status_icon)
1277 {
1278   g_signal_emit (status_icon,
1279                  status_icon_signals [ACTIVATE_SIGNAL], 0);
1280 }
1281
1282 static void
1283 emit_popup_menu_signal (GtkStatusIcon *status_icon,
1284                         guint          button,
1285                         guint32        activate_time)
1286 {
1287   g_signal_emit (status_icon,
1288                  status_icon_signals [POPUP_MENU_SIGNAL], 0,
1289                  button,
1290                  activate_time);
1291 }
1292
1293 #ifdef GDK_WINDOWING_X11
1294
1295 static gboolean
1296 emit_size_changed_signal (GtkStatusIcon *status_icon,
1297                           gint           size)
1298 {
1299   gboolean handled = FALSE;
1300   
1301   g_signal_emit (status_icon,
1302                  status_icon_signals [SIZE_CHANGED_SIGNAL], 0,
1303                  size,
1304                  &handled);
1305
1306   return handled;
1307 }
1308
1309 #endif
1310
1311 #ifdef GDK_WINDOWING_X11
1312
1313 static GtkIconSize
1314 find_icon_size (GtkWidget *widget, 
1315                 gint       pixel_size)
1316 {
1317   GdkScreen *screen;
1318   GtkSettings *settings;
1319   GtkIconSize s, size;
1320   gint w, h, d, dist;
1321
1322   screen = gtk_widget_get_screen (widget);
1323
1324   if (!screen)
1325     return GTK_ICON_SIZE_MENU;
1326
1327   settings = gtk_settings_get_for_screen (screen);
1328   
1329   dist = G_MAXINT;
1330   size = GTK_ICON_SIZE_MENU;
1331
1332   for (s = GTK_ICON_SIZE_MENU; s <= GTK_ICON_SIZE_DIALOG; s++)
1333     {
1334       if (gtk_icon_size_lookup_for_settings (settings, s, &w, &h) &&
1335           w <= pixel_size && h <= pixel_size)
1336         {
1337           d = MAX (pixel_size - w, pixel_size - h);
1338           if (d < dist)
1339             {
1340               dist = d;
1341               size = s;
1342             }
1343         }
1344     }
1345   
1346   return size;
1347 }
1348
1349 #endif
1350
1351 static void
1352 gtk_status_icon_update_image (GtkStatusIcon *status_icon)
1353 {
1354   GtkStatusIconPrivate *priv = status_icon->priv;
1355 #ifdef GDK_WINDOWING_WIN32
1356   HICON prev_hicon;
1357 #endif
1358
1359   switch (priv->storage_type)
1360     {
1361     case GTK_IMAGE_PIXBUF:
1362       {
1363         GdkPixbuf *pixbuf;
1364
1365         pixbuf = priv->image_data.pixbuf;
1366
1367         if (pixbuf)
1368           {
1369             GdkPixbuf *scaled;
1370             gint size;
1371             gint width;
1372             gint height;
1373
1374             size = priv->size;
1375
1376             width  = gdk_pixbuf_get_width  (pixbuf);
1377             height = gdk_pixbuf_get_height (pixbuf);
1378
1379             if (width > size || height > size)
1380               scaled = gdk_pixbuf_scale_simple (pixbuf,
1381                                                 MIN (size, width),
1382                                                 MIN (size, height),
1383                                                 GDK_INTERP_BILINEAR);
1384             else
1385               scaled = g_object_ref (pixbuf);
1386
1387 #ifdef GDK_WINDOWING_X11
1388             gtk_image_set_from_pixbuf (GTK_IMAGE (priv->image), scaled);
1389 #endif
1390 #ifdef GDK_WINDOWING_WIN32
1391             prev_hicon = priv->nid.hIcon;
1392             priv->nid.hIcon = gdk_win32_pixbuf_to_hicon_libgtk_only (scaled);
1393             priv->nid.uFlags |= NIF_ICON;
1394             if (priv->nid.hWnd != NULL && priv->visible)
1395               if (!Shell_NotifyIconW (NIM_MODIFY, &priv->nid))
1396                   g_warning (G_STRLOC ": Shell_NotifyIcon(NIM_MODIFY) failed");
1397             if (prev_hicon)
1398               DestroyIcon (prev_hicon);
1399 #endif
1400 #ifdef GDK_WINDOWING_QUARTZ
1401       QUARTZ_POOL_ALLOC;
1402       [priv->status_item setImage:scaled];
1403       QUARTZ_POOL_RELEASE;
1404 #endif
1405                         
1406             g_object_unref (scaled);
1407           }
1408         else
1409           {
1410 #ifdef GDK_WINDOWING_X11
1411             gtk_image_set_from_pixbuf (GTK_IMAGE (priv->image), NULL);
1412 #endif
1413 #ifdef GDK_WINDOWING_WIN32
1414             priv->nid.uFlags &= ~NIF_ICON;
1415             if (priv->nid.hWnd != NULL && priv->visible)
1416               if (!Shell_NotifyIconW (NIM_MODIFY, &priv->nid))
1417                 g_warning (G_STRLOC ": Shell_NotifyIcon(NIM_MODIFY) failed");
1418 #endif
1419 #ifdef GDK_WINDOWING_QUARTZ
1420       [priv->status_item setImage:NULL];
1421 #endif
1422           }
1423       }
1424       break;
1425
1426     case GTK_IMAGE_STOCK:
1427       {
1428 #ifdef GDK_WINDOWING_X11
1429         GtkIconSize size = find_icon_size (priv->image, priv->size);
1430         gtk_image_set_from_stock (GTK_IMAGE (priv->image),
1431                                   priv->image_data.stock_id,
1432                                   size);
1433 #endif
1434 #ifdef GDK_WINDOWING_WIN32
1435         {
1436           GdkPixbuf *pixbuf =
1437             gtk_widget_render_icon_pixbuf (priv->dummy_widget,
1438                                            priv->image_data.stock_id,
1439                                            GTK_ICON_SIZE_SMALL_TOOLBAR);
1440
1441           prev_hicon = priv->nid.hIcon;
1442           priv->nid.hIcon = gdk_win32_pixbuf_to_hicon_libgtk_only (pixbuf);
1443           priv->nid.uFlags |= NIF_ICON;
1444           if (priv->nid.hWnd != NULL && priv->visible)
1445             if (!Shell_NotifyIconW (NIM_MODIFY, &priv->nid))
1446               g_warning (G_STRLOC ": Shell_NotifyIcon(NIM_MODIFY) failed");
1447           if (prev_hicon)
1448             DestroyIcon (prev_hicon);
1449           g_object_unref (pixbuf);
1450         }
1451 #endif
1452 #ifdef GDK_WINDOWING_QUARTZ
1453         {
1454           GdkPixbuf *pixbuf;
1455
1456           pixbuf = gtk_widget_render_icon_pixbuf (priv->dummy_widget,
1457                                                   priv->image_data.stock_id,
1458                                                   GTK_ICON_SIZE_SMALL_TOOLBAR);
1459           QUARTZ_POOL_ALLOC;
1460           [priv->status_item setImage:pixbuf];
1461           QUARTZ_POOL_RELEASE;
1462           g_object_unref (pixbuf);
1463         }       
1464 #endif
1465       }
1466       break;
1467       
1468     case GTK_IMAGE_ICON_NAME:
1469       {
1470 #ifdef GDK_WINDOWING_X11
1471         GtkIconSize size = find_icon_size (priv->image, priv->size);
1472         gtk_image_set_from_icon_name (GTK_IMAGE (priv->image),
1473                                       priv->image_data.icon_name,
1474                                       size);
1475 #endif
1476 #ifdef GDK_WINDOWING_WIN32
1477         {
1478           GdkPixbuf *pixbuf =
1479             gtk_icon_theme_load_icon (gtk_icon_theme_get_default (),
1480                                       priv->image_data.icon_name,
1481                                       priv->size,
1482                                       0, NULL);
1483           
1484           prev_hicon = priv->nid.hIcon;
1485           priv->nid.hIcon = gdk_win32_pixbuf_to_hicon_libgtk_only (pixbuf);
1486           priv->nid.uFlags |= NIF_ICON;
1487           if (priv->nid.hWnd != NULL && priv->visible)
1488             if (!Shell_NotifyIconW (NIM_MODIFY, &priv->nid))
1489               g_warning (G_STRLOC ": Shell_NotifyIcon(NIM_MODIFY) failed");
1490           if (prev_hicon)
1491             DestroyIcon (prev_hicon);
1492           g_object_unref (pixbuf);
1493         }
1494 #endif
1495 #ifdef GDK_WINDOWING_QUARTZ
1496         {
1497           GdkPixbuf *pixbuf;
1498
1499           pixbuf = gtk_icon_theme_load_icon (gtk_icon_theme_get_default (),
1500                                              priv->image_data.icon_name,
1501                                              priv->size,
1502                                              0, NULL);
1503
1504           QUARTZ_POOL_ALLOC;
1505           [priv->status_item setImage:pixbuf];
1506           QUARTZ_POOL_RELEASE;
1507           g_object_unref (pixbuf);
1508         }
1509 #endif
1510         
1511       }
1512       break;
1513
1514     case GTK_IMAGE_GICON:
1515       {
1516 #ifdef GDK_WINDOWING_X11
1517         GtkIconSize size = find_icon_size (priv->image, priv->size);
1518         gtk_image_set_from_gicon (GTK_IMAGE (priv->image),
1519                                   priv->image_data.gicon,
1520                                   size);
1521 #endif
1522 #ifdef GDK_WINDOWING_WIN32
1523       {
1524         GtkIconInfo *info =
1525         gtk_icon_theme_lookup_by_gicon (gtk_icon_theme_get_default (),
1526                                         priv->image_data.gicon,
1527                                         priv->size,
1528                                         0);
1529         GdkPixbuf *pixbuf = gtk_icon_info_load_icon (info, NULL);
1530
1531         prev_hicon = priv->nid.hIcon;
1532         priv->nid.hIcon = gdk_win32_pixbuf_to_hicon_libgtk_only (pixbuf);
1533         priv->nid.uFlags |= NIF_ICON;
1534         if (priv->nid.hWnd != NULL && priv->visible)
1535           if (!Shell_NotifyIconW (NIM_MODIFY, &priv->nid))
1536             g_warning (G_STRLOC ": Shell_NotifyIcon(NIM_MODIFY) failed");
1537           if (prev_hicon)
1538             DestroyIcon (prev_hicon);
1539           g_object_unref (pixbuf);
1540       }
1541 #endif
1542 #ifdef GDK_WINDOWING_QUARTZ
1543       {
1544         GtkIconInfo *info =
1545         gtk_icon_theme_lookup_by_gicon (gtk_icon_theme_get_default (),
1546                                         priv->image_data.gicon,
1547                                         priv->size,
1548                                         0);
1549         GdkPixbuf *pixbuf = gtk_icon_info_load_icon (info, NULL);
1550
1551         QUARTZ_POOL_ALLOC;
1552         [priv->status_item setImage:pixbuf];
1553         QUARTZ_POOL_RELEASE;
1554         g_object_unref (pixbuf);
1555       }
1556 #endif
1557
1558       }
1559       break;
1560
1561     case GTK_IMAGE_EMPTY:
1562 #ifdef GDK_WINDOWING_X11
1563       gtk_image_set_from_pixbuf (GTK_IMAGE (priv->image), NULL);
1564 #endif
1565 #ifdef GDK_WINDOWING_WIN32
1566       priv->nid.uFlags &= ~NIF_ICON;
1567       if (priv->nid.hWnd != NULL && priv->visible)
1568         if (!Shell_NotifyIconW (NIM_MODIFY, &priv->nid))
1569           g_warning (G_STRLOC ": Shell_NotifyIcon(NIM_MODIFY) failed");
1570 #endif
1571 #ifdef GDK_WINDOWING_QUARTZ
1572         {
1573           QUARTZ_POOL_ALLOC;
1574           [priv->status_item setImage:NULL];
1575           QUARTZ_POOL_RELEASE;
1576         }
1577 #endif
1578       break;
1579     default:
1580       g_assert_not_reached ();
1581       break;
1582     }
1583 }
1584
1585 #ifdef GDK_WINDOWING_X11
1586
1587 static void
1588 gtk_status_icon_size_allocate (GtkStatusIcon *status_icon,
1589                                GtkAllocation *allocation)
1590 {
1591   GtkStatusIconPrivate *priv = status_icon->priv;
1592   GtkOrientation orientation;
1593   gint size;
1594   gint xpad, ypad;
1595
1596   orientation = _gtk_tray_icon_get_orientation (GTK_TRAY_ICON (priv->tray_icon));
1597
1598   if (orientation == GTK_ORIENTATION_HORIZONTAL)
1599     size = allocation->height;
1600   else
1601     size = allocation->width;
1602
1603   gtk_misc_get_padding (GTK_MISC (priv->image), &xpad, &ypad);
1604
1605   priv->image_width = allocation->width - xpad * 2;
1606   priv->image_height = allocation->height - ypad * 2;
1607
1608   if (priv->size != size)
1609     {
1610       priv->size = size;
1611
1612       g_object_notify (G_OBJECT (status_icon), "size");
1613
1614       if (!emit_size_changed_signal (status_icon, size))
1615         gtk_status_icon_update_image (status_icon);
1616     }
1617 }
1618
1619 static void
1620 gtk_status_icon_screen_changed (GtkStatusIcon *status_icon,
1621                                 GdkScreen *old_screen)
1622 {
1623   GtkStatusIconPrivate *priv = status_icon->priv;
1624
1625   if (gtk_widget_get_screen (priv->tray_icon) != old_screen)
1626     {
1627       g_object_notify (G_OBJECT (status_icon), "screen");
1628     }
1629 }
1630
1631 #endif
1632
1633 #ifdef GDK_WINDOWING_X11
1634
1635 static void
1636 gtk_status_icon_padding_changed (GtkStatusIcon *status_icon)
1637 {
1638   GtkStatusIconPrivate *priv = status_icon->priv;
1639   GtkOrientation orientation;
1640   gint padding;
1641
1642   orientation = _gtk_tray_icon_get_orientation (GTK_TRAY_ICON (priv->tray_icon));
1643   padding = _gtk_tray_icon_get_padding (GTK_TRAY_ICON (priv->tray_icon));
1644
1645   if (orientation == GTK_ORIENTATION_HORIZONTAL)
1646     gtk_misc_set_padding (GTK_MISC (priv->image), padding, 0);
1647   else
1648     gtk_misc_set_padding (GTK_MISC (priv->image), 0, padding);
1649 }
1650
1651 static void
1652 gtk_status_icon_embedded_changed (GtkStatusIcon *status_icon)
1653 {
1654   gtk_status_icon_padding_changed (status_icon);
1655   g_object_notify (G_OBJECT (status_icon), "embedded");
1656 }
1657
1658 static void
1659 gtk_status_icon_orientation_changed (GtkStatusIcon *status_icon)
1660 {
1661   gtk_status_icon_padding_changed (status_icon);
1662   g_object_notify (G_OBJECT (status_icon), "orientation");
1663 }
1664
1665 static void
1666 gtk_status_icon_fg_changed (GtkStatusIcon *status_icon)
1667 {
1668   GtkStatusIconPrivate *priv = status_icon->priv;
1669   GdkColor color;
1670
1671   g_object_get (priv->tray_icon, "fg-color", &color, NULL);
1672   gtk_widget_modify_fg (priv->image, GTK_STATE_NORMAL, &color);
1673 }
1674
1675 static void
1676 gtk_status_icon_color_changed (GtkTrayIcon   *tray,
1677                                GParamSpec    *pspec,
1678                                GtkStatusIcon *status_icon)
1679 {
1680   GtkStatusIconPrivate *priv = status_icon->priv;
1681   const gchar *name;
1682   GdkColor color;
1683
1684   switch (pspec->name[0])
1685     {
1686     case 'e':
1687       name = "error";
1688       break;
1689     case 'w':
1690       name = "warning";
1691       break;
1692     case 's':
1693       name = "success";
1694       break;
1695     default:
1696       name = NULL;
1697       break;
1698     }
1699
1700   if (name)
1701     {
1702       GdkRGBA rgba;
1703
1704       g_object_get (priv->tray_icon, pspec->name, &color, NULL);
1705
1706       rgba.red = color.red / 65535.;
1707       rgba.green = color.green / 65535.;
1708       rgba.blue = color.blue / 65535.;
1709       rgba.alpha = 1;
1710
1711       gtk_widget_override_symbolic_color (priv->image, name, &rgba);
1712     }
1713 }
1714
1715 static gboolean
1716 gtk_status_icon_key_press (GtkStatusIcon  *status_icon,
1717                            GdkEventKey    *event)
1718 {
1719   guint state, keyval;
1720
1721   state = event->state & gtk_accelerator_get_default_mod_mask ();
1722   keyval = event->keyval;
1723   if (state == 0 &&
1724       (keyval == GDK_KEY_Return ||
1725        keyval == GDK_KEY_KP_Enter ||
1726        keyval == GDK_KEY_ISO_Enter ||
1727        keyval == GDK_KEY_space ||
1728        keyval == GDK_KEY_KP_Space))
1729     {
1730       emit_activate_signal (status_icon);
1731       return TRUE;
1732     }
1733
1734   return FALSE;
1735 }
1736
1737 static void
1738 gtk_status_icon_popup_menu (GtkStatusIcon  *status_icon)
1739 {
1740   emit_popup_menu_signal (status_icon, 0, gtk_get_current_event_time ());
1741 }
1742
1743 #endif
1744
1745 static gboolean
1746 gtk_status_icon_button_press (GtkStatusIcon  *status_icon,
1747                               GdkEventButton *event)
1748 {
1749   gboolean handled = FALSE;
1750
1751   g_signal_emit (status_icon,
1752                  status_icon_signals [BUTTON_PRESS_EVENT_SIGNAL], 0,
1753                  event, &handled);
1754   if (handled)
1755     return TRUE;
1756
1757   if (event->button == 1 && event->type == GDK_BUTTON_PRESS)
1758     {
1759       emit_activate_signal (status_icon);
1760       return TRUE;
1761     }
1762   else if (event->button == 3 && event->type == GDK_BUTTON_PRESS)
1763     {
1764       emit_popup_menu_signal (status_icon, event->button, event->time);
1765       return TRUE;
1766     }
1767
1768   return FALSE;
1769 }
1770
1771 static gboolean
1772 gtk_status_icon_button_release (GtkStatusIcon  *status_icon,
1773                                 GdkEventButton *event)
1774 {
1775   gboolean handled = FALSE;
1776   g_signal_emit (status_icon,
1777                  status_icon_signals [BUTTON_RELEASE_EVENT_SIGNAL], 0,
1778                  event, &handled);
1779   return handled;
1780 }
1781
1782 #ifdef GDK_WINDOWING_X11
1783 static gboolean
1784 gtk_status_icon_scroll (GtkStatusIcon  *status_icon,
1785                         GdkEventScroll *event)
1786 {
1787   gboolean handled = FALSE;
1788   g_signal_emit (status_icon,
1789                  status_icon_signals [SCROLL_EVENT_SIGNAL], 0,
1790                  event, &handled);
1791   return handled;
1792 }
1793
1794 static gboolean
1795 gtk_status_icon_query_tooltip (GtkStatusIcon *status_icon,
1796                                gint           x,
1797                                gint           y,
1798                                gboolean       keyboard_tip,
1799                                GtkTooltip    *tooltip)
1800 {
1801   gboolean handled = FALSE;
1802   g_signal_emit (status_icon,
1803                  status_icon_signals [QUERY_TOOLTIP_SIGNAL], 0,
1804                  x, y, keyboard_tip, tooltip, &handled);
1805   return handled;
1806 }
1807 #endif /* GDK_WINDOWING_X11 */
1808
1809 static void
1810 gtk_status_icon_reset_image_data (GtkStatusIcon *status_icon)
1811 {
1812   GtkStatusIconPrivate *priv = status_icon->priv;
1813
1814   switch (priv->storage_type)
1815   {
1816     case GTK_IMAGE_PIXBUF:
1817       if (priv->image_data.pixbuf)
1818         g_object_unref (priv->image_data.pixbuf);
1819       priv->image_data.pixbuf = NULL;
1820       g_object_notify (G_OBJECT (status_icon), "pixbuf");
1821       break;
1822
1823     case GTK_IMAGE_STOCK:
1824       g_free (priv->image_data.stock_id);
1825       priv->image_data.stock_id = NULL;
1826
1827       g_object_notify (G_OBJECT (status_icon), "stock");
1828       break;
1829       
1830     case GTK_IMAGE_ICON_NAME:
1831       g_free (priv->image_data.icon_name);
1832       priv->image_data.icon_name = NULL;
1833
1834       g_object_notify (G_OBJECT (status_icon), "icon-name");
1835       break;
1836
1837     case GTK_IMAGE_GICON:
1838       if (priv->image_data.gicon)
1839         g_object_unref (priv->image_data.gicon);
1840       priv->image_data.gicon = NULL;
1841
1842       g_object_notify (G_OBJECT (status_icon), "gicon");
1843       break;
1844
1845     case GTK_IMAGE_EMPTY:
1846       break;
1847     default:
1848       g_assert_not_reached ();
1849       break;
1850   }
1851
1852   priv->storage_type = GTK_IMAGE_EMPTY;
1853   g_object_notify (G_OBJECT (status_icon), "storage-type");
1854 }
1855
1856 static void
1857 gtk_status_icon_set_image (GtkStatusIcon *status_icon,
1858                            GtkImageType   storage_type,
1859                            gpointer       data)
1860 {
1861   GtkStatusIconPrivate *priv = status_icon->priv;
1862
1863   g_object_freeze_notify (G_OBJECT (status_icon));
1864
1865   gtk_status_icon_reset_image_data (status_icon);
1866
1867   priv->storage_type = storage_type;
1868   g_object_notify (G_OBJECT (status_icon), "storage-type");
1869
1870   switch (storage_type) 
1871     {
1872     case GTK_IMAGE_PIXBUF:
1873       priv->image_data.pixbuf = (GdkPixbuf *)data;
1874       g_object_notify (G_OBJECT (status_icon), "pixbuf");
1875       break;
1876     case GTK_IMAGE_STOCK:
1877       priv->image_data.stock_id = g_strdup ((const gchar *)data);
1878       g_object_notify (G_OBJECT (status_icon), "stock");
1879       break;
1880     case GTK_IMAGE_ICON_NAME:
1881       priv->image_data.icon_name = g_strdup ((const gchar *)data);
1882       g_object_notify (G_OBJECT (status_icon), "icon-name");
1883       break;
1884     case GTK_IMAGE_GICON:
1885       priv->image_data.gicon = (GIcon *)data;
1886       g_object_notify (G_OBJECT (status_icon), "gicon");
1887       break;
1888     default:
1889       g_warning ("Image type %u not handled by GtkStatusIcon", storage_type);
1890     }
1891
1892   g_object_thaw_notify (G_OBJECT (status_icon));
1893
1894   gtk_status_icon_update_image (status_icon);
1895 }
1896
1897 /**
1898  * gtk_status_icon_set_from_pixbuf:
1899  * @status_icon: a #GtkStatusIcon
1900  * @pixbuf: (allow-none): a #GdkPixbuf or %NULL
1901  *
1902  * Makes @status_icon display @pixbuf.
1903  * See gtk_status_icon_new_from_pixbuf() for details.
1904  *
1905  * Since: 2.10
1906  **/
1907 void
1908 gtk_status_icon_set_from_pixbuf (GtkStatusIcon *status_icon,
1909                                  GdkPixbuf     *pixbuf)
1910 {
1911   g_return_if_fail (GTK_IS_STATUS_ICON (status_icon));
1912   g_return_if_fail (pixbuf == NULL || GDK_IS_PIXBUF (pixbuf));
1913
1914   if (pixbuf)
1915     g_object_ref (pixbuf);
1916
1917   gtk_status_icon_set_image (status_icon, GTK_IMAGE_PIXBUF,
1918                              (gpointer) pixbuf);
1919 }
1920
1921 /**
1922  * gtk_status_icon_set_from_file:
1923  * @status_icon: a #GtkStatusIcon
1924  * @filename: a filename
1925  * 
1926  * Makes @status_icon display the file @filename.
1927  * See gtk_status_icon_new_from_file() for details.
1928  *
1929  * Since: 2.10 
1930  **/
1931 void
1932 gtk_status_icon_set_from_file (GtkStatusIcon *status_icon,
1933                                const gchar   *filename)
1934 {
1935   GdkPixbuf *pixbuf;
1936   
1937   g_return_if_fail (GTK_IS_STATUS_ICON (status_icon));
1938   g_return_if_fail (filename != NULL);
1939   
1940   pixbuf = gdk_pixbuf_new_from_file (filename, NULL);
1941   
1942   gtk_status_icon_set_from_pixbuf (status_icon, pixbuf);
1943   
1944   if (pixbuf)
1945     g_object_unref (pixbuf);
1946 }
1947
1948 /**
1949  * gtk_status_icon_set_from_stock:
1950  * @status_icon: a #GtkStatusIcon
1951  * @stock_id: a stock icon id
1952  * 
1953  * Makes @status_icon display the stock icon with the id @stock_id.
1954  * See gtk_status_icon_new_from_stock() for details.
1955  *
1956  * Since: 2.10 
1957  **/
1958 void
1959 gtk_status_icon_set_from_stock (GtkStatusIcon *status_icon,
1960                                 const gchar   *stock_id)
1961 {
1962   g_return_if_fail (GTK_IS_STATUS_ICON (status_icon));
1963   g_return_if_fail (stock_id != NULL);
1964
1965   gtk_status_icon_set_image (status_icon, GTK_IMAGE_STOCK,
1966                              (gpointer) stock_id);
1967 }
1968
1969 /**
1970  * gtk_status_icon_set_from_icon_name:
1971  * @status_icon: a #GtkStatusIcon
1972  * @icon_name: an icon name
1973  * 
1974  * Makes @status_icon display the icon named @icon_name from the 
1975  * current icon theme.
1976  * See gtk_status_icon_new_from_icon_name() for details.
1977  *
1978  * Since: 2.10 
1979  **/
1980 void
1981 gtk_status_icon_set_from_icon_name (GtkStatusIcon *status_icon,
1982                                     const gchar   *icon_name)
1983 {
1984   g_return_if_fail (GTK_IS_STATUS_ICON (status_icon));
1985   g_return_if_fail (icon_name != NULL);
1986
1987   gtk_status_icon_set_image (status_icon, GTK_IMAGE_ICON_NAME,
1988                              (gpointer) icon_name);
1989 }
1990
1991 /**
1992  * gtk_status_icon_set_from_gicon:
1993  * @status_icon: a #GtkStatusIcon
1994  * @icon: a GIcon
1995  *
1996  * Makes @status_icon display the #GIcon.
1997  * See gtk_status_icon_new_from_gicon() for details.
1998  *
1999  * Since: 2.14
2000  **/
2001 void
2002 gtk_status_icon_set_from_gicon (GtkStatusIcon *status_icon,
2003                                 GIcon         *icon)
2004 {
2005   g_return_if_fail (GTK_IS_STATUS_ICON (status_icon));
2006   g_return_if_fail (icon != NULL);
2007
2008   if (icon)
2009     g_object_ref (icon);
2010
2011   gtk_status_icon_set_image (status_icon, GTK_IMAGE_GICON,
2012                              (gpointer) icon);
2013 }
2014
2015 /**
2016  * gtk_status_icon_get_storage_type:
2017  * @status_icon: a #GtkStatusIcon
2018  * 
2019  * Gets the type of representation being used by the #GtkStatusIcon
2020  * to store image data. If the #GtkStatusIcon has no image data,
2021  * the return value will be %GTK_IMAGE_EMPTY. 
2022  * 
2023  * Return value: the image representation being used
2024  *
2025  * Since: 2.10
2026  **/
2027 GtkImageType
2028 gtk_status_icon_get_storage_type (GtkStatusIcon *status_icon)
2029 {
2030   g_return_val_if_fail (GTK_IS_STATUS_ICON (status_icon), GTK_IMAGE_EMPTY);
2031
2032   return status_icon->priv->storage_type;
2033 }
2034 /**
2035  * gtk_status_icon_get_pixbuf:
2036  * @status_icon: a #GtkStatusIcon
2037  * 
2038  * Gets the #GdkPixbuf being displayed by the #GtkStatusIcon.
2039  * The storage type of the status icon must be %GTK_IMAGE_EMPTY or
2040  * %GTK_IMAGE_PIXBUF (see gtk_status_icon_get_storage_type()).
2041  * The caller of this function does not own a reference to the
2042  * returned pixbuf.
2043  * 
2044  * Return value: (transfer none): the displayed pixbuf,
2045  *     or %NULL if the image is empty.
2046  *
2047  * Since: 2.10
2048  **/
2049 GdkPixbuf *
2050 gtk_status_icon_get_pixbuf (GtkStatusIcon *status_icon)
2051 {
2052   GtkStatusIconPrivate *priv;
2053
2054   g_return_val_if_fail (GTK_IS_STATUS_ICON (status_icon), NULL);
2055
2056   priv = status_icon->priv;
2057
2058   g_return_val_if_fail (priv->storage_type == GTK_IMAGE_PIXBUF ||
2059                         priv->storage_type == GTK_IMAGE_EMPTY, NULL);
2060
2061   if (priv->storage_type == GTK_IMAGE_EMPTY)
2062     priv->image_data.pixbuf = NULL;
2063
2064   return priv->image_data.pixbuf;
2065 }
2066
2067 /**
2068  * gtk_status_icon_get_stock:
2069  * @status_icon: a #GtkStatusIcon
2070  * 
2071  * Gets the id of the stock icon being displayed by the #GtkStatusIcon.
2072  * The storage type of the status icon must be %GTK_IMAGE_EMPTY or
2073  * %GTK_IMAGE_STOCK (see gtk_status_icon_get_storage_type()).
2074  * The returned string is owned by the #GtkStatusIcon and should not
2075  * be freed or modified.
2076  * 
2077  * Return value: stock id of the displayed stock icon,
2078  *   or %NULL if the image is empty.
2079  *
2080  * Since: 2.10
2081  **/
2082 G_CONST_RETURN gchar *
2083 gtk_status_icon_get_stock (GtkStatusIcon *status_icon)
2084 {
2085   GtkStatusIconPrivate *priv;
2086
2087   g_return_val_if_fail (GTK_IS_STATUS_ICON (status_icon), NULL);
2088
2089   priv = status_icon->priv;
2090
2091   g_return_val_if_fail (priv->storage_type == GTK_IMAGE_STOCK ||
2092                         priv->storage_type == GTK_IMAGE_EMPTY, NULL);
2093   
2094   if (priv->storage_type == GTK_IMAGE_EMPTY)
2095     priv->image_data.stock_id = NULL;
2096
2097   return priv->image_data.stock_id;
2098 }
2099
2100 /**
2101  * gtk_status_icon_get_icon_name:
2102  * @status_icon: a #GtkStatusIcon
2103  * 
2104  * Gets the name of the icon being displayed by the #GtkStatusIcon.
2105  * The storage type of the status icon must be %GTK_IMAGE_EMPTY or
2106  * %GTK_IMAGE_ICON_NAME (see gtk_status_icon_get_storage_type()).
2107  * The returned string is owned by the #GtkStatusIcon and should not
2108  * be freed or modified.
2109  * 
2110  * Return value: name of the displayed icon, or %NULL if the image is empty.
2111  *
2112  * Since: 2.10
2113  **/
2114 G_CONST_RETURN gchar *
2115 gtk_status_icon_get_icon_name (GtkStatusIcon *status_icon)
2116 {
2117   GtkStatusIconPrivate *priv;
2118   
2119   g_return_val_if_fail (GTK_IS_STATUS_ICON (status_icon), NULL);
2120
2121   priv = status_icon->priv;
2122
2123   g_return_val_if_fail (priv->storage_type == GTK_IMAGE_ICON_NAME ||
2124                         priv->storage_type == GTK_IMAGE_EMPTY, NULL);
2125
2126   if (priv->storage_type == GTK_IMAGE_EMPTY)
2127     priv->image_data.icon_name = NULL;
2128
2129   return priv->image_data.icon_name;
2130 }
2131
2132 /**
2133  * gtk_status_icon_get_gicon:
2134  * @status_icon: a #GtkStatusIcon
2135  *
2136  * Retrieves the #GIcon being displayed by the #GtkStatusIcon.
2137  * The storage type of the status icon must be %GTK_IMAGE_EMPTY or
2138  * %GTK_IMAGE_GICON (see gtk_status_icon_get_storage_type()).
2139  * The caller of this function does not own a reference to the
2140  * returned #GIcon.
2141  *
2142  * If this function fails, @icon is left unchanged;
2143  *
2144  * Returns: (transfer none): the displayed icon, or %NULL if the image is empty
2145  *
2146  * Since: 2.14
2147  **/
2148 GIcon *
2149 gtk_status_icon_get_gicon (GtkStatusIcon *status_icon)
2150 {
2151   GtkStatusIconPrivate *priv;
2152
2153   g_return_val_if_fail (GTK_IS_STATUS_ICON (status_icon), NULL);
2154
2155   priv = status_icon->priv;
2156
2157   g_return_val_if_fail (priv->storage_type == GTK_IMAGE_GICON ||
2158                         priv->storage_type == GTK_IMAGE_EMPTY, NULL);
2159
2160   if (priv->storage_type == GTK_IMAGE_EMPTY)
2161     priv->image_data.gicon = NULL;
2162
2163   return priv->image_data.gicon;
2164 }
2165
2166 /**
2167  * gtk_status_icon_get_size:
2168  * @status_icon: a #GtkStatusIcon
2169  * 
2170  * Gets the size in pixels that is available for the image. 
2171  * Stock icons and named icons adapt their size automatically
2172  * if the size of the notification area changes. For other
2173  * storage types, the size-changed signal can be used to
2174  * react to size changes.
2175  *
2176  * Note that the returned size is only meaningful while the 
2177  * status icon is embedded (see gtk_status_icon_is_embedded()).
2178  * 
2179  * Return value: the size that is available for the image
2180  *
2181  * Since: 2.10
2182  **/
2183 gint
2184 gtk_status_icon_get_size (GtkStatusIcon *status_icon)
2185 {
2186   g_return_val_if_fail (GTK_IS_STATUS_ICON (status_icon), 0);
2187
2188   return status_icon->priv->size;
2189 }
2190
2191 /**
2192  * gtk_status_icon_set_screen:
2193  * @status_icon: a #GtkStatusIcon
2194  * @screen: a #GdkScreen
2195  *
2196  * Sets the #GdkScreen where @status_icon is displayed; if
2197  * the icon is already mapped, it will be unmapped, and
2198  * then remapped on the new screen.
2199  *
2200  * Since: 2.12
2201  */
2202 void
2203 gtk_status_icon_set_screen (GtkStatusIcon *status_icon,
2204                             GdkScreen     *screen)
2205 {
2206   g_return_if_fail (GDK_IS_SCREEN (screen));
2207
2208 #ifdef GDK_WINDOWING_X11
2209   gtk_window_set_screen (GTK_WINDOW (status_icon->priv->tray_icon), screen);
2210 #endif
2211 }
2212
2213 /**
2214  * gtk_status_icon_get_screen:
2215  * @status_icon: a #GtkStatusIcon
2216  *
2217  * Returns the #GdkScreen associated with @status_icon.
2218  *
2219  * Return value: (transfer none): a #GdkScreen.
2220  *
2221  * Since: 2.12
2222  */
2223 GdkScreen *
2224 gtk_status_icon_get_screen (GtkStatusIcon *status_icon)
2225 {
2226   g_return_val_if_fail (GTK_IS_STATUS_ICON (status_icon), NULL);
2227
2228 #ifdef GDK_WINDOWING_X11
2229   return gtk_window_get_screen (GTK_WINDOW (status_icon->priv->tray_icon));
2230 #else
2231   return gdk_screen_get_default ();
2232 #endif
2233 }
2234
2235 /**
2236  * gtk_status_icon_set_visible:
2237  * @status_icon: a #GtkStatusIcon
2238  * @visible: %TRUE to show the status icon, %FALSE to hide it
2239  * 
2240  * Shows or hides a status icon.
2241  *
2242  * Since: 2.10
2243  **/
2244 void
2245 gtk_status_icon_set_visible (GtkStatusIcon *status_icon,
2246                              gboolean       visible)
2247 {
2248   GtkStatusIconPrivate *priv;
2249
2250   g_return_if_fail (GTK_IS_STATUS_ICON (status_icon));
2251
2252   priv = status_icon->priv;
2253
2254   visible = visible != FALSE;
2255
2256   if (priv->visible != visible)
2257     {
2258       priv->visible = visible;
2259
2260 #ifdef GDK_WINDOWING_X11
2261       if (visible)
2262         gtk_widget_show (priv->tray_icon);
2263       else if (gtk_widget_get_realized (priv->tray_icon))
2264         {
2265           gtk_widget_hide (priv->tray_icon);
2266           gtk_widget_unrealize (priv->tray_icon);
2267         }
2268 #endif
2269 #ifdef GDK_WINDOWING_WIN32
2270       if (priv->nid.hWnd != NULL)
2271         {
2272           if (visible)
2273             Shell_NotifyIconW (NIM_ADD, &priv->nid);
2274           else
2275             Shell_NotifyIconW (NIM_DELETE, &priv->nid);
2276         }
2277 #endif
2278 #ifdef GDK_WINDOWING_QUARTZ
2279       QUARTZ_POOL_ALLOC;
2280       [priv->status_item setVisible:visible];
2281       QUARTZ_POOL_RELEASE;
2282 #endif
2283       g_object_notify (G_OBJECT (status_icon), "visible");
2284     }
2285 }
2286
2287 /**
2288  * gtk_status_icon_get_visible:
2289  * @status_icon: a #GtkStatusIcon
2290  * 
2291  * Returns whether the status icon is visible or not. 
2292  * Note that being visible does not guarantee that 
2293  * the user can actually see the icon, see also 
2294  * gtk_status_icon_is_embedded().
2295  * 
2296  * Return value: %TRUE if the status icon is visible
2297  *
2298  * Since: 2.10
2299  **/
2300 gboolean
2301 gtk_status_icon_get_visible (GtkStatusIcon *status_icon)
2302 {
2303   g_return_val_if_fail (GTK_IS_STATUS_ICON (status_icon), FALSE);
2304
2305   return status_icon->priv->visible;
2306 }
2307
2308 /**
2309  * gtk_status_icon_is_embedded:
2310  * @status_icon: a #GtkStatusIcon
2311  * 
2312  * Returns whether the status icon is embedded in a notification
2313  * area. 
2314  * 
2315  * Return value: %TRUE if the status icon is embedded in
2316  *   a notification area.
2317  *
2318  * Since: 2.10
2319  **/
2320 gboolean
2321 gtk_status_icon_is_embedded (GtkStatusIcon *status_icon)
2322 {
2323 #ifdef GDK_WINDOWING_X11
2324   GtkPlug *plug;
2325 #endif
2326
2327   g_return_val_if_fail (GTK_IS_STATUS_ICON (status_icon), FALSE);
2328
2329 #ifdef GDK_WINDOWING_X11
2330   plug = GTK_PLUG (status_icon->priv->tray_icon);
2331
2332   if (gtk_plug_get_embedded (plug))
2333     return TRUE;
2334   else
2335     return FALSE;
2336 #endif
2337 #ifdef GDK_WINDOWING_WIN32
2338   return TRUE;
2339 #endif
2340 #ifdef GDK_WINDOWING_QUARTZ
2341   return TRUE;
2342 #endif
2343 }
2344
2345 /**
2346  * gtk_status_icon_position_menu:
2347  * @menu: the #GtkMenu
2348  * @x: return location for the x position
2349  * @y: return location for the y position
2350  * @push_in: whether the first menu item should be offset (pushed in) to be
2351  *           aligned with the menu popup position (only useful for GtkOptionMenu).
2352  * @user_data: the status icon to position the menu on
2353  *
2354  * Menu positioning function to use with gtk_menu_popup()
2355  * to position @menu aligned to the status icon @user_data.
2356  * 
2357  * Since: 2.10
2358  **/
2359 void
2360 gtk_status_icon_position_menu (GtkMenu  *menu,
2361                                gint     *x,
2362                                gint     *y,
2363                                gboolean *push_in,
2364                                gpointer  user_data)
2365 {
2366 #ifdef GDK_WINDOWING_X11
2367   GtkAllocation allocation;
2368   GtkStatusIcon *status_icon;
2369   GtkStatusIconPrivate *priv;
2370   GtkTrayIcon *tray_icon;
2371   GtkWidget *widget;
2372   GdkScreen *screen;
2373   GtkTextDirection direction;
2374   GtkRequisition menu_req;
2375   GdkRectangle monitor;
2376   GdkWindow *window;
2377   gint monitor_num, height, width, xoffset, yoffset;
2378   
2379   g_return_if_fail (GTK_IS_MENU (menu));
2380   g_return_if_fail (GTK_IS_STATUS_ICON (user_data));
2381
2382   status_icon = GTK_STATUS_ICON (user_data);
2383   priv = status_icon->priv;
2384   tray_icon = GTK_TRAY_ICON (priv->tray_icon);
2385   widget = priv->tray_icon;
2386
2387   direction = gtk_widget_get_direction (widget);
2388
2389   screen = gtk_widget_get_screen (widget);
2390   gtk_menu_set_screen (menu, screen);
2391
2392   window = gtk_widget_get_window (widget);
2393   monitor_num = gdk_screen_get_monitor_at_window (screen, window);
2394   if (monitor_num < 0)
2395     monitor_num = 0;
2396   gtk_menu_set_monitor (menu, monitor_num);
2397
2398   gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor);
2399
2400   gdk_window_get_origin (window, x, y);
2401
2402   gtk_widget_get_preferred_size (GTK_WIDGET (menu),
2403                                  &menu_req, NULL);
2404
2405   gtk_widget_get_allocation (widget, &allocation);
2406   if (_gtk_tray_icon_get_orientation (tray_icon) == GTK_ORIENTATION_VERTICAL)
2407     {
2408       width = 0;
2409       height = allocation.height;
2410       xoffset = allocation.width;
2411       yoffset = 0;
2412     }
2413   else
2414     {
2415       width = allocation.width;
2416       height = 0;
2417       xoffset = 0;
2418       yoffset = allocation.height;
2419     }
2420
2421   if (direction == GTK_TEXT_DIR_RTL)
2422     {
2423       if ((*x - (menu_req.width - width)) >= monitor.x)
2424         *x -= menu_req.width - width;
2425       else if ((*x + xoffset + menu_req.width) < (monitor.x + monitor.width))
2426         *x += xoffset;
2427       else if ((monitor.x + monitor.width - (*x + xoffset)) < *x)
2428         *x -= menu_req.width - width;
2429       else
2430         *x += xoffset;
2431     }
2432   else
2433     {
2434       if ((*x + xoffset + menu_req.width) < (monitor.x + monitor.width))
2435         *x += xoffset;
2436       else if ((*x - (menu_req.width - width)) >= monitor.x)
2437         *x -= menu_req.width - width;
2438       else if ((monitor.x + monitor.width - (*x + xoffset)) > *x)
2439         *x += xoffset;
2440       else 
2441         *x -= menu_req.width - width;
2442     }
2443
2444   if ((*y + yoffset + menu_req.height) < (monitor.y + monitor.height))
2445     *y += yoffset;
2446   else if ((*y - (menu_req.height - height)) >= monitor.y)
2447     *y -= menu_req.height - height;
2448   else if (monitor.y + monitor.height - (*y + yoffset) > *y)
2449     *y += yoffset;
2450   else 
2451     *y -= menu_req.height - height;
2452
2453   *push_in = FALSE;
2454 #endif /* GDK_WINDOWING_X11 */
2455
2456 #ifdef GDK_WINDOWING_WIN32
2457   GtkStatusIcon *status_icon;
2458   GtkStatusIconPrivate *priv;
2459   
2460   g_return_if_fail (GTK_IS_MENU (menu));
2461   g_return_if_fail (GTK_IS_STATUS_ICON (user_data));
2462
2463   status_icon = GTK_STATUS_ICON (user_data);
2464   priv = status_icon->priv;
2465
2466   *x = priv->last_click_x;
2467   *y = priv->last_click_y;
2468   *push_in = TRUE;
2469 #endif
2470 }
2471
2472 /**
2473  * gtk_status_icon_get_geometry:
2474  * @status_icon: a #GtkStatusIcon
2475  * @screen: (out) (transfer none) (allow-none): return location for the screen, or %NULL if the
2476  *          information is not needed
2477  * @area: (out) (allow-none): return location for the area occupied by the status
2478  *        icon, or %NULL
2479  * @orientation: (out) (allow-none): return location for the orientation of the panel
2480  *    in which the status icon is embedded, or %NULL. A panel
2481  *    at the top or bottom of the screen is horizontal, a panel
2482  *    at the left or right is vertical.
2483  *
2484  * Obtains information about the location of the status icon
2485  * on screen. This information can be used to e.g. position 
2486  * popups like notification bubbles. 
2487  *
2488  * See gtk_status_icon_position_menu() for a more convenient 
2489  * alternative for positioning menus.
2490  *
2491  * Note that some platforms do not allow GTK+ to provide 
2492  * this information, and even on platforms that do allow it,
2493  * the information is not reliable unless the status icon
2494  * is embedded in a notification area, see
2495  * gtk_status_icon_is_embedded().
2496  *
2497  * Return value: %TRUE if the location information has 
2498  *               been filled in
2499  *
2500  * Since: 2.10
2501  */
2502 gboolean  
2503 gtk_status_icon_get_geometry (GtkStatusIcon    *status_icon,
2504                               GdkScreen       **screen,
2505                               GdkRectangle     *area,
2506                               GtkOrientation   *orientation)
2507 {
2508 #ifdef GDK_WINDOWING_X11   
2509   GtkAllocation allocation;
2510   GtkWidget *widget;
2511   GtkStatusIconPrivate *priv;
2512   gint x, y;
2513
2514   g_return_val_if_fail (GTK_IS_STATUS_ICON (status_icon), FALSE);
2515
2516   priv = status_icon->priv;
2517   widget = priv->tray_icon;
2518
2519   if (screen)
2520     *screen = gtk_widget_get_screen (widget);
2521
2522   if (area)
2523     {
2524       gdk_window_get_origin (gtk_widget_get_window (widget),
2525                              &x, &y);
2526
2527       gtk_widget_get_allocation (widget, &allocation);
2528       area->x = x;
2529       area->y = y;
2530       area->width = allocation.width;
2531       area->height = allocation.height;
2532     }
2533
2534   if (orientation)
2535     *orientation = _gtk_tray_icon_get_orientation (GTK_TRAY_ICON (widget));
2536
2537   return TRUE;
2538 #else
2539   return FALSE;
2540 #endif /* GDK_WINDOWING_X11 */
2541 }
2542
2543 /**
2544  * gtk_status_icon_set_has_tooltip:
2545  * @status_icon: a #GtkStatusIcon
2546  * @has_tooltip: whether or not @status_icon has a tooltip
2547  *
2548  * Sets the has-tooltip property on @status_icon to @has_tooltip.
2549  * See #GtkStatusIcon:has-tooltip for more information.
2550  *
2551  * Since: 2.16
2552  */
2553 void
2554 gtk_status_icon_set_has_tooltip (GtkStatusIcon *status_icon,
2555                                  gboolean       has_tooltip)
2556 {
2557   GtkStatusIconPrivate *priv;
2558
2559   g_return_if_fail (GTK_IS_STATUS_ICON (status_icon));
2560
2561   priv = status_icon->priv;
2562
2563 #ifdef GDK_WINDOWING_X11
2564   gtk_widget_set_has_tooltip (priv->tray_icon, has_tooltip);
2565 #endif
2566 #ifdef GDK_WINDOWING_WIN32
2567   if (!has_tooltip && priv->tooltip_text)
2568     gtk_status_icon_set_tooltip_text (status_icon, NULL);
2569 #endif
2570 #ifdef GDK_WINDOWING_QUARTZ
2571   if (!has_tooltip && priv->tooltip_text)
2572     gtk_status_icon_set_tooltip_text (status_icon, NULL);
2573 #endif
2574 }
2575
2576 /**
2577  * gtk_status_icon_get_has_tooltip:
2578  * @status_icon: a #GtkStatusIcon
2579  *
2580  * Returns the current value of the has-tooltip property.
2581  * See #GtkStatusIcon:has-tooltip for more information.
2582  *
2583  * Return value: current value of has-tooltip on @status_icon.
2584  *
2585  * Since: 2.16
2586  */
2587 gboolean
2588 gtk_status_icon_get_has_tooltip (GtkStatusIcon *status_icon)
2589 {
2590   GtkStatusIconPrivate *priv;
2591   gboolean has_tooltip = FALSE;
2592
2593   g_return_val_if_fail (GTK_IS_STATUS_ICON (status_icon), FALSE);
2594
2595   priv = status_icon->priv;
2596
2597 #ifdef GDK_WINDOWING_X11
2598   has_tooltip = gtk_widget_get_has_tooltip (priv->tray_icon);
2599 #endif
2600 #ifdef GDK_WINDOWING_WIN32
2601   has_tooltip = (priv->tooltip_text != NULL);
2602 #endif
2603 #ifdef GDK_WINDOWING_QUARTZ
2604   has_tooltip = (priv->tooltip_text != NULL);
2605 #endif
2606
2607   return has_tooltip;
2608 }
2609
2610 /**
2611  * gtk_status_icon_set_tooltip_text:
2612  * @status_icon: a #GtkStatusIcon
2613  * @text: the contents of the tooltip for @status_icon
2614  *
2615  * Sets @text as the contents of the tooltip.
2616  *
2617  * This function will take care of setting #GtkStatusIcon:has-tooltip to
2618  * %TRUE and of the default handler for the #GtkStatusIcon::query-tooltip
2619  * signal.
2620  *
2621  * See also the #GtkStatusIcon:tooltip-text property and
2622  * gtk_tooltip_set_text().
2623  *
2624  * Since: 2.16
2625  */
2626 void
2627 gtk_status_icon_set_tooltip_text (GtkStatusIcon *status_icon,
2628                                   const gchar   *text)
2629 {
2630   GtkStatusIconPrivate *priv;
2631
2632   g_return_if_fail (GTK_IS_STATUS_ICON (status_icon));
2633
2634   priv = status_icon->priv;
2635
2636 #ifdef GDK_WINDOWING_X11
2637
2638   gtk_widget_set_tooltip_text (priv->tray_icon, text);
2639
2640 #endif
2641 #ifdef GDK_WINDOWING_WIN32
2642   if (text == NULL)
2643     priv->nid.uFlags &= ~NIF_TIP;
2644   else
2645     {
2646       WCHAR *wcs = g_utf8_to_utf16 (text, -1, NULL, NULL, NULL);
2647
2648       priv->nid.uFlags |= NIF_TIP;
2649       wcsncpy (priv->nid.szTip, wcs, G_N_ELEMENTS (priv->nid.szTip) - 1);
2650       priv->nid.szTip[G_N_ELEMENTS (priv->nid.szTip) - 1] = 0;
2651       g_free (wcs);
2652     }
2653   if (priv->nid.hWnd != NULL && priv->visible)
2654     if (!Shell_NotifyIconW (NIM_MODIFY, &priv->nid))
2655       g_warning (G_STRLOC ": Shell_NotifyIconW(NIM_MODIFY) failed");
2656
2657   g_free (priv->tooltip_text);
2658   priv->tooltip_text = g_strdup (text);
2659 #endif
2660 #ifdef GDK_WINDOWING_QUARTZ
2661   QUARTZ_POOL_ALLOC;
2662   [priv->status_item setToolTip:text];
2663   QUARTZ_POOL_RELEASE;
2664
2665   g_free (priv->tooltip_text);
2666   priv->tooltip_text = g_strdup (text);
2667 #endif
2668 }
2669
2670 /**
2671  * gtk_status_icon_get_tooltip_text:
2672  * @status_icon: a #GtkStatusIcon
2673  *
2674  * Gets the contents of the tooltip for @status_icon.
2675  *
2676  * Return value: the tooltip text, or %NULL. You should free the
2677  *   returned string with g_free() when done.
2678  *
2679  * Since: 2.16
2680  */
2681 gchar *
2682 gtk_status_icon_get_tooltip_text (GtkStatusIcon *status_icon)
2683 {
2684   GtkStatusIconPrivate *priv;
2685   gchar *tooltip_text = NULL;
2686
2687   g_return_val_if_fail (GTK_IS_STATUS_ICON (status_icon), NULL);
2688
2689   priv = status_icon->priv;
2690
2691 #ifdef GDK_WINDOWING_X11
2692   tooltip_text = gtk_widget_get_tooltip_text (priv->tray_icon);
2693 #endif
2694 #ifdef GDK_WINDOWING_WIN32
2695   if (priv->tooltip_text)
2696     tooltip_text = g_strdup (priv->tooltip_text);
2697 #endif
2698 #ifdef GDK_WINDOWING_QUARTZ
2699   if (priv->tooltip_text)
2700     tooltip_text = g_strdup (priv->tooltip_text);
2701 #endif
2702
2703   return tooltip_text;
2704 }
2705
2706 /**
2707  * gtk_status_icon_set_tooltip_markup:
2708  * @status_icon: a #GtkStatusIcon
2709  * @markup: (allow-none): the contents of the tooltip for @status_icon, or %NULL
2710  *
2711  * Sets @markup as the contents of the tooltip, which is marked up with
2712  *  the <link linkend="PangoMarkupFormat">Pango text markup language</link>.
2713  *
2714  * This function will take care of setting #GtkStatusIcon:has-tooltip to %TRUE
2715  * and of the default handler for the #GtkStatusIcon::query-tooltip signal.
2716  *
2717  * See also the #GtkStatusIcon:tooltip-markup property and
2718  * gtk_tooltip_set_markup().
2719  *
2720  * Since: 2.16
2721  */
2722 void
2723 gtk_status_icon_set_tooltip_markup (GtkStatusIcon *status_icon,
2724                                     const gchar   *markup)
2725 {
2726   GtkStatusIconPrivate *priv;
2727 #ifndef GDK_WINDOWING_X11
2728   gchar *text = NULL;
2729 #endif
2730
2731   g_return_if_fail (GTK_IS_STATUS_ICON (status_icon));
2732
2733   priv = status_icon->priv;
2734
2735 #ifdef GDK_WINDOWING_X11
2736   gtk_widget_set_tooltip_markup (priv->tray_icon, markup);
2737 #endif
2738 #ifdef GDK_WINDOWING_WIN32
2739   if (markup)
2740     pango_parse_markup (markup, -1, 0, NULL, &text, NULL, NULL);
2741   gtk_status_icon_set_tooltip_text (status_icon, text);
2742   g_free (text);
2743 #endif
2744 #ifdef GDK_WINDOWING_QUARTZ
2745   if (markup)
2746     pango_parse_markup (markup, -1, 0, NULL, &text, NULL, NULL);
2747   gtk_status_icon_set_tooltip_text (status_icon, text);
2748   g_free (text);
2749 #endif
2750 }
2751
2752 /**
2753  * gtk_status_icon_get_tooltip_markup:
2754  * @status_icon: a #GtkStatusIcon
2755  *
2756  * Gets the contents of the tooltip for @status_icon.
2757  *
2758  * Return value: the tooltip text, or %NULL. You should free the
2759  *   returned string with g_free() when done.
2760  *
2761  * Since: 2.16
2762  */
2763 gchar *
2764 gtk_status_icon_get_tooltip_markup (GtkStatusIcon *status_icon)
2765 {
2766   GtkStatusIconPrivate *priv;
2767   gchar *markup = NULL;
2768
2769   g_return_val_if_fail (GTK_IS_STATUS_ICON (status_icon), NULL);
2770
2771   priv = status_icon->priv;
2772
2773 #ifdef GDK_WINDOWING_X11
2774   markup = gtk_widget_get_tooltip_markup (priv->tray_icon);
2775 #endif
2776 #ifdef GDK_WINDOWING_WIN32
2777   if (priv->tooltip_text)
2778     markup = g_markup_escape_text (priv->tooltip_text, -1);
2779 #endif
2780 #ifdef GDK_WINDOWING_QUARTZ
2781   if (priv->tooltip_text)
2782     markup = g_markup_escape_text (priv->tooltip_text, -1);
2783 #endif
2784
2785   return markup;
2786 }
2787
2788 /**
2789  * gtk_status_icon_get_x11_window_id:
2790  * @status_icon: a #GtkStatusIcon
2791  *
2792  * This function is only useful on the X11/freedesktop.org platform.
2793  * It returns a window ID for the widget in the underlying
2794  * status icon implementation.  This is useful for the Galago 
2795  * notification service, which can send a window ID in the protocol 
2796  * in order for the server to position notification windows 
2797  * pointing to a status icon reliably.
2798  *
2799  * This function is not intended for other use cases which are
2800  * more likely to be met by one of the non-X11 specific methods, such
2801  * as gtk_status_icon_position_menu().
2802  *
2803  * Return value: An 32 bit unsigned integer identifier for the 
2804  * underlying X11 Window
2805  *
2806  * Since: 2.14
2807  */
2808 guint32
2809 gtk_status_icon_get_x11_window_id (GtkStatusIcon *status_icon)
2810 {
2811 #ifdef GDK_WINDOWING_X11
2812   gtk_widget_realize (GTK_WIDGET (status_icon->priv->tray_icon));
2813   return GDK_WINDOW_XID (gtk_widget_get_window (GTK_WIDGET (status_icon->priv->tray_icon)));
2814 #else
2815   return 0;
2816 #endif
2817 }
2818
2819 /**
2820  * gtk_status_icon_set_title:
2821  * @status_icon: a #GtkStatusIcon
2822  * @title: the title 
2823  *
2824  * Sets the title of this tray icon.
2825  * This should be a short, human-readable, localized string 
2826  * describing the tray icon. It may be used by tools like screen
2827  * readers to render the tray icon.
2828  *
2829  * Since: 2.18
2830  */
2831 void
2832 gtk_status_icon_set_title (GtkStatusIcon *status_icon,
2833                            const gchar   *title)
2834 {
2835   GtkStatusIconPrivate *priv;
2836
2837   g_return_if_fail (GTK_IS_STATUS_ICON (status_icon));
2838
2839   priv = status_icon->priv;
2840
2841 #ifdef GDK_WINDOWING_X11
2842   gtk_window_set_title (GTK_WINDOW (priv->tray_icon), title);
2843 #endif
2844 #ifdef GDK_WINDOWING_QUARTZ
2845   g_free (priv->title);
2846   priv->title = g_strdup (title);
2847 #endif
2848 #ifdef GDK_WINDOWING_WIN32
2849   g_free (priv->title);
2850   priv->title = g_strdup (title);
2851 #endif
2852
2853   g_object_notify (G_OBJECT (status_icon), "title");
2854 }
2855
2856 /**
2857  * gtk_status_icon_get_title:
2858  * @status_icon: a #GtkStatusIcon
2859  *
2860  * Gets the title of this tray icon. See gtk_status_icon_set_title().
2861  *
2862  * Returns: the title of the status icon
2863  *
2864  * Since: 2.18
2865  */
2866 G_CONST_RETURN gchar *
2867 gtk_status_icon_get_title (GtkStatusIcon *status_icon)
2868 {
2869   GtkStatusIconPrivate *priv;
2870
2871   g_return_val_if_fail (GTK_IS_STATUS_ICON (status_icon), NULL);
2872
2873   priv = status_icon->priv;
2874
2875 #ifdef GDK_WINDOWING_X11
2876   return gtk_window_get_title (GTK_WINDOW (priv->tray_icon));
2877 #endif
2878 #ifdef GDK_WINDOWING_QUARTZ
2879   return priv->title;
2880 #endif
2881 #ifdef GDK_WINDOWING_WIN32
2882   return priv->title;
2883 #endif
2884 }
2885
2886
2887 /**
2888  * gtk_status_icon_set_name:
2889  * @status_icon: a #GtkStatusIcon
2890  * @name: the name
2891  *
2892  * Sets the name of this tray icon.
2893  * This should be a string identifying this icon. It is may be
2894  * used for sorting the icons in the tray and will not be shown to
2895  * the user.
2896  *
2897  * Since: 2.20
2898  */
2899 void
2900 gtk_status_icon_set_name (GtkStatusIcon *status_icon,
2901                           const gchar   *name)
2902 {
2903   GtkStatusIconPrivate *priv;
2904
2905   g_return_if_fail (GTK_IS_STATUS_ICON (status_icon));
2906
2907   priv = status_icon->priv;
2908
2909 #ifdef GDK_WINDOWING_X11
2910   gtk_window_set_wmclass (GTK_WINDOW (priv->tray_icon), name, name);
2911 #endif
2912
2913   g_object_notify (G_OBJECT (status_icon), "name");
2914 }