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