v25.02
Niri is a scrollable-tiling Wayland compositor. Windows are arranged in columns on an infinite strip going to the right. Opening a new window never causes existing windows to resize.
Here are the improvements from the last release.
[!NOTE] Packagers: I fixed the problem where some tests required
RAYON_NUM_THREADS=1on a heavily multithreaded CPU. Please remove that variable if you had it set, so that we don't miss any new bugs.
https://github.com/user-attachments/assets/a9e37678-5783-4de0-b2c7-a26094cd635f
Tabbed columns
Columns can now present windows as tabs, rather than vertically stacked tiles. This is useful when you have limited vertical space, or when you frequently switch between two large windows and want to avoid scrolling.
Add this new bind to your config to switch a column to tabbed mode:
binds {
Mod+W { toggle-column-tabbed-display; }
}
This is the only new bind you will need. All other keyboard and mouse navigation works exactly the same as with regular columns: switch tabs with focus-window-down/up, add or remove windows with consume-window-into-column/expel-window-from-column, and so on. (Thanks @elkowar for this wonderful UX idea!)
https://github.com/user-attachments/assets/5b357895-bcf3-42eb-a2e1-2b220d63d0c9
There are a few new actions that help navigate the tabs. All of them also work on regular columns.
focus-window-top/bottomfocuses the topmost or the bottommost window in a column.focus-window-down-or-topandfocus-window-up-or-bottomcycle the navigation so the focus jumps from the last to the first window and vice versa.focus-window-in-column <index>focuses a specific window by index.
The tab indicator can be customized in several ways and moved to top/bottom/right of the column. See the wiki page for more details.
You can also make windows open as tabbed columns by default globally or with a window rule. This goes well with the hide-when-single-tab setting for the tab indicator.
Shadows
Niri can now draw shadows behind windows. Apart from being a nice aesthetic effect, shadows help to delineate floating and otherwise overlapping windows. They are especially useful when you disable or clip away client-side decorations (which commonly include shadows of their own).
Niri shadows are not enabled by default to not clash with the shadows coming from client-side decorations. Turning them on is simple enough:
// Enable shadows.
layout {
shadow {
on
}
}
// Also ask windows to omit client-side decorations, so that
// they don't draw their own window shadows.
prefer-no-csd
You can customize properties like softness (blur radius), spread, offset, and color, both globally and for individual windows. Like borders and focus rings, shadows will follow the window corner radius that you set via geometry-corner-radius.
Shadows also work on layer-shell surfaces. Due to the higher variety among layer-shell components, we don't enable shadows for them automatically; you need to explicitly enable them with a layer rule. For example:
// Add a shadow for fuzzel.
layer-rule {
match namespace="^launcher$"
shadow {
on
}
// Fuzzel defaults to 10 px rounded corners.
geometry-corner-radius 10
}
Drag-and-drop view scrolling
In this release I finally addressed one of the longer-standing UX issues: you can now scroll the view left and right during a drag-and-drop operation by moving the mouse close to the monitor's edge. This is similar to how you can scroll various lists and scrolling views in applications during drag-and-drop.
There's a small debounce delay before the scrolling starts so that it doesn't trigger when quickly moving the mouse across monitors. You can customize this, as well as other parameters like maximum scrolling speed, in the new config section.
In addition to drag-and-drop, this gesture will trigger when dragging a window in the tiling layout. Dragging floating windows however won't scroll the view.
https://github.com/user-attachments/assets/9e1f166e-9194-4830-a482-34a00a9a2d61
Screencast target window rule
There's a new is-window-cast-target=true window rule that matches windows "targetted" by an individual-window screencast. You can use it, for example, to highlight the window that you're screensharing by changing its border/focus ring colors.
// Indicate screencasted windows with red colors.
window-rule {
match is-window-cast-target=true
focus-ring {
active-color "#f38ba8"
inactive-color "#7d0d2d"
}
border {
inactive-color "#7d0d2d"
}
shadow {
color "#7d0d2d70"
}
tab-indicator {
active-color "#f38ba8"
inactive-color "#7d0d2d"
}
}
Thanks @elkowar for the suggestion!
Custom titles for Important Hotkeys
We have an Important Hotkeys dialog in niri that pops up at startup with a list of the main binds to get you going. The binds in this list and their titles are hardcoded (so that you're not spammed with all the keys bound by default).
In this release, you can customize this list using the new hotkey-overlay-title property.
- To add a bind to the dialog, or change an existing bind, set it to the title that you want to show:
binds { Mod+Shift+S hotkey-overlay-title="Toggle Dark/Light Style" { spawn "some-script.sh"; } } - To hide an existing bind from the dialog, set it to null:
binds { Mod+Q hotkey-overlay-title=null { close-window; } }
This is especially useful for binds that spawn programs, as niri can't automatically deduce good titles for them. For example, here's my Important Hotkeys list where I gave nice titles to most spawn binds (everything below PrtSc):
These custom titles also support full Pango markup which allows you to change styles, colors, and fonts.
I also made two cosmetic changes to the key combo rendering:
- Ctrl and Shift are now sorted before Alt, matching most other programs. However, when Alt is the Mod key (running niri as a window), then it will be sorted first to emphasize that.
- Space is now rendered with capital S. These names come from xkb in all kinds of spelling variations, and we have to "prettify" them manually in niri. Space seems fairly common, so I added it to the code.
Expand to available width
Sometimes windows don't quite neatly divide into preset widths, making it hard to fill the space on the monitor exactly. The new expand-column-to-available-width bind addresses this: it expands the focused window to take up all remaining free space on the screen.
Since windows on niri can scroll in and out of view, this bind considers the current window positions. All fully visible windows remain on screen.
https://github.com/user-attachments/assets/cdb99398-77a3-42aa-8406-6a56e32559ca
Keyboard shortcuts inhibit protocol
@sodiboo implemented the keyboard-shortcuts-inhibit Wayland protocol. It is used by apps like virtual machines or remote desktop clients to let them pass compositor bindings to the target system.
You can force-deactivate the inhibiting and get your niri shortcuts back using the following new action. Make sure to add it to your config:
binds {
Mod+Escape { toggle-keyboard-shortcuts-inhibit; }
}
You can also make certain binds ignore inhibiting with the new allow-inhibiting=false property. They will always be handled by niri and never passed to the window.
binds {
// This bind will always work, even when using a virtual machine.
Super+Alt+L allow-inhibiting=false { spawn "swaylock"; }
}
Screenshot without writing to disk
Thanks to @sornas, you can now capture screenshots only to the clipboard, without writing the image to disk. Simply press CtrlC in the screenshot UI instead of Space or Enter.
screenshot-screen and screenshot-window binds can do this with a new write-to-disk=false flag:
binds {
Ctrl+Print { screenshot-screen write-to-disk=false; }
Alt+Print { screenshot-window write-to-disk=false; }
}
Or, on the command line:
$ niri msg action screenshot-window --write-to-disk=false
Other improvements in this release
- @sodiboo implemented the
wlr-virtual-pointerWayland protocol required for tools like wayvnc and lan-mouse. These tools should now work with niri, however, keep in mind that you won't able to use niri keyboard binds through them due to a limitation of how the virtual keyboard protocol is currently implemented in Smithay. - @bbb651 added the
scroll-factorwindow rule property. It works the same way as the input setting but can be set for a specific window. - @Faervan added the
toggle-window-rule-opacityaction which lets you temporarily make a window fully opaque, if it was semitransparent from a window rule. - @notpeelz added a setting to entirely disable the primary clipboard (middle click to paste selected text):
clipboard { disable-primary; }at the top level of the niri config. - @Kirottu added two actions to move workspaces:
niri msg action move-workspace-to-index <INDEX>moves a workspace to a specific position on its monitor, andniri msg action move-workspace-to-monitor <OUTPUT>moves a workspace to a different monitor. - @ezemtsov made
niri msg action switch-layoutaccept a layout index (for example,0or1for the first or the second layout respectively) in addition tonextandprev. - @m4rch3n1ng added a way to load the keyboard keymap from an .xkb file. See the wiki page for details.
- @pranaless made the horizontal view movement gesture play better with
center-focused-column "on-overflow": it will now snap a window to the center of the screen when it can't fully fit together with the adjacent window. - @zzzsyyy added a
drag-lockinput flag for touchpads that enables libinput drag lock. - @JohnDowson added a
calibration-matrixinput setting for tablets. See the wiki page for details.
Funding
I work on niri in the spare time that I have from my university studies. If you like what I do, you can support my work on GitHub Sponsors. Big thanks to all current and past sponsors!