Skip to content

TheDave94/kwin-snap-zones

Repository files navigation

Snap Zones — KDE Plasma 6 Wayland

Configurable snap zones for ultrawide (or any) monitors on KDE Plasma 6 Wayland.
Snap active windows to left / center / right zones with Meta+Shift+Arrow.
Auto-place configured apps into their zone when they open.

Works around all the Plasma 6 shortcut breakage:
registerShortcut() removed · khotkeys removed · kglobalaccel won't run shell commands · swhkd grabs the device


Requirements

  • KDE Plasma 6 on Wayland
  • qdbus6 (part of qt6-tools, usually already installed)
  • Python 3 + evdev: pip install --user evdev or sudo pacman -S python-evdev
  • User in the input group: sudo usermod -aG input $USER (log out/in after)

Install

Always clone from the canonical URL to avoid typosquatting:

git clone https://github.com/TheDave94/kwin-snap-zones
cd kwin-snap-zones
./install.sh

The installer:

  1. Verifies file checksums (CHECKSUMS.sha256) before touching anything
  2. Detects your WAYLAND_DISPLAY automatically
  3. Copies the KWin script to ~/.local/share/kwin/scripts/snap-zones/
  4. Installs the listener daemon to ~/.local/share/kwin-snap-zones/
  5. Creates and enables two systemd user services
  6. Runs a D-Bus connectivity smoke test and reports the result

Default Zones

Zone Shortcut Width
Left Meta+Shift+Left 20%
Center Meta+Shift+Up 60%
Right Meta+Shift+Right 20%

Designed for a 49" ultrawide (32:9). Adjust ratios in main.js.

Customize

Change zone ratios — edit ~/.local/share/kwin/scripts/snap-zones/contents/code/main.js:

const LEFT_RATIO   = 0.25;   // 25% left
const CENTER_RATIO = 0.50;   // 50% center
const RIGHT_RATIO  = 0.25;   // 25% right

Auto-place apps — add window class names to the lists in main.js:

const AUTO_LEFT   = ['Alacritty', 'org.kde.dolphin'];
const AUTO_CENTER = ['vivaldi-stable', 'firefox'];
const AUTO_RIGHT  = ['telegram-desktop'];

Find window class names:

  1. Enable spy mode in main.js: set const SPY_MODE = true
  2. Reload: systemctl --user restart snap-zones-autoplace.service
  3. Open any app and watch: journalctl --user -f | grep SNAP_ZONES_SPY
  4. Disable spy mode again when done (SPY_MODE = false)

After any edit, reload:

systemctl --user restart snap-zones-autoplace.service

Uninstall

./uninstall.sh

This stops the services, unloads the KWin script from the running session, and removes all installed files.

Security & Privacy

evdev read scope

The listener daemon reads raw EV_KEY events from all keyboards in order to detect modifier+key combinations. It does not log, store, or transmit any keystrokes. Only Meta+Shift+Arrow combos trigger any action — a local D-Bus call to KWin to move the active window.

You can audit the full source in listener.py. It is ~200 lines with no network calls, no file writes during operation, and no external dependencies beyond evdev and the Python standard library.

Spy mode and window captions

SPY_MODE in main.js logs window class names to help you configure auto-placement. It deliberately does not log window captions (document titles, URLs, etc.) to avoid journald retaining private data. Spy mode is off by default — enable it only during setup.

Input group requirement

Adding your user to the input group grants read access to all input devices (/dev/input/event*). This is a standard requirement for any Wayland-compatible hotkey daemon. The same group is required by tools like wev, libinput, and various other input utilities.

How It Works

Two components work together:

KWin script (main.js) — loaded once at login via a oneshot systemd service. Installs a windowAdded hook for auto-placement.

Listener daemon (listener.py) — monitors raw keyboard input via evdev without grabbing the device (all other apps still receive input normally). On Meta+Shift+Arrow, calls KWin via D-Bus using the absolute path to qdbus6 (resolved at startup, not via PATH).

Meta+Shift+Left
       │
       ▼
listener.py (evdev non-grabbing, single instance via PID file)
       │  /usr/bin/qdbus6 loadScript left.js
       │  /usr/bin/qdbus6 start
       ▼
KWin D-Bus /Scripting
       │
       ▼
left.js: w.frameGeometry = { x, y, width: 20%, height: 100% }

Why Not a Pure KWin Script?

registerShortcut() was silently removed in Plasma 6. KWin scripts can still run JS and manipulate windows — they just can't bind keyboard shortcuts anymore. The evdev listener is the only reliable cross-app shortcut mechanism on Plasma 6 Wayland that doesn't grab the input device.

Troubleshooting

Shortcuts don't fire:

systemctl --user status snap-zones-listener.service
journalctl --user -u snap-zones-listener.service
# If "input group" error: sudo usermod -aG input $USER && reboot

Auto-place not working:

systemctl --user status snap-zones-autoplace.service
journalctl --user -u snap-zones-autoplace.service

Wrong WAYLAND_DISPLAY:

echo $WAYLAND_DISPLAY   # note the value
# Edit the service file:
systemctl --user edit snap-zones-listener.service
# Add: Environment=WAYLAND_DISPLAY=wayland-0  (or whatever yours is)
systemctl --user restart snap-zones-listener.service

License

MIT

About

Configurable snap zones for KDE Plasma 6 Wayland — Meta+Shift+Arrow shortcuts + auto-placement on window open

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors