Skip to content

Instantly share code, notes, and snippets.

@jvns
Created December 3, 2019 21:02
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jvns/d5a0a4daf300f3dd7fa76d13b5aa2d53 to your computer and use it in GitHub Desktop.
Save jvns/d5a0a4daf300f3dd7fa76d13b5aa2d53 to your computer and use it in GitHub Desktop.
#include <X11/Xlib.h>
#include <unistd.h>
#include <assert.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdlib.h>
// change this to your terminal emulator of choice
#define TERM_PATH "/usr/bin/termite"
#define TERM "termite"
// catch BadWindow errors that occur in the main loop
// when a window exits and ignore them
// you may consider this a hack, I don't :^)
int dummy_error_handler(Display *dpy, XErrorEvent *ev) {
return 0;
}
int main() {
Display *dpy;
Window root, *children = NULL, tmp_root, tmp_parent;
XWindowAttributes attr;
XEvent ev;
unsigned int nchildren = 0;
int root_width, root_height;
if(!(dpy = XOpenDisplay(0)))
return 1;
root = DefaultRootWindow(dpy);
XGetWindowAttributes(dpy, root, &attr);
root_width = attr.width;
root_height = attr.height;
pid_t term_pid = fork();
if (!term_pid) {
execl(TERM_PATH, TERM, NULL);
}
assert(term_pid != -1);
sleep(1); // give the terminal some time to spawn a window
int *move_x = NULL,
*move_y = NULL;
XSetErrorHandler(dummy_error_handler);
while(1) {
for (unsigned int i = 0; i < nchildren; i++) {
if (children[i]) {
if (XGetWindowAttributes(dpy, children[i], &attr) == BadWindow)
continue;
int new_x = attr.x + move_x[i],
new_y = attr.y + move_y[i];
XMoveWindow(dpy, children[i], new_x, new_y);
if (new_x <= 0 || (new_x + attr.width) >= root_width)
move_x[i] = -move_x[i];
if (new_y <= 0 || (new_y + attr.height) >= root_height)
move_y[i] = -move_y[i];
}
}
if (children)
XFree(children);
unsigned int new_nchildren;
// Xorg doesn't like us giving it NULLs for root_return and parent_return
// (IMO it should, instead it segfaults in the library), even though we don't need them
XQueryTree(dpy, root, &tmp_root, &tmp_parent, &children, &new_nchildren);
if (new_nchildren > nchildren) {
move_x = realloc(move_x, new_nchildren * sizeof(int));
move_y = realloc(move_y, new_nchildren * sizeof(int));
for (unsigned int i = nchildren; i < new_nchildren; i++) {
move_x[i] = 1; // right
move_y[i] = 1; // down
}
}
nchildren = new_nchildren;
int wstatus;
if(waitpid(term_pid, &wstatus, WNOHANG))
return wstatus; // terminal has exitted, pass on it's return status
usleep(16000);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment