A minimal Wayland screenshot tool with a true screen freeze built from scratch in C.
No swaybg, no swaylock, no wayfreeze, no grim for the freeze — pure Wayland protocol code.
Two components:
| File | Role |
|---|---|
myfreeze.c |
C program: captures screen + displays frozen overlay |
myshot.sh |
Shell script: drives the freeze + runs slurp/grim |
- Connects to Wayland and binds all required protocols
- Queries the output's fractional scale via
wp-fractional-scale-v1 - Captures the screen directly using
zwlr_screencopy_frame_v1into awl_shmbuffer backed by amemfd— no temp file, nogrim - Creates a
zwlr_layer_surface_v1on theOVERLAYlayer stretched fullscreen - Attaches a
wp_viewportand sets destination = logical output size so the buffer maps 1:1 to physical pixels — pixel-perfect on HiDPI/fractional scaled displays - Sets an empty input region so pointer/keyboard events pass through to
slurp - Registers a
wl_surface.framecallback — waits until the compositor has actually rendered the frame (no blind sleep) - Prints its PID to stdout so the shell knows the freeze is on screen
- Blocks on stdin — shell closes the pipe to unfreeze
- On unfreeze: destroys the layer surface, commits a null surface, two
roundtrips so the compositor fully redraws the real desktop, exits
myfreeze (capture + freeze) -> slurp (select region) -> unfreeze -> grim (capture region)
| Protocol | Source | Purpose |
|---|---|---|
zwlr-screencopy-v1 |
wlr-protocols | Capture screen content directly |
zwlr-layer-shell-v1 |
wlr-protocols | Fullscreen overlay surface |
wp-fractional-scale-v1 |
wayland-protocols/staging | Get exact HiDPI scale factor |
wp-viewporter |
wayland-protocols/stable | Pixel-perfect buffer-to-screen mapping |
xdg-shell |
wayland-protocols/stable | Required by wlr-layer-shell |
| Package | Purpose |
|---|---|
grim |
Area/fullscreen screenshot after selection |
slurp |
Interactive region selector |
wl-clipboard |
wl-copy for clipboard |
wayland-client |
Wayland protocol library |
wlr-protocols |
zwlr-screencopy + zwlr-layer-shell XMLs |
wayland-protocols |
fractional-scale + viewporter + xdg-shell XMLs |
wayland-scanner |
Generates C glue from protocol XMLs |
notify-send |
Desktop notifications (libnotify) |
sudo pacman -S wayland wayland-protocols wayland-utils grim slurp wl-clipboard
yay -S wlr-protocolsmakeThis will:
- Auto-detect all protocol XML paths on your system using
find - Run
wayland-scannerto generate C glue for all 5 protocols - Compile
myfreeze(only dependency:wayland-client)
make autoinstallInstalls:
myfreeze→~/.local/bin/myfreezemyshot.sh→~/.local/bin/myshot
make autocleanmake install # install without rebuilding
make uninstall # remove from ~/.local/bin/
make clean # remove binary + generated protocol filesmyshot # fullscreen screenshot, save to ~/Pictures/ + copy to clipboard
myshot -c # fullscreen, clipboard only
myshot -a # area select, save to ~/Pictures/ + copy to clipboard
myshot -a -c # area select, clipboard onlyOutput files are saved as ~/Pictures/Shot_YYYYMMDD_HHMMSS.png.
Add to your mangoWC config:
bind = SUPER SHIFT, p, exec, myshot -a
bind = SUPER SHIFT, s, exec, myshot
.
├── myfreeze.c # screen capture + freeze overlay (C, Wayland native)
├── myshot.sh # screenshot orchestration script (bash)
├── Makefile # build system
└── README.md # this file
The following files are generated by make and not tracked by git:
wlr-screencopy-unstable-v1-client-protocol.h
wlr-screencopy-unstable-v1-client-protocol.c
wlr-layer-shell-unstable-v1-client-protocol.h
wlr-layer-shell-unstable-v1-client-protocol.c
fractional-scale-v1-client-protocol.h
fractional-scale-v1-client-protocol.c
viewporter-client-protocol.h
viewporter-client-protocol.c
xdg-shell-client-protocol.h
xdg-shell-client-protocol.c
myfreeze