2 * Conky, a system monitor, based on torsmo
4 * This program is licensed under BSD license, read COPYING
14 #include <X11/Xatom.h>
16 #include <X11/Xutil.h>
18 #include <X11/Xft/Xft.h>
29 /* some basic X11 stuff */
34 static int set_transparent;
35 static int background_colour;
37 /* workarea from _NET_WORKAREA, this is where window / text is aligned */
41 struct conky_window window;
43 /* local prototypes */
44 static void update_workarea();
45 static Window find_desktop_window(Window *p_root, Window *p_desktop);
46 static Window find_subwindow(Window win, int w, int h);
51 if ((display = XOpenDisplay(0)) == NULL)
52 CRIT_ERR("can't open display: %s", XDisplayName(0));
54 screen = DefaultScreen(display);
55 display_width = DisplayWidth(display, screen);
56 display_height = DisplayHeight(display, screen);
61 static void update_workarea()
63 Window root = RootWindow(display, screen);
64 unsigned long nitems, bytes;
65 unsigned char *buf = NULL;
69 /* default work area is display */
72 workarea[2] = display_width;
73 workarea[3] = display_height;
75 /* get current desktop */
76 if (XGetWindowProperty(display, root, ATOM(_NET_CURRENT_DESKTOP),
77 0, 1, False, XA_CARDINAL, &type, &format,
78 &nitems, &bytes, &buf) == Success
79 && type == XA_CARDINAL && nitems > 0) {
82 /* long desktop = * (long *) buf; */
95 /* Find root window and desktop window. Return desktop window on success,
96 * and set root and desktop byref return values. Return 0 on failure. */
97 static Window find_desktop_window(Window *p_root, Window *p_desktop)
101 unsigned long nitems, bytes;
103 Window root = RootWindow(display, screen);
105 Window troot, parent, *children;
106 unsigned char *buf = NULL;
108 if (!p_root || !p_desktop)
111 /* some window managers set __SWM_VROOT to some child of root window */
113 XQueryTree(display, root, &troot, &parent, &children, &n);
114 for (i = 0; i < (int) n; i++) {
115 if (XGetWindowProperty
116 (display, children[i], ATOM(__SWM_VROOT), 0, 1, False,
117 XA_WINDOW, &type, &format, &nitems, &bytes,
118 &buf) == Success && type == XA_WINDOW) {
119 win = *(Window *) buf;
123 "Conky: desktop window (%lx) found from __SWM_VROOT property\n", win);
137 /* get subwindows from root */
138 win = find_subwindow(root, -1, -1);
142 win = find_subwindow(win, workarea[2], workarea[3]);
151 "Conky: desktop window (%lx) is subwindow of root window (%lx)\n",win,root);
153 fprintf(stderr, "Conky: desktop window (%lx) is root window\n",win);
163 /* sets background to ParentRelative for the Window and all parents */
164 inline void set_transparent_background(Window win)
166 static int colour_set = -1;
167 if (set_transparent) {
170 for (i = 0; i < 50 && parent != RootWindow(display, screen); i++) {
174 XSetWindowBackgroundPixmap(display, parent, ParentRelative);
176 XQueryTree(display, parent, &r, &parent, &children, &n);
179 } else if (colour_set != background_colour) {
180 XSetWindowBackground(display, win, background_colour);
181 colour_set = background_colour;
183 //XClearWindow(display, win); not sure why this was here
186 void init_window(int own_window, int w, int h, int set_trans, int back_colour,
187 char **argv, int argc)
189 /* There seems to be some problems with setting transparent background (on
190 * fluxbox this time). It doesn't happen always and I don't know why it
191 * happens but I bet the bug is somewhere here. */
192 set_transparent = set_trans;
193 background_colour = back_colour;
198 if ( !find_desktop_window( &window.root, &window.desktop ) )
201 if (window.type == TYPE_OVERRIDE) {
204 An override_redirect True window. No WM hints or button processing needed.
206 XSetWindowAttributes attrs = {
207 ParentRelative,0L,0,0L,0,0,Always,0L,0L,False,
208 StructureNotifyMask|ExposureMask,
213 /* Parent is desktop window (which might be a child of root) */
214 window.window = XCreateWindow(display,
216 window.x, window.y, w, h, 0,
220 CWBackPixel|CWOverrideRedirect,
223 XLowerWindow(display, window.window);
225 fprintf(stderr, "Conky: window type - override\n"); fflush(stderr);
229 else { /* window.type != TYPE_OVERRIDE */
232 A window managed by the window manager. Process hints and buttons.
234 XSetWindowAttributes attrs = {
235 ParentRelative,0L,0,0L,0,0,Always,0L,0L,False,
236 StructureNotifyMask|ExposureMask|ButtonPressMask|ButtonReleaseMask,
241 XClassHint classHint;
245 /* Parent is root window so WM can take control */
246 window.window = XCreateWindow(display,
248 window.x, window.y, w, h, 0,
252 CWBackPixel|CWOverrideRedirect,
255 classHint.res_name = window.class_name;
256 classHint.res_class = classHint.res_name;
258 wmHint.flags = InputHint | StateHint;
259 /* allow decorated windows to be given input focus by WM */
260 wmHint.input = TEST_HINT(window.hints,HINT_UNDECORATED) ? False : True;
261 wmHint.initial_state = NormalState;
263 XmbSetWMProperties (display, window.window, window.title, NULL,
265 NULL, &wmHint, &classHint);
267 /* Sets an empty WM_PROTOCOLS property */
268 XSetWMProtocols(display,window.window,NULL,0);
271 /* Set window type */
272 if ( (xa = ATOM(_NET_WM_WINDOW_TYPE)) != None )
275 switch(window.type) {
278 prop = ATOM(_NET_WM_WINDOW_TYPE_DESKTOP);
279 fprintf(stderr, "Conky: window type - desktop\n"); fflush(stderr);
285 prop = ATOM(_NET_WM_WINDOW_TYPE_NORMAL);
286 fprintf(stderr, "Conky: window type - normal\n"); fflush(stderr);
290 XChangeProperty(display, window.window, xa,
293 (unsigned char *) &prop, 1);
296 /* Set desired hints */
298 /* Window decorations */
299 if (TEST_HINT(window.hints,HINT_UNDECORATED)) {
300 /*fprintf(stderr, "Conky: hint - undecorated\n"); fflush(stderr);*/
302 xa = ATOM(_MOTIF_WM_HINTS);
304 long prop[5] = { 2, 0, 0, 0, 0 };
305 XChangeProperty(display, window.window, xa,
306 xa, 32, PropModeReplace,
307 (unsigned char *) prop, 5);
311 /* Below other windows */
312 if (TEST_HINT(window.hints,HINT_BELOW)) {
313 /*fprintf(stderr, "Conky: hint - below\n"); fflush(stderr); */
315 xa = ATOM(_WIN_LAYER);
318 XChangeProperty(display, window.window, xa,
321 (unsigned char *) &prop, 1);
324 xa = ATOM(_NET_WM_STATE);
326 Atom xa_prop = ATOM(_NET_WM_STATE_BELOW);
327 XChangeProperty(display, window.window, xa,
330 (unsigned char *) &xa_prop,
335 /* Above other windows */
336 if (TEST_HINT(window.hints,HINT_ABOVE)) {
337 /*fprintf(stderr, "Conky: hint - above\n"); fflush(stderr);*/
339 xa = ATOM(_WIN_LAYER);
342 XChangeProperty(display, window.window, xa,
345 (unsigned char *) &prop, 1);
348 xa = ATOM(_NET_WM_STATE);
350 Atom xa_prop = ATOM(_NET_WM_STATE_ABOVE);
351 XChangeProperty(display, window.window, xa,
354 (unsigned char *) &xa_prop,
360 if (TEST_HINT(window.hints,HINT_STICKY)) {
361 /*fprintf(stderr, "Conky: hint - sticky\n"); fflush(stderr); */
363 xa = ATOM(_NET_WM_DESKTOP);
365 CARD32 xa_prop = 0xFFFFFFFF;
366 XChangeProperty(display, window.window, xa,
369 (unsigned char *) &xa_prop,
373 xa = ATOM(_NET_WM_STATE);
375 Atom xa_prop = ATOM(_NET_WM_STATE_STICKY);
376 XChangeProperty(display, window.window, xa,
379 (unsigned char *) &xa_prop,
385 if (TEST_HINT(window.hints,HINT_SKIP_TASKBAR)) {
386 /*fprintf(stderr, "Conky: hint - skip_taskbar\n"); fflush(stderr);*/
388 xa = ATOM(_NET_WM_STATE);
390 Atom xa_prop = ATOM(_NET_WM_STATE_SKIP_TASKBAR);
391 XChangeProperty(display, window.window, xa,
394 (unsigned char *) &xa_prop,
400 if (TEST_HINT(window.hints,HINT_SKIP_PAGER)) {
401 /*fprintf(stderr, "Conky: hint - skip_pager\n"); fflush(stderr);*/
403 xa = ATOM(_NET_WM_STATE);
405 Atom xa_prop = ATOM(_NET_WM_STATE_SKIP_PAGER);
406 XChangeProperty(display, window.window, xa,
409 (unsigned char *) &xa_prop,
414 } /* else { window.type != TYPE_OVERRIDE */
416 fprintf(stderr, "Conky: drawing to created window (%lx)\n", window.window);
419 XMapWindow(display, window.window);
421 } else /* if (own_window) { */
423 /* root / desktop window */
425 XWindowAttributes attrs;
428 window.window = find_desktop_window( &window.root, &window.desktop );
430 if (XGetWindowAttributes(display, window.window, &attrs)) {
431 window.width = attrs.width;
432 window.height = attrs.height;
435 fprintf(stderr, "Conky: drawing to desktop window\n");
438 /* Drawable is same as window. This may be changed by double buffering. */
439 window.drawable = window.window;
444 if (!XdbeQueryExtension(display, &major, &minor)) {
448 XdbeAllocateBackBufferName(display,
451 if (window.back_buffer != None) {
452 window.drawable = window.back_buffer;
454 "Conky: drawing to double buffer\n");
459 ERR("failed to set up double buffer");
462 fprintf(stderr, "Conky: drawing to single buffer\n");
467 /*set_transparent_background(window.window); must be done after double buffer stuff? */
470 set_transparent_background(window.window);
471 XClearWindow(display, window.window);
475 XSelectInput(display, window.window, ExposureMask
478 ? (StructureNotifyMask | PropertyChangeMask |
479 ButtonPressMask | ButtonReleaseMask) : 0)
484 static Window find_subwindow(Window win, int w, int h)
487 Window troot, parent, *children;
490 /* search subwindows with same size as display or work area */
492 for (i = 0; i < 10; i++) {
493 XQueryTree(display, win, &troot, &parent, &children, &n);
495 for (j = 0; j < n; j++) {
496 XWindowAttributes attrs;
498 if (XGetWindowAttributes
499 (display, children[j], &attrs)) {
500 /* Window must be mapped and same size as display or work space */
501 if (attrs.map_state != 0 &&
502 ((attrs.width == display_width
503 && attrs.height == display_height)
505 && attrs.height == h))) {
520 long get_x11_color(const char *name)
525 (display, DefaultColormap(display, screen), name, &color)) {
526 /* lets check if it's a hex colour with the # missing in front
527 * if yes, then do something about it
531 strncpy(&newname[1], name, 62);
532 /* now lets try again */
533 if (!XParseColor(display, DefaultColormap(display, screen), &newname[0], &color)) {
534 ERR("can't parse X color '%s'", name);
539 (display, DefaultColormap(display, screen), &color))
540 ERR("can't allocate X color '%s'", name);
542 return (long) color.pixel;
548 values.graphics_exposures = 0;
549 values.function = GXcopy;
550 window.gc = XCreateGC(display, window.drawable,
551 GCFunction | GCGraphicsExposures, &values);