Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
#define _POSIX_C_SOURCE 199309L
//#define DEBUG
#include <Imlib2.h>
#include <X11/Xatom.h>
#include <X11/Xlib.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
typedef struct {
Window root;
Pixmap pixmap;
Imlib_Context *render_context;
int width, height;
} Monitor;
void setRootAtoms(Display *display, Monitor *monitor) {
Atom atom_root, atom_eroot, type;
unsigned char *data_root, *data_eroot;
int format;
unsigned long length, after;
atom_root = XInternAtom(display, "_XROOTMAP_ID", True);
atom_eroot = XInternAtom(display, "ESETROOT_PMAP_ID", True);
// doing this to clean up after old background
if (atom_root != None && atom_eroot != None) {
XGetWindowProperty(display, monitor->root, atom_root, 0L, 1L, False,
AnyPropertyType, &type, &format, &length, &after,
&data_root);
if (type == XA_PIXMAP) {
XGetWindowProperty(display, monitor->root, atom_eroot, 0L, 1L, False,
AnyPropertyType, &type, &format, &length, &after,
&data_eroot);
if (data_root && data_eroot && type == XA_PIXMAP &&
*((Pixmap *)data_root) == *((Pixmap *)data_eroot))
XKillClient(display, *((Pixmap *)data_root));
}
}
atom_root = XInternAtom(display, "_XROOTPMAP_ID", False);
atom_eroot = XInternAtom(display, "ESETROOT_PMAP_ID", False);
// setting new background atoms
XChangeProperty(display, monitor->root, atom_root, XA_PIXMAP, 32,
PropModeReplace, (unsigned char *)&monitor->pixmap, 1);
XChangeProperty(display, monitor->root, atom_eroot, XA_PIXMAP, 32,
PropModeReplace, (unsigned char *)&monitor->pixmap, 1);
}
int main(int argc, char *argv[]) {
#ifdef DEBUG
fprintf(stdout, "Loading images");
#endif
Imlib_Image images[] = {
imlib_load_image("/home/alecs/Repos/paperview/scenes/castle/out-0.bmp"),
imlib_load_image("/home/alecs/Repos/paperview/scenes/castle/out-1.bmp"),
imlib_load_image("/home/alecs/Repos/paperview/scenes/castle/out-2.bmp"),
imlib_load_image("/home/alecs/Repos/paperview/scenes/castle/out-3.bmp"),
imlib_load_image("/home/alecs/Repos/paperview/scenes/castle/out-4.bmp"),
imlib_load_image("/home/alecs/Repos/paperview/scenes/castle/out-5.bmp"),
imlib_load_image("/home/alecs/Repos/paperview/scenes/castle/out-6.bmp"),
imlib_load_image("/home/alecs/Repos/paperview/scenes/castle/out-7.bmp"),
};
int images_count = 8;
#ifdef DEBUG
fprintf(stdout, "Loading monitors\n");
#endif
Display *display = XOpenDisplay(NULL);
if (!display) {
fprintf(stderr, "Could not open XDisplay\n");
exit(42);
}
const int screen_count = ScreenCount(display);
#ifdef DEBUG
fprintf(stdout, "Found %d screens\n", screen_count);
#endif
Monitor *monitors = malloc(sizeof(Monitor) * screen_count);
for (int current_screen = 0; current_screen < screen_count;
++current_screen) {
#ifdef DEBUG
fprintf(stdout, "Running screen %d\n", current_screen);
#endif
const int width = DisplayWidth(display, current_screen);
const int height = DisplayHeight(display, current_screen);
const int depth = DefaultDepth(display, current_screen);
Visual *vis = DefaultVisual(display, current_screen);
const int cm = DefaultColormap(display, current_screen);
#ifdef DEBUG
fprintf(stdout, "Screen %d: width: %d, height: %d, depth: %d\n",
current_screen, width, height, depth);
#endif
Window root = RootWindow(display, current_screen);
Pixmap pixmap = XCreatePixmap(display, root, width, height, depth);
monitors[current_screen].width = width;
monitors[current_screen].height = height;
monitors[current_screen].root = root;
monitors[current_screen].pixmap = pixmap;
monitors[current_screen].render_context = imlib_context_new();
imlib_context_push(monitors[current_screen].render_context);
imlib_context_set_display(display);
imlib_context_set_visual(vis);
imlib_context_set_colormap(cm);
imlib_context_set_drawable(pixmap);
imlib_context_set_color_range(imlib_create_color_range());
imlib_context_pop();
}
#ifdef DEBUG
fprintf(stdout, "Loaded %d screens\n", screen_count);
#endif
#ifdef DEBUG
fprintf(stdout, "Starting render loop");
#endif
struct timespec timeout;
timeout.tv_sec = 0;
timeout.tv_nsec = 33000000;
for (int cycle = 0; cycle < 10; ++cycle) {
Imlib_Image current = images[cycle % images_count];
for (int monitor = 0; monitor < screen_count; ++monitor) {
Monitor *c_monitor = &monitors[monitor];
imlib_context_push(c_monitor->render_context);
imlib_context_set_dither(1);
imlib_context_set_blend(1);
imlib_context_set_image(current);
imlib_render_image_on_drawable(0, 0);
setRootAtoms(display, c_monitor);
XKillClient(display, AllTemporary);
XSetCloseDownMode(display, RetainTemporary);
XSetWindowBackgroundPixmap(display, c_monitor->root, c_monitor->pixmap);
XClearWindow(display, c_monitor->root);
XFlush(display);
XSync(display, False);
imlib_context_pop();
}
nanosleep(&timeout, NULL);
}
}
@glouw

This comment has been minimized.

Copy link

@glouw glouw commented Aug 2, 2020

Very pretty. I like how you got rid of SDL2 entirely and made it purely X11. This will be very portable. I'll link to this in my README if you are okay with that?

@AlecsFerra

This comment has been minimized.

Copy link
Owner Author

@AlecsFerra AlecsFerra commented Aug 2, 2020

Very pretty. I like how you got rid of SDL2 entirely and made it purely X11. This will be very portable. I'll link to this in my README if you are okay with that?

For sure but performance wise it's worst I'm trying to figure out a way to reintroduce SDL

@glouw

This comment has been minimized.

Copy link

@glouw glouw commented Aug 2, 2020

ah okay. I assume most of the work is being done by the CPU with X11 libraries. SDL2 stores its SDL_Texture images on GPU memory, which makes image copying and image resizing to the screen very cheap

@jmi2k

This comment has been minimized.

Copy link

@jmi2k jmi2k commented Aug 3, 2020

Would one of Xorg's extensions allow you to upload the textures to the GPU instead? No problem with SDL though, just thinking that a pure Xorg solution would also be desirable.

@glouw

This comment has been minimized.

Copy link

@glouw glouw commented Aug 3, 2020

Yes I agree on that. Almost all my projects rely on SDL2, so it feels at home. Alec's solution hits very close to home though.

@sdhand

This comment has been minimized.

Copy link

@sdhand sdhand commented Aug 3, 2020

You could almost certainly use the XRender extension to do this efficiently, but the API isn't especially nice or well documented.

@heapslip

This comment has been minimized.

Copy link

@heapslip heapslip commented Aug 3, 2020

@glouw and @AlecsFerra thanks for this!
It works pretty ok when not recording (https://gist.ro/animatedwallpaper.mp4) even at 2560x1440, it would be awesome to juice out a bit more performance.

@Rodrigo-Barros

This comment has been minimized.

Copy link

@Rodrigo-Barros Rodrigo-Barros commented Aug 9, 2020

hey anyone can give any tip about how compile this?
when I try the terminal says:
/usr/bin/ld: animated_wallpaper.c:(.text+0x6c1): undefined reference for "XClearWindow"
I'm trying compile with this command: gcc animated_wallpaper.c

@jmi2k

This comment has been minimized.

Copy link

@jmi2k jmi2k commented Aug 9, 2020

@Rodrigo-Barros Try with gcc -lX11 animated_wallpaper.c

@Rodrigo-Barros

This comment has been minimized.

Copy link

@Rodrigo-Barros Rodrigo-Barros commented Aug 10, 2020

@jmi2k thanks , I have tried again and now its working, I only change cycle < 10 to cycle < images_count, I forget replace the imlib_load_image content, and I was receiving warnings on terminal my fault, and again thank you.

@plasmoduck

This comment has been minimized.

Copy link

@plasmoduck plasmoduck commented Sep 19, 2020

How do I use this instead of the other version?

✗ doas gcc -lX11 animated_wallpaper.c
/usr/local/bin/ld: /tmp//ccbPBjeP.o: in function main': animated_wallpaper.c:(.text+0x1ff): undefined reference to imlib_load_image'
/usr/local/bin/ld: animated_wallpaper.c:(.text+0x210): undefined reference
to imlib_load_image' /usr/local/bin/ld: animated_wallpaper.c:(.text+0x221): undefined reference to imlib_load_image'
/usr/local/bin/ld: animated_wallpaper.c:(.text+0x232): undefined reference
to imlib_load_image' /usr/local/bin/ld: animated_wallpaper.c:(.text+0x243): undefined reference to imlib_load_image'
/usr/local/bin/ld: /tmp//ccbPBjeP.o:animated_wallpaper.c:(.text+0x254): more undefined references to imlib_load_image' follow /usr/local/bin/ld: /tmp//ccbPBjeP.o: in function main':
animated_wallpaper.c:(.text+0x448): undefined reference to imlib_context_new' /usr/local/bin/ld: animated_wallpaper.c:(.text+0x46b): undefined reference to imlib_context_push'
/usr/local/bin/ld: animated_wallpaper.c:(.text+0x477): undefined reference
to imlib_context_set_display' /usr/local/bin/ld: animated_wallpaper.c:(.text+0x483): undefined reference to imlib_context_set_visual'
/usr/local/bin/ld: animated_wallpaper.c:(.text+0x490): undefined reference
to imlib_context_set_colormap' /usr/local/bin/ld: animated_wallpaper.c:(.text+0x49c): undefined reference to imlib_context_set_drawable'
/usr/local/bin/ld: animated_wallpaper.c:(.text+0x4a1): undefined reference
to imlib_create_color_range' /usr/local/bin/ld: animated_wallpaper.c:(.text+0x4a9): undefined reference to imlib_context_set_color_range'
/usr/local/bin/ld: animated_wallpaper.c:(.text+0x4ae): undefined reference
to `imlib_context_pop'
/usr/local/bin/ld: animated_wallpaper.c:(.text+0x52a): undefined reference

@Rodrigo-Barros

This comment has been minimized.

Copy link

@Rodrigo-Barros Rodrigo-Barros commented Sep 19, 2020

@plasmoduck First you need see if you have all libs in your system like the Imlib2, I'm using Ubuntu focal fossa, so if you running the same distro like me you can install running: $ sudo apt install libimlib2-dev .
For compiling I use this code: $ gcc animated_wallpaper.c -lX11 -lImlib2, and one last tip change the contents of line 61 ownwards to match your pc wallpaper location, I hope helps.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.