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