| NEOFLUX(1) | User Commands | NEOFLUX(1) |
neoflux - a Fluxbox-style window manager for X11 with grouping, a slit, and chord keybindings
neoflux [--replace] [--version] [--help]
neoflux is a reparenting window manager for X11, written in Rust, in the spirit of Fluxbox. It wraps each managed window in a decorated frame and adds three signature features:
neoflux is configured entirely through plain-text TOML files in ~/.config/neoflux/, which are re-read live by the reconfigure action. It speaks enough EWMH / ICCCM to cooperate with panels, pagers, wmctrl(1), and xdotool(1).
Any other argument is an error (exit status 2).
On first run neoflux seeds a starter set of files in ~/.config/neoflux/. Any of these you delete is recreated at the next fresh login (not on a restart). All use the same TOML format and are optional; keep everything in config.toml or break pieces out. The files are merged in memory as overlays — there is no file include directive.
Your files are never rewritten, so they drift behind new releases: a missing key simply takes its built-in default, but a [keys] or [chords] table replaces the defaults wholesale, so new default bindings do not reach an existing keys.toml. To catch up, neoflux rewrites ~/.config/neoflux/defaults/ on every fresh start with the reference files shipped in the running binary (the starter set, the themes, and config.example.toml with every key documented) — always current, never read by neoflux, never to be edited. After an upgrade a banner notes how many config changes arrived; neoflux --whats-new lists them, and diff -u defaults/keys.toml keys.toml shows exactly what your file lacks.
A bare key = value line must come before the first [section] header (a TOML rule); sections may then appear in any order. Colours are "#rrggbb" (also "0xrrggbb" or "rrggbb"). Booleans are true / false. An unparseable file is skipped with the rest of the config left intact, and the error is logged and shown in an on-screen banner at startup / reconfigure.
Bare top-level keys (set in config.toml). Appearance keys marked (theme) normally live in theme.toml; setting them in config.toml pins them over the theme.
Edge and window snapping.
Optional. Overrides snap.gap. screen = gap to monitor edges; window = gap between windows. Honored by snap and maximize.
The Fluxbox-style resize handle.
Rounded frame corners (needs the X SHAPE extension; ignored if absent). The border wraps the title bar, so rounding top rounds the title bar's top corners. Maximized / fullscreen windows are always square.
The title-bar look and button layout. Colour / font / height keys are (theme) keys.
Per-button themed images go in [titlebar.buttons.<kind>] tables with image (base), focus, and pressed PNG paths; missing variants fall back to image, and with no image the built-in vector glyph is drawn.
Popup-menu appearance (root, window, and slit menus). Colours come from [titlebar]; only font and font-size (px) are separate, and both default to the title bar's. Row height scales with the font size.
Root (right-click) menu entries; an array of tables. Replaces the default single “Terminal” item. May live in menu.toml instead. Each entry has label plus either command or a nested submenu, and optionally icon:
neoflux-menugen(1) generates a categorized menu.toml (one submenu per application category, with icons) from the installed applications' .desktop files.
Up to four slit definitions (a list replaces the four-edges default). Each has edge (top/right/bottom/left) and optional size (omit = auto-size to the largest dockapp; a number pins a fixed width, min 8). See THE SLIT.
Route dockapps to a slit by WM_CLASS. Each has class and either slit = N or slits = [N, ...] (0-based). With a list, each new instance of the class fills the next listed slit.
Per-window rules (the Fluxbox apps equivalent). Match on class (WM_CLASS class), name (WM_CLASS instance), and/or title (case-insensitive substring); all present matchers must match. Then apply any of: desktop (1-based), sticky, maximized, shaded, above, skip-grouping, decor (none/border/normal), fullscreen (cover/fill: this window's fullscreen policy, overriding the top-level key), x, y, width, height.
Mouse bindings added to the built-in defaults (last match wins, so they override). See MOUSE.
Keyboard bindings and chords. A [keys] / [chords] table replaces the built-in set wholesale. See KEYBINDINGS and CHORDS.
A binding maps a combo to an action: "Mod+Mod+key" = "action". Modifier tokens are super, alt, control (ctrl), shift, and $mod/mod (the configured mod-key); mod4/win and mod1 are accepted aliases. The key is an X keysym name (Tab, Return, Right, F1, a letter/digit, an XF86... multimedia name, or ASCII punctuation by its keysym name — bracketleft, semicolon, grave, as xev(1) prints them — or simply the character itself: [, ;, `. Only + must be spelled plus, since it separates the tokens.) An unrecognized modifier or key name is rejected and logged rather than silently dropped.
Super+Return spawn:xterm Super+Shift+q quit Super+Shift+c close Super+c center-both Super+Tab next-window Super+Shift+Tab prev-window Super+grave next-window:monitor Super+Shift+grave prev-window:monitor Super+Alt+Tab last-window Super+Right next-tab Super+Left prev-tab Super+Control+Right move-tab-right Super+Control+Left move-tab-left Super+Shift+Right desktop-next Super+Shift+Left desktop-prev Super+F1..F4 desktop:1..4 Super+1..4 move-to-desktop:1..4 Super+s shade Super+Shift+s toggle-sticky Super+f fullscreen Super+Shift+f movie Super+m maximize Super+n minimize Super+Shift+l lock-window
With more than four desktops, raise count and add Super+F5.. / Super+5.. bindings to match.
A chord is a leader key followed by a single key from a chord table. Press chord-leader (default Super+x), release, then press a key listed in [chords]. The chord values are the same action strings as keybindings; cancel (or any unbound key) aborts. A bare modifier press never cancels a pending chord, so Super+x followed by a Super+-key works.
Default [chords] (after Super+x):
c close space center-both d detach p picture-in-picture r root-menu m window-menu w window-list s focus-slit:next g cancel Left move-left:5 Right move-right:5 Up move-up:5 Down move-down:5
argument-key (default Super+u) is neoflux's Emacs C-u: press it, optionally type digits, then run any keybinding or chord, and that binding receives the number. A banner shows the argument as you type it. What a binding does with it:
Every other action ignores the argument. Any other key (g, Escape, an unbound key) abandons it; the digits are typed without modifiers (keypad digits also count), and Super+u pressed after digits is ignored.
A [[mouse]] entry has context, button, optional mods, and action. Context is root, titlebar, or window. Button is 1=left, 2=middle, 3=right, 4/5=wheel. mods uses the same modifier tokens as keybindings (empty = none). Actions: move, resize, group (tab), raise, lower, shade, maximize, minimize, close, window-menu (menu), window-list (clientmenu), root-menu, next-tab, prev-tab, spawn:CMD, none.
Built-in defaults:
titlebar L=move M=lower R=window-menu window Super+L=move Super+M=group Super+R=resize root M=window-list R=root-menu
In a tabbed group, a plain left-click on a tab switches to it and a plain drag moves the whole window. To reorder tabs, hold the modifier: Super+left-drag (the window-context move binding) started on a tab slides that tab along the bar without moving the window; dragged clearly off the bar, the tab detaches into a window of its own that follows the pointer, and releasing over another window's title bar (Super still held) groups it into that window. To move a whole tabbed window with the modifier, Super+left-drag its body.
A plain left-drag on a titled window's bare border (outside the grips) resizes toward the pressed edge, widening to a diagonal within corner px of a frame corner — it never moves the window. Moving with the mouse is a title-bar (or Super+drag) gesture only. A window with no title bar keeps the configured title-bar action on its border, since that border is its only mouse handle.
While a resize drags (modifier drag or grip), a small popup at the window's center shows the live dimensions: in pixels, or — for a client that declares resize increments in WM_NORMAL_HINTS (terminals, emacs) — in the client's own units (columns x rows), as in Fluxbox.
next-window / prev-window (default Super+Tab / Super+Shift+Tab) cycle windows on the current desktop in stacking order, top to bottom: from the top window, next-window steps to the one below it, working toward the least-recently-raised, then wraps. The order is frozen for the duration of a tab sequence so each press marches down the stack rather than bouncing between the top two; it re-reads the stack whenever focus moves by other means. With cycle-minimized set, minimized windows are included (focusing one restores it in place). When the desktop's only window is minimized, a press restores and focuses it rather than doing nothing for want of a second window to cycle to.
These switchers take in every monitor (each showing its own desktop when [[workspaces.monitor]] gives it one), as Alt+Tab does on most desktops. next-window:monitor / prev-window:monitor (default Super+grave / Super+Shift+grave, the key above Tab) cycle only the monitor you are on: the one the focused window is on, or the one under the pointer when nothing is focused. A window belongs to the monitor its frame overlaps most. Pressing the other switcher in the middle of a sequence starts a fresh one.
Switch with desktop:N / desktop-next / desktop-prev, and send the focused window with move-to-desktop:N. Dragging a window to the left or right screen edge moves it to the adjacent desktop (skipping hidden ones). After a switch, focus goes to the top-most normal window on the target desktop (always-on-top / picture-in-picture windows are skipped unless they are the only thing visible).
Hidden desktops ([workspaces] hidden) are reachable only by their explicit keybind and never appear in next/prev cycling, the desktop rows of the window menu, Send to desktop, or — when placed as a trailing block — external pagers. Their windows stay secret too: a window on a hidden desktop is left out of the window menu and of the Group with / Merge group with pickers (and of _NET_CLIENT_LIST) except while that hidden desktop is the current one. A window minimized on a hidden desktop is recovered via the Super+Tab switcher with cycle-minimized on (see WINDOW SWITCHER), or from the window menu once you are on that desktop.
Independent monitors. By default every monitor shows the same desktop, as one wide desktop spanning them all. A [[workspaces.monitor]] block gives an output its own desktop range with its own current desktop, so e.g. desktop:6 switches only the monitor that owns desktop 6 and moves keyboard focus there (the top-most window on that monitor, or nothing if it is empty), while the other monitor keeps showing what it was showing. desktop-next / desktop-prev cycle within the desktops of the focused monitor — the one holding the focused window, or the one last switched or clicked on — and wrap within that range. move-to-desktop:N onto another monitor's desktop slides the window over to that monitor at the same offset; move-to-monitor:next does the same without naming a desktop, and focus-monitor:next moves keyboard focus across (neither is bound by default). Dragging (or nudging) a window onto another monitor makes it join the desktop that monitor is showing, so it stays put there. Dragging to a screen edge changes desktop only at an outer edge; the seam between two monitors is just part of the move. The built-in pager shows one strip per monitor with that monitor's desktops. New windows join the current desktop of the monitor they open on. Sticky windows stay visible everywhere.
EWMH has a single current desktop, so _NET_CURRENT_DESKTOP (what external pagers and wmctrl -d show) reports the focused monitor's, and an external pager highlights only that one; clicking a desktop in it still switches the monitor that owns that desktop. If an output with its own desktops is unplugged (or was never present — a laptop's docking monitor), its desktops fold into the primary monitor until it returns, when they slide back. While folded, an empty desktop of that set is dormant: absent from next/prev cycling, the pager, the menus, and the advertised EWMH count, exactly like a hidden desktop, so an absent monitor adds no phantom desktops. It is still reachable by desktop:N, and any window on it (one that was there at unplug time, or one you park there) keeps or brings it in view as an ordinary primary desktop. Several blocks for outputs that are never plugged in at the same time are fine. reconfigure also re-enumerates monitors.
The slit swallows dockapps. By default there are four auto-sized slits, one per edge, in CSS order, so a dockapp's --dock N (the flux-dock-apps flag) lands on 0=top, 1=right, 2=bottom, 3=left; a dockapp with no --dock goes to the right. A dockapp may also set the _NEOFLUX_SLIT property to pick a slit, and [[slit-rule]] routes by WM_CLASS. Out-of-range targets are clamped to the last slit.
Right-click a slit for its menu: choose the screen edge it sits on (live for the session), and — when the click is on a specific dockapp — Move Up / Move Down to reorder it (persisted to slitlist) and Send to slit N to move it to another slit (live for the session; a reconfigure / restart re-routes per rule). Intra-slit order is pinned by the slitlist file: listed WM_CLASS names sort first in file order, the rest follow in arrival order.
Keyboard focus in the slit. The focus-slit action (default chord Super+x then s) parks the X keyboard focus on a dockapp, so a keyboard, remote control or game pad can drive it: the dockapp sees FocusIn and draws a ring (the flux dock apps fluxLauncher and fluxVolume do; arrows move their selection or the level, Return activates), while the window manager keeps Tab / Shift+Tab to step along the slit and Escape to hand focus back to the window that had it. Clicking or switching to any window ends it too. No window is advertised as active while focus is in the slit.
The lock-window action (default Super+Shift+l) pins the screen to the focused window — for handing the keyboard to someone, letting someone look over your shoulder, or just staying on task. Every other window is hidden, on every monitor; the locked window keeps its place and is fully usable (its tabs, maximize, fullscreen, shade, nudge, close, and anything the application does itself). Its dialogs open and take focus as usual; any other new window is held hidden until the lock is released. Desktop switching, window cycling, the menus, spawn, minimize, sticky, detach, reconfigure, restart and quit are refused with a reminder banner naming the unlock key. The slits stay visible, so clocks and meters keep going, but clicks on them are swallowed. The pager strip shows but does not switch. The same action unlocks; closing the locked window unlocks too.
This is a courtesy lock, not a security boundary: X11 has no isolation, so the locked application can still start other programs, a terminal inside it is a full escape, and the virtual-terminal switch keys still work. For a real kiosk or screen lock, use a dedicated tool.
Every menu can be driven from the keyboard while it is open: Up/Down (Page_Up/Page_Down, Home/End) move the highlight, Return/space run the highlighted row, Right drills into a submenu, Escape, Left or XF86Back close the menu, and a letter jumps to the next row starting with it. The mouse keeps working at the same time. Open a menu without the mouse with the root-menu, window-menu and window-list actions (default chords Super+x then r / m / w); a key-opened menu starts with its first row highlighted.
The startup file is an ordinary shell script (/bin/sh), run once at a fresh login. Put background helpers — a wallpaper setter, a panel, a compositor — here, each backgrounded with a trailing & so the script returns:
feh --bg-fill ~/wallpaper.png & xfce4-panel & xterm
Do not end it with exec neoflux (unlike a classic Fluxbox startup) — neoflux runs the script itself, after it is already managing the screen. It is interpreted by sh (sh path), so any #! shebang line is ignored and no execute bit is required. Its standard output and error are discarded (they do not appear in the log). The script is run detached, so a final foreground command (no &) blocks only that one line, never the window manager; and it is not re-run on a restart (the NEOFLUX_RESTART environment variable marks the re-exec).
neoflux-import(1), neoflux-menugen(1), neoflux-session(1), fluxbox(1), wmctrl(1), xdotool(1)
neoflux-import(1) converts an existing ~/.fluxbox configuration (keys, apps, init, menu, slitlist, and styles) into neoflux's TOML files. neoflux-menugen(1) generates menu.toml from installed applications. neoflux-session(1) is the display-manager session wrapper.
neoflux is developed by Chris (OsugiSakae).
| October 30, 2026 | neoflux 0.5.3 |