Skip to content

v0.1.9

Latest
Compare
Choose a tag to compare
@YaLTeR YaLTeR released this 14 Sep 11:44
· 1 commit to main since this release

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: niri now requires libdisplay-info.

New IPC functionality

In this release, I designed and implemented an event stream in niri's IPC which lets you continuously listen to compositor events like workspace or window changes. The event stream enables taskbar applications to make correct and efficient widgets for niri.

I implemented the niri modules for workspaces, focused window, and keyboard layout in Waybar, available in its fresh 0.11.0 release. Pull requests are open for yambar and ironbar thanks to their contributors.

niri-waybar-workspaces.mp4

IPC windows and workspaces now have unique IDs, and all individual window and workspace actions can address a specific window or workspace by its ID. On the command line, a new niri msg windows command lists all windows with their IDs, and window commands accept an --id <ID> argument to target a specific window, for example:

$ niri msg action fullscreen-window --id 2

Also, there's a new niri msg action focus-window --id <ID> action and a new niri msg keyboard-layouts command.

I wrote some documentation on the programmatic access to the niri IPC socket. I also set up an online rustdoc for the niri-ipc crate where I documented every IPC type and request. Please refer there when working with the niri IPC.

Unfortunately, while adding ID arguments to IPC actions, I discovered a backward incompatibility trap in serde-json. The default enum representation—externally tagged—prevents you from changing a unit variant to a struct variant, because the representation gains an extra dictionary. "FullscreenWindow" becomes {"FullscreenWindow":{}}, and the former does not parse with the new definition.

I decided to make a JSON breaking change, converting all unit Action enum variants to struct variants (with or without fields). I doubt anyone used them directly through JSON since these actions could only address the focused window or column. All enum variants that already had fields are unchanged, and the niri msg CLI is also unaffected.

With this breaking change out of the way, any further JSON additions should remain backward compatible, so that existing scripts and programs communicating with niri will keep working with new niri versions.

Height distribution changes

One common complaint about niri's layout was the ability to make a multi-window column not "add up" to the total height of the monitor. The behavior was also fairly unobvious: with two windows in a column, you resize one, and the other resizes along as expected. Then, you resize the other, but the first window doesn't react. It felt like a bug.

Last time there was a design problem (unwanted scrolling with focus-follows-mouse), we quickly found a solution by brainstorming in a Discussion. So, I made a big write-up about window heights in #593. While there hasn't been much discussion, the act of laying out in writing all considerations and constraints had spawned a potential solution in my mind, which turned out to work quite well.

In this release, I reworked the window height distribution to do the expected thing in more cases. A column of two or more windows will always try to match the monitor height, as long as the minimum window sizes allow that. Resizing one window will resize all other windows in a column proportionally. The window that you resized last retains its height just like before, which lets you size one window in a column exactly to fit something, unaffected by adding more windows into the column, or moving it across monitors.

Keep in mind that a single-window column can still be resized arbitrarily, including shorter or taller than the monitor. Until floating windows are implemented, this is necessary for some uses that require exact-sized windows.

niri-height-distribution.mp4

Additionally, I found and fixed a small issue where windows in a column would occasionally "snap" to a smaller size when resizing.

Preset window heights

@TheAngusMcFire implemented a preset-window-heights layout option and a corresponding switch-preset-window-height bind, which work like the existing column width presets.

By default, it's bound to ModShiftR, which is consistent with Shift making resize binds affect the height rather than the width. The default bind to resetting the window height therefore moved to ModCtrlR. (None of this affects you if you already have a niri config; you'll need to add any new binds manually.)

Output names

You might be familiar with this sight:

$ niri msg focused-output
Output "Unknown Unknown Unknown" (DP-1)
  ...

Thanks to @cmeissl finishing the libdisplay-info bindings, this sight is no more.

$ niri msg focused-output
Output "Acer Technologies XV320QU LV 420615FCD4200" (DP-1)
  ...

Following this, all throughout niri I implemented the ability to address outputs by name. This includes config output, map-to-output, open-on-output; niri msg output; wlr-output-management tools (wdisplays, kanshi); and xdg-desktop-portal-gnome screencasting where the screen selector will now show the monitor model and screencast session restore will remember the output name rather than the connector.

xdg-desktop-portal-gnome monitor selector showing monitor models

The recommended way to configure everything output-related is now by name (as shown in niri msg outputs). This way, configuration does not depend on the connector name that can be non-deterministic with multiple GPUs or when using thunderbolt docks.

// Previously: output "DP-1" {
output "Dell Inc. Dell S2716DG #ASOwvAqQj0Dd" {
    mode "2560x1440@143.998"
    // ...
}

I was also finally able to change the monitor sorting order to use the output name rather than the connector name, once again making it more deterministic. Note that this may swap your monitor positions if you were using multiple monitors and haven't manually configured them.

Transactional updates

One of Wayland's premises is that "every frame is perfect" except the first one. The compositor is in full control of the display, and window state changes are atomic and correlate to specific compositor requests.

This allows the compositor to synchronize updates for multiple windows: render the old state until all windows update, then switch to the new state all at once, with no broken frame in between.

However, possible doesn't mean easy, and different kinds of transactional updates need different approaches in the code. For this release, I implemented two relatively common cases.

Resizing

Thanks to the scrollable tiling nature, niri doesn't need to synchronize resizes among all windows on a workspace. However, windows in one column must still resize in unison: they must have the same width, and their heights must add up exactly to the monitor height.

niri-synchronized-resizing.mp4

Closing

Closing a window resizes all other windows in the column to take up the freed space. Normally, resize and close animations hide this, but if you disable animations, the flicker becomes very noticeable. The closing transaction fixes this: niri waits until other windows have resized before hiding the closed window.

niri-close-transactions.mp4

On-demand VRR

Thanks to @my4ng, we now have on-demand variable refresh rate as a window rule.

Some monitors flicker at the lowest VRR refresh rate, some drivers have VRR bugs, and some clients don't handle VRR too well. Now, niri can enable VRR only when a specific window is on screen (for example, a video player, or a game), thereby avoiding most of those issues.

Configure your output with on-demand=true:

output "Acer Technologies XV320QU LV 420615FCD4200" {
    // ...
    // This will keep VRR off unless enabled by a window rule.
    variable-refresh-rate on-demand=true
}

Then, add variable-refresh-rate true window rules as necessary:

// Enable VRR when mpv is on screen.
window-rule {
    match app-id="^mpv$"
    variable-refresh-rate true
}

NVIDIA flickering fix

There was a problem with NVIDIA flickering on niri, which the user could fix by enabling the wait-for-frame-completion-before-queueing debug flag. Turns out, this was only necessary because ages ago I forgot to add a check in the code. 🤦

Starting from this release, you should no longer need to set that debug flag, and NVIDIA GPUs should no longer flicker on niri out of the box (fingers crossed).

Small UX improvements

The horizontal touchpad swipe gesture will no longer go past the first or last column on the workspace.

niri-horizontal-gesture-snap-limit.mp4

And focus-follows-mouse will no longer "catch" windows on workspaces as you're switching away from them, which is especially important when using the new workspaces bar modules.

niri-focus-follows-mouse-during-workspace-switch.mp4

Other improvements in this release

  • Niri will now attempt to read the config file from /etc/niri/config.kdl when ~/.config/niri/config.kdl is missing.
  • Added an always-center-single-column layout option that makes a single column on a workspace always centered (thanks @elkowar).
  • Switching a workspace by index and back-and-forth is now animated the same way as switching a workspace up or down.
  • On-demand layer-shell surfaces will now automatically get focus when they appear, which works better with some application launchers like lxqt-runner.
  • Added a NIRI_DISABLE_SYSTEM_MANAGER_NOTIFY environment variable; when set to 1 it will suppress niri's own notification to systemd or NOTIFY_FD. This is useful for some custom systemd setups like uwsm.
  • Niri will try harder to light up monitors, which may help it get a better resolution on some multi-monitor setups on some hardware.
  • Fixed xdg-desktop-portal-gnome unable to open a file chooser from Xwayland windows.
  • Fixed crashes when a resume from suspend or a monitor power-on sends bogus vblank events on some hardware.
  • Fixed niri msg action do-screen-transition rendering wrong across monitor scale and transform changes.
  • Fixed move-column-to-workspace to a different output only moving one window and not the whole column.
  • Fixed set-window-height N% actually trying to use 100×N% height.
  • Fixed niri not informing layer-shell surfaces of changes to preferred scale and transform.
  • Portal screencasts now use damage to reduce unnecessary rendering.
  • Improved portal screencast frame timing to fix an occasional stuck wrong frame and niri sometimes sending frames too often.
  • Fixed unsync subsurfaces of layer-shell, cursors, and DnD icons not causing output redraws when they should. (Does anything even use those currently?)
  • Exclusive layer-shell surfaces are now preferred for keyboard focus to on-demand layer-shell surfaces on the same layer.
  • Updated Smithay:
    • Fixed layer-shell pop-up menu cursor input being slightly offset.
    • Fixed inverted scroll direction when running the compositor as a nested window.