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