github YaLTeR/niri v0.1.6

latest release: v0.1.7
one month ago

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 bit too long to switch, you can increase the delay during which the screen is frozen (defaults to 250 ms):

niri msg action do-screen-transition --delay-ms 500

Animation Custom Shaders

Finally, for something more advanced. I'm experimenting with the ability to set custom shaders for animations. Currently, I added support to all three base window animations (open, close, resize).

No, not those shaders.

For example, you can use a custom shader to change the default crossfade resize to an animation that crops the window when it is growing, and crossfades only when it is shrinking. This looks nicer for the text-heavy terminals since it avoids visually stretching the text.

niri-resize-shader.mp4

For the closing animation, I made a shader that makes the windows fall down and rotate, inspired by the S rank animation from osu!lazer:

niri-close-custom-shader.mp4

And for the opening, I made a simple expanding circle example:

niri-open-custom-shader.mp4

The way you make these shaders is by writing a GLSL function:

animations {
    window-resize {
        custom-shader r"
            vec4 resize_color(vec3 coords_curr_geo, vec3 size_curr_geo) {
                vec3 coords_tex_next = niri_geo_to_tex_next * coords_curr_geo;
                vec4 color = texture2D(niri_tex_next, coords_tex_next.st);
                return color;
            }
        "
    }
}

Like all other settings, custom shaders are live-reloaded as you edit the config. I've got detailed documentation with many examples, including all shaders above, in this folder.

Other improvements in this release

  • Niri will now guess the default scale factor for monitors, which should make HiDPI laptops get 200% scaling by default.
  • Some Intel multi-monitor setups that didn't work before will now work (niri now filters out CCS modifiers that increase required bandwidth).
  • Asahi and other ARM and kmsro devices will now work in more cases.
  • Made screencasting on Asahi work, at least in some cases.
  • On-demand layer-shell surfaces no longer receive exclusive keyboard focus. This fixes panels like xfce4-panel. On-demand focus will be properly implemented later.
  • Fixed IME popup positioning to be within the parent window and not obscure the input region (thanks @kchibisov).
  • Fixed screenshots not always pasting from the clipboard correctly.
  • Added Abgr8888 and Xbgr8888 formats to wl_shm which fixes some clients that assume they are always present.
  • Added a linear easing animation curve.
  • Fixed focus ring rendering above the fullscreen window backdrop.
  • Fixed border and focus ring config changes not applying until the next screen redraw.
  • Corrected the draw order for windows in the closing animation.
  • Updated Smithay, which:
    • Fixed drag-and-drop cursor sometimes getting stuck in Firefox.
    • Fixed a crash with clients using the virtual keyboard protocol.
    • Fixed some screen lockers like gtklock not working.
    • Fixed some wl_subsurface issues.
    • Fixed running on a TTY not working on some setups, like QEMU + virgl.
    • Slightly improved performance.

Don't miss a new niri release

NewReleases is sending notifications on new releases.