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