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 #define WINDOW_NAME_FMT "%s - conky"
31 /* some basic X11 stuff */
36 static int set_transparent;
37 static int background_colour;
39 /* workarea from _NET_WORKAREA, this is where window / text is aligned */
43 struct conky_window window;
45 /* local prototypes */
46 static void update_workarea();
47 static Window find_desktop_window(Window *p_root, Window *p_desktop);
48 static Window find_subwindow(Window win, int w, int h);
53 if ((display = XOpenDisplay(0)) == NULL)
54 CRIT_ERR("can't open display: %s", XDisplayName(0));
56 screen = DefaultScreen(display);
57 display_width = DisplayWidth(display, screen);
58 display_height = DisplayHeight(display, screen);
63 static void update_workarea()
65 Window root = RootWindow(display, screen);
66 unsigned long nitems, bytes;
67 unsigned char *buf = NULL;
71 /* default work area is display */
74 workarea[2] = display_width;
75 workarea[3] = display_height;
77 /* get current desktop */
78 if (XGetWindowProperty(display, root, ATOM(_NET_CURRENT_DESKTOP),
79 0, 1, False, XA_CARDINAL, &type, &format,
80 &nitems, &bytes, &buf) == Success
81 && type == XA_CARDINAL && nitems > 0) {
84 /* long desktop = * (long *) buf; */
97 /* Find root window and desktop window. Return desktop window on success,
98 * and set root and desktop byref return values. Return 0 on failure. */
99 static Window find_desktop_window(Window *p_root, Window *p_desktop)
103 unsigned long nitems, bytes;
105 Window root = RootWindow(display, screen);
107 Window troot, parent, *children;
108 unsigned char *buf = NULL;
110 if (!p_root || !p_desktop)
113 /* some window managers set __SWM_VROOT to some child of root window */
115 XQueryTree(display, root, &troot, &parent, &children, &n);
116 for (i = 0; i < (int) n; i++) {
117 if (XGetWindowProperty
118 (display, children[i], ATOM(__SWM_VROOT), 0, 1, False,
119 XA_WINDOW, &type, &format, &nitems, &bytes,
120 &buf) == Success && type == XA_WINDOW) {
121 win = *(Window *) buf;
125 "Conky: desktop window (%lx) found from __SWM_VROOT property\n", win);
139 /* get subwindows from root */
140 win = find_subwindow(root, -1, -1);
144 win = find_subwindow(win, workarea[2], workarea[3]);
153 "Conky: desktop window (%lx) is subwindow of root window (%lx)\n",win,root);
155 fprintf(stderr, "Conky: desktop window (%lx) is root window\n",win);
165 /* sets background to ParentRelative for the Window and all parents */
166 inline void set_transparent_background(Window win)
168 static int colour_set = -1;
169 if (set_transparent) {
172 for (i = 0; i < 50 && parent != RootWindow(display, screen); i++) {
176 XSetWindowBackgroundPixmap(display, parent, ParentRelative);
178 XQueryTree(display, parent, &r, &parent, &children, &n);
181 } else if (colour_set != background_colour) {
182 XSetWindowBackground(display, win, background_colour);
183 colour_set = background_colour;
185 //XClearWindow(display, win); not sure why this was here
188 void init_window(int own_window, int w, int h, int set_trans, int back_colour, char * nodename,
189 char **argv, int argc)
191 /* There seems to be some problems with setting transparent background (on
192 * fluxbox this time). It doesn't happen always and I don't know why it
193 * happens but I bet the bug is somewhere here. */
194 set_transparent = set_trans;
195 background_colour = back_colour;
197 nodename = (char *)nodename;
202 if ( !find_desktop_window( &window.root, &window.desktop ) )
205 if (window.type == TYPE_OVERRIDE) {
208 An override_redirect True window. No WM hints or button processing needed.
210 XSetWindowAttributes attrs = {
211 ParentRelative,0L,0,0L,0,0,Always,0L,0L,False,
212 StructureNotifyMask|ExposureMask,
217 /* Parent is desktop window (which might be a child of root) */
218 window.window = XCreateWindow(display,
220 window.x, window.y, w, h, 0,
224 CWBackPixel|CWOverrideRedirect,
227 XLowerWindow(display, window.window);
229 fprintf(stderr, "Conky: window type - override\n"); fflush(stderr);
233 else { /* window.type != TYPE_OVERRIDE */
236 A window managed by the window manager. Process hints and buttons.
238 XSetWindowAttributes attrs = {
239 ParentRelative,0L,0,0L,0,0,Always,0L,0L,False,
240 StructureNotifyMask|ExposureMask|ButtonPressMask|ButtonReleaseMask,
245 XClassHint classHint;
248 char window_title[256];
250 /* Parent is root window so WM can take control */
251 window.window = XCreateWindow(display,
253 window.x, window.y, w, h, 0,
257 CWBackPixel|CWOverrideRedirect,
260 classHint.res_name = window.wm_class_name;
261 classHint.res_class = classHint.res_name;
263 wmHint.flags = InputHint | StateHint;
264 wmHint.input = False;
265 wmHint.initial_state = NormalState;
267 sprintf(window_title,WINDOW_NAME_FMT,nodename);
269 XmbSetWMProperties (display, window.window, window_title, NULL,
271 NULL, &wmHint, &classHint);
273 /* Sets an empty WM_PROTOCOLS property */
274 XSetWMProtocols(display,window.window,NULL,0);
277 /* Set window type */
278 if ( (xa = ATOM(_NET_WM_WINDOW_TYPE)) != None )
281 switch(window.type) {
284 prop = ATOM(_NET_WM_WINDOW_TYPE_DESKTOP);
285 fprintf(stderr, "Conky: window type - desktop\n"); fflush(stderr);
291 prop = ATOM(_NET_WM_WINDOW_TYPE_NORMAL);
292 fprintf(stderr, "Conky: window type - normal\n"); fflush(stderr);
296 XChangeProperty(display, window.window, xa,
299 (unsigned char *) &prop, 1);
302 /* Set desired hints */
304 /* Window decorations */
305 if (TEST_HINT(window.hints,HINT_UNDECORATED)) {
306 fprintf(stderr, "Conky: hint - undecorated\n"); fflush(stderr);
308 xa = ATOM(_MOTIF_WM_HINTS);
310 long prop[5] = { 2, 0, 0, 0, 0 };
311 XChangeProperty(display, window.window, xa,
312 xa, 32, PropModeReplace,
313 (unsigned char *) prop, 5);
317 /* Below other windows */
318 if (TEST_HINT(window.hints,HINT_BELOW)) {
319 fprintf(stderr, "Conky: hint - below\n"); fflush(stderr);
321 xa = ATOM(_WIN_LAYER);
324 XChangeProperty(display, window.window, xa,
327 (unsigned char *) &prop, 1);
330 xa = ATOM(_NET_WM_STATE);
332 Atom xa_prop = ATOM(_NET_WM_STATE_BELOW);
333 XChangeProperty(display, window.window, xa,
336 (unsigned char *) &xa_prop,
341 /* Above other windows */
342 if (TEST_HINT(window.hints,HINT_ABOVE)) {
343 fprintf(stderr, "Conky: hint - above\n"); fflush(stderr);
345 xa = ATOM(_WIN_LAYER);
348 XChangeProperty(display, window.window, xa,
351 (unsigned char *) &prop, 1);
354 xa = ATOM(_NET_WM_STATE);
356 Atom xa_prop = ATOM(_NET_WM_STATE_ABOVE);
357 XChangeProperty(display, window.window, xa,
360 (unsigned char *) &xa_prop,
366 if (TEST_HINT(window.hints,HINT_STICKY)) {
367 fprintf(stderr, "Conky: hint - sticky\n"); fflush(stderr);
369 xa = ATOM(_NET_WM_DESKTOP);
371 CARD32 xa_prop = 0xFFFFFFFF;
372 XChangeProperty(display, window.window, xa,
375 (unsigned char *) &xa_prop,
379 xa = ATOM(_NET_WM_STATE);
381 Atom xa_prop = ATOM(_NET_WM_STATE_STICKY);
382 XChangeProperty(display, window.window, xa,
385 (unsigned char *) &xa_prop,
391 if (TEST_HINT(window.hints,HINT_SKIP_TASKBAR)) {
392 fprintf(stderr, "Conky: hint - skip_taskbar\n"); fflush(stderr);
394 xa = ATOM(_NET_WM_STATE);
396 Atom xa_prop = ATOM(_NET_WM_STATE_SKIP_TASKBAR);
397 XChangeProperty(display, window.window, xa,
400 (unsigned char *) &xa_prop,
406 if (TEST_HINT(window.hints,HINT_SKIP_PAGER)) {
407 fprintf(stderr, "Conky: hint - skip_pager\n"); fflush(stderr);
409 xa = ATOM(_NET_WM_STATE);
411 Atom xa_prop = ATOM(_NET_WM_STATE_SKIP_PAGER);
412 XChangeProperty(display, window.window, xa,
415 (unsigned char *) &xa_prop,
420 } /* else { window.type != TYPE_OVERRIDE */
422 fprintf(stderr, "Conky: drawing to created window (%lx)\n", window.window);
425 XMapWindow(display, window.window);
427 } else /* if (own_window) { */
429 /* root / desktop window */
431 XWindowAttributes attrs;
434 window.window = find_desktop_window( &window.root, &window.desktop );
436 if (XGetWindowAttributes(display, window.window, &attrs)) {
437 window.width = attrs.width;
438 window.height = attrs.height;
441 fprintf(stderr, "Conky: drawing to desktop window\n");
444 /* Drawable is same as window. This may be changed by double buffering. */
445 window.drawable = window.window;
450 if (!XdbeQueryExtension(display, &major, &minor)) {
454 XdbeAllocateBackBufferName(display,
457 if (window.back_buffer != None) {
458 window.drawable = window.back_buffer;
460 "Conky: drawing to double buffer\n");
465 ERR("failed to set up double buffer");
468 fprintf(stderr, "Conky: drawing to single buffer\n");
473 /*set_transparent_background(window.window); must be done after double buffer stuff? */
476 set_transparent_background(window.window);
477 XClearWindow(display, window.window);
481 XSelectInput(display, window.window, ExposureMask
484 ? (StructureNotifyMask | PropertyChangeMask |
485 ButtonPressMask | ButtonReleaseMask) : 0)
490 static Window find_subwindow(Window win, int w, int h)
493 Window troot, parent, *children;
496 /* search subwindows with same size as display or work area */
498 for (i = 0; i < 10; i++) {
499 XQueryTree(display, win, &troot, &parent, &children, &n);
501 for (j = 0; j < n; j++) {
502 XWindowAttributes attrs;
504 if (XGetWindowAttributes
505 (display, children[j], &attrs)) {
506 /* Window must be mapped and same size as display or work space */
507 if (attrs.map_state != 0 &&
508 ((attrs.width == display_width
509 && attrs.height == display_height)
511 && attrs.height == h))) {
526 long get_x11_color(const char *name)
531 (display, DefaultColormap(display, screen), name, &color)) {
532 /* lets check if it's a hex colour with the # missing in front
533 * if yes, then do something about it
537 strncpy(&newname[1], name, 62);
538 /* now lets try again */
539 if (!XParseColor(display, DefaultColormap(display, screen), &newname[0], &color)) {
540 ERR("can't parse X color '%s'", name);
545 (display, DefaultColormap(display, screen), &color))
546 ERR("can't allocate X color '%s'", name);
548 return (long) color.pixel;
554 values.graphics_exposures = 0;
555 values.function = GXcopy;
556 window.gc = XCreateGC(display, window.drawable,
557 GCFunction | GCGraphicsExposures, &values);