]> icculus.org git repositories - dana/openbox.git/blob - tools/kdetrayproxy/kdetrayproxy.c
missing sys/time.h
[dana/openbox.git] / tools / kdetrayproxy / kdetrayproxy.c
1 #include <X11/Xlib.h>
2 #include <X11/Xatom.h>
3 #include <stdio.h>
4 #include <stdlib.h>
5 #include <string.h>
6 #include <sys/select.h>
7 #include <unistd.h>
8 #include <sys/time.h>
9
10 typedef struct IList {
11     Window win;
12     int ignore_unmaps;
13
14     struct IList *next;
15 } IList;
16
17 Display *display;
18 Window root;
19 Atom winhint;
20 Atom roothint;
21 int xfd;
22 IList *list;
23
24 void init();
25 void eventloop();
26 void handleevent(XEvent *e);
27 void addicon(Window win);
28 void removeicon(Window win, int unmap);
29 int issystray(Atom *a, int n);
30 void updatehint();
31 Window findclient(Window win);
32 int ignore_errors(Display *d, XErrorEvent *e);
33 void wait_time(unsigned int t);
34
35 int main()
36 {
37     init();
38     updatehint();
39     eventloop();
40     return 0;
41 }
42
43 void init()
44 {
45     display = XOpenDisplay(NULL);
46     if (!display) {
47         fprintf(stderr, "Could not open display\n");
48         exit(EXIT_FAILURE);
49     }
50
51     xfd = ConnectionNumber(display);
52
53     root = RootWindowOfScreen(DefaultScreenOfDisplay(display));
54
55     winhint = XInternAtom(display, "_KDE_NET_WM_SYSTEM_TRAY_WINDOW_FOR", 0);
56     roothint = XInternAtom(display, "_KDE_NET_SYSTEM_TRAY_WINDOWS", 0);
57
58     XSelectInput(display, root, SubstructureNotifyMask);
59 }
60
61 void eventloop()
62 {
63     XEvent e;
64     fd_set set;
65
66     while (1) {
67         int event = False;
68         while (XPending(display)) {
69             event = True;
70             XNextEvent(display, &e);
71             handleevent(&e);
72         }
73         if (!event) {
74             FD_ZERO(&set);
75             FD_SET(xfd, &set);
76             select(xfd + 1, &set, NULL, NULL, NULL);
77         }
78     }
79 }
80
81 void handleevent(XEvent *e)
82 {
83     switch (e->type) {
84     case MapNotify:
85     {
86         Atom *a;
87         int n;
88         Window w;
89
90         w = findclient(e->xmap.window);
91         if (w) {
92             a = XListProperties(display, w, &n);
93             if (issystray(a, n))
94                 addicon(w);
95             XFree(a);
96         }
97         break;
98     }
99     case UnmapNotify:
100         removeicon(e->xunmap.window, True);
101         break;
102     case DestroyNotify:
103         removeicon(e->xdestroywindow.window, False);
104         break;
105     }
106 }
107
108 int ignore_errors(Display *d, XErrorEvent *e)
109 {
110     (void)d; (void)e;
111     return 1;
112 }
113
114 void addicon(Window win)
115 {
116     IList *it;
117
118     for (it = list; it; it = it->next)
119         if (it->win == win) return; /* duplicate */
120
121     it = list;
122     list = malloc(sizeof(IList));
123     list->win = win;
124     list->ignore_unmaps = 2;
125     list->next = it;
126
127     XSelectInput(display, win, StructureNotifyMask);
128     /* if i set the root hint too fast the dock app can fuck itself up */
129     wait_time(1000000 / 8);
130     updatehint();
131 }
132
133 void removeicon(Window win, int unmap)
134 {
135     IList *it, *last = NULL;
136     void *old;
137
138     for (it = list; it; last = it, it = it->next)
139         if (it->win == win) {
140             if (it->ignore_unmaps && unmap) {
141                 it->ignore_unmaps--;
142                 return;
143             }
144
145             if (!last)
146                 list = it->next;
147             else
148                 last->next = it->next;
149
150             XSync(display, False);
151             old = XSetErrorHandler(ignore_errors);
152             XSelectInput(display, win, NoEventMask);
153             XSync(display, False);
154             XSetErrorHandler(old);
155             free(it);
156
157             updatehint();
158         }
159 }
160
161 int issystray(Atom *a, int n)
162 {
163     int i, r = False;
164
165     for (i = 0; i < n; ++i) { 
166         if (a[i] == winhint) {
167             r = True;
168             break;
169         }
170     }
171     return r;
172 }
173
174 void updatehint()
175 {
176     IList *it;
177     int *wins, n, i;
178
179     for (it = list, n = 0; it; it = it->next, ++n) ;
180     if (n) {
181         wins = malloc(sizeof(int) * n);
182         for (it = list, i = 0; it; it = it->next, ++i)
183             wins[i] = it->win;
184     } else
185         wins = NULL;
186     XChangeProperty(display, root, roothint, XA_WINDOW, 32, PropModeReplace,
187                     (unsigned char*) wins, n);
188 }
189
190 Window findclient(Window win)
191 {
192   Window r, *children;
193   unsigned int n, i;
194   Atom state = XInternAtom(display, "WM_STATE", True);
195   Atom ret_type;
196   int ret_format;
197   unsigned long ret_items, ret_bytesleft;
198   unsigned long *prop_return;
199
200   XQueryTree(display, win, &r, &r, &children, &n);
201   for (i = 0; i < n; ++i) {
202     Window w = findclient(children[i]);
203     if (w) return w;
204   }
205
206   /* try me */
207   XGetWindowProperty(display, win, state, 0, 1,
208                      False, state, &ret_type, &ret_format,
209                      &ret_items, &ret_bytesleft,
210                      (unsigned char**) &prop_return); 
211   if (ret_type == None || ret_items < 1)
212     return None;
213   return win; /* found it! */
214 }
215
216 void wait_time(unsigned int t)
217 {
218     struct timeval time;
219     time.tv_sec = 0;
220     time.tv_usec = t;
221     select(1, NULL, NULL, NULL, &time);
222 }