No issues found
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 |
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 }