Skip to content

Latest commit

 

History

History
2536 lines (1621 loc) · 100 KB

docs.md

File metadata and controls

2536 lines (1621 loc) · 100 KB

Packages provided by this flake

packages.<system>.<name>

(where <system> is one of: x86_64-linux, aarch64-linux)

Important

Packages for aarch64-linux are untested. They might work, but i can't guarantee it.

You should preferably not be using these outputs directly. Instead, you should use overlays.niri.

packages.<system>.niri-stable

The latest stable tagged version of niri, along with potential patches.

Currently, this is release v0.1.10-1 with no additional patches.

To access this package under pkgs.niri-stable, you should use overlays.niri.

packages.<system>.niri-unstable

The latest commit to the development branch of niri.

Currently, this is exactly commit 82e3024 which was authored on 2024-12-11 18:39:58.

Warning

niri-unstable is not a released version, there are no stability guarantees, and it may break your workflow from itme to time.

The specific package provided by this flake is automatically updated without any testing. The only guarantee is that it builds.

To access this package under pkgs.niri-unstable, you should use overlays.niri.

overlays.niri

A nixpkgs overlay that provides niri-stable and niri-unstable.

It is recommended to use this overlay over directly accessing the outputs. This is because the overlay ensures that the dependencies match your system's nixpkgs version, which is most important for mesa. If mesa doesn't match, niri will be unable to run in a TTY.

You can enable this overlay by adding this line to your configuration:

{
  nixpkgs.overlays = [ niri.overlays.niri ];
}

You can then access the packages via pkgs.niri-stable and pkgs.niri-unstable as if they were part of nixpkgs.

nixosModules.niri

The full NixOS module for niri.

By default, this module does the following:

  • It will enable a binary cache managed by me, sodiboo. This helps you avoid building niri from source, which can take a long time in release mode.
  • If you have home-manager installed in your NixOS configuration (rather than as a standalone program), this module will automatically import homeModules.config for all users and give it the correct package to use for validation.
  • If you have home-manager and stylix installed in your NixOS configuration, this module will also automatically import homeModules.stylix for all users.

programs.niri.enable

  • type: boolean
  • default: false

Whether to install and enable niri.

This also enables the necessary system components for niri to function properly, such as desktop portals and polkit.

programs.niri.package

The package that niri will use.

You may wish to set it to the following values:

niri-flake.cache.enable

  • type: boolean
  • default: true

Whether or not to enable the binary cache niri.cachix.org in your nix configuration.

Using a binary cache can save you time, by avoiding redundant rebuilds.

This cache is managed by me, sodiboo, and i use GitHub Actions to automaticaly upload builds of pkgs.niri-stable and pkgs.niri-unstable (for nixpkgs unstable and stable). By using it, you are trusting me to not upload malicious builds, and as such you may disable it.

If you do not wish to use this cache, then you may wish to set programs.niri.package to pkgs.niri, in order to take advantage of the NixOS cache.

homeModules.niri

The full home-manager module for niri.

By default, this module does nothing. It will import homeModules.config, which provides many configuration options, and it also provides some options to install niri.

programs.niri.enable

  • type: boolean
  • default: false

Whether to install and enable niri.

This also enables the necessary system components for niri to function properly, such as desktop portals and polkit.

programs.niri.package

The package that niri will use.

You may wish to set it to the following values:

homeModules.stylix

Stylix integration. It provides a target to enable niri.

This module is automatically imported if you have home-manager and stylix installed in your NixOS configuration.

If you use standalone home-manager, you must import it manually if you wish to use stylix with niri. (since it can't be automatically imported in that case)

stylix.targets.niri.enable

Whether to style niri according to your stylix config.

Note that enabling this stylix target will cause a config file to be generated, even if you don't set programs.niri.config.

This also means that, with stylix installed, having everything set to default does generate an actual config file.

homeModules.config

Configuration options for niri. This module is automatically imported by nixosModules.niri and homeModules.niri.

By default, this module does nothing. It provides many configuration options for niri, such as keybindings, animations, and window rules.

When its options are set, it generates $XDG_CONFIG_HOME/niri/config.kdl for the user. This is the default path for niri's config file.

It will also validate the config file with the niri validate command before committing that config. This ensures that the config file is always valid, else your system will fail to build. When using programs.niri.settings to configure niri, that's not necessary, because it will always generate a valid config file. But, if you set programs.niri.config directly, then this is very useful.

type: variant of

Some of the options below make use of a "variant" type.

This is a type that behaves similarly to a submodule, except you can only set one of its suboptions.

An example of this usage is in animations.<name>, where each event can have either an easing animation or a spring animation.
You cannot set parameters for both, so variant is used here.

programs.niri.package

The niri package that the config is validated against. This cannot be modified if you set the identically-named option in nixosModules.niri or homeModules.niri.

programs.niri.config

  • type: null or string or kdl document

The niri config file.

  • When this is null, no config file is generated.
  • When this is a string, it is assumed to be the config file contents.
  • When this is kdl document, it is serialized to a string before being used as the config file contents.

By default, this is a KDL document that reflects the settings in programs.niri.settings.

programs.niri.finalConfig

  • type: null or string

The final niri config file contents.

This is a string that reflects the document stored in programs.niri.config.

It is exposed mainly for debugging purposes, such as when you need to inspect how a certain option affects the resulting config file.

programs.niri.settings

  • type: null or (submodule)
  • default: null

Nix-native settings for niri.

By default, when this is null, no config file is generated.

Beware that setting programs.niri.config completely overrides everything under this option.

programs.niri.settings.binds

  • type: attribute set of niri keybind

programs.niri.settings.binds.<name>.action

  • type: niri action, which is a kdl leaf

An action is represented as an attrset with a single key, being the name, and a value that is a list of its arguments. For example, to represent a spawn action, you could do this:

{
  programs.niri.settings.binds = {
    "XF86AudioRaiseVolume".action.spawn = ["wpctl" "set-volume" "@DEFAULT_AUDIO_SINK@" "0.1+"];
    "XF86AudioLowerVolume".action.spawn = ["wpctl" "set-volume" "@DEFAULT_AUDIO_SINK@" "0.1-"];
  };
}

If there is only a single argument, you can pass it directly. It will be implicitly converted to a list in that case.

{
  programs.niri.settings.binds = {
    "Mod+D".action.spawn = "fuzzel";
    "Mod+1".action.focus-workspace = 1;
  };
}

For actions taking properties (named arguments), you can pass an attrset.

{
  programs.niri.settings.binds = {
    "Mod+Shift+E".action.quit.skip-confirmation = true;
  };
}

There is also a set of functions available under config.lib.niri.actions.

Usage is like so:

{
  programs.niri.settings.binds = with config.lib.niri.actions; {
    "XF86AudioRaiseVolume".action = spawn "wpctl" "set-volume" "@DEFAULT_AUDIO_SINK@" "0.1+";
    "XF86AudioLowerVolume".action = spawn "wpctl" "set-volume" "@DEFAULT_AUDIO_SINK@" "0.1-";

    "Mod+D".action = spawn "fuzzel";
    "Mod+1".action = focus-workspace 1;

    "Mod+Shift+E".action = quit;
    "Mod+Ctrl+Shift+E".action = quit { skip-confirmation=true; };

    "Mod+Plus".action = set-column-width "+10%";
  }
}

Keep in mind that each one of these attributes (i.e. the nix bindings) are actually identical functions with different node names, and they can take arbitrarily many arguments. The documentation here is based on the real acceptable arguments for these actions, but the nix bindings do not enforce this. If you pass the wrong arguments, niri will reject the config file, but evaluation will proceed without problems.

For actions that don't take any arguments, just use the corresponding attribute from config.lib.niri.actions. They are listed as action-name. For actions that do take arguments, they are notated like so: λ action-name :: <args>, to clarify that they "should" be used as functions. Hopefully, <args> will be clear enough in most cases, but it's worth noting some nontrivial kinds of arguments:

  • size-change: This is a special argument type used for some actions by niri. It's a string.
    It can take either a fixed size as an integer number of logical pixels ("480", "1200") or a proportion of your screen as a percentage ("30%", "70%")
    Additionally, it can either be an absolute change (setting the new size of the window), or a relative change (adding or subtracting from its size).
    Relative size changes are written with a +/- prefix, and absolute size changes have no prefix.

  • { field :: type }: This means that the action takes a named argument (in kdl, we call it a property).
    To pass such an argument, you should pass an attrset with the key and value. You can pass many properties in one attrset, or you can pass several attrsets with different properties.
    Required fields are marked with * before their name, and if no fields are required, you can use the action without any arguments too (see quit in the example above).
    If a field is marked with ?, then omitting it is meaningful. (without ?, it will have a default value)

  • [type]: This means that the action takes several arguments as a list. Although you can pass a list directly, it's more common to pass them as separate arguments.
    spawn ["foo" "bar" "baz"] is equivalent to spawn "foo" "bar" "baz".

Tip

You can use partial application to create a spawn command with full support for shell syntax:

{
  programs.niri.settings.binds = with config.lib.niri.actions; let
    sh = spawn "sh" "-c";
  in {
    "Print".action = sh ''grim -g "$(slurp)" - | wl-copy'';
  };
}
  • λ quit :: { skip-confirmation :: bool }
  • suspend
  • power-off-monitors
  • power-on-monitors
  • toggle-debug-tint
  • debug-toggle-opaque-regions
  • debug-toggle-damage
  • λ spawn :: [string]
  • λ do-screen-transition :: { delay-ms? :: u16 }
  • screenshot
  • screenshot-screen
  • screenshot-window
  • close-window
  • fullscreen-window
  • focus-window-previous (only on niri-unstable)
  • focus-column-left
  • focus-column-right
  • focus-column-first
  • focus-column-last
  • focus-column-right-or-first
  • focus-column-left-or-last
  • focus-window-or-monitor-up
  • focus-window-or-monitor-down
  • focus-column-or-monitor-left
  • focus-column-or-monitor-right
  • focus-window-down
  • focus-window-up
  • focus-window-down-or-column-left
  • focus-window-down-or-column-right
  • focus-window-up-or-column-left
  • focus-window-up-or-column-right
  • focus-window-or-workspace-down
  • focus-window-or-workspace-up
  • move-column-left
  • move-column-right
  • move-column-to-first
  • move-column-to-last
  • move-column-left-or-to-monitor-left
  • move-column-right-or-to-monitor-right
  • move-window-down
  • move-window-up
  • move-window-down-or-to-workspace-down
  • move-window-up-or-to-workspace-up
  • consume-or-expel-window-left
  • consume-or-expel-window-right
  • consume-window-into-column
  • expel-window-from-column
  • center-column
  • focus-workspace-down
  • focus-workspace-up
  • λ focus-workspace :: u8 | string
  • focus-workspace-previous
  • move-window-to-workspace-down
  • move-window-to-workspace-up
  • λ move-window-to-workspace :: u8 | string
  • move-column-to-workspace-down
  • move-column-to-workspace-up
  • λ move-column-to-workspace :: u8 | string
  • move-workspace-down
  • move-workspace-up
  • focus-monitor-left
  • focus-monitor-right
  • focus-monitor-down
  • focus-monitor-up
  • move-window-to-monitor-left
  • move-window-to-monitor-right
  • move-window-to-monitor-down
  • move-window-to-monitor-up
  • move-column-to-monitor-left
  • move-column-to-monitor-right
  • move-column-to-monitor-down
  • move-column-to-monitor-up
  • λ set-window-height :: size-change
  • reset-window-height
  • switch-preset-column-width
  • switch-preset-window-height
  • maximize-column
  • λ set-column-width :: size-change
  • λ switch-layout :: "next" | "prev"
  • show-hotkey-overlay
  • move-workspace-to-monitor-left
  • move-workspace-to-monitor-right
  • move-workspace-to-monitor-down
  • move-workspace-to-monitor-up

programs.niri.settings.binds.<name>.allow-when-locked

  • type: boolean
  • default: false

Whether this keybind should be allowed when the screen is locked.

This is only applicable for spawn keybinds.

programs.niri.settings.binds.<name>.cooldown-ms

  • type: null or signed integer
  • default: null

The minimum cooldown before a keybind can be triggered again, in milliseconds.

This is mostly useful for binds on the mouse wheel, where you might not want to activate an action several times in quick succession. You can use it for any bind, though.

programs.niri.settings.binds.<name>.repeat

  • type: boolean
  • default: true

Whether this keybind should trigger repeatedly when held down.

programs.niri.settings.switch-events.lid-close

programs.niri.settings.switch-events.lid-open

programs.niri.settings.switch-events.tablet-mode-off

programs.niri.settings.switch-events.tablet-mode-on

<switch-bind>

  • type: niri switch bind

<switch-bind>.action

  • type: niri switch action, which is a kdl leaf

A switch action is represented as an attrset with a single key, being the name, and a value that is a list of its arguments.

See also binds.<name>.action for more information on how this works, it has the exact same option type. Beware that switch binds are not the same as regular binds, and the actions they take are different. Currently, they can only accept spawn binds. Correct usage is like so:

{
  programs.niri.settings.switch-events = {
    tablet-mode-on.action.spawn = ["gsettings" "set" "org.gnome.desktop.a11y.applications" "screen-keyboard-enabled" "true"];
    tablet-mode-off.action.spawn = ["gsettings" "set" "org.gnome.desktop.a11y.applications" "screen-keyboard-enabled" "false"];
  };
}

programs.niri.settings.screenshot-path

  • type: null or string
  • default: "~/Pictures/Screenshots/Screenshot from %Y-%m-%d %H-%M-%S.png"

The path to save screenshots to.

If this is null, then no screenshots will be saved.

If the path starts with a ~, then it will be expanded to the user's home directory.

The path is then passed to stftime(3) with the current time, and the result is used as the final path.

programs.niri.settings.hotkey-overlay.skip-at-startup

  • type: boolean
  • default: false

Whether to skip the hotkey overlay shown when niri starts.

programs.niri.settings.prefer-no-csd

  • type: boolean
  • default: false

Whether to prefer server-side decorations (SSD) over client-side decorations (CSD).

programs.niri.settings.spawn-at-startup

  • type: list of (submodule)

programs.niri.settings.spawn-at-startup.*.command

  • type: list of string

programs.niri.settings.workspaces

  • type: attribute set of (submodule)

Declare named workspaces.

Named workspaces are similar to regular, dynamic workspaces, except they can be referred to by name, and they are persistent, they do not close when there are no more windows left on them.

Usage is like so:

{
  programs.niri.settings.workspaces."name" = {};
  programs.niri.settings.workspaces."01-another-one" = {
    open-on-output = "DP-1";
    name = "another-one";
  };
}

Unless a name is declared, the workspace will use the attribute key as the name.

Workspaces will be created in a specific order: sorted by key. If you do not care about the order of named workspaces, you can skip using the name attribute, and use the key instead. If you do care about it, you can use the key to order them, and a name attribute to have a friendlier name.

programs.niri.settings.workspaces.<name>.name

  • type: null or string
  • default: null

An (optional) name for the workspace. Defaults to the value of the key.

This attribute is intended to be used when you wish to preserve a specific order for the named workspaces.

programs.niri.settings.workspaces.<name>.open-on-output

  • type: null or string
  • default: null

The name of the output the workspace should be assigned to.

programs.niri.settings.input.focus-follows-mouse.enable

  • type: boolean
  • default: false

Whether to focus the window under the mouse when the mouse moves.

programs.niri.settings.input.focus-follows-mouse.max-scroll-amount

  • type: null or string
  • default: null

The maximum proportion of the screen to scroll at a time

programs.niri.settings.input.keyboard.repeat-delay

  • type: signed integer
  • default: 600

The delay in milliseconds before a key starts repeating.

programs.niri.settings.input.keyboard.repeat-rate

  • type: signed integer
  • default: 25

The rate in characters per second at which a key repeats.

programs.niri.settings.input.keyboard.track-layout

  • type: one of "global", "window"
  • default: "global"

The keyboard layout can be remembered per "window", such that when you switch to a window, the keyboard layout is set to the one that was last used in that window.

By default, there is only one "global" keyboard layout and changing it in any window will affect the keyboard layout used in all other windows too.

programs.niri.settings.input.keyboard.xkb

Parameters passed to libxkbcommon, which handles the keyboard in niri.

Further reading:

programs.niri.settings.input.keyboard.xkb.layout

  • type: string
  • default: ""

A comma-separated list of layouts (languages) to include in the keymap.

See xkeyboard-config(7) for a list of available layouts and their variants.

If this is set to an empty string, the layout will be read from the XKB_DEFAULT_LAYOUT environment variable.

programs.niri.settings.input.keyboard.xkb.model

  • type: string
  • default: ""

The keyboard model by which to interpret keycodes and LEDs

See xkeyboard-config(7) for a list of available models.

If this is set to an empty string, the model will be read from the XKB_DEFAULT_MODEL environment variable.

programs.niri.settings.input.keyboard.xkb.options

  • type: null or string
  • default: null

A comma separated list of options, through which the user specifies non-layout related preferences, like which key combinations are used for switching layouts, or which key is the Compose key.

See xkeyboard-config(7) for a list of available options.

If this is set to an empty string, no options will be used.

If this is set to null, the options will be read from the XKB_DEFAULT_OPTIONS environment variable.

programs.niri.settings.input.keyboard.xkb.rules

  • type: string
  • default: ""

The rules file to use.

The rules file describes how to interpret the values of the model, layout, variant and options fields.

If this is set to an empty string, the rules will be read from the XKB_DEFAULT_RULES environment variable.

programs.niri.settings.input.keyboard.xkb.variant

  • type: string
  • default: ""

A comma separated list of variants, one per layout, which may modify or augment the respective layout in various ways.

See xkeyboard-config(7) for a list of available variants for each layout.

If this is set to an empty string, the variant will be read from the XKB_DEFAULT_VARIANT environment variable.

programs.niri.settings.input.mouse.accel-profile

  • type: null or one of "adaptive", "flat"
  • default: null

Further reading:

programs.niri.settings.input.mouse.accel-speed

  • type: floating point number
  • default: 0.000000

Further reading:

programs.niri.settings.input.mouse.enable

  • type: boolean
  • default: true

programs.niri.settings.input.mouse.left-handed

  • type: boolean
  • default: false

Whether to accomodate left-handed usage for this device. This varies based on the exact device, but will for example swap left/right mouse buttons.

Further reading:

programs.niri.settings.input.mouse.middle-emulation

  • type: boolean
  • default: false

Whether a middle mouse button press should be sent when you press the left and right mouse buttons

Further reading:

programs.niri.settings.input.mouse.natural-scroll

  • type: boolean
  • default: false

Whether scrolling should move the content in the scrolled direction (as opposed to moving the viewport)

Further reading:

programs.niri.settings.input.mouse.scroll-button

  • type: null or signed integer
  • default: null

When scroll-method = "on-button-down", this is the button that will be used to enable scrolling. This button must be on the same physical device as the pointer, according to libinput docs. The type is a button code, as defined in input-event-codes.h. Most commonly, this will be set to BTN_LEFT, BTN_MIDDLE, or BTN_RIGHT, or at least some mouse button, but any button from that file is a valid value for this option (though, libinput may not necessarily do anything useful with most of them)

Further reading:

programs.niri.settings.input.mouse.scroll-factor

  • type: null or floating point number
  • default: null

For all scroll events triggered by a wheel source, the scroll distance is multiplied by this factor.

This is not a libinput property, but rather a niri-specific one.

programs.niri.settings.input.mouse.scroll-method

  • type: null or one of "no-scroll", "two-finger", "edge", "on-button-down"
  • default: null

When to convert motion events to scrolling events. The default and supported values vary based on the device type.

Further reading:

programs.niri.settings.input.power-key-handling.enable

  • type: boolean
  • default: true

By default, niri will take over the power button to make it sleep instead of power off.

You can disable this behaviour if you prefer to configure the power button elsewhere.

programs.niri.settings.input.tablet.enable

  • type: boolean
  • default: true

programs.niri.settings.input.tablet.left-handed

  • type: boolean
  • default: false

Whether to accomodate left-handed usage for this device. This varies based on the exact device, but will for example swap left/right mouse buttons.

Further reading:

programs.niri.settings.input.tablet.map-to-output

  • type: null or string
  • default: null

programs.niri.settings.input.touch.map-to-output

  • type: null or string
  • default: null

programs.niri.settings.input.touchpad.accel-profile

  • type: null or one of "adaptive", "flat"
  • default: null

Further reading:

programs.niri.settings.input.touchpad.accel-speed

  • type: floating point number
  • default: 0.000000

Further reading:

programs.niri.settings.input.touchpad.click-method

  • type: null or one of "button-areas", "clickfinger"
  • default: null

Method to determine which mouse button is pressed when you click the touchpad.

Further reading:

programs.niri.settings.input.touchpad.disabled-on-external-mouse

  • type: boolean
  • default: false

Whether to disable the touchpad when an external mouse is plugged in.

Further reading:

programs.niri.settings.input.touchpad.dwt

  • type: boolean
  • default: false

Whether to disable the touchpad while typing.

Further reading:

programs.niri.settings.input.touchpad.dwtp

  • type: boolean
  • default: false

Whether to disable the touchpad while the trackpoint is in use.

Further reading:

programs.niri.settings.input.touchpad.enable

  • type: boolean
  • default: true

programs.niri.settings.input.touchpad.left-handed

  • type: boolean
  • default: false

Whether to accomodate left-handed usage for this device. This varies based on the exact device, but will for example swap left/right mouse buttons.

Further reading:

programs.niri.settings.input.touchpad.middle-emulation

  • type: boolean
  • default: false

Whether a middle mouse button press should be sent when you press the left and right mouse buttons

Further reading:

programs.niri.settings.input.touchpad.natural-scroll

  • type: boolean
  • default: true

Whether scrolling should move the content in the scrolled direction (as opposed to moving the viewport)

Further reading:

programs.niri.settings.input.touchpad.scroll-button

  • type: null or signed integer
  • default: null

When scroll-method = "on-button-down", this is the button that will be used to enable scrolling. This button must be on the same physical device as the pointer, according to libinput docs. The type is a button code, as defined in input-event-codes.h. Most commonly, this will be set to BTN_LEFT, BTN_MIDDLE, or BTN_RIGHT, or at least some mouse button, but any button from that file is a valid value for this option (though, libinput may not necessarily do anything useful with most of them)

Further reading:

programs.niri.settings.input.touchpad.scroll-factor

  • type: null or floating point number
  • default: null

For all scroll events triggered by a finger source, the scroll distance is multiplied by this factor.

This is not a libinput property, but rather a niri-specific one.

programs.niri.settings.input.touchpad.scroll-method

  • type: null or one of "no-scroll", "two-finger", "edge", "on-button-down"
  • default: null

When to convert motion events to scrolling events. The default and supported values vary based on the device type.

Further reading:

programs.niri.settings.input.touchpad.tap

  • type: boolean
  • default: true

Whether to enable tap-to-click.

Further reading:

programs.niri.settings.input.touchpad.tap-button-map

  • type: null or one of "left-middle-right", "left-right-middle"
  • default: null

The mouse button to register when tapping with 1, 2, or 3 fingers, when input.touchpad.tap is enabled.

Further reading:

programs.niri.settings.input.trackball.accel-profile

  • type: null or one of "adaptive", "flat"
  • default: null

Further reading:

programs.niri.settings.input.trackball.accel-speed

  • type: floating point number
  • default: 0.000000

Further reading:

programs.niri.settings.input.trackball.enable

  • type: boolean
  • default: true

programs.niri.settings.input.trackball.left-handed

  • type: boolean
  • default: false

Whether to accomodate left-handed usage for this device. This varies based on the exact device, but will for example swap left/right mouse buttons.

Further reading:

programs.niri.settings.input.trackball.middle-emulation

  • type: boolean
  • default: false

Whether a middle mouse button press should be sent when you press the left and right mouse buttons

Further reading:

programs.niri.settings.input.trackball.natural-scroll

  • type: boolean
  • default: false

Whether scrolling should move the content in the scrolled direction (as opposed to moving the viewport)

Further reading:

programs.niri.settings.input.trackball.scroll-button

  • type: null or signed integer
  • default: null

When scroll-method = "on-button-down", this is the button that will be used to enable scrolling. This button must be on the same physical device as the pointer, according to libinput docs. The type is a button code, as defined in input-event-codes.h. Most commonly, this will be set to BTN_LEFT, BTN_MIDDLE, or BTN_RIGHT, or at least some mouse button, but any button from that file is a valid value for this option (though, libinput may not necessarily do anything useful with most of them)

Further reading:

programs.niri.settings.input.trackball.scroll-method

  • type: null or one of "no-scroll", "two-finger", "edge", "on-button-down"
  • default: null

When to convert motion events to scrolling events. The default and supported values vary based on the device type.

Further reading:

programs.niri.settings.input.trackpoint.accel-profile

  • type: null or one of "adaptive", "flat"
  • default: null

Further reading:

programs.niri.settings.input.trackpoint.accel-speed

  • type: floating point number
  • default: 0.000000

Further reading:

programs.niri.settings.input.trackpoint.enable

  • type: boolean
  • default: true

programs.niri.settings.input.trackpoint.left-handed

  • type: boolean
  • default: false

Whether to accomodate left-handed usage for this device. This varies based on the exact device, but will for example swap left/right mouse buttons.

Further reading:

programs.niri.settings.input.trackpoint.middle-emulation

  • type: boolean
  • default: false

Whether a middle mouse button press should be sent when you press the left and right mouse buttons

Further reading:

programs.niri.settings.input.trackpoint.natural-scroll

  • type: boolean
  • default: false

Whether scrolling should move the content in the scrolled direction (as opposed to moving the viewport)

Further reading:

programs.niri.settings.input.trackpoint.scroll-button

  • type: null or signed integer
  • default: null

When scroll-method = "on-button-down", this is the button that will be used to enable scrolling. This button must be on the same physical device as the pointer, according to libinput docs. The type is a button code, as defined in input-event-codes.h. Most commonly, this will be set to BTN_LEFT, BTN_MIDDLE, or BTN_RIGHT, or at least some mouse button, but any button from that file is a valid value for this option (though, libinput may not necessarily do anything useful with most of them)

Further reading:

programs.niri.settings.input.trackpoint.scroll-method

  • type: null or one of "no-scroll", "two-finger", "edge", "on-button-down"
  • default: null

When to convert motion events to scrolling events. The default and supported values vary based on the device type.

Further reading:

programs.niri.settings.input.warp-mouse-to-focus

  • type: boolean
  • default: false

Whether to warp the mouse to the focused window when switching focus.

programs.niri.settings.input.workspace-auto-back-and-forth

  • type: boolean
  • default: false

When invoking focus-workspace to switch to a workspace by index, if the workspace is already focused, usually nothing happens. When this option is enabled, the workspace will cycle back to the previously active workspace.

Of note is that it does not switch to the previous index, but the previous workspace. That means you can reorder workspaces inbetween these actions, and it will still take you to the actual same workspace you came from.

programs.niri.settings.outputs

  • type: attribute set of (submodule)

programs.niri.settings.outputs.<name>.background-color

  • type: null or string
  • default: null

The background color of this output. This is equivalent to launching swaybg -c <color> on that output, but is handled by the compositor itself for solid colors.

programs.niri.settings.outputs.<name>.enable

  • type: boolean
  • default: true

programs.niri.settings.outputs.<name>.mode

  • type: null or (submodule)
  • default: null

The resolution and refresh rate of this display.

By default, when this is null, niri will automatically pick a mode for you.

If this is set to an invalid mode (i.e unsupported by this output), niri will act as if it is unset and pick one for you.

programs.niri.settings.outputs.<name>.mode.height

  • type: signed integer

programs.niri.settings.outputs.<name>.mode.refresh

  • type: null or floating point number
  • default: null

The refresh rate of this output. When this is null, but the resolution is set, niri will automatically pick the highest available refresh rate.

programs.niri.settings.outputs.<name>.mode.width

  • type: signed integer

programs.niri.settings.outputs.<name>.position

  • type: null or (submodule)
  • default: null

Position of the output in the global coordinate space.

This affects directional monitor actions like "focus-monitor-left", and cursor movement.

The cursor can only move between directly adjacent outputs.

Output scale has to be taken into account for positioning, because outputs are sized in logical pixels.

For example, a 3840x2160 output with scale 2.0 will have a logical size of 1920x1080, so to put another output directly adjacent to it on the right, set its x to 1920.

If the position is unset or multiple outputs overlap, niri will instead place the output automatically.

programs.niri.settings.outputs.<name>.position.x

  • type: signed integer

programs.niri.settings.outputs.<name>.position.y

  • type: signed integer

programs.niri.settings.outputs.<name>.scale

  • type: null or floating point number or signed integer
  • default: null

The scale of this output, which represents how many physical pixels fit in one logical pixel.

If this is null, niri will automatically pick a scale for you.

programs.niri.settings.outputs.<name>.transform.flipped

  • type: boolean
  • default: false

Whether to flip this output vertically.

programs.niri.settings.outputs.<name>.transform.rotation

  • type: one of 0, 90, 180, 270
  • default: 0

Counter-clockwise rotation of this output in degrees.

programs.niri.settings.outputs.<name>.variable-refresh-rate

  • type: one of false, "on-demand", true
  • default: false

Whether to enable variable refresh rate (VRR) on this output.

VRR is also known as Adaptive Sync, FreeSync, and G-Sync.

Setting this to "on-demand" will enable VRR only when a window with window-rules.*.variable-refresh-rate is present on this output.

programs.niri.settings.cursor.hide-after-inactive-ms

  • type: null or signed integer
  • default: null

If set, the cursor will automatically hide once this number of milliseconds passes since the last cursor movement.

programs.niri.settings.cursor.hide-when-typing

  • type: boolean
  • default: false

Whether to hide the cursor when typing.

programs.niri.settings.cursor.size

  • type: signed integer
  • default: 24

The size of the cursor in logical pixels.

This will also set the XCURSOR_SIZE environment variable for all spawned processes.

programs.niri.settings.cursor.theme

  • type: string
  • default: "default"

The name of the xcursor theme to use.

This will also set the XCURSOR_THEME environment variable for all spawned processes.

programs.niri.settings.layout.border

The border is a decoration drawn inside every window in the layout. It will take space away from windows. That is, if you have a border of 8px, then each window will be 8px smaller on each edge than if you had no border.

The currently focused window, i.e. the window that can receive keyboard input, will be drawn according to layout.border.active, and all other windows will be drawn according to layout.border.inactive.

If you have layout.focus-ring enabled, the border will be drawn inside (and over) the focus ring.

programs.niri.settings.layout.border.enable

  • type: boolean
  • default: false

Whether to enable the border.

programs.niri.settings.layout.border.width

  • type: floating point number or signed integer
  • default: 4

The width of the border drawn around each window.

programs.niri.settings.layout.border.active

  • type: <decoration>, which is a variant of: color | gradient
  • default:
    {
      color = "rgb(255 200 127)";
    }

The color of the border for the window that has keyboard focus.

programs.niri.settings.layout.border.inactive

  • type: <decoration>, which is a variant of: color | gradient
  • default:
    {
      color = "rgb(80 80 80)";
    }

The color of the border for windows that do not have keyboard focus.

programs.niri.settings.layout.focus-ring

The focus ring is a decoration drawn around the last focused window on each monitor. It takes no space away from windows. If you have insufficient gaps, the focus ring can be drawn over adjacent windows, but it will never affect the layout of windows.

The focused window of the currently focused monitor, i.e. the window that can receive keyboard input, will be drawn according to layout.focus-ring.active, and the last focused window on all other monitors will be drawn according to layout.focus-ring.inactive.

If you have layout.border enabled, the focus ring will be drawn around (and under) the border.

programs.niri.settings.layout.focus-ring.enable

  • type: boolean
  • default: true

Whether to enable the focus ring.

programs.niri.settings.layout.focus-ring.width

  • type: floating point number or signed integer
  • default: 4

The width of the focus ring drawn around each focused window.

programs.niri.settings.layout.focus-ring.active

  • type: <decoration>, which is a variant of: color | gradient
  • default:
    {
      color = "rgb(127 200 255)";
    }

The color of the focus ring for the window that has keyboard focus.

programs.niri.settings.layout.focus-ring.inactive

  • type: <decoration>, which is a variant of: color | gradient
  • default:
    {
      color = "rgb(80 80 80)";
    }

The color of the focus ring for windows that do not have keyboard focus.

programs.niri.settings.layout.insert-hint

The insert hint is a decoration drawn between windows during an interactive move operation. It is drawn in the gap where the window will be inserted when you release the window. It does not occupy any space in the gap, and the insert hint extends onto the edges of adjacent windows. When you release the moved window, the windows that are covered by the insert hint will be pushed aside to make room for the moved window.

programs.niri.settings.layout.insert-hint.enable

  • type: boolean
  • default: true

Whether to enable the insert hint.

programs.niri.settings.layout.insert-hint.display

  • type: <decoration>, which is a variant of: color | gradient
  • default:
    {
      color = "rgba(127 200 255 50%)";
    }

The color of the insert hint.

<decoration>

  • type: variant of: color | gradient

A decoration is drawn around a surface, adding additional elements that are not necessarily part of an application, but are part of what we think of as a "window".

This type specifically represents decorations drawn by niri: that is, layout.focus-ring and/or layout.border.

<decoration>.color

  • type: string

A solid color to use for the decoration.

This is a CSS <color> value, like "rgb(255 0 0)", "#C0FFEE", or "sandybrown".

The specific crate that niri uses to parse this also supports some nonstandard color functions, like hwba(), hsv(), hsva(). See csscolorparser for details.

<decoration>.gradient

  • type: gradient

A linear gradient to use for the decoration.

This is meant to approximate the CSS linear-gradient() function, but niri does not fully support all the same parameters. Only an angle in degrees is supported.

<decoration>.gradient.angle

  • type: signed integer
  • default: 180

The angle of the gradient, in degrees, measured clockwise from a gradient that starts at the bottom and ends at the top.

This is the same as the angle parameter in the CSS linear-gradient() function, except you can only express it in degrees.

<decoration>.gradient.from

  • type: string

The starting <color> of the gradient.

For more details, see <decoration>.color.

<decoration>.gradient.in'

  • type: null or one of "srgb", "srgb-linear", "oklab", "oklch shorter hue", "oklch longer hue", "oklch increasing hue", "oklch decreasing hue"
  • default: null

The colorspace to interpolate the gradient in. This option is named in' because in is a reserved keyword in Nix.

This is a subset of the <color-interpolation-method> values in CSS.

<decoration>.gradient.relative-to

  • type: one of "window", "workspace-view"
  • default: "window"

The rectangle that this gradient is contained within.

If a gradient is relative-to the "window", then the gradient will start and stop at the window bounds. If you have many windows, then the gradients will have many starts and stops.

 four windows arranged in two columns; a big window to the left of three stacked windows. a gradient is drawn from the bottom left corner of each window, which is yellow, transitioning to red at the top right corner of each window. the three vertical windows look identical, with a yellow and red corner, and the other two corners are slightly different shades of orange. the big window has a yellow and red corner, with the top left corner being a very red orange orange, and the bottom right corner being a very yellow orange. the top edge of the top stacked window has a noticeable transition from a yellowish orange to completely red.

If the gradient is instead relative-to the "workspace-view", then the gradient will start and stop at the bounds of your view. Windows decorations will take on the color values from just the part of the screen that they occupy

 four windows arranged in two columns; a big window to the left of three stacked windows. a gradient is drawn from the bottom left corner of the workspace view, which is yellow, transitioning to red at the top right corner of the workspace view. it looks like the gradient starts in the bottom left of the big window, and ends in the top right of the upper stacked window. the bottom left corner of the top stacked window is a red orange color, and the bottom left corner of the middle stacked window is a more neutral orange color. the bottom edge of the big window is almost entirely yellow, and the top edge of the top stacked window is almost entirely red.

these beautiful images are sourced from the release notes for v0.1.3

<decoration>.gradient.to

  • type: string

The ending <color> of the gradient.

For more details, see <decoration>.color.

programs.niri.settings.layout.always-center-single-column

  • type: boolean
  • default: false

This is like center-focused-column = "always";, but only for workspaces with a single column. Changes nothing is center-focused-column is set to "always". Has no effect if more than one column is present.

programs.niri.settings.layout.center-focused-column

  • type: one of "never", "always", "on-overflow"
  • default: "never"

When changing focus, niri can automatically center the focused column.

  • "never": If the focused column doesn't fit, it will be aligned to the edges of the screen.
  • "on-overflow": if the focused column doesn't fit, it will be centered on the screen.
  • "always": the focused column will always be centered, even if it was already fully visible.

programs.niri.settings.layout.default-column-width

  • type: {} or (variant of: fixed | proportion)

The default width for new columns.

When this is set to an empty attrset {}, windows will get to decide their initial width. This is not null, such that it can be distinguished from window rules that don't touch this

See layout.preset-column-widths for more information.

You can override this for specific windows using window-rules.*.default-column-width

programs.niri.settings.layout.default-column-width.fixed

  • type: signed integer

The width of the column in logical pixels

programs.niri.settings.layout.default-column-width.proportion

  • type: floating point number

The width of the column as a proportion of the screen's width

programs.niri.settings.layout.gaps

  • type: floating point number or signed integer
  • default: 16

The gap between windows in the layout, measured in logical pixels.

programs.niri.settings.layout.preset-column-widths

  • type: list of variant of: fixed | proportion

The widths that switch-preset-column-width will cycle through.

Each width can either be a fixed width in logical pixels, or a proportion of the screen's width.

Example:

{
  programs.niri.settings.layout.preset-column-widths = [
    { proportion = 1. / 3.; }
    { proportion = 1. / 2.; }
    { proportion = 2. / 3.; }

    # { fixed = 1920; }
  ];
}

programs.niri.settings.layout.preset-column-widths.*.fixed

  • type: signed integer

The width of the column in logical pixels

programs.niri.settings.layout.preset-column-widths.*.proportion

  • type: floating point number

The width of the column as a proportion of the screen's width

programs.niri.settings.layout.preset-window-heights

  • type: list of variant of: fixed | proportion

The heights that switch-preset-window-height will cycle through.

Each height can either be a fixed height in logical pixels, or a proportion of the screen's height.

Example:

{
  programs.niri.settings.layout.preset-window-heights = [
    { proportion = 1. / 3.; }
    { proportion = 1. / 2.; }
    { proportion = 2. / 3.; }

    # { fixed = 1080; }
  ];
}

programs.niri.settings.layout.preset-window-heights.*.fixed

  • type: signed integer

The height of the window in logical pixels

programs.niri.settings.layout.preset-window-heights.*.proportion

  • type: floating point number

The height of the window as a proportion of the screen's height

programs.niri.settings.layout.struts

The distances from the edges of the screen to the eges of the working area.

The top and bottom struts are absolute gaps from the edges of the screen. If you set a bottom strut of 64px and the scale is 2.0, then the output will have 128 physical pixels under the scrollable working area where it only shows the wallpaper.

Struts are computed in addition to layer-shell surfaces. If you have a waybar of 32px at the top, and you set a top strut of 16px, then you will have 48 logical pixels from the actual edge of the display to the top of the working area.

The left and right structs work in a similar way, except the padded space is not empty. The horizontal struts are used to constrain where focused windows are allowed to go. If you define a left strut of 64px and go to the first window in a workspace, that window will be aligned 64 logical pixels from the left edge of the output, rather than snapping to the actual edge of the screen. If another window exists to the left of this window, then you will see 64px of its right edge (if you have zero borders and gaps)

programs.niri.settings.layout.struts.bottom

  • type: floating point number or signed integer
  • default: 0

programs.niri.settings.layout.struts.left

  • type: floating point number or signed integer
  • default: 0

programs.niri.settings.layout.struts.right

  • type: floating point number or signed integer
  • default: 0

programs.niri.settings.layout.struts.top

  • type: floating point number or signed integer
  • default: 0

programs.niri.settings.animations.enable

  • type: boolean
  • default: true

programs.niri.settings.animations.slowdown

  • type: floating point number
  • default: 1.000000

programs.niri.settings.animations.config-notification-open-close

  • type: null or <animation>
  • default:
    {
      spring = {
        damping-ratio = 0.600000;
        epsilon = 0.001000;
        stiffness = 1000;
      };
    }

programs.niri.settings.animations.horizontal-view-movement

  • type: null or <animation>
  • default:
    {
      spring = {
        damping-ratio = 1.000000;
        epsilon = 0.000100;
        stiffness = 800;
      };
    }

programs.niri.settings.animations.screenshot-ui-open

  • type: null or <animation>
  • default:
    {
      easing = {
        curve = "ease-out-quad";
        duration-ms = 200;
      };
    }

programs.niri.settings.animations.window-close

  • type: null or <animation>
  • default:
    {
      easing = {
        curve = "ease-out-quad";
        duration-ms = 150;
      };
    }

programs.niri.settings.animations.window-movement

  • type: null or <animation>
  • default:
    {
      spring = {
        damping-ratio = 1.000000;
        epsilon = 0.000100;
        stiffness = 800;
      };
    }

programs.niri.settings.animations.window-open

  • type: null or <animation>
  • default:
    {
      easing = {
        curve = "ease-out-expo";
        duration-ms = 150;
      };
    }

programs.niri.settings.animations.window-resize

  • type: null or <animation>
  • default:
    {
      spring = {
        damping-ratio = 1.000000;
        epsilon = 0.000100;
        stiffness = 800;
      };
    }

programs.niri.settings.animations.workspace-switch

  • type: null or <animation>
  • default:
    {
      spring = {
        damping-ratio = 1.000000;
        epsilon = 0.000100;
        stiffness = 1000;
      };
    }

programs.niri.settings.animations.shaders

These options should contain the source code for GLSL shaders.

See: https://github.com/YaLTeR/niri/wiki/Configuration:-Animations#custom-shader

programs.niri.settings.animations.shaders.window-close

  • type: null or string
  • default: null

programs.niri.settings.animations.shaders.window-open

  • type: null or string
  • default: null

programs.niri.settings.animations.shaders.window-resize

  • type: null or string
  • default: null

<animation>

  • type: variant of: easing | spring

<animation>.easing.curve

  • type: one of "linear", "ease-out-quad", "ease-out-cubic", "ease-out-expo"

The curve to use for the easing function.

<animation>.easing.duration-ms

  • type: signed integer

<animation>.spring.damping-ratio

  • type: floating point number

<animation>.spring.epsilon

  • type: floating point number

<animation>.spring.stiffness

  • type: signed integer

programs.niri.settings.environment

  • type: attribute set of (null or string)

Environment variables to set for processes spawned by niri.

If an environment variable is already set in the environment, then it will be overridden by the value set here.

If a value is null, then the environment variable will be unset, even if it already existed.

Examples:

{
  programs.niri.settings.environment = {
    QT_QPA_PLATFORM = "wayland";
    DISPLAY = null;
  };
}

programs.niri.settings.window-rules

  • type: list of window rule

Window rules.

A window rule will match based on window-rules.*.matches and window-rules.*.excludes. Both of these are lists of "match rules".

A given match rule can match based on the title or app-id fields. For a given match rule to "match" a window, it must match on all fields.

  • The title field, when non-null, is a regular expression. It will match a window if the client has set a title and its title matches the regular expression.

  • The app-id field, when non-null, is a regular expression. It will match a window if the client has set an app id and its app id matches the regular expression.

  • If a field is null, it will always match.

For a given window rule to match a window, the above logic is employed to determine whether any given match rule matches, and the interactions between them decide whether the window rule as a whole will match. For a given window rule:

  • A given window is "considered" if any of the match rules in window-rules.*.matches successfully match this window. If all of the match rules do not match this window, then that window will never match this window rule.

  • If window-rules.*.matches contains no match rules, it will match any window and "consider" it for this window rule.

  • If a given window is "considered" for this window rule according to the above rules, the selection can be further refined with window-rules.*.excludes. If any of the match rules in excludes match this window, it will be rejected and this window rule will not match the given window.

That is, a given window rule will apply to a given window if any of the entries in window-rules.*.matches match that window (or there are none), AND none of the entries in window-rules.*.excludes match that window.

All fields of a window rule can be set to null, which represents that the field shall have no effect on the window (and in general, the client is allowed to choose the initial value).

To compute the final set of window rules that apply to a given window, each window rule in this list is consdered in order.

At first, every field is set to null.

Then, for each applicable window rule:

  • If a given field is null on this window rule, it has no effect. It does nothing and "inherits" the value from the previous rule.
  • If the given field is not null, it will overwrite the value from any previous rule.

The "final value" of a field is simply its value at the end of this process. That is, the final value of a field is the one from the last window rule that matches the given window rule (not considering null entries, unless there are no non-null entries)

If the final value of a given field is null, then it usually means that the client gets to decide. For more information, see the documentation for each field.

programs.niri.settings.window-rules.*.matches

  • type: list of match rule

A list of rules to match windows.

If any of these rules match a window (or there are none), that window rule will be considered for this window. It can still be rejected by window-rules.*.excludes

If all of the rules do not match a window, then this window rule will not apply to that window.

programs.niri.settings.window-rules.*.matches.*.app-id

  • type: null or regular expression
  • default: null

A regular expression to match against the app id of the window.

When non-null, for this field to match a window, a client must set the app id of its window and the app id must match this regex.

programs.niri.settings.window-rules.*.matches.*.title

  • type: null or regular expression
  • default: null

A regular expression to match against the title of the window.

When non-null, for this field to match a window, a client must set the title of its window and the title must match this regex.

programs.niri.settings.window-rules.*.matches.*.is-active

  • type: null or boolean
  • default: null

When non-null, for this field to match a window, the value must match whether the window is active or not.

Every monitor has up to one active window, and is-active=true will match the active window on each monitor. A monitor can have zero active windows if no windows are open on it. There can never be more than one active window on a monitor.

programs.niri.settings.window-rules.*.matches.*.is-active-in-column

  • type: null or boolean
  • default: null

When non-null, for this field to match a window, the value must match whether the window is active in its column or not.

Every column has exactly one active-in-column window. If it is the active column, this window is also the active window. A column may not have zero active-in-column windows, or more than one active-in-column window.

The active-in-column window is the window that was last focused in that column. When you switch focus to a column, the active-in-column window will be the new focused window.

programs.niri.settings.window-rules.*.matches.*.is-focused

  • type: null or boolean
  • default: null

When non-null, for this field to match a window, the value must match whether the window has keyboard focus or not.

A note on terminology used here: a window is actually a toplevel surface, and a surface just refers to any rectangular region that a client can draw to. A toplevel surface is just a surface with additional capabilities and properties (e.g. "fullscreen", "resizable", "min size", etc)

For a window to be focused, its surface must be focused. There is up to one focused surface, and it is the surface that can receive keyboard input. There can never be more than one focused surface. There can be zero focused surfaces if and only if there are zero surfaces. The focused surface does not have to be a toplevel surface. It can also be a layer-shell surface. In that case, there is a surface with keyboard focus but no window with keyboard focus.

programs.niri.settings.window-rules.*.matches.*.at-startup

  • type: null or boolean
  • default: null

When true, this rule will match windows opened within the first 60 seconds of niri starting up. This is useful for setting up initial window positions and sizes.

programs.niri.settings.window-rules.*.excludes

  • type: list of match rule

A list of rules to exclude windows.

If any of these rules match a window, then this window rule will not apply to that window, even if it matches one of the rules in window-rules.*.matches

If none of these rules match a window, then this window rule will not be rejected. It will apply to that window if and only if it matches one of the rules in window-rules.*.matches

programs.niri.settings.window-rules.*.excludes.*.app-id

  • type: null or regular expression
  • default: null

A regular expression to match against the app id of the window.

When non-null, for this field to match a window, a client must set the app id of its window and the app id must match this regex.

programs.niri.settings.window-rules.*.excludes.*.title

  • type: null or regular expression
  • default: null

A regular expression to match against the title of the window.

When non-null, for this field to match a window, a client must set the title of its window and the title must match this regex.

programs.niri.settings.window-rules.*.excludes.*.is-active

  • type: null or boolean
  • default: null

When non-null, for this field to match a window, the value must match whether the window is active or not.

Every monitor has up to one active window, and is-active=true will match the active window on each monitor. A monitor can have zero active windows if no windows are open on it. There can never be more than one active window on a monitor.

programs.niri.settings.window-rules.*.excludes.*.is-active-in-column

  • type: null or boolean
  • default: null

When non-null, for this field to match a window, the value must match whether the window is active in its column or not.

Every column has exactly one active-in-column window. If it is the active column, this window is also the active window. A column may not have zero active-in-column windows, or more than one active-in-column window.

The active-in-column window is the window that was last focused in that column. When you switch focus to a column, the active-in-column window will be the new focused window.

programs.niri.settings.window-rules.*.excludes.*.is-focused

  • type: null or boolean
  • default: null

When non-null, for this field to match a window, the value must match whether the window has keyboard focus or not.

A note on terminology used here: a window is actually a toplevel surface, and a surface just refers to any rectangular region that a client can draw to. A toplevel surface is just a surface with additional capabilities and properties (e.g. "fullscreen", "resizable", "min size", etc)

For a window to be focused, its surface must be focused. There is up to one focused surface, and it is the surface that can receive keyboard input. There can never be more than one focused surface. There can be zero focused surfaces if and only if there are zero surfaces. The focused surface does not have to be a toplevel surface. It can also be a layer-shell surface. In that case, there is a surface with keyboard focus but no window with keyboard focus.

programs.niri.settings.window-rules.*.excludes.*.at-startup

  • type: null or boolean
  • default: null

When true, this rule will match windows opened within the first 60 seconds of niri starting up. This is useful for setting up initial window positions and sizes.

programs.niri.settings.window-rules.*.default-column-width

  • type: null or {} or (variant of: fixed | proportion)
  • default: null

By default, when this option is null, then this window rule will not affect the default column width. If none of the applicable window rules have a nonnull value, it will be gotten from layout.default-column-width

If this option is not null, then its value will take priority over layout.default-column-width for windows matching this rule.

As a reminder, an empty attrset {} is not the same as null. Here, null represents that this window rule has no effect on the default width, wheras {} represents "let the client choose".

programs.niri.settings.window-rules.*.default-column-width.fixed

  • type: signed integer

The width of the column in logical pixels

programs.niri.settings.window-rules.*.default-column-width.proportion

  • type: floating point number

The width of the column as a proportion of the screen's width

programs.niri.settings.window-rules.*.open-fullscreen

  • type: null or boolean
  • default: null

Whether to open this window in fullscreen.

If the final value of this field is true, then this window will always be forced to open in fullscreen.

If the final value of this field is false, then this window is never allowed to open in fullscreen, even if it requests to do so.

If the final value of this field is null, then the client gets to decide if this window will open in fullscreen.

programs.niri.settings.window-rules.*.open-maximized

  • type: null or boolean
  • default: null

Whether to open this window in a maximized column.

If the final value of this field is null or false, then the window will not open in a maximized column.

If the final value of this field is true, then the window will open in a maximized column.

programs.niri.settings.window-rules.*.open-on-output

  • type: null or string
  • default: null

The output to open this window on.

If final value of this field is an output that exists, the new window will open on that output.

If the final value is an output that does not exist, or it is null, then the window opens on the currently focused output.

programs.niri.settings.window-rules.*.open-on-workspace

  • type: null or string
  • default: null

The workspace to open this window on.

If the final value of this field is a named workspace that exists, the window will open on that workspace.

If the final value of this is a named workspace that does not exist, or it is null, the window opens on the currently focused workspace.

programs.niri.settings.window-rules.*.block-out-from

  • type: null or one of "screencast", "screen-capture"
  • default: null

Whether to block out this window from screen captures. When the final value of this field is null, it is not blocked from screen captures.

This is useful to protect sensitive information, like the contents of password managers or private chats. It is very important to understand the implications of this option, as described below, especially if you are a streamer or content creator.

Some of this may be obvious, but in general, these invariants should hold true:

  • a window is never meant to be blocked out from the actual physical screen (otherwise you wouldn't be able to see it at all)
  • a block-out-from window is meant to be always blocked out from screencasts (as they are often used for livestreaming etc)
  • a block-out-from window is not supposed to be blocked from screenshots (because usually these are not broadcasted live, and you generally know what you're taking a screenshot of)

There are three methods of screencapture in niri:

  1. The org.freedesktop.portal.ScreenCast interface, which is used by tools like OBS primarily to capture video. When block-out-from = "screencast"; or block-out-from = "screen-capture";, this window is blocked out from the screencast portal, and will not be visible to screencasting software making use of the screencast portal.

  2. The wlr-screencopy protocol, which is used by tools like grim primarily to capture screenshots. When block-out-from = "screencast";, this protocol is not affected and tools like grim can still capture the window just fine. This is because you may still want to take a screenshot of such windows. However, some screenshot tools display a fullscreen overlay with a frozen image of the screen, and then capture that. This overlay is not blocked out in the same way, and may leak the window contents to an active screencast. When block-out-from = "screen-capture";, this window is blocked out from wlr-screencopy and thus will never leak in such a case, but of course it will always be blocked out from screenshots and (sometimes) the physical screen.

  3. The built in screenshot action, implemented in niri itself. This tool works similarly to those based on wlr-screencopy, but being a part of the compositor gets superpowers regarding secrecy of window contents. Its frozen overlay will never leak window contents to an active screencast, because information of blocked windows and can be distinguished for the physical output and screencasts. block-out-from does not affect the built in screenshot tool at all, and you can always take a screenshot of any window.

block-out-from can ScreenCast? can screencopy? can screenshot?
null yes yes yes
"screencast" no yes yes
"screen-capture" no no yes

Caution

Streamers: Do not accidentally leak window contents via screenshots.

For windows where block-out-from = "screencast";, contents of a window may still be visible in a screencast, if the window is indirectly displayed by a tool using wlr-screencopy.

If you are a streamer, either:

  • make sure not to use wlr-screencopy tools that display a preview during your stream, or
  • set block-out-from = "screen-capture"; to ensure that the window is never visible in a screencast.

Caution

Do not let malicious wlr-screencopy clients capture your top secret windows.

(and don't let malicious software run on your system in the first place, you silly goose)

For windows where block-out-from = "screencast";, contents of a window will still be visible to any application using wlr-screencopy, even if you did not consent to this application capturing your screen.

Note that sandboxed clients restricted via security context (i.e. Flatpaks) do not have access to wlr-screencopy at all, and are not a concern.

If a window's contents are so secret that they must never be captured by any (non-sandboxed) application, set block-out-from = "screen-capture";.

Essentially, use block-out-from = "screen-capture"; if you want to be sure that the window is never visible to any external tool no matter what; or use block-out-from = "screencast"; if you want to be able to capture screenshots of the window without its contents normally being visible in a screencast. (at the risk of some tools still leaking the window contents, see above)

programs.niri.settings.window-rules.*.border

See layout.border.

programs.niri.settings.window-rules.*.border.enable

  • type: null or boolean
  • default: null

Whether to enable the border.

programs.niri.settings.window-rules.*.border.width

  • type: null or floating point number or signed integer
  • default: null

The width of the border drawn around each matched window.

programs.niri.settings.window-rules.*.border.active

The color of the border for the window that has keyboard focus.

programs.niri.settings.window-rules.*.border.inactive

The color of the border for windows that do not have keyboard focus.

programs.niri.settings.window-rules.*.clip-to-geometry

  • type: null or boolean
  • default: null

Whether to clip the window to its visual geometry, i.e. whether the corner radius should be applied to the window surface itself or just the decorations.

programs.niri.settings.window-rules.*.draw-border-with-background

  • type: null or boolean
  • default: null

Whether to draw the focus ring and border with a background.

Normally, for windows with server-side decorations, niri will draw an actual border around them, because it knows they will be rectangular.

Because client-side decorations can take on arbitrary shapes, most notably including rounded corners, niri cannot really know the "correct" place to put a border, so for such windows it will draw a solid rectangle behind them instead.

For most windows, this looks okay. At worst, you have some uneven/jagged borders, instead of a gaping hole in the region outside of the corner radius of the window but inside its bounds.

If you wish to make windows sucha s your terminal transparent, and they use CSD, this is very undesirable. Instead of showing your wallpaper, you'll get a solid rectangle.

You can set this option per window to override niri's default behaviour, and instruct it to omit the border background for CSD windows. You can also explicitly enable it for SSD windows.

programs.niri.settings.window-rules.*.focus-ring

See layout.focus-ring.

programs.niri.settings.window-rules.*.focus-ring.enable

  • type: null or boolean
  • default: null

Whether to enable the focus ring.

programs.niri.settings.window-rules.*.focus-ring.width

  • type: null or floating point number or signed integer
  • default: null

The width of the focus ring drawn around each matched window with focus.

programs.niri.settings.window-rules.*.focus-ring.active

The color of the focus ring for the window that has keyboard focus.

programs.niri.settings.window-rules.*.focus-ring.inactive

The color of the focus ring for windows that do not have keyboard focus.

programs.niri.settings.window-rules.*.geometry-corner-radius

  • type: null or (submodule)
  • default: null

The corner radii of the window decorations (border and focus ring) in logical pixels.

By default, the actual window surface will be unaffected by this.

Set window-rules.*.clip-to-geometry to true to clip the window to its visual geometry, i.e. apply the corner radius to the window surface itself.

programs.niri.settings.window-rules.*.geometry-corner-radius.bottom-left

  • type: floating point number

programs.niri.settings.window-rules.*.geometry-corner-radius.bottom-right

  • type: floating point number

programs.niri.settings.window-rules.*.geometry-corner-radius.top-left

  • type: floating point number

programs.niri.settings.window-rules.*.geometry-corner-radius.top-right

  • type: floating point number

programs.niri.settings.window-rules.*.opacity

  • type: null or floating point number
  • default: null

The opacity of the window, ranging from 0 to 1.

If the final value of this field is null, niri will fall back to a value of 1.

Note that this is applied in addition to the opacity set by the client. Setting this to a semitransparent value on a window that is already semitransparent will make it even more transparent.

programs.niri.settings.window-rules.*.max-height

  • type: null or signed integer
  • default: null

Sets the maximum height (in logical pixels) that niri will ever ask this window for.

Keep in mind that the window itself always has a final say in its size, and may not respect the maximum height set by this option.

Also, note that the maximum height is not taken into account when automatically sizing columns. That is, when a column is created normally, windows in it will be "automatically sized" to fill the vertical space. This algorithm will respect a minimum height, and not make windows any smaller than that, but the max height is only taken into account if it is equal to the min height. In other words, it will only accept a "fixed height" or a "minimum height". In practice, most windows do not set a max size unless it is equal to their min size, so this is usually not a problem without window rules.

If you manually change the window heights, then max-height will be taken into account and restrict you from making it any taller, as you'd intuitively expect.

programs.niri.settings.window-rules.*.max-width

  • type: null or signed integer
  • default: null

Sets the maximum width (in logical pixels) that niri will ever ask this window for.

Keep in mind that the window itself always has a final say in its size, and may not respect the maximum width set by this option.

programs.niri.settings.window-rules.*.min-height

  • type: null or signed integer
  • default: null

Sets the minimum height (in logical pixels) that niri will ever ask this window for.

Keep in mind that the window itself always has a final say in its size, and may not respect the minimum height set by this option.

programs.niri.settings.window-rules.*.min-width

  • type: null or signed integer
  • default: null

Sets the minimum width (in logical pixels) that niri will ever ask this window for.

Keep in mind that the window itself always has a final say in its size, and may not respect the minimum width set by this option.

programs.niri.settings.window-rules.*.variable-refresh-rate

  • type: null or boolean
  • default: null

Takes effect only when the window is on an output with outputs.*.variable-refresh-rate set to "on-demand". If the final value of this field is true, then the output will enable variable refresh rate when this window is present on it.

programs.niri.settings.debug

  • type: null or (attribute set of kdl arguments)
  • default: null

Debug options for niri.

kdl arguments in the type refers to a list of arguments passed to a node under the debug section. This is a way to pass arbitrary KDL-valid data to niri. See binds for more information on all the ways you can use this.

Note that for no-argument nodes, there is no special way to define them here. You can't pass them as just a "string" because that makes no sense here. You must pass it an empty array of arguments.

Here's an example of how to use this:

{
  programs.niri.settings.debug = {
    disable-cursor-plane = [];
    render-drm-device = "/dev/dri/renderD129";
  };
}

This option is, just like binds, not verified by the nix module. But, it will be validated by niri before committing the config.

Additionally, i don't guarantee stability of the debug options. They may change at any time without prior notice, either because of niri changing the available options, or because of me changing this to a more reasonable schema.