flow-wm 0.1.0

A scrolling, infinite-horizontal-canvas tiling window manager for Windows
Documentation
#:schema ./schemas/flow-rules.schema.json



# Default window classification rules for FlowWM.

#

# This file is embedded into flowd.exe at compile time (via `include_str!`) and

# provides sensible defaults for common Windows system windows that should NOT

# be tiled. It does NOT ship as a separate runtime file. Users can override

# any of these rules by adding their own rules in flow-rules.toml (which is

# checked first).

#

# Format: first match wins. Each rule has a "match" clause (AND logic) and

# an "action" (tile, float, or ignore).

#

# For match field documentation, see the MatchRule docstring in src/config/types.rs.



default_action = "float"



# ── Windows Shell ────────────────────────────────────────────────────



# Windows taskbar — primary monitor.

[[rules]]

match = { class = "Shell_TrayWnd" }

action = "ignore"



# Windows taskbar — secondary monitors. On multi-monitor setups explorer creates

# one taskbar window per additional monitor under a distinct class

# (`Shell_SecondaryTrayWnd`, NOT `Shell_TrayWnd`). It is a top-level, visible,

# titled, non-cloaked, ownerless shell surface, so it passes every pre-filter

# gate exactly like the primary taskbar above — without this rule the secondary

# taskbar registers as Floating and gets a border overlay drawn around it.

# Class-only match: same race-free rationale as the primary taskbar rule.

[[rules]]

match = { class = "Shell_SecondaryTrayWnd" }

action = "ignore"



# WinUI / XAML Islands desktop content bridge — an invisible helper window

# (title "DesktopWindowXamlSource") created by WinUI 3 / XAML Islands hosts

# (Settings, Photos, the Run box, …). It passes flow's visibility/Alt+Tab/owner

# gates but is never a real app window the user would want tiled, so ignore it

# by class (race-free).

[[rules]]

match = { class = "Windows.UI.Composition.DesktopWindowContentBridge" }

action = "ignore"



# Windows 11 Start Menu host. The actual start menu runs in

# StartMenuExperienceHost.exe (NOT ShellExperienceHost.exe below, which hosts

# the older shell surfaces). Its popup surface is a top-level

# `Xaml_WindowedPopupClass` window titled "PopupHost" that passes every gate,

# so without this rule it is classified Floating and gets a border drawn around

# the start menu.

[[rules]]

match = { exe = "StartMenuExperienceHost.exe" }

action = "ignore"



# XAML windowed-popups — the class used by the Start Menu popup, Action Center

# flyouts, jump lists, and other OS-level XAML popups. All are transient system

# surfaces, never app windows. Ignored by class (race-free) so any host gets

# covered regardless of its exe name.

[[rules]]

match = { class = "Xaml_WindowedPopupClass" }

action = "ignore"



# Windows Search overlay — Windows 10 (`SearchUI.exe`).

[[rules]]

match = { exe = "SearchUI.exe" }

action = "ignore"



# Windows Search overlay — Windows 11 22H2+ (`SearchHost.exe`). Win11 split the

# search UI out of `SearchUI.exe` into `SearchHost.exe`, so the Win10 rule above

# no longer catches it. The surface is a top-level, titled, non-cloaked-while-

# open, ownerless popup that passes every gate, so without this rule it gets

# floated and bordered whenever the user opens Search.

[[rules]]

match = { exe = "SearchHost.exe" }

action = "ignore"



# Older shell-experience host (Action Center / Cortana surfaces). The modern

# Start Menu is hosted by StartMenuExperienceHost.exe, handled above.

[[rules]]

match = { exe = "ShellExperienceHost.exe" }

action = "ignore"



# Windows Action Center / Quick Settings / notification toasts

[[rules]]

match = { exe = "ShellExperienceHost.exe", class = "Windows.UI.Core.CoreWindow" }

action = "ignore"



# ── System Dialogs ──────────────────────────────────────────────────



# Common Win32 dialog boxes (Open/Save As, Properties, etc.)

[[rules]]

match = { class = "#32770" }

action = "ignore"



# ── Explorer ────────────────────────────────────────────────────────



# Windows Explorer file open/save dialogs

[[rules]]

match = { exe = "explorer.exe", class = "CabinetWClass" }

action = "ignore"



# Explorer's internal content tab — the surface where files actually render

# when navigating. A child of CabinetWClass that passes flow's pre-filters;

# floating it draws the border overlay over the file list (blank-page bug).

[[rules]]

match = { exe = "explorer.exe", class = "ShellTabWindowClass" }

action = "ignore"



# WinUI non-client input sink — invisible helper for pointer/pen routing,

# created by Explorer, Settings, Photos, and any WinUI 3 host. Never a real

# app window. (Same rationale as the DesktopWindowContentBridge rule above.)

[[rules]]

match = { class = "InputNonClientPointerSource" }

action = "ignore"



# ── Task Manager ────────────────────────────────────────────────────



# Task Manager's main window — the real top-level surface the user interacts

# with. Float it so it stays where the user places it instead of entering the

# tiling layout. Scoped to its class so the auxiliary helper windows below do

# not also match this rule.

[[rules]]

match = { exe = "Taskmgr.exe", class = "TaskManagerWindow" }

action = "float"



# Task Manager auxiliary helper windows. The WinUI Task Manager (Taskmgr.exe)

# creates several internal surfaces besides its main window: an acrylic

# backdrop ("Glass Window", class GlassWindow), a "Filter Control Glass

# Window", and a "TaskManagerMain" native HWND host (class NativeHWNDHost).

# Each passes flow's visibility/Alt+Tab/owner gates — they are top-level,

# titled, and owner-less — yet none is a window the user would want floated or

# tiled. Without these rules every helper registers as Floating and gets its

# own border overlay + a 180ms animation when Task Manager opens. Scoped to exe

# so a legitimate app reusing one of these classes is unaffected.

[[rules]]

match = { exe = "Taskmgr.exe", class = "GlassWindow" }

action = "ignore"



[[rules]]

match = { exe = "Taskmgr.exe", class = "FilterControlGlassWindow" }

action = "ignore"



[[rules]]

match = { exe = "Taskmgr.exe", class = "NativeHWNDHost" }

action = "ignore"



# ── Accessibility ───────────────────────────────────────────────────



# On-Screen Keyboard

[[rules]]

match = { class = "OSKMainClass" }

action = "ignore"



# Magnifier

[[rules]]

match = { exe = "Magnify.exe" }

action = "ignore"



# Narrator

[[rules]]

match = { exe = "Narrator.exe" }

action = "ignore"



# ── Custom Apps ───────────────────────────────────────────────────



[[rules]]

match = { exe = "Surfshark.exe" }

action = "float"



[[rules]]

match = { exe = "Addictive Keys.exe" }

action = "float"



[[rules]]

match = { exe = "steamwebhelper.exe", title = "Friends List" }

action = "float"



# ── Powertoys ───────────────────────────────────────────────────



[[rules]]

match = { exe = "Microsoft.CmdPal.UI.exe" }

action = "float"



# ── Chromium-based apps (Chrome, Edge, VS Code, Electron, ...) ──────



# Chromium "Legacy Window" — an invisible helper (class

# `Chrome_RenderWidgetHostHWND`, title "Chrome Legacy Window") created by every

# Chromium-based host: Chrome, Edge, VS Code (Electron), Slack, Discord, etc.

#

# It passes the Win32 pre-filters (WS_VISIBLE, non-empty title, no owner, not

# DWM-cloaked) yet is never shown to the user, so it must be ignored.

#

# Why match by `class` instead of `exe` + `title`?

# - `exe` differs per host (chrome.exe vs Code.exe vs msedge.exe ...), so an

#   exe-constrained rule only ever catches one app. The class name is identical

#   across all of them, so a single rule covers every Chromium host.

# - The class is assigned at window creation, while the title may be set a few

#   milliseconds later. Class matching is therefore race-free; title matching

#   can miss a window classified at creation time before its title arrives.

#

# This also kills the layout/animation churn caused by the transient legacy

# windows that Chrome spawns and destroys whenever a tab is opened or closed —

# ignored windows never enter the tiling layout, so no recalculation fires.

[[rules]]

match = { class = "Chrome_RenderWidgetHostHWND" }

action = "ignore"



# ── Chrome.exe ──────



# Chrome picture-in-picture overlay — keep it floating.

[[rules]]

match = { exe = "chrome.exe", title = "Picture in picture" }

action = "float"



# Chrome auxiliary toolbar window. chrome.exe creates a top-level window titled

# "ToolbarWindow32" — the name of the predefined Win32 comctl32 toolbar control

# class. It passes every pre-filter gate (visible, titled, Alt+Tab visible, no

# owner, not minimized) yet is an invisible helper, not a browser surface, so

# without this rule it registers as Floating and gets a border overlay.

#

# Why scope to `exe`? `ToolbarWindow32` is a universal control class name: any

# legacy Win32 app using a standard comctl32 toolbar produces a window whose

# text/class is "ToolbarWindow32". Matching on the title alone would catch

# legitimate toolbar controls in other apps, so the rule is confined to

# chrome.exe to target only Chrome's helper and leave other apps untouched.

[[rules]]

match = { exe = "chrome.exe", title = "ToolbarWindow32" }

action = "ignore"



# ── WindowsTerminal.exe ──────



# For Windows Terminal on git commit / Create Git Worktree 

[[rules]]

action = "float"



[rules.match]

exe = "WindowsTerminal.exe"

class = "CASCADIA_HOSTING_WINDOW_CLASS"