]> Pileus Git - ~andy/gtk/blob - gtk/gtkstatusicon.c
4e8a008dd3b140c66dd018d008adf7bf697a9206
[~andy/gtk] / gtk / gtkstatusicon.c
1 /* gtkstatusicon.c:
2  *
3  * Copyright (C) 2003 Sun Microsystems, Inc.
4  * Copyright (C) 2005 Hans Breuer <hans@breuer.org>
5  * Copyright (C) 2005 Novell, Inc.
6  * Copyright (C) 2006 Imendio AB
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Library General Public
10  * License as published by the Free Software Foundation; either
11  * version 2 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Library General Public License for more details.
17  *
18  * You should have received a copy of the GNU Library General Public
19  * License along with this library; if not, write to the
20  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21  * Boston, MA 02111-1307, USA.
22  *
23  * Authors:
24  *      Mark McLoughlin <mark@skynet.ie>
25  *      Hans Breuer <hans@breuer.org>
26  *      Tor Lillqvist <tml@novell.com>
27  *      Mikael Hallendal <micke@imendio.com>
28  */
29
30 #include <config.h>
31 #include <string.h>
32
33 #include "gtkstatusicon.h"
34
35 #include "gtkintl.h"
36 #include "gtkiconfactory.h"
37 #include "gtkmain.h"
38 #include "gtkmarshalers.h"
39 #include "gtktrayicon.h"
40
41 #include "gtkprivate.h"
42 #include "gtkwidget.h"
43
44 #ifdef GDK_WINDOWING_X11
45 #include "gdk/x11/gdkx.h"
46 #endif
47
48 #ifdef GDK_WINDOWING_WIN32
49 #include "gtkicontheme.h"
50 #include "gtklabel.h"
51
52 #include "win32/gdkwin32.h"
53 #define WM_GTK_TRAY_NOTIFICATION (WM_USER+1)
54 #endif
55
56 #ifdef GDK_WINDOWING_QUARTZ
57 #include "gtkicontheme.h"
58 #include "gtklabel.h"
59 #endif  
60
61 #include "gdkkeysyms.h"
62
63 #include "gtkalias.h"
64
65 #define BLINK_TIMEOUT 500
66
67 enum
68 {
69   PROP_0,
70   PROP_PIXBUF,
71   PROP_FILE,
72   PROP_STOCK,
73   PROP_ICON_NAME,
74   PROP_STORAGE_TYPE,
75   PROP_SIZE,
76   PROP_SCREEN,
77   PROP_VISIBLE,
78   PROP_ORIENTATION,
79   PROP_EMBEDDED,
80   PROP_BLINKING
81 };
82
83 enum 
84 {
85   ACTIVATE_SIGNAL,
86   POPUP_MENU_SIGNAL,
87   SIZE_CHANGED_SIGNAL,
88   LAST_SIGNAL
89 };
90
91 static guint status_icon_signals [LAST_SIGNAL] = { 0 };
92
93 #ifdef GDK_WINDOWING_QUARTZ
94 #include "gtkstatusicon-quartz.c"
95 #endif
96
97 struct _GtkStatusIconPrivate
98 {
99 #ifdef GDK_WINDOWING_X11
100   GtkWidget    *tray_icon;
101   GtkWidget    *image;
102 #endif
103
104 #ifdef GDK_WINDOWING_WIN32
105   GtkWidget     *dummy_widget;
106   NOTIFYICONDATAW nid;
107   gint          last_click_x, last_click_y;
108   GtkOrientation orientation;
109 #endif
110         
111 #ifdef GDK_WINDOWING_QUARTZ
112   GtkWidget     *dummy_widget;
113   GtkQuartzStatusIcon *status_item;
114 #endif
115
116   gint          size;
117
118   gint          image_width;
119   gint          image_height;
120
121   GtkImageType  storage_type;
122
123   union
124     {
125       GdkPixbuf *pixbuf;
126       gchar     *stock_id;
127       gchar     *icon_name;
128     } image_data;
129
130   GdkPixbuf    *blank_icon;
131   guint         blinking_timeout;
132
133   guint         blinking : 1;
134   guint         blink_off : 1;
135   guint         visible : 1;
136 };
137
138 static GObject* gtk_status_icon_constructor      (GType                  type,
139                                                   guint                  n_construct_properties,
140                                                   GObjectConstructParam *construct_params);
141 static void     gtk_status_icon_finalize         (GObject        *object);
142 static void     gtk_status_icon_set_property     (GObject        *object,
143                                                   guint           prop_id,
144                                                   const GValue   *value,
145                                                   GParamSpec     *pspec);
146 static void     gtk_status_icon_get_property     (GObject        *object,
147                                                   guint           prop_id,
148                                                   GValue         *value,
149                                                   GParamSpec     *pspec);
150
151 #ifdef GDK_WINDOWING_X11
152 static void     gtk_status_icon_size_allocate    (GtkStatusIcon  *status_icon,
153                                                   GtkAllocation  *allocation);
154 static void     gtk_status_icon_screen_changed   (GtkStatusIcon  *status_icon,
155                                                   GdkScreen      *old_screen);
156 static void     gtk_status_icon_embedded_changed (GtkStatusIcon *status_icon);
157 static void     gtk_status_icon_orientation_changed (GtkStatusIcon *status_icon);
158
159 static gboolean gtk_status_icon_key_press        (GtkStatusIcon  *status_icon,
160                                                   GdkEventKey    *event);
161 static void     gtk_status_icon_popup_menu       (GtkStatusIcon  *status_icon);
162 #endif
163 static gboolean gtk_status_icon_button_press     (GtkStatusIcon  *status_icon,
164                                                   GdkEventButton *event);
165 static void     gtk_status_icon_disable_blinking (GtkStatusIcon  *status_icon);
166 static void     gtk_status_icon_reset_image_data (GtkStatusIcon  *status_icon);
167 static void     gtk_status_icon_update_image    (GtkStatusIcon *status_icon);
168
169 G_DEFINE_TYPE (GtkStatusIcon, gtk_status_icon, G_TYPE_OBJECT)
170
171 static void
172 gtk_status_icon_class_init (GtkStatusIconClass *class)
173 {
174   GObjectClass *gobject_class = (GObjectClass *) class;
175
176   gobject_class->constructor  = gtk_status_icon_constructor;
177   gobject_class->finalize     = gtk_status_icon_finalize;
178   gobject_class->set_property = gtk_status_icon_set_property;
179   gobject_class->get_property = gtk_status_icon_get_property;
180
181   g_object_class_install_property (gobject_class,
182                                    PROP_PIXBUF,
183                                    g_param_spec_object ("pixbuf",
184                                                         P_("Pixbuf"),
185                                                         P_("A GdkPixbuf to display"),
186                                                         GDK_TYPE_PIXBUF,
187                                                         GTK_PARAM_READWRITE));
188
189   g_object_class_install_property (gobject_class,
190                                    PROP_FILE,
191                                    g_param_spec_string ("file",
192                                                         P_("Filename"),
193                                                         P_("Filename to load and display"),
194                                                         NULL,
195                                                         GTK_PARAM_WRITABLE));
196
197   g_object_class_install_property (gobject_class,
198                                    PROP_STOCK,
199                                    g_param_spec_string ("stock",
200                                                         P_("Stock ID"),
201                                                         P_("Stock ID for a stock image to display"),
202                                                         NULL,
203                                                         GTK_PARAM_READWRITE));
204   
205   g_object_class_install_property (gobject_class,
206                                    PROP_ICON_NAME,
207                                    g_param_spec_string ("icon-name",
208                                                         P_("Icon Name"),
209                                                         P_("The name of the icon from the icon theme"),
210                                                         NULL,
211                                                         GTK_PARAM_READWRITE));
212   
213   g_object_class_install_property (gobject_class,
214                                    PROP_STORAGE_TYPE,
215                                    g_param_spec_enum ("storage-type",
216                                                       P_("Storage type"),
217                                                       P_("The representation being used for image data"),
218                                                       GTK_TYPE_IMAGE_TYPE,
219                                                       GTK_IMAGE_EMPTY,
220                                                       GTK_PARAM_READABLE));
221
222   g_object_class_install_property (gobject_class,
223                                    PROP_SIZE,
224                                    g_param_spec_int ("size",
225                                                      P_("Size"),
226                                                      P_("The size of the icon"),
227                                                      0,
228                                                      G_MAXINT,
229                                                      0,
230                                                      GTK_PARAM_READABLE));
231
232   g_object_class_install_property (gobject_class,
233                                    PROP_SCREEN,
234                                    g_param_spec_object ("screen",
235                                                         P_("Screen"),
236                                                         P_("The screen where this status icon will be displayed"),
237                                                         GDK_TYPE_SCREEN,
238                                                         GTK_PARAM_READWRITE));
239
240   g_object_class_install_property (gobject_class,
241                                    PROP_BLINKING,
242                                    g_param_spec_boolean ("blinking",
243                                                          P_("Blinking"),
244                                                          P_("Whether or not the status icon is blinking"),
245                                                          FALSE,
246                                                          GTK_PARAM_READWRITE));
247
248   g_object_class_install_property (gobject_class,
249                                    PROP_VISIBLE,
250                                    g_param_spec_boolean ("visible",
251                                                          P_("Visible"),
252                                                          P_("Whether or not the status icon is visible"),
253                                                          TRUE,
254                                                          GTK_PARAM_READWRITE));
255
256
257   /**
258    * GtkStatusIcon:embedded: 
259    *
260    * %TRUE if the statusicon is embedded in a notification area.
261    *
262    * Since: 2.12
263    */
264   g_object_class_install_property (gobject_class,
265                                    PROP_EMBEDDED,
266                                    g_param_spec_boolean ("embedded",
267                                                          P_("Embedded"),
268                                                          P_("Whether or not the status icon is embedded"),
269                                                          FALSE,
270                                                          GTK_PARAM_READABLE));
271
272   /**
273    * GtkStatusIcon:orientation:
274    *
275    * The orientation of the tray in which the statusicon 
276    * is embedded. 
277    *
278    * Since: 2.12
279    */
280   g_object_class_install_property (gobject_class,
281                                    PROP_ORIENTATION,
282                                    g_param_spec_enum ("orientation",
283                                                       P_("Orientation"),
284                                                       P_("The orientation of the tray"),
285                                                       GTK_TYPE_ORIENTATION,
286                                                       GTK_ORIENTATION_HORIZONTAL,
287                                                       GTK_PARAM_READABLE));
288
289
290   /**
291    * GtkStatusIcon::activate:
292    * @status_icon: the object which received the signal
293    *
294    * Gets emitted when the user activates the status icon. 
295    * If and how status icons can activated is platform-dependent.
296    *
297    * Since: 2.10
298    */
299   status_icon_signals [ACTIVATE_SIGNAL] =
300     g_signal_new (I_("activate"),
301                   G_TYPE_FROM_CLASS (gobject_class),
302                   G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
303                   G_STRUCT_OFFSET (GtkStatusIconClass, activate),
304                   NULL,
305                   NULL,
306                   g_cclosure_marshal_VOID__VOID,
307                   G_TYPE_NONE,
308                   0);
309
310   /**
311    * GtkStatusIcon::popup-menu:
312    * @status_icon: the object which received the signal
313    * @button: the button that was pressed, or 0 if the 
314    *   signal is not emitted in response to a button press event
315    * @activate_time: the timestamp of the event that
316    *   triggered the signal emission
317    *
318    * Gets emitted when the user brings up the context menu
319    * of the status icon. Whether status icons can have context 
320    * menus and how these are activated is platform-dependent.
321    *
322    * The @button and @activate_timeout parameters should be 
323    * passed as the last to arguments to gtk_menu_popup().
324    *
325    * Since: 2.10
326    */
327   status_icon_signals [POPUP_MENU_SIGNAL] =
328     g_signal_new (I_("popup_menu"),
329                   G_TYPE_FROM_CLASS (gobject_class),
330                   G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
331                   G_STRUCT_OFFSET (GtkStatusIconClass, popup_menu),
332                   NULL,
333                   NULL,
334                   _gtk_marshal_VOID__UINT_UINT,
335                   G_TYPE_NONE,
336                   2,
337                   G_TYPE_UINT,
338                   G_TYPE_UINT);
339
340   /**
341    * GtkStatusIcon::size-changed:
342    * @status_icon: the object which received the signal
343    * @size: the new size
344    *
345    * Gets emitted when the size available for the image
346    * changes, e.g. because the notification area got resized.
347    *
348    * Return value: %TRUE if the icon was updated for the new
349    * size. Otherwise, GTK+ will scale the icon as necessary.
350    *
351    * Since: 2.10
352    */
353   status_icon_signals [SIZE_CHANGED_SIGNAL] =
354     g_signal_new (I_("size_changed"),
355                   G_TYPE_FROM_CLASS (gobject_class),
356                   G_SIGNAL_RUN_LAST,
357                   G_STRUCT_OFFSET (GtkStatusIconClass, size_changed),
358                   g_signal_accumulator_true_handled,
359                   NULL,
360                   _gtk_marshal_BOOLEAN__INT,
361                   G_TYPE_BOOLEAN,
362                   1,
363                   G_TYPE_INT);
364
365   g_type_class_add_private (class, sizeof (GtkStatusIconPrivate));
366 }
367
368 #ifdef GDK_WINDOWING_WIN32
369
370 static void
371 build_button_event (GtkStatusIconPrivate *priv,
372                     GdkEventButton       *e,
373                     guint                 button)
374 {
375   POINT pos;
376   GdkRectangle monitor0;
377
378   /* We know that gdk/win32 puts the primary monitor at index 0 */
379   gdk_screen_get_monitor_geometry (gdk_screen_get_default (), 0, &monitor0);
380   e->window = g_object_ref (gdk_get_default_root_window ());
381   e->send_event = TRUE;
382   e->time = GetTickCount ();
383   GetCursorPos (&pos);
384   priv->last_click_x = e->x = pos.x + monitor0.x;
385   priv->last_click_y = e->y = pos.y + monitor0.y;
386   e->axes = NULL;
387   e->state = 0;
388   e->button = button;
389   e->device = gdk_display_get_default ()->core_pointer;
390   e->x_root = e->x;
391   e->y_root = e->y;
392 }
393
394 typedef struct
395 {
396   GtkStatusIcon *status_icon;
397   GdkEventButton *event;
398 } ButtonCallbackData;
399
400 static gboolean
401 button_callback (gpointer data)
402 {
403   ButtonCallbackData *bc = (ButtonCallbackData *) data;
404
405   gtk_status_icon_button_press (bc->status_icon, bc->event);
406
407   gdk_event_free ((GdkEvent *) bc->event);
408   g_free (data);
409
410   return FALSE;
411 }
412
413 static UINT taskbar_created_msg = 0;
414 static GSList *status_icons = NULL;
415
416 static LRESULT CALLBACK
417 wndproc (HWND   hwnd,
418          UINT   message,
419          WPARAM wparam,
420          LPARAM lparam)
421 {
422   if (message == taskbar_created_msg)
423     {
424       GSList *rover;
425
426       for (rover = status_icons; rover != NULL; rover = rover->next)
427         {
428           GtkStatusIcon *status_icon = GTK_STATUS_ICON (rover->data);
429           GtkStatusIconPrivate *priv = status_icon->priv;
430
431           priv->nid.hWnd = hwnd;
432           priv->nid.uID = GPOINTER_TO_UINT (status_icon);
433           priv->nid.uCallbackMessage = WM_GTK_TRAY_NOTIFICATION;
434           priv->nid.uFlags = NIF_MESSAGE;
435
436           if (!Shell_NotifyIconW (NIM_ADD, &priv->nid))
437             {
438               g_warning ("%s:%d:Shell_NotifyIcon(NIM_ADD) failed", __FILE__, __LINE__-2);
439               priv->nid.hWnd = NULL;
440               continue;
441             }
442
443           gtk_status_icon_update_image (status_icon);
444         }
445       return 0;
446     }
447
448   if (message == WM_GTK_TRAY_NOTIFICATION)
449     {
450       ButtonCallbackData *bc;
451       
452       switch (lparam)
453         {
454         case WM_LBUTTONDOWN:
455         case WM_RBUTTONDOWN:
456           bc = g_new (ButtonCallbackData, 1);
457           bc->event = (GdkEventButton *) gdk_event_new (GDK_BUTTON_PRESS);
458           bc->status_icon = GTK_STATUS_ICON (wparam);
459           build_button_event (bc->status_icon->priv, bc->event, (lparam == WM_LBUTTONDOWN) ? 1 : 3);
460           g_idle_add (button_callback, bc);
461           break;
462         default :
463           break;
464         }
465         return 0;
466     }
467   else
468     {
469       return DefWindowProc (hwnd, message, wparam, lparam);
470     }
471 }
472
473 static HWND
474 create_tray_observer (void)
475 {
476   WNDCLASS    wclass;
477   static HWND hwnd = NULL;
478   ATOM        klass;
479   HINSTANCE   hmodule = GetModuleHandle (NULL);
480
481   if (hwnd)
482     return hwnd;
483
484   taskbar_created_msg = RegisterWindowMessage("TaskbarCreated");
485
486   memset (&wclass, 0, sizeof(WNDCLASS));
487   wclass.lpszClassName = "gtkstatusicon-observer";
488   wclass.lpfnWndProc   = wndproc;
489   wclass.hInstance     = hmodule;
490
491   klass = RegisterClass (&wclass);
492   if (!klass)
493     return NULL;
494
495   hwnd = CreateWindow (MAKEINTRESOURCE (klass),
496                        NULL, WS_POPUP,
497                        0, 0, 1, 1, NULL, NULL,
498                        hmodule, NULL);
499   if (!hwnd)
500     {
501       UnregisterClass (MAKEINTRESOURCE(klass), hmodule);
502       return NULL;
503     }
504
505   return hwnd;
506 }
507
508 #endif
509
510 static void
511 gtk_status_icon_init (GtkStatusIcon *status_icon)
512 {
513   GtkStatusIconPrivate *priv;
514
515   priv = G_TYPE_INSTANCE_GET_PRIVATE (status_icon, GTK_TYPE_STATUS_ICON,
516                                       GtkStatusIconPrivate);
517   status_icon->priv = priv;
518   
519   priv->storage_type = GTK_IMAGE_EMPTY;
520   priv->visible      = TRUE;
521
522 #ifdef GDK_WINDOWING_X11
523   priv->size         = 0;
524   priv->image_width  = 0;
525   priv->image_height = 0;
526
527   priv->tray_icon = GTK_WIDGET (_gtk_tray_icon_new (NULL));
528
529   gtk_widget_add_events (GTK_WIDGET (priv->tray_icon),
530                          GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK);
531
532   g_signal_connect_swapped (priv->tray_icon, "key-press-event",
533                             G_CALLBACK (gtk_status_icon_key_press), status_icon);
534   g_signal_connect_swapped (priv->tray_icon, "popup-menu",
535                             G_CALLBACK (gtk_status_icon_popup_menu), status_icon);
536   g_signal_connect_swapped (priv->tray_icon, "notify::embedded",
537                             G_CALLBACK (gtk_status_icon_embedded_changed), status_icon);
538   g_signal_connect_swapped (priv->tray_icon, "notify::orientation",
539                             G_CALLBACK (gtk_status_icon_orientation_changed), status_icon);
540   g_signal_connect_swapped (priv->tray_icon, "button-press-event",
541                             G_CALLBACK (gtk_status_icon_button_press), status_icon);
542   g_signal_connect_swapped (priv->tray_icon, "screen-changed",
543                             G_CALLBACK (gtk_status_icon_screen_changed), status_icon);
544   priv->image = gtk_image_new ();
545   GTK_WIDGET_SET_FLAGS (priv->image, GTK_CAN_FOCUS);
546   gtk_container_add (GTK_CONTAINER (priv->tray_icon), priv->image);
547   gtk_widget_show (priv->image);
548
549   g_signal_connect_swapped (priv->image, "size-allocate",
550                             G_CALLBACK (gtk_status_icon_size_allocate), status_icon);
551
552 #endif
553
554 #ifdef GDK_WINDOWING_WIN32
555
556   /* Get position and orientation of Windows taskbar. */
557   {
558     APPBARDATA abd;
559     
560     abd.cbSize = sizeof (abd);
561     SHAppBarMessage (ABM_GETTASKBARPOS, &abd);
562     if (abd.rc.bottom - abd.rc.top > abd.rc.right - abd.rc.left)
563       priv->orientation = GTK_ORIENTATION_VERTICAL;
564     else
565       priv->orientation = GTK_ORIENTATION_HORIZONTAL;
566   }
567
568   priv->last_click_x = priv->last_click_y = 0;
569
570   /* Are the system tray icons always 16 pixels square? */
571   priv->size         = 16;
572   priv->image_width  = 16;
573   priv->image_height = 16;
574
575   priv->dummy_widget = gtk_label_new ("");
576
577   memset (&priv->nid, 0, sizeof (priv->nid));
578
579   priv->nid.hWnd = create_tray_observer ();
580   priv->nid.uID = GPOINTER_TO_UINT (status_icon);
581   priv->nid.uCallbackMessage = WM_GTK_TRAY_NOTIFICATION;
582   priv->nid.uFlags = NIF_MESSAGE;
583
584   if (!Shell_NotifyIconW (NIM_ADD, &priv->nid))
585     {
586       g_warning ("%s:%d:Shell_NotifyIcon(NIM_ADD) failed", __FILE__, __LINE__-2);
587       priv->nid.hWnd = NULL;
588     }
589
590   status_icons = g_slist_append (status_icons, status_icon);
591
592 #endif
593         
594 #ifdef GDK_WINDOWING_QUARTZ
595   priv->dummy_widget = gtk_label_new ("");
596
597   QUARTZ_POOL_ALLOC;
598
599   priv->status_item = [[GtkQuartzStatusIcon alloc] initWithStatusIcon:status_icon];
600
601   priv->image_width = priv->image_height = [priv->status_item getHeight];
602   priv->size = priv->image_height;
603
604   QUARTZ_POOL_RELEASE;
605
606 #endif 
607 }
608
609 static GObject*
610 gtk_status_icon_constructor (GType                  type,
611                              guint                  n_construct_properties,
612                              GObjectConstructParam *construct_params)
613 {
614   GObject *object;
615 #ifdef GDK_WINDOWING_X11
616   GtkStatusIcon *status_icon;
617   GtkStatusIconPrivate *priv;
618 #endif
619
620   object = G_OBJECT_CLASS (gtk_status_icon_parent_class)->constructor (type,
621                                                                        n_construct_properties,
622                                                                        construct_params);
623
624 #ifdef GDK_WINDOWING_X11
625   status_icon = GTK_STATUS_ICON (object);
626   priv = status_icon->priv;
627   
628   if (priv->visible)
629     gtk_widget_show (priv->tray_icon);
630 #endif
631
632   return object;
633 }
634
635 static void
636 gtk_status_icon_finalize (GObject *object)
637 {
638   GtkStatusIcon *status_icon = GTK_STATUS_ICON (object);
639   GtkStatusIconPrivate *priv = status_icon->priv;
640
641   gtk_status_icon_disable_blinking (status_icon);
642   
643   gtk_status_icon_reset_image_data (status_icon);
644
645   if (priv->blank_icon)
646     g_object_unref (priv->blank_icon);
647   priv->blank_icon = NULL;
648
649 #ifdef GDK_WINDOWING_X11
650   gtk_widget_destroy (priv->tray_icon);
651 #endif
652
653 #ifdef GDK_WINDOWING_WIN32
654   if (priv->nid.hWnd != NULL && priv->visible)
655     Shell_NotifyIconW (NIM_DELETE, &priv->nid);
656   if (priv->nid.hIcon)
657     DestroyIcon (priv->nid.hIcon);
658
659   gtk_widget_destroy (priv->dummy_widget);
660
661   status_icons = g_slist_remove (status_icons, status_icon);
662 #endif
663         
664 #ifdef GDK_WINDOWING_QUARTZ
665   QUARTZ_POOL_ALLOC;
666   [priv->status_item release];
667   QUARTZ_POOL_RELEASE;
668 #endif
669
670   G_OBJECT_CLASS (gtk_status_icon_parent_class)->finalize (object);
671 }
672
673 static void
674 gtk_status_icon_set_property (GObject      *object,
675                               guint         prop_id,
676                               const GValue *value,
677                               GParamSpec   *pspec)
678 {
679   GtkStatusIcon *status_icon = GTK_STATUS_ICON (object);
680
681   switch (prop_id)
682     {
683     case PROP_PIXBUF:
684       gtk_status_icon_set_from_pixbuf (status_icon, g_value_get_object (value));
685       break;
686     case PROP_FILE:
687       gtk_status_icon_set_from_file (status_icon, g_value_get_string (value));
688       break;
689     case PROP_STOCK:
690       gtk_status_icon_set_from_stock (status_icon, g_value_get_string (value));
691       break;
692     case PROP_ICON_NAME:
693       gtk_status_icon_set_from_icon_name (status_icon, g_value_get_string (value));
694       break;
695     case PROP_SCREEN:
696       gtk_status_icon_set_screen (status_icon, g_value_get_object (value));
697       break;
698     case PROP_BLINKING:
699       gtk_status_icon_set_blinking (status_icon, g_value_get_boolean (value));
700       break;
701     case PROP_VISIBLE:
702       gtk_status_icon_set_visible (status_icon, g_value_get_boolean (value));
703       break;
704     default:
705       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
706       break;
707     }
708 }
709
710 static void
711 gtk_status_icon_get_property (GObject    *object,
712                               guint       prop_id,
713                               GValue     *value,
714                               GParamSpec *pspec)
715 {
716   GtkStatusIcon *status_icon = GTK_STATUS_ICON (object);
717   GtkStatusIconPrivate *priv = status_icon->priv;
718
719   /* The "getter" functions whine if you try to get the wrong
720    * storage type. This function is instead robust against that,
721    * so that GUI builders don't have to jump through hoops
722    * to avoid g_warning
723    */
724
725   switch (prop_id)
726     {
727     case PROP_PIXBUF:
728       if (priv->storage_type != GTK_IMAGE_PIXBUF)
729         g_value_set_object (value, NULL);
730       else
731         g_value_set_object (value, gtk_status_icon_get_pixbuf (status_icon));
732       break;
733     case PROP_STOCK:
734       if (priv->storage_type != GTK_IMAGE_STOCK)
735         g_value_set_string (value, NULL);
736       else
737         g_value_set_string (value, gtk_status_icon_get_stock (status_icon));
738       break;
739     case PROP_ICON_NAME:
740       if (priv->storage_type != GTK_IMAGE_ICON_NAME)
741         g_value_set_string (value, NULL);
742       else
743         g_value_set_string (value, gtk_status_icon_get_icon_name (status_icon));
744       break;
745     case PROP_STORAGE_TYPE:
746       g_value_set_enum (value, gtk_status_icon_get_storage_type (status_icon));
747       break;
748     case PROP_SIZE:
749       g_value_set_int (value, gtk_status_icon_get_size (status_icon));
750       break;
751     case PROP_SCREEN:
752       g_value_set_object (value, gtk_status_icon_get_screen (status_icon));
753       break;
754     case PROP_BLINKING:
755       g_value_set_boolean (value, gtk_status_icon_get_blinking (status_icon));
756       break;
757     case PROP_VISIBLE:
758       g_value_set_boolean (value, gtk_status_icon_get_visible (status_icon));
759       break;
760     case PROP_EMBEDDED:
761       g_value_set_boolean (value, gtk_status_icon_is_embedded (status_icon));
762       break;
763     case PROP_ORIENTATION:
764 #ifdef GDK_WINDOWING_X11
765       g_value_set_enum (value, _gtk_tray_icon_get_orientation (GTK_TRAY_ICON (status_icon->priv->tray_icon)));
766 #endif
767 #ifdef GDK_WINDOWING_WIN32
768       g_value_set_enum (value, status_icon->priv->orientation);
769 #endif
770       break;
771     default:
772       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
773       break;
774     }
775 }
776
777 /**
778  * gtk_status_icon_new:
779  * 
780  * Creates an empty status icon object.
781  * 
782  * Return value: a new #GtkStatusIcon
783  *
784  * Since: 2.10
785  **/
786 GtkStatusIcon *
787 gtk_status_icon_new (void)
788 {
789   return g_object_new (GTK_TYPE_STATUS_ICON, NULL);
790 }
791
792 /**
793  * gtk_status_icon_new_from_pixbuf:
794  * @pixbuf: a #GdkPixbuf
795  * 
796  * Creates a status icon displaying @pixbuf. 
797  *
798  * The image will be scaled down to fit in the available 
799  * space in the notification area, if necessary.
800  * 
801  * Return value: a new #GtkStatusIcon
802  *
803  * Since: 2.10
804  **/
805 GtkStatusIcon *
806 gtk_status_icon_new_from_pixbuf (GdkPixbuf *pixbuf)
807 {
808   return g_object_new (GTK_TYPE_STATUS_ICON,
809                        "pixbuf", pixbuf,
810                        NULL);
811 }
812
813 /**
814  * gtk_status_icon_new_from_file:
815  * @filename: a filename
816  * 
817  * Creates a status icon displaying the file @filename. 
818  *
819  * The image will be scaled down to fit in the available 
820  * space in the notification area, if necessary.
821  * 
822  * Return value: a new #GtkStatusIcon
823  *
824  * Since: 2.10
825  **/
826 GtkStatusIcon *
827 gtk_status_icon_new_from_file (const gchar *filename)
828 {
829   return g_object_new (GTK_TYPE_STATUS_ICON,
830                        "file", filename,
831                        NULL);
832 }
833
834 /**
835  * gtk_status_icon_new_from_stock:
836  * @stock_id: a stock icon id
837  * 
838  * Creates a status icon displaying a stock icon. Sample stock icon
839  * names are #GTK_STOCK_OPEN, #GTK_STOCK_QUIT. You can register your 
840  * own stock icon names, see gtk_icon_factory_add_default() and 
841  * gtk_icon_factory_add(). 
842  *
843  * Return value: a new #GtkStatusIcon
844  *
845  * Since: 2.10
846  **/
847 GtkStatusIcon *
848 gtk_status_icon_new_from_stock (const gchar *stock_id)
849 {
850   return g_object_new (GTK_TYPE_STATUS_ICON,
851                        "stock", stock_id,
852                        NULL);
853 }
854
855 /**
856  * gtk_status_icon_new_from_icon_name:
857  * @icon_name: an icon name
858  * 
859  * Creates a status icon displaying an icon from the current icon theme.
860  * If the current icon theme is changed, the icon will be updated 
861  * appropriately.
862  * 
863  * Return value: a new #GtkStatusIcon
864  *
865  * Since: 2.10
866  **/
867 GtkStatusIcon *
868 gtk_status_icon_new_from_icon_name (const gchar *icon_name)
869 {
870   return g_object_new (GTK_TYPE_STATUS_ICON,
871                        "icon-name", icon_name,
872                        NULL);
873 }
874
875 static void
876 emit_activate_signal (GtkStatusIcon *status_icon)
877 {
878   g_signal_emit (status_icon,
879                  status_icon_signals [ACTIVATE_SIGNAL], 0);
880 }
881
882 static void
883 emit_popup_menu_signal (GtkStatusIcon *status_icon,
884                         guint          button,
885                         guint32        activate_time)
886 {
887   g_signal_emit (status_icon,
888                  status_icon_signals [POPUP_MENU_SIGNAL], 0,
889                  button,
890                  activate_time);
891 }
892
893 #ifdef GDK_WINDOWING_X11
894
895 static gboolean
896 emit_size_changed_signal (GtkStatusIcon *status_icon,
897                           gint           size)
898 {
899   gboolean handled = FALSE;
900   
901   g_signal_emit (status_icon,
902                  status_icon_signals [SIZE_CHANGED_SIGNAL], 0,
903                  size,
904                  &handled);
905
906   return handled;
907 }
908
909 #endif
910
911 static GdkPixbuf *
912 gtk_status_icon_blank_icon (GtkStatusIcon *status_icon)
913 {
914   GtkStatusIconPrivate *priv = status_icon->priv;
915
916   if (priv->blank_icon)
917     {
918       gint width, height;
919
920       width  = gdk_pixbuf_get_width (priv->blank_icon);
921       height = gdk_pixbuf_get_height (priv->blank_icon);
922
923
924       if (width == priv->image_width && height == priv->image_height)
925         return priv->blank_icon;
926       else
927         {
928           g_object_unref (priv->blank_icon);
929           priv->blank_icon = NULL;
930         }
931     }
932
933   priv->blank_icon = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8,
934                                      priv->image_width, 
935                                      priv->image_height);
936   if (priv->blank_icon)
937     gdk_pixbuf_fill (priv->blank_icon, 0);
938
939   return priv->blank_icon;
940 }
941
942 #ifdef GDK_WINDOWING_X11
943
944 static GtkIconSize
945 find_icon_size (GtkWidget *widget, 
946                 gint       pixel_size)
947 {
948   GdkScreen *screen;
949   GtkSettings *settings;
950   GtkIconSize s, size;
951   gint w, h, d, dist;
952
953   screen = gtk_widget_get_screen (widget);
954
955   if (!screen)
956     return GTK_ICON_SIZE_MENU;
957
958   settings = gtk_settings_get_for_screen (screen);
959   
960   dist = G_MAXINT;
961   size = GTK_ICON_SIZE_MENU;
962
963   for (s = GTK_ICON_SIZE_MENU; s < GTK_ICON_SIZE_DIALOG; s++)
964     {
965       if (gtk_icon_size_lookup_for_settings (settings, s, &w, &h) &&
966           w <= pixel_size && h <= pixel_size)
967         {
968           d = MAX (pixel_size - w, pixel_size - h);
969           if (d < dist)
970             {
971               dist = d;
972               size = s;
973             }
974         }
975     }
976   
977   return size;
978 }
979
980 #endif
981
982 static void
983 gtk_status_icon_update_image (GtkStatusIcon *status_icon)
984 {
985   GtkStatusIconPrivate *priv = status_icon->priv;
986 #ifdef GDK_WINDOWING_WIN32
987   HICON prev_hicon;
988 #endif
989
990   if (priv->blink_off)
991     {
992 #ifdef GDK_WINDOWING_X11
993       gtk_image_set_from_pixbuf (GTK_IMAGE (priv->image),
994                                  gtk_status_icon_blank_icon (status_icon));
995 #endif
996 #ifdef GDK_WINDOWING_WIN32
997       prev_hicon = priv->nid.hIcon;
998       priv->nid.hIcon = gdk_win32_pixbuf_to_hicon_libgtk_only (gtk_status_icon_blank_icon (status_icon));
999       priv->nid.uFlags |= NIF_ICON;
1000       if (priv->nid.hWnd != NULL && priv->visible)
1001         if (!Shell_NotifyIconW (NIM_MODIFY, &priv->nid))
1002           g_warning ("%s:%d:Shell_NotifyIcon(NIM_MODIFY) failed", __FILE__, __LINE__-1);
1003       if (prev_hicon)
1004         DestroyIcon (prev_hicon);
1005 #endif
1006 #ifdef GDK_WINDOWING_QUARTZ
1007       QUARTZ_POOL_ALLOC;
1008       [priv->status_item setImage:gtk_status_icon_blank_icon (status_icon)];
1009       QUARTZ_POOL_RELEASE;
1010 #endif
1011       return;
1012     }
1013
1014   switch (priv->storage_type)
1015     {
1016     case GTK_IMAGE_PIXBUF:
1017       {
1018         GdkPixbuf *pixbuf;
1019
1020         pixbuf = priv->image_data.pixbuf;
1021
1022         if (pixbuf)
1023           {
1024             GdkPixbuf *scaled;
1025             gint size;
1026             gint width;
1027             gint height;
1028
1029             size = priv->size;
1030
1031             width  = gdk_pixbuf_get_width  (pixbuf);
1032             height = gdk_pixbuf_get_height (pixbuf);
1033
1034             if (width > size || height > size)
1035               scaled = gdk_pixbuf_scale_simple (pixbuf,
1036                                                 MIN (size, width),
1037                                                 MIN (size, height),
1038                                                 GDK_INTERP_BILINEAR);
1039             else
1040               scaled = g_object_ref (pixbuf);
1041
1042 #ifdef GDK_WINDOWING_X11
1043             gtk_image_set_from_pixbuf (GTK_IMAGE (priv->image), scaled);
1044 #endif
1045 #ifdef GDK_WINDOWING_WIN32
1046             prev_hicon = priv->nid.hIcon;
1047             priv->nid.hIcon = gdk_win32_pixbuf_to_hicon_libgtk_only (scaled);
1048             priv->nid.uFlags |= NIF_ICON;
1049             if (priv->nid.hWnd != NULL && priv->visible)
1050               if (!Shell_NotifyIconW (NIM_MODIFY, &priv->nid))
1051                   g_warning ("%s:%d:Shell_NotifyIcon(NIM_MODIFY) failed", __FILE__, __LINE__-1);
1052             if (prev_hicon)
1053               DestroyIcon (prev_hicon);
1054 #endif
1055 #ifdef GDK_WINDOWING_QUARTZ
1056       QUARTZ_POOL_ALLOC;
1057       [priv->status_item setImage:scaled];
1058       QUARTZ_POOL_RELEASE;
1059 #endif
1060                         
1061             g_object_unref (scaled);
1062           }
1063         else
1064           {
1065 #ifdef GDK_WINDOWING_X11
1066             gtk_image_set_from_pixbuf (GTK_IMAGE (priv->image), NULL);
1067 #endif
1068 #ifdef GDK_WINDOWING_WIN32
1069             priv->nid.uFlags &= ~NIF_ICON;
1070             if (priv->nid.hWnd != NULL && priv->visible)
1071               if (!Shell_NotifyIconW (NIM_MODIFY, &priv->nid))
1072                 g_warning ("%s:%d:Shell_NotifyIcon(NIM_MODIFY) failed", __FILE__, __LINE__-1);
1073 #endif
1074 #ifdef GDK_WINDOWING_QUARTZ
1075       [priv->status_item setImage:NULL];
1076 #endif
1077           }
1078       }
1079       break;
1080
1081     case GTK_IMAGE_STOCK:
1082       {
1083 #ifdef GDK_WINDOWING_X11
1084         GtkIconSize size = find_icon_size (priv->image, priv->size);
1085         gtk_image_set_from_stock (GTK_IMAGE (priv->image),
1086                                   priv->image_data.stock_id,
1087                                   size);
1088 #endif
1089 #ifdef GDK_WINDOWING_WIN32
1090         {
1091           GdkPixbuf *pixbuf =
1092             gtk_widget_render_icon (priv->dummy_widget,
1093                                     priv->image_data.stock_id,
1094                                     GTK_ICON_SIZE_SMALL_TOOLBAR,
1095                                     NULL);
1096
1097           prev_hicon = priv->nid.hIcon;
1098           priv->nid.hIcon = gdk_win32_pixbuf_to_hicon_libgtk_only (pixbuf);
1099           priv->nid.uFlags |= NIF_ICON;
1100           if (priv->nid.hWnd != NULL && priv->visible)
1101             if (!Shell_NotifyIconW (NIM_MODIFY, &priv->nid))
1102               g_warning ("%s:%d:Shell_NotifyIcon(NIM_MODIFY) failed", __FILE__, __LINE__-1);
1103           if (prev_hicon)
1104             DestroyIcon (prev_hicon);
1105           g_object_unref (pixbuf);
1106         }
1107 #endif
1108 #ifdef GDK_WINDOWING_QUARTZ
1109         {
1110           GdkPixbuf *pixbuf;
1111
1112           pixbuf = gtk_widget_render_icon (priv->dummy_widget,
1113                                            priv->image_data.stock_id,
1114                                            GTK_ICON_SIZE_SMALL_TOOLBAR,
1115                                            NULL);
1116           QUARTZ_POOL_ALLOC;
1117           [priv->status_item setImage:pixbuf];
1118           QUARTZ_POOL_RELEASE;
1119           g_object_unref (pixbuf);
1120         }       
1121 #endif
1122       }
1123       break;
1124       
1125     case GTK_IMAGE_ICON_NAME:
1126       {
1127 #ifdef GDK_WINDOWING_X11
1128         GtkIconSize size = find_icon_size (priv->image, priv->size);
1129         gtk_image_set_from_icon_name (GTK_IMAGE (priv->image),
1130                                       priv->image_data.icon_name,
1131                                       size);
1132 #endif
1133 #ifdef GDK_WINDOWING_WIN32
1134         {
1135           GdkPixbuf *pixbuf =
1136             gtk_icon_theme_load_icon (gtk_icon_theme_get_default (),
1137                                       priv->image_data.icon_name,
1138                                       priv->size,
1139                                       0, NULL);
1140           
1141           prev_hicon = priv->nid.hIcon;
1142           priv->nid.hIcon = gdk_win32_pixbuf_to_hicon_libgtk_only (pixbuf);
1143           priv->nid.uFlags |= NIF_ICON;
1144           if (priv->nid.hWnd != NULL && priv->visible)
1145             if (!Shell_NotifyIconW (NIM_MODIFY, &priv->nid))
1146               g_warning ("%s:%d:Shell_NotifyIcon(NIM_MODIFY) failed", __FILE__, __LINE__-1);
1147           if (prev_hicon)
1148             DestroyIcon (prev_hicon);
1149           g_object_unref (pixbuf);
1150         }
1151 #endif
1152 #ifdef GDK_WINDOWING_QUARTZ
1153         {
1154           GdkPixbuf *pixbuf;
1155
1156           pixbuf = gtk_icon_theme_load_icon (gtk_icon_theme_get_default (),
1157                                              priv->image_data.icon_name,
1158                                              priv->size,
1159                                              0, NULL);
1160
1161           QUARTZ_POOL_ALLOC;
1162           [priv->status_item setImage:pixbuf];
1163           QUARTZ_POOL_RELEASE;
1164           g_object_unref (pixbuf);
1165         }
1166 #endif
1167         
1168       }
1169       break;
1170       
1171     case GTK_IMAGE_EMPTY:
1172 #ifdef GDK_WINDOWING_X11
1173       gtk_image_set_from_pixbuf (GTK_IMAGE (priv->image), NULL);
1174 #endif
1175 #ifdef GDK_WINDOWING_WIN32
1176       priv->nid.uFlags &= ~NIF_ICON;
1177       if (priv->nid.hWnd != NULL && priv->visible)
1178         if (!Shell_NotifyIconW (NIM_MODIFY, &priv->nid))
1179           g_warning ("%s:%d:Shell_NotifyIcon(NIM_MODIFY) failed", __FILE__, __LINE__-1);
1180 #endif
1181 #ifdef GDK_WINDOWING_QUARTZ
1182         {
1183           QUARTZ_POOL_ALLOC;
1184           [priv->status_item setImage:NULL];
1185           QUARTZ_POOL_RELEASE;
1186         }
1187 #endif
1188       break;
1189     default:
1190       g_assert_not_reached ();
1191       break;
1192     }
1193 }
1194
1195 #ifdef GDK_WINDOWING_X11
1196
1197 static void
1198 gtk_status_icon_size_allocate (GtkStatusIcon *status_icon,
1199                                GtkAllocation *allocation)
1200 {
1201   GtkStatusIconPrivate *priv = status_icon->priv;
1202   GtkOrientation orientation;
1203   gint size;
1204
1205   orientation = _gtk_tray_icon_get_orientation (GTK_TRAY_ICON (priv->tray_icon));
1206
1207   if (orientation == GTK_ORIENTATION_HORIZONTAL)
1208     size = allocation->height;
1209   else
1210     size = allocation->width;
1211
1212   priv->image_width = allocation->width - GTK_MISC (priv->image)->xpad * 2;
1213   priv->image_height = allocation->height - GTK_MISC (priv->image)->ypad * 2;
1214
1215   if (priv->size != size)
1216     {
1217       priv->size = size;
1218
1219       g_object_notify (G_OBJECT (status_icon), "size");
1220
1221       if (!emit_size_changed_signal (status_icon, size))
1222         gtk_status_icon_update_image (status_icon);
1223     }
1224 }
1225
1226 static void
1227 gtk_status_icon_screen_changed (GtkStatusIcon *status_icon,
1228                                 GdkScreen *old_screen)
1229 {
1230   GtkStatusIconPrivate *priv = status_icon->priv;
1231
1232   if (gtk_widget_get_screen (priv->tray_icon) != old_screen)
1233     {
1234       g_object_notify (G_OBJECT (status_icon), "screen");
1235     }
1236 }
1237
1238 #endif
1239
1240 #ifdef GDK_WINDOWING_X11
1241
1242 static void
1243 gtk_status_icon_embedded_changed (GtkStatusIcon *status_icon)
1244 {
1245   g_object_notify (G_OBJECT (status_icon), "embedded");
1246 }
1247
1248 static void
1249 gtk_status_icon_orientation_changed (GtkStatusIcon *status_icon)
1250 {
1251   g_object_notify (G_OBJECT (status_icon), "orientation");
1252 }
1253
1254 static gboolean
1255 gtk_status_icon_key_press (GtkStatusIcon  *status_icon,
1256                            GdkEventKey    *event)
1257 {
1258   guint state, keyval;
1259
1260   state = event->state & gtk_accelerator_get_default_mod_mask ();
1261   keyval = event->keyval;
1262   if (state == 0 &&
1263       (keyval == GDK_Return ||
1264        keyval == GDK_KP_Enter ||
1265        keyval == GDK_ISO_Enter ||
1266        keyval == GDK_space ||
1267        keyval == GDK_KP_Space))
1268     {
1269       emit_activate_signal (status_icon);
1270       return TRUE;
1271     }
1272
1273   return FALSE;
1274 }
1275
1276 static void
1277 gtk_status_icon_popup_menu (GtkStatusIcon  *status_icon)
1278 {
1279   emit_popup_menu_signal (status_icon, 0, gtk_get_current_event_time ());
1280 }
1281
1282 #endif
1283
1284 static gboolean
1285 gtk_status_icon_button_press (GtkStatusIcon  *status_icon,
1286                               GdkEventButton *event)
1287 {
1288   if (event->button == 1 && event->type == GDK_BUTTON_PRESS)
1289     {
1290       emit_activate_signal (status_icon);
1291       return TRUE;
1292     }
1293   else if (event->button == 3 && event->type == GDK_BUTTON_PRESS)
1294     {
1295       emit_popup_menu_signal (status_icon, event->button, event->time);
1296       return TRUE;
1297     }
1298
1299   return FALSE;
1300 }
1301
1302 static void
1303 gtk_status_icon_reset_image_data (GtkStatusIcon *status_icon)
1304 {
1305   GtkStatusIconPrivate *priv = status_icon->priv;
1306
1307   switch (priv->storage_type)
1308   {
1309     case GTK_IMAGE_PIXBUF:
1310       if (priv->image_data.pixbuf)
1311         g_object_unref (priv->image_data.pixbuf);
1312       priv->image_data.pixbuf = NULL;
1313       g_object_notify (G_OBJECT (status_icon), "pixbuf");
1314       break;
1315
1316     case GTK_IMAGE_STOCK:
1317       g_free (priv->image_data.stock_id);
1318       priv->image_data.stock_id = NULL;
1319
1320       g_object_notify (G_OBJECT (status_icon), "stock");
1321       break;
1322       
1323     case GTK_IMAGE_ICON_NAME:
1324       g_free (priv->image_data.icon_name);
1325       priv->image_data.icon_name = NULL;
1326
1327       g_object_notify (G_OBJECT (status_icon), "icon-name");
1328       break;
1329       
1330     case GTK_IMAGE_EMPTY:
1331       break;
1332     default:
1333       g_assert_not_reached ();
1334       break;
1335   }
1336
1337   priv->storage_type = GTK_IMAGE_EMPTY;
1338   g_object_notify (G_OBJECT (status_icon), "storage-type");
1339 }
1340
1341 static void
1342 gtk_status_icon_set_image (GtkStatusIcon *status_icon,
1343                            GtkImageType   storage_type,
1344                            gpointer       data)
1345 {
1346   GtkStatusIconPrivate *priv = status_icon->priv;
1347
1348   g_object_freeze_notify (G_OBJECT (status_icon));
1349
1350   gtk_status_icon_reset_image_data (status_icon);
1351
1352   priv->storage_type = storage_type;
1353   g_object_notify (G_OBJECT (status_icon), "storage-type");
1354
1355   switch (storage_type) 
1356     {
1357     case GTK_IMAGE_PIXBUF:
1358       priv->image_data.pixbuf = (GdkPixbuf *)data;
1359       g_object_notify (G_OBJECT (status_icon), "pixbuf");
1360       break;
1361     case GTK_IMAGE_STOCK:
1362       priv->image_data.stock_id = g_strdup ((const gchar *)data);
1363       g_object_notify (G_OBJECT (status_icon), "stock");
1364       break;
1365     case GTK_IMAGE_ICON_NAME:
1366       priv->image_data.icon_name = g_strdup ((const gchar *)data);
1367       g_object_notify (G_OBJECT (status_icon), "icon-name");
1368       break;
1369     default:
1370       g_warning ("Image type %u not handled by GtkStatusIcon", storage_type);
1371     }
1372
1373   g_object_thaw_notify (G_OBJECT (status_icon));
1374
1375   gtk_status_icon_update_image (status_icon);
1376 }
1377
1378 /**
1379  * gtk_status_icon_set_from_pixbuf:
1380  * @status_icon: a #GtkStatusIcon
1381  * @pixbuf: a #GdkPixbuf or %NULL
1382  * 
1383  * Makes @status_icon display @pixbuf. 
1384  * See gtk_status_icon_new_from_pixbuf() for details.
1385  *
1386  * Since: 2.10
1387  **/
1388 void
1389 gtk_status_icon_set_from_pixbuf (GtkStatusIcon *status_icon,
1390                                  GdkPixbuf     *pixbuf)
1391 {
1392   g_return_if_fail (GTK_IS_STATUS_ICON (status_icon));
1393   g_return_if_fail (pixbuf == NULL || GDK_IS_PIXBUF (pixbuf));
1394
1395   if (pixbuf)
1396     g_object_ref (pixbuf);
1397
1398   gtk_status_icon_set_image (status_icon, GTK_IMAGE_PIXBUF,
1399                              (gpointer) pixbuf);
1400 }
1401
1402 /**
1403  * gtk_status_icon_set_from_file:
1404  * @status_icon: a #GtkStatusIcon
1405  * @filename: a filename
1406  * 
1407  * Makes @status_icon display the file @filename.
1408  * See gtk_status_icon_new_from_file() for details.
1409  *
1410  * Since: 2.10 
1411  **/
1412 void
1413 gtk_status_icon_set_from_file (GtkStatusIcon *status_icon,
1414                                const gchar   *filename)
1415 {
1416   GdkPixbuf *pixbuf;
1417   
1418   g_return_if_fail (GTK_IS_STATUS_ICON (status_icon));
1419   g_return_if_fail (filename != NULL);
1420   
1421   pixbuf = gdk_pixbuf_new_from_file (filename, NULL);
1422   
1423   gtk_status_icon_set_from_pixbuf (status_icon, pixbuf);
1424   
1425   if (pixbuf)
1426     g_object_unref (pixbuf);
1427 }
1428
1429 /**
1430  * gtk_status_icon_set_from_stock:
1431  * @status_icon: a #GtkStatusIcon
1432  * @stock_id: a stock icon id
1433  * 
1434  * Makes @status_icon display the stock icon with the id @stock_id.
1435  * See gtk_status_icon_new_from_stock() for details.
1436  *
1437  * Since: 2.10 
1438  **/
1439 void
1440 gtk_status_icon_set_from_stock (GtkStatusIcon *status_icon,
1441                                 const gchar   *stock_id)
1442 {
1443   g_return_if_fail (GTK_IS_STATUS_ICON (status_icon));
1444   g_return_if_fail (stock_id != NULL);
1445
1446   gtk_status_icon_set_image (status_icon, GTK_IMAGE_STOCK,
1447                              (gpointer) stock_id);
1448 }
1449
1450 /**
1451  * gtk_status_icon_set_from_icon_name:
1452  * @status_icon: a #GtkStatusIcon
1453  * @icon_name: an icon name
1454  * 
1455  * Makes @status_icon display the icon named @icon_name from the 
1456  * current icon theme.
1457  * See gtk_status_icon_new_from_icon_name() for details.
1458  *
1459  * Since: 2.10 
1460  **/
1461 void
1462 gtk_status_icon_set_from_icon_name (GtkStatusIcon *status_icon,
1463                                     const gchar   *icon_name)
1464 {
1465   g_return_if_fail (GTK_IS_STATUS_ICON (status_icon));
1466   g_return_if_fail (icon_name != NULL);
1467
1468   gtk_status_icon_set_image (status_icon, GTK_IMAGE_ICON_NAME,
1469                              (gpointer) icon_name);
1470 }
1471
1472 /**
1473  * gtk_status_icon_get_storage_type:
1474  * @status_icon: a #GtkStatusIcon
1475  * 
1476  * Gets the type of representation being used by the #GtkStatusIcon
1477  * to store image data. If the #GtkStatusIcon has no image data,
1478  * the return value will be %GTK_IMAGE_EMPTY. 
1479  * 
1480  * Return value: the image representation being used
1481  *
1482  * Since: 2.10
1483  **/
1484 GtkImageType
1485 gtk_status_icon_get_storage_type (GtkStatusIcon *status_icon)
1486 {
1487   g_return_val_if_fail (GTK_IS_STATUS_ICON (status_icon), GTK_IMAGE_EMPTY);
1488
1489   return status_icon->priv->storage_type;
1490 }
1491 /**
1492  * gtk_status_icon_get_pixbuf:
1493  * @status_icon: a #GtkStatusIcon
1494  * 
1495  * Gets the #GdkPixbuf being displayed by the #GtkStatusIcon.
1496  * The storage type of the status icon must be %GTK_IMAGE_EMPTY or
1497  * %GTK_IMAGE_PIXBUF (see gtk_status_icon_get_storage_type()).
1498  * The caller of this function does not own a reference to the
1499  * returned pixbuf.
1500  * 
1501  * Return value: the displayed pixbuf, or %NULL if the image is empty.
1502  *
1503  * Since: 2.10
1504  **/
1505 GdkPixbuf *
1506 gtk_status_icon_get_pixbuf (GtkStatusIcon *status_icon)
1507 {
1508   GtkStatusIconPrivate *priv;
1509
1510   g_return_val_if_fail (GTK_IS_STATUS_ICON (status_icon), NULL);
1511
1512   priv = status_icon->priv;
1513
1514   g_return_val_if_fail (priv->storage_type == GTK_IMAGE_PIXBUF ||
1515                         priv->storage_type == GTK_IMAGE_EMPTY, NULL);
1516
1517   if (priv->storage_type == GTK_IMAGE_EMPTY)
1518     priv->image_data.pixbuf = NULL;
1519
1520   return priv->image_data.pixbuf;
1521 }
1522
1523 /**
1524  * gtk_status_icon_get_stock:
1525  * @status_icon: a #GtkStatusIcon
1526  * 
1527  * Gets the id of the stock icon being displayed by the #GtkStatusIcon.
1528  * The storage type of the status icon must be %GTK_IMAGE_EMPTY or
1529  * %GTK_IMAGE_STOCK (see gtk_status_icon_get_storage_type()).
1530  * The returned string is owned by the #GtkStatusIcon and should not
1531  * be freed or modified.
1532  * 
1533  * Return value: stock id of the displayed stock icon,
1534  *   or %NULL if the image is empty.
1535  *
1536  * Since: 2.10
1537  **/
1538 G_CONST_RETURN gchar *
1539 gtk_status_icon_get_stock (GtkStatusIcon *status_icon)
1540 {
1541   GtkStatusIconPrivate *priv;
1542
1543   g_return_val_if_fail (GTK_IS_STATUS_ICON (status_icon), NULL);
1544
1545   priv = status_icon->priv;
1546
1547   g_return_val_if_fail (priv->storage_type == GTK_IMAGE_STOCK ||
1548                         priv->storage_type == GTK_IMAGE_EMPTY, NULL);
1549   
1550   if (priv->storage_type == GTK_IMAGE_EMPTY)
1551     priv->image_data.stock_id = NULL;
1552
1553   return priv->image_data.stock_id;
1554 }
1555
1556 /**
1557  * gtk_status_icon_get_icon_name:
1558  * @status_icon: a #GtkStatusIcon
1559  * 
1560  * Gets the name of the icon being displayed by the #GtkStatusIcon.
1561  * The storage type of the status icon must be %GTK_IMAGE_EMPTY or
1562  * %GTK_IMAGE_ICON_NAME (see gtk_status_icon_get_storage_type()).
1563  * The returned string is owned by the #GtkStatusIcon and should not
1564  * be freed or modified.
1565  * 
1566  * Return value: name of the displayed icon, or %NULL if the image is empty.
1567  *
1568  * Since: 2.10
1569  **/
1570 G_CONST_RETURN gchar *
1571 gtk_status_icon_get_icon_name (GtkStatusIcon *status_icon)
1572 {
1573   GtkStatusIconPrivate *priv;
1574   
1575   g_return_val_if_fail (GTK_IS_STATUS_ICON (status_icon), NULL);
1576
1577   priv = status_icon->priv;
1578
1579   g_return_val_if_fail (priv->storage_type == GTK_IMAGE_ICON_NAME ||
1580                         priv->storage_type == GTK_IMAGE_EMPTY, NULL);
1581
1582   if (priv->storage_type == GTK_IMAGE_EMPTY)
1583     priv->image_data.icon_name = NULL;
1584
1585   return priv->image_data.icon_name;
1586 }
1587
1588 /**
1589  * gtk_status_icon_get_size:
1590  * @status_icon: a #GtkStatusIcon
1591  * 
1592  * Gets the size in pixels that is available for the image. 
1593  * Stock icons and named icons adapt their size automatically
1594  * if the size of the notification area changes. For other
1595  * storage types, the size-changed signal can be used to
1596  * react to size changes.
1597  *
1598  * Note that the returned size is only meaningful while the 
1599  * status icon is embedded (see gtk_status_icon_is_embedded()).
1600  * 
1601  * Return value: the size that is available for the image
1602  *
1603  * Since: 2.10
1604  **/
1605 gint
1606 gtk_status_icon_get_size (GtkStatusIcon *status_icon)
1607 {
1608   g_return_val_if_fail (GTK_IS_STATUS_ICON (status_icon), 0);
1609
1610   return status_icon->priv->size;
1611 }
1612
1613 /**
1614  * gtk_status_icon_set_screen:
1615  * @status_icon: a #GtkStatusIcon
1616  * @screen: a #GdkScreen
1617  *
1618  * Sets the #GdkScreen where @status_icon is displayed; if
1619  * the icon is already mapped, it will be unmapped, and
1620  * then remapped on the new screen.
1621  *
1622  * Since: 2.12
1623  */
1624 void
1625 gtk_status_icon_set_screen (GtkStatusIcon *status_icon,
1626                             GdkScreen     *screen)
1627 {
1628   g_return_if_fail (GDK_IS_SCREEN (screen));
1629
1630 #ifdef GDK_WINDOWING_X11
1631   gtk_window_set_screen (GTK_WINDOW (status_icon->priv->tray_icon), screen);
1632 #endif
1633 }
1634
1635 /** 
1636  * gtk_status_icon_get_screen:
1637  * @status_icon: a #GtkStatusIcon
1638  *
1639  * Returns the #GdkScreen associated with @status_icon.
1640  *
1641  * Return value: a #GdkScreen.
1642  *
1643  * Since: 2.12
1644  */
1645 GdkScreen *
1646 gtk_status_icon_get_screen (GtkStatusIcon *status_icon)
1647 {
1648   g_return_val_if_fail (GTK_IS_STATUS_ICON (status_icon), NULL);
1649
1650 #ifdef GDK_WINDOWING_X11   
1651   return gtk_window_get_screen (GTK_WINDOW (status_icon->priv->tray_icon));
1652 #else
1653   return gdk_screen_get_default ();
1654 #endif
1655 }
1656
1657 /**
1658  * gtk_status_icon_set_tooltip:
1659  * @status_icon: a #GtkStatusIcon
1660  * @tooltip_text: the tooltip text, or %NULL
1661  * 
1662  * Sets the tooltip of the status icon.
1663  * 
1664  * Since: 2.10
1665  **/ 
1666 void
1667 gtk_status_icon_set_tooltip (GtkStatusIcon *status_icon,
1668                              const gchar   *tooltip_text)
1669 {
1670   GtkStatusIconPrivate *priv;
1671
1672   g_return_if_fail (GTK_IS_STATUS_ICON (status_icon));
1673
1674   priv = status_icon->priv;
1675
1676 #ifdef GDK_WINDOWING_X11
1677
1678   gtk_widget_set_tooltip_text (priv->tray_icon, tooltip_text);
1679
1680 #endif
1681 #ifdef GDK_WINDOWING_WIN32
1682   if (tooltip_text == NULL)
1683     priv->nid.uFlags &= ~NIF_TIP;
1684   else
1685     {
1686       WCHAR *wcs = g_utf8_to_utf16 (tooltip_text, -1, NULL, NULL, NULL);
1687
1688       priv->nid.uFlags |= NIF_TIP;
1689       wcsncpy (priv->nid.szTip, wcs, G_N_ELEMENTS (priv->nid.szTip) - 1);
1690       priv->nid.szTip[G_N_ELEMENTS (priv->nid.szTip) - 1] = 0;
1691       g_free (wcs);
1692     }
1693   if (priv->nid.hWnd != NULL && priv->visible)
1694     if (!Shell_NotifyIconW (NIM_MODIFY, &priv->nid))
1695       g_warning ("%s:%d:Shell_NotifyIconW(NIM_MODIFY) failed", __FILE__, __LINE__-1);
1696 #endif
1697 #ifdef GDK_WINDOWING_QUARTZ
1698   QUARTZ_POOL_ALLOC;
1699   [priv->status_item setToolTip:tooltip_text];
1700   QUARTZ_POOL_RELEASE;
1701 #endif
1702 }
1703
1704 static gboolean
1705 gtk_status_icon_blinker (GtkStatusIcon *status_icon)
1706 {
1707   GtkStatusIconPrivate *priv = status_icon->priv;
1708   
1709   priv->blink_off = !priv->blink_off;
1710
1711   gtk_status_icon_update_image (status_icon);
1712
1713   return TRUE;
1714 }
1715
1716 static void
1717 gtk_status_icon_enable_blinking (GtkStatusIcon *status_icon)
1718 {
1719   GtkStatusIconPrivate *priv = status_icon->priv;
1720   
1721   if (!priv->blinking_timeout)
1722     {
1723       gtk_status_icon_blinker (status_icon);
1724
1725       priv->blinking_timeout =
1726         gdk_threads_add_timeout (BLINK_TIMEOUT, 
1727                        (GSourceFunc) gtk_status_icon_blinker, 
1728                        status_icon);
1729     }
1730 }
1731
1732 static void
1733 gtk_status_icon_disable_blinking (GtkStatusIcon *status_icon)
1734 {
1735   GtkStatusIconPrivate *priv = status_icon->priv;
1736   
1737   if (priv->blinking_timeout)
1738     {
1739       g_source_remove (priv->blinking_timeout);
1740       priv->blinking_timeout = 0;
1741       priv->blink_off = FALSE;
1742
1743       gtk_status_icon_update_image (status_icon);
1744     }
1745 }
1746
1747 /**
1748  * gtk_status_icon_set_visible:
1749  * @status_icon: a #GtkStatusIcon
1750  * @visible: %TRUE to show the status icon, %FALSE to hide it
1751  * 
1752  * Shows or hides a status icon.
1753  *
1754  * Since: 2.10
1755  **/
1756 void
1757 gtk_status_icon_set_visible (GtkStatusIcon *status_icon,
1758                              gboolean       visible)
1759 {
1760   GtkStatusIconPrivate *priv;
1761
1762   g_return_if_fail (GTK_IS_STATUS_ICON (status_icon));
1763
1764   priv = status_icon->priv;
1765
1766   visible = visible != FALSE;
1767
1768   if (priv->visible != visible)
1769     {
1770       priv->visible = visible;
1771
1772 #ifdef GDK_WINDOWING_X11
1773       if (visible)
1774         gtk_widget_show (priv->tray_icon);
1775       else if (GTK_WIDGET_REALIZED (priv->tray_icon)) 
1776         {
1777           gtk_widget_hide (priv->tray_icon);
1778           gtk_widget_unrealize (priv->tray_icon);
1779         }
1780 #endif
1781 #ifdef GDK_WINDOWING_WIN32
1782       if (priv->nid.hWnd != NULL)
1783         {
1784           if (visible)
1785             Shell_NotifyIconW (NIM_ADD, &priv->nid);
1786           else
1787             Shell_NotifyIconW (NIM_DELETE, &priv->nid);
1788         }
1789 #endif
1790 #ifdef GDK_WINDOWING_QUARTZ
1791       QUARTZ_POOL_ALLOC;
1792       [priv->status_item setVisible:visible];
1793       QUARTZ_POOL_RELEASE;
1794 #endif
1795       g_object_notify (G_OBJECT (status_icon), "visible");
1796     }
1797 }
1798
1799 /**
1800  * gtk_status_icon_get_visible:
1801  * @status_icon: a #GtkStatusIcon
1802  * 
1803  * Returns whether the status icon is visible or not. 
1804  * Note that being visible does not guarantee that 
1805  * the user can actually see the icon, see also 
1806  * gtk_status_icon_is_embedded().
1807  * 
1808  * Return value: %TRUE if the status icon is visible
1809  *
1810  * Since: 2.10
1811  **/
1812 gboolean
1813 gtk_status_icon_get_visible (GtkStatusIcon *status_icon)
1814 {
1815   g_return_val_if_fail (GTK_IS_STATUS_ICON (status_icon), FALSE);
1816
1817   return status_icon->priv->visible;
1818 }
1819
1820 /**
1821  * gtk_status_icon_set_blinking:
1822  * @status_icon: a #GtkStatusIcon
1823  * @blinking: %TRUE to turn blinking on, %FALSE to turn it off
1824  * 
1825  * Makes the status icon start or stop blinking. 
1826  * Note that blinking user interface elements may be problematic
1827  * for some users, and thus may be turned off, in which case
1828  * this setting has no effect.
1829  *
1830  * Since: 2.10
1831  **/
1832 void
1833 gtk_status_icon_set_blinking (GtkStatusIcon *status_icon,
1834                               gboolean       blinking)
1835 {
1836   GtkStatusIconPrivate *priv;
1837
1838   g_return_if_fail (GTK_IS_STATUS_ICON (status_icon));
1839
1840   priv = status_icon->priv;
1841
1842   blinking = blinking != FALSE;
1843
1844   if (priv->blinking != blinking)
1845     {
1846       priv->blinking = blinking;
1847
1848       if (blinking)
1849         gtk_status_icon_enable_blinking (status_icon);
1850       else
1851         gtk_status_icon_disable_blinking (status_icon);
1852
1853       g_object_notify (G_OBJECT (status_icon), "blinking");
1854     }
1855 }
1856
1857 /**
1858  * gtk_status_icon_get_blinking:
1859  * @status_icon: a #GtkStatusIcon
1860  * 
1861  * Returns whether the icon is blinking, see 
1862  * gtk_status_icon_set_blinking().
1863  * 
1864  * Return value: %TRUE if the icon is blinking
1865  *
1866  * Since: 2.10
1867  **/
1868 gboolean
1869 gtk_status_icon_get_blinking (GtkStatusIcon *status_icon)
1870 {
1871   g_return_val_if_fail (GTK_IS_STATUS_ICON (status_icon), FALSE);
1872
1873   return status_icon->priv->blinking;
1874 }
1875
1876 /**
1877  * gtk_status_icon_is_embedded:
1878  * @status_icon: a #GtkStatusIcon
1879  * 
1880  * Returns whether the status icon is embedded in a notification
1881  * area. 
1882  * 
1883  * Return value: %TRUE if the status icon is embedded in
1884  *   a notification area.
1885  *
1886  * Since: 2.10
1887  **/
1888 gboolean
1889 gtk_status_icon_is_embedded (GtkStatusIcon *status_icon)
1890 {
1891 #ifdef GDK_WINDOWING_X11
1892   GtkPlug *plug;
1893 #endif
1894
1895   g_return_val_if_fail (GTK_IS_STATUS_ICON (status_icon), FALSE);
1896
1897 #ifdef GDK_WINDOWING_X11
1898   plug = GTK_PLUG (status_icon->priv->tray_icon);
1899
1900   if (plug->socket_window)
1901     return TRUE;
1902   else
1903     return FALSE;
1904 #endif
1905 #ifdef GDK_WINDOWING_WIN32
1906   return TRUE;
1907 #endif
1908 #ifdef GDK_WINDOWING_QUARTZ
1909   return TRUE;
1910 #endif
1911 }
1912
1913 /**
1914  * gtk_status_icon_position_menu:
1915  * @menu: the #GtkMenu
1916  * @x: return location for the x position
1917  * @y: return location for the y position
1918  * @push_in: whether the first menu item should be offset (pushed in) to be
1919  *           aligned with the menu popup position (only useful for GtkOptionMenu).
1920  * @user_data: the status icon to position the menu on
1921  *
1922  * Menu positioning function to use with gtk_menu_popup()
1923  * to position @menu aligned to the status icon @user_data.
1924  * 
1925  * Since: 2.10
1926  **/
1927 void
1928 gtk_status_icon_position_menu (GtkMenu  *menu,
1929                                gint     *x,
1930                                gint     *y,
1931                                gboolean *push_in,
1932                                gpointer  user_data)
1933 {
1934 #ifdef GDK_WINDOWING_X11
1935   GtkStatusIcon *status_icon;
1936   GtkStatusIconPrivate *priv;
1937   GtkTrayIcon *tray_icon;
1938   GtkWidget *widget;
1939   GdkScreen *screen;
1940   GtkTextDirection direction;
1941   GtkRequisition menu_req;
1942   GdkRectangle monitor;
1943   gint monitor_num, height, width, xoffset, yoffset;
1944   
1945   g_return_if_fail (GTK_IS_MENU (menu));
1946   g_return_if_fail (GTK_IS_STATUS_ICON (user_data));
1947
1948   status_icon = GTK_STATUS_ICON (user_data);
1949   priv = status_icon->priv;
1950   tray_icon = GTK_TRAY_ICON (priv->tray_icon);
1951   widget = priv->tray_icon;
1952
1953   direction = gtk_widget_get_direction (widget);
1954
1955   screen = gtk_widget_get_screen (widget);
1956   gtk_menu_set_screen (menu, screen);
1957
1958   monitor_num = gdk_screen_get_monitor_at_window (screen, widget->window);
1959   if (monitor_num < 0)
1960     monitor_num = 0;
1961   gtk_menu_set_monitor (menu, monitor_num);
1962
1963   gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor);
1964
1965   gdk_window_get_origin (widget->window, x, y);
1966   
1967   gtk_widget_size_request (GTK_WIDGET (menu), &menu_req);
1968
1969   if (_gtk_tray_icon_get_orientation (tray_icon) == GTK_ORIENTATION_VERTICAL)
1970     {
1971       width = 0;
1972       height = widget->allocation.height;
1973       xoffset = widget->allocation.width;
1974       yoffset = 0;
1975     }
1976   else
1977     {
1978       width = widget->allocation.width;
1979       height = 0;
1980       xoffset = 0;
1981       yoffset = widget->allocation.height;
1982     }
1983
1984   if (direction == GTK_TEXT_DIR_RTL)
1985     {
1986       if ((*x - (menu_req.width - width)) >= monitor.x)
1987         *x -= menu_req.width - width;
1988       else if ((*x + xoffset + menu_req.width) < (monitor.x + monitor.width))
1989         *x += xoffset;
1990       else if ((monitor.x + monitor.width - (*x + xoffset)) < *x)
1991         *x -= menu_req.width - width;
1992       else
1993         *x += xoffset;
1994     }
1995   else
1996     {
1997       if ((*x + xoffset + menu_req.width) < (monitor.x + monitor.width))
1998         *x += xoffset;
1999       else if ((*x - (menu_req.width - width)) >= monitor.x)
2000         *x -= menu_req.width - width;
2001       else if ((monitor.x + monitor.width - (*x + xoffset)) > *x)
2002         *x += xoffset;
2003       else 
2004         *x -= menu_req.width - width;
2005     }
2006
2007   if ((*y + yoffset + menu_req.height) < (monitor.y + monitor.height))
2008     *y += yoffset;
2009   else if ((*y - (menu_req.height - height)) >= monitor.y)
2010     *y -= menu_req.height - height;
2011   else if (monitor.y + monitor.height - (*y + yoffset) > *y)
2012     *y += yoffset;
2013   else 
2014     *y -= menu_req.height - height;
2015
2016   *push_in = FALSE;
2017 #endif /* GDK_WINDOWING_X11 */
2018
2019 #ifdef GDK_WINDOWING_WIN32
2020   GtkStatusIcon *status_icon;
2021   GtkStatusIconPrivate *priv;
2022   
2023   g_return_if_fail (GTK_IS_MENU (menu));
2024   g_return_if_fail (GTK_IS_STATUS_ICON (user_data));
2025
2026   status_icon = GTK_STATUS_ICON (user_data);
2027   priv = status_icon->priv;
2028
2029   *x = priv->last_click_x;
2030   *y = priv->last_click_y;
2031   *push_in = TRUE;
2032 #endif
2033 }
2034
2035 /**
2036  * gtk_status_icon_get_geometry:
2037  * @status_icon: a #GtkStatusIcon
2038  * @screen: return location for the screen, or %NULL if the
2039  *          information is not needed 
2040  * @area: return location for the area occupied by the status 
2041  *        icon, or %NULL
2042  * @orientation: return location for the orientation of the panel 
2043  *    in which the status icon is embedded, or %NULL. A panel 
2044  *    at the top or bottom of the screen is horizontal, a panel 
2045  *    at the left or right is vertical.
2046  *
2047  * Obtains information about the location of the status icon
2048  * on screen. This information can be used to e.g. position 
2049  * popups like notification bubbles. 
2050  *
2051  * See gtk_status_icon_position_menu() for a more convenient 
2052  * alternative for positioning menus.
2053  *
2054  * Note that some platforms do not allow GTK+ to provide 
2055  * this information, and even on platforms that do allow it,
2056  * the information is not reliable unless the status icon
2057  * is embedded in a notification area, see
2058  * gtk_status_icon_is_embedded().
2059  *
2060  * Return value: %TRUE if the location information has 
2061  *               been filled in
2062  *
2063  * Since: 2.10
2064  */
2065 gboolean  
2066 gtk_status_icon_get_geometry (GtkStatusIcon    *status_icon,
2067                               GdkScreen       **screen,
2068                               GdkRectangle     *area,
2069                               GtkOrientation   *orientation)
2070 {
2071 #ifdef GDK_WINDOWING_X11   
2072   GtkWidget *widget;
2073   GtkStatusIconPrivate *priv;
2074   gint x, y;
2075
2076   g_return_val_if_fail (GTK_IS_STATUS_ICON (status_icon), FALSE);
2077
2078   priv = status_icon->priv;
2079   widget = priv->tray_icon;
2080
2081   if (screen)
2082     *screen = gtk_widget_get_screen (widget);
2083
2084   if (area)
2085     {
2086       gdk_window_get_origin (widget->window, &x, &y);
2087       area->x = x;
2088       area->y = y;
2089       area->width = widget->allocation.width;
2090       area->height = widget->allocation.height;
2091     }
2092
2093   if (orientation)
2094     *orientation = _gtk_tray_icon_get_orientation (GTK_TRAY_ICON (widget));
2095
2096   return TRUE;
2097 #else
2098   return FALSE;
2099 #endif /* GDK_WINDOWING_X11 */
2100 }
2101
2102 /**
2103  * gtk_status_icon_get_x11_window_id:
2104  * @status_icon: a #GtkStatusIcon
2105  *
2106  * This function is only useful on the X11/freedesktop.org platform.
2107  * It returns a window ID for the widget in the underlying
2108  * status icon implementation.  This is useful for the Galago 
2109  * notification service, which can send a window ID in the protocol 
2110  * in order for the server to position notification windows 
2111  * pointing to a status icon reliably.
2112  *
2113  * This function is not intended for other use cases which are
2114  * more likely to be met by one of the non-X11 specific methods, such
2115  * as gtk_status_icon_position_menu().
2116  *
2117  * Return value: An 32 bit unsigned integer identifier for the 
2118  * underlying X11 Window
2119  *
2120  * Since: 2.14
2121  */
2122 guint32
2123 gtk_status_icon_get_x11_window_id (GtkStatusIcon *status_icon)
2124 {
2125 #ifdef GDK_WINDOWING_X11
2126   gtk_widget_realize (GTK_WIDGET (status_icon->priv->tray_icon));
2127   return GDK_WINDOW_XID (GTK_WIDGET (status_icon->priv->tray_icon)->window);
2128 #else
2129   return 0;
2130 #endif
2131 }
2132
2133 #define __GTK_STATUS_ICON_C__
2134 #include "gtkaliasdef.c"