Grid Tiling for KWin: automatic window tiling on KDE Plasma
A kwin script that automatically tiles windows
At a glance
- What is it?
- Grid-Tiling-Kwin is a KWin script that tiles windows onto a configurable grid, per screen and per virtual desktop, and adds drag and drop movement plus a large set of global shortcuts. It is a declarative script installed by symlink rather than through kpackagetool, and its behaviour is driven mostly by regex matching on window properties.
- Who is it for?
- Grid Tiling for KWin suits a KDE Plasma user who wants tiling windows without switching desktop environments or installing a compositor level tiling manager, and the per screen and per desktop grid configuration plus the regex based window rules cover the cases a plain grid does not.
- Can I use it commercially?
- Yes, with conditions. GPL-3.0 is a copyleft licence: if you distribute software that includes it, you must release that software's source code under the same licence. Running it internally without distributing it does not trigger that obligation.
- Is it still maintained?
- Yes. The repository last received commits 62 days ago.
- What is it written in?
- Mainly JavaScript, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.
Editorial analysis
A declarative KWin script installed with two symlinks
Grid-Tiling-Kwin is a kwin script that automatically tiles windows. The repository is small: a contents/ directory holding the script code, a metadata.json file, the LICENSE, and the README you are reading now.
Installation is deliberately manual, and the reason is documented. The readme states that kpackagetool6 is at this moment of writing broken and unable to install declarative kwin scripts without a main.js file. So instead of a package install, you create the directory and link the two files in.
mkdir -p ~/.local/share/kwin/scripts/grid-tiling
cd ~/.local/share/kwin/scripts/grid-tiling
ln -s <path>/contents
ln -s <path>/metadata.jsonThe placeholder path is the path to this repository on your machine. Uninstalling is the reverse: delete the linked or copied files you created during installation. If you want the script for every user on the system, the same process applies against /usr/share instead of ~/.local/share.
Because it is a declarative script rather than one with a main.js, the code lives under contents/ as QML, and the repository topics list qml and plasma alongside kwin and javascript. The script is then activated from the system settings, which is also where the configuration button lives.
That last point has a consequence worth flagging early. When you adjust settings in the menu, the script needs to be restarted before the settings are applied. The readme gives the procedure: turn the script off, apply, turn it back on and apply again, or do a complete KWin restart by re-logging or rebooting. Configuration is therefore not live in the way most users expect.
Where a new window goes, and when it does not get tiled
The core behaviour is that windows are tiled automatically onto a grid, with a custom grid size per desktop and per screen. The ordering rules are what make this usable rather than merely neat.
New windows are first attempted to be added to the desktop and screen that the application itself set. So a window that opens on a particular virtual desktop stays there, which respects what the application asked for.
If there is insufficient space, the script automatically tries other screens first, then other desktops, and ultimately resorts to not tiling the new window if none of them have space.
That cascade is the detail most tiling implementations get wrong. Trying screens before desktops keeps a window on the physical display you are looking at, and only moves it to another virtual desktop as a last resort, which is where the user's attention is not.
The overflow behaviour is defined too. The script can handle more windows than there is space for, but once all desktops and screens are full, all new windows start as floating instead of tiling, until there is space again to tile new windows. Floating is the graceful fallback rather than a window disappearing off the grid.
Inside the grid, movement is done by drag and drop and by global shortcuts. Windows can be moved between desktops, screens and activities, resized, and minimized, with the script providing additional shortcuts for each of those, including one to toggle minimization for all windows on a desktop at once.
Grid sizes per screen and per desktop, all comma separated
Grid size is configured on a per screen basis using a comma separated list of integers in the configuration user interface.
The readme gives the example: rows=2,2 and colums=2,3 results in screen 1 being 2x2 and screen 2 being 2x3. Note that the key in the example is spelled colums, which is how the configuration interface presents it, and the two lists are indexed by screen number. Rows and columns for screens that were not defined default to the first element of the list, so a single screen setup is just a one element list and a two screen setup adds a second.
Desktop rows, columns and names define overrides based on matching the desktop name using regex. That is the mechanism for a different layout on a particular virtual desktop, for example a desktop named work getting a 2x1 grid while the rest use 2x2.
The regex matching is done with the JavaScript RegExp class, built from the string the user provides, and the test method is applied to the window class property, equivalent to RegExp(config).test(window.resourceName). The readme explains how to find the value for these properties on a window by opening the Windows Operations Menu, and points at the min space section of the configuration interface for examples.
The same mechanism is used for the blacklist and whitelist of windows excluded from tiling, and for the minimum space restriction, which matches based on regex as well. A size of 1 is the largest and fully takes up a desktop, size of 2 means it takes up at least half of the virtual desktop, and so on. That limit is how you stop a small always-on-top panel from taking a quarter of the grid.
Global shortcuts, and the stale registration problem after an update
The recommended shortcut table is long, and it shows how much of the script's value is in keyboard control rather than in the tiling itself.
The Grid Tiling entries cover movement with Meta+Ctrl and the arrow keys, size changes with Meta+= for increase, Meta+- for decrease, Meta++ for maximize and Meta+\_ for minimize, and toggles for the gap with Meta+G, the border with Meta+B, and tiling versus floating with Meta+T. There is also Meta+R to refresh and Meta+Ctrl+R to reset.
Some entries override standard KWin bindings. Meta+End and Meta+Home move a window to the next or previous desktop, Meta+Space toggles the overview, and Meta+W closes the window. If you use those keys for something else, the script will win, or you will have to change them.
The update problem is the part worth understanding. The readme explains that after updates some of the shortcuts may have been renamed, but KWin still keeps the old ones registered. Removing them takes a specific sequence: disable the script first, then go to the shortcuts settings window and use the delete button on the KWin application entry that contains the script's shortcuts, restart KWin, and activate the script again.
That is a real operational cost of the shortcut-driven design. A user upgrading the script a few times ends up with a shortcuts panel full of dead entries unless they do that cleanup, and the wrong entry will still fire.
There is also a note for people with one screen only. The readme suggests repurposing the KWin shortcuts for moving windows between screens so they can move between desktops instead, trading away the screen moving shortcuts for more flexibility in the grid. That is a reasonable trade for a laptop, and it is the kind of decision the configuration interface exists to support.
Version coupling, logging and the force option
This version of the script uses the latest KWin API methods, and the readme says that if you are using an older version of KWin you should choose the appropriate branch. That is the main compatibility constraint, and it is a hard one: the script talks to KWin signals and geometry APIs that shift between Plasma releases.
Logging is available from the system log, and the readme gives the Wayland example directly, using journalctl with the _COMM filter set to kwin_wayland.
journalctl _COMM=kwin_waylandThat is the first thing to reach for when tiling misbehaves, because a script that manipulates window geometry silently is hard to debug by watching the screen.
The force option is the documented remedy for the other common complaint, applications that change the geometry of windows on their own. The readme says that if you have trouble with other applications changing the geometry of windows you may try the force option. Screen edges can also be configured to move windows between virtual desktops when dragged, and the focus policy can be configured to follow the cursor.
The licence field on the repository says GPL-3.0, and the root carries a LICENSE file. That is a strong copyleft licence, and it matters in a way it does not for most scripts, because a script like this is often copied, modified and redistributed between users. This is not legal advice, but the obligation to distribute modifications under the same terms is the part to read before you fork it and share your fork.
Editorial conclusion
Grid Tiling for KWin suits a KDE Plasma user who wants tiling windows without switching desktop environments or installing a compositor level tiling manager, and the per screen and per desktop grid configuration plus the regex based window rules cover the cases a plain grid does not. It does not suit anyone on GNOME or other desktops, since it depends on KWin specific APIs and signals, and the script needs to be restarted after settings changes, which is a friction the documentation openly admits. Before installing, check that you are on a recent KWin version, since the current branch uses the latest KWin API methods and older versions need a different branch, and read the shortcuts list, because upgrades can leave stale entries registered in the KWin shortcuts panel.
Frequently asked questions
How do I install the Grid Tiling KWin script?
Create ~/.local/share/kwin/scripts/grid-tiling, change into it and symlink the contents directory and metadata.json from the repository. The manual route is used because the readme states kpackagetool6 is currently broken and unable to install declarative kwin scripts without a main.js file.
How do I configure the grid size per screen in Grid-Tiling-Kwin?
Use a comma separated list of integers in the configuration user interface, where screen rows and columns define the defaults per screen. For example rows=2,2 and colums=2,3 gives screen 1 a 2x2 grid and screen 2 a 2x3 grid, and undefined screens default to the first element.
Why are my new Grid-Tiling-Kwin settings not applied?
The script needs to be restarted after you change settings. The readme describes turning the script off, applying, turning it back on and applying again, or performing a complete KWin restart by re-logging or rebooting.
How do I exclude a window from tiling in Grid-Tiling-Kwin?
Use the blacklist and whitelist options, which match windows with a regex. Matching is done with the JavaScript RegExp class and the test method against the window class property, equivalent to RegExp(config).test(window.resourceName), and the window resource name can be found through the Windows Operations Menu.
Which KWin version does the current Grid-Tiling-Kwin branch support?
The current version of the script uses the latest KWin API methods, and the readme says that if you are on an older version of KWin you should choose the appropriate branch. The repository has no GitHub releases and the last push was on 2026-08-22.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/lingtjien-grid-tiling-kwin)Was this useful?