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