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