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