]> Dogcows Code - chaz/tint2/blob - src/systray/systraybar.c
cleanup code
[chaz/tint2] / src / systray / systraybar.c
1 /**************************************************************************
2 * Tint2 : systraybar
3 *
4 * Copyright (C) 2009 thierry lorthiois (lorthiois@bbsoft.fr)
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License version 2
8 * as published by the Free Software Foundation.
9 *
10 * This program 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
13 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 **************************************************************************/
18
19 #include <X11/Xlib.h>
20 #include <X11/Xutil.h>
21 #include <X11/Xatom.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <glib.h>
26 #include <Imlib2.h>
27
28 #include "systraybar.h"
29 #include "server.h"
30 #include "panel.h"
31
32 GSList *icons;
33
34 /* defined in the systray spec */
35 #define SYSTEM_TRAY_REQUEST_DOCK 0
36 #define SYSTEM_TRAY_BEGIN_MESSAGE 1
37 #define SYSTEM_TRAY_CANCEL_MESSAGE 2
38
39 Window net_sel_win = None;
40
41
42 void init_systray()
43 {
44 Panel *panel;
45 Systraybar *sysbar;
46 int i, run_systray;
47
48 cleanup_systray();
49
50 run_systray = 0;
51 for (i=0 ; i < nb_panel ; i++) {
52 if (panel1[i].systray.area.visible) {
53 run_systray = 1;
54 break;
55 }
56 }
57 if (run_systray) {
58 if (XGetSelectionOwner(server.dsp, server.atom._NET_SYSTEM_TRAY_SCREEN) != None) {
59 fprintf(stderr, "tint2 warning : another systray is running\n");
60 run_systray = 0;
61 }
62 }
63
64 if (run_systray)
65 run_systray = net_init();
66
67 for (i=0 ; i < nb_panel ; i++) {
68 panel = &panel1[i];
69 sysbar = &panel->systray;
70
71 if (!run_systray) {
72 sysbar->area.visible = 0;
73 continue;
74 }
75 if (!sysbar->area.visible)
76 continue;
77
78 sysbar->area.parent = panel;
79 sysbar->area.panel = panel;
80
81 sysbar->area.posy = panel->area.pix.border.width + panel->area.paddingy;
82 sysbar->area.height = panel->area.height - (2 * sysbar->area.posy);
83 sysbar->area.width = 100;
84
85 sysbar->area.posx = panel->area.width - panel->area.paddingxlr - panel->area.pix.border.width - sysbar->area.width;
86 if (panel->clock.area.visible)
87 sysbar->area.posx -= (panel->clock.area.width + panel->area.paddingx);
88
89 sysbar->area.redraw = 1;
90 }
91 }
92
93
94 void cleanup_systray()
95 {
96 Panel *panel;
97 int i;
98
99 for (i=0 ; i < nb_panel ; i++) {
100 panel = &panel1[i];
101 if (!panel->systray.area.visible) continue;
102
103 free_area(&panel->systray.area);
104 }
105
106 if (net_sel_win != None) {
107 XDestroyWindow(server.dsp, net_sel_win);
108 net_sel_win = None;
109 }
110 }
111
112
113 int resize_systray (Systraybar *sysbar)
114 {
115 return 0;
116 }
117
118
119
120 Window win, root;
121 int width, height;
122 int border;
123 int icon_size;
124
125
126 void fix_geometry()
127 {
128 GSList *it;
129
130 //* find the proper width and height
131 width = 0;
132 height = icon_size;
133 for (it = icons; it != NULL; it = g_slist_next(it)) {
134 width += icon_size;
135 }
136
137 XResizeWindow(server.dsp, win, width + border * 2, height + border * 2);
138 }
139
140
141 gboolean error;
142 int window_error_handler(Display *d, XErrorEvent *e)
143 {
144 d=d;e=e;
145 if (e->error_code == BadWindow) {
146 error = TRUE;
147 } else {
148 //g_printerr("X ERROR NOT BAD WINDOW!\n");
149 abort();
150 }
151 return 0;
152 }
153
154
155 gboolean icon_swallow(TrayWindow *traywin)
156 {
157 XErrorHandler old;
158
159 error = FALSE;
160 old = XSetErrorHandler(window_error_handler);
161 XReparentWindow(server.dsp, traywin->id, win, 0, 0);
162 XSync(server.dsp, False);
163 XSetErrorHandler(old);
164
165 return !error;
166 }
167
168
169 // The traywin must have its id and type set.
170 gboolean icon_add(Window id)
171 {
172 TrayWindow *traywin;
173
174 traywin = g_new0(TrayWindow, 1);
175 traywin->id = id;
176
177 if (!icon_swallow(traywin)) {
178 g_free(traywin);
179 return FALSE;
180 }
181
182 // find the positon for the systray app window
183 int count = g_slist_length(icons);
184 traywin->x = border + ((width % icon_size) / 2) +
185 (count % (width / icon_size)) * icon_size;
186 traywin->y = border + ((height % icon_size) / 2) +
187 (count / (height / icon_size)) * icon_size;
188
189 // add the new icon to the list
190 icons = g_slist_append(icons, traywin);
191
192 // watch for the icon trying to resize itself!
193 XSelectInput(server.dsp, traywin->id, StructureNotifyMask);
194
195 // position and size the icon window
196 XMoveResizeWindow(server.dsp, traywin->id, traywin->x, traywin->y, icon_size, icon_size);
197
198 // resize our window so that the new window can fit in it
199 fix_geometry();
200
201 // flush before clearing, otherwise the clear isn't effective.
202 XFlush(server.dsp);
203 // make sure the new child will get the right stuff in its background
204 // for ParentRelative.
205 XClearWindow(server.dsp, win);
206
207 // show the window
208 XMapRaised(server.dsp, traywin->id);
209
210 return TRUE;
211 }
212
213
214 int net_init()
215 {
216 // init systray protocol
217 net_sel_win = XCreateSimpleWindow(server.dsp, server.root_win, -1, -1, 1, 1, 0, 0, 0);
218
219 XSetSelectionOwner(server.dsp, server.atom._NET_SYSTEM_TRAY_SCREEN, net_sel_win, CurrentTime);
220 if (XGetSelectionOwner(server.dsp, server.atom._NET_SYSTEM_TRAY_SCREEN) != net_sel_win) {
221 fprintf(stderr, "tint2 warning : can't get systray manager\n");
222 return 0;
223 }
224
225 XEvent m;
226 m.type = ClientMessage;
227 m.xclient.message_type = server.atom.MANAGER;
228 m.xclient.format = 32;
229 m.xclient.data.l[0] = CurrentTime;
230 m.xclient.data.l[1] = server.atom._NET_SYSTEM_TRAY_SCREEN;
231 m.xclient.data.l[2] = net_sel_win;
232 m.xclient.data.l[3] = 0;
233 m.xclient.data.l[4] = 0;
234 XSendEvent(server.dsp, server.root_win, False, StructureNotifyMask, &m);
235 return 1;
236 }
237
238
239 void net_message(XClientMessageEvent *e)
240 {
241 unsigned long opcode;
242 Window id;
243
244 opcode = e->data.l[1];
245
246 switch (opcode)
247 {
248 case SYSTEM_TRAY_REQUEST_DOCK: /* dock a new icon */
249 id = e->data.l[2];
250 if (id && icon_add(id))
251 XSelectInput(server.dsp, id, StructureNotifyMask);
252 break;
253
254 case SYSTEM_TRAY_BEGIN_MESSAGE:
255 //g_printerr("Message From Dockapp\n");
256 id = e->window;
257 break;
258
259 case SYSTEM_TRAY_CANCEL_MESSAGE:
260 //g_printerr("Message Cancelled\n");
261 id = e->window;
262 break;
263
264 default:
265 if (opcode == server.atom._NET_SYSTEM_TRAY_MESSAGE_DATA) {
266 //g_printerr("Text For Message From Dockapp:\n%s\n", e->data.b);
267 id = e->window;
268 break;
269 }
270
271 /* unknown message type. not in the spec. */
272 //g_printerr("Warning: Received unknown client message to System Tray selection window.\n");
273 break;
274 }
275 }
276
277
278 /*
279 void event_loop()
280 {
281 XEvent e;
282 Window cover;
283 GSList *it;
284
285 while (!exit_app) {
286 while (XPending(server.dsp)) {
287 XNextEvent(display, &e);
288
289 switch (e.type)
290 {
291 case PropertyNotify:
292 // systray window list has changed?
293 if (e.xproperty.atom == kde_systray_prop) {
294 XSelectInput(display, win, NoEventMask);
295 kde_update_icons();
296 XSelectInput(display, win, StructureNotifyMask);
297
298 while (XCheckTypedEvent(display, PropertyNotify, &e));
299 }
300
301 break;
302
303 case ConfigureNotify:
304 if (e.xany.window != win) {
305 // find the icon it pertains to and beat it into submission
306 GSList *it;
307
308 for (it = icons; it != NULL; it = g_slist_next(it)) {
309 TrayWindow *traywin = it->data;
310 if (traywin->id == e.xany.window) {
311 XMoveResizeWindow(display, traywin->id, traywin->x, traywin->y,
312 icon_size, icon_size);
313 break;
314 }
315 }
316 break;
317 }
318
319 // briefly cover the entire containing window, which causes it and
320 // all of the icons to refresh their windows. finally, they update
321 // themselves when the background of the main window's parent changes.
322
323 cover = XCreateSimpleWindow(display, win, 0, 0,
324 border * 2 + width, border * 2 + height,
325 0, 0, 0);
326 XMapWindow(display, cover);
327 XDestroyWindow(display, cover);
328
329 break;
330
331 case ReparentNotify:
332 if (e.xany.window == win) // reparented to us
333 break;
334 case UnmapNotify:
335 case DestroyNotify:
336 for (it = icons; it; it = g_slist_next(it)) {
337 if (((TrayWindow*)it->data)->id == e.xany.window) {
338 icon_remove(it);
339 break;
340 }
341 }
342 break;
343
344 case ClientMessage:
345 if (e.xclient.message_type == net_opcode_atom &&
346 e.xclient.format == 32 &&
347 e.xclient.window == net_sel_win)
348 net_message(&e.xclient);
349
350 default:
351 break;
352 }
353 }
354 usleep(500000);
355 }
356
357 // remove/unparent all the icons
358 while (icons) {
359 // do the remove here explicitly, cuz the event handler isn't going to
360 // happen anymore.
361 icon_remove(icons);
362 }
363 }
364 */
365
This page took 0.056024 seconds and 5 git commands to generate.