port of tactile to KDE
  • QML 51.4%
  • JavaScript 35.2%
  • Shell 7.8%
  • Python 4.6%
  • Makefile 1%
Find a file
ciguatera 64980ff6ae Document the layout picker fix, and bring stale docs up to date
The picker fix in 7990a11 went in without a word in DESIGN: why `checked` is
re-bound on click rather than set, why the buttons stay checkable (Breeze
draws no selected state otherwise), and why picking a layout in the editor
switches the screen to it -- the grid behind the pane is the preview.

The README gains an update recipe. `make install` over an installed copy
replaces files under a loaded scene effect, the risk `make uninstall` is built
to avoid, and would not take effect anyway: KWin keeps running the QML it has
loaded, and `make enable` reloads nothing when the effect is already enabled.
So: make disable && make install && make enable.

Also corrected, some older than this work:

  * §6 said 1-4 persist the layout and that tiles match "tile letters"; the
    choice is session-only, and tiles match key specs in two passes
  * §9 still called the next/previous monitor keys hardcoded, though they
    have been configurable since a97fd67
  * §14 described the suite as four scenarios; it is A-V, 33 passing on one
    output, now with a table of what each group covers

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-20 19:41:45 -04:00
docs Document the layout picker fix, and bring stale docs up to date 2026-09-20 19:41:45 -04:00
experiments Let tile keys carry modifiers, and stop the editor stranding the grid 2026-09-20 19:34:16 -04:00
LICENSES Make each layout an editable table, and add SPDX headers 2026-09-20 18:38:54 -04:00
src Let tile keys carry modifiers, and stop the editor stranding the grid 2026-09-20 19:34:16 -04:00
.gitignore Initial commit: Tactile port to KWin as a Plasma 6 scene effect 2026-09-20 14:32:16 -04:00
LICENSE Add GPL-3.0-or-later LICENSE 2026-09-20 14:35:46 -04:00
Makefile Make each layout an editable table, and add SPDX headers 2026-09-20 18:38:54 -04:00
README.md Document the layout picker fix, and bring stale docs up to date 2026-09-20 19:41:45 -04:00
REUSE.toml Make each layout an editable table, and add SPDX headers 2026-09-20 18:38:54 -04:00

tactile-kde

A keyboard-driven window tiler for KDE Plasma 6 on Wayland — a port of the GNOME Shell extension Tactile to KWin.

Press Alt+R to show a grid over the current screen, then type two tile keys (or the same key twice) to move and resize the focused window into the rectangle spanned by those two tiles.

Status: working, tested in a nested compositor; not yet run in a real session. See docs/DESIGN.md for the port design and the evidence behind it.

make install    # package + install via kpackagetool6
make enable     # or: System Settings -> Desktop Effects -> Tactile

./experiments/run-tests.sh            # drive it in a nested compositor; never touches your session
OUTPUTS=2 ./experiments/run-tests.sh  # same, with two virtual monitors
./experiments/run-probe.sh   # the original API probe (docs/DESIGN.md section 13)

Why this exists

Tactile's interaction model is "show a grid, type two corners". Nothing on Plasma offers exactly that:

  • KWin's built-in custom tiling (Meta+T tile editor) snaps with the mouse, or with Meta+arrow keys through a fixed quarter/half layout.
  • MouseTiler is the closest existing KWin script, but it is pointer-driven by design: its overlay is created with Qt.WindowTransparentForInput and it tracks Workspace.cursorPos, so the keyboard is never grabbed.

Reproducing Tactile means holding a modal keyboard grab while an overlay is on screen. On Plasma that is something only a KWin effect can do, which drives the whole design.

Planned behaviour

Key Action
Alt+R Show / hide the grid
Meta+Shift+T Open the layout editor (from anywhere)
, Open the layout editor (while the grid is showing)
Esc Cancel, or close the editor
tile key (Q W E R / A S D F / Z X C V by default) Pick a corner; two picks commit
Space / Shift+Space Move the grid to the next / previous monitor
1–4 Switch the current monitor to layout 1–4

Multiple monitors

Space and Shift+Space walk the grid to the next and previous monitor, wrapping, in the order your outputs are arranged. The grid moves, not the window — the window follows when you pick two tiles, landing on whichever monitor the grid is on. Each monitor remembers which layout it was last using, so one screen can be on a 2×1 split while another is on 4×3.

Each of the four layouts is a table of up to 7 columns × 5 rows, with one key per cell — a letter, or a combination such as Shift+A or Ctrl+Period when the letters run out. Rows and columns carry an integer weight, so tiles can be uneven; a weight of 0 hides that row or column without shifting the keys either side of it. Each monitor remembers which layout it last used. Gap size, border size, text size and colours are configurable, with an option to follow the system accent colour.

Try it without touching your session

./experiments/run-nested.sh

Opens a second compositor in a window on your desktop, with Tactile installed into a throwaway HOME and its own D-Bus session, so Alt+R there never collides with your real shortcuts. Click into the window and press Alt+R. Close the window to end it.

This is the recommended first run: it is the only way to exercise real keystrokes through the keyboard grab without risking your live compositor.

Install for real

make install
make enable

To update an installed copy after pulling or editing, disable it first:

make disable && make install && make enable

make install on an already-installed package replaces its files in place, and doing that under a loaded scene effect is the same risk make uninstall goes out of its way to avoid. It also would not take effect: KWin keeps running the QML it already loaded until the effect is unloaded and loaded again, and make enable alone reloads nothing when the effect was already enabled.

Then find Tactile under System Settings → Window Management → Desktop Effects. It is an effect, not a script, so it does not appear under KWin Scripts — that is deliberate: only an effect can hold the keyboard grab that bare letter keys need.

To remove it:

make uninstall

That disables the effect and waits for KWin to unload it before deleting the files — removing a loaded scene effect out from under a running compositor is a good way to crash kwin_wayland, so don't just rm -rf the package directory.

Changing the shortcut

Alt+R is only the default. Once the effect has been enabled at least once, it registers itself with KWin's global shortcut system, so rebind it in System Settings → Shortcuts → KWin → "Tactile: show tiling grid". Your binding is stored in kglobalshortcutsrc and takes precedence from then on.

There is intentionally no shortcut setting in kwinrc: KGlobalAccel already owns this, and a config entry would silently lose to whatever you set in System Settings.

Note that Alt+R is grabbed globally, so it will shadow any application that uses Alt+R as a menu accelerator. Rebind if that bites.

Settings

The layout editor

Press , while the grid is showing, or Meta+Shift+T from anywhere.

The editor draws over the grid, and the grid redraws as you type, so you are looking at the result while you make it:

┌ Tactile grid layouts ──────────────────  1 │ 2 │ 3 │ 4 ┐
│  Columns: 4   Rows: 2                                  │
│                                                        │
│                1       1       1       1               │
│         1  │   Q   ││   W   ││   E   ││   R   │        │
│         1  │Shift+A││   S   ││   D   ││   F   │        │
│                                                        │
│  Gap between tiles: 0        Reset this layout   Done  │
└────────────────────────────────────────────────────────┘

Set Columns and Rows, and the table resizes to match — that size is the layout's size, stored on its own, not inferred from anything you type. Then put one key in each cell: that is the key which picks that tile. A cell takes a letter, a named key (Space, F5, Period, …), or a combination — Shift+A, Ctrl+Period, Meta+Q — so a table can reach past the letters you have. The tile is labelled with its modifiers set small above the key. The numbers down the left and across the top are each row's and column's share of the screen; 0 hides that row or column. A cell is outlined in red if its key is used twice (only the first such cell can be picked) or if what you typed is not a key at all.

1–4 at the top right pick which layout you are editing, and switch the grid behind the editor to that layout too, so the preview is always the table you are editing. The grid stays on the last layout you edited after you close the editor, just as if you had pressed that number key. Tab moves from cell to cell. Every field applies immediately and is saved when you close the editor.

Done (or Escape) closes the editor. If you opened it over a grid you were already using, you are put back on that grid; if you opened it with Meta+Shift+T, the overlay closes with it.

This lives in the grid rather than in System Settings because the System Settings page is a fixed Qt Designer form with no code behind it, and a table that resizes with a spin box cannot be expressed there.

Everything else

System Settings → Window Management → Desktop Effects → Tactile → ⚙ — colours, sizes, dimming, the in-overlay control keys, and the behaviour options.

The two trigger shortcuts are deliberately not there: they are global shortcuts owned by KGlobalAccel, so they live in System Settings → Shortcuts → KWin (see Changing the shortcut above). Everything else is a key read while the effect holds the keyboard grab, which is why it is an effect setting instead.

Cycling between monitors

Keys tab → Next monitor / Previous monitor. Defaults are Space and Shift+Space.

Editing by hand

Settings are written to kwinrc under [Effect-tactile], so you can equally set them directly — after which qdbus org.kde.KWin /KWin reconfigure applies them without a restart. Each layout is a size plus four lists, and KConfig splits the lists on commas:

[Effect-tactile]
L1Cols=4
L1Rows=2
L1ColWeights=1,1,1,1
L1RowWeights=1,1
L1KeyRow0=q,w,e,r
L1KeyRow1=a,s,d,f

So a Dvorak or Colemak layout is a few lines per layout. A row list may be shorter than the table is wide; cells with no key are simply unreachable. Note that KConfig omits any entry that still matches its default, so a freshly reset layout writes nothing at all.

Every key in this file — the tile keys above and the control keys below — takes an optional Shift+ / Ctrl+ / Alt+ / Meta+ modifier plus a named key (Space, Escape, Tab, Return, Backspace, F1–F12, arrows, Comma, Period, Slash, Plus, …) or any single character. (+ itself has to be spelled Plus, since it is the separator.) A tile row may therefore read L1KeyRow0=Shift+q,Ctrl+w,e,r. The control keys may each list several alternatives:

KeyCancel=Escape Backspace
KeyNextMonitor=Space Tab
KeyPrevMonitor=Shift+Space
KeySettings=Comma
KeyLayout1=1
KeyLayout4=4

Control keys match modifiers exactly, which is what keeps Space and Shift+Space distinct. Tile keys are matched in two passes — the cells that name modifiers first, then the ones that do not — so Shift+A and a can sit in the same table and each pick its own tile, wherever they are in it. A cell that names no modifiers still ignores Shift, so Caps Lock will not stop a tile being picked, but it no longer answers to Ctrl, Alt or Meta.

The full list of settings and defaults is in docs/DESIGN.md § 8.

Development

Never load, unload or test this package in your live Plasma session — unloading a scene effect while it is active has segfaulted kwin_wayland. Use the nested-compositor recipe in docs/DESIGN.md § Testing.

Credits

  • Tactile by lundal — the original extension and the source of the interaction model, grid maths and default key map. GPL-3.0-or-later.
  • MouseTiler by rxappdev — reference for KWin QML packaging, overlay rendering and window geometry handling. GPL-3.0.

License

GPL-3.0-or-later — see LICENSE.

This is a port of Tactile, which is GPL-3.0-or-later, so this project inherits that licence. The port reimplements Tactile's interaction model and grid arithmetic in QML/JavaScript; docs/DESIGN.md additionally quotes KWin, which is GPL-2.0-or-later.