Hack of the day:
- Problem
I wanted to be able to fade to a new background image. But how could I get the current background image so that the two images can blended together?
- Solution
I dived into Xlib for the first time since 2003 and came up with a small C program that reads the current background image and writes it to a JPEG file.
I now have a script that downloads a new background image every hour and nicely fades to this new background by getting the current background and gradually blending the new image over this. :-)
Code:
// compile with: gcc -Wall -ansi -pedantic getbg.c -o getbg -lX11 -ljpeg
// usage: ./getbg mybg.jpg
#include <X11/Xlib.h>
#include <X11/Xatom.h>
#include <X11/Xutil.h>
#include <stdio.h>
#include <stdlib.h>
#include <jpeglib.h>
int write_jpeg(XImage *img, const char* filename)
{
FILE* outfile;long pixel;
unsigned
int x, y;
char* buffer;
struct jpeg_compress_struct cinfo;
struct jpeg_error_mgr jerr;
JSAMPROW row_pointer;
"wb");
outfile = fopen(filename,
if (!outfile) {"Failed to open output file %s", filename);
fprintf(stderr, 1;
return
}
/* collect separate RGB values to a buffer */
sizeof(char)*3*img->width*img->height);
buffer = malloc(0; y < img->height; y++) {
for (y = 0; x < img->width; x++) {
for (x =
pixel = XGetPixel(img,x,y);3+x*3+0] = (char)(pixel>>16);
buffer[y*img->width*3+x*3+1] = (char)((pixel&0x00ff00)>>8);
buffer[y*img->width*3+x*3+2] = (char)(pixel&0x0000ff);
buffer[y*img->width*
}
}
cinfo.err = jpeg_std_error(&jerr);
jpeg_create_compress(&cinfo);
jpeg_stdio_dest(&cinfo, outfile);
cinfo.image_width = img->width;
cinfo.image_height = img->height;3;
cinfo.input_components =
cinfo.in_color_space = JCS_RGB;
jpeg_set_defaults(&cinfo);85, TRUE);
jpeg_set_quality(&cinfo,
jpeg_start_compress(&cinfo, TRUE);
while (cinfo.next_scanline < cinfo.image_height) {
row_pointer = (JSAMPROW) &buffer[cinfo.next_scanline3)*img->width];
*(img->depth>>1);
jpeg_write_scanlines(&cinfo, &row_pointer,
}
free(buffer);
jpeg_finish_compress(&cinfo);
fclose(outfile);
0;
return
}
Pixmap GetRootPixmap(Display* display, Window *root)
{
Pixmap currentRootPixmap;act_type;
Atom
int act_format;long nitems, bytes_after;
unsigned char *data = NULL;
unsigned
Atom _XROOTPMAP_ID;
"_XROOTPMAP_ID", False);
_XROOTPMAP_ID = XInternAtom(display,
0, 1, False,
if (XGetWindowProperty(display, *root, _XROOTPMAP_ID, act_type, &act_format, &nitems, &bytes_after,
XA_PIXMAP, &
&data) == Success) {
if (data) {
currentRootPixmap = *((Pixmap *) data);
XFree(data);
}
}
return currentRootPixmap;
}
int main(int argc, const char *argv[])
{
int screen;
Window root;
Display* display;
XWindowAttributes attrs;
Pixmap bg;
XImage* img;
2) {
if (argc < "Usage: %s [filename]\n", argv[0]);
fprintf(stderr, 1;
return
}
"DISPLAY"));
display = XOpenDisplay(getenv(
if (display == NULL) {"cannot connect to X server %s\n",
fprintf(stderr, "DISPLAY") ? getenv("DISPLAY") : "(default)");
getenv(1;
return
}
screen = DefaultScreen(display);
root = RootWindow(display, DefaultScreen(display));
XGetWindowAttributes(display, root, &attrs);
bg = GetRootPixmap(display, &root);0, 0, attrs.width, attrs.height, ~0, ZPixmap);
img = XGetImage(display, bg,
XFreePixmap(display, bg);
if (!img) {"Can't create ximage\n");
fprintf(stderr, 1;
return
}
24) {
if (img->depth != "Image depth is %d. Must be 24 bits.\n", img->depth);
fprintf(stderr, 1;
return
}
1])) {
if (write_jpeg(img, argv["JPEG file successfully written to %s\n", argv[1]);
printf(
}
XDestroyImage(img);
0;
return }