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