DYNAMONIX
Note
This project is maintained with the assistance of AI tools. All changes are subject to manual review and a comprehensive test suite to ensure stability and quality.
What? #
A tui/cli program for tweaking niri wm display outputs dynamically without modifying the underlying configuration. Dynamonix speaks to the compositor only through the niri socket. It does not read the niri configuration file. It does not write the niri configuration file.
Why? #
Setting up new monitors/display outputs and adjusting the layout requires
making changes to the niri configuration file even if you only need to use
that display output layout for a brief period. Now if niri is configured
using nix/home-manager, you'll also need to do a home-manager switch.
Dynamonix lets you tweak the current display output layout quickly with a pretty TUI without changing your niri configuration file. All changes made by dynamonix are in-memory and ephemeral. To use an arrangement again later, save it as a profile. A profile goes in a file of dynamonix, and your niri configuration file stays as it is.
dynamonix 3 outputs · 3 on · 2 pending changes
╭ arrangement ───────────────────────────────╮╭ outputs ──────────────────╮
│ ││▍● DP-2 3440x1440 ×1 │
│ ┌───────────────┐ ┌────────────┐ ││ ● HDMI-A-1 3840x2160 ×1 │
│ │ DP-2 │ │ HDMI-A-1 │ ││ ● eDP-1 1920x1200 ×1 │
│ │ 3440x1440 ×1 │ │ 3840x2160 │ │╰───────────────────────────╯
│ └───────┬───────┴──────┴────────────┘ │╭ properties ───────────────╮
│ │ eDP-1 ││ mode 3440x1440 ★ 1/3 │
│ │ 1920x1200 ×1 ││ rate 143.999 Hz │
│ └───────────────────────────────┤│ scale ×1 │
╰────────────────────────────────────────────╯╰───────────────────────────╯
The compositor forgets these changes in two conditions:
- The compositor stops.
- The niri configuration file changes, and the compositor reads it again.
To keep an arrangement after a restart, save it as a profile, or write it in your niri configuration file.
Installation #
Cargo #
The program needs Rust 1.90 or a later version.
cargo install dynamonix
Nix #
The repository holds a flake. The flake builds the program for x86_64-linux
and for aarch64-linux.
Run the program one time. This command installs nothing:
nix run git+https://git.devtechnica.com/sreedev/dynamonix
Put the program in your profile:
nix profile install git+https://git.devtechnica.com/sreedev/dynamonix
Add the flake to the inputs of your own flake. The follows line keeps one
copy of nixpkgs:
{
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
dynamonix = {
url = "git+https://git.devtechnica.com/sreedev/dynamonix";
inputs.nixpkgs.follows = "nixpkgs";
};
};
outputs =
{ nixpkgs, dynamonix, ... }:
{
nixosConfigurations.example = nixpkgs.lib.nixosSystem {
system = "x86_64-linux";
modules = [
(
{ pkgs, ... }:
{
nixpkgs.overlays = [ dynamonix.overlays.default ];
environment.systemPackages = [ pkgs.dynamonix ];
}
)
];
};
};
}
The overlay gives the name pkgs.dynamonix. A configuration that uses no
overlay takes the package from the flake directly:
environment.systemPackages = [ dynamonix.packages.x86_64-linux.default ];
Use #
Start the program in a niri session:
dynamonix
Show the outputs and stop:
dynamonix list
Show the interface with three monitors of a sample. This mode does not need a compositor:
dynamonix --demo
Show the outputs as JSON for a script. The command writes one JSON object and nothing else:
dynamonix list --json
Save the arrangement of the outputs with a name:
dynamonix save desk
Send the arrangement of a saved profile without the interface:
dynamonix apply desk
Let the program send the profile of a new group of monitors with no question:
dynamonix --auto
Show the profiles that you saved. This command does not need a compositor:
dynamonix profiles
Use a different socket:
dynamonix --socket /run/user/1000/niri.wayland-2.12345.sock
Profiles #
A profile holds an arrangement of your monitors with a name. The program keeps
the profiles in $XDG_CONFIG_HOME/dynamonix/profiles.json. It uses
~/.config/dynamonix/profiles.json when the environment gives no absolute
$XDG_CONFIG_HOME.
A profile records the make, the model and the serial number of each monitor. It does not record the name of the output. A profile therefore finds the same monitors after you move a cable to a different connector.
The apply command obeys the same safety rules as the interface. It examines
the layout before it sends the layout. The command shows no interface, so it
works in a niri key binding, in a script, and in a hotplug rule. The exit
status tells a script what occurred:
| Status | Condition |
|---|---|
| 0 | The compositor has the layout of the profile. |
| 1 | The program stopped with an error. |
| 2 | The program or the compositor did not accept the layout. |
Autoswitch #
You connect a monitor or you remove a monitor while the interface runs. The
program searches the profiles for the new group of monitors. When a profile
matches, the program shows the name of the profile, and you press Enter to
send it. The program sends nothing before that.
Start the program with --auto to send the matching profile with no question.
A group with no profile changes nothing.
The safety rules hold in both conditions. The program does not send a layout with an error. It reports the error instead.
Keys #
| Key | Operation |
|---|---|
← ↑ ↓ → or h j k l |
Move the selected output 48 pixels. The output aligns with the outputs near it. |
Shift and an arrow key |
Move the output one pixel. The output does not align. |
Tab |
Move the attention between the map and the list. |
m / M |
Select the next mode or the previous mode. |
+ / - |
Make the scale factor larger or smaller. |
r / R |
Turn the output 90 degrees. |
e |
Turn the output on or off. |
v |
Turn the variable refresh rate on or off. |
a |
Put all the outputs in one row. |
c |
Put all the outputs in one column. |
n |
Move the arrangement to the origin. |
u |
Remove the last change. |
Ctrl and r |
Return the change that the last u removed. |
U |
Remove all your changes. A u after it returns them. |
Enter |
Send the changes to the compositor. |
q or Esc |
Stop the program. |
Pointer #
Press an output in the map and move the pointer. The output follows the
pointer and aligns with the outputs near it, with the same rules as the keys.
Hold Shift to move with no alignment. The movement of one hold makes one
change, and one u removes it. A press outside of every output moves
nothing.
Safety #
The program examines an arrangement before it sends the arrangement. It stops two conditions:
- The program does not turn off the last output. A computer with no output is difficult to use.
- The program does not send a mode that the monitor does not have.
The program gives a warning for two other conditions. It does not stop them:
- Two outputs cover the same area.
- The outputs make more than one group, with a space between the groups.
Behavior of the compositor #
The program measured this behavior on niri 26.04:
- The compositor makes the logical size from the physical size. It divides the physical size by the scale factor. It then removes the fraction.
- The compositor accepts a scale factor between 0.1 and 10.0. It changes a value that is outside of these limits. It gives no error.
- The compositor accepts a change for a monitor that is not connected. It keeps the change. It applies the change when the monitor connects.
- The compositor has no event for a change of the outputs. A program that wants to know about a new monitor must ask the compositor again. The program therefore asks the compositor at a regular time. It also asks immediately after an other event.
Documentation #
The wiki holds the documents of the project:
License #
Refer to the LICENSE file at the root of the repository.