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|ButtonPressMask|ButtonReleaseMask,
214 XClassHint classHint;
217 char window_title[256];
219 /* We want to parent the window to the root so it's under WM control,
220 * but we want to forward button clicks to the desktop window for menus.
221 * On some desktop systems, the desktop window != root window. */
222 if ( !find_desktop_window( &window.root, &window.desktop ) )
225 window.window = XCreateWindow(display, window.root,
226 window.x, window.y, w, h, 0,
230 CWBackPixel|CWOverrideRedirect,
233 fprintf(stderr, "Conky: drawing to created window (%lx)\n", window.window);
236 classHint.res_name = window.wm_class_name;
237 classHint.res_class = classHint.res_name;
239 wmHint.flags = InputHint | StateHint;
240 wmHint.input = False;
241 wmHint.initial_state = NormalState;
243 sprintf(window_title,WINDOW_NAME_FMT,nodename);
245 XmbSetWMProperties (display, window.window, window_title, NULL,
247 NULL, &wmHint, &classHint);
249 /* Sets an empty WM_PROTOCOLS property */
250 XSetWMProtocols(display,window.window,NULL,0);
253 /* Set window type */
254 if ( (xa = ATOM(_NET_WM_WINDOW_TYPE)) != None )
257 switch(window.type) {
260 prop = ATOM(_NET_WM_WINDOW_TYPE_DESKTOP);
261 fprintf(stderr, "Conky: window type - desktop\n"); fflush(stderr);
268 prop = ATOM(_NET_WM_WINDOW_TYPE_NORMAL);
269 fprintf(stderr, "Conky: window type - normal\n"); fflush(stderr);
273 XChangeProperty(display, window.window, xa,
276 (unsigned char *) &prop, 1);
279 /* Set desired hints */
281 /* Window decorations */
282 if (TEST_HINT(window.hints,HINT_UNDECORATED)) {
283 fprintf(stderr, "Conky: hint - undecorated\n"); fflush(stderr);
285 xa = ATOM(_MOTIF_WM_HINTS);
287 long prop[5] = { 2, 0, 0, 0, 0 };
288 XChangeProperty(display, window.window, xa,
289 xa, 32, PropModeReplace,
290 (unsigned char *) prop, 5);
294 /* Below other windows */
295 if (TEST_HINT(window.hints,HINT_BELOW)) {
296 fprintf(stderr, "Conky: hint - below\n"); fflush(stderr);
298 xa = ATOM(_WIN_LAYER);
301 XChangeProperty(display, window.window, xa,
304 (unsigned char *) &prop, 1);
307 xa = ATOM(_NET_WM_STATE);
309 Atom xa_prop = ATOM(_NET_WM_STATE_BELOW);
310 XChangeProperty(display, window.window, xa,
313 (unsigned char *) &xa_prop,
318 /* Above other windows */
319 if (TEST_HINT(window.hints,HINT_ABOVE)) {
320 fprintf(stderr, "Conky: hint - above\n"); fflush(stderr);
322 xa = ATOM(_WIN_LAYER);
325 XChangeProperty(display, window.window, xa,
328 (unsigned char *) &prop, 1);
331 xa = ATOM(_NET_WM_STATE);
333 Atom xa_prop = ATOM(_NET_WM_STATE_ABOVE);
334 XChangeProperty(display, window.window, xa,
337 (unsigned char *) &xa_prop,
343 if (TEST_HINT(window.hints,HINT_STICKY)) {
344 fprintf(stderr, "Conky: hint - sticky\n"); fflush(stderr);
346 xa = ATOM(_NET_WM_DESKTOP);
348 CARD32 xa_prop = 0xFFFFFFFF;
349 XChangeProperty(display, window.window, xa,
352 (unsigned char *) &xa_prop,
356 xa = ATOM(_NET_WM_STATE);
358 Atom xa_prop = ATOM(_NET_WM_STATE_STICKY);
359 XChangeProperty(display, window.window, xa,
362 (unsigned char *) &xa_prop,
368 if (TEST_HINT(window.hints,HINT_SKIP_TASKBAR)) {
369 fprintf(stderr, "Conky: hint - skip_taskbar\n"); fflush(stderr);
371 xa = ATOM(_NET_WM_STATE);
373 Atom xa_prop = ATOM(_NET_WM_STATE_SKIP_TASKBAR);
374 XChangeProperty(display, window.window, xa,
377 (unsigned char *) &xa_prop,
383 if (TEST_HINT(window.hints,HINT_SKIP_PAGER)) {
384 fprintf(stderr, "Conky: hint - skip_pager\n"); fflush(stderr);
386 xa = ATOM(_NET_WM_STATE);
388 Atom xa_prop = ATOM(_NET_WM_STATE_SKIP_PAGER);
389 XChangeProperty(display, window.window, xa,
392 (unsigned char *) &xa_prop,
397 XMapWindow(display, window.window);
402 /* root / desktop window */
404 XWindowAttributes attrs;
407 window.window = find_desktop_window( &window.root, &window.desktop );
409 if (XGetWindowAttributes(display, window.window, &attrs)) {
410 window.width = attrs.width;
411 window.height = attrs.height;
414 fprintf(stderr, "Conky: drawing to desktop window\n");
417 /* Drawable is same as window. This may be changed by double buffering. */
418 window.drawable = window.window;
423 if (!XdbeQueryExtension(display, &major, &minor)) {
427 XdbeAllocateBackBufferName(display,
430 if (window.back_buffer != None) {
431 window.drawable = window.back_buffer;
433 "Conky: drawing to double buffer\n");
438 ERR("failed to set up double buffer");
441 fprintf(stderr, "Conky: drawing to single buffer\n");
446 /*set_transparent_background(window.window); must be done after double buffer stuff? */
449 set_transparent_background(window.window);
450 XClearWindow(display, window.window);
454 XSelectInput(display, window.window, ExposureMask
457 ? (StructureNotifyMask | PropertyChangeMask |
458 ButtonPressMask | ButtonReleaseMask) : 0)
463 static Window find_subwindow(Window win, int w, int h)
466 Window troot, parent, *children;
469 /* search subwindows with same size as display or work area */
471 for (i = 0; i < 10; i++) {
472 XQueryTree(display, win, &troot, &parent, &children, &n);
474 for (j = 0; j < n; j++) {
475 XWindowAttributes attrs;
477 if (XGetWindowAttributes
478 (display, children[j], &attrs)) {
479 /* Window must be mapped and same size as display or work space */
480 if (attrs.map_state != 0 &&
481 ((attrs.width == display_width
482 && attrs.height == display_height)
484 && attrs.height == h))) {
499 long get_x11_color(const char *name)
504 (display, DefaultColormap(display, screen), name, &color)) {
505 /* lets check if it's a hex colour with the # missing in front
506 * if yes, then do something about it
510 strncpy(&newname[1], name, 62);
511 /* now lets try again */
512 if (!XParseColor(display, DefaultColormap(display, screen), &newname[0], &color)) {
513 ERR("can't parse X color '%s'", name);
518 (display, DefaultColormap(display, screen), &color))
519 ERR("can't allocate X color '%s'", name);
521 return (long) color.pixel;
527 values.graphics_exposures = 0;
528 values.function = GXcopy;
529 window.gc = XCreateGC(display, window.drawable,
530 GCFunction | GCGraphicsExposures, &values);