git.lucas.co / cce-compositor
Wayland compositor (wlroots)
git clone https://git.lucas.co/cce-compositor.git

commite43ba9ab6c61679b6a875af12cc32a1b58d4bdb3
parent9a40ec57d5
authorIsaac Freund <[email protected]>
date2025-08-11 09:48
build: delete dead riverctl/rivertile code

 PACKAGING.md                           |   6 -
 README.md                              |   3 -
 build.zig                              |  85 +----
 completions/bash/riverctl              | 150 ---------
 completions/fish/riverctl.fish         | 140 --------
 completions/zsh/_riverctl              | 217 -------------
 contrib/layout.c                       | 488 ----------------------------
 contrib/layout.py                      | 146 ---------
 doc/riverctl.1.scd                     | 562 ---------------------------------
 doc/rivertile.1.scd                    |  88 ------
 example/init                           | 162 ----------
 protocol/river-control-unstable-v1.xml |  85 -----
 protocol/river-layout-v3.xml           | 196 ------------
 riverctl/main.zig                      | 148 ---------
 rivertile/main.zig                     | 419 ------------------------
 15 files changed, 2 insertions(+), 2893 deletions(-)

diff --git a/PACKAGING.md b/PACKAGING.md
index 315fe14..0b32c32 100644
--- a/PACKAGING.md
+++ b/PACKAGING.md
@@ -144,12 +144,6 @@ install() {
 }
 ```
 
-## River specific suggestions
-
-I recommend installing the example init file found at `example/init` to
-`/usr/share/examples/river/init` or similar if your distribution has such
-a convention.
-
 ## Examples
 
 Build for the host architecture and libc ABI:
diff --git a/README.md b/README.md
index d9f3aa3..3b0bf28 100644
--- a/README.md
+++ b/README.md
@@ -87,9 +87,6 @@ Usually this executable is a shell script invoking *riverctl*(1) to create
 mappings, start programs such as a layout generator or status bar, and
 perform other configuration.
 
-An example init script with sane defaults is provided [here](example/init)
-in the example directory.
-
 For complete documentation see the `river(1)`, `riverctl(1)`, and
 `rivertile(1)` man pages.
 
diff --git a/build.zig b/build.zig
index 15aa910..a32d3ca 100644
--- a/build.zig
+++ b/build.zig
@@ -31,24 +31,6 @@ pub fn build(b: *Build) !void {
         break :scdoc_found true;
     };
 
-    const bash_completion = b.option(
-        bool,
-        "bash-completion",
-        "Set to true to install bash completion for riverctl. Defaults to true.",
-    ) orelse true;
-
-    const zsh_completion = b.option(
-        bool,
-        "zsh-completion",
-        "Set to true to install zsh completion for riverctl. Defaults to true.",
-    ) orelse true;
-
-    const fish_completion = b.option(
-        bool,
-        "fish-completion",
-        "Set to true to install fish completion for riverctl. Defaults to true.",
-    ) orelse true;
-
     const xwayland = b.option(
         bool,
         "xwayland",
@@ -96,8 +78,6 @@ pub fn build(b: *Build) !void {
     scanner.addSystemProtocol("unstable/xdg-decoration/xdg-decoration-unstable-v1.xml");
 
     scanner.addCustomProtocol(b.path("protocol/river-window-management-v1.xml"));
-    scanner.addCustomProtocol(b.path("protocol/river-control-unstable-v1.xml"));
-    scanner.addCustomProtocol(b.path("protocol/river-layout-v3.xml"));
     scanner.addCustomProtocol(b.path("protocol/wlr-output-power-management-unstable-v1.xml"));
 
     // Some of these versions may be out of date with what wlroots implements.
@@ -124,9 +104,6 @@ pub fn build(b: *Build) !void {
 
     scanner.generate("river_window_manager_v1", 1);
 
-    scanner.generate("zriver_control_v1", 1);
-    scanner.generate("river_layout_manager_v3", 2);
-
     scanner.generate("zwlr_output_power_manager_v1", 1);
 
     const wayland = b.createModule(.{ .root_source_file = scanner.result });
@@ -213,52 +190,6 @@ pub fn build(b: *Build) !void {
         b.installArtifact(rivercompat);
     }
 
-    {
-        const riverctl = b.addExecutable(.{
-            .name = "riverctl",
-            .root_source_file = b.path("riverctl/main.zig"),
-            .target = target,
-            .optimize = optimize,
-            .strip = strip,
-            .use_llvm = llvm,
-            .use_lld = llvm,
-        });
-        riverctl.root_module.addOptions("build_options", options);
-
-        riverctl.root_module.addImport("flags", flags);
-        riverctl.root_module.addImport("wayland", wayland);
-        riverctl.linkLibC();
-        riverctl.linkSystemLibrary("wayland-client");
-
-        riverctl.pie = pie;
-        riverctl.root_module.omit_frame_pointer = omit_frame_pointer;
-
-        b.installArtifact(riverctl);
-    }
-
-    {
-        const rivertile = b.addExecutable(.{
-            .name = "rivertile",
-            .root_source_file = b.path("rivertile/main.zig"),
-            .target = target,
-            .optimize = optimize,
-            .strip = strip,
-            .use_llvm = llvm,
-            .use_lld = llvm,
-        });
-        rivertile.root_module.addOptions("build_options", options);
-
-        rivertile.root_module.addImport("flags", flags);
-        rivertile.root_module.addImport("wayland", wayland);
-        rivertile.linkLibC();
-        rivertile.linkSystemLibrary("wayland-client");
-
-        rivertile.pie = pie;
-        rivertile.root_module.omit_frame_pointer = omit_frame_pointer;
-
-        b.installArtifact(rivertile);
-    }
-
     {
         const wf = Build.Step.WriteFile.create(b);
         const pc_file = wf.add("river-protocols.pc", b.fmt(
@@ -272,12 +203,12 @@ pub fn build(b: *Build) !void {
             \\Version: {s}
         , .{ b.install_prefix, full_version }));
 
-        b.installFile("protocol/river-layout-v3.xml", "share/river-protocols/river-layout-v3.xml");
+        b.installFile("protocol/river-window-management-v1.xml", "share/river-protocols/river-window-management-v1.xml");
         b.getInstallStep().dependOn(&b.addInstallFile(pc_file, "share/pkgconfig/river-protocols.pc").step);
     }
 
     if (man_pages) {
-        inline for (.{ "river", "riverctl", "rivertile" }) |page| {
+        inline for (.{"river"}) |page| {
             // Workaround for https://github.com/ziglang/zig/issues/16369
             // Even passing a buffer to std.Build.Step.Run appears to be racy and occasionally deadlocks.
             const scdoc = b.addSystemCommand(&.{ "/bin/sh", "-c", "scdoc < doc/" ++ page ++ ".1.scd" });
@@ -289,18 +220,6 @@ pub fn build(b: *Build) !void {
         }
     }
 
-    if (bash_completion) {
-        b.installFile("completions/bash/riverctl", "share/bash-completion/completions/riverctl");
-    }
-
-    if (zsh_completion) {
-        b.installFile("completions/zsh/_riverctl", "share/zsh/site-functions/_riverctl");
-    }
-
-    if (fish_completion) {
-        b.installFile("completions/fish/riverctl.fish", "share/fish/vendor_completions.d/riverctl.fish");
-    }
-
     {
         const globber_test = b.addTest(.{
             .root_source_file = b.path("common/globber.zig"),
diff --git a/completions/bash/riverctl b/completions/bash/riverctl
deleted file mode 100644
index 68684d5..0000000
--- a/completions/bash/riverctl
+++ /dev/null
@@ -1,150 +0,0 @@
-function __riverctl_completion ()
-{
-	local rule_actions="float no-float ssd csd tags output position dimensions fullscreen no-fullscreen"
-	if [ "${COMP_CWORD}" -eq 1 ]
-	then
-		OPTS=" \
-			keyboard-group-create \
-			keyboard-group-destroy \
-			keyboard-group-add \
-			keyboard-group-remove \
-			keyboard-layout \
-			keyboard-layout-file \
-			close \
-			exit \
-			focus-output \
-			focus-view \
-			input \
-			list-inputs \
-			list-input-configs \
-			move \
-			resize \
-			rule-add \
-			rule-del \
-			list-rules \
-			snap \
-			send-to-output \
-			spawn \
-			swap \
-			toggle-float \
-			toggle-fullscreen \
-			zoom \
-			default-layout \
-			output-layout \
-			send-layout-cmd \
-			set-focused-tags \
-			focus-previous-tags \
-			send-to-previous-tags \
-			set-view-tags \
-			toggle-focused-tags \
-			toggle-view-tags \
-			spawn-tagmask \
-			declare-mode \
-			enter-mode \
-			map \
-			map-pointer \
-			map-switch \
-			unmap \
-			unmap-pointer \
-			unmap-switch \
-			default-attach-mode \
-			output-attach-mode \
-			background-color \
-			border-color-focused \
-			border-color-unfocused \
-			border-color-urgent \
-			border-width \
-			focus-follows-cursor \
-			hide-cursor \
-			set-repeat \
-			set-cursor-warp \
-			xcursor-theme"
-		COMPREPLY=($(compgen -W "${OPTS}" -- "${COMP_WORDS[1]}"))
-	elif [ "${COMP_CWORD}" -eq 2 ]
-	then
-		case "${COMP_WORDS[1]}" in
-			"focus-output"|"send-to-output") OPTS="next previous up right down left" ;;
-			"focus-view"|"swap") OPTS="next previous up down left right" ;;
-			"input") OPTS="$(riverctl list-inputs | sed '/configured:/d')" ;;
-			"move"|"snap") OPTS="up down left right" ;;
-			"resize") OPTS="horizontal vertical" ;;
-			"rule-add"|"rule-del") OPTS="-app-id -title $rule_actions" ;;
-			"list-rules") OPTS="float ssd tags output position dimensions fullscreen" ;;
-			"map") OPTS="-release -repeat -layout" ;;
-			"unmap") OPTS="-release" ;;
-			"default-attach-mode"|"output-attach-mode") OPTS="top bottom above below after" ;;
-			"focus-follows-cursor") OPTS="disabled normal always" ;;
-			"set-cursor-warp") OPTS="disabled on-output-change on-focus-change" ;;
-			"hide-cursor") OPTS="timeout when-typing" ;;
-			*) return ;;
-		esac
-		COMPREPLY=($(compgen -W "${OPTS}" -- "${COMP_WORDS[2]}"))
-	elif [ "${COMP_CWORD}" -eq 3 ]
-	then
-		if [ "${COMP_WORDS[1]}" == "input" ]
-		then
-			OPTS="events \
-				accel-profile \
-				pointer-accel \
-				click-method \
-				drag \
-				drag-lock \
-				disable-while-typing \
-				disable-while-trackpointing \
-				middle-emulation \
-				natural-scroll \
-				scroll-factor \
-				left-handed \
-				tap \
-				tap-button-map \
-				scroll-method \
-				scroll-button \
-				map-to-output"
-			COMPREPLY=($(compgen -W "${OPTS}" -- "${COMP_WORDS[3]}"))
-		elif [ "${COMP_WORDS[1]}" == "hide-cursor" ]
-		then
-			case "${COMP_WORDS[2]}" in
-				"when-typing") OPTS="enabled disabled" ;;
-				*) return ;;
-			esac
-			COMPREPLY=($(compgen -W "${OPTS}" -- "${COMP_WORDS[3]}"))
-		fi
-	elif [ "${COMP_CWORD}" -eq 4 ]
-	then
-		if [ "${COMP_WORDS[1]}" == "input" ]
-		then
-			case "${COMP_WORDS[3]}" in
-				"events") OPTS="enabled disabled disabled-on-external-mouse" ;;
-				"accel-profile") OPTS="none flat adaptive" ;;
-				"click-method") OPTS="none button-areas clickfinger" ;;
-				"drag"|"drag-lock"|"disable-while-typing"|"middle-emulation"|"left-handed"|"tap") OPTS="enabled disabled" ;;
-				"tap-button-map") OPTS="left-right-middle left-middle-right" ;;
-				"scroll-method") OPTS="none two-finger edge button" ;;
-				*) return ;;
-			esac
-			COMPREPLY=($(compgen -W "${OPTS}" -- "${COMP_WORDS[4]}"))
-		elif [ "${COMP_WORDS[1]:0:5}" == "rule-" ]
-		then
-			case "${COMP_WORDS[2]}" in
-				"-app-id") OPTS="-title $rule_actions" ;;
-				"-title") OPTS="-app-id $rule_actions" ;;
-				*) return ;;
-			esac
-			COMPREPLY=($(compgen -W "${OPTS}" -- "${COMP_WORDS[4]}"))
-		fi
-	elif [ "${COMP_CWORD}" -eq 6 ]
-	then
-		if [ "${COMP_WORDS[1]:0:5}" == "rule-" ]
-		then
-			case "${COMP_WORDS[4]}" in
-				"-app-id"|"-title") OPTS="$rule_actions" ;;
-				*) return ;;
-			esac
-			COMPREPLY=($(compgen -W "${OPTS}" -- "${COMP_WORDS[6]}"))
-		fi
-	else
-		return
-	fi
-}
-
-complete -F __riverctl_completion riverctl
diff --git a/completions/fish/riverctl.fish b/completions/fish/riverctl.fish
deleted file mode 100644
index 65fad0a..0000000
--- a/completions/fish/riverctl.fish
+++ /dev/null
@@ -1,140 +0,0 @@
-function __riverctl_list_input_devices
-    riverctl list-inputs | sed '/configured:/d'
-end
-
-function __fish_riverctl_complete_arg
-    set -l cmd (commandline -opc)
-    if test (count $cmd) -eq $argv[1]
-        return 0
-    end
-    return 1
-end
-
-# Remove any previous completion, such as options extracted from the manpage
-complete -c riverctl -e
-# Do not suggest files
-complete -c riverctl -f
-# Options
-complete -c riverctl -n '__fish_riverctl_complete_arg 1' -o 'h'       -d 'Print a help message and exit'
-complete -c riverctl -n '__fish_riverctl_complete_arg 1' -o 'version' -d 'Print the version number and exit'
-
-# Actions
-complete -c riverctl -n '__fish_riverctl_complete_arg 1' -a 'close'                  -d 'Close the focued view'
-complete -c riverctl -n '__fish_riverctl_complete_arg 1' -a 'exit'                   -d 'Exit the compositor, terminating the Wayland session'
-complete -c riverctl -n '__fish_riverctl_complete_arg 1' -a 'focus-output'           -d 'Focus the next or previous output'
-complete -c riverctl -n '__fish_riverctl_complete_arg 1' -a 'focus-view'             -d 'Focus the next or previous view in the stack'
-complete -c riverctl -n '__fish_riverctl_complete_arg 1' -a 'input'                  -d 'Create a configuration rule for an input device'
-complete -c riverctl -n '__fish_riverctl_complete_arg 1' -a 'list-inputs'            -d 'List all input devices'
-complete -c riverctl -n '__fish_riverctl_complete_arg 1' -a 'list-input-configs'     -d 'List all input configurations'
-complete -c riverctl -n '__fish_riverctl_complete_arg 1' -a 'move'                   -d 'Move the focused view in the specified direction'
-complete -c riverctl -n '__fish_riverctl_complete_arg 1' -a 'resize'                 -d 'Resize the focused view along the given axis'
-complete -c riverctl -n '__fish_riverctl_complete_arg 1' -a 'snap'                   -d 'Snap the focused view to the specified screen edge'
-complete -c riverctl -n '__fish_riverctl_complete_arg 1' -a 'send-to-output'         -d 'Send the focused view to the next/previous output'
-complete -c riverctl -n '__fish_riverctl_complete_arg 1' -a 'spawn'                  -d 'Run shell_command using /bin/sh -c'
-complete -c riverctl -n '__fish_riverctl_complete_arg 1' -a 'swap'                   -d 'Swap the focused view with the next/previous visible non-floating view'
-complete -c riverctl -n '__fish_riverctl_complete_arg 1' -a 'toggle-float'           -d 'Toggle the floating state of the focused view'
-complete -c riverctl -n '__fish_riverctl_complete_arg 1' -a 'toggle-fullscreen'      -d 'Toggle the fullscreen state of the focused view'
-complete -c riverctl -n '__fish_riverctl_complete_arg 1' -a 'zoom'                   -d 'Bump the focused view to the top of the layout stack'
-complete -c riverctl -n '__fish_riverctl_complete_arg 1' -a 'default-layout'         -d 'Set the layout namespace to be used by all outputs by default'
-complete -c riverctl -n '__fish_riverctl_complete_arg 1' -a 'output-layout'          -d 'Set the layout namespace of currently focused output'
-complete -c riverctl -n '__fish_riverctl_complete_arg 1' -a 'send-layout-cmd'        -d 'Send command to the layout generator on the currently focused output with the given namespace'
-# Tag managements
-complete -c riverctl -n '__fish_riverctl_complete_arg 1' -a 'set-focused-tags'       -d 'Show views with tags corresponding to the set bits of tags'
-complete -c riverctl -n '__fish_riverctl_complete_arg 1' -a 'set-view-tags'          -d 'Assign the currently focused view the tags corresponding to the set bits of tags'
-complete -c riverctl -n '__fish_riverctl_complete_arg 1' -a 'toggle-focused-tags'    -d 'Toggle visibility of views with tags corresponding to the set bits of tags'
-complete -c riverctl -n '__fish_riverctl_complete_arg 1' -a 'toggle-view-tags'       -d 'Toggle the tags of the currently focused view'
-complete -c riverctl -n '__fish_riverctl_complete_arg 1' -a 'spawn-tagmask'          -d 'Set a tagmask to filter the tags assigned to newly spawned views on the focused output'
-complete -c riverctl -n '__fish_riverctl_complete_arg 1' -a 'focus-previous-tags'    -d 'Sets tags to their previous value on the focused output'
-complete -c riverctl -n '__fish_riverctl_complete_arg 1' -a 'send-to-previous-tags'  -d 'Assign the currently focused view the previous tags of the focused output'
-# Mappings
-complete -c riverctl -n '__fish_riverctl_complete_arg 1' -a 'declare-mode'           -d 'Create a new mode'
-complete -c riverctl -n '__fish_riverctl_complete_arg 1' -a 'enter-mode'             -d 'Switch to given mode if it exists'
-complete -c riverctl -n '__fish_riverctl_complete_arg 1' -a 'map'                    -d 'Run command when key is pressed while modifiers are held down and in the specified mode'
-complete -c riverctl -n '__fish_riverctl_complete_arg 1' -a 'map-pointer'            -d 'Move or resize views or run command when button and modifers are held down while in the specified mode'
-complete -c riverctl -n '__fish_riverctl_complete_arg 1' -a 'map-switch '            -d 'Run command when river receives a switch event in the specified mode'
-complete -c riverctl -n '__fish_riverctl_complete_arg 1' -a 'unmap'                  -d 'Remove the mapping defined by the arguments'
-complete -c riverctl -n '__fish_riverctl_complete_arg 1' -a 'unmap-pointer'          -d 'Remove the pointer mapping defined by the arguments'
-complete -c riverctl -n '__fish_riverctl_complete_arg 1' -a 'unmap-switch'           -d 'Remove the switch mapping defined by the arguments'
-# Rules
-complete -c riverctl -n '__fish_riverctl_complete_arg 1' -a 'rule-add'               -d 'Apply an action to matching views'
-complete -c riverctl -n '__fish_riverctl_complete_arg 1' -a 'rule-del'               -d 'Delete a rule added with rule-add'
-complete -c riverctl -n '__fish_riverctl_complete_arg 1' -a 'list-rules'             -d 'Print rules in a given list'
-# Configuration
-complete -c riverctl -n '__fish_riverctl_complete_arg 1' -a 'default-attach-mode'    -d 'Set the attach mode to be used by all outputs by default'
-complete -c riverctl -n '__fish_riverctl_complete_arg 1' -a 'output-attach-mode'     -d 'Set the attach mode of the currently focused output'
-complete -c riverctl -n '__fish_riverctl_complete_arg 1' -a 'background-color'       -d 'Set the background color'
-complete -c riverctl -n '__fish_riverctl_complete_arg 1' -a 'border-color-focused'   -d 'Set the border color of focused views'
-complete -c riverctl -n '__fish_riverctl_complete_arg 1' -a 'border-color-unfocused' -d 'Set the border color of unfocused views'
-complete -c riverctl -n '__fish_riverctl_complete_arg 1' -a 'border-color-urgent'    -d 'Set the border color of urgent views'
-complete -c riverctl -n '__fish_riverctl_complete_arg 1' -a 'border-width'           -d 'Set the border width to pixels'
-complete -c riverctl -n '__fish_riverctl_complete_arg 1' -a 'focus-follows-cursor'   -d 'Configure the focus behavior when moving cursor'
-complete -c riverctl -n '__fish_riverctl_complete_arg 1' -a 'hide-cursor'            -d 'Hide cursor when typing or after inactivity'
-complete -c riverctl -n '__fish_riverctl_complete_arg 1' -a 'set-repeat'             -d 'Set the keyboard repeat rate and repeat delay'
-complete -c riverctl -n '__fish_riverctl_complete_arg 1' -a 'set-cursor-warp'        -d 'Set the cursor warp mode'
-complete -c riverctl -n '__fish_riverctl_complete_arg 1' -a 'xcursor-theme'          -d 'Set the xcursor theme'
-# Keyboardgroups
-complete -c riverctl -n '__fish_riverctl_complete_arg 1' -a 'keyboard-group-create'  -d 'Create a keyboard group'
-complete -c riverctl -n '__fish_riverctl_complete_arg 1' -a 'keyboard-group-destroy' -d 'Destroy a keyboard group'
-complete -c riverctl -n '__fish_riverctl_complete_arg 1' -a 'keyboard-group-add'     -d 'Add a keyboard to a keyboard group'
-complete -c riverctl -n '__fish_riverctl_complete_arg 1' -a 'keyboard-group-remove'  -d 'Remove a keyboard from a keyboard group'
-complete -c riverctl -n '__fish_riverctl_complete_arg 1' -a 'keyboard-layout'        -d 'Set the keyboard layout'
-complete -c riverctl -n '__fish_riverctl_complete_arg 1' -a 'keyboard-layout-file'   -d 'Set the keyboard layout from a file.'
-
-# Subcommands
-complete -c riverctl -n '__fish_seen_subcommand_from focus-output send-to-output' -n '__fish_riverctl_complete_arg 2' -a 'next previous up right down left'
-complete -c riverctl -n '__fish_seen_subcommand_from focus-view swap'             -n '__fish_riverctl_complete_arg 2' -a 'next previous up down left right'
-complete -c riverctl -n '__fish_seen_subcommand_from move snap'                   -n '__fish_riverctl_complete_arg 2' -a 'up down left right'
-complete -c riverctl -n '__fish_seen_subcommand_from resize'                      -n '__fish_riverctl_complete_arg 2' -a 'horizontal vertical'
-complete -c riverctl -n '__fish_seen_subcommand_from map'                                                             -o 'release' -o 'repeat' -o 'layout'
-complete -c riverctl -n '__fish_seen_subcommand_from unmap'                       -n '__fish_riverctl_complete_arg 2' -o 'release'
-complete -c riverctl -n '__fish_seen_subcommand_from default-attach-mode'         -n '__fish_riverctl_complete_arg 2' -a 'top bottom above below after'
-complete -c riverctl -n '__fish_seen_subcommand_from output-attach-mode'          -n '__fish_riverctl_complete_arg 2' -a 'top bottom above below after'
-complete -c riverctl -n '__fish_seen_subcommand_from focus-follows-cursor'        -n '__fish_riverctl_complete_arg 2' -a 'disabled normal always'
-complete -c riverctl -n '__fish_seen_subcommand_from set-cursor-warp'             -n '__fish_riverctl_complete_arg 2' -a 'disabled on-output-change on-focus-change'
-complete -c riverctl -n '__fish_seen_subcommand_from list-rules'                  -n '__fish_riverctl_complete_arg 2' -a 'float ssd tags output position dimensions fullscreen'
-
-# Options and subcommands for 'rule-add' and 'rule-del'
-set -l rule_actions float no-float ssd csd tags output position dimensions fullscreen no-fullscreen
-complete -c riverctl -n '__fish_seen_subcommand_from rule-add rule-del' -n "not __fish_seen_subcommand_from $rule_actions" -n 'not __fish_seen_argument -o app-id' -o 'app-id' -r
-complete -c riverctl -n '__fish_seen_subcommand_from rule-add rule-del' -n "not __fish_seen_subcommand_from $rule_actions" -n 'not __fish_seen_argument -o title'  -o 'title' -r
-complete -c riverctl -n '__fish_seen_subcommand_from rule-add rule-del' -n "not __fish_seen_subcommand_from $rule_actions" -n 'test (math (count (commandline -opc)) % 2) -eq 0' -a "$rule_actions"
-set -e rule_actions
-
-# Subcommands for 'input'
-complete -c riverctl -n '__fish_seen_subcommand_from input; and __fish_riverctl_complete_arg 2' -a "(__riverctl_list_input_devices)"
-
-complete -c riverctl -n '__fish_seen_subcommand_from input; and __fish_riverctl_complete_arg 3' -a 'events'               -d 'Configure whether the input device\'s events will be used'
-complete -c riverctl -n '__fish_seen_subcommand_from input; and __fish_riverctl_complete_arg 3' -a 'accel-profile'        -d 'Set the pointer acceleration profile'
-complete -c riverctl -n '__fish_seen_subcommand_from input; and __fish_riverctl_complete_arg 3' -a 'pointer-accel'        -d 'Set the pointer acceleration factor'
-complete -c riverctl -n '__fish_seen_subcommand_from input; and __fish_riverctl_complete_arg 3' -a 'click-method'         -d 'Set the click method'
-complete -c riverctl -n '__fish_seen_subcommand_from input; and __fish_riverctl_complete_arg 3' -a 'drag'                 -d 'Enable or disable the tap-and-drag functionality'
-complete -c riverctl -n '__fish_seen_subcommand_from input; and __fish_riverctl_complete_arg 3' -a 'drag-lock'            -d 'Enable or disable the drag lock functionality'
-complete -c riverctl -n '__fish_seen_subcommand_from input; and __fish_riverctl_complete_arg 3' -a 'disable-while-typing' -d 'Enable or disable the disable-while-typing functionality'
-complete -c riverctl -n '__fish_seen_subcommand_from input; and __fish_riverctl_complete_arg 3' -a 'disable-while-trackpointing' -d 'Enable or disable the disable-while-trackpointing functionality'
-complete -c riverctl -n '__fish_seen_subcommand_from input; and __fish_riverctl_complete_arg 3' -a 'middle-emulation'     -d 'Enable or disable the middle-emulation functionality'
-complete -c riverctl -n '__fish_seen_subcommand_from input; and __fish_riverctl_complete_arg 3' -a 'natural-scroll'       -d 'Enable or disable the natural-scroll functionality'
-complete -c riverctl -n '__fish_seen_subcommand_from input; and __fish_riverctl_complete_arg 3' -a 'scroll-factor'        -d 'Set the scroll factor'
-complete -c riverctl -n '__fish_seen_subcommand_from input; and __fish_riverctl_complete_arg 3' -a 'left-handed'          -d 'Enable or disable the left handed mode'
-complete -c riverctl -n '__fish_seen_subcommand_from input; and __fish_riverctl_complete_arg 3' -a 'tap'                  -d 'Enable or disable the tap functionality'
-complete -c riverctl -n '__fish_seen_subcommand_from input; and __fish_riverctl_complete_arg 3' -a 'tap-button-map'       -d 'Configure the button mapping for tapping'
-complete -c riverctl -n '__fish_seen_subcommand_from input; and __fish_riverctl_complete_arg 3' -a 'scroll-method'        -d 'Set the scroll method'
-complete -c riverctl -n '__fish_seen_subcommand_from input; and __fish_riverctl_complete_arg 3' -a 'scroll-button'        -d 'Set the scroll button'
-complete -c riverctl -n '__fish_seen_subcommand_from input; and __fish_riverctl_complete_arg 3' -a 'map-to-output'        -d 'Map to a given output'
-
-# Subcommands for the subcommands of 'input'
-complete -c riverctl -n '__fish_seen_subcommand_from input; and __fish_riverctl_complete_arg 4; and __fish_seen_subcommand_from drag drag-lock disable-while-typing disable-while-trackpointing middle-emulation natural-scroll left-handed tap' -a 'enabled disabled'
-complete -c riverctl -n '__fish_seen_subcommand_from input; and __fish_riverctl_complete_arg 4; and __fish_seen_subcommand_from events'         -a 'enabled disabled disabled-on-external-mouse'
-complete -c riverctl -n '__fish_seen_subcommand_from input; and __fish_riverctl_complete_arg 4; and __fish_seen_subcommand_from accel-profile'  -a 'none flat adaptive'
-complete -c riverctl -n '__fish_seen_subcommand_from input; and __fish_riverctl_complete_arg 4; and __fish_seen_subcommand_from click-method'   -a 'none button-areas clickfinger'
-complete -c riverctl -n '__fish_seen_subcommand_from input; and __fish_riverctl_complete_arg 4; and __fish_seen_subcommand_from tap-button-map' -a 'left-right-middle left-middle-right'
-complete -c riverctl -n '__fish_seen_subcommand_from input; and __fish_riverctl_complete_arg 4; and __fish_seen_subcommand_from scroll-method'  -a 'none'       -d 'No scrolling'
-complete -c riverctl -n '__fish_seen_subcommand_from input; and __fish_riverctl_complete_arg 4; and __fish_seen_subcommand_from scroll-method'  -a 'two-finger' -d 'Scroll by swiping with two fingers simultaneously'
-complete -c riverctl -n '__fish_seen_subcommand_from input; and __fish_riverctl_complete_arg 4; and __fish_seen_subcommand_from scroll-method'  -a 'edge'       -d 'Scroll by swiping along the edge'
-complete -c riverctl -n '__fish_seen_subcommand_from input; and __fish_riverctl_complete_arg 4; and __fish_seen_subcommand_from scroll-method'  -a 'button'     -d 'Scroll with pointer movement while holding down a button'
-
-# Subcommands for 'hide-cursor'
-complete -c riverctl -n '__fish_seen_subcommand_from hide-cursor; and __fish_riverctl_complete_arg 2' -a 'timeout'     -d 'Hide cursor if it wasn\'t moved in the last X millisecond, until it is moved again'
-complete -c riverctl -n '__fish_seen_subcommand_from hide-cursor; and __fish_riverctl_complete_arg 2' -a 'when-typing' -d 'Enable or disable whether the cursor should be hidden when pressing any non-modifier key'
-
-# Subcommands for the subcommands of 'hide-cursor'
-complete -c riverctl -n '__fish_seen_subcommand_from hide-cursor; and __fish_riverctl_complete_arg 3; and __fish_seen_subcommand_from when-typing' -a 'enabled disabled'
diff --git a/completions/zsh/_riverctl b/completions/zsh/_riverctl
deleted file mode 100644
index 73df6b1..0000000
--- a/completions/zsh/_riverctl
+++ /dev/null
@@ -1,217 +0,0 @@
-#compdef riverctl
-#
-# Completion script for riverctl, part of river <https://codeberg.org/river/river>
-
-# This is the list of all riverctl first argument, i.e `riverctl <first_arg>`.
-# If a command doesn't need completion for subcommands then you just need
-# to add a line to this list.
-# Format is '<command-name>:<description>'
-_riverctl_commands()
-{
-    local -a riverctl_commands
-
-    riverctl_commands=(
-        # Actions
-        'close:Close the focused view'
-        'exit:Exit the compositor, terminating the Wayland session'
-        'focus-output:Focus the next or previous output'
-        'focus-view:Focus the next or previous view in the stack'
-        'move:Move the focused view in the specified direction'
-        'resize:Resize the focused view along the given axis'
-        'snap:Snap the focused view to the specified screen edge'
-        'send-to-output:Send the focused view to the next or the previous output'
-        'spawn:Run shell_command using /bin/sh -c'
-        'swap:Swap the focused view with the next/previous visible non-floating view'
-        'toggle-float:Toggle the floating state of the focused view'
-        'toggle-fullscreen:Toggle the fullscreen state of the focused view'
-        'zoom:Bump the focused view to the top of the layout stack'
-        'default-layout:Set the layout namespace to be used by all outputs by default.'
-        'output-layout:Set the layout namespace of currently focused output.'
-        'send-layout-cmd:Send command to the layout generator on the currently focused output with matching namespace'
-        # Tag management
-        'set-focused-tags:Show views with tags corresponding to the set bits of tags'
-        'set-view-tags:Assign the currently focused view the tags corresponding to the set bits of tags'
-        'toggle-focused-tags:Toggle visibility of views with tags corresponding to the set bits of tags'
-        'toggle-view-tags:Toggle the tags of the currently focused view'
-        'spawn-tagmask:Set a tagmask to filter the tags assigned to newly spawned views on the focused output'
-        'focus-previous-tags:Sets tags to their previous value on the focused output'
-        'send-to-previous-tags:Assign the currently focused view the previous tags of the focused output'
-        # Mappings
-        'declare-mode:Create a new mode'
-        'enter-mode:Switch to given mode if it exists'
-        'map:Run command when key is pressed while modifiers are held down and in the specified mode'
-        'map-pointer:Move or resize views or run command when button and modifiers are held down while in the specified mode'
-        'map-switch:Run command when river receives a switch event in the specified mode'
-        'unmap:Remove the mapping defined by the arguments'
-        'unmap-pointer:Remove the pointer mapping defined by the arguments'
-        'unmap-switch:Remove the switch mapping defined by the arguments'
-        # Rules
-        'rule-add:Apply an action to matching views'
-        'rule-del:Delete a rule added with rule-add'
-        'list-rules:Print rules in a given list'
-        # Configuration
-        'default-attach-mode:Configure where new views should attach to the view stack'
-        'output-attach-mode:Configure where new views should attach to the view stack of the currently focuesed output'
-        'background-color:Set the background color'
-        'border-color-focused:Set the border color of focused views'
-        'border-color-unfocused:Set the border color of unfocused views'
-        'border-color-urgent:Set the border color of urgent views'
-        'border-width:Set the border width to pixels'
-        'focus-follows-cursor:Configure the focus behavior when moving cursor'
-        'hide-cursor:Hide cursor when typing or after inactivity'
-        'set-repeat:Set the keyboard repeat rate and repeat delay'
-        'set-cursor-warp:Set the cursor warp mode.'
-        'xcursor-theme:Set the xcursor theme'
-        # Keyboard groups
-        'keyboard-group-create:Create a keyboard group'
-        'keyboard-group-destroy:Destroy a keyboard group'
-        'keyboard-group-add:Add a keyboard to a keyboard group'
-        'keyboard-group-remove:Remove a keyboard from a keyboard group'
-        'keyboard-layout:Set the keyboard layout'
-        'keyboard-layout-file:Set the keyboard layout from a file'
-        # Input
-        'input:Configure input devices'
-        'list-inputs:List all input devices'
-        'list-input-configs:List all input configurations'
-    )
-
-    _describe -t command 'command' riverctl_commands
-}
-
-# This is the function called for the completion. Commands added in the
-# riverctl_commands above are generated in the `commands` case, there is
-# nothing more to do for this. If a command has a subcommand then a new case
-# need to be added in `args`.
-# If this is a simple subcommand with simple multi choice, the easier way to
-# do it is:
-#   <command-name>) _alternative 'arguments:args:(<choice1 choice2)' ;;
-# If the subcommand also has subcommands then, good luck...
-# This is really complex, the easiest example to look at is the `hide-cursor` one.
-_riverctl()
-{
-    local state line
-
-    _arguments -C \
-        '1: :->commands' \
-        '*:: :->args'
-
-    case "$state" in
-        commands) _alternative 'common-commands:common:_riverctl_commands' ;;
-        args)
-            case "$line[1]" in
-                focus-output) _alternative 'arguments:args:(next previous up right down left)' ;;
-                focus-view) _alternative 'arguments:args:(next previous up down left right)' ;;
-                keyboard-layout) _arguments '*::optional:(-rules -model -variant -options)' ;;
-                input)
-                    _arguments '1: :->name' '2: :->commands' ':: :->args'
-
-                    case "$state" in
-                        name)  _alternative "arguments:args:($(riverctl list-inputs | grep -e '^[^[:space:]]'))" ;;
-                        commands)
-                            local -a input_subcommands
-                            input_subcommands=(
-                                'events:Configure whether the input devices events will be used by river'
-                                'accel-profile:Set the pointer acceleration profile'
-                                'pointer-accel:Set the pointer acceleration factor'
-                                'click-method:Set the click method'
-                                'drag:Enable or disable the tap-and-drag functionality'
-                                'drag-lock:Enable or disable the drag lock functionality'
-                                'disable-while-typing:Enable or disable the disable-while-typing functionality'
-                                'disable-while-trackpointing:Enable or disable the disable-while-trackpointing functionality'
-                                'middle-emulation:Enable or disable the middle click emulation functionality'
-                                'natural-scroll:Enable or disable the natural scroll functionality'
-                                'scroll-factor:Set the scroll factor'
-                                'left-handed:Enable or disable the left handed mode'
-                                'tap:Enable or disable the tap functionality'
-                                'tap-button-map:Configure the button mapping for tapping'
-                                'scroll-method:Set the scroll method'
-                                'scroll-button:Set the scroll button'
-                                'map-to-output:Map to a given output'
-                            )
-
-                        _describe -t command 'command' input_subcommands
-                        ;;
-                        args)
-                            case "$line[2]" in
-                                events) _alternative 'input-cmds:args:(enabled disabled disabled-on-external-mouse)' ;;
-                                accel-profile) _alternative 'input-cmds:args:(none flat adaptive)' ;;
-                                click-method) _alternative 'input-cmds:args:(none button-areas clickfinger)' ;;
-                                drag) _alternative 'input-cmds:args:(enabled disabled)' ;;
-                                drag-lock) _alternative 'input-cmds:args:(enabled disabled)' ;;
-                                disable-while-typing) _alternative 'input-cmds:args:(enabled disabled)' ;;
-                                disable-while-trackpointing) _alternative 'input-cmds:args:(enabled disabled)' ;;
-                                middle-emulation) _alternative 'input-cmds:args:(enabled disabled)' ;;
-                                natural-scroll) _alternative 'input-cmds:args:(enabled disabled)' ;;
-                                left-handed) _alternative 'input-cmds:args:(enabled disabled)' ;;
-                                tap) _alternative 'input-cmds:args:(enabled disabled)' ;;
-                                tap-button-map) _alternative 'input-cmds:args:(left-right-middle left-middle-right)' ;;
-                                scroll-method) _alternative 'input-cmds:args:(none two-finger edge button)' ;;
-                                *) return 0 ;;
-                            esac
-                        ;;
-                    esac
-                ;;
-                move) _alternative 'arguments:args:(up down left right)' ;;
-                resize) _alternative 'arguments:args:(horizontal vertical)' ;;
-                snap) _alternative 'arguments:args:(up down left right)' ;;
-                send-to-output) _arguments \
-                                    '1::optional:(-current-tag)' \
-                                    '::args:(next previous up right down left)'
-                ;;
-                swap) _alternative 'arguments:args:(next previous up down left right)' ;;
-                map) _alternative 'arguments:optional:(-release -repeat -layout)' ;;
-                unmap) _alternative 'arguments:optional:(-release)' ;;
-                map-switch | unmap-switch)
-                    _arguments '1: :' '2:args:(lid tablet)' '3:args:->args'
-                    case "$state" in
-                        args)
-                            case "$line[2]" in
-                                lid) _alternative 'arguments:args:(close open)' ;;
-                                tablet) _alternative 'arguments:args:(on off)' ;;
-                            esac
-                        ;;
-                    esac
-                ;;
-                default-attach-mode) _alternative 'arguments:args:(top bottom above below after)' ;;
-                output-attach-mode) _alternative 'arguments:args:(top bottom above below after)' ;;
-                focus-follows-cursor) _alternative 'arguments:args:(disabled normal always)' ;;
-                set-cursor-warp) _alternative 'arguments:args:(disabled on-output-change on-focus-change)' ;;
-                hide-cursor)
-                    _arguments '1: :->commands' ':: :->args'
-
-                    case "$state" in
-                        commands)
-                            local -a hide_cursor_subcommands
-                            hide_cursor_subcommands=(
-                                "timeout:Hide cursor if it wasn\'t moved in the last X millisecond, until it is moved again"
-                                'when-typing:Enable or disable whether the cursor should be hidden when pressing any non-modifier key'
-                            )
-
-                            _describe -t command 'command' hide_cursor_subcommands
-                            ;;
-                        args)
-                            case "$line[1]" in
-                                when-typing) _alternative 'hide-cursor-cmds:args:(enabled disabled)' ;;
-                                *) return 0 ;;
-                            esac
-                        ;;
-                    esac
-                ;;
-                rule-add | rule-del)
-                    # This is not perfect as it only complete if there is
-                    # either '-app-id' or '-title'.
-                    # The empty action(2) mean that we need an argument
-                    # but we don't generate anything for it.
-                    # In case of a new rule added in river, we just need
-                    # to add it to the third option between '()',
-                    # i.e (float no-float <new-option>)
-                    _arguments '1: :(-app-id -title)' '2: : ' ':: :(float no-float ssd csd tags output position dimensions fullscreen no-fullscreen)'
-                ;;
-                list-rules) _alternative 'arguments:args:(float ssd tags output position dimensions fullscreen)' ;;
-                *) return 0 ;;
-            esac
-        ;;
-    esac
-}
-
-_riverctl "$@"
diff --git a/contrib/layout.c b/contrib/layout.c
deleted file mode 100644
index 0e1fdfb..0000000
--- a/contrib/layout.c
+++ /dev/null
@@ -1,488 +0,0 @@
-/*
- * Tiled layout for river, implemented in understandable, simple, commented code.
- * Reading this code should help you get a basic understanding of how to use
- * river-layout to create a basic layout generator.
- *
- * Q: Wow, this is a lot of code just for a layout!
- * A: No, it really is not. Most of the code here is just generic Wayland client
- *    boilerplate. The actual layout part is pretty small.
- *
- * Q: Can I use this to port dwm layouts to river?
- * A: Yes you can! You just need to replace the logic in layout_handle_layout_demand().
- *    You don't even need to fully understand the protocol if all you want to
- *    do is just port some layouts.
- *
- * Q: I have no idea how any of this works.
- * A: If all you want to do is create layouts, you do not need to understand
- *    the Wayland parts of the code. If you still want to understand it and are
- *    familiar with how Wayland clients work, read the protocol. If you are new
- *    to writing Wayland client code, you can read https://wayland-book.com,
- *    then read the protocol.
- *
- * Q: How do I build this?
- * A: To build, you need to generate the header and code of the layout protocol
- *    extension and link against them. This is achieved with the following
- *    commands (You may want to setup a build system).
- *
- *        wayland-scanner private-code < river-layout-v3.xml > river-layout-v3.c
- *        wayland-scanner client-header < river-layout-v3.xml > river-layout-v3.h
- *        gcc -Wall -Wextra -Wpedantic -Wno-unused-parameter -c -o layout.o layout.c
- *        gcc -Wall -Wextra -Wpedantic -Wno-unused-parameter -c -o river-layout-v3.o river-layout-v3.c
- *        gcc -o layout layout.o river-layout-v3.o -lwayland-client
- */
-
-#include <assert.h>
-#include <ctype.h>
-#include <stdbool.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include <wayland-client.h>
-#include <wayland-client-protocol.h>
-
-#include "river-layout-v3.h"
-
-/* A few macros to indulge the inner glibc user. */
-#define MIN(a, b) ( a < b ? a : b )
-#define MAX(a, b) ( a > b ? a : b )
-#define CLAMP(a, b, c) ( MIN(MAX(b, c), MAX(MIN(b, c), a)) )
-
-struct Output
-{
-	struct wl_list link;
-
-	struct wl_output       *output;
-	struct river_layout_v3 *layout;
-
-	uint32_t main_count;
-	double main_ratio;
-	uint32_t view_padding;
-	uint32_t outer_padding;
-
-	bool configured;
-};
-
-/* In Wayland it's a good idea to have your main data global, since you'll need
- * it everywhere anyway.
- */
-struct wl_display  *wl_display;
-struct wl_registry *wl_registry;
-struct wl_callback *sync_callback;
-struct river_layout_manager_v3 *layout_manager;
-struct wl_list outputs;
-bool loop = true;
-int ret = EXIT_FAILURE;
-
-static void layout_handle_layout_demand (void *data, struct river_layout_v3 *river_layout_v3,
-		uint32_t view_count, uint32_t width, uint32_t height, uint32_t tags, uint32_t serial)
-{
-	struct Output *output = (struct Output *)data;
-
-	/* Simple tiled layout with no frills.
-	 *
-	 * If you want to create your own layout, just rip the following code
-	 * out and replace it with your own logic. All dynamic tiling layouts
-	 * you know, for example from dwm, can be easily ported to river this
-	 * way. For more creative layouts, you probably also want to add custom
-	 * values. Happy hacking!
-	 */
-	width -= 2 * output->outer_padding, height -= 2 * output->outer_padding;
-	unsigned int main_size, stack_size, view_x, view_y, view_width, view_height;
-	if ( output->main_count == 0 )
-	{
-		main_size  = 0;
-		stack_size = width;
-	}
-	else if ( view_count <= output->main_count )
-	{
-		main_size  = width;
-		stack_size = 0;
-	}
-	else
-	{
-		main_size  = width * output->main_ratio;
-		stack_size = width - main_size;
-	}
-	for (unsigned int i = 0; i < view_count; i++)
-	{
-		if ( i < output->main_count ) /* main area. */
-		{
-			view_x      = 0;
-			view_width  = main_size;
-			view_height = height / MIN(output->main_count, view_count);
-			view_y      = i * view_height;
-		}
-		else /* Stack area. */
-		{
-			view_x      = main_size;
-			view_width  = stack_size;
-			view_height = height / ( view_count - output->main_count);
-			view_y      = (i - output->main_count) * view_height;
-		}
-
-		river_layout_v3_push_view_dimensions(output->layout,
-				view_x + output->view_padding + output->outer_padding,
-				view_y + output->view_padding + output->outer_padding,
-				view_width - (2 * output->view_padding),
-				view_height - (2 * output->view_padding),
-				serial);
-	}
-
-	/* Committing the layout means telling the server that your code is done
-	 * laying out windows. Make sure you have pushed exactly the right
-	 * amount of view dimensions, a mismatch is a protocol error.
-	 *
-	 * You also have to provide a layout name. This is a user facing string
-	 * that the server can forward to status bars. You can use it to tell
-	 * the user which layout is currently in use. You could also add some
-	 * status information about your layout, but in this example we are
-	 * boring and just use a static "[]=" like in dwm.
-	 */
-	river_layout_v3_commit(output->layout, "[]=", serial);
-}
-
-static void layout_handle_namespace_in_use (void *data, struct river_layout_v3 *river_layout_v3)
-{
-	/* Oh no, the namespace we choose is already used by another client!
-	 * All we can do now is destroy the river_layout object. Because we are
-	 * lazy, we just abort and let our cleanup mechanism destroy it. A more
-	 * sophisticated client could instead destroy only the one single
-	 * affected river_layout object and recover from this mishap. Writing
-	 * such a client is left as an exercise for the reader.
-	 */
-	fputs("Namespace already in use.\n", stderr);
-	loop = false;
-}
-
-static bool skip_whitespace (char **ptr)
-{
-	if ( *ptr == NULL )
-		return false;
-	while (isspace(**ptr))
-	{
-		(*ptr)++;
-		if ( **ptr == '\0' )
-			return false;
-	}
-	return true;
-}
-
-static bool skip_nonwhitespace (char **ptr)
-{
-	if ( *ptr == NULL )
-		return false;
-	while (! isspace(**ptr))
-	{
-		(*ptr)++;
-		if ( **ptr == '\0' )
-			return false;
-	}
-	return true;
-}
-
-static const char *get_second_word (char **ptr, const char *name)
-{
-	/* Skip to the next word. */
-	if ( !skip_nonwhitespace(ptr) || !skip_whitespace(ptr) )
-	{
-		fprintf(stderr, "ERROR: Too few arguments. '%s' needs one argument.\n", name);
-		return NULL;
-	}
-
-	/* Now we know where the second word begins. */
-	const char *second_word = *ptr;
-
-	/* Check if there is a third word. */
-	if ( skip_nonwhitespace(ptr) && skip_whitespace(ptr) )
-	{
-		fprintf(stderr, "ERROR: Too many arguments. '%s' needs one argument.\n", name);
-		return NULL;
-	}
-
-	return second_word;
-}
-
-static void handle_uint32_command (char **ptr, uint32_t *value, const char *name)
-{
-	const char *second_word = get_second_word(ptr, name);
-	if ( second_word == NULL )
-		return;
-	const int32_t arg = atoi(second_word);
-	if ( *second_word == '+' || *second_word == '-' )
-		*value = (uint32_t)MAX((int32_t)*value + arg, 0);
-	else
-		*value = (uint32_t)MAX(arg, 0);
-}
-
-static void handle_float_command(char **ptr, double *value, const char *name, double clamp_upper, double clamp_lower)
-{
-	const char *second_word = get_second_word(ptr, name);
-	if ( second_word == NULL )
-		return;
-	const double arg = atof(second_word);
-	if ( *second_word == '+' || *second_word == '-' )
-		*value = CLAMP(*value + arg, clamp_upper, clamp_lower);
-	else
-		*value = CLAMP(arg, clamp_upper, clamp_lower);
-}
-
-static bool word_comp (const char *word, const char *comp)
-{
-	if ( strncmp(word, comp, strlen(comp)) == 0 )
-	{
-		const char *after_comp = word + strlen(comp);
-		if ( isspace(*after_comp) ||  *after_comp == '\0' )
-			return true;
-	}
-	return false;
-
-}
-
-static void layout_handle_user_command (void *data, struct river_layout_v3 *river_layout_manager_v3,
-		const char *_command)
-{
-	/* The user_command event will be received whenever the user decided to
-	 * send us a command. As an example, commands can be used to change the
-	 * layout values. Parsing the commands is the job of the layout
-	 * generator, the server just sends us the raw string.
-	 *
-	 * After this event is recevied, the views on the output will be
-	 * re-arranged and so we will also receive a layout_demand event.
-	 */
-
-	struct Output *output = (struct Output *)data;
-
-	/* Skip preceding whitespace. */
-	char *command = (char *)_command;
-	if (! skip_whitespace(&command))
-		return;
-
-	if (word_comp(command, "main_count"))
-		handle_uint32_command(&command, &output->main_count, "main_count");
-	else if (word_comp(command, "view_padding"))
-		handle_uint32_command(&command, &output->view_padding, "view_padding");
-	else if (word_comp(command, "outer_padding"))
-		handle_uint32_command(&command, &output->outer_padding, "outer_padding");
-	else if (word_comp(command, "main_ratio"))
-		handle_float_command(&command, &output->main_ratio, "main_ratio", 0.1, 0.9);
-	else if (word_comp(command, "reset"))
-	{
-		/* This is an example of a command that does something different
-		 * than just modifying a value. It resets all values to their
-		 * defaults.
-		 */
-
-		if ( skip_nonwhitespace(&command) && skip_whitespace(&command) )
-		{
-			fputs("ERROR: Too many arguments. 'reset' has no arguments.\n", stderr);
-			return;
-		}
-
-		output->main_count    = 1;
-		output->main_ratio    = 0.6;
-		output->view_padding  = 5;
-		output->outer_padding = 5;
-	}
-	else
-		fprintf(stderr, "ERROR: Unknown command: %s\n", command);
-}
-
-static const struct river_layout_v3_listener layout_listener = {
-	.namespace_in_use = layout_handle_namespace_in_use,
-	.layout_demand    = layout_handle_layout_demand,
-	.user_command     = layout_handle_user_command,
-};
-
-static void configure_output (struct Output *output)
-{
-	output->configured = true;
-
-	/* The namespace of the layout is how the compositor chooses what layout
-	 * to use. It can be any arbitrary string. It should describe roughly
-	 * what kind of layout your client will create, so here we use "tile".
-	 */
-	output->layout = river_layout_manager_v3_get_layout(layout_manager,
-			output->output, "tile");
-	river_layout_v3_add_listener(output->layout, &layout_listener, output);
-}
-
-static bool create_output (struct wl_output *wl_output)
-{
-	struct Output *output = calloc(1, sizeof(struct Output));
-	if ( output == NULL )
-	{
-		fputs("Failed to allocate.\n", stderr);
-		return false;
-	}
-
-	output->output     = wl_output;
-	output->layout     = NULL;
-	output->configured = false;
-
-	/* These are the parameters of our layout. In this case, they are the
-	 * ones you'd typically expect from a dynamic tiling layout, but if you
-	 * are creative, you can do more. You can use any arbitrary amount of
-	 * all kinds of values in your layout. If the user wants to change a
-	 * value, the server lets us know using user_command event of the
-	 * river_layout object.
-	 *
-	 * A layout generator is responsible for having sane defaults for all
-	 * layout values. The server only sends user_command events when there
-	 * actually is a command the user wants to send us.
-	 */
-	output->main_count    = 1;
-	output->main_ratio    = 0.6;
-	output->view_padding  = 5;
-	output->outer_padding = 5;
-
-	/* If we already have the river_layout_manager, we can get a
-	 * river_layout object for this output.
-	 */
-	if ( layout_manager != NULL )
-		configure_output(output);
-
-	wl_list_insert(&outputs, &output->link);
-	return true;
-}
-
-static void destroy_output (struct Output *output)
-{
-	if ( output->layout != NULL )
-		river_layout_v3_destroy(output->layout);
-	wl_output_destroy(output->output);
-	wl_list_remove(&output->link);
-	free(output);
-}
-
-static void destroy_all_outputs ()
-{
-	struct Output *output, *tmp;
-	wl_list_for_each_safe(output, tmp, &outputs, link)
-		destroy_output(output);
-}
-
-static void registry_handle_global (void *data, struct wl_registry *registry,
-		uint32_t name, const char *interface, uint32_t version)
-{
-	if ( strcmp(interface, river_layout_manager_v3_interface.name) == 0 )
-		layout_manager = wl_registry_bind(registry, name,
-				&river_layout_manager_v3_interface, 1);
-	else if ( strcmp(interface, wl_output_interface.name) == 0 )
-	{
-		struct wl_output *wl_output = wl_registry_bind(registry, name,
-				&wl_output_interface, version);
-		if (! create_output(wl_output))
-		{
-			loop = false;
-			ret = EXIT_FAILURE;
-		}
-	}
-}
-
-/* A no-op function we plug into listeners when we don't want to handle an event. */
-static void noop () {}
-
-static const struct wl_registry_listener registry_listener = {
-	.global        = registry_handle_global,
-	.global_remove = noop
-};
-
-static void sync_handle_done (void *data, struct wl_callback *wl_callback,
-		uint32_t irrelevant)
-{
-	wl_callback_destroy(wl_callback);
-	sync_callback = NULL;
-
-	/* When this function is called, the registry finished advertising all
-	 * available globals. Let's check if we have everything we need.
-	 */
-	if ( layout_manager == NULL )
-	{
-		fputs("Wayland compositor does not support river-layout-v3.\n", stderr);
-		ret = EXIT_FAILURE;
-		loop = false;
-		return;
-	}
-
-	/* If outputs were registered before the river_layout_manager is
-	 * available, they won't have a river_layout, so we need to create those
-	 * here.
-	 */
-	struct Output *output;
-	wl_list_for_each(output, &outputs, link)
-		if (! output->configured)
-			configure_output(output);
-}
-
-static const struct wl_callback_listener sync_callback_listener = {
-	.done = sync_handle_done,
-};
-
-static bool init_wayland (void)
-{
-	/* We query the display name here instead of letting wl_display_connect()
-	 * figure it out itself, because libwayland (for legacy reasons) falls
-	 * back to using "wayland-0" when $WAYLAND_DISPLAY is not set, which is
-	 * generally not desirable.
-	 */
-	const char *display_name = getenv("WAYLAND_DISPLAY");
-	if ( display_name == NULL )
-	{
-		fputs("WAYLAND_DISPLAY is not set.\n", stderr);
-		return false;
-	}
-
-	wl_display = wl_display_connect(display_name);
-	if ( wl_display == NULL )
-	{
-		fputs("Can not connect to Wayland server.\n", stderr);
-		return false;
-	}
-
-	wl_list_init(&outputs);
-
-	/* The registry is a global object which is used to advertise all
-	 * available global objects.
-	 */
-	wl_registry = wl_display_get_registry(wl_display);
-	wl_registry_add_listener(wl_registry, &registry_listener, NULL);
-
-	/* The sync callback we attach here will be called when all previous
-	 * requests have been handled by the server. This allows us to know the
-	 * end of the startup, at which point all necessary globals should be
-	 * bound.
-	 */
-	sync_callback = wl_display_sync(wl_display);
-	wl_callback_add_listener(sync_callback, &sync_callback_listener, NULL);
-
-	return true;
-}
-
-static void finish_wayland (void)
-{
-	if ( wl_display == NULL )
-		return;
-
-	destroy_all_outputs();
-
-	if ( sync_callback != NULL )
-		wl_callback_destroy(sync_callback);
-	if ( layout_manager != NULL )
-		river_layout_manager_v3_destroy(layout_manager);
-
-	wl_registry_destroy(wl_registry);
-	wl_display_disconnect(wl_display);
-}
-
-int main (int argc, char *argv[])
-{
-	if (init_wayland())
-	{
-		ret = EXIT_SUCCESS;
-		while ( loop && wl_display_dispatch(wl_display) != -1 );
-	}
-	finish_wayland();
-	return ret;
-}
diff --git a/contrib/layout.py b/contrib/layout.py
deleted file mode 100755
index 5313449..0000000
--- a/contrib/layout.py
+++ /dev/null
@@ -1,146 +0,0 @@
-#!/usr/bin/env python3
-#
-# Fibonacci spiral layout for river, implemented in simple python. Reading this
-# code should help you get a basic understanding of how to use river-layout to
-# create a basic layout generator.
-#
-# This depends on pywayland: https://github.com/flacjacket/pywayland/
-#
-# Q: Wow, this looks complicated!
-# A: For simple layouts, you really only need to care about what's in the
-#    layout_handle_layout_demand() function. And the rest isn't as complicated
-#    as it looks.
-#
-# Q: The script runs but nothing happens! How can I see this layout?
-# A: Once started, to set this layout as default use the command:
-#    riverctl default-layout layout.py
-
-import mmap
-import time
-from pywayland.client import Display
-from pywayland.protocol.wayland import WlOutput
-try:
-    from pywayland.protocol.river_layout_v3 import RiverLayoutManagerV3
-except:
-    river_layout_help = """
-    Your pywayland package does not have bindings for river-layout-v3.
-    You can generate the bindings with the following command:
-         python3 -m pywayland.scanner -i /usr/share/wayland/wayland.xml river-layout-v3.xml
-    It is recommended to use a virtual environment to avoid modifying your
-    system-wide python installation, See: https://docs.python.org/3/library/venv.html
-    """
-    print(river_layout_help)
-    quit()
-
-layout_manager = None
-outputs = []
-loop = True
-
-def layout_handle_layout_demand(layout, view_count, usable_w, usable_h, tags, serial):
-    x = 0
-    y = 0
-    w = usable_w
-    h = usable_h
-    for i in range(0, view_count - 1):
-        if i % 2 == 0:
-            w //= 2
-            if i % 4 == 2:
-                layout.push_view_dimensions(x + w, y, w, h, serial)
-            else:
-                layout.push_view_dimensions(x, y, w, h, serial)
-                x += w
-        else:
-            h //= 2
-            if i % 4 == 3:
-                layout.push_view_dimensions(x, y + h, w, h, serial)
-            else:
-                layout.push_view_dimensions(x, y, w, h, serial)
-                y += h
-    layout.push_view_dimensions(x, y, w, h, serial)
-
-    # Committing the layout means telling the server that your code is done
-    # laying out windows. Make sure you have pushed exactly the right amount of
-    # view dimensions, a mismatch is a fatal protocol error.
-    #
-    # You also have to provide a layout name. This is a user facing string that
-    # the server can forward to status bars. You can use it to tell the user
-    # which layout is currently in use. You could also add some status
-    # information status information about your layout, which is what we do here.
-    layout.commit(f"{view_count} windows laid out by python", serial)
-
-def layout_handle_namespace_in_use(layout):
-    # Oh no, the namespace we choose is already used by another client! All we
-    # can do now is destroy the layout object. Because we are lazy, we just
-    # abort and let our cleanup mechanism destroy it. A more sophisticated
-    # client could instead destroy only the one single affected layout object
-    # and recover from this mishap. Writing such a client is left as an exercise
-    # for the reader.
-    print("Namespace already in use!")
-    global loop
-    loop = False
-
-class Output(object):
-    def __init__(self):
-        self.output = None
-        self.layout = None
-        self.id = None
-
-    def destroy(self):
-        if self.layout is not None:
-            self.layout.destroy()
-        if self.output is not None:
-            self.output.destroy()
-
-    def configure(self):
-        global layout_manager
-        if self.layout is None and layout_manager is not None:
-            # We need to set a namespace, which is used to identify our layout.
-            self.layout = layout_manager.get_layout(self.output, "layout.py")
-            self.layout.user_data = self
-            self.layout.dispatcher["layout_demand"] = layout_handle_layout_demand
-            self.layout.dispatcher["namespace_in_use"] = layout_handle_namespace_in_use
-
-def registry_handle_global(registry, id, interface, version):
-    global layout_manager
-    global output
-    if interface == 'river_layout_manager_v3':
-        layout_manager = registry.bind(id, RiverLayoutManagerV3, version)
-    elif interface == 'wl_output':
-        output = Output()
-        output.output = registry.bind(id, WlOutput, version)
-        output.id = id
-        output.configure()
-        outputs.append(output)
-
-def registry_handle_global_remove(registry, id):
-    for output in outputs:
-        if output.id == id:
-            output.destroy()
-            outputs.remove(output)
-
-display = Display()
-display.connect()
-
-registry = display.get_registry()
-registry.dispatcher["global"] = registry_handle_global
-registry.dispatcher["global_remove"] = registry_handle_global_remove
-
-display.dispatch(block=True)
-display.roundtrip()
-
-if layout_manager is None:
-    print("No layout_manager, aborting")
-    quit()
-
-for output in outputs:
-    output.configure()
-
-while loop and display.dispatch(block=True) != -1:
-    pass
-
-# Destroy outputs
-for output in outputs:
-    output.destroy()
-    outputs.remove(output)
-
-display.disconnect()
diff --git a/doc/riverctl.1.scd b/doc/riverctl.1.scd
deleted file mode 100644
index 01b05a1..0000000
--- a/doc/riverctl.1.scd
+++ /dev/null
@@ -1,562 +0,0 @@
-RIVERCTL(1)
-
-# NAME
-
-riverctl - command-line interface for controlling river
-
-# SYNOPSIS
-
-*riverctl* [_options_] _command_ [_command specific arguments_]
-
-# DESCRIPTION
-
-*riverctl* is a command-line utility used to control and configure river
-over the Wayland protocol.
-
-# OPTIONS
-
-*-h*
-	Print a help message and exit.
-
-*-version*
-	Print the version number and exit.
-
-# TERMINOLOGY
-
-This manual uses terms that some may find confusing, coming mostly from their
-usage among other Wayland projects.
-
-The *compositor*, display server, Wayland server etc. are ways to refer to river
-itself.
-
-A *view* (or *toplevel*) is what most call a window.
-
-An *output* is a synonym for a screen or monitor.
-
-*Tags* are river's way of dividing views of an output into groups (not
-necessarily disjunct), an analogy to workspaces.
-
-# COMMANDS
-
-## ACTIONS
-
-*close*
-	Close the focused view.
-
-*exit*
-	Exit the compositor, terminating the Wayland session.
-
-*focus-output* *next*|*previous*|*up*|*right*|*down*|*left*|_name_
-	Focus the next or previous output, the closest output in any direction
-	or an output by name.
-
-*focus-view* [*-skip-floating*] *next*|*previous*|*up*|*down*|*left*|*right*
-	Focus the next or previous view in the stack or the closest view in
-	any direction.
-
-	- *-skip-floating*: Skip floating views, only focusing tiled ones.
-
-*move* *up*|*down*|*left*|*right* _delta_
-	Move the focused view in the specified direction by _delta_ logical
-	pixels. The view will be set to floating.
-
-*resize* *horizontal*|*vertical* _delta_
-	Resize the focused view along the given axis by _delta_ logical
-	pixels. The view will be set to floating.
-
-*snap* *up*|*down*|*left*|*right*
-	Snap the focused view to the specified screen edge. The view will
-	be set to floating.
-
-*send-to-output* [*-current-tags*] *next*|*previous*|*up*|*right*|*down*|*left*|_name_
-	Send the focused view to the next or previous output, the closest
-	output in any direction or to an output by name.
-
-	- *-current-tags*: Assign the currently focused tags of the destination
-	  output to the view.
-
-*spawn* _shell_command_
-	Run _shell_command_ using `/bin/sh -c _shell_command_`. Note that
-	*spawn* only takes a single argument. To spawn a command taking
-	multiple arguments, wrapping the command in quotes is recommended.
-
-*swap* *next*|*previous*|*up*|*down*|*left*|*right*
-	Swap the focused view with the next or previous non-floating view in the
-	stack or the closest non-floating view in any direction.
-
-*toggle-float*
-	Toggle the floating state of the focused view.
-
-*toggle-fullscreen*
-	Toggle the fullscreen state of the focused view.
-
-*zoom*
-	Bump the focused view to the top of the layout stack. If the top
-	view in the stack is already focused, bump the second view.
-
-*default-layout* _namespace_
-	Set the layout namespace to be used by all outputs by default.
-
-*output-layout* _namespace_
-	Set the layout namespace of currently focused output, overriding
-	the value set with *default-layout* if any.
-
-*send-layout-cmd* _namespace_ _command_
-	Send _command_ to the layout generator on the currently focused output
-	with the given _namespace_, if any. What commands a layout generator
-	understands depends on the layout generator. For rivertile, see the
-	documentation in the *rivertile*(1) man page.
-
-## TAG MANAGEMENT
-
-Tags are similar to workspaces but more flexible. You can assign views multiple
-tags and focus multiple tags simultaneously. Bitfields are used to describe
-sets of tags when interfacing with river. As such, the following commands
-take a normal base 10 number as their argument but the semantics are best
-understood in binary. The binary number 000000001 represents a set containing
-only tag 1 while 100001101 represents a set containing tags 1, 3, 4, and 9.
-
-When a view spawns it is assigned the currently focused tags of the output.
-
-At least one tag must always be focused and each view must be assigned at
-least one tag. Operations that would violate either of these requirements
-are ignored by river.
-
-*set-focused-tags* _tags_
-	Show views with tags corresponding to the set bits of _tags_ on the
-	currently focused output.
-
-*set-view-tags* _tags_
-	Assign the currently focused view the tags corresponding to the set
-	bits of _tags_.
-
-*toggle-focused-tags* _tags_
-	Toggle visibility of views with tags corresponding to the set bits
-	of _tags_ on the currently focused output.
-
-*toggle-view-tags* _tags_
-	Toggle the tags of the currently focused view corresponding to the
-	set bits of _tags_.
-
-*spawn-tagmask* _tagmask_
-	Set a _tagmask_ to filter the tags assigned to newly spawned views. This mask
-	will be applied to the tags of new views with a bitwise and. If, for example,
-	the tags 000011111 are focused and the spawn _tagmask_ is 111110001, a
-	new view will be assigned the tags 000010001. If no tags would remain after
-	filtering, the _tagmask_ is ignored.
-
-*focus-previous-tags*
-	Sets tags to their previous value on the currently focused output,
-	allowing jumping back and forth between 2 tag setups.
-
-*send-to-previous-tags*
-	Assign the currently focused view the previous tags of the currently
-	focused output.
-
-## MAPPINGS
-
-Mappings are modal in river. Each mapping is associated with a mode and
-is only active while in that mode. There are two special modes: "normal"
-and "locked". The normal mode is the initial mode on startup. The locked
-mode is automatically entered while the session is locked (e.g. due to
-a screenlocker). It cannot be entered or exited manually.
-
-The following modifiers are available for use in mappings:
-
-	- Shift
-	- Control
-	- Mod1 (Alt)
-	- Mod3
-	- Mod4 (Super)
-	- Mod5
-	- None
-
-Alt and Super are aliases for Mod1 and Mod4 respectively. None allows creating
-a mapping without modifiers.
-
-Keys are specified by their XKB keysym name. See
-_/usr/include/xkbcommon/xkbcommon-keysyms.h_ for the complete list.
-
-Mouse buttons are specified by Linux input event code names. The most commonly
-used values are:
-
-	- BTN_LEFT - left mouse button
-	- BTN_RIGHT - right mouse button
-	- BTN_MIDDLE - middle mouse button
-
-A complete list may be found in _/usr/include/linux/input-event-codes.h_
-
-*declare-mode* _name_
-	Create a new mode called _name_.
-
-*enter-mode* _name_
-	Switch to given mode if it exists.
-
-*map* [*-release*|*-repeat*|*-layout* _index_] _mode_ _modifiers_ _key_ _command_
-	Run _command_ when _key_ is pressed while _modifiers_ are held down
-	and in the specified _mode_.
-
-	- *-release*: if passed activate on key release instead of key press
-	- *-repeat*: if passed activate repeatedly until key release; may not
-	  be used with *-release*
-	- *-layout*: if passed, a specific layout is pinned to the mapping.
-	  When the mapping is checked against a pressed key, this layout is
-	  used to translate the key independent of the active layout
-		- _index_: zero-based index of a layout set with the *keyboard-layout*
-		  command. If the index is out of range, the *-layout* option will
-		  have no effect
-	- _mode_: name of the mode for which to create the mapping
-	- _modifiers_: one or more of the modifiers listed above, separated
-	  by a plus sign (+).
-	- _key_: an XKB keysym name as described above
-	- _command_: any command that may be run with riverctl
-
-*map-pointer* _mode_ _modifiers_ _button_ _action_|_command_
-	Move or resize views or run _command_ when _button_ and _modifiers_ are held
-	down while in the specified _mode_. The view under the cursor will be
-	focused.
-
-	- _mode_: name of the mode for which to create the mapping
-	- _modifiers_: one or more of the modifiers listed above, separated
-	  by a plus sign (+).
-	- _button_: the name of a Linux input event code as described above
-	- _action_: one of the following values:
-		- move-view
-		- resize-view
-	- _command_: any command that may be run with riverctl
-
-*map-switch* _mode_ *lid*|*tablet* _state_ _command_
-	Run _command_ when river receives a certain switch event.
-
-	- _mode_: name of the mode for which to create the mapping
-	- _lid_|_tablet_: 'lid switch' and 'tablet mode switch' are supported
-	- _state_:
-		- possible states for _lid_:
-			- close
-			- open
-		- possible states for _tablet_:
-			- on
-			- off
-	- _command_: any command that may be run with riverctl
-
-*unmap* [*-release*] _mode_ _modifiers_ _key_
-	Remove the mapping defined by the arguments:
-
-	- *-release*: if passed unmap the key release instead of the key press
-	- _mode_: name of the mode for which to remove the mapping
-	- _modifiers_: one or more of the modifiers listed above, separated
-	  by a plus sign (+).
-	- _key_: an XKB keysym name as described above
-
-*unmap-pointer* _mode_ _modifiers_ _button_
-	Remove the pointer mapping defined by the arguments:
-
-	- _mode_: name of the mode for which to remove the mapping
-	- _modifiers_: one or more of the modifiers listed above, separated
-	  by a plus sign (+).
-	- _button_: the name of a Linux input event code as described above
-
-*unmap-switch* _mode_ *lid*|*tablet* _state_
-	Remove the switch mapping defined by the arguments:
-
-	- _mode_: name of the mode for which to remove the mapping
-	- _lid_|_tablet_: the switch for which to remove the mapping
-	- _state_: a state as listed above
-
-## RULES
-
-Rules match the app-id and title of views against a _glob_ pattern.  A _glob_
-is a string that may optionally have an _\*_ at the beginning and/or end. An
-_\*_ in a _glob_ matches zero or more arbitrary characters in the app-id
-or title.
-
-For example, _abc_ is matched by _a\*_, _\*a\*_, _\*b\*_, _\*c_, _abc_, and
-_\*_ but not matched by _\*a_, _b\*_, _\*b_, _c\*_, or _ab_. Note that _\*_
-matches everything while _\*\*_ and the empty string are invalid.
-
-*rule-add* [*-app-id* _glob_|*-title* _glob_] _action_ [_arguments_]
-	Add a rule that applies an _action_ to views with *app-id* and *title*
-	matched by the respective _glob_. Omitting *-app-id* or *-title*
-	is equivalent to passing *-app-id* _\*_ or *-title* _\*_.
-	Some actions require one or more _arguments_.
-
-	The supported _action_ types are:
-
-	- *float*: Make the view floating. Applies only to new views.
-	- *no-float*: Don't make the view floating. Applies only to
-	  new views.
-	- *ssd*: Use server-side decorations for the view. Applies to new
-	  and existing views.
-	- *csd*: Use client-side decorations for the view. Applies to new
-	  and existing views.
-	- *tags*: Set the initial tags of the view. Requires the tags as
-	  an argument. Applies only to new views.
-	- *output*: Set the initial output of the view. Requires the output
-	  as an argument. Applies only to new views. The output can be specified
-	  either by connector name (such as _HDMI-A-1_, or _DP-2_), or by
-	  identifier in the form of _MAKE MODEL SERIAL_, for example for an output
-	  with make: _HP Inc._, model: _HP 22w_, and serial: _CNC93720WF_, the
-	  identifier would be: _HP Inc. HP 22w CNC93720WF_. If the make, model, or
-	  serial is unknown, the word "Unknown" is used instead.
-	- *position*: Set the initial position of the view, clamping to the
-	  bounds of the output. Requires x and y coordinates of the view as
-	  arguments, both of which must be non-negative. Applies only to new views.
-	- *dimensions*: Set the initial dimensions of the view, clamping to the
-	  constraints of the view. Requires width and height of the view as
-	  arguments, both of which must be non-negative. Applies only to new views.
-	- *fullscreen*: Make the view fullscreen. Applies only to new views.
-	- *no-fullscreen*: Don't make the view fullscreen. Applies only to
-	  new views.
-
-	Both *float* and *no-float* rules are added to the same list,
-	which means that adding a *no-float* rule with the same arguments
-	as a *float* rule will overwrite it. The same holds for *ssd* and
-	*csd*, *fullscreen* and *no-fullscreen* rules.
-
-	If multiple rules in a list match a given view the most specific
-	rule will be applied. For example with the following rules
-	```
-	app-id  title  action
-	foo     bar    ssd
-	foo     *      csd
-	*       bar    csd
-	*       baz    ssd
-	```
-	a view with app-id 'foo' and title 'bar' would get ssd despite matching
-	two csd rules as the first rule is most specific. Furthermore a view
-	with app-id 'foo' and title 'baz' would get csd despite matching the
-	last rule in the list since app-id specificity takes priority over
-	title specificity.
-
-	If a view is not matched by any rule, river will respect the csd/ssd
-	wishes of the client and may start the view floating based on simple
-	heuristics intended to catch popup-like views.
-
-	If a view is started fullscreen or is not floating, then *position* and
-	*dimensions* rules will have no effect  A view must be matched by a *float*
-	rule in order for them to take effect.
-
-*rule-del* [*-app-id* _glob_|*-title* _glob_] _action_
-	Delete a rule created using *rule-add* with the given arguments.
-
-*list-rules* *float*|*ssd*|*tags*|*position*|*dimensions*|*fullscreen*
-	Print the specified rule list. The output is ordered from most specific
-	to least specific, the same order in which views are checked against
-	when searching for a match. Only the first matching rule in the list
-	has an effect on a given view.
-
-## CONFIGURATION
-
-*default-attach-mode* *top*|*bottom*|*above*|*below*|*after <N>*
-	Set the attach mode to be used by all outputs by default.
-
-	Possible values:
-	- top: Prepends the newly spawned view at the top of the stack.
-	- bottom: Appends the newly spawned view at the bottom of the stack.
-	- above: Inserts the newly spawned view above the currently focused view.
-	- below: Inserts the newly spawned view below the currently focused view.
-	- after <N>: Inserts the newly spawned view after N views in the stack.
-
-	Note that the deprecated *attach-mode* command is aliased to
-	*default-attach-mode* for backwards compatibility.
-
-*output-attach-mode* *top*|*bottom*|*above*|*below*|*after <N>*
-	Set the attach mode of the currently focused output, overriding the value of
-	default-attach-mode if any.
-
-*background-color* _0xRRGGBB_|_0xRRGGBBAA_
-	Set the background color.
-
-*border-color-focused* _0xRRGGBB_|_0xRRGGBBAA_
-	Set the border color of focused views.
-
-*border-color-unfocused* _0xRRGGBB_|_0xRRGGBBAA_
-	Set the border color of unfocused views.
-
-*border-color-urgent* _0xRRGGBB_|_0xRRGGBBAA_
-	Set the border color of urgent views.
-
-*border-width* _pixels_
-	Set the border width to _pixels_.
-
-*focus-follows-cursor* *disabled*|*normal*|*always*
-	There are three available modes:
-
-	- _disabled_: Moving the cursor does not affect focus. This is
-	  the default.
-	- _normal_: Moving the cursor over a view will focus that view.
-	  Moving the cursor within a view will not re-focus that view if
-	  focus has moved elsewhere.
-	- _always_: Moving the cursor will always focus whatever view is
-	  under the cursor.
-
-	If the view to be focused is on an output that does not have focus,
-	focus is switched to that output.
-
-*hide-cursor* *timeout* _timeout_
-	Hide the cursor if it wasn't moved in the last _timeout_ milliseconds
-	until it is moved again. The default value is 0, which disables
-	automatically hiding the cursor. Show the cursor again on any movement.
-
-*hide-cursor* *when-typing* *enabled*|*disabled*
-	Hide the cursor when pressing any non-modifier key. Show the cursor
-	again on any movement.
-
-*set-cursor-warp* *disabled*|*on-output-change*|*on-focus-change*
-	Set the cursor warp mode. There are two available modes:
-
-	- _disabled_: Cursor will not be warped. This is the default.
-	- _on-output-change_: When a different output is focused, the cursor will be
-	  warped to its center.
-	- _on-focus-change_: When a different view/output is focused, the cursor will be
-	  warped to its center.
-
-*set-repeat* _rate_ _delay_
-	Set the keyboard repeat rate to _rate_ key repeats per second and
-	repeat delay to _delay_ milliseconds.
-
-*xcursor-theme* _theme_name_ [_size_]
-	Set the xcursor theme to _theme_name_ and optionally set the _size_.
-	The theme of the default seat determines the default for Xwayland
-	and is made available through the _XCURSOR_THEME_ and _XCURSOR_SIZE_
-	environment variables.
-
-## INPUT CONFIGURATION
-
-*list-inputs*
-	List all input devices.
-
-*list-input-configs*
-	List all input configurations.
-
-*keyboard-layout* [-rules _rules_] [-model _model_] [-variant _variant_] \
-[-options _options_] _layout_
-	Set the XKB layout for all keyboards. Defaults from libxkbcommon are used for
-	everything left unspecified. Note that _layout_ may be a comma separated list
-	of layouts (e.g. "us,de") which may be switched between using various key
-	combinations configured through the options argument (e.g. -options
-	"grp:ctrl_space_toggle"). See *xkeyboard-config*(7) for possible values and
-	more information.
-
-*keyboard-layout-file* _path_
-	Set the XKB layout for all keyboards from an XKB keymap file at the provided
-	path. Documentation for the XKB keymap file format can be found at the
-	following URL:
-	https://xkbcommon.org/doc/current/keymap-text-format-v1.html
-
-*keyboard-group-create* _group_name_
-	Create a keyboard group. A keyboard group collects multiple keyboards in
-	a single logical keyboard. This means that all state, like the active
-	modifiers, is shared between the keyboards in a group.
-
-*keyboard-group-destroy* _group_name_
-	Destroy the keyboard group with the given name. All attached keyboards
-	will be released, making them act as separate devices again.
-
-*keyboard-group-add* _group_name_ _input_device_name_
-	Add a keyboard to a keyboard group, identified by the keyboard's
-	input device name. Any currently connected and future keyboards with
-	the given name will be added to the group. Simple globbing patterns are
-	supported, see the rules section for further information on globs.
-
-*keyboard-group-remove* _group_name_ _input_device_name_
-	Remove a keyboard from a keyboard group, identified by the keyboard's
-	input device name.
-
-The _input_ command can be used to create a configuration rule for an input
-device identified by its _name_.
-The _name_ of an input device consists of its type, its numerical vendor id,
-its numerical product id and finally its self-advertised name, separated by -.
-Simple globbing patterns are supported, see the rules section for further
-information on globs.
-
-A list of all device properties that can be configured may be found below.
-However note that not every input device supports every property.
-
-*input* _name_ *events* *enabled*|*disabled*|*disabled-on-external-mouse*
-	Configure whether the input devices events will be used by river.
-
-*input* _name_ *accel-profile* *none*|*flat*|*adaptive*
-	Set the pointer acceleration profile of the input device.
-
-*input* _name_ *pointer-accel* _factor_
-	Set the pointer acceleration factor of the input device. Needs a float
-	between -1.0 and 1.0.
-
-*input* _name_ *click-method* *none*|*button-areas*|*clickfinger*
-	Set the click method of the input device.
-
-*input* _name_ *drag* *enabled*|*disabled*
-	Enable or disable the tap-and-drag functionality of the input device.
-
-*input* _name_ *drag-lock* *enabled*|*disabled*
-	Enable or disable the drag lock functionality of the input device.
-
-*input* _name_ *disable-while-typing* *enabled*|*disabled*
-	Enable or disable the disable-while-typing functionality of the input device.
-
-*input* _name_ *disable-while-trackpointing* *enabled*|*disabled*
-	Enable or disable the disable-while-trackpointing functionality of the input device.
-
-*input* _name_ *middle-emulation* *enabled*|*disabled*
-	Enable or disable the middle click emulation functionality of the input device.
-
-*input* _name_ *natural-scroll* *enabled*|*disabled*
-	Enable or disable the natural scroll functionality of the input device. If
-	active, the scroll direction is inverted.
-
-*input* _name_ *scroll-factor* _factor_
-	Set the scroll factor of the input device. Accepts a postive value
-	greater than 0. For example, a _factor_ of 0.5 will make scrolling twice
-	as slow while a _factor_ of 3 will make scrolling 3 times as fast.
-
-*input* _name_ *left-handed* *enabled*|*disabled*
-	Enable or disable the left handed mode of the input device.
-
-*input* _name_ *tap* *enabled*|*disabled*
-	Enable or disable the tap functionality of the input device.
-
-*input* _name_ *tap-button-map* *left-right-middle*|*left-middle-right*
-	Configure the button mapping for tapping.
-
-	- _left-right-middle_: 1 finger tap equals left click, 2 finger tap equals
-	  right click, 3 finger tap equals middle click.
-	- _left-middle-right_: 1 finger tap equals left click, 2 finger tap equals
-	  middle click, 3 finger tap equals right click.
-
-*input* _name_ *scroll-method* *none*|*two-finger*|*edge*|*button*
-	Set the scroll method of the input device.
-
-	- _none_: No scrolling
-	- _two-finger_: Scroll by swiping with two fingers simultaneously
-	- _edge_: Scroll by swiping along the edge
-	- _button_: Scroll with pointer movement while holding down a button
-
-*input* _name_ *scroll-button* _button_
-	Set the scroll button of an input device. _button_ is the name of a Linux
-	input event code.
-
-*input* _name_ *map-to-output* _output_|*disabled*
-	Maps the input to a given output. This is valid even if the output isn't
-	currently active and will lead to the device being mapped once it is
-	connected.
-
-# EXAMPLES
-
-Bind Super+Return in normal mode to spawn a *foot*(1) terminal:
-
-	riverctl map normal Mod4 Return spawn 'foot --app-id=foobar'
-
-Bind Super+Shift+J to swap the focused view with the next visible view:
-
-	riverctl map normal Mod4+Shift J swap next
-
-# AUTHORS
-
-Maintained by Isaac Freund <[email protected]> who is assisted by open
-source contributors. For more information about river's development, see
-<https://isaacfreund.com/software/river>.
-
-# SEE ALSO
-
-*river*(1), *rivertile*(1)
diff --git a/doc/rivertile.1.scd b/doc/rivertile.1.scd
deleted file mode 100644
index a73ebde..0000000
--- a/doc/rivertile.1.scd
+++ /dev/null
@@ -1,88 +0,0 @@
-RIVERTILE(1)
-
-# NAME
-
-rivertile - tiled layout generator for river
-
-# SYNOPSIS
-
-*rivertile* [_options_]
-
-# DESCRIPTION
-
-*rivertile* is a layout generator for *river*(1). It provides a simple tiled
-layout with split main/secondary stacks. The initial state may be configured
-with various options passed on startup. Some values may additionally be
-modified while rivertile is running with the help of *riverctl*(1).
-
-# OPTIONS
-
-*-h*
-	Print a help message and exit.
-
-*-version*
-	Print the version number and exit.
-
-*-view-padding* _pixels_
-	Set the padding around views in pixels. (Default: 6)
-
-*-outer-padding* _pixels_
-	Set the padding around the edge of the layout area in pixels.
-	(Default: 6)
-
-*-main-location* [*top*|*bottom*|*left*|*right*]
-	Set the initial location of the main area in the layout.
-	(Default: *left*)
-
-*-main-count* _count_
-	Set the initial number of views in the main area of the
-	layout. (Default: 1)
-
-*-main-ratio* _ratio_
-	Set the initial ratio of the main area to total layout area. The
-	_ratio_ must be between 0.1 and 0.9, inclusive. (Default: 0.6)
-
-# COMMANDS
-
-These commands may be sent to rivertile at runtime with the help of
-*riverctl*(1).
-
-*main-location* [*top*|*bottom*|*left*|*right*]
-	Set the location of the main area in the layout.
-
-*main-count* _value_
-	Set or modify the number of views in the main area of the layout. If
-	_value_ is prefixed by a +/- sign, _value_ is added/subtracted from the
-	current count. If there is no sign, the main count is set to _value_.
-	Note that the main count cannot be decreased below 1.
-
-*main-ratio* _value_
-	Set or modify the ratio of the main area to total layout area. If
-	_value_ is prefixed by a +/- sign, _value_ is added/subtracted from
-	the current ratio. If there is no sign, the main ratio is set to
-	_value_. Note that the ratio will always be clamped to the range
-	0.1 to 0.9.
-
-# EXAMPLES
-
-Start *rivertile* with 4 pixels outer padding and the *top* main location:
-
-	rivertile -outer-padding 4 -main-location top
-
-Increase the main ratio by 0.1 at runtime:
-
-	riverctl send-layout-cmd rivertile "main-ratio +0.1"
-
-Set the main count to 3 at runtime:
-
-	riverctl send-layout-cmd rivertile "main-count 3"
-
-# AUTHORS
-
-Maintained by Isaac Freund <[email protected]> who is assisted by open
-source contributors. For more information about river's development, see
-<https://isaacfreund.com/software/river>.
-
-# SEE ALSO
-
-*river*(1), *riverctl*(1)
diff --git a/example/init b/example/init
deleted file mode 100755
index 06595b5..0000000
--- a/example/init
+++ /dev/null
@@ -1,162 +0,0 @@
-#!/bin/sh
-
-# This is the example configuration file for river.
-#
-# If you wish to edit this, you will probably want to copy it to
-# $XDG_CONFIG_HOME/river/init or $HOME/.config/river/init first.
-#
-# See the river(1), riverctl(1), and rivertile(1) man pages for complete
-# documentation.
-
-# Note: the "Super" modifier is also known as Logo, GUI, Windows, Mod4, etc.
-
-# Super+Shift+Return to start an instance of foot (https://codeberg.org/dnkl/foot)
-riverctl map normal Super+Shift Return spawn foot
-
-# Super+Q to close the focused view
-riverctl map normal Super Q close
-
-# Super+Shift+E to exit river
-riverctl map normal Super+Shift E exit
-
-# Super+J and Super+K to focus the next/previous view in the layout stack
-riverctl map normal Super J focus-view next
-riverctl map normal Super K focus-view previous
-
-# Super+Shift+J and Super+Shift+K to swap the focused view with the next/previous
-# view in the layout stack
-riverctl map normal Super+Shift J swap next
-riverctl map normal Super+Shift K swap previous
-
-# Super+Period and Super+Comma to focus the next/previous output
-riverctl map normal Super Period focus-output next
-riverctl map normal Super Comma focus-output previous
-
-# Super+Shift+{Period,Comma} to send the focused view to the next/previous output
-riverctl map normal Super+Shift Period send-to-output next
-riverctl map normal Super+Shift Comma send-to-output previous
-
-# Super+Return to bump the focused view to the top of the layout stack
-riverctl map normal Super Return zoom
-
-# Super+H and Super+L to decrease/increase the main ratio of rivertile(1)
-riverctl map normal Super H send-layout-cmd rivertile "main-ratio -0.05"
-riverctl map normal Super L send-layout-cmd rivertile "main-ratio +0.05"
-
-# Super+Shift+H and Super+Shift+L to increment/decrement the main count of rivertile(1)
-riverctl map normal Super+Shift H send-layout-cmd rivertile "main-count +1"
-riverctl map normal Super+Shift L send-layout-cmd rivertile "main-count -1"
-
-# Super+Alt+{H,J,K,L} to move views
-riverctl map normal Super+Alt H move left 100
-riverctl map normal Super+Alt J move down 100
-riverctl map normal Super+Alt K move up 100
-riverctl map normal Super+Alt L move right 100
-
-# Super+Alt+Control+{H,J,K,L} to snap views to screen edges
-riverctl map normal Super+Alt+Control H snap left
-riverctl map normal Super+Alt+Control J snap down
-riverctl map normal Super+Alt+Control K snap up
-riverctl map normal Super+Alt+Control L snap right
-
-# Super+Alt+Shift+{H,J,K,L} to resize views
-riverctl map normal Super+Alt+Shift H resize horizontal -100
-riverctl map normal Super+Alt+Shift J resize vertical 100
-riverctl map normal Super+Alt+Shift K resize vertical -100
-riverctl map normal Super+Alt+Shift L resize horizontal 100
-
-# Super + Left Mouse Button to move views
-riverctl map-pointer normal Super BTN_LEFT move-view
-
-# Super + Right Mouse Button to resize views
-riverctl map-pointer normal Super BTN_RIGHT resize-view
-
-# Super + Middle Mouse Button to toggle float
-riverctl map-pointer normal Super BTN_MIDDLE toggle-float
-
-for i in $(seq 1 9)
-do
-    tags=$((1 << ($i - 1)))
-
-    # Super+[1-9] to focus tag [0-8]
-    riverctl map normal Super $i set-focused-tags $tags
-
-    # Super+Shift+[1-9] to tag focused view with tag [0-8]
-    riverctl map normal Super+Shift $i set-view-tags $tags
-
-    # Super+Control+[1-9] to toggle focus of tag [0-8]
-    riverctl map normal Super+Control $i toggle-focused-tags $tags
-
-    # Super+Shift+Control+[1-9] to toggle tag [0-8] of focused view
-    riverctl map normal Super+Shift+Control $i toggle-view-tags $tags
-done
-
-# Super+0 to focus all tags
-# Super+Shift+0 to tag focused view with all tags
-all_tags=$(((1 << 32) - 1))
-riverctl map normal Super 0 set-focused-tags $all_tags
-riverctl map normal Super+Shift 0 set-view-tags $all_tags
-
-# Super+Space to toggle float
-riverctl map normal Super Space toggle-float
-
-# Super+F to toggle fullscreen
-riverctl map normal Super F toggle-fullscreen
-
-# Super+{Up,Right,Down,Left} to change layout orientation
-riverctl map normal Super Up    send-layout-cmd rivertile "main-location top"
-riverctl map normal Super Right send-layout-cmd rivertile "main-location right"
-riverctl map normal Super Down  send-layout-cmd rivertile "main-location bottom"
-riverctl map normal Super Left  send-layout-cmd rivertile "main-location left"
-
-# Declare a passthrough mode. This mode has only a single mapping to return to
-# normal mode. This makes it useful for testing a nested wayland compositor
-riverctl declare-mode passthrough
-
-# Super+F11 to enter passthrough mode
-riverctl map normal Super F11 enter-mode passthrough
-
-# Super+F11 to return to normal mode
-riverctl map passthrough Super F11 enter-mode normal
-
-# Various media key mapping examples for both normal and locked mode which do
-# not have a modifier
-for mode in normal locked
-do
-    # Eject the optical drive (well if you still have one that is)
-    riverctl map $mode None XF86Eject spawn 'eject -T'
-
-    # Control pulse audio volume with pamixer (https://github.com/cdemoulins/pamixer)
-    riverctl map $mode None XF86AudioRaiseVolume  spawn 'pamixer -i 5'
-    riverctl map $mode None XF86AudioLowerVolume  spawn 'pamixer -d 5'
-    riverctl map $mode None XF86AudioMute         spawn 'pamixer --toggle-mute'
-
-    # Control MPRIS aware media players with playerctl (https://github.com/altdesktop/playerctl)
-    riverctl map $mode None XF86AudioMedia spawn 'playerctl play-pause'
-    riverctl map $mode None XF86AudioPlay  spawn 'playerctl play-pause'
-    riverctl map $mode None XF86AudioPrev  spawn 'playerctl previous'
-    riverctl map $mode None XF86AudioNext  spawn 'playerctl next'
-
-    # Control screen backlight brightness with brightnessctl (https://github.com/Hummer12007/brightnessctl)
-    riverctl map $mode None XF86MonBrightnessUp   spawn 'brightnessctl set +5%'
-    riverctl map $mode None XF86MonBrightnessDown spawn 'brightnessctl set 5%-'
-done
-
-# Set background and border color
-riverctl background-color 0x002b36
-riverctl border-color-focused 0x93a1a1
-riverctl border-color-unfocused 0x586e75
-
-# Set keyboard repeat rate
-riverctl set-repeat 50 300
-
-# Make all views with an app-id that starts with "float" and title "foo" start floating.
-riverctl rule-add -app-id 'float*' -title 'foo' float
-
-# Make all views with app-id "bar" and any title use client-side decorations
-riverctl rule-add -app-id "bar" csd
-
-# Set the default layout generator to be rivertile and start it.
-# River will send the process group of the init executable SIGTERM on exit.
-riverctl default-layout rivertile
-rivertile -view-padding 6 -outer-padding 6 &
diff --git a/protocol/river-control-unstable-v1.xml b/protocol/river-control-unstable-v1.xml
deleted file mode 100644
index aa5fc4d..0000000
--- a/protocol/river-control-unstable-v1.xml
+++ /dev/null
@@ -1,85 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<protocol name="river_control_unstable_v1">
-  <copyright>
-    Copyright 2020 The River Developers
-
-    Permission to use, copy, modify, and/or distribute this software for any
-    purpose with or without fee is hereby granted, provided that the above
-    copyright notice and this permission notice appear in all copies.
-
-    THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
-    WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-    MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
-    ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-    WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-    ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-    OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-  </copyright>
-
-  <interface name="zriver_control_v1" version="1">
-    <description summary="run compositor commands">
-      This interface allows clients to run compositor commands and receive a
-      success/failure response with output or a failure message respectively.
-
-      Each command is built up in a series of add_argument requests and
-      executed with a run_command request. The first argument is the command
-      to be run.
-
-      A complete list of commands should be made available in the man page of
-      the compositor.
-    </description>
-
-    <request name="destroy" type="destructor">
-      <description summary="destroy the river_control object">
-        This request indicates that the client will not use the
-        river_control object any more. Objects that have been created
-        through this instance are not affected.
-      </description>
-    </request>
-
-    <request name="add_argument">
-      <description summary="add an argument to the current command">
-        Arguments are stored by the server in the order they were sent until
-        the run_command request is made.
-      </description>
-      <arg name="argument" type="string" summary="the argument to add"/>
-    </request>
-
-    <request name="run_command">
-      <description summary="run the current command">
-        Execute the command built up using the add_argument request for the
-        given seat.
-      </description>
-      <arg name="seat" type="object" interface="wl_seat"/>
-      <arg name="callback" type="new_id" interface="zriver_command_callback_v1"
-        summary="callback object"/>
-    </request>
-  </interface>
-
-  <interface name="zriver_command_callback_v1" version="1">
-    <description summary="callback object">
-      This object is created by the run_command request. Exactly one of the
-      success or failure events will be sent. This object will be destroyed
-      by the compositor after one of the events is sent.
-    </description>
-
-    <event name="success" type="destructor">
-      <description summary="command successful">
-        Sent when the command has been successfully received and executed by
-        the compositor. Some commands may produce output, in which case the
-        output argument will be a non-empty string.
-      </description>
-      <arg name="output" type="string" summary="the output of the command"/>
-    </event>
-
-    <event name="failure" type="destructor">
-      <description summary="command failed">
-        Sent when the command could not be carried out. This could be due to
-        sending a non-existent command, no command, not enough arguments, too
-        many arguments, invalid arguments, etc.
-      </description>
-      <arg name="failure_message" type="string"
-        summary="a message explaining why failure occurred"/>
-    </event>
-  </interface>
-</protocol>
diff --git a/protocol/river-layout-v3.xml b/protocol/river-layout-v3.xml
deleted file mode 100644
index 8a1bdce..0000000
--- a/protocol/river-layout-v3.xml
+++ /dev/null
@@ -1,196 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<protocol name="river_layout_v3">
-  <copyright>
-    Copyright 2020-2021 The River Developers
-
-    Permission to use, copy, modify, and/or distribute this software for any
-    purpose with or without fee is hereby granted, provided that the above
-    copyright notice and this permission notice appear in all copies.
-
-    THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
-    WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-    MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
-    ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-    WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-    ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-    OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-  </copyright>
-
-  <description summary="let clients propose view positions and dimensions">
-    This protocol specifies a way for clients to propose arbitrary positions
-    and dimensions for a set of views on a specific output of a compositor
-    through the river_layout_v3 object.
-
-    Layouts are a strictly linear list of views, the position and dimensions
-    of which are supplied by the client. Any complex underlying data structure
-    a client may use when generating the layout is lost in transmission. This
-    is an intentional limitation.
-
-    Additionally, this protocol allows the compositor to deliver arbitrary
-    user-provided commands associated with a layout to clients. A client
-    may use these commands to implement runtime configuration/control, or
-    may ignore them entirely. How the user provides these commands to the
-    compositor is not specified by this protocol and left to compositor policy.
-
-    Warning! The protocol described in this file is currently in the
-    testing phase. Backward compatible changes may be added together with
-    the corresponding interface version bump. Backward incompatible changes
-    can only be done by creating a new major version of the extension.
-  </description>
-
-  <interface name="river_layout_manager_v3" version="2">
-    <description summary="manage river layout objects">
-      A global factory for river_layout_v3 objects.
-    </description>
-
-    <request name="destroy" type="destructor">
-      <description summary="destroy the river_layout_manager object">
-        This request indicates that the client will not use the
-        river_layout_manager object any more. Objects that have been created
-        through this instance are not affected.
-      </description>
-    </request>
-
-    <request name="get_layout">
-      <description summary="create a river_layout_v3 object">
-        This creates a new river_layout_v3 object for the given wl_output.
-
-        All layout related communication is done through this interface.
-
-        The namespace is used by the compositor to decide which river_layout_v3
-        object will receive layout demands for the output.
-
-        The namespace is required to be be unique per-output. Furthermore,
-        two separate clients may not share a namespace on separate outputs. If
-        these conditions are not upheld, the the namespace_in_use event will
-        be sent directly after creation of the river_layout_v3 object.
-      </description>
-      <arg name="id" type="new_id" interface="river_layout_v3"/>
-      <arg name="output" type="object" interface="wl_output"/>
-      <arg name="namespace" type="string" summary="namespace of the layout object"/>
-    </request>
-  </interface>
-
-  <interface name="river_layout_v3" version="2">
-    <description summary="receive and respond to layout demands">
-      This interface allows clients to receive layout demands from the
-      compositor for a specific output and subsequently propose positions and
-      dimensions of individual views.
-    </description>
-
-    <enum name="error">
-      <entry name="count_mismatch" value="0" summary="number of
-        proposed dimensions does not match number of views in layout"/>
-      <entry name="already_committed" value="1" summary="the layout demand with
-        the provided serial was already committed"/>
-    </enum>
-
-    <request name="destroy" type="destructor">
-      <description summary="destroy the river_layout_v3 object">
-        This request indicates that the client will not use the river_layout_v3
-        object any more.
-      </description>
-    </request>
-
-    <event name="namespace_in_use">
-      <description summary="the requested namespace is already in use">
-        After this event is sent, all requests aside from the destroy event
-        will be ignored by the server. If the client wishes to try again with
-        a different namespace they must create a new river_layout_v3 object.
-      </description>
-    </event>
-
-    <event name="layout_demand">
-      <description summary="the compositor requires a layout">
-        The compositor sends this event to inform the client that it requires a
-        layout for a set of views.
-
-        The usable width and height indicate the space in which the client
-        can safely position views without interfering with desktop widgets
-        such as panels.
-
-        The serial of this event is used to identify subsequent requests as
-        belonging to this layout demand. Beware that the client might need
-        to handle multiple layout demands at the same time.
-
-        The server will ignore responses to all but the most recent layout
-        demand. Thus, clients are only required to respond to the most recent
-        layout_demand received. If a newer layout_demand is received before
-        the client has finished responding to an old demand, the client should
-        abort work on the old demand as any further work would be wasted.
-      </description>
-      <arg name="view_count" type="uint" summary="number of views in the layout"/>
-      <arg name="usable_width" type="uint" summary="width of the usable area"/>
-      <arg name="usable_height" type="uint" summary="height of the usable area"/>
-      <arg name="tags" type="uint" summary="tags of the output, 32-bit bitfield"/>
-      <arg name="serial" type="uint" summary="serial of the layout demand"/>
-    </event>
-
-    <request name="push_view_dimensions">
-      <description summary="propose dimensions of the next view">
-        This request proposes a size and position for a view in the layout demand
-        with matching serial.
-
-        A client must send this request for every view that is part of the
-        layout demand. The number of views in the layout is given by the
-        view_count argument of the layout_demand event. Pushing too many or
-        too few view dimensions is a protocol error.
-
-        The x and y coordinates are relative to the usable area of the output,
-        with (0,0) as the top left corner.
-      </description>
-      <arg name="x" type="int" summary="x coordinate of view"/>
-      <arg name="y" type="int" summary="y coordinate of view"/>
-      <arg name="width" type="uint" summary="width of view"/>
-      <arg name="height" type="uint" summary="height of view"/>
-      <arg name="serial" type="uint" summary="serial of layout demand"/>
-    </request>
-
-    <request name="commit">
-      <description summary="commit a layout">
-        This request indicates that the client is done pushing dimensions
-        and the compositor may apply the layout. This completes the layout
-        demand with matching serial, any other requests sent with the serial
-        are a protocol error.
-
-        The layout_name argument is a user-facing name or short description
-        of the layout that is being committed. The compositor may for example
-        display this on a status bar, though what exactly is done with it is
-        left to the compositor's discretion.
-
-        The compositor is free to use this proposed layout however it chooses,
-        including ignoring it.
-      </description>
-      <arg name="layout_name" type="string" summary="name of committed layout"/>
-      <arg name="serial" type="uint" summary="serial of layout demand"/>
-    </request>
-
-    <event name="user_command">
-      <description summary="a command sent by the user">
-        This event informs the client of a command sent to it by the user.
-
-        The semantic meaning of the command is left for the client to
-        decide. It is also free to ignore it entirely if it so chooses.
-
-        A layout_demand will be sent after this event if the compositor is
-        currently using this layout object to arrange the output.
-
-        If version 2 or higher of the river_layout_v3 object is bound, the
-        user_command_tags event is guaranteed to be sent directly before the
-        user_command event.
-      </description>
-      <arg name="command" type="string"/>
-    </event>
-
-    <event name="user_command_tags" since="2">
-      <description summary="a command sent by the user">
-        If version 2 or higher of the river_layout_v3 object is bound, this
-        event will be sent directly before every user_command event. This allows
-        layout generators to be aware of the active tags when a user command is
-        sent. This is necessary for generators wanting to keep settings on a
-        per-tag basis.
-      </description>
-      <arg name="tags" type="uint" summary="tags of the output, 32-bit bitfield"/>
-    </event>
-  </interface>
-</protocol>
diff --git a/riverctl/main.zig b/riverctl/main.zig
deleted file mode 100644
index 06d083b..0000000
--- a/riverctl/main.zig
+++ /dev/null
@@ -1,148 +0,0 @@
-// This file is part of river, a dynamic tiling wayland compositor.
-//
-// Copyright 2020-2021 The River Developers
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, version 3.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program. If not, see <https://www.gnu.org/licenses/>.
-
-const std = @import("std");
-const mem = std.mem;
-const io = std.io;
-const posix = std.posix;
-const assert = std.debug.assert;
-const builtin = @import("builtin");
-
-const wayland = @import("wayland");
-const wl = wayland.client.wl;
-const zriver = wayland.client.zriver;
-
-const flags = @import("flags");
-
-const usage =
-    \\usage: riverctl [options] <command>
-    \\
-    \\  -h              Print this help message and exit.
-    \\  -version        Print the version number and exit.
-    \\
-    \\Complete documentation of the recognized commands may be found in
-    \\the riverctl(1) man page.
-    \\
-;
-
-const gpa = std.heap.c_allocator;
-
-pub const Globals = struct {
-    control: ?*zriver.ControlV1 = null,
-    seat: ?*wl.Seat = null,
-};
-
-pub fn main() !void {
-    _main() catch |err| {
-        switch (err) {
-            error.RiverControlNotAdvertised => fatal(
-                \\The Wayland server does not support river-control-unstable-v1.
-                \\Do your versions of river and riverctl match?
-            , .{}),
-            error.SeatNotAdverstised => fatal(
-                \\The Wayland server did not advertise any seat.
-            , .{}),
-            error.ConnectFailed => {
-                std.log.err("Unable to connect to the Wayland server.", .{});
-                if (posix.getenvZ("WAYLAND_DISPLAY") == null) {
-                    fatal("WAYLAND_DISPLAY is not set.", .{});
-                } else {
-                    fatal("Does WAYLAND_DISPLAY contain the socket name of a running server?", .{});
-                }
-            },
-            else => return err,
-        }
-    };
-}
-
-fn _main() !void {
-    const result = flags.parser([*:0]const u8, &.{
-        .{ .name = "h", .kind = .boolean },
-        .{ .name = "version", .kind = .boolean },
-    }).parse(std.os.argv[1..]) catch {
-        try io.getStdErr().writeAll(usage);
-        posix.exit(1);
-    };
-    if (result.flags.h) {
-        try io.getStdOut().writeAll(usage);
-        posix.exit(0);
-    }
-    if (result.flags.version) {
-        try io.getStdOut().writeAll(@import("build_options").version ++ "\n");
-        posix.exit(0);
-    }
-
-    const display = try wl.Display.connect(null);
-    const registry = try display.getRegistry();
-
-    var globals = Globals{};
-
-    registry.setListener(*Globals, registryListener, &globals);
-    if (display.roundtrip() != .SUCCESS) fatal("initial roundtrip failed", .{});
-
-    const control = globals.control orelse return error.RiverControlNotAdvertised;
-    const seat = globals.seat orelse return error.SeatNotAdverstised;
-
-    for (result.args) |arg| control.addArgument(arg);
-
-    const callback = try control.runCommand(seat);
-    callback.setListener(?*anyopaque, callbackListener, null);
-
-    // Loop until our callback is called and we exit.
-    while (true) {
-        if (display.dispatch() != .SUCCESS) fatal("failed to dispatch wayland events", .{});
-    }
-}
-
-fn registryListener(registry: *wl.Registry, event: wl.Registry.Event, globals: *Globals) void {
-    switch (event) {
-        .global => |global| {
-            if (mem.orderZ(u8, global.interface, wl.Seat.interface.name) == .eq) {
-                assert(globals.seat == null); // TODO: support multiple seats
-                globals.seat = registry.bind(global.name, wl.Seat, 1) catch @panic("out of memory");
-            } else if (mem.orderZ(u8, global.interface, zriver.ControlV1.interface.name) == .eq) {
-                globals.control = registry.bind(global.name, zriver.ControlV1, 1) catch @panic("out of memory");
-            }
-        },
-        .global_remove => {},
-    }
-}
-
-fn callbackListener(_: *zriver.CommandCallbackV1, event: zriver.CommandCallbackV1.Event, _: ?*anyopaque) void {
-    switch (event) {
-        .success => |success| {
-            if (mem.len(success.output) > 0) {
-                const stdout = io.getStdOut().writer();
-                stdout.print("{s}\n", .{success.output}) catch @panic("failed to write to stdout");
-            }
-            posix.exit(0);
-        },
-        .failure => |failure| {
-            // A small hack to provide usage text when river reports an unknown command.
-            if (mem.orderZ(u8, failure.failure_message, "unknown command") == .eq) {
-                std.log.err("unknown command", .{});
-                io.getStdErr().writeAll(usage) catch {};
-                posix.exit(1);
-            }
-            fatal("{s}", .{failure.failure_message});
-        },
-    }
-}
-
-fn fatal(comptime format: []const u8, args: anytype) noreturn {
-    std.log.err(format, args);
-    posix.exit(1);
-}
diff --git a/rivertile/main.zig b/rivertile/main.zig
deleted file mode 100644
index ad76ed9..0000000
--- a/rivertile/main.zig
+++ /dev/null
@@ -1,419 +0,0 @@
-// This file is part of river, a dynamic tiling wayland compositor.
-//
-// Copyright 2020-2021 The River Developers
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, version 3.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program. If not, see <https://www.gnu.org/licenses/>.
-
-// This is an implementation of the  default "tiled" layout of dwm and the
-// 3 other orientations thereof. This code is written for the main stack
-// to the left and then the input/output values are adjusted to apply
-// the necessary transformations to derive the other orientations.
-//
-// With 4 views and one main on the left, the layout looks something like this:
-//
-// +-----------------------+------------+
-// |                       |            |
-// |                       |            |
-// |                       |            |
-// |                       +------------+
-// |                       |            |
-// |                       |            |
-// |                       |            |
-// |                       +------------+
-// |                       |            |
-// |                       |            |
-// |                       |            |
-// +-----------------------+------------+
-
-const std = @import("std");
-const fmt = std.fmt;
-const mem = std.mem;
-const math = std.math;
-const posix = std.posix;
-const assert = std.debug.assert;
-
-const wayland = @import("wayland");
-const wl = wayland.client.wl;
-const river = wayland.client.river;
-
-const flags = @import("flags");
-
-const usage =
-    \\usage: rivertile [options]
-    \\
-    \\  -h              Print this help message and exit.
-    \\  -version        Print the version number and exit.
-    \\  -view-padding   Set the padding around views in pixels. (Default 6)
-    \\  -outer-padding  Set the padding around the edge of the layout area in
-    \\                  pixels. (Default 6)
-    \\  -main-location  Set the initial location of the main area in the
-    \\                  layout. (Default left)
-    \\  -main-count     Set the initial number of views in the main area of the
-    \\                  layout. (Default 1)
-    \\  -main-ratio     Set the initial ratio of main area to total layout
-    \\                  area. (Default: 0.6)
-    \\
-;
-
-const Command = enum {
-    @"main-location",
-    @"main-count",
-    @"main-ratio",
-};
-
-const Location = enum {
-    top,
-    right,
-    bottom,
-    left,
-};
-
-// Configured through command line options
-var view_padding: u31 = 6;
-var outer_padding: u31 = 6;
-var default_main_location: Location = .left;
-var default_main_count: u31 = 1;
-var default_main_ratio: f64 = 0.6;
-
-/// We don't free resources on exit, only when output globals are removed.
-const gpa = std.heap.c_allocator;
-
-const Context = struct {
-    initialized: bool = false,
-    layout_manager: ?*river.LayoutManagerV3 = null,
-    outputs: std.DoublyLinkedList(Output) = .{},
-
-    fn addOutput(context: *Context, registry: *wl.Registry, name: u32) !void {
-        const wl_output = try registry.bind(name, wl.Output, 3);
-        errdefer wl_output.release();
-        const node = try gpa.create(std.DoublyLinkedList(Output).Node);
-        errdefer gpa.destroy(node);
-        try node.data.init(context, wl_output, name);
-        context.outputs.append(node);
-    }
-};
-
-const Output = struct {
-    wl_output: *wl.Output,
-    name: u32,
-
-    main_location: Location,
-    main_count: u31,
-    main_ratio: f64,
-
-    layout: *river.LayoutV3 = undefined,
-
-    fn init(output: *Output, context: *Context, wl_output: *wl.Output, name: u32) !void {
-        output.* = .{
-            .wl_output = wl_output,
-            .name = name,
-            .main_location = default_main_location,
-            .main_count = default_main_count,
-            .main_ratio = default_main_ratio,
-        };
-        if (context.initialized) try output.getLayout(context);
-    }
-
-    fn getLayout(output: *Output, context: *Context) !void {
-        assert(context.initialized);
-        output.layout = try context.layout_manager.?.getLayout(output.wl_output, "rivertile");
-        output.layout.setListener(*Output, layoutListener, output);
-    }
-
-    fn deinit(output: *Output) void {
-        output.wl_output.release();
-        output.layout.destroy();
-    }
-
-    fn layoutListener(layout: *river.LayoutV3, event: river.LayoutV3.Event, output: *Output) void {
-        switch (event) {
-            .namespace_in_use => fatal("namespace 'rivertile' already in use.", .{}),
-
-            .user_command => |ev| {
-                var it = mem.tokenizeSequence(u8, mem.span(ev.command), " ");
-                const raw_cmd = it.next() orelse {
-                    std.log.err("not enough arguments", .{});
-                    return;
-                };
-                const raw_arg = it.next() orelse {
-                    std.log.err("not enough arguments", .{});
-                    return;
-                };
-                if (it.next() != null) {
-                    std.log.err("too many arguments", .{});
-                    return;
-                }
-                const cmd = std.meta.stringToEnum(Command, raw_cmd) orelse {
-                    std.log.err("unknown command: {s}", .{raw_cmd});
-                    return;
-                };
-                switch (cmd) {
-                    .@"main-location" => {
-                        output.main_location = std.meta.stringToEnum(Location, raw_arg) orelse {
-                            std.log.err("unknown location: {s}", .{raw_arg});
-                            return;
-                        };
-                    },
-                    .@"main-count" => {
-                        const arg = fmt.parseInt(i32, raw_arg, 10) catch |err| {
-                            std.log.err("failed to parse argument: {}", .{err});
-                            return;
-                        };
-                        switch (raw_arg[0]) {
-                            '+' => output.main_count +|= @intCast(arg),
-                            '-' => {
-                                const result = output.main_count +| arg;
-                                if (result >= 1) output.main_count = @intCast(result);
-                            },
-                            else => {
-                                if (arg >= 1) output.main_count = @intCast(arg);
-                            },
-                        }
-                    },
-                    .@"main-ratio" => {
-                        const arg = fmt.parseFloat(f64, raw_arg) catch |err| {
-                            std.log.err("failed to parse argument: {}", .{err});
-                            return;
-                        };
-                        switch (raw_arg[0]) {
-                            '+', '-' => {
-                                output.main_ratio = math.clamp(output.main_ratio + arg, 0.1, 0.9);
-                            },
-                            else => output.main_ratio = math.clamp(arg, 0.1, 0.9),
-                        }
-                    },
-                }
-            },
-
-            .layout_demand => |ev| {
-                assert(ev.view_count > 0);
-
-                const main_count = @min(output.main_count, ev.view_count);
-                const secondary_count = saturatingCast(u31, ev.view_count) -| main_count;
-
-                const usable_width = switch (output.main_location) {
-                    .left, .right => saturatingCast(u31, ev.usable_width) -| (2 *| outer_padding),
-                    .top, .bottom => saturatingCast(u31, ev.usable_height) -| (2 *| outer_padding),
-                };
-                const usable_height = switch (output.main_location) {
-                    .left, .right => saturatingCast(u31, ev.usable_height) -| (2 *| outer_padding),
-                    .top, .bottom => saturatingCast(u31, ev.usable_width) -| (2 *| outer_padding),
-                };
-
-                // to make things pixel-perfect, we make the first main and first secondary
-                // view slightly larger if the height is not evenly divisible
-                var main_width: u31 = undefined;
-                var main_height: u31 = undefined;
-                var main_height_rem: u31 = undefined;
-
-                var secondary_width: u31 = undefined;
-                var secondary_height: u31 = undefined;
-                var secondary_height_rem: u31 = undefined;
-
-                if (secondary_count > 0) {
-                    main_width = @intFromFloat(output.main_ratio * @as(f64, @floatFromInt(usable_width)));
-                    main_height = usable_height / main_count;
-                    main_height_rem = usable_height % main_count;
-
-                    secondary_width = usable_width - main_width;
-                    secondary_height = usable_height / secondary_count;
-                    secondary_height_rem = usable_height % secondary_count;
-                } else {
-                    main_width = usable_width;
-                    main_height = usable_height / main_count;
-                    main_height_rem = usable_height % main_count;
-                }
-
-                var i: u31 = 0;
-                while (i < ev.view_count) : (i += 1) {
-                    var x: i32 = undefined;
-                    var y: i32 = undefined;
-                    var width: u31 = undefined;
-                    var height: u31 = undefined;
-
-                    if (i < main_count) {
-                        x = 0;
-                        y = (i * main_height) + if (i > 0) main_height_rem else 0;
-                        width = main_width;
-                        height = main_height + if (i == 0) main_height_rem else 0;
-                    } else {
-                        x = main_width;
-                        y = (i - main_count) * secondary_height + if (i > main_count) secondary_height_rem else 0;
-                        width = secondary_width;
-                        height = secondary_height + if (i == main_count) secondary_height_rem else 0;
-                    }
-
-                    x +|= view_padding;
-                    y +|= view_padding;
-                    width -|= 2 *| view_padding;
-                    height -|= 2 *| view_padding;
-
-                    switch (output.main_location) {
-                        .left => layout.pushViewDimensions(
-                            x +| outer_padding,
-                            y +| outer_padding,
-                            width,
-                            height,
-                            ev.serial,
-                        ),
-                        .right => layout.pushViewDimensions(
-                            usable_width - width - x +| outer_padding,
-                            y +| outer_padding,
-                            width,
-                            height,
-                            ev.serial,
-                        ),
-                        .top => layout.pushViewDimensions(
-                            y +| outer_padding,
-                            x +| outer_padding,
-                            height,
-                            width,
-                            ev.serial,
-                        ),
-                        .bottom => layout.pushViewDimensions(
-                            y +| outer_padding,
-                            usable_width - width - x +| outer_padding,
-                            height,
-                            width,
-                            ev.serial,
-                        ),
-                    }
-                }
-
-                switch (output.main_location) {
-                    .left => layout.commit("rivertile - left", ev.serial),
-                    .right => layout.commit("rivertile - right", ev.serial),
-                    .top => layout.commit("rivertile - top", ev.serial),
-                    .bottom => layout.commit("rivertile - bottom", ev.serial),
-                }
-            },
-            .user_command_tags => {},
-        }
-    }
-};
-
-pub fn main() !void {
-    const result = flags.parser([*:0]const u8, &[_]flags.Flag{
-        .{ .name = "h", .kind = .boolean },
-        .{ .name = "version", .kind = .boolean },
-        .{ .name = "view-padding", .kind = .arg },
-        .{ .name = "outer-padding", .kind = .arg },
-        .{ .name = "main-location", .kind = .arg },
-        .{ .name = "main-count", .kind = .arg },
-        .{ .name = "main-ratio", .kind = .arg },
-    }).parse(std.os.argv[1..]) catch {
-        try std.io.getStdErr().writeAll(usage);
-        posix.exit(1);
-    };
-    if (result.flags.h) {
-        try std.io.getStdOut().writeAll(usage);
-        posix.exit(0);
-    }
-    if (result.args.len != 0) fatalPrintUsage("unknown option '{s}'", .{result.args[0]});
-
-    if (result.flags.version) {
-        try std.io.getStdOut().writeAll(@import("build_options").version ++ "\n");
-        posix.exit(0);
-    }
-    if (result.flags.@"view-padding") |raw| {
-        view_padding = fmt.parseUnsigned(u31, raw, 10) catch
-            fatalPrintUsage("invalid value '{s}' provided to -view-padding", .{raw});
-    }
-    if (result.flags.@"outer-padding") |raw| {
-        outer_padding = fmt.parseUnsigned(u31, raw, 10) catch
-            fatalPrintUsage("invalid value '{s}' provided to -outer-padding", .{raw});
-    }
-    if (result.flags.@"main-location") |raw| {
-        default_main_location = std.meta.stringToEnum(Location, raw) orelse
-            fatalPrintUsage("invalid value '{s}' provided to -main-location", .{raw});
-    }
-    if (result.flags.@"main-count") |raw| {
-        default_main_count = fmt.parseUnsigned(u31, raw, 10) catch
-            fatalPrintUsage("invalid value '{s}' provided to -main-count", .{raw});
-    }
-    if (result.flags.@"main-ratio") |raw| {
-        default_main_ratio = fmt.parseFloat(f64, raw) catch {
-            fatalPrintUsage("invalid value '{s}' provided to -main-ratio", .{raw});
-        };
-        if (default_main_ratio < 0.1 or default_main_ratio > 0.9) {
-            fatalPrintUsage("invalid value '{s}' provided to -main-ratio", .{raw});
-        }
-    }
-
-    const display = wl.Display.connect(null) catch {
-        std.debug.print("Unable to connect to Wayland server.\n", .{});
-        posix.exit(1);
-    };
-    defer display.disconnect();
-
-    var context: Context = .{};
-
-    const registry = try display.getRegistry();
-    registry.setListener(*Context, registryListener, &context);
-    if (display.roundtrip() != .SUCCESS) fatal("initial roundtrip failed", .{});
-
-    if (context.layout_manager == null) {
-        fatal("wayland compositor does not support river-layout-v3.\n", .{});
-    }
-
-    context.initialized = true;
-
-    var it = context.outputs.first;
-    while (it) |node| : (it = node.next) {
-        const output = &node.data;
-        try output.getLayout(&context);
-    }
-
-    while (true) {
-        if (display.dispatch() != .SUCCESS) fatal("failed to dispatch wayland events", .{});
-    }
-}
-
-fn registryListener(registry: *wl.Registry, event: wl.Registry.Event, context: *Context) void {
-    switch (event) {
-        .global => |global| {
-            if (mem.orderZ(u8, global.interface, river.LayoutManagerV3.interface.name) == .eq) {
-                context.layout_manager = registry.bind(global.name, river.LayoutManagerV3, 1) catch return;
-            } else if (mem.orderZ(u8, global.interface, wl.Output.interface.name) == .eq) {
-                context.addOutput(registry, global.name) catch |err| fatal("failed to bind output: {}", .{err});
-            }
-        },
-        .global_remove => |ev| {
-            var it = context.outputs.first;
-            while (it) |node| : (it = node.next) {
-                const output = &node.data;
-                if (output.name == ev.name) {
-                    context.outputs.remove(node);
-                    output.deinit();
-                    gpa.destroy(node);
-                    break;
-                }
-            }
-        },
-    }
-}
-
-fn fatal(comptime format: []const u8, args: anytype) noreturn {
-    std.log.err(format, args);
-    posix.exit(1);
-}
-
-fn fatalPrintUsage(comptime format: []const u8, args: anytype) noreturn {
-    std.log.err(format, args);
-    std.io.getStdErr().writeAll(usage) catch {};
-    posix.exit(1);
-}
-
-fn saturatingCast(comptime T: type, x: anytype) T {
-    return @max(math.minInt(T), @min(math.maxInt(T), x));
-}