diff options
| -rw-r--r-- | .github/workflows/ci.yml | 12 | ||||
| -rw-r--r-- | wiki/Application-Issues.md | 30 | ||||
| -rw-r--r-- | wiki/Configuration:-Input.md | 1 | ||||
| -rw-r--r-- | wiki/Design-Principles.md | 11 | ||||
| -rw-r--r-- | wiki/Developing-niri.md | 65 | ||||
| -rw-r--r-- | wiki/Example-systemd-Setup.md | 75 | ||||
| -rw-r--r-- | wiki/Home.md | 5 | ||||
| -rw-r--r-- | wiki/Important-Software.md | 35 | ||||
| -rw-r--r-- | wiki/Layer‐Shell-Components.md | 5 | ||||
| -rw-r--r-- | wiki/Xwayland.md | 48 | ||||
| -rw-r--r-- | wiki/_Sidebar.md | 10 |
11 files changed, 297 insertions, 0 deletions
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 38b43386..7fc1c44d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -196,3 +196,15 @@ jobs: - run: nix build continue-on-error: true + + publish-wiki: + if: github.event_name == 'push' && github.ref == 'refs/heads/main' + needs: build + permissions: + contents: write + runs-on: ubuntu-22.04 + steps: + - uses: actions/checkout@v4 + with: + show-progress: false + - uses: Andrew-Chen-Wang/github-wiki-action@v4 diff --git a/wiki/Application-Issues.md b/wiki/Application-Issues.md new file mode 100644 index 00000000..695a3f24 --- /dev/null +++ b/wiki/Application-Issues.md @@ -0,0 +1,30 @@ +### VSCode + +There seems to be a bug in VSCode's Wayland backend until 1.86.0 which causes the window to not show up when using server-side decorations. So, to run VSCode: + +1. Make sure VSCode is 1.86.0 or above, or that `prefer-no-csd` is **not set** in the niri config +2. Run `code --ozone-platform-hint=auto --enable-features=WaylandWindowDecorations` + +Also, if you're having issues with some VSCode hotkeys, try starting `Xwayland` and setting the `DISPLAY=:0` environment variable for VSCode. That is, still running VSCode with the Wayland backend, but with `DISPLAY` set to a running Xwayland instance. Apparently, VSCode currently unconditionally queries the X server for a keymap. + +### Chromium + +When creating new windows within Chromium (e.g. with <kbd>Ctrl</kbd><kbd>N</kbd>), there's a Chromium bug with sizing: + +- With CSD (`prefer-no-csd` unset), the window will be a bit smaller than needed +- With SSD (`prefer-no-csd` set), the window buffer will be offset to the top-left + +Both of these can be fixed by resizing the new Chromium window. + +### WezTerm + +There's [a bug](https://github.com/wez/wezterm/issues/4708) in WezTerm that it waits for a zero-sized Wayland configure event, so its window never shows up in niri. To work around it, put this window rule in the niri config (included in the default config): + +``` +window-rule { + match app-id=r#"^org\.wezfurlong\.wezterm$"# + default-column-width {} +} +``` + +This empty default column width lets WezTerm pick its own initial width which makes it show up properly.
\ No newline at end of file diff --git a/wiki/Configuration:-Input.md b/wiki/Configuration:-Input.md new file mode 100644 index 00000000..00d7bdd4 --- /dev/null +++ b/wiki/Configuration:-Input.md @@ -0,0 +1 @@ +WIP diff --git a/wiki/Design-Principles.md b/wiki/Design-Principles.md new file mode 100644 index 00000000..82521080 --- /dev/null +++ b/wiki/Design-Principles.md @@ -0,0 +1,11 @@ +These are some of the general principles for the design of niri's window layout. They can be sidestepped in specific circumstances if there's a good reason. + +1. Opening a new window should not affect the sizes of any existing windows. +2. The focused window should not move around on its own. + - In particular: windows opening, closing and resizing to the left of the focused window should not cause it to visually move. +3. If a window or popup is larger than the screen, it should be aligned on the top left corner. + - The top left area of a window is more likely to contain something important so it should always be visible. +4. Setting window width or height to a fixed pixel size (e.g. `set-column-width 1280` or `default-column-width { fixed 1280; }`) will set the size of the window itself, however setting to a proportional size (e.g. `set-column-width 50%`) will set the size of the tile, including the border added by niri. + - With proportions, the user is looking to tile multiple windows on screen, so they should include borders. + - With fixed sizes, the user wants to test a specific client size or take a specifically sized screenshot, so they should affect the window directly. + - After the size is set, it is always converted to a value that includes the borders, to make the code sane. That is, `set-column-width 1000` followed by changing the niri border width will resize the window accordingly.
\ No newline at end of file diff --git a/wiki/Developing-niri.md b/wiki/Developing-niri.md new file mode 100644 index 00000000..f30bfb3c --- /dev/null +++ b/wiki/Developing-niri.md @@ -0,0 +1,65 @@ +## Running a Local Build + +The main way of testing niri during development is running it as a nested window. The second step is usually switching to a different TTY and running niri there. + +Once a feature or fix is reasonably complete, you generally want to run a local build as your main compositor for proper testing. The easiest way to do that is to install niri normally (from a distro package for example), then overwrite the binary with `sudo cp ./target/release/niri /usr/bin/niri`. Do make sure that you know how to revert to a working version in case everything breaks though. + +If you use an RPM-based distro, you can generate an RPM package for a local build with `cargo generate-rpm`. + +## Logging Levels + +Niri uses [`tracing`](https://lib.rs/crates/tracing) for logging. This is how logging levels are used: + +- `error!`: programming errors and bugs that are recoverable. Things you'd normally use `unwrap()` for. However, when a Wayland compositor crashes, it brings down the entire session, so it's better to recover and log an `error!` whenever reasonable. If you see an `ERROR` in the niri log, that always indicates a *bug*. +- `warn!`: something bad but still *possible* happened. Informing the user that they did something wrong, or that their hardware did something weird, falls into this category. For example, config parsing errors should be indicated with a `warn!`. +- `info!`: the most important messages related to normal operation. Running niri with `RUST_LOG=niri=info` should not make the user want to disable logging altogether. +- `debug!`: less important messages related to normal operation. Running niri with `debug!` messages hidden should not negatively impact the UX. +- `trace!`: everything that can be useful for debugging but is otherwise too spammy or performance intensive. `trace!` messages are *compiled out* of release builds. + +## Tests + +We have some unit tests, most prominently for the layout code and for config parsing. + +When adding new operations to the layout, add them to the `Op` enum at the bottom of `src/layout/mod.rs` (this will automatically include it in the randomized tests), and if applicable to the `every_op` arrays below. + +When adding new config options, include them in the config parsing test. + +### Running Tests + +Make sure to run `cargo test --all` to run tests from sub-crates too. + +Some tests are a bit too slow to run normally, like the randomized tests of the layout code, so they are normally skipped. Set the `RUN_SLOW_TESTS` variable to run them: + +``` +env RUN_SLOW_TESTS=1 cargo test --all +``` + +It also usually helps to run the randomized tests for a longer period, so that they can explore more inputs. You can control this with environment variables. This is how I usually run tests before pushing: + +``` +env RUN_SLOW_TESTS=1 PROPTEST_CASES=200000 PROPTEST_MAX_GLOBAL_REJECTS=200000 RUST_BACKTRACE=1 cargo test --release --all +``` + +### Visual Tests + +The `niri-visual-tests` sub-crate is a GTK application that runs hard-coded test cases so that you can visually check that they look right. It uses mock windows with the real layout and rendering code. It is especially helpful when working on animations. + +## Profiling + +We have integration with the [Tracy](https://github.com/wolfpld/tracy) profiler which you can enable by building niri with a feature flag: + +``` +cargo build --release --features=profile-with-tracy +``` + +Then you can open Tracy (you will need the latest stable release) and attach to a running niri instance to collect profiling data. This is **not** currently "on-demand" (until the next Tracy release), so niri will always collect profiling data when compiled this way, and you can't run a build like this as your main compositor. + +To make a niri function show up in Tracy, instrument it like this: + +```rust +pub fn some_function() { + let _span = tracy_client::span!("some_function"); + + // Code of the function. +} +```
\ No newline at end of file diff --git a/wiki/Example-systemd-Setup.md b/wiki/Example-systemd-Setup.md new file mode 100644 index 00000000..a3a96de0 --- /dev/null +++ b/wiki/Example-systemd-Setup.md @@ -0,0 +1,75 @@ +When starting niri from a display manager like GDM, or otherwise through the `niri-session` binary, it runs as a systemd service. +This provides the necessary systemd integration to run programs like `mako` and services like `xdg-desktop-portal` bound to the graphical session. + +Here's an example on how you might set up [`mako`](https://github.com/emersion/mako), [`waybar`](https://github.com/Alexays/Waybar), [`swaybg`](https://github.com/swaywm/swaybg) and [`swayidle`](https://github.com/swaywm/swayidle) to run as systemd services with niri. +In contrast to the `spawn-at-startup` config option, this lets you easily monitor their status and output, and restart or reload them. + +1. Install them, i.e. `sudo dnf install mako waybar swaybg swayidle` +2. Create a `niri.service.wants` folder: `mkdir -p ~/.config/systemd/user/niri.service.wants` + + This is a special systemd folder. + Any services linked there will be started together with `niri.service` (which is a systemd unit used by niri when running as a session). + +3. `mako` and `waybar` provide systemd units out of the box, so you can simply symlink them into the `niri.service.wants` folder: + + ``` + ln -s /usr/lib/systemd/user/mako.service ~/.config/systemd/user/niri.service.wants/ + ln -s /usr/lib/systemd/user/waybar.service ~/.config/systemd/user/niri.service.wants/ + ``` + +4. `swaybg` does not provide a systemd unit, since you need to pass the background image as a command-line argument. + So we will make our own. + Put the following into `~/.config/systemd/user/swaybg.service`: + + ``` + [Unit] + PartOf=graphical-session.target + After=graphical-session.target + Requisite=graphical-session.target + + [Service] + ExecStart=/usr/bin/swaybg -m fill -i "%h/Pictures/LakeSide.png" + Restart=on-failure + ``` + + Replace the image path with the one you want. + `%h` is expanded to your home directory. + + After editing `swaybg.service`, run `systemctl --user daemon-reload` so systemd picks up the changes in the file. + + Now, also symlink this to `niri.service.wants`: + + ``` + ln -s ~/.config/systemd/user/swaybg.service ~/.config/systemd/user/niri.service.wants/ + ``` + +5. `swayidle` similarly does not provide a service so we will also make our own. Put the following into `~/.config/systemd/user/swayidle.service`: + + ``` + [Unit] + PartOf=graphical-session.target + After=graphical-session.target + Requisite=graphical-session.target + + [Service] + ExecStart=/usr/bin/swayidle -w timeout 601 'niri msg action power-off-monitors' timeout 600 'swaylock -f' before-sleep 'swaylock -f' + Restart=on-failure + ``` + + Then, run `systemctl --user daemon-reload` and symlink this file to `niri.service.wants`: + + ``` + ln -s ~/.config/systemd/user/swayidle.service ~/.config/systemd/user/niri.service.wants/ + ``` + +That's it! +Now these three utilities will be started together with the niri session and stopped when it exits. +You can also restart them with a command like `systemctl --user restart waybar.service`, for example after editing their config files. + +### Running Programs Across Logout + +When running niri as a session, exiting it (logging out) will kill all programs that you've started within. However, sometimes you want a program, like `tmux`, `dtach` or similar, to persist in this case. To do this, run it in a transient systemd scope: + +``` +systemd-run --user --scope tmux new-session +```
\ No newline at end of file diff --git a/wiki/Home.md b/wiki/Home.md new file mode 100644 index 00000000..9cbf7563 --- /dev/null +++ b/wiki/Home.md @@ -0,0 +1,5 @@ +Welcome to the niri wiki! + +Check out the available pages on the right. + +The wiki is open to contribution, but please discuss bigger changes in [our Matrix room](https://matrix.to/#/#niri:matrix.org) first! The wiki is generated from files in the `wiki/` folder of the repository, so you can open a pull request modifying it there. diff --git a/wiki/Important-Software.md b/wiki/Important-Software.md new file mode 100644 index 00000000..8301f9e8 --- /dev/null +++ b/wiki/Important-Software.md @@ -0,0 +1,35 @@ +Since niri is not a complete desktop environment, you will very likely want to run the following software to make sure that other apps work fine. + +### Notification Daemon + +Many apps need one. For example, [mako](https://github.com/emersion/mako) works well. Use [a systemd setup](https://github.com/YaLTeR/niri/wiki/Example-systemd-Setup) or `spawn-at-startup`. + +### Portals + +These provide a cross-desktop API for apps to use for various things like file pickers or UI settings. Flatpak apps in particular require working portals. + +Portals **require** [running niri as a session](https://github.com/YaLTeR/niri#session), which means through the `niri-session` script or from a display manager. You will want the following portals installed: + +* `xdg-desktop-portal-gtk`: implements most of the basic functionality, this is the "default fallback portal". +* `xdg-desktop-portal-gnome`: required for screencasting support. +* `gnome-keyring`: implements the Secret portal, required for certain apps to work. + +Then systemd should start them on-demand automatically. These particular portals are configured in `niri-portals.conf` which [must be installed](https://github.com/YaLTeR/niri#installation) in the correct location. + +Since we're using `xdg-desktop-portal-gnome`, Flatpak apps will read the GNOME UI settings. For example, to enable the dark style, run: + +``` +dconf write /org/gnome/desktop/interface/color-scheme '"prefer-dark"' +``` + +### Authentication Agent + +Required when apps need to ask for root permissions. Something like `plasma-polkit-agent` works fine. Start it [with systemd](https://github.com/YaLTeR/niri/wiki/Example-systemd-Setup) or with `spawn-at-startup`. + +Note that to start `plasma-polkit-agent` with systemd on Fedora, you'll need to override its systemd service to add the correct dependency. Run: + +``` +systemctl --user edit --full plasma-polkit-agent.service +``` + +Then add `After=graphical-session.target`.
\ No newline at end of file diff --git a/wiki/Layer‐Shell-Components.md b/wiki/Layer‐Shell-Components.md new file mode 100644 index 00000000..d1166966 --- /dev/null +++ b/wiki/Layer‐Shell-Components.md @@ -0,0 +1,5 @@ +Things to keep in mind with layer-shell components (bars, launchers, etc.): + +1. Popups (tooltips, popup menus) render on the same layer as the component itself. Put your bar at the top layer, or menus will render below windows. +2. Components on the bottom and background layers will never receive keyboard focus, including for popups. They will however receive pointer focus as expected. +3. When a full-screen window is active and covers the entire screen, it will render above the top layer, and it will be prioritized for keyboard focus. If your launcher uses the top layer, and you try to run it while looking at a full-screen window, it won't show up. Only the overlay layer will show up on top of full-screen windows.
\ No newline at end of file diff --git a/wiki/Xwayland.md b/wiki/Xwayland.md new file mode 100644 index 00000000..95644ee9 --- /dev/null +++ b/wiki/Xwayland.md @@ -0,0 +1,48 @@ +X11 is very cursed, so built-in Xwayland support is not planned at the moment. +However, there are multiple solutions to running X11 apps in niri. + +## Directly running Xwayland in rootful mode +This method involves invoking XWayland directly and running it as its own window, it also requires an extra X11 window manager running inside it. + + + +Here's how you do it: + +1. Run `Xwayland` (just the binary on its own without flags). +This will spawn a black window which you can resize and fullscreen (with Mod+Shift+F) for convenience. +On older Xwayland versions the window will be screen-sized and non-resizable. +1. Run some X11 window manager in there, e.g. `env DISPLAY=:0 i3`. +This way you can manage X11 windows inside the Xwayland instance. +1. Run an X11 application there, e.g. `env DISPLAY=:0 flatpak run com.valvesoftware.Steam`. + +With fullscreen game inside a fullscreen Xwayland you get pretty much a normal gaming experience. + +One caveat is that currently rootful Xwayland doesn't seem to share clipboard with the compositor. +For textual data you can do it manually using [wl-clipboard](https://github.com/bugaevc/wl-clipboard), for example: + +- `env DISPLAY=:0 xsel -ob | wl-copy` to copy from Xwayland to niri clipboard +- `wl-paste | env DISPLAY=:0 xsel -ib` to copy from niri to Xwayland clipboard + +## Using the Cage Wayland compositor + +It is also possible to run the X11 application in [Cage](https://github.com/cage-kiosk/cage), which runs a nested Wayland session which also supports Xwayland, where the X11 application can run in. + +Compared to the Xwayland rootful method, this does not require running an extra X11 window manager, and can be used with one command `cage -- /path/to/application`. However, it can also cause issues if multiple windows are launched inside Cage, since Cage is meant to be used in kiosks, every new window will be automatically full-screened and take over the previously opened window. + +To use Cage you need to: + +1. Install `cage`, it should be in most repositories. +2. Run `cage -- /path/to/application` and enjoy your X11 program on niri. + +Optionally one can also modify the desktop entry for the application and add the `cage --` prefix to the `Exec` property. The Spotify Flatpak for example would look something like this: + +```ini +[Desktop Entry] +Type=Application +Name=Spotify +GenericName=Online music streaming service +Comment=Access all of your favorite music +Icon=com.spotify.Client +Exec=cage -- flatpak run com.spotify.Client +Terminal=false +```
\ No newline at end of file diff --git a/wiki/_Sidebar.md b/wiki/_Sidebar.md new file mode 100644 index 00000000..545dd5c7 --- /dev/null +++ b/wiki/_Sidebar.md @@ -0,0 +1,10 @@ +## Usage +* [Example systemd Setup](https://github.com/YaLTeR/niri/wiki/Example-systemd-Setup) +* [Important Software](https://github.com/YaLTeR/niri/wiki/Important-Software) +* [Layer‐Shell Components](https://github.com/YaLTeR/niri/wiki/Layer%E2%80%90Shell-Components) +* [VSCode, Chromium, WezTerm](https://github.com/YaLTeR/niri/wiki/Application-Issues) +* [Xwayland](https://github.com/YaLTeR/niri/wiki/Xwayland) + +## Development +* [Design Principles](https://github.com/YaLTeR/niri/wiki/Design-Principles) +* [Developing niri](https://github.com/YaLTeR/niri/wiki/Developing-niri)
\ No newline at end of file |
