Skip to content

Instantly share code, notes, and snippets.

@shmup
Last active January 21, 2025 18:32
Show Gist options
  • Save shmup/19edfe68fa11d2d474b7c600df4f65cf to your computer and use it in GitHub Desktop.
Save shmup/19edfe68fa11d2d474b7c600df4f65cf to your computer and use it in GitHub Desktop.
gcc -o vpets vpets.c -lX11 -lXext
#include <X11/Xatom.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/extensions/shape.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
int main() {
Display *display;
Window window;
XVisualInfo vinfo;
XSetWindowAttributes attr;
GC gc;
XColor color;
Colormap colormap;
int screen;
// circle parameters
int circle_x = 0;
int circle_y = 0;
int circle_dx = 2;
int circle_dy = 2;
int circle_radius = 40;
int circle_diameter = circle_radius * 2;
int window_size = circle_diameter + 20; // the circle's bounding box is offset
// color parameters
unsigned long red = 65535;
unsigned long green = 0;
unsigned long blue = 0;
unsigned long alpha = 32767; // 50% opacity
// animation parameters
int fps = 120;
int sleep_time = 1000000 / fps;
// open a connection to the x server
display = XOpenDisplay(NULL);
if (!display) {
fprintf(stderr, "Cannot open display\n");
return 1;
}
screen = DefaultScreen(display);
// get argb visual
if (!XMatchVisualInfo(display, screen, 32, TrueColor, &vinfo)) {
fprintf(stderr, "No matching visual found\n");
return 1;
}
// create a colormap
colormap = XCreateColormap(display, RootWindow(display, screen), vinfo.visual,
AllocNone);
// set window attributes
attr.colormap = colormap;
attr.background_pixel = 0; // transparent background
attr.border_pixel = 0;
attr.event_mask = StructureNotifyMask;
// create a window
window = XCreateWindow(
display, RootWindow(display, screen), 0, 0, window_size, window_size, 0,
vinfo.depth, InputOutput, vinfo.visual,
CWColormap | CWBackPixel | CWBorderPixel | CWEventMask, &attr);
// set window properties to keep it on top and ignore window manager
Atom window_type = XInternAtom(display, "_NET_WM_WINDOW_TYPE", False);
Atom window_type_dock =
XInternAtom(display, "_NET_WM_WINDOW_TYPE_DOCK", False);
XChangeProperty(display, window, window_type, XA_ATOM, 32, PropModeReplace,
(unsigned char *)&window_type_dock, 1);
XSetWindowAttributes swa;
swa.override_redirect = True;
XChangeWindowAttributes(display, window, CWOverrideRedirect, &swa);
// create a gc
gc = XCreateGC(display, window, 0, NULL);
// set a color with transparency (red, 50% opacity) in the pixel value
// directly
color.pixel = (alpha << 16) | (red << 8) | green;
color.red = red;
color.green = green;
color.blue = blue;
color.flags = DoRed | DoGreen | DoBlue;
XAllocColor(display, colormap, &color);
// create a non-rectangular shape for the window
Pixmap mask = XCreatePixmap(display, window, window_size, window_size, 1);
GC shape_gc = XCreateGC(display, mask, 0, 0);
XSetForeground(display, shape_gc, 0);
XFillRectangle(display, mask, shape_gc, 0, 0, window_size, window_size);
XSetForeground(display, shape_gc, 1);
XFillArc(display, mask, shape_gc, window_size - circle_diameter,
window_size - circle_diameter, circle_diameter, circle_diameter, 0,
360 * 64);
XShapeCombineMask(display, window, ShapeBounding, 0, 0, mask, ShapeSet);
XFreeGC(display, shape_gc);
XFreePixmap(display, mask);
// map the window
XMapWindow(display, window);
// animation loop
while (1) {
// move the circle
circle_x += circle_dx;
circle_y += circle_dy;
// bounce off the edges of the screen
if (circle_x + window_size > DisplayWidth(display, screen) ||
circle_x < 0) {
circle_dx = -circle_dx;
}
if (circle_y + window_size > DisplayHeight(display, screen) ||
circle_y < 0) {
circle_dy = -circle_dy;
}
// clear the window by making a transparent shape
XSetForeground(display, gc, 0);
XFillRectangle(display, window, gc, 0, 0, window_size, window_size);
// set the color and draw the circle
XSetForeground(display, gc, color.pixel);
XFillArc(display, window, gc, window_size - circle_diameter,
window_size - circle_diameter, circle_diameter, circle_diameter, 0,
360 * 64);
// move the window
XMoveWindow(display, window, circle_x, circle_y);
// flush the output buffer
XFlush(display);
// sleep for a short time
usleep(sleep_time);
}
// clean up
XFreeGC(display, gc);
XDestroyWindow(display, window);
XCloseDisplay(display);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment