Skip to content

Releases: YaLTeR/niri

v25.02

22 Feb 07:24
Compare
Choose a tag to compare

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=1 on a heavily multithreaded CPU. Please remove that variable if you had it set, so that we don't miss any new bugs.

niri-25-02.mp4

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!)

niri-tabs.mp4

There are a few new actions that help navigate the tabs. All of them also work on regular columns.

  • focus-window-top/bottom focuses the topmost or the bottommost window in a column.
  • focus-window-down-or-top and focus-window-up-or-bottom cycle 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.

Tab indicator at the top of the column.

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).

Shadows help to tell windows apart.

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.

Hard shadows example.

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
}

Shadow behind fuzzel.

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.

niri-dnd-edge-scroll.mp4

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"
    }
}

Screencasted window highlighted in a red color.

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):

Important Hotkeys with many customized titles.

These custom titles also support full Pango markup which allows you to change styles, colors, and fonts.

Important Hotkeys with custom Pango markup.

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.

niri-expand-to-available-width.mp4

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</k...

Read more

v25.01

11 Jan 17:27
e05bc26
Compare
Choose a tag to compare

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... hang on, how come we jumped from v0.1 all the way to v25?

Starting now, niri escapes ZeroVer is switching to year.month versioning. In 25.01, the "25" is year 2025, and "01" is month 01 (January). So version 25.01 tells you that this release was tagged in January of 2025.

Hotfix releases will use the third component. For example, the first hotfix for the 25.01 release would be called 25.01.1.

There are a few reasons for this change.

  • For niri, semver isn't very useful. Big and small features are added every release, and so far we've managed to avoid any breaking changes to the config file. Calendar versioning at least tells you how old of a version you're running.
  • v0.1.x left no place for a hotfix version. I couldn't even put v0.1.10.1 into Cargo.toml because it has four components instead of three. The new versioning has just two components, leaving one extra for the hotfix version.
  • I feel like niri is now sufficiently featureful to graduate from v0.1. :) I expanded the Status section of the README to cover some of the frequently asked "is this thing supported" questions.

Similar versioning is also used in other projects like Helix, NixOS and Ubuntu.

With this change, the niri releases remain unscheduled: once every few months, and not bound to any particular cycle. Whenever I feel that it's a good time for a new version.

Note

Packagers: niri now requires Rust 1.80. Also, there are new environment variables to override the niri version string and commit: NIRI_BUILD_VERSION_STRING and NIRI_BUILD_COMMIT. The new Packaging niri wiki page shows how to use them, along with everything else important for packaging.

New niri tests need XDG_RUNTIME_DIR to be set. You can use export XDG_RUNTIME_DIR="$(mktemp -d)".

If some tests fail with Err::AlreadyInUse on a heavily multi-threaded CPU, set RAYON_NUM_THREADS=1. This is tracked in #953.

Floating windows

Floating windows are here! It took a big refactor and a good month of hard work, but the most liked niri feature request is done.

Like other WMs, niri will auto-float dialogs and fixed-size windows. With no extra configuration, this release does away with most of the annoying dialog scrolling.

niri-floating-dialogs.mp4
Opening LibreOffice no longer causes the view to shift an ultrawide worth to the right.

Being a scrolling WM, there were several options and design decisions to consider for how floating windows should work. I opted for a setup familiar from other tiling WMs: floating windows are on a separate "layer" that always shows on top of the tiled windows, and the floating layout does not scroll. Each workspace/monitor has its own floating layout, just like each workspace/monitor has its own tiling layout.

Finally, you can properly showcase your scrollable-tiling WM setup.

There's a surprising number of features and small details that go into a good floating experience. Things like correct parent-child stacking, focus-follows-mouse activating but not raising the window, or restoring the floating size and position after moving the window to the tiling layout and back.

niri-floating.mp4

Since floating windows live on a workspace, and workspaces can move between monitors, it's important that floating windows never end up "out of bounds" and unreachable outside the monitor.

Internally, niri remembers floating window positions relative to the monitor size, and will always push windows slightly away from the monitor edges. This way, windows are always visible, and moving the workspace to a smaller monitor will roughly preserve the window layout. Furthermore, moving the workspace to a smaller monitor and back will restore the original window positions exactly.

In the following demo, I'm resizing a nested niri with three floating windows, simulating monitor resolution changes.

niri-floating-offscreen.mp4

There's a set of actions for focusing the floating or the tiling layout, and for moving windows around. The updated default config includes switch-focus-between-floating-and-tiling bound to ModShiftV and toggle-window-floating bound to ModV. All relevant existing binds keep working when the focus is on the floating layout, e.g. focus-column-right will activate the next floating window to the right.

Additionally, on a mouse, you can easily move a window between floating and tiling by right-clicking while dragging it. You can tell which of the two it "targets" by the presence of the tiling insertion hint.

niri-interactive-move-floating-switch.mp4

There's a new is-floating window rule matcher, and new open-floating and default-floating-position rules.

You can use open-floating to float some window that isn't covered by the auto-floating heuristics, like the Firefox Picture-in-Picture player. And default-floating-position supports putting floating windows relative to the four corners of a monitor:

// Open the Firefox Picture-in-Picture window at the bottom-left corner of the screen
// with a small gap.
window-rule {
    match app-id="firefox$" title="^Picture-in-Picture$"

    open-floating true
    default-floating-position x=32 y=32 relative-to="bottom-left"
}

Meanwhile, real tiling WM users like @algernon can set a blanket open-floating false rule to disable all auto-floating heuristics. Rest assured that our new set of 3135 snapshot tests across all possible window opening settings will keep this working.

All in all, this release contains a fairly complete per-workspace floating layout. Going forward, we can expand the functionality, for example by adding a sticky/show on all workspaces window flag. Or perhaps by putting modal dialogs as floating right into the scrolling layout.

Also, when resizing tiled windows, their height is now clamped to the monitor height. It used to be unlimited so that you could take window screenshots larger than the monitor size, but now you can do that with a floating window.

Layer-shell improvements

This release has several fixes to layer-shell handling.

  • @cmeissl fixed the problem where the pop-up menu on Waybar and other GTK 3 bars would sometimes get stuck and fail to open. The way it was fixed disables keyboard navigation in those menus, but this is consistent with other compositors like Sway.
  • @cmeissl also fixed some clients crashing when opening nested pop-up menus (like lxqt-panel app menus).
  • @calops fixed niri not always activating the window below when clicking through layer-shell surfaces. Previously, that code didn't account for the surface's input region.
  • Pop-up menus from all layer-shell surfaces now render on top of regular windows. So putting Waybar at the top layer is no longer necessary for usable context menus.
  • Niri will now give bottom and background layer-shell surfaces on-demand keyboard focus and allow them to take pop-up grabs.
  • Certain actions like focus-column-right will now move the focus from an on-demand layer-shell surface back to the main layout, allowing you to "escape" layer-shell with just a keyboard.

Combined, these improvements make the desktop icons components from LXQt and Xfce "just work" on niri. Thanks @stefonarch from LXQt for helping me test this and working on the LXQt niri session.

Xfce desktop icons with a context menu, terminal, and file manager on niri.

Layer rules

At last, you can block out layer-shell notifications from screencasts just like windows:

// Block out mako notifications from screencasts.
layer-rule {
    match namespace="^notifications$"
    block-out-from "screencast"
}

Layer rules work very similarly to window rules but with a different set of matchers and properties. See the wiki page for more details.

You can currently match by layer-shell namespace, and set block-out-from and opacity. To find out the namespace, use niri msg layers which lists all currently open layer-shell surfaces.

Drag-and-drop focus switch

Drag-and-dropping something will now focus the output where you dropped it. This makes dragging a Firefox tab to a different output open it on that output.

niri-firefox-dnd-to-different-monitor.mp4

Successful drag-and-dro...

Read more

v0.1.10.1

13 Nov 07:58
Compare
Choose a tag to compare

This is a hotfix release for niri v0.1.10.

  • Fixed scrolling not working when the mouse {} or touchpad {} section is omitted from the config file.
  • Made the mouse cursor show up on scroll which makes scrolling work when the cursor was hidden (thanks @r-vdp).
  • Fixed a crash when holding Space in the screenshot UI.
  • Bound touch-dragging with held Mod to interactive window move.

v0.1.10

09 Nov 16:06
Compare
Choose a tag to compare

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.

Interactive window moving

While not full-blown floating window support quite yet, this is an important step towards that. You can now move windows by dragging them by title bars, or anywhere while holding Mod.

niri-interactive-move.mp4

To prevent accidental layout changes, the windows rubber-band a little before you drag them out.

niri-interactive-move-rubberband.mp4

Furthermore, I made both interactive moving and resizing work on a touchscreen.

niri-touch-move-resize.mp4

Thanks to @Pajn for implementing a fairly complete proof-of-concept of this feature!

Locked pointer location hint

@sodiboo implemented the pointer location hint request. Apps like Blender use it to tell the compositor the final location after a locked pointer movement so that the compositor can update its own pointer location to match it.

niri-pointer-position-hint.mp4

Laptop lid and tablet mode switch bindings

Thanks to @cmeissl, you can now bind commands to laptop lid opening/closing and tablet mode switching. You can use this to automatically enable an on-screen keyboard when a convertible laptop enters tablet mode. See the switch events wiki page for more information and examples.

Additionally, I implemented disabling of the internal laptop monitor when closing the lid. So your workspaces will automatically move to the external screen. If for some reason this breaks for you, set the new keep-laptop-panel-on-when-lid-is-closed debug config flag.

Pointer hiding

@yzy-1 implemented new cursor hiding options: hide when typing (on any key press), and hide after a set inactivity period. See the wiki page for more details.

cursor {
    hide-when-typing

    // Or, after a timeout:
    // hide-after-inactive-ms 1000
}

To complement this, there are a few improvements to the hidden pointer behavior. The pointer will now show up on mouse button press, and on the contrary, it will stay hidden on programmatic and keyboard-triggered movement, like focusing a different monitor, or when using warp-mouse-to-focus.

Input configuration improvements

Thanks to @tazjin, @chillinbythetree and @elipp for:

  • Adding a trackball input config section.
  • Adding a scroll-button setting to mice, touchpads, trackpoints, and trackballs.
  • Adding a scroll-factor setting to mice and touchpads that you can use to speed up or slow down scrolling.

See the input config wiki page for more information.

Other improvements in this release

  • Tablet input no longer follows the monitor rotation: you need to rotate your graphics tablet together with your monitor. This makes convertible laptops work properly; this is also how input works on other desktop environments. Thanks @cmeissl.
  • The GTK Access portal is now explicitly set in niri-portals.conf, which makes it work. It is required for applications requesting PipeWire webcam and microphone access, such as the Firefox package on Fedora 41. Thanks @cmeissl.
  • The niri-ipc crate is now published to crates.io.
  • Active workspace is now preserved across monitor disconnects and reconnects.
  • Added a window --id argument to niri msg action consume-or-expel-window-left/right and to the IPC.
  • Added an explicit power-on-monitors action that can be useful with certain hardware. Niri still automatically powers on monitors on any input event.
  • Added support for running niri as a dinit service: files in resources/dinit/ and corresponding code in niri-session (thanks @markK24).
  • Added a disable-monitor-names debug config flag as a workaround for niri crashing when plugging in two monitors reporting the exact same make/model/serial. This issue is tracked in #734.
  • The focused window will now become visually inactive when a layer-shell app in front has keyboard focus.
  • Fixed focus-window-up-or-column-right focusing left instead of right.
  • Fixed an animation jump when expelling a narrower window from a column with uneven window widths.
  • Fixed the logind power key inhibit file descriptor leaking into processes spawned by niri.
  • Fixed window close view position restoration triggering for windows that didn't get focused upon opening.
  • Fixed a crash when an output disappears immediately after connecting.
  • Fixed used xdg-activation token memory leak.
  • Fixed lock screen clients hanging until a monitor is enabled when no monitors are enabled.
  • Updated Smithay:
    • Fixed memory leak when locking the screen.
    • Fixed occasional visual freezing of GTK and other apps.
    • Fixed a regression that made it so increasing the output scale in niri v0.1.9 didn't propagate to some clients, keeping them blurry.

v0.1.9

14 Sep 11:44
Compare
Choose a tag to compare

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 "[email protected]"
    // ...
}

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...

Read more

v0.1.8

10 Aug 12:40
Compare
Choose a tag to compare

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.

Today is a special day. Niri is one year old! πŸ₯³

β”Œ (main) ~/s/r/niri
└─ git show --format='commit %H%nCommitDate: %cd%n%n    %s' --no-patch ad3c3f8
commit ad3c3f8cefd38d2bf26b466d8e34eccde3bca443
CommitDate: Thu Aug 10 14:49:38 2023 +0400

    Init from smallvil

We've come a long way since then! I am very happy with how niri is shaping up. I am especially grateful to 45 (!) contributors who have volunteered their time to improve something in the compositor over the year.

We also managed to amass more than 3000 stars, and almost 400 people in our comfy Matrix room!

Nevertheless, there's plenty to be done. Without further ado, here are the improvements from the last release.

Note

Packagers: niri now requires pango >= 1.44 and rust >= 1.77.

Gradient border color spaces

A big thanks to @CaliOn2 for overhauling gradient rendering in niri, adding support for interpolation color spaces! You can now set gradient borders to draw not just in srgb, but also in srgb-linear, oklab and oklch, the latter with support for {shorter,longer,increasing,decreasing} hue.

Which means that you can now have beautiful rainbow gradient borders:

Alacritty with a rainbow border via an "oklch longer hue" gradient

layout {
    border {
        active-gradient from="red" to="orange" angle=45 in="oklch longer hue"
    }
}

As usual, niri gradients are rendered the same way as CSS linear-gradient(), so you can use any browser tool to configure them.

Additionally, @my4ng debugged and fixed gradients rendering with a sharp edge on NVIDIA, and I fixed gradient rendering being reversed at angle=90.

Screenshot UI pointer toggle

You can now toggle mouse pointer visibility in the screenshot UI by pressing P. I added a new help panel to remind you of this, and to explain how to capture the screenshot.

niri-screenshot-ui-panel.mp4

Also, the screenshot UI now fades in. (As usual, you can disable this animation if you don't like it.) Finally, I fixed some minor regressions with area selection that were introduced in the fractional scaling refactor.

Key repeat for binds

Thanks to @salman-farooq-sh, niri now has key repeat for all binds. This is especially useful for binds that control volume and brightness. Or for having some fun by spawning a ton of windows.

niri-key-repeat.mp4

You can disable key repeat for specific binds using the new repeat=false property:

binds {
    // Disable key repeat for this bind.
    Mod+T repeat=false { spawn "alacritty"; }
}

Focus-follows-mouse improvements

Being a scrollable-tiling compositor, niri faces some unique design challenges for otherwise commonplace functionality. One particularly annoying example was unwanted view movement caused by focus-follows-mouse.

When using niri, you will frequently have windows partially off-screen. With focus-follows-mouse, moving the cursor over such a window would focus it and scroll it into view. This is especially problematic if you have two monitors side-by-side, and just want to move the mouse to the other monitor.

To figure out the solution, I outlined all problems and possible solutions in a GitHub discussion. Some very productive brainstorming followed, and a solution emerged: a view scroll threshold for focus-follows-mouse.

In the config, you can now set a property on focus-follows-mouse:

input {
    focus-follows-mouse max-scroll-amount="0%"
}

This number controls how much scrolling is allowed to happen for focus-follows-mouse to trigger. With 0% (the new suggested default), focus-follows-mouse will only focus a window if it does not cause any scrolling. You can also set this to bigger values, e.g. 10% will restrict it to when the view scrolls no more than 10% of the screen width.

niri-focus-follows-mouse-threshold.mp4

I've personally been avoiding focus-follows-mouse in niri in the past precisely because of the undesired scrolling, but max-scroll-amount="0%" had pretty much solved that problem, so since then I've been using it just fine.

This release has another fix to focus-follows-mouse: when using the always-centered mode, it will no longer cause rapid window scrolling. The issue was the way the logic interacted with pointer focus update suppression during animations.

wlr-output-management

@gmorer implemented the wlr-output-management protocol, which means that you can now use third-party tools like kanshi or wdisplays to configure the outputs in niri.

Checking display settings in wdisplays

Keep in mind that changes applied this way are transient and are not automatically saved into your niri configuration, just like the niri msg output command.

wlr-screencopy version 3

Niri had supported wlr-screencopy version 1 since v0.1.3. This was enough for screenshot tools like grim, but not for screen recording tools. This was an intentional choice, as the screen recording parts of this protocol are quite complex, and need a very different implementation from the existing PipeWire screencasting.

For this release, @my4ng dived in and implemented it! Now, niri supports wlr-screencopy version 3 and you can use tools like wf-recorder and wl-mirror.

niri-wf-recorder.mp4

As a bonus, I found and fixed a bug in region capture with a fractional scale.

Negative struts

@salman-farooq-sh implemented a small change to allow strut config values to go negative. It's not obvious at first why this is needed (why would you want windows to peek outside the screen bounds?), but actually, this is an elegant solution for having smaller outer gaps than inner gaps.

In niri, one of the design principles is that opening a new window never causes existing windows to resize. Turns out, this restriction prevents differentiating horizontal inner and outer gaps. Imagine inner gaps = 10 and outer gaps = 0. A single 50%-wide window should then take exactly 50% of the screen. But then, opening a second window introduces an inner gap, so now the first window must occupy (50% minus a half gap), requiring a resize!

Negative struts work around this problem. All gap values remain equal, but you can use left and right strut values equal to negative gap size to "push" the "outer" gaps off-screen. Visually, this looks the same as having no outer gaps, while not causing any unintended window resizes.

Inner gaps without outer gaps in niri

layout {
    gaps 16

    struts {
        left -16
        right -16
        top -16
        bottom -16
    }
}

PipeWire screencast fixes

I implemented the full DMA-BUF modifier negotiation procedure for PipeWire screencasts (when using xdg-desktop-portal-gnome). As an immediate benefit, it makes screencasting work on NVIDIA. It should also fix GStreamer-based screen recording tools like Kooha, however, I have not been able to get this to work just yet. Perhaps it'll start working with the next PipeWire release? We'll see.

Wiki configuration snippet tests

This is not directly related to running niri, but is very cool nonetheless! @Suyashtnt implemented a test that verifies that every single config example on the wiki successfully parses. Combined with the fact that every single config option has an example code block, we should be very much set to catch any unintentional config parsing regressions.

Nightly COPR

With some help from @my4ng, I set up a COPR with automatic git niri builds: https://copr.fedorainfracloud.org/coprs/yalter/niri-git

Turns out, this is quite easy, and involves adding a special template .spec file into the repository, and setting up a webhook so GitHub can tell COPR to trigger a build when the main branch is updated.

If you run Fedora, you can use this new COPR to stay more up-to-date with niri development.

Other improvements in this release

  • Implemented on-demand keyboard focus mode for layer-shell surfaces, which is used by some newer bar applications.
  • Added focus-window-or-monitor-{up,down} actions (thanks @TheAngusMcFire).
  • Added move-column-left-or-to-monitor-left and move-column-right-or-to-monitor-right actions (thanks @brainlessbitch).
  • Added a middle-emulation flag to touchpad, mouse, and trackpoint settings.
  • Added a background-color option to outputs that sets the color of the default niri solid background. You can use this if you don't want to run any third-party background tools. Thanks @anant-357!
  • Added Mod3/ISO_Level5_Shift modifier support to key bindings (thanks @jpeeler).
  • Enabled sub-pixel glyph positioning for better kerning in niri panels.
  • Added a profile-with-tracy-ondemand build feature that produces a build with on-demand Tracy pr...
Read more

v0.1.7

29 Jun 07:10
Compare
Choose a tag to compare

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.

Fractional Scaling

The big update this time is fractional scale support. You can set output scale to fractional values like 1.5 and automatic scale factor guessing will now return fractional scale factors.

On the surface this sounds simple, but under the hood, doing it properly required a complete refactor of the layout system to use fractional coordinates and sizes (and then chasing down all of the bugs caused by this).

The result is well worth it though. Borders, gaps and windows are always physical-pixel aligned, and not restricted to integer logical pixel positions. There's no blur or position-dependent +-1 px jank. Fractional-scale-aware clients remain crisp at any scale.

Here's a demo of going through every single currently representable fractional scale factor between 100% and 200% where everything remains crisp, including a 1 px checkerboard in mpv. Watch it in the native 1920Γ—1080 resolution if you want to see the checkerboard correctly.

niri-scale.mp4

As a bonus, you can set the scale to a value below 1, which will make things smaller and give you more space. This could be useful in specific cases like monitors with very big pixel size, but it will lose you some image crispness.

Fractional Layout

As previously mentioned, niri layout now completely operates in floating-point. While fractional scaling benefits the most from this, fractional layout is also useful for integer scales.

Concretely, you can now set border and focus ring width, gaps, struts to fractional values, which will round to physical pixels according to the monitor's scale factor. Which means you can have 1 px wide borders on a 200% monitor for example by setting the border width to 0.5.

The view position is also no longer restricted to integer logical pixels, so when you do a touchpad swipe gesture on a 200% monitor, windows will move in single physical pixel increments.

If you're interested in the technical details of how this works, check this wiki page.

Window Screencasts

You can now select an individual window to screencast through xdg-desktop-portal-gnome. You can resize windows, open pop-ups, use block-out rules, and it will all work correctly.

niri-window-screencast-2.mp4

This involved some refactoring of the PipeWire screencasting code in niri, most notably adding support for changing the video stream size on the fly. As a bonus, monitor screencasts will now also keep running through monitor resolution changes.

I still need to work out some details like frame callback delivery to obscured windows, but the current implementation should already work for a lot of use cases.

xdg-activation

@pcc implemented the xdg-activation-v1 protocol which allows apps to pass focus to other apps. For example, clicking on a link in a GTK 4 app will now automatically focus your browser, switching the workspace if necessary.

niri-xdg-activation.mp4

This protocol is also used by clients to indicate urgency; this part is not implemented yet (but planned).

Workspace Switch Mouse Gesture

Last release I added the horizontal Mod + middle mouse drag gesture to scroll the view. This release I also added the vertical drag gesture to switch workspaces, just like on a touchpad you can swipe both horizontally and vertically.

niri-vertical-mouse-gesture.mp4

Other improvements in this release

  • Added four actions focus-window-{up,down}-or-column-{left,right} which allow traversing all windows on a workspace in order (thanks @minego).
  • Added actions focus-column-right-or-first, focus-column-left-or-last which allow the focus to loop around (thanks @sullyj3).
  • Added actions focus-column-or-monitor-left and focus-column-or-monitor-right that switch the monitor upon reaching the end of the workspace.
  • Added niri msg focused-output which returns information about the currently focused output (thanks @rustysec).
  • Added off flag to disable input devices (thanks @yuja).
  • Added left-handed flag to touchpad, mouse, tablet input config.
  • Added scroll-method property to touchpad, mouse, trackpoint input config (thanks @yuja).
  • Added disabled-on-external-mouse flag to touchpad input config (thanks @yuja).
  • Niri now additionally reads the config file path from $NIRI_CONFIG, to help with nix wrappers. The --config flag still takes precedence (thanks @sodiboo).
  • Changed absolute pointer input to work over a union rectangle across all outputs, rather than picking a single output (thanks @galister).
  • Changed tablet input without a specific map-to-output to map to a union rectangle across all outputs. This makes Open Tablet Driver work.
  • Changed foreign-toplevel (i.e. Waybar) window activation to animate the workspace switch.
  • Changed output scale setting to no longer require the fractional part, i.e. scale 2 will work.
  • Fixed focus-window-or-workspace-{up,down} missing the workspace switch animation.
  • Fixed empty named workspaces disappearing upon output removal.
  • Fixed a crash when an (already unfullscreened) window that in a column with other windows requests to be unfullscreened.
  • Fixed key repeat not working when the keyboard config section is missing.
  • Fixed some crashes when no outputs are connected. On some devices outputs reconnect themselves upon resuming from sleep, which was triggering these issues.
  • Fixed rounded corners rendering blurry on very high scale factors.
  • Fixed the automatic draw border with background check to also include the KDE decoration protocol value. This makes it work for some older clients like GTK 3 (thanks @kchibisov).
  • Fixed ISO_Level3_Shift modifier not showing up in the Important Hotkeys list.
  • Niri now increases the fd limit to the maximum, fixing some fd-heavy clients (e.g. running RustRover in Xwayland).
  • Updated Smithay, which fixes running on the NVIDIA 555 driver (explicit sync is still not implemented for now).

v0.1.6

18 May 11:35
Compare
Choose a tag to compare

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.

We've now got a small setup showcase thread, be sure to check it out!

And here are the improvements from the last release.

Gestures

In this release, I added mouse gestures for resizing and scrolling the view. I also made a wiki page listing all existing gestures.

Interactive Window Resizing

You can now resize windows interactively with a mouse (yes, finally). Both by edge-dragging windows with client-side decorations, and anywhere on a window by holding Mod together with the right mouse button.

To complement this, there are two new double-click gestures: double-clicking a resize will expand the window to the full monitor width, or reset the window height to take up all available space, depending on the edge that you double-click. Thanks @FreeFull for suggesting these gestures!

Resetting the window height is also available as the new reset-window-height key binding.

niri-interactive-resize.mp4

Despite the ubiquity, interactive resizing proved quite tricky to implement with plenty of edge cases (tiling makes it harder since multiple things need to coordinate together). The main challenge stems from the fact that when resizing a window by the left edge, its right edge should stay in place, which means that the window itself must move to the left, strictly in sync with changing size. Throw into the mix slow windows (the red rectangle on the video), windows not strictly obeying the given size (e.g. terminals snapping to the cell grid), and multiple windows in a column (which must all resize together), and you've got a wild asynchronous cocktail.

There was even a Chromium bug involved in this one, and a similar Firefox issue is waiting on a recent GTK 3 update.

Mouse View Scrolling

Holding Mod and the middle mouse button (scroll wheel) will now let you scroll the view. This uses the touchpad swipe gesture code with all its decelerated spring animation goodness, but makes sure that the spot that you "grabbed" stays locked to the mouse cursor.

niri-mouse-view-gesture.mp4
Quite embarrassing how long it took me to come up with this one, considering I am primarily a mouse user.

Functionality

This release also adds some nice new functionality.

Named Workspaces

You can now declare named workspaces in the config.

workspace "browser"

workspace "chat" {
    open-on-output "DP-2"
}

Unlike normal (dynamic) workspaces, named workspaces are persistent (they are not deleted when they have no windows), but otherwise they behave just like normal workspaces: you can reposition them and move to different monitors.

Actions like focus-workspace or move-column-to-workspace can refer to workspaces by name in addition to by index. Also, you can use the new open-on-workspace window rule to make a window open on a specific named workspace:

// Declare a workspace named "chat" that opens on the "DP-2" output.
workspace "chat" {
    open-on-output "DP-2"
}

// Open Fractal on the "chat" workspace.
window-rule {
    match app-id=r#"^org\.gnome\.Fractal$"#
    open-on-workspace "chat"
}

You can find a few more details on the wiki page.

Named workspaces should mostly solve the "shove a bunch of windows on correct monitors at startup" problem while working seamlessly with the dynamic workspace system. Thanks to @algernon for implementing this!

IPC Improvements

The new niri msg output command lets you apply transient output configuration changes. It uses the same syntax as the config file, e.g. niri msg output eDP-1 scale 2. These changes will persist until you edit the output settings in the config file (or restart niri).

While adding this, I also made output names case-insensitive, both for niri msg output and for the config file, which should make things less annoying.

Additionally, @rustysec added a niri msg workspaces command which will be extra useful now with the introduction of named workspaces:

β”Œ ~
└─ niri msg workspaces
Output "DP-2":
   1 "chat"
   2 "browser"
 * 3
   4

Output "eDP-1":
   1 "notes"
 * 2
   3

Like with other IPC commands, you can use the --json flag to get the same data in a machine-readable form.

New Window Rules

You can now set focus-ring and border properties in window rules to override them for specific windows.

The new is_active_in_column matcher, added by @TheZoq2, can be used to make a magnifier-like window layout:

window-rule {
    match is-active-in-column=false

    min-height 100
    max-height 100
}

Finally, the new at-startup matcher will match during the first 60 seconds after niri startup. You can combine it with open-on-output or open-on-workspace properties to put windows where they belong when starting the session, but not afterward. I found it quite useful for e.g. browsers where I want new windows to open normally as I go on with my day, rather than keep spawning on the same monitor and workspace.

// Open Firefox maximized on the "browser" workspace, but only at niri startup.
window-rule {
    match at-startup=true app-id=r#"^org\.mozilla\.firefox$"#

    open-on-workspace "browser"
    open-maximized true
}

Debugging Features

There are a few new debugging features:

  • The debug-toggle-opaque-regions bind will draw regions marked as opaque in blue and others in red.

  • The debug-toggle-damage bind will draw the damage computed for the screen. Kind of, mostly. Good enough to tell when something wrong is going on.

  • The disable-direct-scanout flag disables direct scanout to the primary and the overlay planes.

Eye candy

Of course, there are also new eye candy features!

Rounded Window Corners

Niri can now do corner rounding, a clear must-have feature for any self-respecting Wayland compositor. I've got quite an extensive implementation here, actually. Let's take a look.

You set the radius with the new geometry-corner-radius window rule.

By itself, it doesn't clip the window but merely informs elements like the border and the focus ring which window radius they should assume. This means that you can keep using client-side-decorated windows with their own rounded corners and shadows, and have the borders drawn with the right radius.

window-rule {
    geometry-corner-radius 12
}

This sets the radius of the window geometryβ€”the inner radius of the border. The outer border radius is computed automatically taking the border width into account.

You can even set a separate radius for every corner, for example, to match GTK 3 applications:

window-rule {
    match app-id="^gnome-terminal-server$"
    geometry-corner-radius 8 8 0 0
}

No, I don't particularly see anyone going out of their way to set this up for every window.

Next, the new clip-to-geometry window rule will make niri actually clip windows to their geometry, including the geometry-corner-radius that you have set.

window-rule {
    geometry-corner-radius 12
    clip-to-geometry true
}

Combine this with prefer-no-csd to get the classic rounded corner setup that works on all windows:

prefer-no-csd

layout {
    focus-ring {
        off
    }

    border {
        width 2
    }
}

window-rule {
    geometry-corner-radius 12
    clip-to-geometry true
}

All of this works correctly with subsurfaces, windows blocked out from screencasts, transparency, resize and other animations. And whenever possible, there's no overhead: opaque regions are preserved (except for the corners themselves), and even overlay plane unredirection still works for subsurfaces completely inside the clipped geometry!

Tricky Cases Opaque Regions Unredirection

Screen Transition

I added a do-screen-transition action which lets you switch between light and dark, or between different themes, smoothly like in GNOME Shell.

niri-screen-transition.mp4

The key is to make sure the applications themselves switch their theme without animation and as fast as possible, then niri's own screen transition will make it look nice and synchronized.

If your apps take just a...

Read more

v0.1.5

20 Apr 13:55
Compare
Choose a tag to compare

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.

This time I decided to update the demo video in the README. Here's the new video if you're curious:

demo.mp4

Now let's go over the improvements from the last release.

More animations

A big focus in this release was on animations. I've animated many more actions: window movement, resizing, and closing. Each of these was challenging to implement in its own way, but I'm quite happy with the end result.

niri-new-anims.mp4

Naturally, all animations work well with windows blocked out from screencasts.

As usual, you can disable or configure individual animations if you prefer. Find instructions on the wiki page.

While working on these animations, I fixed a few minor issues with view positioning. So niri now works better even with animations disabled.

Spring animation improvements

Spring animations are now more robust: values and durations are clamped more aggressively where it makes sense. For example, a bouncy window opening animation will become fully opaque upon reaching the full window size, and won't become transparent again during the following bounces.

niri-open-anim-clamp.mp4

Also, when using slowdown, the touchpad gesture velocity is now scaled by the slowdown factor, making the animation smoother.

Variable refresh rate

Niri now has basic variable refresh rate (VRR) support. You can enable it by setting a variable-refresh-rate flag in the output config. Check the wiki for an example and caveats.

Additionally, niri msg outputs now shows whether VRR is supported and enabled.

IPC improvements

niri msg received a few quality-of-life improvements thanks to @sodiboo:

  • Added niri msg version that shows the running niri compositor version and the niri CLI version. They are the same binary, so their versions should match, but they can briefly go out of sync after a niri update.
  • When niri msg receives an error from the compositor, it will now check if the compositor and the CLI versions match, and if not, print a message reminding you that you may need to restart niri.
  • Added niri msg request-error that will always result in an error from the compositor. This can aid in script development to check that your error handling works right.

Other improvements in this release

  • Added an allow-when-locked=true flag for spawn key bindings that makes them work when the session is locked. Check the wiki for an example.
  • Previous view position is now restored upon unfullscreening a window.
  • The SIGPIPE handler is now set to default in niri msg to prevent panic backtraces from showing up when stdout is closed.
  • The mouse cursor is now hidden upon touchscreen interaction.
  • Corrected some DRM leasing behavior to fix crashes when DRM leasing is unavailable and better handle hotplugging.
  • Added an ease-out-quad easing curve.
  • Fixed warp-mouse-to-focus not triggering when a window is closed by unmapping its buffer.
  • Fixed the horizontal touchpad gesture redrawing continuously rather than only on touchpad events.
  • Fixed overdamped spring instability being able to crash the compositor.
  • Added a microphone mute example bind to the default config.

v0.1.4

30 Mar 11:09
Compare
Choose a tag to compare

Before we begin: downgrade xz to v5.4. Done? Good, let's get to the 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.

Block out windows from screencasts

You can now instruct niri to block out certain windows from screencasts with a window rule. This can be useful for apps like password managers or messengers that you don't want to accidentally show during meetings or streams.

Screenshot showing a visible Secrets window and an OBS window screencasting the screen where there's a black rectangle instead of the Secrets window.

The compositor (niri in this case) is the perfect place for this functionality since it is solely responsible for the video frames sent to displays and screencast clients like OBS. Plus, the compositor has the entire window tree, and can selectively block out individual windows while retaining correct layered compositing.

This blocking out also seamlessly works with the built-in screenshot UI. You can capture a screenshot with interactive area selection while seeing all windows normally, and on a screencast, this entire process, including the interactive selection UI, will have the windows correctly blocked out.

block-out-from.mp4

Unfortunately, this kind of tight integration is not possible with third-party screenshot annotation/preview tools. To avoid accidentally showing windows even when using third-party screenshot tools, niri provides a more aggressive mode that blocks out the window from all screen capture tools, not just xdg-desktop-portal screencasts.

Dynamic window rules

Window rules, introduced in the last release, let you adjust behavior for individual windows. For this release, I did the necessary refactors to support dynamic window rules that apply continuously to open windows.

The main example of course is the rule to block out windows from screencasts (described above), but you can also override whether borders draw with a solid background, change the window size limits and adjust window opacity.

As an example, you can replicate the "inactive windows become semitransparent" effect:

window-rule {
    match is-active=false
    opacity 0.9
}

Screenshot showing three apps, the middle one focused, and the ones on the side are semitransparent.

Check out the window rules wiki page for a complete list of properties that you can set.

By the way, I also added a little niri msg focused-window IPC command that shows you the title and app ID of the focused window, to aid in writing rule matchers.

Warp mouse to focus & focus follows mouse

Two popular features among tiling WMs, now in niri.

Warp mouse to focus, implemented by @FluxTape (thanks!), will automatically move the mouse into windows as you focus them. Focus follows mouse on the other hand will automatically focus windows under the cursor as you move it around.

These two actually work very well together, give it a try!

niri-warp-mouse-focus-follows.mp4

Mouse and touchpad scroll bindings

It is now possible to bind mouse wheel and touchpad scrolls to perform actions or spawn commands. Mouse scrolling activates every wheel "tick", whereas touchpad scrolling emulates scroll "ticks" based on finger distance traveled.

Additionally, you can now set a cooldown for binds to avoid triggering them too often with scrolling.

binds {
    Mod+WheelScrollDown cooldown-ms=150 { focus-workspace-down; }
    Mod+WheelScrollUp   cooldown-ms=150 { focus-workspace-up; }

    Mod+TouchpadScrollDown { spawn "wpctl" "set-volume" "@DEFAULT_AUDIO_SINK@" "0.02+"; }
    Mod+TouchpadScrollUp   { spawn "wpctl" "set-volume" "@DEFAULT_AUDIO_SINK@" "0.02-"; }
}

Check the wiki page for more details.

wlr-gamma-control

Niri now implements the wlr-gamma-control protocol that is required for "Night Light" tools like wlsunset and gammastep. Thanks @phuhl for working on this!

Note

As it turns out, setting the gamma is pretty slow, at least on my system. I suggest using wlsunset because it only sets the gamma when it needs to change, rather than, say, every few seconds unconditionally.

xdg-desktop-portal-gnome 46.0

I implemented more of the Mutter D-Bus interface to support xdg-desktop-portal-gnome 46.0 with its new screencast monitor selector with visual positions:

Screenshot of the new monitor selector in xdg-desktop-portal-gnome 46.0.

Documentation

As you've noticed, I've been linking the wiki pages a lot. The reason for this is that over the past week I went through the entire config and wrote detailed documentation and examples for every single option.

Check out all this documentation here on the wiki: https://github.com/YaLTeR/niri/wiki/Configuration:-Overview

A major benefit of this is that it allowed me to declutter the default config by removing some of the less important things and instead linking the wiki. This will improve the experience for people trying out niri as they no longer need to sift through the entire window rule and animation examples.

If you find a mistake, feel free to open a pull request against the wiki/ folder of the repository.

Also, shoutouts to great reference-style docs @sodiboo had been writing for the nix flake: https://github.com/sodiboo/niri-flake/blob/main/docs.md#programsnirisettings

Other improvements in this release

  • When opening and closing a window without switching focus in between (think various dialogs and temporary windows), niri focuses the previous window since that's where you came from. Now, when this happens, niri will also restore the view position, which makes the behavior more natural and less annoying.
  • Fixed wp-viewporter bugs in Smithay (thanks @cmeissl). Particularly, this prevented Chromium and Electron applications from accepting mouse input after resizing.
  • Added more information to niri msg outputs (logical output position, size, scale, transform, and current and preferred mode flags).
  • Added a click-method input setting for touchpads (thanks @uetcis).
  • Added a workspace-auto-back-and-forth setting that causes switching to the same workspace by index twice to switch back to the previous workspace (thanks @FluxTape).
  • Added support for ISO_Level3_Shift / Mod5 modifier (thanks @Trundle).
  • Added a once-per-second fallback timer that sends frame callbacks to off-screen windows, which fixes issues with vsynced games in gamescope.
  • The last folder in the screenshot path is now automatically created if it doesn't exist.
  • Corrected pointer location reported to lock screen surfaces.
  • Fixed niri crashing when a screencast is attempted after failing to initialize PipeWire.
    • If on your system PipeWire is not started automatically, you need to make sure that it is started before niri for niri to have screencast support.
  • Fixed a crash that could happen when stopping the same screencast session twice with the right timing.
  • Relaxed checks for DRM render nodes, which in theory allows niri to run on more devices with split DRM display/render nodes (various ARM boards like Raspberry Pi).
  • Made the EGL wl-display extension optional on the TTY which makes niri work on some NVIDIA GPUs where it didn't before.
  • Niri now tries to reduce the max bits-per-channel output property to 8 which may result in more monitor configurations working.
  • Fixed building on musl.
  • Fixed mouse scrolling inside nested niri window sometimes being too slow.
  • Fixed hardcoding us as the keyboard layout when it is missing from the config (turns out libxkbcommon handles that one for us).