diff --git a/README.md b/README.md index 5135753..8078f6d 100644 --- a/README.md +++ b/README.md @@ -35,6 +35,12 @@ Only needed at build-time: |--------------------|------------------------------|---------------------| | wayland-protocols | `dev-libs/wayland-protocols` | `wayland-protocols` | +Optional (for building man pages): + +| Dependency | Gentoo Name | Debian/Ubuntu Name | +|--------------------|------------------------------|---------------------| +| scdoc | `app-text/scdoc` | `scdoc` | + #### Note for Gentoo Users Beansprout is available in my personal [ebuild repo](https://codeberg.org/bwbuhse/beansprout). diff --git a/REUSE.toml b/REUSE.toml index 9e41b16..9ef242d 100644 --- a/REUSE.toml +++ b/REUSE.toml @@ -1,7 +1,7 @@ version = 1 [[annotations]] -path = ["README.md", "docs/**"] +path = ["README.md", "man/**", "docs/**"] SPDX-FileCopyrightText = "2026 Ben Buhse " SPDX-License-Identifier = "CC-BY-4.0" diff --git a/build.zig b/build.zig index 03c2d0d..103fd7d 100644 --- a/build.zig +++ b/build.zig @@ -11,6 +11,15 @@ pub fn build(b: *std.Build) void { const strip = b.option(bool, "strip", "Omit debug information") orelse false; const pie = b.option(bool, "pie", "Build a Position Independent Executable") orelse false; + const man_pages = b.option( + bool, + "man-pages", + "Set to true to build man pages. Requires scdoc. Defaults to true if scdoc is found.", + ) orelse scdoc_found: { + // Default to true if scdoc is available; else false. + _ = b.findProgram(&.{"scdoc"}, &.{}) catch break :scdoc_found false; + break :scdoc_found true; + }; // Wayland const scanner = Scanner.create(b, .{}); @@ -75,6 +84,20 @@ pub fn build(b: *std.Build) void { b.installArtifact(beansprout); + const man_step = b.step("man", "Build man pages"); + if (man_pages) { + inline for (.{ .{ "beansprout", "1" }, .{ "beansprout", "5" } }) |page| { + const scdoc = b.addSystemCommand(&.{ "/bin/sh", "-c", "scdoc < man/" ++ page[0] ++ "." ++ page[1] ++ ".scd" }); + scdoc.addFileArg(b.path("man/" ++ page[0] ++ "." ++ page[1] ++ ".scd")); + const stdout = scdoc.captureStdOut(); + const install = b.addInstallFile(stdout, "share/man/man" ++ page[1] ++ "/" ++ page[0] ++ "." ++ page[1]); + b.getInstallStep().dependOn(&install.step); + man_step.dependOn(&install.step); + } + } else { + man_step.dependOn(&b.addFail("man pages disabled; scdoc not found or -Dman-pages=false was set").step); + } + const exe_unit_tests = b.addTest(.{ .root_module = beansprout.root_module, }); diff --git a/man/beansprout.1.scd b/man/beansprout.1.scd new file mode 100644 index 0000000..da4d1a9 --- /dev/null +++ b/man/beansprout.1.scd @@ -0,0 +1,60 @@ +BEANSPROUT(1) + +# NAME + +beansprout - tiling window manager for river + +# SYNOPSIS + +*beansprout* [_options_] + +# DESCRIPTION + +*beansprout* is a tiling window manager for the *river*(1) Wayland compositor. +It communicates with river using the river-window-management-v1 protocol and +other River-specific Wayland protocols. + +*beansprout* uses a primary/stack tiling layout inspired by dwm with a +customizable ratio and primary count. It uses a 32-bit tag system rather than +workspaces. Each output has its own tags, primary count, and ratio. + +# OPTIONS + +*-h* + Print a help message and exit. + +*-version* + Print the version number and exit. + +*-log-level* [*error*|*warning*|*info*|*debug*] + Set the log level. (Default: *warning*) + +# USAGE + +You can either add *beansprout* to the river init file or directly run: + + river -c beansprout + +If you need to exit river, for example if *beansprout* crashes, you can use +river's hardcoded *Ctrl+Alt+Delete* keybind. + +# CONFIGURATION + +*beansprout* is configured with a KDL file located at +_$XDG_CONFIG_HOME/beansprout/config.kdl_. If _$XDG_CONFIG_HOME_ is not set, +this defaults to _~/.config/beansprout/config.kdl_. + +See *beansprout*(5) for a full configuration reference. + +If the config file is missing, *beansprout* falls back to built-in defaults +(which will be missing keybinds). If an individual node or block is invalid, +*beansprout* will try to ignore the error and continue. + +# AUTHORS + +Maintained by Ben Buhse . For more information about +beansprout's development, see . + +# SEE ALSO + +*beansprout*(5), *river*(1) diff --git a/man/beansprout.5.scd b/man/beansprout.5.scd new file mode 100644 index 0000000..6bf9c58 --- /dev/null +++ b/man/beansprout.5.scd @@ -0,0 +1,361 @@ +BEANSPROUT(5) + +# NAME + +beansprout - configuration file + +# DESCRIPTION + +*beansprout*(1) is configured with a KDL file located at +_$XDG_CONFIG_HOME/beansprout/config.kdl_. If _$XDG_CONFIG_HOME_ is not set, +this defaults to _~/.config/beansprout/config.kdl_. + +All configuration is applied top-down, so later options overwrite earlier ones. + +Any node can have a *host=* property to restrict it to a specific hostname. +This is useful for sharing a config file across machines. Nodes without a +*host=* property apply to all hosts. + +# GENERAL SETTINGS + +*attach_mode* *top*|*bottom* + Whether new windows go to the top or bottom of the window stack. + (Default: *top*) + +*primary_count* _count_ + Number of windows in the primary stack. (Default: 1) + +*primary_ratio* _ratio_ + Proportion of output width taken by the primary stack. Must be between + 0.10 and 0.90. (Default: 0.55) + +*primary_side* *left*|*right* + Which side of the output the primary stack is on. (Default: *left*) + +*single_window_ratio* _ratio_ + Proportion of output width taken when a single tiled window is visible. + Must be between 0.10 and 1.00. When less than 1.0, the window is + centered. (Default: 1.00) + +*focus_follows_pointer* _bool_ + Whether mousing over a new window should move focus. + (Default: *true*) + +*pointer_warp_on_focus_change* _bool_ + Whether the pointer should warp to the center of newly-focused windows. + (Default: *true*) + +*wallpaper_image_path* _path_ + Path to image to use as wallpaper. The same image is displayed on all + outputs, scaled separately. If not set, the background is a blank black + screen. + +# BORDERS + +Border settings are placed inside a *borders* block: + +``` +borders { + width 2 + color_focused "0x89b4fa" + color_unfocused "0x1e1e2e" +} +``` + +*width* _pixels_ + Border width in pixels. (Default: 2) + +*color_focused* _color_ + Border color of the focused window in 0xRRGGBB or 0xRRGGBBAA hex + format. (Default: 0x89b4fa) + +*color_unfocused* _color_ + Border color of unfocused windows in 0xRRGGBB or 0xRRGGBBAA hex + format. (Default: 0x1e1e2e) + +# WINDOW RULES + +Window rules let you set properties on windows when they first appear, based +on their app_id and/or title. Rules are placed inside a *window_rules* block: + +``` +window_rules { + float app_id="firefox" title="Picture-in-Picture" + float title="*Preferences*" + no_float app_id="mpv" + tags 0x0004 app_id="Slack" +} +``` + +## Rule Types + +*float* [*app_id=*_pattern_] [*title=*_pattern_] + Make matching windows float. + +*no_float* [*app_id=*_pattern_] [*title=*_pattern_] + Keep matching windows tiled. + +*tags* _bitmask_ [*app_id=*_pattern_] [*title=*_pattern_] + Assign matching windows to specific tags. The argument is a 32-bit + integer representing the tag bitfield. + +## Matching + +Each rule can have an *app_id=* and/or *title=* property. Both support glob +patterns using *\** as a wildcard. A rule with neither property matches all +windows. If both are specified, both must match. + +Rules are evaluated top-to-bottom. Each matching rule applies only the +properties it specifies, so multiple rules can contribute different properties +to the same window. For the same property, later rules override earlier ones. + +Rules are applied once during window initialization. Title changes after +initialization do not re-trigger rules. + +# BAR + +The bar is an optional widget that shows the time. It is only created when a +*bar* block is present: + +``` +bar { + position top +} +``` + +*fonts* _fontconfig_ + Comma-separated FontConfig font string. (Default: "monospace:size=14") + +*text_color* _color_ + Text color. (Default: 0xcdd6f4) + +*background_color* _color_ + Background color. (Default: 0x1e1e2e) + +*position* *top*|*bottom* + Bar position. (Default: *top*) + +The bar also supports *margins* and *anchors* child blocks; see *TAG OVERLAY* +for their format. + +# TAG OVERLAY + +The tag overlay is an optional widget that briefly shows tag state when +switching tags. It is only created when a *tag_overlay* block is present: + +``` +tag_overlay { + tag_amount 10 +} +``` + +*border_width* _pixels_ + Widget border width in pixels. (Default: 2) + +*tag_amount* _count_ + Number of displayed tags, 1-32. (Default: 9) + +*tags_per_row* _count_ + Tags per row, 1-32. (Default: 32) + +*square_size* _pixels_ + Size of tag squares in pixels. (Default: 40) + +*square_inner_padding* _pixels_ + Padding around occupied indicator. (Default: 10) + +*square_padding* _pixels_ + Padding around tag squares. (Default: 15) + +*square_border_width* _pixels_ + Border width of tag squares. (Default: 1) + +*timeout* _milliseconds_ + Display duration in milliseconds. (Default: 500) + +*background_color*, *border_color*, *square_active_background_color*, +*square_active_border_color*, *square_active_occupied_color*, +*square_inactive_background_color*, *square_inactive_border_color*, +*square_inactive_occupied_color* + Color settings in 0xRRGGBB or 0xRRGGBBAA hex format. Defaults follow + the Catppuccin Mocha theme. + +## Anchors + +The *anchors* child block controls which edge(s) of the screen the overlay +attaches to. Each direction is a boolean. Default: unanchored (centered). + + *top*, *right*, *bottom*, *left* + +## Margins + +The *margins* child block sets pixel offsets from the anchored edge(s). All +default to 0. + + *top*, *right*, *bottom*, *left* + +# KEYBINDS + +Keyboard bindings are placed inside a *keybinds* block. Each binding has the +form: + + _command_ _modifiers_ _keysym_ [_arguments..._] + +## Modifiers + +Modifiers are combined with *+*. They are case-insensitive. + +- *Mod4* or *Super* - Super/Windows key +- *Shift* - Shift key +- *Ctrl* - Control key +- *Mod1* or *Alt* - Alt key +- *Mod3* - Mod3 key +- *Mod5* - Mod5 key +- *None* - No modifier (e.g., for media keys) + +## Keysyms + +Keysym names follow the XKB naming convention (case-insensitive). A full list +can typically be found at _/usr/include/xkbcommon/xkbcommon-keysyms.h_. + +## Commands + +*spawn* _modifiers_ _keysym_ _command_ + Launch a program. + +*focus_next_window*, *focus_prev_window* + Focus the next/previous window in the stack. + +*focus_next_output*, *focus_prev_output* + Focus the next/previous output. + +*send_to_next_output*, *send_to_prev_output* + Send the focused window to the next/previous output. + +*zoom* + Swap the focused window with the primary window. + +*swap_next*, *swap_prev* + Swap the focused window with the next/previous in stack. + +*toggle_float* + Float/unfloat the focused window. + +*toggle_fullscreen* + Toggle fullscreen on the focused window. + +*close_window* + Close the focused window. + +*change_ratio* _modifiers_ _keysym_ _float_ + Adjust the primary/stack ratio on the current output. + +*increment_primary_count*, *decrement_primary_count* + Add/remove a window from the primary side. + +*move_up*, *move_down*, *move_left*, *move_right* _modifiers_ _keysym_ _pixels_ + Move a floating window by the given number of pixels. + +*resize_width*, *resize_height* _modifiers_ _keysym_ _pixels_ + Resize a floating window (negative to shrink). + +*center_float* + Center the focused floating window on its output. + +*set_output_tags* _modifiers_ _keysym_ _bitmask_ + Set the tags on the focused output. + +*set_window_tags* _modifiers_ _keysym_ _bitmask_ + Set the tags on the focused window. + +*toggle_output_tags* _modifiers_ _keysym_ _bitmask_ + Toggle a tag on the focused output. + +*toggle_window_tags* _modifiers_ _keysym_ _bitmask_ + Toggle a tag on the focused window. + +*reload_config* + Reload the config file. + +*toggle_passthrough* + Toggle passthrough mode to disable keybinds. + +## Tag Binds + +The special *tag_bind* command generates bindings for keys 1-9 mapped to tags +1<<0 through 1<<8: + +``` +keybinds { + tag_bind Mod4 set_output_tags + tag_bind Mod4+Shift set_window_tags + tag_bind Mod4+Ctrl toggle_output_tags + tag_bind Mod4+Ctrl+Shift toggle_window_tags +} +``` + +# POINTER BINDS + +Mouse button bindings are placed inside a *pointer_binds* block: + +``` +pointer_binds { + move_window Mod4 BTN_LEFT + resize_window Mod4 BTN_RIGHT +} +``` + +*move_window* + Drag to move the window. + +*resize_window* + Drag to resize the window. + +Button names: *BTN_LEFT* / *button1*, *BTN_RIGHT* / *button3*, +*BTN_MIDDLE* / *button2*. Numeric button codes are also accepted. Names are +case-insensitive. + +# INPUT DEVICE CONFIGURATION + +Input device settings are placed inside *input* blocks. A block without a +*name=* property applies to all devices. A block with *name=* applies only to +the matching device: + +``` +input { + accel_profile "flat" +} + +input name="PIXA3854:00 093A:0274 Touchpad" { + accel_profile "adaptive" + natural_scroll "enabled" + tap "disabled" +} +``` + +All libinput configuration options supported by river are also supported by +*beansprout*. Available settings include: + +- *accel_profile* +- *accel_speed* +- *click_method* +- *clickfinger_button_map* +- *drag* +- *drag_lock* +- *dwt* +- *dwtp* +- *left_handed* +- *middle_emulation* +- *natural_scroll* +- *rotation* +- *scroll_button* +- *scroll_button_lock* +- *scroll_method* +- *send_events* +- *tap* +- *tap_button_map* +- *three_finger_drag* + +# SEE ALSO + +*beansprout*(1), *river*(1)