1 #include "icons.h"
2 #include "net.h"
3 #include <assert.h>
4 #include <stdlib.h>
5 
6 gboolean error;
window_error_handler(Display * d,XErrorEvent * e)7 int window_error_handler(Display *d, XErrorEvent *e)
8 {
9   d=d;e=e;
10   if (e->error_code == BadWindow) {
11     error = TRUE;
12   } else {
13     g_printerr("X ERROR NOT BAD WINDOW!\n");
14     abort();
15   }
16   return 0;
17 }
18 
19 
icon_swallow(TrayWindow * traywin)20 gboolean icon_swallow(TrayWindow *traywin)
21 {
22   XErrorHandler old;
23 
24   error = FALSE;
25   old = XSetErrorHandler(window_error_handler);
26   XReparentWindow(display, traywin->id, win, 0, 0);
27   XSync(display, False);
28   XSetErrorHandler(old);
29 
30   return !error;
31 }
32 
33 
34 /*
35   The traywin must have its id and type set.
36 */
icon_add(Window id,TrayWindowType type)37 gboolean icon_add(Window id, TrayWindowType type)
38 {
39   TrayWindow *traywin;
40 
41   assert(id);
42   assert(type);
43 
44   if (wmaker) {
45     /* do we have room in our window for another icon? */
46     unsigned int max = (width / icon_size) * (height / icon_size);
47     if (g_slist_length(icons) >= max)
48       return FALSE; /* no room, sorry! REJECTED! */
49   }
50 
51   traywin = g_new0(TrayWindow, 1);
52   traywin->type = type;
53   traywin->id = id;
54 
55   if (!icon_swallow(traywin)) {
56     g_free(traywin);
57     return FALSE;
58   }
59 
60   /* find the positon for the systray app window */
61   if (!wmaker) {
62     traywin->x = border + (horizontal ? width : 0);
63     traywin->y = border + (horizontal ? 0 : height);
64   } else {
65     int count = g_slist_length(icons);
66     traywin->x = border + ((width % icon_size) / 2) +
67       (count % (width / icon_size)) * icon_size;
68     traywin->y = border + ((height % icon_size) / 2) +
69       (count / (height / icon_size)) * icon_size;
70   }
71 
72   /* add the new icon to the list */
73   icons = g_slist_append(icons, traywin);
74 
75   /* watch for the icon trying to resize itself! BAD ICON! BAD! */
76   XSelectInput(display, traywin->id, StructureNotifyMask);
77 
78   /* position and size the icon window */
79   XMoveResizeWindow(display, traywin->id,
80                     traywin->x, traywin->y, icon_size, icon_size);
81 
82   /* resize our window so that the new window can fit in it */
83   fix_geometry();
84 
85   /* flush before clearing, otherwise the clear isn't effective. */
86   XFlush(display);
87   /* make sure the new child will get the right stuff in its background
88      for ParentRelative. */
89   XClearWindow(display, win);
90 
91   /* show the window */
92   XMapRaised(display, traywin->id);
93 
94   return TRUE;
95 }
96 
97 
icon_remove(GSList * node)98 void icon_remove(GSList *node)
99 {
100   XErrorHandler old;
101   TrayWindow *traywin = node->data;
102   Window traywin_id = traywin->id;
103 
104   if (traywin->type == NET)
105     net_icon_remove(traywin);
106 
107   XSelectInput(display, traywin->id, NoEventMask);
108 
109   /* remove it from our list */
110   g_free(node->data);
111   icons = g_slist_remove_link(icons, node);
112 
113   /* reparent it to root */
114   error = FALSE;
115   old = XSetErrorHandler(window_error_handler);
116   XReparentWindow(display, traywin_id, root, 0, 0);
117   XSync(display, False);
118   XSetErrorHandler(old);
119 
120   reposition_icons();
121   fix_geometry();
122 }
123