Skip to content

Instantly share code, notes, and snippets.

@digitalsignalperson
Last active June 20, 2023 09:07
Show Gist options
  • Save digitalsignalperson/11183814a20f9491380285151d31588d to your computer and use it in GitHub Desktop.
Save digitalsignalperson/11183814a20f9491380285151d31588d to your computer and use it in GitHub Desktop.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <X11/Xlib.h>
#include <X11/extensions/shape.h>
#include <X11/Xatom.h>
// Enable clickthrough, transparency, and always on top for a given window
// x-clickthrough <windowid> <alpha (0-100)>
//
// alpha < 100 will enable window always on top and enable clickthrough
// alpha = 100 will disable window always on top and disable clickthrough
//
// Compile with:
// gcc x-clickthrough.c -o x-clickthrough -lX11 -lXext
//
// Examples:
// x-clickthrough $(wmctrl -l | fzf | awk '{print $1}') 50
// wmctrl -lx | awk '$3 ~ /mpv/ { print $1 }' | xargs -I {} x-clickthrough {} 50 # enable for all mpv windows
// wmctrl -lx | awk '$3 ~ /mpv/ { print $1 }' | xargs -I {} x-clickthrough {} 100 # disable for all mpv windows
void setTransparency(Display *display, Window window, int level) {
Atom opacityAtom = XInternAtom(display, "_NET_WM_WINDOW_OPACITY", False);
unsigned long opacityValue = (unsigned long)((double)level / 100.0 * 0xffffffff);
XChangeProperty(display, window, opacityAtom, XA_CARDINAL, 32, PropModeReplace, (unsigned char *)&opacityValue, 1);
}
void setAlwaysOnTop(Display *display, Window window, int enable) {
Atom netWmStateAbove = XInternAtom(display, "_NET_WM_STATE_ABOVE", False);
Atom netWmState = XInternAtom(display, "_NET_WM_STATE", False);
XClientMessageEvent ev;
memset(&ev, 0, sizeof(ev));
ev.type = ClientMessage;
ev.display = display;
ev.window = window;
ev.message_type = netWmState;
ev.format = 32;
ev.data.l[0] = enable ? 1 : 0;
ev.data.l[1] = netWmStateAbove;
ev.data.l[2] = 0;
XSendEvent(display, DefaultRootWindow(display), False, SubstructureRedirectMask | SubstructureNotifyMask, (XEvent *)&ev);
XSync(display, False);
}
void setClickthrough(Display *display, Window window, int enable) {
if (enable) {
XRectangle rect = {0, 0, 0, 0};
Region region = XCreateRegion();
XUnionRectWithRegion(&rect, region, region);
XShapeCombineRegion(display, window, ShapeInput, 0, 0, region, ShapeSet);
XDestroyRegion(region);
} else {
XShapeCombineMask(display, window, ShapeInput, 0, 0, None, ShapeSet);
}
}
int main(int argc, char *argv[]) {
if (argc < 3) {
fprintf(stderr, "Usage: %s <windowid> <alpha (0-100)>\nSet alpha to 100 to disable clickthrough.\n", argv[0]);
return 1;
}
Window window = strtoul(argv[1], NULL, 0);
int level = atoi(argv[2]);
Display *display = XOpenDisplay(NULL);
if (display == NULL) {
fprintf(stderr, "Failed to open display\n");
return 1;
}
setTransparency(display, window, level);
setClickthrough(display, window, level < 100);
setAlwaysOnTop(display, window, level < 100);
if (level == 100)
XRaiseWindow(display, window);
XCloseDisplay(display);
return 0;
}
@digitalsignalperson
Copy link
Author

inspired by mpv-player/mpv#8949

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment