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