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>
31 #define WINDOW_NAME_FMT "%s - conky"
33 /* some basic X11 stuff */
38 static int set_transparent;
39 static int background_colour;
41 /* workarea from _NET_WORKAREA, this is where window / text is aligned */
45 struct conky_window window;
47 /* local prototypes */
48 static void update_workarea();
49 static Window find_desktop_window(Window *p_root, Window *p_desktop);
50 static Window find_subwindow(Window win, int w, int h);
55 if ((display = XOpenDisplay(0)) == NULL)
56 CRIT_ERR("can't open display: %s", XDisplayName(0));
58 screen = DefaultScreen(display);
59 display_width = DisplayWidth(display, screen);
60 display_height = DisplayHeight(display, screen);
65 static void update_workarea()
67 Window root = RootWindow(display, screen);
68 unsigned long nitems, bytes;
69 unsigned char *buf = NULL;
73 /* default work area is display */
76 workarea[2] = display_width;
77 workarea[3] = display_height;
79 /* get current desktop */
80 if (XGetWindowProperty(display, root, ATOM(_NET_CURRENT_DESKTOP),
81 0, 1, False, XA_CARDINAL, &type, &format,
82 &nitems, &bytes, &buf) == Success
83 && type == XA_CARDINAL && nitems > 0) {
86 /* long desktop = * (long *) buf; */
99 /* Find root window and desktop window. Return desktop window on success,
100 * and set root and desktop byref return values. Return 0 on failure. */
101 static Window find_desktop_window(Window *p_root, Window *p_desktop)
105 unsigned long nitems, bytes;
107 Window root = RootWindow(display, screen);
109 Window troot, parent, *children;
110 unsigned char *buf = NULL;
112 if (!p_root || !p_desktop)
115 /* some window managers set __SWM_VROOT to some child of root window */
117 XQueryTree(display, root, &troot, &parent, &children, &n);
118 for (i = 0; i < (int) n; i++) {
119 if (XGetWindowProperty
120 (display, children[i], ATOM(__SWM_VROOT), 0, 1, False,
121 XA_WINDOW, &type, &format, &nitems, &bytes,
122 &buf) == Success && type == XA_WINDOW) {
123 win = *(Window *) buf;
127 "Conky: desktop window (%lx) found from __SWM_VROOT property\n", win);
141 /* get subwindows from root */
142 win = find_subwindow(root, -1, -1);
146 win = find_subwindow(win, workarea[2], workarea[3]);
155 "Conky: desktop window (%lx) is subwindow of root window (%lx)\n",win,root);
157 fprintf(stderr, "Conky: desktop window (%lx) is root window\n",win);
167 /* sets background to ParentRelative for the Window and all parents */
168 inline void set_transparent_background(Window win)
170 static int colour_set = -1;
171 if (set_transparent) {
174 for (i = 0; i < 50 && parent != RootWindow(display, screen); i++) {
178 XSetWindowBackgroundPixmap(display, parent, ParentRelative);
180 XQueryTree(display, parent, &r, &parent, &children, &n);
183 } else if (colour_set != background_colour) {
184 XSetWindowBackground(display, win, background_colour);
185 colour_set = background_colour;
187 //XClearWindow(display, win); not sure why this was here
190 void init_window(int own_window, int w, int h, int set_trans, int back_colour, char * nodename,
191 char **argv, int argc)
193 /* There seems to be some problems with setting transparent background (on
194 * fluxbox this time). It doesn't happen always and I don't know why it
195 * happens but I bet the bug is somewhere here. */
196 set_transparent = set_trans;
197 background_colour = back_colour;
199 nodename = (char *)nodename;
204 if ( !find_desktop_window( &window.root, &window.desktop ) )
207 if (window.type == TYPE_OVERRIDE) {
210 An override_redirect True window. No WM hints or button processing needed.
212 XSetWindowAttributes attrs = {
213 ParentRelative,0L,0,0L,0,0,Always,0L,0L,False,
214 StructureNotifyMask|ExposureMask,
219 /* Parent is desktop window (which might be a child of root) */
220 window.window = XCreateWindow(display,
222 window.x, window.y, w, h, 0,
226 CWBackPixel|CWOverrideRedirect,
229 XLowerWindow(display, window.window);
231 fprintf(stderr, "Conky: window type - override\n"); fflush(stderr);
235 else { /* window.type != TYPE_OVERRIDE */
238 A window managed by the window manager. Process hints and buttons.
240 XSetWindowAttributes attrs = {
241 ParentRelative,0L,0,0L,0,0,Always,0L,0L,False,
242 StructureNotifyMask|ExposureMask|ButtonPressMask|ButtonReleaseMask,
247 XClassHint classHint;
250 char window_title[256];
252 /* Parent is root window so WM can take control */
253 window.window = XCreateWindow(display,
255 window.x, window.y, w, h, 0,
259 CWBackPixel|CWOverrideRedirect,
262 classHint.res_name = window.wm_class_name;
263 classHint.res_class = classHint.res_name;
265 wmHint.flags = InputHint | StateHint;
266 wmHint.input = False;
267 wmHint.initial_state = NormalState;
269 sprintf(window_title,WINDOW_NAME_FMT,nodename);
271 XmbSetWMProperties (display, window.window, window_title, NULL,
273 NULL, &wmHint, &classHint);
275 /* Sets an empty WM_PROTOCOLS property */
276 XSetWMProtocols(display,window.window,NULL,0);
279 /* Set window type */
280 if ( (xa = ATOM(_NET_WM_WINDOW_TYPE)) != None )
283 switch(window.type) {
286 prop = ATOM(_NET_WM_WINDOW_TYPE_DESKTOP);
287 fprintf(stderr, "Conky: window type - desktop\n"); fflush(stderr);
293 prop = ATOM(_NET_WM_WINDOW_TYPE_NORMAL);
294 fprintf(stderr, "Conky: window type - normal\n"); fflush(stderr);
298 XChangeProperty(display, window.window, xa,
301 (unsigned char *) &prop, 1);
304 /* Set desired hints */
306 /* Window decorations */
307 if (TEST_HINT(window.hints,HINT_UNDECORATED)) {
308 fprintf(stderr, "Conky: hint - undecorated\n"); fflush(stderr);
310 xa = ATOM(_MOTIF_WM_HINTS);
312 long prop[5] = { 2, 0, 0, 0, 0 };
313 XChangeProperty(display, window.window, xa,
314 xa, 32, PropModeReplace,
315 (unsigned char *) prop, 5);
319 /* Below other windows */
320 if (TEST_HINT(window.hints,HINT_BELOW)) {
321 fprintf(stderr, "Conky: hint - below\n"); fflush(stderr);
323 xa = ATOM(_WIN_LAYER);
326 XChangeProperty(display, window.window, xa,
329 (unsigned char *) &prop, 1);
332 xa = ATOM(_NET_WM_STATE);
334 Atom xa_prop = ATOM(_NET_WM_STATE_BELOW);
335 XChangeProperty(display, window.window, xa,
338 (unsigned char *) &xa_prop,
343 /* Above other windows */
344 if (TEST_HINT(window.hints,HINT_ABOVE)) {
345 fprintf(stderr, "Conky: hint - above\n"); fflush(stderr);
347 xa = ATOM(_WIN_LAYER);
350 XChangeProperty(display, window.window, xa,
353 (unsigned char *) &prop, 1);
356 xa = ATOM(_NET_WM_STATE);
358 Atom xa_prop = ATOM(_NET_WM_STATE_ABOVE);
359 XChangeProperty(display, window.window, xa,
362 (unsigned char *) &xa_prop,
368 if (TEST_HINT(window.hints,HINT_STICKY)) {
369 fprintf(stderr, "Conky: hint - sticky\n"); fflush(stderr);
371 xa = ATOM(_NET_WM_DESKTOP);
373 CARD32 xa_prop = 0xFFFFFFFF;
374 XChangeProperty(display, window.window, xa,
377 (unsigned char *) &xa_prop,
381 xa = ATOM(_NET_WM_STATE);
383 Atom xa_prop = ATOM(_NET_WM_STATE_STICKY);
384 XChangeProperty(display, window.window, xa,
387 (unsigned char *) &xa_prop,
393 if (TEST_HINT(window.hints,HINT_SKIP_TASKBAR)) {
394 fprintf(stderr, "Conky: hint - skip_taskbar\n"); fflush(stderr);
396 xa = ATOM(_NET_WM_STATE);
398 Atom xa_prop = ATOM(_NET_WM_STATE_SKIP_TASKBAR);
399 XChangeProperty(display, window.window, xa,
402 (unsigned char *) &xa_prop,
408 if (TEST_HINT(window.hints,HINT_SKIP_PAGER)) {
409 fprintf(stderr, "Conky: hint - skip_pager\n"); fflush(stderr);
411 xa = ATOM(_NET_WM_STATE);
413 Atom xa_prop = ATOM(_NET_WM_STATE_SKIP_PAGER);
414 XChangeProperty(display, window.window, xa,
417 (unsigned char *) &xa_prop,
422 } /* else { window.type != TYPE_OVERRIDE */
424 fprintf(stderr, "Conky: drawing to created window (%lx)\n", window.window);
427 XMapWindow(display, window.window);
429 } else /* if (own_window) { */
431 /* root / desktop window */
433 XWindowAttributes attrs;
436 window.window = find_desktop_window( &window.root, &window.desktop );
438 if (XGetWindowAttributes(display, window.window, &attrs)) {
439 window.width = attrs.width;
440 window.height = attrs.height;
443 fprintf(stderr, "Conky: drawing to desktop window\n");
446 /* Drawable is same as window. This may be changed by double buffering. */
447 window.drawable = window.window;
452 if (!XdbeQueryExtension(display, &major, &minor)) {
456 XdbeAllocateBackBufferName(display,
459 if (window.back_buffer != None) {
460 window.drawable = window.back_buffer;
462 "Conky: drawing to double buffer\n");
467 ERR("failed to set up double buffer");
470 fprintf(stderr, "Conky: drawing to single buffer\n");
475 /*set_transparent_background(window.window); must be done after double buffer stuff? */
478 set_transparent_background(window.window);
479 XClearWindow(display, window.window);
483 XSelectInput(display, window.window, ExposureMask
486 ? (StructureNotifyMask | PropertyChangeMask |
487 ButtonPressMask | ButtonReleaseMask) : 0)
492 static Window find_subwindow(Window win, int w, int h)
495 Window troot, parent, *children;
498 /* search subwindows with same size as display or work area */
500 for (i = 0; i < 10; i++) {
501 XQueryTree(display, win, &troot, &parent, &children, &n);
503 for (j = 0; j < n; j++) {
504 XWindowAttributes attrs;
506 if (XGetWindowAttributes
507 (display, children[j], &attrs)) {
508 /* Window must be mapped and same size as display or work space */
509 if (attrs.map_state != 0 &&
510 ((attrs.width == display_width
511 && attrs.height == display_height)
513 && attrs.height == h))) {
528 long get_x11_color(const char *name)
533 (display, DefaultColormap(display, screen), name, &color)) {
534 /* lets check if it's a hex colour with the # missing in front
535 * if yes, then do something about it
539 strncpy(&newname[1], name, 62);
540 /* now lets try again */
541 if (!XParseColor(display, DefaultColormap(display, screen), &newname[0], &color)) {
542 ERR("can't parse X color '%s'", name);
547 (display, DefaultColormap(display, screen), &color))
548 ERR("can't allocate X color '%s'", name);
550 return (long) color.pixel;
556 values.graphics_exposures = 0;
557 values.function = GXcopy;
558 window.gc = XCreateGC(display, window.drawable,
559 GCFunction | GCGraphicsExposures, &values);