Repository navigation
Releases: GGEZUS/niri-tablet
Release list
v26.04.20
niri v26.04 + 20 patches (was 18). A breaking gesture rename, a new gesture pair, a GUI configurator, and a smarter auto-rotate helper.
Breaking: gesture nodes renamed
tap-4 / swipe-4-up / swipe-4-down are now tap-more / swipe-more-up / swipe-more-down, and they apply at one finger more than touchscreen-swipe.fingers (4 by default) instead of a hardcoded four. fingers itself is now restricted to 3 or 4, enforced at parse time.
Configs from v26.04.18 or earlier that still use the old names fail validation on this build. Run ./update-niri-tablet.sh and answer y when it offers the rename: one dated .bak per touched file, undone unless niri validate passes on the whole include chain. Or open EasySetup and save once. Either way, rename before your next login, or the session starts on niri's default config with an error notification until the file is fixed.
New
swipe-more-left/swipe-more-right: quick horizontal flicks with one finger more than the base count now run discrete actions, like the vertical ones. Unbound (the shipped default) they keep the horizontal drag's behavior (resize-column or move-view).- EasySetup, a GTK4/libadwaita configurator: pick actions from installed apps or a curated catalog, test-run them live, import/export schemes, and save only what
niri validateaccepts.cargo build --releaseinniri-tablet-easysetup/; details in the EasySetup wiki page. - Tablet-mode gate in niri-rotate.sh: on 2-in-1s the auto-rotate helper stays idle in laptop mode and catches up when folded into a tablet. ThinkPad and HP convertibles detected automatically;
NIRI_ROTATE_TABLET_MODE_SYSFSfor other vendors,NIRI_ROTATE_TABLET_MODE_ONLY=noto disable. Machines without a switch are untouched. - The shipped
config/gestures.kdlis now the full scheme the author runs daily: hold-swipes move windows, the bottom edge toggles the OSK, a 4-finger flick up toggles fullscreen.
Changed
- The updater detects old gesture names in
~/.config/niriafter installing and offers the rename (--yesreports without editing). - New 60-second demo video.
The 20 patches
feat(input): add touchscreen 3-finger swipe gesturesfeat(config): add touchscreen-swipe gesture configurationdocs: document touchscreen swipe gesturesfeat(input): touchscreen tap and bottom-edge swipe gesturesfeat(input): discrete 4-finger vertical swipe gesturesfix(input): count late-joining fingers and fix deadlock in discrete swipestest(config): refresh the parse insta snapshot for the touchscreen gesture fieldsfeat(ui): show-touch-points: compositor-rendered touch point visualizationfeat(input): hold-swipe touchscreen gestures: move windows with a held swipefix(input): own multi-finger touch sequences: gestures stop leaking to appsfix(input): latch gesture ownership through smithay's implicit touch grabfix(input): clear touch gesture state when a touch device is removedfeat(input): gesture debug logging behind gestures debug-logfeat(input): single-finger edge and corner swipe gesturesdocs: document touchscreen edge and corner swipe gesturesfix(test): edge-swipe test helper rectangle constructionfeat(input): horizontal swipe column-resize modedocs: document the touchscreen-swipe action optionsfeat(gestures): derive the tap/flick tier from fingersfeat(gestures): swipe-more-left/right for extra-finger flicks
v26.04.18: edge & corner swipes and live width resize
niri v26.04 + 18 patches, installed as niri-tablet 26.04.18.
New since v26.04.13:
Edge and corner swipes (one finger). A finger swiping inward from a
screen edge, or diagonally out of a corner, runs any niri action. Four
edge zones and four corner zones, each bound on its own:
touchscreen-edge-swipe {
bottom { spawn-sh "~/.local/bin/niri-osk.sh"; }
top { toggle-overview; }
left { focus-column-left; }
right { focus-column-right; }
}Edges trigger on a 40px perpendicular-dominant stroke starting within
48px of the edge; corners need a genuinely diagonal 20px stroke, so a
mostly-straight swipe near a corner still does nothing and the adjacent
edges stay usable. Taps and short drags in the strips keep reaching
apps, unbound zones are inert, and bindings apply live without a
re-login.
Breaking change: the old touchscreen-edge-swipe { spawn ...; } form no
longer parses (it never worked on hardware); use the per-zone children
shown above.
Live width resize on the 3-finger horizontal drag. New mode:
touchscreen-swipe {
horizontal-swipe "resize-column"
}Instead of scrolling the view, the horizontal drag now widens or
narrows the focused window, tracking your fingers 1:1: drag right to
widen, left to narrow; the width stops when you stop and stays where
you lift. It rides niri's own interactive-resize machinery (the same one
Mod+right-click uses), so the resize is smooth, respects window min/max
sizes, and works on floating windows too. The default remains
"move-view" (the animated scroll), and a drag with nothing focused falls
back to it.
Example config rewritten. config/gestures.kdl carried too much
comment noise; it now states only what earns its place (the
fingers/*-4 tier relationship, the nesting of the edge/corner blocks).
No semantic changes.
Also in this release: the wiki documents every touchscreen-swipe node
(previously only fingers/off were listed), and an edge-swipe test
helper that failed to compile in the test profile was fixed.
Verified on hardware on both a Microsoft Surface Go 2 and a ThinkPad
T480: the resize mode, all four edge zones, the fallbacks, and app
delivery in the edge strips.
The full niri test suite passes (236 tests, plus the config and
wiki-doc suites), and the 18-patch series applies cleanly over the
v26.04 tag.
Install
Arch Linux: easiest, with the bundled updater:
git clone https://github.com/GGEZUS/niri-tablet.git
cd niri-tablet
./update-niri-tablet.shManual equivalent:
cd niri-tablet/pkg
makepkg -si # builds upstream niri + patches; replaces stock niriUpgrading: ./update-niri-tablet.sh (or git pull && makepkg -si), then
log out and back in. Other distros: the series is plain patch/git am
cargo build; see the
README.
NixOS: bump rev in the fetchFromGitHub block to v26.04.18
(the hash will change with it; leave it empty once and Nix prints the
right one).
Patch series (changelog)
feat(input): add touchscreen 3-finger swipe gesturesfeat(config): add touchscreen-swipe gesture configurationdocs: document touchscreen swipe gesturesfeat(input): touchscreen tap and bottom-edge swipe gesturesfeat(input): discrete 4-finger vertical swipe gesturesfix(input): count late-joining fingers and fix deadlock in discrete swipestest(config): refresh the parse insta snapshot for the touchscreen gesture fieldsfeat(ui): show-touch-points — compositor-rendered touch point visualizationfeat(input): hold-swipe touchscreen gestures — move windows with a held swipefix(input): own multi-finger touch sequences — gestures stop leaking to appsfix(input): latch gesture ownership through smithay's implicit touch grabfix(input): clear touch gesture state when a touch device is removedfeat(input): gesture debug logging behind gestures debug-logfeat(input): single-finger edge and corner swipe gesturesdocs: document touchscreen edge and corner swipe gesturesfix(test): edge-swipe test helper rectangle constructionfeat(input): horizontal swipe column-resize modedocs: document the touchscreen-swipe action options
Each rebase onto a new niri release gets a new tag (v<niri-version>.<patch-count>,
matching the installed pkgver) and appends its changes here.
v26.04.13 — gesture debug logging (bug-report helper)
niri v26.04 + 13 patches, installed as niri-tablet 26.04.13.
New in this release: gestures { debug-log }, a bug-report helper.
If a gesture misbehaves, the flag turns on per-event logging of the
touchscreen gesture stack: every finger down/up/motion with slot ids,
positions and timestamps, the recognition decision (finger count,
direction, hold vs quick), and the action dispatched for taps, discrete
swipes and edge swipes. Every line is prefixed gesture-debug: and
written at info level, so a plain journalctl excerpt is enough to debug
a repro remotely:
journalctl --user -u niri.service --since -10m | grep gesture-debugOff by default, no behavior change to the gestures themselves. Toggling
it works live: save the config and the flag applies from the next touch
(no re-login). Running niri from a terminal instead? The same lines go
to its stderr. Details in the README, section "Gesture debug logging".
Why it exists: the first external bug report (4-finger gestures acting
as 3-finger ones on some hardware) needs exactly this stream to
diagnose. If you hit a gesture bug, please enable the flag, reproduce
it a few times, and attach the collected lines to your issue; it makes
these fixable from a distance.
The full niri test suite passes (227 tests, plus the config and
wiki-doc suites), and the 13-patch series applies cleanly over the
v26.04 tag.
Install
Arch Linux: easiest, with the bundled updater:
git clone https://github.com/GGEZUS/niri-tablet.git
cd niri-tablet
./update-niri-tablet.shManual equivalent:
cd niri-tablet/pkg
makepkg -si # builds upstream niri + patches; replaces stock niriUpgrading: ./update-niri-tablet.sh (or git pull && makepkg -si), then
log out and back in. Other distros: the series is plain patch/git am
cargo build; see the
README.
NixOS: bump rev in the fetchFromGitHub block to v26.04.13
(the hash will change with it; leave it empty once and Nix prints the
right one).
Patch series (changelog)
feat(input): add touchscreen 3-finger swipe gesturesfeat(config): add touchscreen-swipe gesture configurationdocs: document touchscreen swipe gesturesfeat(input): touchscreen tap and bottom-edge swipe gesturesfeat(input): discrete 4-finger vertical swipe gesturesfix(input): count late-joining fingers and fix deadlock in discrete swipestest(config): refresh the parse insta snapshot for the touchscreen gesture fieldsfeat(ui): show-touch-points — compositor-rendered touch point visualizationfeat(input): hold-swipe touchscreen gestures — move windows with a held swipefix(input): own multi-finger touch sequences — gestures stop leaking to appsfix(input): latch gesture ownership through smithay's implicit touch grabfix(input): clear touch gesture state when a touch device is removedfeat(input): gesture debug logging behind gestures debug-log
Each rebase onto a new niri release gets a new tag (v<niri-version>.<patch-count>,
matching the installed pkgver) and appends its changes here.
v26.04.12 — touch-device removal no longer wedges the session
v26.04.12 — touch-device removal no longer wedges the session
niri v26.04 + 12 patches, installed as niri-tablet 26.04.12.
If a touchscreen vanished mid-gesture — a USB crash-loop, an unplug, any
hotplug hiccup — three wedges persisted until the next re-login:
touch_input_suspendednever cleared (it only clears on the last
finger's lift, which never came), so every touch of the re-enumerated
device was swallowed: touch stayed dead for the rest of the session;- any installed gesture grab stayed on the touch handle, eating future
touches; - touches already delivered to an app never got their lift — the same
stuck-phantom-touch class v26.04.11 fixed (apps ignoring taps and
clicks until restarted).
The fix (patch 0012): on_device_removed now runs the same teardown
on_touch_cancel performs — synthetic lifts + frame for client-visible
touches, grab release, both tracker resets, suspension cleared,
touch-point overlay dropped — before the seat's touch handle is
destroyed. The moment the device returns (a crash-looping touchscreen
usually re-enumerates within seconds), touch works again. No re-login,
no phantom touches.
Found in the wild: a T480 whose Raydium touchscreen entered a ~5.5 s USB
disconnect loop mid-session — touch dead for the whole session and apps
eating touchpad clicks until restarted. Post-fix, the full gesture set
verified on the same machine, and the full niri test suite (227 tests)
passes.
Install
Arch Linux — easiest, with the bundled updater (added right after this
release; git pull once if your clone predates it):
git clone https://github.com/GGEZUS/niri-tablet.git
cd niri-tablet
./update-niri-tablet.sh # fetch → changelog → build → install → pin IgnorePkgManual equivalent:
cd niri-tablet/pkg
makepkg -si # builds upstream niri + patches; replaces stock niriUpgrading: ./update-niri-tablet.sh (or git pull && makepkg -si), then log
out and back in. Other distros: the series is plain patch/git am +
cargo build — see the
README.
Patch series (changelog)
feat(input): add touchscreen 3-finger swipe gesturesfeat(config): add touchscreen-swipe gesture configurationdocs: document touchscreen swipe gesturesfeat(input): touchscreen tap and bottom-edge swipe gesturesfeat(input): discrete 4-finger vertical swipe gesturesfix(input): count late-joining fingers and fix deadlock in discrete swipestest(config): refresh the parse insta snapshot for the touchscreen gesture fieldsfeat(ui): show-touch-points — compositor-rendered touch point visualizationfeat(input): hold-swipe touchscreen gestures — move windows with a held swipefix(input): own multi-finger touch sequences — gestures stop leaking to appsfix(input): latch gesture ownership through smithay's implicit touch grabfix(input): clear touch gesture state when a touch device is removed
Each rebase onto a new niri release gets a new tag (v<niri-version>.<patch-count>,
matching the installed pkgver) and appends its changes here.
v26.04.11 — phantom-touch fix
v26.04.11 — phantom-touch fix
niri v26.04 + 11 patches, installed as niri-tablet 26.04.11.
This release fixes the phantom-touch bug introduced by the gesture-ownership
patch: after 3/4-finger gestures, apps (browsers especially) kept believing
extra fingers were still on screen — a single-finger scroll pinch-zoomed, taps
were ignored — until the app was restarted.
Root cause: smithay installs an implicit TouchDownGrab on every delivered
touch-down, so is_grabbed() is true from the first finger that lands on an
app window. The ownership latch required "not grabbed", so over app surfaces it
never fired: every finger of the gesture streamed to the app, and the gesture
grab then swallowed their lifts — stuck touches, with touch ids reused while
stuck (double-downs on the wire).
The fix (patch 0011): the latch treats the implicit grab as "no grab" and
drops it when the compositor takes over, ending the already-delivered touches
with synthetic lifts + a frame. A hardware touch-cancel now ends client-visible
touches the same way (smithay's TouchHandle::cancel() is a silent no-op for
frame-flushed slots), and the edge-swipe lift is frame-finalized.
Verified on a ThinkPad touchscreen (Raydium) and a Surface Go 2 (IPTS):
WAYLAND_DEBUG captures show every gesture ending app-visible touches cleanly
— zero double-downs, zero stuck touches, at most two app-visible fingers per
gesture (nine phantoms before the fix). Capture logs are in
bugreports/phantom-touch-20260824/.
Install
Arch Linux:
git clone https://github.com/GGEZUS/niri-tablet.git
cd niri-tablet/pkg
makepkg -si # builds upstream niri + patches; replaces stock niriUpgrading: git pull && makepkg -si, then log out and back in. Other distros:
the series is plain patch/git am + cargo build — see the
README.
Patch series (changelog)
feat(input): add touchscreen 3-finger swipe gesturesfeat(config): add touchscreen-swipe gesture configurationdocs: document touchscreen swipe gesturesfeat(input): touchscreen tap and bottom-edge swipe gesturesfeat(input): discrete 4-finger vertical swipe gesturesfix(input): count late-joining fingers and fix deadlock in discrete swipestest(config): refresh the parse insta snapshot for the touchscreen gesture fieldsfeat(ui): show-touch-points — compositor-rendered touch point visualizationfeat(input): hold-swipe touchscreen gestures — move windows with a held swipefix(input): own multi-finger touch sequences — gestures stop leaking to appsfix(input): latch gesture ownership through smithay's implicit touch grab
Each rebase onto a new niri release gets a new tag (v<niri-version>.<patch-count>,
matching the installed pkgver) and appends its changes here.
v26.04.10 — first release
First release of the niri-tablet patchset: niri v26.04 + 10 patches, installed as niri-tablet 26.04.10.
Tablet/touchscreen support for niri: multi-finger
window-management gestures, an on-screen keyboard helper that adapts to screen
orientation, and automatic display rotation — everything needed to run a niri
session with the keyboard detached.
The gesture set
| Gesture | Action |
|---|---|
| 3-finger drag, horizontal | scroll the view across columns (animated) |
| 3-finger drag, vertical | workspace carousel (animated) |
| 3-finger tap | maximize / restore the focused column |
| 3-finger hold + swipe | move the focused window: left/right a column, up/down a workspace |
| 4-finger tap | window overview (built-in; any launcher binds in its place) |
| 4-finger flick down | close the focused window |
| 4-finger flick up | toggle the on-screen keyboard (needs the OSK script) |
Every gesture is configurable — each node takes any niri action, same as
keybinds. Multi-finger gestures are owned by the compositor: apps never see
them, so a 3-finger swipe doesn't pinch-zoom a browser or drag-select terminal
text mid-gesture. Single- and two-finger input (including app pinch-zoom) and
touchpad behavior are untouched.
Install
Arch Linux:
git clone https://github.com/GGEZUS/niri-tablet.git
cd niri-tablet/pkg
makepkg -si # builds upstream niri + patches; replaces stock niriOther distros: the series is plain patch/git am + cargo build — see the
README.
Patch series (changelog)
feat(input): add touchscreen 3-finger swipe gesturesfeat(config): add touchscreen-swipe gesture configurationdocs: document touchscreen swipe gesturesfeat(input): touchscreen tap and bottom-edge swipe gesturesfeat(input): discrete 4-finger vertical swipe gesturesfix(input): count late-joining fingers and fix deadlock in discrete swipestest(config): refresh the parse insta snapshot for the touchscreen gesture fieldsfeat(ui): show-touch-points — compositor-rendered touch point visualizationfeat(input): hold-swipe touchscreen gestures — move windows with a held swipefix(input): own multi-finger touch sequences — gestures stop leaking to apps
Each rebase onto a new niri release gets a new tag (v<niri-version>.<patch-count>,
matching the installed pkgver) and appends its changes here.