]> Dogcows Code - chaz/openbox/blob - tools/kdetrayproxy/kdetrayproxy.c
note 5483 in CHANGELOG
[chaz/openbox] / tools / kdetrayproxy / kdetrayproxy.c
1 /* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
2
3 kdetrayproxy.c for the Openbox window manager
4 Copyright (c) 2003 Ben Jansens
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 See the COPYING file for a copy of the GNU General Public License.
17 */
18
19 #include <X11/Xlib.h>
20 #include <X11/Xatom.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <sys/select.h>
25 #include <unistd.h>
26 #include <sys/time.h>
27
28 typedef struct IList {
29 Window win;
30 int ignore_unmaps;
31
32 struct IList *next;
33 } IList;
34
35 Display *display;
36 Window root;
37 Atom winhint;
38 Atom roothint;
39 int xfd;
40 IList *list;
41
42 void init();
43 void eventloop();
44 void handleevent(XEvent *e);
45 void addicon(Window win);
46 void removeicon(Window win, int unmap);
47 int issystray(Atom *a, int n);
48 void updatehint();
49 Window findclient(Window win);
50 int ignore_errors(Display *d, XErrorEvent *e);
51 void wait_time(unsigned int t);
52
53 int main()
54 {
55 init();
56 updatehint();
57 eventloop();
58 return 0;
59 }
60
61 void init()
62 {
63 display = XOpenDisplay(NULL);
64 if (!display) {
65 fprintf(stderr, "Could not open display\n");
66 exit(EXIT_FAILURE);
67 }
68
69 xfd = ConnectionNumber(display);
70
71 root = RootWindowOfScreen(DefaultScreenOfDisplay(display));
72
73 winhint = XInternAtom(display, "_KDE_NET_WM_SYSTEM_TRAY_WINDOW_FOR", 0);
74 roothint = XInternAtom(display, "_KDE_NET_SYSTEM_TRAY_WINDOWS", 0);
75
76 XSelectInput(display, root, SubstructureNotifyMask);
77 }
78
79 void eventloop()
80 {
81 XEvent e;
82 fd_set set;
83
84 while (1) {
85 int event = False;
86 while (XPending(display)) {
87 event = True;
88 XNextEvent(display, &e);
89 handleevent(&e);
90 }
91 if (!event) {
92 FD_ZERO(&set);
93 FD_SET(xfd, &set);
94 select(xfd + 1, &set, NULL, NULL, NULL);
95 }
96 }
97 }
98
99 void handleevent(XEvent *e)
100 {
101 switch (e->type) {
102 case MapNotify:
103 {
104 Atom *a;
105 int n;
106 Window w;
107
108 w = findclient(e->xmap.window);
109 if (w) {
110 a = XListProperties(display, w, &n);
111 if (issystray(a, n))
112 addicon(w);
113 XFree(a);
114 }
115 break;
116 }
117 case UnmapNotify:
118 removeicon(e->xunmap.window, True);
119 break;
120 case DestroyNotify:
121 removeicon(e->xdestroywindow.window, False);
122 break;
123 }
124 }
125
126 int ignore_errors(Display *d, XErrorEvent *e)
127 {
128 (void)d; (void)e;
129 return 1;
130 }
131
132 void addicon(Window win)
133 {
134 IList *it;
135
136 for (it = list; it; it = it->next)
137 if (it->win == win) return; /* duplicate */
138
139 it = list;
140 list = malloc(sizeof(IList));
141 list->win = win;
142 list->ignore_unmaps = 2;
143 list->next = it;
144
145 XSelectInput(display, win, StructureNotifyMask);
146 /* if i set the root hint too fast the dock app can fuck itself up */
147 wait_time(1000000 / 8);
148 updatehint();
149 }
150
151 void removeicon(Window win, int unmap)
152 {
153 IList *it, *last = NULL;
154 int (*old)(Display *, XErrorEvent *);
155
156 for (it = list; it; last = it, it = it->next)
157 if (it->win == win) {
158 if (it->ignore_unmaps && unmap) {
159 it->ignore_unmaps--;
160 return;
161 }
162
163 if (!last)
164 list = it->next;
165 else
166 last->next = it->next;
167
168 XSync(display, False);
169 old = XSetErrorHandler(ignore_errors);
170 XSelectInput(display, win, NoEventMask);
171 XSync(display, False);
172 XSetErrorHandler(old);
173 free(it);
174
175 updatehint();
176 }
177 }
178
179 int issystray(Atom *a, int n)
180 {
181 int i, r = False;
182
183 for (i = 0; i < n; ++i) {
184 if (a[i] == winhint) {
185 r = True;
186 break;
187 }
188 }
189 return r;
190 }
191
192 void updatehint()
193 {
194 IList *it;
195 int *wins, n, i;
196
197 for (it = list, n = 0; it; it = it->next, ++n) ;
198 if (n) {
199 wins = malloc(sizeof(int) * n);
200 for (it = list, i = 0; it; it = it->next, ++i)
201 wins[i] = it->win;
202 } else
203 wins = NULL;
204 XChangeProperty(display, root, roothint, XA_WINDOW, 32, PropModeReplace,
205 (unsigned char*) wins, n);
206 }
207
208 Window findclient(Window win)
209 {
210 Window r, *children;
211 unsigned int n, i;
212 Atom state = XInternAtom(display, "WM_STATE", True);
213 Atom ret_type;
214 int ret_format;
215 unsigned long ret_items, ret_bytesleft;
216 unsigned long *prop_return;
217
218 XQueryTree(display, win, &r, &r, &children, &n);
219 for (i = 0; i < n; ++i) {
220 Window w = findclient(children[i]);
221 if (w) return w;
222 }
223
224 /* try me */
225 XGetWindowProperty(display, win, state, 0, 1,
226 False, state, &ret_type, &ret_format,
227 &ret_items, &ret_bytesleft,
228 (unsigned char**) &prop_return);
229 if (ret_type == None || ret_items < 1)
230 return None;
231 return win; /* found it! */
232 }
233
234 void wait_time(unsigned int t)
235 {
236 struct timeval time;
237 time.tv_sec = 0;
238 time.tv_usec = t;
239 select(1, NULL, NULL, NULL, &time);
240 }
This page took 0.044708 seconds and 4 git commands to generate.