This is a module for Waybar that displays a window minimap for the current niri workspace.

[!IMPORTANT] niri ≥ v25.08 is required (for the window locations in IPC messages to be available).
If you're using an amd64 system, you can get a pre-built binary from the
releases page.
Download and place waybar-niri-windows.so anywhere permanent;
~/.config/waybar is a good place.
If you'd like to build from source (or if you're on a different platform):
apt install libgtk-3-dev, pacman -S gtk3, etc.).make to produce waybar-niri-windows.so. This might take a while (thanks to cgo).Move the library anywhere permanent, e.g. ~/.config/waybar.
Add a CFFI module to your Waybar config:
{
"modules-left": ["cffi/niri-windows"],
"cffi/niri-windows": {
// path where you placed the .so file
"module_path": "/home/calico32/.config/waybar/waybar-niri-windows.so",
// configure the module's behavior
"options": {
// set the module mode
// "graphical" (default): draw a minimap of windows in the current workspace
// "text": draws symbols and a focus indicator for each column (mirrors v1 behavior)
"mode": "graphical",
// ======= graphical mode options =======
// when to show floating windows
// - "always": always show floating window view, even if there are no floating windows
// - "auto" (default): show floating window view if there are floating windows on the current workspace
// - "never": never show floating windows
"show-floating": "auto",
// pick where the floating windows be shown relative to tiled windows
// - "left": show floating windows on the left
// - "right" (default): show floating windows on the right
"floating-position": "right",
// set minimum size of windows, in pixels (default: 1, minimum: 1)
// if this value is too large to fit all windows (e.g. in a column with many windows),
// it will be reduced
"minimum-size": 1,
// set spacing between windows/columns, in pixels (default: 1, minimum: 0)
// if this value is too large, it will be reduced
"spacing": 1,
// set minimum size of windows, in pixels, to draw icons for (default: 0, minimum: 0)
// if unset or 0, icons will only be drawn for tiled windows that are the only one in their column
// if 1+, icons will be drawn for all windows where w >= icon-minimum-size and h >= icon-minimum-size
// icons must be set in the "rules" section below for this to have any effect
"icon-minimum-size": 0,
// account for borders when calculating window sizes; see note below (default: 0, minimum: 0)
"column-borders": 0, // border on .column
"floating-borders": 0, // border on .floating
// trigger actions on tile click (see https://yalter.github.io/niri/niri_ipc/enum.Action.html for available actions)
// only actions that take a single window ID are supported
// set to an empty string to disable
"on-tile-click": "FocusWindow", // (default: FocusWindow)
"on-tile-middle-click": "CloseWindow", // (default: CloseWindow)
"on-tile-right-click": "", // (default: none)
// add CSS classes/icons to windows based on their App ID/Title (see `niri msg windows`)
// Go regular expression syntax is supported for app-id and title (see https://pkg.go.dev/regexp/syntax)
// rules are checked in the order they are defined - first match wins and checking stops
// set "continue" to true to also check and apply subsequent rules even if this rule matches
// if multiple rules with icons are applied, the first one will be used
// *icons are not drawn for floating windows by default*; set "icon-minimum-size" to enable (see above)
"rules": [
// .alacritty will be added to all windows with the App ID "Alacritty"
// will be drawn in windows that match
{ "app-id": "Alacritty", "class": "alacritty", "icon": "" },
// .firefox will be added to all windows with the App ID "firefox"
// subsequent rules are also checked and applied for firefox windows
{ "app-id": "firefox", "class": "firefox", "continue": true },
// .youtube-music will be added to all windows that have "YouTube Music" at the end of their title
// will be drawn in windows that match
{ "title": "YouTube Music$", "class": "youtube-music", "icon": "" }
],
// ======= text mode options =======
// customize the symbols used to draw the columns/windows
"symbols": {
"unfocused": "⋅",
"focused": "⊙",
"unfocused-floating": "∗",
"focused-floating": "⊛",
// text to display when there are no windows on the current workspace
// if this is an empty string (default), the module will be hidden when there are no windows
"empty": ""
}
},
"actions": {
// use niri IPC action names to trigger them (see https://yalter.github.io/niri/niri_ipc/enum.Action.html for available actions)
// any action that has no fields is supported
"on-scroll-up": "FocusColumnLeft",
"on-scroll-down": "FocusColumnRight"
// in graphical mode, don't configure click actions here—they're handled by the module above
}
}
}
Use these selectors in your CSS to style the module.
Windows:
.cffi-niri-windows .tile: any window, tiled or floating.cffi-niri-windows .column .tile: tiled window.cffi-niri-windows .floating .tile: floating window.cffi-niri-windows .<custom-class>: any window with a custom class (see rules in the config):hover (mouse hover) or :active (focused) to any of the above selectors to style those states.:first-child, :last-child, and :nth-child(n) to style the first, last, or nth window in a column.:only-child to style the window when it is the only window in a column..urgent to style windows marked as urgent.Containers:
.cffi-niri-windows .column: column of tiled windows.cffi-niri-windows .floating: floating window view:active to any of the above selectors to style that container when they contain the focused window.:first-child, :last-child, and :nth-child(n) to style the first, last, or nth container.:only-child to style the container when it is the only container.For example:
.cffi-niri-windows .tile {
background-color: rgba(255, 255, 255, 0.5);
}
.cffi-niri-windows .tile:hover {
background-color: rgba(255, 255, 255, 0.7);
}
.cffi-niri-windows .tile:active {
background-color: rgb(255, 255, 255);
}
[!NOTE]
Adding borders to containers may cause them to overflow the bar height. If this happens, set these config options to account for the borders:
- Set
column-bordersto the total height (in pixels) of the top and bottom border on.column- Set
floating-bordersto the total height (in pixels) of the top and bottom border on.floatingFor example, for the following CSS:
```css .cffi-niri-windows .column { border: 1px solid rgba(255, 255, 255, 0.85); }
.cffi-niri-windows .floating { border: 2px solid rgba(255, 255, 255, 0.85); } ```
Set
column-bordersto2andfloating-bordersto4.
Text mode (be sure to specify a font that supports the symbols you're using):
.cffi-niri-windows label.cffi-niri-windows label {
font-family: Uiua386;
font-size: 18px;
margin-top: -2px;
}
Contributions are welcome! If you find a bug or have a feature request, please open an issue or PR.
This project is licensed under the MIT License. See the LICENSE file for details.
$ claude mcp add waybar-niri-windows \
-- python -m otcore.mcp_server <graph>