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 /* Allow WM control of conky again. Shielding conky from the WM
205 * via override redirect creates more problems than it's worth and
206 * makes it impossible to use tools like devilspie to manage the
207 * conky windows beyond the parameters we offer. ButtonPress
208 * events are now explicitly forwarded to the desktop window. */
209 XSetWindowAttributes attrs = {
210 ParentRelative,0L,0,0L,0,0,Always,0L,0L,False,
211 StructureNotifyMask|ExposureMask|
212 (window.type==TYPE_OVERRIDE ? ButtonPressMask|ButtonReleaseMask : 0),
214 (window.type==TYPE_OVERRIDE ? True : False),
217 XClassHint classHint;
220 char window_title[256];
222 /* We want to parent the window to the root so it's under WM control,
223 * but we want to forward button clicks to the desktop window for menus.
224 * On some desktop systems, the desktop window != root window. */
225 if ( !find_desktop_window( &window.root, &window.desktop ) )
228 window.window = XCreateWindow(display,
229 window.type==TYPE_OVERRIDE ? window.desktop : window.root,
230 window.x, window.y, w, h, 0,
234 CWBackPixel|CWOverrideRedirect,
237 fprintf(stderr, "Conky: drawing to created window (%lx)\n", window.window);
240 classHint.res_name = window.wm_class_name;
241 classHint.res_class = classHint.res_name;
243 wmHint.flags = InputHint | StateHint;
244 wmHint.input = False;
245 wmHint.initial_state = NormalState;
247 sprintf(window_title,WINDOW_NAME_FMT,nodename);
249 XmbSetWMProperties (display, window.window, window_title, NULL,
251 NULL, &wmHint, &classHint);
253 /* Sets an empty WM_PROTOCOLS property */
254 XSetWMProtocols(display,window.window,NULL,0);
257 /* Set window type */
258 if ( (xa = ATOM(_NET_WM_WINDOW_TYPE)) != None )
261 switch(window.type) {
264 prop = ATOM(_NET_WM_WINDOW_TYPE_DESKTOP);
265 fprintf(stderr, "Conky: window type - desktop\n"); fflush(stderr);
271 fprintf(stderr, "Conky: window type - override\n"); fflush(stderr);
277 prop = ATOM(_NET_WM_WINDOW_TYPE_NORMAL);
278 fprintf(stderr, "Conky: window type - normal\n"); fflush(stderr);
282 if (window.type != TYPE_OVERRIDE)
283 XChangeProperty(display, window.window, xa,
286 (unsigned char *) &prop, 1);
289 /* Set desired hints */
291 /* Window decorations */
292 if (TEST_HINT(window.hints,HINT_UNDECORATED)) {
293 fprintf(stderr, "Conky: hint - undecorated\n"); fflush(stderr);
295 xa = ATOM(_MOTIF_WM_HINTS);
297 long prop[5] = { 2, 0, 0, 0, 0 };
298 XChangeProperty(display, window.window, xa,
299 xa, 32, PropModeReplace,
300 (unsigned char *) prop, 5);
304 /* Below other windows */
305 if (TEST_HINT(window.hints,HINT_BELOW)) {
306 fprintf(stderr, "Conky: hint - below\n"); fflush(stderr);
308 xa = ATOM(_WIN_LAYER);
311 XChangeProperty(display, window.window, xa,
314 (unsigned char *) &prop, 1);
317 xa = ATOM(_NET_WM_STATE);
319 Atom xa_prop = ATOM(_NET_WM_STATE_BELOW);
320 XChangeProperty(display, window.window, xa,
323 (unsigned char *) &xa_prop,
328 /* Above other windows */
329 if (TEST_HINT(window.hints,HINT_ABOVE)) {
330 fprintf(stderr, "Conky: hint - above\n"); fflush(stderr);
332 xa = ATOM(_WIN_LAYER);
335 XChangeProperty(display, window.window, xa,
338 (unsigned char *) &prop, 1);
341 xa = ATOM(_NET_WM_STATE);
343 Atom xa_prop = ATOM(_NET_WM_STATE_ABOVE);
344 XChangeProperty(display, window.window, xa,
347 (unsigned char *) &xa_prop,
353 if (TEST_HINT(window.hints,HINT_STICKY)) {
354 fprintf(stderr, "Conky: hint - sticky\n"); fflush(stderr);
356 xa = ATOM(_NET_WM_DESKTOP);
358 CARD32 xa_prop = 0xFFFFFFFF;
359 XChangeProperty(display, window.window, xa,
362 (unsigned char *) &xa_prop,
366 xa = ATOM(_NET_WM_STATE);
368 Atom xa_prop = ATOM(_NET_WM_STATE_STICKY);
369 XChangeProperty(display, window.window, xa,
372 (unsigned char *) &xa_prop,
378 if (TEST_HINT(window.hints,HINT_SKIP_TASKBAR)) {
379 fprintf(stderr, "Conky: hint - skip_taskbar\n"); fflush(stderr);
381 xa = ATOM(_NET_WM_STATE);
383 Atom xa_prop = ATOM(_NET_WM_STATE_SKIP_TASKBAR);
384 XChangeProperty(display, window.window, xa,
387 (unsigned char *) &xa_prop,
393 if (TEST_HINT(window.hints,HINT_SKIP_PAGER)) {
394 fprintf(stderr, "Conky: hint - skip_pager\n"); fflush(stderr);
396 xa = ATOM(_NET_WM_STATE);
398 Atom xa_prop = ATOM(_NET_WM_STATE_SKIP_PAGER);
399 XChangeProperty(display, window.window, xa,
402 (unsigned char *) &xa_prop,
407 if (window.type == TYPE_OVERRIDE)
408 XLowerWindow(display, window.window);
410 XMapWindow(display, window.window);
414 /* root / desktop window */
416 XWindowAttributes attrs;
419 window.window = find_desktop_window( &window.root, &window.desktop );
421 if (XGetWindowAttributes(display, window.window, &attrs)) {
422 window.width = attrs.width;
423 window.height = attrs.height;
426 fprintf(stderr, "Conky: drawing to desktop window\n");
429 /* Drawable is same as window. This may be changed by double buffering. */
430 window.drawable = window.window;
435 if (!XdbeQueryExtension(display, &major, &minor)) {
439 XdbeAllocateBackBufferName(display,
442 if (window.back_buffer != None) {
443 window.drawable = window.back_buffer;
445 "Conky: drawing to double buffer\n");
450 ERR("failed to set up double buffer");
453 fprintf(stderr, "Conky: drawing to single buffer\n");
458 /*set_transparent_background(window.window); must be done after double buffer stuff? */
461 set_transparent_background(window.window);
462 XClearWindow(display, window.window);
466 XSelectInput(display, window.window, ExposureMask
469 ? (StructureNotifyMask | PropertyChangeMask |
470 ButtonPressMask | ButtonReleaseMask) : 0)
475 static Window find_subwindow(Window win, int w, int h)
478 Window troot, parent, *children;
481 /* search subwindows with same size as display or work area */
483 for (i = 0; i < 10; i++) {
484 XQueryTree(display, win, &troot, &parent, &children, &n);
486 for (j = 0; j < n; j++) {
487 XWindowAttributes attrs;
489 if (XGetWindowAttributes
490 (display, children[j], &attrs)) {
491 /* Window must be mapped and same size as display or work space */
492 if (attrs.map_state != 0 &&
493 ((attrs.width == display_width
494 && attrs.height == display_height)
496 && attrs.height == h))) {
511 long get_x11_color(const char *name)
516 (display, DefaultColormap(display, screen), name, &color)) {
517 /* lets check if it's a hex colour with the # missing in front
518 * if yes, then do something about it
522 strncpy(&newname[1], name, 62);
523 /* now lets try again */
524 if (!XParseColor(display, DefaultColormap(display, screen), &newname[0], &color)) {
525 ERR("can't parse X color '%s'", name);
530 (display, DefaultColormap(display, screen), &color))
531 ERR("can't allocate X color '%s'", name);
533 return (long) color.pixel;
539 values.graphics_exposures = 0;
540 values.function = GXcopy;
541 window.gc = XCreateGC(display, window.drawable,
542 GCFunction | GCGraphicsExposures, &values);