Open-source project
gerritdevriese/kzones avatar
gerritdevriese/kzones

KZones gives KDE a FancyZones-style zone layout

KDE KWin Script for snapping windows into zones

706 stars56 forksQMLGPL-3.0

At a glance

What is it?
KZones is a KWin script for KDE Plasma that snaps windows into zones the way PowerToys FancyZones does on Windows, with a drag overlay, a zone selector, edge snapping and JSON-defined layouts. The layouts are plain JSON in the script settings, and a zone can name the applications it prefers, which is the feature that makes a mixed-workflow desktop workable.
Who is it for?
Adopt KZones if you run KDE Plasma and want the window arrangement behaviour that FancyZones provides on Windows, especially on an ultrawide where the default tiling leaves you guessing where a window went. Skip it if you are on GNOME or Windows, since this is a KWin script and has no meaning outside Plasma, and if you want a maintained project with a regular release stream, because the version line moves slowly.
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 46 days ago.
What is it written in?
Mainly QML, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 20, 2026, and from our analysis. They are not legal advice.

Editorial analysis

A KWin script, which decides what it can and cannot do

KZones is a KDE KWin Script for snapping windows into zones, described as handy when using a super or ultrawide monitor, and as an alternative to PowerToys FancyZones and the Windows 11 snap layouts.

Calling it a KWin script is the whole architectural story. KWin scripts are how third parties extend the window manager in Plasma, and the consequence is that anything the script does is bounded by what the KWin scripting API exposes. A zone layout is therefore a composition of window geometry operations that the compositor performs, not a compositor replacement.

That explains the shape of the feature set. There is no tiling engine, no virtual desktop manager, no per-application rules engine beyond what the layout JSON expresses. The script moves windows into rectangles and gets out of the way.

The distribution routes reflect the same constraint. The project is on the KDE Store, in the AUR as kwin-scripts-kzones, and in nixpkgs as kdePackages.kzones, and the homepage points at the store listing. The primary language is QML, which is the scripting language KWin scripts use, and the licence is GPL-3.0.

The last push was on 2026-09-07 with release v0.9.2 from 2026-02-20, after v0.9.1 from 2025-10-11 and v0.9 from 2024-09-11, so the version line moves slowly.

Three ways to get a window into a zone

There are three interaction mechanisms, and they differ in when they appear and how much they demand of the user.

The Zone Selector is a small widget that appears when you drag a window to the top of the screen, and it allows you to snap the window to a zone regardless of the current layout. It is the lightweight path, and the setting for it controls the distance from the top of the screen at which the selector starts to appear.

The Zone Overlay is a fullscreen overlay that appears when you move a window. It shows all zones from the current layout, and the window snaps to the zone you drop it on. Two settings shape it: whether the overlay is shown when you start moving a window or when you press the toggle overlay shortcut, and where the cursor needs to be in order to highlight a zone, either in the center of the zone or anywhere inside it. There is also a choice of whether the indicator displays all zones or only the highlighted one.

Edge Snapping allows you to snap windows to zones by dragging them to the edge of the screen, and the setting for it controls the distance from the edge at which it starts to appear.

The overlay is the richest of the three, and the hover behaviour is where the tuning matters. Requiring the cursor to be in the center of a zone makes accidental snaps less likely; requiring it anywhere inside is faster but twitchier.

There is one dependency between the mechanisms and the desktop. The documentation says to make sure to disable the default edge snapping functionality before enabling this, which is a real conflict rather than a formality, since both want the same gesture.

Layouts are JSON you can edit in the settings dialog

Layouts are defined as JSON in the Layouts tab of the script settings, and the documentation says you can define your own layouts by modifying that JSON.

The simple example is three zones across the screen:

json
[
  {
    "name": "Layout 1",
    "padding": 0,
    "zones": [
      {
        "x": 0,
        "y": 0,
        "height": 100,
        "width": 25
      },
      {
        "x": 25,
        "y": 0,
        "height": 100,
        "width": 50
      },
      {
        "x": 75,
        "y": 0,
        "height": 100,
        "width": 25
      }
    ]
  }
]

The coordinates are percentages, which is what makes a layout resolution independent. A zone at x 25, width 50 means the middle half of the screen at any resolution, so the same layout works on a 1080p monitor and an ultrawide without editing.

The advanced example shows two things a simple one cannot. A zone can carry an `applications` list, so a zone is reserved for a particular program:

json
      {
        "x": 25,
        "y": 0,
        "height": 100,
        "width": 50,
        "applications": ["firefox"]
      }

And a single JSON array can hold several named layouts, the Priority Grid, the Quadrant Grid and the Columns example, which you cycle between. The main array can contain as many layouts as you want, and each layout object needs a `name`, which is the name of the layout shown when cycling between layouts, and a `padding` value alongside the zone list.

The application-specific zone is the feature that makes this usable day to day. A layout that dedicates the middle half of the screen to a browser and puts everything else in the sides is a workflow rule expressed in geometry, and it is the kind of thing FancyZones users expect and which a plain tiling window manager will not do.

The per-screen and per-application behaviours are where the edges are

Several of the general settings are about how the script behaves when the desktop is more complicated than one screen with one window.

Track active layout per screen lets you enable it if you have multiple monitors, and the documentation says this allows you to have different active layouts on different screens. That is a small feature with a large effect on an ultrawide setup, where the main display and a secondary one rarely want the same arrangement.

Automatically snap all new windows makes the script snap a new window to its closest zone when it launches. The note attached to it is the one to read: if you enable this, you should probably add some filters to exclude certain applications from being snapped, like games or other applications that don't work well with tiling. Spectacle is given as a good example, as it won't be able to take screenshots of the entire screen when it's snapped to a zone.

That example is the general lesson. Tiling and full-screen tools conflict, and the script's answer is that you exclude the conflicting application rather than trying to detect the conflict.

Remember and restore window geometries means the script remembers the geometry of each window when it is moved to a zone, and when the window is moved out of the zone it will be restored to its original geometry. That is a small courtesy that matters in a workflow where you move a window into a zone temporarily and then back out.

Display OSD messages can be disabled if you do not want to see any, and fade windows while moving reduces the opacity of other windows while the active window is being moved, which is a legibility feature rather than a cosmetic one when several zones are highlighted at once.

Installing is a store click, or a make and a kpackagetool

There are two install routes, and the second is the one to read if you want to build it yourself.

The first is the built-in script manager. Go to System Settings / Window Management / KWin Scripts / Get New and search for KZones. Depending on your Plasma version, one of two packages will be downloaded and installed, either KZones or KZones for Plasma 5. That version split is the first thing to check, because installing the Plasma 6 package on Plasma 5 is the kind of thing that fails silently by not appearing in the list.

Building it yourself needs zip on your system first, and then:

sh
git clone https://github.com/gerritdevriese/kzones
cd kzones && make

The Makefile shows what the build actually does, and it is a good deal more than zipping a folder.

The package name is `kzones.kwinscript`, and the build target packages the `src` directory into it with zip. The install target then runs `kpackagetool6 --type=KWin/Script -i` on the package, falling back to an upgrade of the same package if the install fails, which is how you reinstall over an existing version. The uninstall target removes it by name with `kpackagetool6 --type=KWin/Script -r`.

Enabling and disabling are separate from installing, and they go through the KWin configuration file rather than the package tool. The enable target writes `kzonesEnabled true` into the Plugins group of kwinrc with `kwriteconfig6` and then asks KWin to reconfigure over D-Bus with `qdbus org.kde.KWin /KWin reconfigure`. The disable target writes the same key as false and reconfigures in the same way.

The remaining targets are for development. There is a restart-kwin target that replaces the running compositor, choosing `kwin_x11 --replace` or `kwin_wayland --replace` depending on `XDG_SESSION_TYPE`, and a logs target that follows `journalctl` for the X11 compositor or the user journal for the Wayland one, filtered on the QT_CATEGORY values js, qml and kwin_scripting.

The nested session target is how the script gets tested at all

One Makefile target deserves its own section, because it explains how a window manager script can be developed without restarting your desktop.

The start-session target prints Starting nested Wayland session and then runs a shell fragment that unsets LD_PRELOAD, creates a directory under the runtime directory named nested_plasma, and writes a wrapper script into it. The session variables at the top of the Makefile set the shape of it, with a session width of 1920 and a session height of 1080, an output count of 1, a verbose flag, and an applications list that is currently commented out with dolphin, konsole and kate as examples.

That is a nested compositor: a second Plasma session running inside your current one, which lets you reload the script and see the result without touching the session you are working in. For a KWin script, that is the difference between a two-second edit-compile cycle and restarting your compositor on every change.

The session width and height matter for this project in particular, and the reason is that the layouts are defined in percentages. A layout that divides the screen into quarters has to be checked at more than one aspect ratio, and a fixed 1920 by 1080 nested session is the standard shape to test against, with the output count controlling how many screens the nested session presents.

The applications list is the other variable, and its purpose is to decide which windows the nested session should show. Leaving it empty means everything is available, and the commented-out example lists the dolphin file manager, the konsole terminal and the kate editor, which is a sensible minimal set for exercising a window management script.

Editorial conclusion

Adopt KZones if you run KDE Plasma and want the window arrangement behaviour that FancyZones provides on Windows, especially on an ultrawide where the default tiling leaves you guessing where a window went. Skip it if you are on GNOME or Windows, since this is a KWin script and has no meaning outside Plasma, and if you want a maintained project with a regular release stream, because the version line moves slowly. Verify first which Plasma version you have, since the store publishes a separate package for Plasma 5, and that you disable KWin's own edge snapping before enabling KZones', because the documentation says to do that and the two will otherwise fight over the same gesture.

Frequently asked questions

How do I install KZones on KDE Plasma?

Open System Settings, go to Window Management, then KWin Scripts, then Get New and search for KZones. Depending on your Plasma version, either the KZones or the KZones for Plasma 5 package is downloaded and installed. To build it yourself, install zip, clone the repository and run make in the cloned directory.

How do I define my own window layouts in KZones?

Edit the JSON in the Layouts tab of the script settings. The main array holds as many layouts as you want, and each layout has a name, a padding value and a zones list where each zone has x, y, height and width in percentages. A zone can also carry an applications array to reserve that space for specific programs.

What do I need to change before enabling KZones edge snapping?

You need to disable the default KWin edge snapping functionality first, because the two otherwise compete for the same gesture. The script's own edge snapping setting then controls the distance from the edge of the screen at which snapping starts to appear.

Official sources

  1. gerritdevriese/kzones on GitHub
  2. License: GPL-3.0
  3. Project website
  4. README
  5. Releases
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.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/gerritdevriese-kzones.svg)](https://hysenlabs.com/projects/gerritdevriese-kzones)

Was this useful?