Per-application focus control for KWin — without touching global policy
kwin-focus-helperis a lightweight KWin script with an optional Rust CLI that allows explicitly selected applications to bypass KWin’s focus stealing prevention — while keeping global window behavior unchanged.
It is designed for non-standard launch contexts where legitimate applications are incorrectly treated as focus stealers.
This tool is not a general desktop tweak.
It is intended for users who run applications via:
sandbox wrappers (e.g. proclet, firejail, bubblewrap)
Flatpak or custom containers
privileged or wrapped launchers
security-conscious workflows that alter window ownership or activation flow
If you launch applications normally as a regular user and do not experience focus issues, you probably do not need this tool.
By default,
kwin-focus-helperdoes nothing until explicitly configured.
Runtime
- KDE Plasma (KWin window manager)
Optional (recommended)
qdbus6(or compatibleqdbus) — forfocusctl reconfigureBuild dependencies (only if building from source)
Rust toolchain (
cargo) — forfocusctl
kpackagetool6— only for manual / per-user installs
KWin’s Focus stealing prevention (often set to Medium) is a good global default, but it can break legitimate workflows under certain conditions:
New browser windows opening behind existing ones
Dialogs appearing unfocused
Sandboxed or wrapped applications being misclassified as “suspicious”
Lowering the global setting affects all applications, which is undesirable.
kwin-focus-helpersolves this per application.
Your global KWin focus policy remains unchanged
You define a whitelist of window classes
Only windows matching those classes are allowed to:
raise themselves (
workspace.raiseWindow)receive focus (
workspace.activeWindow)This gives those applications “
Focus stealing = None” behavior — and nothing else.No global overrides. No heuristics. No surprises.
1) 🔹 KWin Script (JavaScript)
Runs inside KWin
Observes:
new windows
activation requests
Applies focus behavior only to whitelisted window classes
2) 🔹
focusctl(optional Rust CLI)A small helper to manage configuration explicitly and safely:
focusctl list-classes focusctl add-class google-chrome-stable focusctl remove-class google-chrome-stable focusctl list-keys
From source
git clone https://github.com/darko5r/kwin-focus-helper.git cd kwin-focus-helper make installInstaller options can be passed via ARGS:
make reinstall ARGS='-y' make install ARGS='--no-focusctl'Verify installation:
make status make testFrom AUR
yay -S kwin-focus-helper
Add one or more window classes that should be allowed to receive focus:
focusctl add-class google-chrome-stable focusctl add-class firefoxNew windows from these applications will now raise and focus correctly, even when global focus stealing prevention is set to Medium.
Manage entries:
focusctl list-classes focusctl remove-class google-chrome-stable
kwin-focus-helperis designed to integrate cleanly with launchers and sandboxing tools.A typical flow:
- Temporarily allow a window class
- Reconfigure KWin
- Launch the wrapped / sandboxed application
- (Optional) remove the class afterward
This enables correct behavior without permanently changing user policy.
focusctl wrap(recommended)For most integrations,
focusctl wrapis the preferred interface.It provides an explicit, minimal boundary between launch logic and KWin behavior.
Explicit class
focusctl wrap ProcletChrome -- google-chrome-stableSandboxed example
focusctl wrap ProcletChrome -- proclet -- google-chrome-stableAutomatic class (derived from argv[0])
focusctl wrap --auto -- google-chrome-stable
Script installs but does not appear or update in KWin
In rare cases, KDE’s service cache may become stale.
You can fully reset the script and rebuild caches:
kpackagetool6 --type=KWin/Script -r kwin-focus-helper rm -rf ~/.local/share/kwin/scripts/kwin-focus-helper rm -f ~/.cache/ksycoca6_* kbuildsycoca6Then reinstall:
make install
Click the target window and run:
xprop WM_CLASSUsually, the second string is the correct class name.