This program reads raw pixels from the pipe/stdin in a loop and set the root window background.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <X11/Xatom.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
int
main(int argc, char **argv)
{
Display *dpy;
Window root;
XImage *ximg;
Pixmap pm;
GC gc;
int scrn, fmt, ret;
char *img;
unsigned int w, h;
Atom aroot, aeroot, atype;
unsigned char *data_root, *data_eroot;
size_t len, after, siz, nread;
ret = EXIT_SUCCESS;
dpy = XOpenDisplay(NULL);
scrn = DefaultScreen(dpy);
root = RootWindow(dpy, scrn);
w = DisplayWidth(dpy, scrn);
h = DisplayHeight(dpy, scrn);
siz = 4 * w * h;
img = malloc(siz);
ximg = XCreateImage(dpy, CopyFromParent, 24, ZPixmap, 0, img, w, h, 32, 0);
pm = XCreatePixmap(dpy, root, w, h, 24);
aroot = XInternAtom(dpy, "_XROOTMAP_ID", True);
aeroot = XInternAtom(dpy, "ESETROOT_PMAP_ID", True);
if (aroot != None && aeroot != None) {
XGetWindowProperty(dpy, root, aroot, 0L, 1L, False, AnyPropertyType,
&atype, &fmt, &len, &after, &data_root);
if (atype == XA_PIXMAP) {
XGetWindowProperty(dpy, root, aeroot, 0L, 1L, False, AnyPropertyType,
&atype, &fmt, &len, &after, &data_eroot);
if (data_root && data_eroot && atype == XA_PIXMAP
&& *((Pixmap *) data_root) == *((Pixmap *) data_eroot))
XKillClient(dpy, *((Pixmap *) data_root));
}
}
aroot = XInternAtom(dpy, "_XROOTPMAP_ID", False);
aeroot = XInternAtom(dpy, "ESETROOT_PMAP_ID", False);
if (aroot == None || aeroot == None) {
fputs("atomic disaster\n", stderr);
ret = EXIT_FAILURE;
goto exit;
}
XChangeProperty(dpy, root, aroot, XA_PIXMAP, 32, PropModeReplace,
(unsigned char *)&pm, 1);
XChangeProperty(dpy, root, aeroot, XA_PIXMAP, 32, PropModeReplace,
(unsigned char *)&pm, 1);
XSetCloseDownMode(dpy, RetainTemporary);
XFlush(dpy);
gc = XCreateGC(dpy, pm, 0, NULL);
while ((nread = fread(img, 1, siz, stdin)) == siz) {
XPutImage(dpy, pm, gc, ximg, 0, 0, 0, 0, w, h);
XKillClient(dpy, AllTemporary);
XSetWindowBackgroundPixmap(dpy, root, pm);
XClearWindow(dpy, root);
XFlush(dpy);
XSync(dpy, False);
}
if (feof(stdin) && nread != 0) {
fputs("bad input\n", stderr);
ret = EXIT_FAILURE;
} else if (ferror(stdin)) {
perror("");
ret = EXIT_FAILURE;
}
exit:
XFreeGC(dpy, gc);
XFreePixmap(dpy, pm);
XDestroyImage(ximg);
XCloseDisplay(dpy);
return ret;
}
How do I handle Xlib function errors? And should I handle all of them? Virtually every function here can return an error, even stdio ones and if I wrap each in an if statement the code would be infinite (if (fputs("msg", stderr) == EOF) { if (fputs...).
Does setting the buffer size with setvbuf make sense since I know upfront that the input size should be the multiple of 4 * w * h which is in the order of megabytes? As per the second answer to similar question improvement would be minimal, but I'm not sure how to verify it.
I am using it with stream from ImageMagick, like this:
stream -map bgra wallpaper.png - | myprog
bgra instead of rgba because I couldn't find any proper way around this and unlike the OP I had simpler solution than the slow loop. And a because if I did just rgb bottom 1/4th of the screen looked like it was broken, even though the depth in XCreateImage is set to 24. So only png format works for now, since stream freaks out when I tell it to add alpha to jpg and co.