gnome-shell-3.6.3.1/src/tray/na-tray-manager.c

No issues found

Incomplete coverage

Tool Failure ID Location Function Message Data
clang-analyzer no-output-found tray/na-tray-manager.c Message(text='Unable to locate XML output from invoke-clang-analyzer') None
Failure running clang-analyzer ('no-output-found')
Message
Unable to locate XML output from invoke-clang-analyzer
  1 /* na-tray-manager.c
  2  * Copyright (C) 2002 Anders Carlsson <andersca@gnu.org>
  3  * Copyright (C) 2003-2006 Vincent Untz
  4  *
  5  * This library is free software; you can redistribute it and/or
  6  * modify it under the terms of the GNU Lesser General Public
  7  * License as published by the Free Software Foundation; either
  8  * version 2 of the License, or (at your option) any later version.
  9  *
 10  * This library is distributed in the hope that it will be useful,
 11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 13  * Lesser General Public License for more details.
 14  *
 15  * You should have received a copy of the GNU Lesser General Public
 16  * License along with this library; if not, write to the
 17  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 18  * Boston, MA 02111-1307, USA.
 19  *
 20  * Used to be: eggtraymanager.c
 21  */
 22 
 23 #include <config.h>
 24 #include <string.h>
 25 #include <libintl.h>
 26 
 27 #include "na-tray-manager.h"
 28 
 29 #if defined (GDK_WINDOWING_X11)
 30 #include <gdk/gdkx.h>
 31 #include <X11/Xatom.h>
 32 #elif defined (GDK_WINDOWING_WIN32)
 33 #include <gdk/gdkwin32.h>
 34 #endif
 35 #include <gtk/gtk.h>
 36 
 37 /* Signals */
 38 enum
 39 {
 40   TRAY_ICON_ADDED,
 41   TRAY_ICON_REMOVED,
 42   MESSAGE_SENT,
 43   MESSAGE_CANCELLED,
 44   LOST_SELECTION,
 45   LAST_SIGNAL
 46 };
 47 
 48 enum {
 49   PROP_0,
 50   PROP_ORIENTATION
 51 };
 52 
 53 typedef struct
 54 {
 55   long id, len;
 56   long remaining_len;
 57   
 58   long timeout;
 59   char *str;
 60 #ifdef GDK_WINDOWING_X11
 61   Window window;
 62 #endif
 63 } PendingMessage;
 64 
 65 static guint manager_signals[LAST_SIGNAL];
 66 
 67 #define SYSTEM_TRAY_REQUEST_DOCK    0
 68 #define SYSTEM_TRAY_BEGIN_MESSAGE   1
 69 #define SYSTEM_TRAY_CANCEL_MESSAGE  2
 70 
 71 #define SYSTEM_TRAY_ORIENTATION_HORZ 0
 72 #define SYSTEM_TRAY_ORIENTATION_VERT 1
 73 
 74 #ifdef GDK_WINDOWING_X11
 75 static gboolean na_tray_manager_check_running_screen_x11 (GdkScreen *screen);
 76 #endif
 77 
 78 static void na_tray_manager_finalize     (GObject      *object);
 79 static void na_tray_manager_set_property (GObject      *object,
 80 					  guint         prop_id,
 81 					  const GValue *value,
 82 					  GParamSpec   *pspec);
 83 static void na_tray_manager_get_property (GObject      *object,
 84 					  guint         prop_id,
 85 					  GValue       *value,
 86 					  GParamSpec   *pspec);
 87 
 88 static void na_tray_manager_unmanage (NaTrayManager *manager);
 89 
 90 G_DEFINE_TYPE (NaTrayManager, na_tray_manager, G_TYPE_OBJECT)
 91 
 92 static void
 93 na_tray_manager_init (NaTrayManager *manager)
 94 {
 95   manager->invisible = NULL;
 96   manager->socket_table = g_hash_table_new (NULL, NULL);
 97 
 98   manager->fg.red = 0;
 99   manager->fg.green = 0;
100   manager->fg.blue = 0;
101 
102   manager->error.red = 0xffff;
103   manager->error.green = 0;
104   manager->error.blue = 0;
105 
106   manager->warning.red = 0xffff;
107   manager->warning.green = 0xffff;
108   manager->warning.blue = 0;
109 
110   manager->success.red = 0;
111   manager->success.green = 0xffff;
112   manager->success.blue = 0;
113 }
114 
115 static void
116 na_tray_manager_class_init (NaTrayManagerClass *klass)
117 {
118   GObjectClass *gobject_class;
119   
120   gobject_class = (GObjectClass *)klass;
121 
122   gobject_class->finalize = na_tray_manager_finalize;
123   gobject_class->set_property = na_tray_manager_set_property;
124   gobject_class->get_property = na_tray_manager_get_property;
125 
126   g_object_class_install_property (gobject_class,
127 				   PROP_ORIENTATION,
128 				   g_param_spec_enum ("orientation",
129 						      "orientation",
130 						      "orientation",
131 						      GTK_TYPE_ORIENTATION,
132 						      GTK_ORIENTATION_HORIZONTAL,
133 						      G_PARAM_READWRITE |
134 						      G_PARAM_CONSTRUCT |
135 						      G_PARAM_STATIC_NAME |
136 						      G_PARAM_STATIC_NICK |
137 						      G_PARAM_STATIC_BLURB));
138   
139   manager_signals[TRAY_ICON_ADDED] =
140     g_signal_new ("tray_icon_added",
141 		  G_OBJECT_CLASS_TYPE (klass),
142 		  G_SIGNAL_RUN_LAST,
143 		  G_STRUCT_OFFSET (NaTrayManagerClass, tray_icon_added),
144                   NULL, NULL, NULL,
145 		  G_TYPE_NONE, 1,
146 		  GTK_TYPE_SOCKET);
147 
148   manager_signals[TRAY_ICON_REMOVED] =
149     g_signal_new ("tray_icon_removed",
150 		  G_OBJECT_CLASS_TYPE (klass),
151 		  G_SIGNAL_RUN_LAST,
152 		  G_STRUCT_OFFSET (NaTrayManagerClass, tray_icon_removed),
153                   NULL, NULL, NULL,
154 		  G_TYPE_NONE, 1,
155 		  GTK_TYPE_SOCKET);
156   manager_signals[MESSAGE_SENT] =
157     g_signal_new ("message_sent",
158 		  G_OBJECT_CLASS_TYPE (klass),
159 		  G_SIGNAL_RUN_LAST,
160 		  G_STRUCT_OFFSET (NaTrayManagerClass, message_sent),
161                   NULL, NULL, NULL,
162 		  G_TYPE_NONE, 4,
163 		  GTK_TYPE_SOCKET,
164 		  G_TYPE_STRING,
165 		  G_TYPE_LONG,
166 		  G_TYPE_LONG);
167   manager_signals[MESSAGE_CANCELLED] =
168     g_signal_new ("message_cancelled",
169 		  G_OBJECT_CLASS_TYPE (klass),
170 		  G_SIGNAL_RUN_LAST,
171 		  G_STRUCT_OFFSET (NaTrayManagerClass, message_cancelled),
172                   NULL, NULL, NULL,
173 		  G_TYPE_NONE, 2,
174 		  GTK_TYPE_SOCKET,
175 		  G_TYPE_LONG);
176   manager_signals[LOST_SELECTION] =
177     g_signal_new ("lost_selection",
178 		  G_OBJECT_CLASS_TYPE (klass),
179 		  G_SIGNAL_RUN_LAST,
180 		  G_STRUCT_OFFSET (NaTrayManagerClass, lost_selection),
181                   NULL, NULL, NULL,
182 		  G_TYPE_NONE, 0);
183 
184 #if defined (GDK_WINDOWING_X11)
185   /* Nothing */
186 #elif defined (GDK_WINDOWING_WIN32)
187   g_warning ("Port NaTrayManager to Win32");
188 #else
189   g_warning ("Port NaTrayManager to this GTK+ backend");
190 #endif
191 }
192 
193 static void
194 na_tray_manager_finalize (GObject *object)
195 {
196   NaTrayManager *manager;
197   
198   manager = NA_TRAY_MANAGER (object);
199 
200   na_tray_manager_unmanage (manager);
201 
202   g_list_free (manager->messages);
203   g_hash_table_destroy (manager->socket_table);
204   
205   G_OBJECT_CLASS (na_tray_manager_parent_class)->finalize (object);
206 }
207 
208 static void
209 na_tray_manager_set_property (GObject      *object,
210 			      guint         prop_id,
211 			      const GValue *value,
212 			      GParamSpec   *pspec)
213 {
214   NaTrayManager *manager = NA_TRAY_MANAGER (object);
215 
216   switch (prop_id)
217     {
218     case PROP_ORIENTATION:
219       na_tray_manager_set_orientation (manager, g_value_get_enum (value));
220       break;
221     default:
222       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
223       break;
224     }
225 }
226 
227 static void
228 na_tray_manager_get_property (GObject    *object,
229 			      guint       prop_id,
230 			      GValue     *value,
231 			      GParamSpec *pspec)
232 {
233   NaTrayManager *manager = NA_TRAY_MANAGER (object);
234 
235   switch (prop_id)
236     {
237     case PROP_ORIENTATION:
238       g_value_set_enum (value, manager->orientation);
239       break;
240     default:
241       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
242       break;
243     }
244 }
245 
246 NaTrayManager *
247 na_tray_manager_new (void)
248 {
249   NaTrayManager *manager;
250 
251   manager = g_object_new (NA_TYPE_TRAY_MANAGER, NULL);
252 
253   return manager;
254 }
255 
256 #ifdef GDK_WINDOWING_X11
257 
258 static gboolean
259 na_tray_manager_plug_removed (GtkSocket       *socket,
260 			      NaTrayManager   *manager)
261 {
262   NaTrayChild *child = NA_TRAY_CHILD (socket);
263 
264   g_hash_table_remove (manager->socket_table,
265                        GINT_TO_POINTER (child->icon_window));
266   g_signal_emit (manager, manager_signals[TRAY_ICON_REMOVED], 0, child);
267 
268   /* This destroys the socket. */
269   return FALSE;
270 }
271 
272 static void
273 na_tray_manager_handle_dock_request (NaTrayManager       *manager,
274 				     XClientMessageEvent *xevent)
275 {
276   Window icon_window = xevent->data.l[2];
277   GtkWidget *child;
278 
279   if (g_hash_table_lookup (manager->socket_table,
280                            GINT_TO_POINTER (icon_window)))
281     {
282       /* We already got this notification earlier, ignore this one */
283       return;
284     }
285 
286   child = na_tray_child_new (manager->screen, icon_window);
287   if (child == NULL) /* already gone or other error */
288     return;
289 
290   g_signal_emit (manager, manager_signals[TRAY_ICON_ADDED], 0,
291 		 child);
292 
293   /* If the child wasn't attached, then destroy it */
294 
295   if (!GTK_IS_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (child))))
296     {
297       gtk_widget_destroy (child);
298       return;
299     }
300 
301   g_signal_connect (child, "plug_removed",
302 		    G_CALLBACK (na_tray_manager_plug_removed), manager);
303 
304   gtk_socket_add_id (GTK_SOCKET (child), icon_window);
305 
306   if (!gtk_socket_get_plug_window (GTK_SOCKET (child)))
307     {
308       /* Embedding failed, we won't get a plug-removed signal */
309       /* This signal destroys the socket */
310       g_signal_emit (manager, manager_signals[TRAY_ICON_REMOVED], 0, child);
311       return;
312     }
313 
314   g_hash_table_insert (manager->socket_table,
315                        GINT_TO_POINTER (icon_window), child);
316   gtk_widget_show (child);
317 }
318 
319 static void
320 pending_message_free (PendingMessage *message)
321 {
322   g_free (message->str);
323   g_free (message);
324 }
325 
326 static void
327 na_tray_manager_handle_message_data (NaTrayManager       *manager,
328 				     XClientMessageEvent *xevent)
329 {
330   GList *p;
331   int    len;
332   
333   /* Try to see if we can find the pending message in the list */
334   for (p = manager->messages; p; p = p->next)
335     {
336       PendingMessage *msg = p->data;
337 
338       if (xevent->window == msg->window)
339 	{
340 	  /* Append the message */
341 	  len = MIN (msg->remaining_len, 20);
342 
343 	  memcpy ((msg->str + msg->len - msg->remaining_len),
344 		  &xevent->data, len);
345 	  msg->remaining_len -= len;
346 
347 	  if (msg->remaining_len == 0)
348 	    {
349 	      GtkSocket *socket;
350 
351 	      socket = g_hash_table_lookup (manager->socket_table,
352                                             GINT_TO_POINTER (msg->window));
353 
354 	      if (socket)
355 		  g_signal_emit (manager, manager_signals[MESSAGE_SENT], 0,
356 				 socket, msg->str, msg->id, msg->timeout);
357 
358 	      pending_message_free (msg);
359 	      manager->messages = g_list_remove_link (manager->messages, p);
360               g_list_free_1 (p);
361 	    }
362 
363           break;
364 	}
365     }
366 }
367 
368 static void
369 na_tray_manager_handle_begin_message (NaTrayManager       *manager,
370 				      XClientMessageEvent *xevent)
371 {
372   GtkSocket      *socket;
373   GList          *p;
374   PendingMessage *msg;
375   long            timeout;
376   long            len;
377   long            id;
378 
379   socket = g_hash_table_lookup (manager->socket_table,
380                                 GINT_TO_POINTER (xevent->window));
381   /* we don't know about this tray icon, so ignore the message */
382   if (!socket)
383     return;
384 
385   timeout = xevent->data.l[2];
386   len     = xevent->data.l[3];
387   id      = xevent->data.l[4];
388 
389   /* Check if the same message is already in the queue and remove it if so */
390   for (p = manager->messages; p; p = p->next)
391     {
392       PendingMessage *pmsg = p->data;
393 
394       if (xevent->window == pmsg->window &&
395 	  id == pmsg->id)
396 	{
397 	  /* Hmm, we found it, now remove it */
398 	  pending_message_free (pmsg);
399 	  manager->messages = g_list_remove_link (manager->messages, p);
400           g_list_free_1 (p);
401 	  break;
402 	}
403     }
404 
405   if (len == 0)
406     {
407       g_signal_emit (manager, manager_signals[MESSAGE_SENT], 0,
408                      socket, "", id, timeout);
409     }
410   else
411     {
412       /* Now add the new message to the queue */
413       msg = g_new0 (PendingMessage, 1);
414       msg->window = xevent->window;
415       msg->timeout = timeout;
416       msg->len = len;
417       msg->id = id;
418       msg->remaining_len = msg->len;
419       msg->str = g_malloc (msg->len + 1);
420       msg->str[msg->len] = '\0';
421       manager->messages = g_list_prepend (manager->messages, msg);
422     }
423 }
424 
425 static void
426 na_tray_manager_handle_cancel_message (NaTrayManager       *manager,
427 				       XClientMessageEvent *xevent)
428 {
429   GList     *p;
430   GtkSocket *socket;
431   long       id;
432 
433   id = xevent->data.l[2];
434   
435   /* Check if the message is in the queue and remove it if so */
436   for (p = manager->messages; p; p = p->next)
437     {
438       PendingMessage *msg = p->data;
439 
440       if (xevent->window == msg->window &&
441 	  id == msg->id)
442 	{
443 	  pending_message_free (msg);
444 	  manager->messages = g_list_remove_link (manager->messages, p);
445           g_list_free_1 (p);
446 	  break;
447 	}
448     }
449 
450   socket = g_hash_table_lookup (manager->socket_table,
451                                 GINT_TO_POINTER (xevent->window));
452   
453   if (socket)
454     {
455       g_signal_emit (manager, manager_signals[MESSAGE_CANCELLED], 0,
456 		     socket, xevent->data.l[2]);
457     }
458 }
459 
460 static GdkFilterReturn
461 na_tray_manager_window_filter (GdkXEvent *xev,
462                                GdkEvent  *event,
463                                gpointer   data)
464 {
465   XEvent        *xevent = (GdkXEvent *)xev;
466   NaTrayManager *manager = data;
467 
468   if (xevent->type == ClientMessage)
469     {
470       /* _NET_SYSTEM_TRAY_OPCODE: SYSTEM_TRAY_REQUEST_DOCK */
471       if (xevent->xclient.message_type == manager->opcode_atom &&
472           xevent->xclient.data.l[1]    == SYSTEM_TRAY_REQUEST_DOCK)
473 	{
474           na_tray_manager_handle_dock_request (manager,
475                                                (XClientMessageEvent *) xevent);
476           return GDK_FILTER_REMOVE;
477 	}
478       /* _NET_SYSTEM_TRAY_OPCODE: SYSTEM_TRAY_BEGIN_MESSAGE */
479       else if (xevent->xclient.message_type == manager->opcode_atom &&
480                xevent->xclient.data.l[1]    == SYSTEM_TRAY_BEGIN_MESSAGE)
481         {
482           na_tray_manager_handle_begin_message (manager,
483                                                 (XClientMessageEvent *) event);
484           return GDK_FILTER_REMOVE;
485         }
486       /* _NET_SYSTEM_TRAY_OPCODE: SYSTEM_TRAY_CANCEL_MESSAGE */
487       else if (xevent->xclient.message_type == manager->opcode_atom &&
488                xevent->xclient.data.l[1]    == SYSTEM_TRAY_CANCEL_MESSAGE)
489         {
490           na_tray_manager_handle_cancel_message (manager,
491                                                  (XClientMessageEvent *) event);
492           return GDK_FILTER_REMOVE;
493         }
494       /* _NET_SYSTEM_TRAY_MESSAGE_DATA */
495       else if (xevent->xclient.message_type == manager->message_data_atom)
496         {
497           na_tray_manager_handle_message_data (manager,
498                                                (XClientMessageEvent *) event);
499           return GDK_FILTER_REMOVE;
500         }
501     }
502   else if (xevent->type == SelectionClear)
503     {
504       g_signal_emit (manager, manager_signals[LOST_SELECTION], 0);
505       na_tray_manager_unmanage (manager);
506     }
507 
508   return GDK_FILTER_CONTINUE;
509 }
510 
511 #if 0
512 //FIXME investigate why this doesn't work
513 static gboolean
514 na_tray_manager_selection_clear_event (GtkWidget         *widget,
515                                        GdkEventSelection *event,
516                                        NaTrayManager     *manager)
517 {
518   g_signal_emit (manager, manager_signals[LOST_SELECTION], 0);
519   na_tray_manager_unmanage (manager);
520 
521   return FALSE;
522 }
523 #endif
524 #endif  
525 
526 static void
527 na_tray_manager_unmanage (NaTrayManager *manager)
528 {
529 #ifdef GDK_WINDOWING_X11
530   GdkDisplay *display;
531   guint32     timestamp;
532   GtkWidget  *invisible;
533   GdkWindow  *window;
534 
535   if (manager->invisible == NULL)
536     return;
537 
538   invisible = manager->invisible;
539   window = gtk_widget_get_window (invisible);
540 
541   g_assert (GTK_IS_INVISIBLE (invisible));
542   g_assert (gtk_widget_get_realized (invisible));
543   g_assert (GDK_IS_WINDOW (window));
544   
545   display = gtk_widget_get_display (invisible);
546   
547   if (gdk_selection_owner_get_for_display (display, manager->selection_atom) ==
548       window)
549     {
550       timestamp = gdk_x11_get_server_time (window);
551       gdk_selection_owner_set_for_display (display,
552                                            NULL,
553                                            manager->selection_atom,
554                                            timestamp,
555                                            TRUE);
556     }
557 
558   gdk_window_remove_filter (window,
559                             na_tray_manager_window_filter, manager);  
560 
561   manager->invisible = NULL; /* prior to destroy for reentrancy paranoia */
562   gtk_widget_destroy (invisible);
563   g_object_unref (G_OBJECT (invisible));
564 #endif
565 }
566 
567 static void
568 na_tray_manager_set_orientation_property (NaTrayManager *manager)
569 {
570 #ifdef GDK_WINDOWING_X11
571   GdkWindow  *window;
572   GdkDisplay *display;
573   Atom        orientation_atom;
574   gulong      data[1];
575 
576   g_return_if_fail (manager->invisible != NULL);
577   window = gtk_widget_get_window (manager->invisible);
578   g_return_if_fail (window != NULL);
579 
580   display = gtk_widget_get_display (manager->invisible);
581   orientation_atom = gdk_x11_get_xatom_by_name_for_display (display,
582                                                             "_NET_SYSTEM_TRAY_ORIENTATION");
583 
584   data[0] = manager->orientation == GTK_ORIENTATION_HORIZONTAL ?
585 		SYSTEM_TRAY_ORIENTATION_HORZ :
586 		SYSTEM_TRAY_ORIENTATION_VERT;
587 
588   XChangeProperty (GDK_DISPLAY_XDISPLAY (display),
589 		   GDK_WINDOW_XID (window),
590                    orientation_atom,
591 		   XA_CARDINAL, 32,
592 		   PropModeReplace,
593 		   (guchar *) &data, 1);
594 #endif
595 }
596 
597 static void
598 na_tray_manager_set_visual_property (NaTrayManager *manager)
599 {
600 #ifdef GDK_WINDOWING_X11
601   GdkWindow  *window;
602   GdkDisplay *display;
603   Visual     *xvisual;
604   Atom        visual_atom;
605   gulong      data[1];
606 
607   g_return_if_fail (manager->invisible != NULL);
608   window = gtk_widget_get_window (manager->invisible);
609   g_return_if_fail (window != NULL);
610 
611   /* The visual property is a hint to the tray icons as to what visual they
612    * should use for their windows. If the X server has RGBA colormaps, then
613    * we tell the tray icons to use a RGBA colormap and we'll composite the
614    * icon onto its parents with real transparency. Otherwise, we just tell
615    * the icon to use our colormap, and we'll do some hacks with parent
616    * relative backgrounds to simulate transparency.
617    */
618 
619   display = gtk_widget_get_display (manager->invisible);
620   visual_atom = gdk_x11_get_xatom_by_name_for_display (display,
621 						       "_NET_SYSTEM_TRAY_VISUAL");
622 
623   if (gdk_screen_get_rgba_visual (manager->screen) != NULL &&
624       gdk_display_supports_composite (display))
625     xvisual = GDK_VISUAL_XVISUAL (gdk_screen_get_rgba_visual (manager->screen));
626   else
627     {
628       /* We actually want the visual of the tray where the icons will
629        * be embedded. In almost all cases, this will be the same as the visual
630        * of the screen.
631        */
632       xvisual = GDK_VISUAL_XVISUAL (gdk_screen_get_system_visual (manager->screen));
633     }
634 
635   data[0] = XVisualIDFromVisual (xvisual);
636 
637   XChangeProperty (GDK_DISPLAY_XDISPLAY (display),
638                    GDK_WINDOW_XID (window),
639                    visual_atom,
640                    XA_VISUALID, 32,
641                    PropModeReplace,
642                    (guchar *) &data, 1);
643 #endif
644 }
645 
646 static void
647 na_tray_manager_set_colors_property (NaTrayManager *manager)
648 {
649 #ifdef GDK_WINDOWING_X11
650   GdkWindow  *window;
651   GdkDisplay *display;
652   Atom        atom;
653   gulong      data[12];
654 
655   g_return_if_fail (manager->invisible != NULL);
656   window = gtk_widget_get_window (manager->invisible);
657   g_return_if_fail (window != NULL);
658 
659   display = gtk_widget_get_display (manager->invisible);
660   atom = gdk_x11_get_xatom_by_name_for_display (display,
661                                                 "_NET_SYSTEM_TRAY_COLORS");
662 
663   data[0] = manager->fg.red;
664   data[1] = manager->fg.green;
665   data[2] = manager->fg.blue;
666   data[3] = manager->error.red;
667   data[4] = manager->error.green;
668   data[5] = manager->error.blue;
669   data[6] = manager->warning.red;
670   data[7] = manager->warning.green;
671   data[8] = manager->warning.blue;
672   data[9] = manager->success.red;
673   data[10] = manager->success.green;
674   data[11] = manager->success.blue;
675 
676   XChangeProperty (GDK_DISPLAY_XDISPLAY (display),
677                    GDK_WINDOW_XID (window),
678                    atom,
679                    XA_CARDINAL, 32,
680                    PropModeReplace,
681                    (guchar *) &data, 12);
682 #endif
683 }
684 
685 #ifdef GDK_WINDOWING_X11
686 
687 static gboolean
688 na_tray_manager_manage_screen_x11 (NaTrayManager *manager,
689 				   GdkScreen     *screen)
690 {
691   GdkDisplay *display;
692   Screen     *xscreen;
693   GtkWidget  *invisible;
694   GdkWindow  *window;
695   char       *selection_atom_name;
696   guint32     timestamp;
697   
698   g_return_val_if_fail (NA_IS_TRAY_MANAGER (manager), FALSE);
699   g_return_val_if_fail (manager->screen == NULL, FALSE);
700 
701   /* If there's already a manager running on the screen
702    * we can't create another one.
703    */
704 #if 0
705   if (na_tray_manager_check_running_screen_x11 (screen))
706     return FALSE;
707 #endif
708   
709   manager->screen = screen;
710 
711   display = gdk_screen_get_display (screen);
712   xscreen = GDK_SCREEN_XSCREEN (screen);
713   
714   invisible = gtk_invisible_new_for_screen (screen);
715   gtk_widget_realize (invisible);
716   
717   gtk_widget_add_events (invisible,
718                          GDK_PROPERTY_CHANGE_MASK | GDK_STRUCTURE_MASK);
719 
720   selection_atom_name = g_strdup_printf ("_NET_SYSTEM_TRAY_S%d",
721 					 gdk_screen_get_number (screen));
722   manager->selection_atom = gdk_atom_intern (selection_atom_name, FALSE);
723   g_free (selection_atom_name);
724 
725   manager->invisible = invisible;
726   g_object_ref (G_OBJECT (manager->invisible));
727 
728   na_tray_manager_set_orientation_property (manager);
729   na_tray_manager_set_visual_property (manager);
730   na_tray_manager_set_colors_property (manager);
731   
732   window = gtk_widget_get_window (invisible);
733 
734   timestamp = gdk_x11_get_server_time (window);
735 
736   /* Check if we could set the selection owner successfully */
737   if (gdk_selection_owner_set_for_display (display,
738                                            window,
739                                            manager->selection_atom,
740                                            timestamp,
741                                            TRUE))
742     {
743       XClientMessageEvent xev;
744       GdkAtom             opcode_atom;
745       GdkAtom             message_data_atom;
746 
747       xev.type = ClientMessage;
748       xev.window = RootWindowOfScreen (xscreen);
749       xev.message_type = gdk_x11_get_xatom_by_name_for_display (display,
750                                                                 "MANAGER");
751 
752       xev.format = 32;
753       xev.data.l[0] = timestamp;
754       xev.data.l[1] = gdk_x11_atom_to_xatom_for_display (display,
755                                                          manager->selection_atom);
756       xev.data.l[2] = GDK_WINDOW_XID (window);
757       xev.data.l[3] = 0;	/* manager specific data */
758       xev.data.l[4] = 0;	/* manager specific data */
759 
760       XSendEvent (GDK_DISPLAY_XDISPLAY (display),
761 		  RootWindowOfScreen (xscreen),
762 		  False, StructureNotifyMask, (XEvent *)&xev);
763 
764       opcode_atom = gdk_atom_intern ("_NET_SYSTEM_TRAY_OPCODE", FALSE);
765       manager->opcode_atom = gdk_x11_atom_to_xatom_for_display (display,
766                                                                 opcode_atom);
767 
768       message_data_atom = gdk_atom_intern ("_NET_SYSTEM_TRAY_MESSAGE_DATA",
769                                            FALSE);
770       manager->message_data_atom = gdk_x11_atom_to_xatom_for_display (display,
771                                                                       message_data_atom);
772 
773       /* Add a window filter */
774 #if 0
775       /* This is for when we lose the selection of _NET_SYSTEM_TRAY_Sx */
776       g_signal_connect (invisible, "selection-clear-event",
777                         G_CALLBACK (na_tray_manager_selection_clear_event),
778                         manager);
779 #endif
780       gdk_window_add_filter (window,
781                              na_tray_manager_window_filter, manager);
782       return TRUE;
783     }
784   else
785     {
786       gtk_widget_destroy (invisible);
787       g_object_unref (invisible);
788       manager->invisible = NULL;
789 
790       manager->screen = NULL;
791  
792       return FALSE;
793     }
794 }
795 
796 #endif
797 
798 gboolean
799 na_tray_manager_manage_screen (NaTrayManager *manager,
800 			       GdkScreen     *screen)
801 {
802   g_return_val_if_fail (GDK_IS_SCREEN (screen), FALSE);
803   g_return_val_if_fail (manager->screen == NULL, FALSE);
804 
805 #ifdef GDK_WINDOWING_X11
806   return na_tray_manager_manage_screen_x11 (manager, screen);
807 #else
808   return FALSE;
809 #endif
810 }
811 
812 #ifdef GDK_WINDOWING_X11
813 
814 static gboolean
815 na_tray_manager_check_running_screen_x11 (GdkScreen *screen)
816 {
817   GdkDisplay *display;
818   Atom        selection_atom;
819   char       *selection_atom_name;
820 
821   display = gdk_screen_get_display (screen);
822   selection_atom_name = g_strdup_printf ("_NET_SYSTEM_TRAY_S%d",
823                                          gdk_screen_get_number (screen));
824   selection_atom = gdk_x11_get_xatom_by_name_for_display (display,
825                                                           selection_atom_name);
826   g_free (selection_atom_name);
827 
828   if (XGetSelectionOwner (GDK_DISPLAY_XDISPLAY (display),
829                           selection_atom) != None)
830     return TRUE;
831   else
832     return FALSE;
833 }
834 
835 #endif
836 
837 gboolean
838 na_tray_manager_check_running (GdkScreen *screen)
839 {
840   g_return_val_if_fail (GDK_IS_SCREEN (screen), FALSE);
841 
842 #ifdef GDK_WINDOWING_X11
843   return na_tray_manager_check_running_screen_x11 (screen);
844 #else
845   return FALSE;
846 #endif
847 }
848 
849 void
850 na_tray_manager_set_orientation (NaTrayManager  *manager,
851 				 GtkOrientation  orientation)
852 {
853   g_return_if_fail (NA_IS_TRAY_MANAGER (manager));
854 
855   if (manager->orientation != orientation)
856     {
857       manager->orientation = orientation;
858 
859       na_tray_manager_set_orientation_property (manager);
860 
861       g_object_notify (G_OBJECT (manager), "orientation");
862     }
863 }
864 
865 void
866 na_tray_manager_set_colors (NaTrayManager *manager,
867                             GdkColor      *fg,
868                             GdkColor      *error,
869                             GdkColor      *warning,
870                             GdkColor      *success)
871 {
872   g_return_if_fail (NA_IS_TRAY_MANAGER (manager));
873 
874   if (!gdk_color_equal (&manager->fg, fg) ||
875       !gdk_color_equal (&manager->error, error) ||
876       !gdk_color_equal (&manager->warning, warning) ||
877       !gdk_color_equal (&manager->success, success))
878     {
879       manager->fg = *fg;
880       manager->error = *error;
881       manager->warning = *warning;
882       manager->success = *success;
883 
884       na_tray_manager_set_colors_property (manager);
885     }
886 }
887 
888 GtkOrientation
889 na_tray_manager_get_orientation (NaTrayManager *manager)
890 {
891   g_return_val_if_fail (NA_IS_TRAY_MANAGER (manager), GTK_ORIENTATION_HORIZONTAL);
892 
893   return manager->orientation;
894 }