Skip to content

Releases: YaLTeR/niri

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

v0.1.3

09 Mar 11:12
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: 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.

Also, please consider including the wp-viewporter revert: 40cec34 to fix a mouse input bug with Chromium and Electron apps.

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!

Dramatic reenactment (this laptop doesn't have a touchscreen).

Gradient borders

Focus ring and borders can now use a linear gradient instead of a solid color!

image

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

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 to true will fullscreen the window upon opening, and setting it to false 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 saw mpv --fs do this, so it's not a big problem (you can just remove the mpv flag).

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/[email protected]
           ├─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 and systemctl import-environment.
  • Niri now sets XDG_CURRENT_DESKTOP and XDG_SESSION_TYPE in the main binary, rather than in the niri-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 the NOTIFY_SOCKET...
Read more

v0.1.2

17 Feb 05:33
Compare
Choose a tag to compare

Thanks everyone for 1000 stars! 🥳

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 libinput >= 1.21.

The new niri-visual-tests subcrate is development-only and should not be packaged. If you do cargo test --workspace, make sure to exclude it: cargo test --workspace --exclude niri-visual-tests, as it brings extra native dependencies.

Window opening animations

Windows now appear with an animation! Existing windows to the right move away, and the new window fades in, avoiding sudden visual jumps. All happening quickly enough to hopefully not be distracting.

niri-open-anims-release.mp4

More animations are coming, but they need time and work to implement right.

Animation settings

If you prefer reduced motion, or on the contrary if you want more animation, you can now set this up in a new animations config section. There's a flag to turn off, and a setting to adjust speed for all animations at once, as well as settings for every individual animation should you need it.

These settings replace the now-removed animation-slowdown debug flag.

Idle protocols

Niri now implements the ext-idle-notify and idle-inhibit pair of Wayland protocols. This allows tools like swayidle to work, and clients like mpv to pause them from working while you're watching videos.

As a bonus, I also implemented the org.freedesktop.ScreenSaver D-Bus interface for idle inhibiting, used by xdg-desktop-portal-gtk. This was necessary to make Flatpak Firefox correctly inhibit the idle state, and in general covers more applications.

Invoke actions via IPC

As the first expansion to the niri msg command, you can now invoke any bindable action with niri msg action do-something. That is, if you can bind something like Mod+F { maximize-column; }, then you can also call it programmatically with niri msg action maximize-column.

Turns out, one thing IPC actions are pretty convenient for is scripting video demos, like the one above!

Also, niri now has a way to report errors back to the IPC client, instead of leaving it in the dark for requests that don't otherwise need a response.

Window rules (the beginnings thereof)

You can now set some (at the moment, two) settings on a per-window basis. You can match or exclude windows from a rule with regular expressions on app-id and window title, similarly to other compositors. See the default config for a detailed explanation.

The settings you can currently set are default-column-width and open-on-output. Most notably, this lets you work around WezTerm's initial configure bug:

window-rule {
    // This regexp is intentionally made as specific as possible.
    // You can get away with app-id="wezterm" if you want.
    match app-id=r#"^org\.wezfurlong\.wezterm$"#

    default-column-width {}
}

More rules, including dynamically updating ones, are coming, after some refactors.

Better focus stealing prevention

To minimize your distraction, niri prevents new windows from taking focus while you're in a fullscreen application (I've had enough games ruined by a sudden Steam chat message). In this release, niri will additionally track when a newly opened window is a dialog from a particular existing window, and put that dialog to the immediate right from its parent window. The dialog will get focus only if the parent window was focused.

This change both prevents some random client from a different monitor/workspace from taking focus with a sudden dialog (looking at you, syncthing-gtk), and lets dialogs originating from fullscreen windows take focus as expected, bypassing the normal fullscreen focus stealing prevention.

Improved filtering in the hotkey overlay

The hotkey overlay shows a hardcoded set of binds that I deemed "most important". Included are the spawn actions, because binds like "spawn terminal" and "spawn application launcher" are definitely up there in the importance list.

However, not all commands you might want to spawn are that important, and with a lot of binds, the list could get polluted with many entries like XF86AudioRaiseVolume. Filtering based on program name doesn't sound very robust, so, instead, now the hotkey overlay will only show spawn binds with Mod or Super in the hotkey.

Additionally, out of multiple spawn binds to the same command, only the first one will show up in the hotkey overlay, which is consistent with all other hotkeys.

Before After
Hotkey overlay before the change. Hotkey overlay after the change.

Other improvements

  • Fixed a crash with some monitors with weird EDID data, and fixed inability to light up some monitors by filtering out interlaced modes.
  • Implemented DRM leasing. This lets you use VR applications and headsets with niri. Thanks @Supreeeme for working on this!
  • Added consume-or-expel-window-{left,right} actions that either expel the focused window into its own column, or consume a singular focused window into a column. These act as an alternative to the existing consume and expel commands, and are not bound to any keys by default. Thanks @exoticorn for implementing them!
  • Added a dwtp flag to touchpad settings for disable-when-trackpointing.
  • Added trackpoint input settings. Thanks @okvik for implementing them!
  • Added a way to bind / IPC-invoke quit while skipping the "Are you sure you want to exit niri?" dialog: Mod+Shift+E { quit skip-confirmation=true; }.
  • You can no longer spawn multiple lockscreen clients at once (more relevant now with swayidle).
  • Fixed binds like Super+Q not working (you had to spell it out as Mod+Super+Q).
  • Changed the default swaylock bind from Mod+Alt+L to Super+Alt+L to fix a collision with the Mod+L bind when running niri as a window (not sure how I missed this in testing). You don't usually want to "lock the screen" of a nested niri anyway.
  • Monitors powered off with DPMS will now light up upon switching the TTY back to niri.
  • The NIRI_SOCKET environment variable is now exported into the systemd and D-Bus session, which lets systemd units run niri msg. For example, this allows you to run swayidle as a systemd service.
  • Fixed a Smithay bug which mistakenly sent primary-selection to wlr-data-control v1 clients, causing them to crash (thanks @kchibisov).
  • Fixed border using focus ring's default values instead of its own.
  • Fixed omitting the layout config section resulting in gaps 0 instead of the default gaps 16.
  • Fixed target monitor not getting focus when pressing move-column-to-monitor-* on an empty source monitor.