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: the niri default config now spawns waybar at startup so as not to start with a blank desktop. Please consider adding Waybar as a recommended dependency (or changing it to some other bar).
The Overview
The big new thing in niri v25.05 is the Overview. It zooms out your workspaces and windows to let you see what's going on at a glance, navigate, and drag windows around, all without having to touch the keyboard.
niri-overview-release.mp4
You can open it with the toggle-overview
bind, via the new top-left hot corner, or using a touchpad four-finger swipe. While in the overview, all keyboard shortcuts keep working, while pointing devices get easier:
- Mouse: left click and drag windows to move them, right click and drag to scroll workspaces left/right, scroll to switch workspaces (no holding Mod required).
- Touchpad: two-finger scrolling that matches the normal three-finger gestures.
- Touchscreen: one-finger scrolling, or one-finger long press to move a window.
niri-overview-touch.mp4
Drag-and-drop will scroll the workspaces up/down in the overview, and will activate a workspace when holding it for a moment. Combined with the hot corner, this lets you do a mouse-only DnD across workspaces.
niri-overview-dnd-across-ws.mp4
By the way, this new drag-and-drop hold will also bring floating windows to the top outside the overview.
You can drag-and-drop a window to a new workspace above, below, or between existing workspaces.
niri-overview-insert-between.mp4
To make the spatial model work for the overview, niri now draws a separate background under each workspace. For layer-shell tools, the background and bottom layers zoom out together with the workspaces, while the top and overlay layers remain on top of the overview. Make sure to put your bar on the top layer.
The background behind the workspaces in the overview is called the backdrop. There are new backdrop-color
settings both globally in the overview {}
section and per-output.
If you want something more interesting in the backdrop, there's a new place-within-backdrop
layer rule. You can use it on a wallpaper tool showing a blurred version of your background, for example.
Since backgrounds are now tied to workspaces, they will also move together with workspaces. If you don't like this, you can combine place-within-backdrop
with a transparent background-color
to get the stationary wallpaper back. Check the overview wiki page for an example configuration. There, you will also find how to change the overview zoom level or disable the hot corner.
There have also been smaller spatial model fixes to accommodate the overview. For example, the top layer-shell layer and the interactively dragged window now render on top of the background- and bottom-layer popups.
Finally, @CharlieQLe added an IPC request and event for monitoring the overview's open state.
Screencasting features
For this release, I worked on several new features for screencasting and screensharing. To keep track of them, I wrote a new wiki page that describes all screencasting-related functionality in niri. Check it out!
I should also mention the new wait-for-frame-completion-in-pipewire
debug flag by @coleleavitt. If you started having glitches when screencasting on NVIDIA (e.g., in Discord), this flag should help, until we support explicit sync for PipeWire screencasts.
Dynamic screencast target
A dynamic cast target is a special target that can change what it streams. You can select it as a special "niri Dynamic Cast Target" in the window selection dialog:
The dynamic target starts as an empty, transparent video stream. Then, you can use the following binds to change what it shows:
set-dynamic-cast-window
to cast the focused window.set-dynamic-cast-monitor
to cast the focused monitor.clear-dynamic-cast-target
to go back to an empty stream.
You can also use these actions from the command line, for example, to interactively pick which window to cast. Check the screencasting wiki page for more details and examples.
niri-dynamic-cast-target.mp4
Windowed fullscreen
A common feature in WMs is fake, or detached, or windowed fullscreen. The compositor tells the window that it went fullscreen, but in reality keeps it as a normal window.
This is useful when screencasting browser-based presentations like Google Slides, where you usually want to hide the browser UI, which requires fullscreening the browser. Real fullscreen is not always convenient, for example, if you have an ultrawide monitor, or just want to leave the browser as a smaller window, without taking up an entire monitor.
Now, niri can help, with the new toggle-windowed-fullscreen
bind. It tells the app that it went fullscreen, while in reality leaving it as a normal window that you can resize and put wherever you want.
binds {
Mod+Ctrl+Shift+F { toggle-windowed-fullscreen; }
}
Here's an example showing a windowed-fullscreen Google Slides presentation, along with the presenter view and a meeting app, all on the same monitor:
Screenshot UI
For this release, I made the screenshot UI support tablet and touchscreen input for drawing the selection, closing this long-standing gap. I also added a small capture button to the panel at the bottom, making it possible to select and save a screenshot without a keyboard.
niri-screenshot-ui-touch.mp4
Keyboard use got better too: the screenshot UI will now recognize some windowing binds like move-column-left/right
, move-window-up/down
and set-window-width/height
, and move the selection region as if it was a floating window. Thanks to @nnyyxxxx for prototyping the implementation! Naturally, this opens the door for making a bunch more windowing actions work on the screenshot UI selection.
Finally, @TobyBridle added a show-pointer
flag to screenshot
and screenshot-screen
actions to control whether the mouse cursor is included in the image.
Window urgency
Urgency is an unspecified but commonly implemented Wayland behavior where a window can request the user's attention. The compositor will then draw it with a red border, and signal this urgency to other desktop components.
Now, @Duncaen implemented window urgency in niri. It comes with a host of urgent-color
settings on borders, focus-rings and tab indicators, an is-urgent
window rule matcher, and urgency indicators for windows and workspaces in the IPC.
Urgency is cleared once you focus a window. You can also manually toggle urgency for a specific window with the new toggle-urgent
, set-urgent
, and unset-urgent
actions.
@Duncaen is also adding niri urgency support to Waybar in this PR.
IPC improvements
We have several new things in the IPC system.
@bbb651 implemented niri msg pick-window
that lets you select a window by clicking. The command then outputs information about this window, which can be used for scripting. For example, you can make a "screenshot clicked window" script:
$ niri msg action screenshot-window --id="$(niri msg --json pick-window | jq .id)"
@nnyyxxxx added niri msg pick-color
that prints the color of the selected pixel. They also hooked it up to the PickColor method of the Screenshot portal, making the color picker work in apps.
niri-pick-color.mp4
The niri IPC socket had so far been conservatively limited to a single request per connection. @titaniumtraveler helped to lift this limitation: now niri will keep reading and replying to requests as they arrive. Keep in mind that requests are still processed one by one and not atomically; read the niri-ipc documentation for more details.
Finally, there's a small UX improvement. It's a common situation after updating niri that the running niri compositor is still the old version (since you haven't restarted it yet), but the niri binary (and hence the niri msg
CLI) is already the new version. Then, using a newly added niri msg
feature will ask the running niri compositor something that it doesn't understand yet, yielding an error.
When this happens, niri msg
will additionally request the version of the running niri compositor, and notify you if it doesn't match the CLI version, prompting you to restart. Unfortunately, this check didn't fire if niri msg
failed parsing the response, leading to some confusion.
In the new release, I made the check work properly for this case too.
Windowing actions
We've got a number of new actions for working with windows:
- @annikahannig added
focus-monitor
,move-window-to-monitor
, andmove-column-to-monitor
by monitor name (in addition to the existing directional actions). - @Duncaen added
focus-column
andmove-column-to-index
that work by index of the column within the workspace. - @nnyyxxxx worked on a new
move-window-to-workspace --focus=false
flag that will send the active window to a different workspace without following it. - @yzy-1 added
--focus=false
to themove-column-to-workspace/up/down
actions. - Fixed panic when passing out-of-bounds index to
move-workspace-to-index --reference
. - Fixed
move-workspace-to-index
being 0-based instead of 1-based (we use 1-based workspace indices elsewhere).
I also added a new center-visible-columns
action that centers all fully visible columns on screen, as a companion to expand-column-to-available-width
from the last release.
niri-center-visible-columns.mp4
Finally, while not a new action, consume-or-expel-window-left
will now restore the view position similarly to closing a window. This is especially useful with tabbed columns: opening a new window and immediately consuming it left will add it as a tab without messing up the view.
niri-consume-left-view-restore.mp4
Input device settings
We added several settings for input devices. Read more about them on the input configuration wiki page.
- Added
drag
totouchpad
that allows disabling tap-and-drag (thanks @alexdavid). - Added
off
totouch
to disable touchscreen devices (thanks @nnyyxxxx). - Added
left-handed
totrackpoint
(thanks @dbeley). - Added
mod-key
andmod-key-nested
that let you change theMod
key (thanks @notpeelz). - Added
numlock
setting tokeyboard
to automatically enable Num Lock at startup (thanks @erdii). Note that there's a known issue where it only works after pressing a modifier key (Super, Alt, etc.). - @TyberiusPrime extended
warp-mouse-to-focus
with modes:mode=center-xy
andmode=center-xy-always
make the mouse always go to the center of the window both vertically and horizontally.
Output focusing at startup
@lualeet added a new focus-at-startup
output flag that will make niri focus that output when starting up if it is connected. Additionally, niri will now start with the mouse cursor centered in the focused monitor.
Screen locker red flash fix
Niri will now wait for a lock surface to appear before rendering a locked session, thereby fixing the infamous red flash when locking the screen. Note that semitransparent lock surfaces will still show a red background, so you'll want to disable the fade-in in hyprlock.
niri-lock-screen-wait.mp4
Tiled state window rule
The Tiled state is one of the states a Wayland compositor can set on a toplevel window. Generally, windows react to it by removing their shadows and squaring rounded corners. Terminals stop snapping their window size to the terminal grid.
By default, niri sets the Tiled state together with prefer-no-csd
. However, it can be useful to control the Tiled state separately, for example if you want to keep client-side decorations (for mouse-only dragging and closing) together with square corners (for visuals).
In this release, I exposed it as the tiled-state
window rule. Apart from blanket enabling, you can also set it based on whether the window is tiled or floating. For example:
// Make tiled windows rectangular while using CSD.
window-rule {
match is-floating=false
tiled-state true
}
niri-tiled-state-rule.mp4
More efficient offscreening
Offscreening is rendering a window into an intermediate texture rather than straight to the monitor. It's often used to correctly apply alpha blending when compositing multiple layers.
So far, offscreening in niri was rather inefficient because it was only used during short animations. The intermediate texture would get recreated from scratch every frame. Due to this, I couldn't add any longer-running transparency effects because I didn't want to use the inefficient offscreening.
For this release, I reworked how offscreening works in niri: it reuses the intermediate texture whenever possible, and it correctly tracks damage both "inside" and "outside" the offscreen. So when an offscreened window redraws, only the damaged part will redraw inside the intermediate texture, and this damage will be propagated out, to be used when compositing the texture itself.
Practically, this means slightly improved animation efficiency for window opening and resizing. It also enables using offscreening for longer-running effects. In particular, I could finally make windows semitransparent as you're dragging them around, making it easier to see where they will land inside the tiling layout.
niri-interactive-move-transparency.mp4
Animations for tabbed columns also use transparency. Before, they didn't use offscreens, resulting in blending artifacts in some conditions. Now they use the new offscreens, so transparency always looks correct.
Regular window opacity does not use offscreening, so border or focus ring may still show through.
Another improvement from the offscreening rework is that offscreens now track which surfaces are visible "inside" the temporary texture. If a surface is completely obscured or otherwise invisible "inside" the temporary texture, it will no longer get frame callbacks. This is a minor efficiency improvement, but it happens to work around an issue with Firefox's experimental subsurface compositor.
baba-is-float
layer rule
The last niri release had a secret April Fools' feature: the baba-is-float
window rule that makes windows FLOAT up and down. Now this widely acclaimed feature is available for layer surfaces too!
// Make fuzzel FLOAT.
layer-rule {
match namespace="^launcher$"
baba-is-float true
}
niri-is-float.mp4
Other improvements in this release
- Fixed cursor hiding with
hide-when-typing
orhide-after-inactive-ms
breaking tooltips, and input in some first-person games (thanks @bbogdan-ov). - Added a
background-color
setting tolayout {}
that sets the background color for all workspaces/outputs. - Added anchors to links throughout the wiki. Thanks @chinatsu for implementing anchor support in the wiki deployment GitHub action that we use, and for fixing the links.
- Added
niri completions
subcommand to generate shell completions (thanks @titaniumtraveler). - Added
top
,bottom
,left
,right
values fordefault-floating-position relative-to=
which align the window to the center of a side of a monitor (thanks @Mandarancio). - Added support for negative shadow spread (thanks @LunarEclipse363).
- Added the
honor-xdg-activation-with-invalid-serial
debug flag that fixes focusing the window when clicking on a tray icon for Discord, Telegram, and some other apps. (It is a bug in the apps or their toolkits that they need this debug flag.) - Added
niri msg action toggle-keyboard-shortcuts-inhibit
—the bind was added last release, but we forgot the CLI/IPC action (thanks @sodiboo). - Renamed ISO_Level3/5_Shift to Mod5/3 in the Important Hotkeys dialog.
- In the default config, added custom Important Hotkeys titles for the spawn binds.
- Fixed window opening animation being off-center during a concurrent resize animation.
- Fixed clicking on a partially offscreen window with animations disabled hitting the window at its final position, rather than its visible (initial) position. This makes the behavior consistent with enabled animations.
- Fixed putting
center-focused-column "always"
in the config not updating the view position right away. - Fixed swipe and DnD scroll gestures not taking into account the time between the last pointer movement and button release, leading to unintended jumps.
- Made it possible for the view position to animate during a DnD scroll. This makes windows scroll into view when "dragging out" the first or the last window on a workspace, like they used to two releases ago.
- Removed cancellation for the workspace-switch gesture. Now when you add or lift a finger during the gesture, it will complete as if you lifted all fingers, rather than resetting back to the starting position.
- Fixed swipe gesture forgetting the previous workspace when starting and stopping on the same workspace.
- Fixed a jump when "catching" a workspace-switch animation with a workspace-switch gesture.
- Made xdg-activation also consider pointer focus for token validity.
- Fixed popups showing up inside the animating resizing window (in addition to rendering normally on top).
- Fixed panic at startup when the configured xkb keymap fails to compile.
- Fixed panic when trying to interactively resize from a tab indicator.
- Fixed panic and broken frames with some overdamped spring animation settings.
- Fixed tab indicator width, gap, gaps_between being able to round down to 0 physical pixels when they are set to above 0 in the config.
- Fixed the interactively moved window getting input on all outputs rather than just the correct one (you could observe this with a combination of touchscreen and mouse input).
- Fixed wrong min/max size computation for windows while going out of fullscreen.
- Fixed interactively moved window not always updating properly.
- Fixed removing a window that is going into fullscreen not resetting the stored unfullscreen view position.
- Fixed interactively resizing a window that is going out of fullscreen not resetting the stored unfullscreen view position.
- Fixed DnD scroll not stopping when interactively moving a fullscreen window that unfullscreens to floating.
- Changed logging to go to stderr rather than stdout (thanks @titaniumtraveler).
- Updated Smithay:
- Fixed panic on monitor hotplugging.
- Fixed panic on some ARM devices.
- Fixed panic upon receiving negative damage width/height from a Wayland client.
- Fixed panic upon receiving subsurface place_above/below with no parent.
- Fixed presentation feedback getting discarded for subsurfaces.
- Fixed some popups going off-screen instead of shrinking.
- Fixed cursor shape sometimes getting stuck in Chromium.
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!
And here's a bonus for everyone who got all the way through this huge release, an ASUS Eee PC from 2008 running the overview!
niri-overview-eeepc.mp4