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: if you're not using systemd and the niri-session
script, you may need to change your niri startup command to niri --session
. Please read below on the changes for environments without systemd.
Touchpad gestures
I grew annoyed enough with the lack of a horizontal touchpad gesture in niri, so I spent several days working on the gestures. I tried three different horizontal gesture behaviors, and the one I landed on does a fairly good job of moving the windows where you intended.
I also made many overall improvements to both the vertical and the horizontal gestures to make them feel very good. They are now inertial, meaning that a short flick is enough to take you to the next workspace, as the gesture will account for the speed of your fingers. Vertical gesture has rubberbanding at the edges, indicating that you can't go any further. Finally, both gestures use spring animations when releasing fingers, which feel natural as they also take the finger speed into account. If you swipe with enough force, you'll even get a small bounce at the edge!
touchpad-gestures.mp4
Thanks goes to the maintainers of libadwaita since that's where I copied lots of the code and numeric values from.
Spring animations
As part of the gesture work, niri now supports spring animations. These are physics-based animations that are especially well suited for gestures, but feel good on their own too. Based on the spring configuration, they can optionally give small bounces and oscillations.
I made three of the four default animations to use springs. If you had custom animation settings in your config, comment them out to give springs a try! Also, check the default config for a more detailed explanation and examples on how to set up spring animations.
config-error-bounce.mp4
Touch support
@cmeissl added basic touchscreen support to niri. Thanks!
Gradient borders
Focus ring and borders can now use a linear gradient instead of a solid color!
This is how you can set it up:
layout {
border {
active-gradient from="#f38ba8" to="#f9e2af" angle=45 relative-to="workspace-view"
inactive-gradient from="#585b70" to="#7f849c" angle=45 relative-to="workspace-view"
}
}
Colors can use several CSS-like notations, and the gradient itself is rendered like CSS linear-gradient(angle, from, to)
. You can use some CSS gradient generator, like this one, to get a gradient you like, then copy the values into the niri config.
Also, gradients can be relative to windows individually (the default), or to the whole view of the workspace. It's easier to explain visually:
Default | relative-to="workspace-view"
|
---|---|
By the way, regular colors can also now be written with CSS-like notations. The old four-number way is now deprecated.
// catppuccin-mocha Sapphire
active-color "#74c7ec"
// catppuccin-mocha Surface2
inactive-color "#585b70"
wlr-screencopy
While niri supports xdg-desktop-portal screencasting and has a built-in screenshot UI, these are not very well suited for taking programmatic screenshots (and the current screenshot portal API isn't very good either). So, in this release, niri implements wlr-screencopy version 1 (not 3). Now you can take screenshots with grim.
Screen recording tools based on wlr-screencopy will need version 3, so they won't work for now. (The screencast portal is better for this anyway; for example, it leaves frame pacing entirely to the compositor, where it belongs.) Version 1 should be sufficient for any screenshot tool; if a screenshot tool complains that it needs version 3 then it likely needs a simple patch to avoid requesting version 3 if unavailable.
Like other security-sensitive protocols, wlr-screencopy is not available to sandboxed clients with a security context (such as Flatpaks).
Finally, all three of my outputs on a single screenshot.
|
Thanks to @sodiboo for implementing wlr-screencopy support!
Frame timing fixes
I fixed several issues in the presentation time handling and frame callback tracking logic.
- Frame callbacks were sometimes sent ~1 frame later than they should've been, meaning that clients had much less time to render.
- With specific timing it was possible for frame callbacks to stop getting sent to certain surfaces, causing a window to stop redrawing until something else updates the screen.
- Zero presentation time from DRM (which can happen on some drivers) sometimes resulted in a panic.
Stricter config validation
Due to the ease of use in knuffel, the KDL parsing library we use in niri, some nodes technically accepted multiple children, despite only expecting one. Specifically, default-column-width {}
and binds. Also, you could write multiple binds to the same key combination, which is similarly not supported.
This has been fixed to cause a config validation error. While technically a config-breaking change, it's more of a bug fix, since before all these extra nodes that you could write were ignored. Therefore I considered it fine to include in a minor niri version bump.
Thanks @sodiboo for implementing this validation!
Refactored window creation flow
I reworked the window creation flow and tracking of unmapped windows in niri to make it more robust and less "all over the place". As part of this:
- With borders enabled,
default-column-width {}
(unset, the app picks its own) caused the app to shrink a bit right after it appeared. This wasn't really noticeable, but it resulted in a smaller window size than what the app wanted. It is now fixed. - Corrected
default-column-width { fixed N; }
similarly not taking borders into account, resulting in a smaller window than the specified N. - Added support for apps requesting a specific fullscreen monitor before they first appear (
mpv --fs-screen=N
will now work). - Added
open-maximized true
window rule. - Added
open-fullscreen true/false
window rule. Setting it totrue
will fullscreen the window upon opening, and setting it tofalse
will deny the window from fullscreening upon opening.- Some windows can request fullscreen after they are initially configured, but before they are first shown on screen. In this case
open-fullscreen false
will not work, because these window rules apply at the initial configure. So far I only sawmpv --fs
do this, so it's not a big problem (you can just remove the mpv flag).
- Some windows can request fullscreen after they are initially configured, but before they are first shown on screen. In this case
Systemd scopes
When niri runs applications it will now put them into transient systemd scopes. One concrete benefit is that when an application uses too much RAM and systemd-oomd kills it, niri won't go down alongside the app, so the rest of your session will stay intact.
Many other tools (like Flatpak, tmux, or systemd itself) already do this for the commands they spawn, so niri joins this established practice.
┌ ~
└─ systemctl --user status
● sparklingbrook
State: running
Units: 444 loaded (incl. loaded aliases)
Jobs: 0 queued
Failed: 0 units
Since: Mon 2024-03-04 10:25:20 +04; 4 days ago
systemd: 254.9-1.fc39
CGroup: /user.slice/user-1000.slice/user@1000.service
├─app.slice
│ ├─app-niri-alacritty-1672431.scope
│ │ ├─1672431 alacritty
│ │ ├─1672446 /usr/bin/fish
│ │ └─1672578 systemctl --user status --no-pager
│ ├─app-niri-fuzzel-1672466.scope
│ │ └─1672468 /var/home/yalter/stuff/blender-4.0.2-linux-x64/blender
<...>
├─session.slice
│ ├─niri.service
│ │ └─1663138 /usr/bin/niri --session
<...>
Also, since the niri.service
scope now only contains niri itself, I have moved it into session.slice
, a slice for important services such as the compositor.
Running without systemd
I've made it easier to run niri in environments without systemd.
- Added a new, enabled by default, feature
systemd
which gates calls to the systemd D-Bus API. Currently, this includes starting transient scopes andsystemctl import-environment
. - Niri now sets
XDG_CURRENT_DESKTOP
andXDG_SESSION_TYPE
in the main binary, rather than in theniri-session
script. - Added a
niri --session
flag for running niri as the main session instance, which means that it will import environment variables globally into systemd and D-Bus, and start D-Bus services. This flag replaces auto-detection based on the presence of theNOTIFY_SOCKET
variable. - Added a
dinit
feature that runsdinitctl setenv
to import environment, and added ready notifications throughNOTIFY_FD
environment variable (thanks @metent).
So, if you package niri:
- Check if you need to call
niri --session
instead ofniri
. - Make sure you compile with the
systemd
feature if needed. - Compile with the
dinit
feature if your distribution uses dinit.
Other improvements in this release
- Fixed a Smithay crash when a client sets a buffer scale of 0. The client is now correctly terminated with a protocol error.
- Fixed a crash when parsing the EDID of certain monitors.
- Fixed screen locking when monitors are powered off.
- Fixed windows disappearing when requesting to be fullscreen on a different output than they were displayed on.
- Fixed empty workspaces sometimes not getting cleaned up during the workspace switch gesture.
- Fixed screen resolution changes not always triggering output repositioning, which could result in overlapping outputs (which manifested as mouse clicks seemingly not always working).
- Fixed
toggle-debug-tint
desynchronizing for newly connected outputs. - Commented out the default bind for
toggle-debug-tint
. spawn
andspawn-at-startup
will now expand~
to the home directory in the command name, similarly to howscreenshot-path
does it. In the command arguments~
will not be expanded.- Added the
environment {}
config section where you can control the environment variables that niri sets for the commands it spawns. - Implemented the wp-viewporter protocol. This makes
Xwayland -fullscreen
work (that flag makes it emulate a specific screen resolution for the clients inside). - Implemented the xdg-foreign protocol, which allows tracking dialog parent relationships in more cases, which will be more useful in the future.
- Overlays like the exit confirmation dialog are no longer dismissed by a mouse button release, which means that a Waybar module that calls
niri msg action quit
on click will now work as expected. - Clarified in the default config how workspace indices work.
- Changed several
error!
log messages towarn!
for consistency. In niri,error!
always indicates a bug in our code. If something can happen without a bug in niri, then it should be awarn!
.