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,
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 NORMAL window type for _NET_WM_WINDOW_TYPE. */
254 xa = ATOM(_NET_WM_WINDOW_TYPE);
256 Atom prop = ATOM(_NET_WM_WINDOW_TYPE_NORMAL);
257 XChangeProperty(display, window.window, xa,
260 (unsigned char *) &prop,
264 /* Set desired hints */
266 /* Window decorations */
267 if (TEST_HINT(window.hints,HINT_UNDECORATED)) {
268 fprintf(stderr, "Conky: hint - undecorated\n"); fflush(stderr);
270 xa = ATOM(_MOTIF_WM_HINTS);
272 long prop[5] = { 2, 0, 0, 0, 0 };
273 XChangeProperty(display, window.window, xa,
274 xa, 32, PropModeReplace,
275 (unsigned char *) prop, 5);
279 /* Below other windows */
280 if (TEST_HINT(window.hints,HINT_BELOW)) {
281 fprintf(stderr, "Conky: hint - below\n"); fflush(stderr);
283 xa = ATOM(_WIN_LAYER);
286 XChangeProperty(display, window.window, xa,
289 (unsigned char *) &prop, 1);
292 xa = ATOM(_NET_WM_STATE);
294 Atom xa_prop = ATOM(_NET_WM_STATE_BELOW);
295 XChangeProperty(display, window.window, xa,
298 (unsigned char *) &xa_prop,
303 /* Above other windows */
304 if (TEST_HINT(window.hints,HINT_ABOVE)) {
305 fprintf(stderr, "Conky: hint - above\n"); fflush(stderr);
307 xa = ATOM(_WIN_LAYER);
310 XChangeProperty(display, window.window, xa,
313 (unsigned char *) &prop, 1);
316 xa = ATOM(_NET_WM_STATE);
318 Atom xa_prop = ATOM(_NET_WM_STATE_ABOVE);
319 XChangeProperty(display, window.window, xa,
322 (unsigned char *) &xa_prop,
328 if (TEST_HINT(window.hints,HINT_STICKY)) {
329 fprintf(stderr, "Conky: hint - sticky\n"); fflush(stderr);
331 xa = ATOM(_NET_WM_DESKTOP);
333 CARD32 xa_prop = 0xFFFFFFFF;
334 XChangeProperty(display, window.window, xa,
337 (unsigned char *) &xa_prop,
341 xa = ATOM(_NET_WM_STATE);
343 Atom xa_prop = ATOM(_NET_WM_STATE_STICKY);
344 XChangeProperty(display, window.window, xa,
347 (unsigned char *) &xa_prop,
353 if (TEST_HINT(window.hints,HINT_SKIP_TASKBAR)) {
354 fprintf(stderr, "Conky: hint - skip_taskbar\n"); fflush(stderr);
356 xa = ATOM(_NET_WM_STATE);
358 Atom xa_prop = ATOM(_NET_WM_STATE_SKIP_TASKBAR);
359 XChangeProperty(display, window.window, xa,
362 (unsigned char *) &xa_prop,
368 if (TEST_HINT(window.hints,HINT_SKIP_PAGER)) {
369 fprintf(stderr, "Conky: hint - skip_pager\n"); fflush(stderr);
371 xa = ATOM(_NET_WM_STATE);
373 Atom xa_prop = ATOM(_NET_WM_STATE_SKIP_PAGER);
374 XChangeProperty(display, window.window, xa,
377 (unsigned char *) &xa_prop,
382 XMapWindow(display, window.window);
387 /* root / desktop window */
389 XWindowAttributes attrs;
392 window.window = find_desktop_window( &window.root, &window.desktop );
394 if (XGetWindowAttributes(display, window.window, &attrs)) {
395 window.width = attrs.width;
396 window.height = attrs.height;
399 fprintf(stderr, "Conky: drawing to desktop window\n");
402 /* Drawable is same as window. This may be changed by double buffering. */
403 window.drawable = window.window;
408 if (!XdbeQueryExtension(display, &major, &minor)) {
412 XdbeAllocateBackBufferName(display,
415 if (window.back_buffer != None) {
416 window.drawable = window.back_buffer;
418 "Conky: drawing to double buffer\n");
423 ERR("failed to set up double buffer");
426 fprintf(stderr, "Conky: drawing to single buffer\n");
431 /*set_transparent_background(window.window); must be done after double buffer stuff? */
434 set_transparent_background(window.window);
435 XClearWindow(display, window.window);
439 XSelectInput(display, window.window, ExposureMask
442 ? (StructureNotifyMask | PropertyChangeMask | ButtonPressMask) : 0)
447 static Window find_subwindow(Window win, int w, int h)
450 Window troot, parent, *children;
453 /* search subwindows with same size as display or work area */
455 for (i = 0; i < 10; i++) {
456 XQueryTree(display, win, &troot, &parent, &children, &n);
458 for (j = 0; j < n; j++) {
459 XWindowAttributes attrs;
461 if (XGetWindowAttributes
462 (display, children[j], &attrs)) {
463 /* Window must be mapped and same size as display or work space */
464 if (attrs.map_state != 0 &&
465 ((attrs.width == display_width
466 && attrs.height == display_height)
468 && attrs.height == h))) {
483 long get_x11_color(const char *name)
488 (display, DefaultColormap(display, screen), name, &color)) {
489 /* lets check if it's a hex colour with the # missing in front
490 * if yes, then do something about it
494 strncpy(&newname[1], name, 62);
495 /* now lets try again */
496 if (!XParseColor(display, DefaultColormap(display, screen), &newname[0], &color)) {
497 ERR("can't parse X color '%s'", name);
502 (display, DefaultColormap(display, screen), &color))
503 ERR("can't allocate X color '%s'", name);
505 return (long) color.pixel;
511 values.graphics_exposures = 0;
512 values.function = GXcopy;
513 window.gc = XCreateGC(display, window.drawable,
514 GCFunction | GCGraphicsExposures, &values);