From b374947b45ddd44d0d565a8028b336eab1b8316f Mon Sep 17 00:00:00 2001 From: Julian Orth Date: Thu, 4 Apr 2024 15:48:36 +0200 Subject: [PATCH 1/3] all: reorganize packages for release --- Cargo.lock | 18 +++++++++--------- Cargo.toml | 18 +++++++++++++----- algorithms/Cargo.toml | 6 +++--- jay-config/Cargo.toml | 1 + src/cli/screenshot.rs | 2 +- src/rect.rs | 2 +- src/rect/region.rs | 2 +- src/rect/tests.rs | 2 +- toml-config/Cargo.toml | 2 ++ 9 files changed, 32 insertions(+), 21 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3c72f148..4cdd16c0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -39,13 +39,6 @@ dependencies = [ "memchr", ] -[[package]] -name = "algorithms" -version = "0.1.0" -dependencies = [ - "smallvec", -] - [[package]] name = "android-tzdata" version = "0.1.1" @@ -500,11 +493,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" [[package]] -name = "jay" +name = "jay-algorithms" +version = "0.1.0" +dependencies = [ + "smallvec", +] + +[[package]] +name = "jay-compositor" version = "0.1.0" dependencies = [ "ahash", - "algorithms", "anyhow", "arrayvec", "ash", @@ -523,6 +522,7 @@ dependencies = [ "humantime", "indexmap", "isnt", + "jay-algorithms", "jay-config", "jay-toml-config", "libloading 0.8.1", diff --git a/Cargo.toml b/Cargo.toml index 7bac7c86..c911769d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,8 +1,15 @@ [package] -name = "jay" +name = "jay-compositor" version = "0.1.0" edition = "2021" build = "build/build.rs" +license = "GPL-3.0-only" +description = "The Jay compositor" +repository = "https://github.com/mahkoh/jay" + +[[bin]] +name = "jay" +path = "src/main.rs" [workspace] members = ["jay-config", "toml-config", "algorithms", "toml-spec"] @@ -14,6 +21,10 @@ panic = "abort" panic = "abort" [dependencies] +jay-config = { path = "jay-config" } +jay-toml-config = { path = "toml-config" } +jay-algorithms = { path = "algorithms" } + uapi = "0.2.13" thiserror = "1.0.56" ahash = "0.8.7" @@ -29,9 +40,6 @@ rand = "0.8.5" smallvec = { version = "1.11.1", features = ["const_generics", "const_new", "union"] } byteorder = "1.5.0" bincode = "1.3.3" -jay-config = { path = "jay-config" } -jay-toml-config = { path = "toml-config" } -algorithms = { path = "algorithms" } pin-project = "1.1.4" clap = { version = "4.4.18", features = ["derive", "wrap_help"] } clap_complete = "4.4.10" @@ -57,7 +65,7 @@ cc = "1.0.86" #[profile.dev.build-override] #opt-level = 3 -[profile.dev.package."algorithms"] +[profile.dev.package."jay-algorithms"] opt-level = 3 [profile.dev.package."smallvec"] diff --git a/algorithms/Cargo.toml b/algorithms/Cargo.toml index 7a908e8d..3bb8f64f 100644 --- a/algorithms/Cargo.toml +++ b/algorithms/Cargo.toml @@ -1,9 +1,9 @@ [package] -name = "algorithms" +name = "jay-algorithms" version = "0.1.0" edition = "2021" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html +license = "GPL-3.0-only" +description = "Internal dependency of the Jay compositor" [dependencies] smallvec = { version = "1.8.0", features = ["const_generics", "const_new", "union"] } diff --git a/jay-config/Cargo.toml b/jay-config/Cargo.toml index e5bd2f87..39d1e113 100644 --- a/jay-config/Cargo.toml +++ b/jay-config/Cargo.toml @@ -4,6 +4,7 @@ version = "0.1.0" edition = "2021" license = "GPL-3.0-only" description = "Configuration crate for the Jay compositor" +repository = "https://github.com/mahkoh/jay" [dependencies] bincode = "1.3.3" diff --git a/src/cli/screenshot.rs b/src/cli/screenshot.rs index 865d5646..0d8bd10a 100644 --- a/src/cli/screenshot.rs +++ b/src/cli/screenshot.rs @@ -14,8 +14,8 @@ use { jay_screenshot::{Dmabuf, Error}, }, }, - algorithms::qoi::xrgb8888_encode_qoi, chrono::Local, + jay_algorithms::qoi::xrgb8888_encode_qoi, std::rc::Rc, }; diff --git a/src/rect.rs b/src/rect.rs index a3031c79..c310632b 100644 --- a/src/rect.rs +++ b/src/rect.rs @@ -5,7 +5,7 @@ mod tests; pub use region::RegionBuilder; use { - algorithms::rect::RectRaw, + jay_algorithms::rect::RectRaw, smallvec::SmallVec, std::fmt::{Debug, Formatter}, }; diff --git a/src/rect/region.rs b/src/rect/region.rs index f004c1af..72deeba2 100644 --- a/src/rect/region.rs +++ b/src/rect/region.rs @@ -1,6 +1,6 @@ use { crate::rect::{Rect, Region}, - algorithms::rect::{ + jay_algorithms::rect::{ region::{extents, rects_to_bands, subtract, union}, RectRaw, }, diff --git a/src/rect/tests.rs b/src/rect/tests.rs index 9eb4dccf..9d46f824 100644 --- a/src/rect/tests.rs +++ b/src/rect/tests.rs @@ -1,6 +1,6 @@ use { crate::rect::{Rect, Region}, - algorithms::rect::RectRaw, + jay_algorithms::rect::RectRaw, }; #[test] diff --git a/toml-config/Cargo.toml b/toml-config/Cargo.toml index a6d0c4e2..4352621e 100644 --- a/toml-config/Cargo.toml +++ b/toml-config/Cargo.toml @@ -2,6 +2,8 @@ name = "jay-toml-config" version = "0.1.0" edition = "2021" +license = "GPL-3.0-only" +description = "Internal dependency of the Jay compositor" [lib] crate-type = ["lib", "cdylib"] From 1a9b7146fd1e2ad0723590d5953d259da8cdcfdf Mon Sep 17 00:00:00 2001 From: Julian Orth Date: Fri, 5 Apr 2024 17:25:07 +0200 Subject: [PATCH 2/3] config: allow configuring repeat rates via toml --- toml-config/src/config.rs | 10 +++ toml-config/src/config/parsers.rs | 1 + toml-config/src/config/parsers/action.rs | 12 ++++ toml-config/src/config/parsers/config.rs | 15 ++++- toml-config/src/config/parsers/repeat_rate.rs | 45 +++++++++++++ toml-config/src/lib.rs | 8 +++ toml-spec/spec/spec.generated.json | 39 ++++++++++++ toml-spec/spec/spec.generated.md | 63 +++++++++++++++++++ toml-spec/spec/spec.yaml | 50 +++++++++++++++ 9 files changed, 241 insertions(+), 2 deletions(-) create mode 100644 toml-config/src/config/parsers/repeat_rate.rs diff --git a/toml-config/src/config.rs b/toml-config/src/config.rs index 514f424e..eb2458bf 100644 --- a/toml-config/src/config.rs +++ b/toml-config/src/config.rs @@ -117,6 +117,9 @@ pub enum Action { workspace: Option, output: OutputMatch, }, + SetRepeatRate { + rate: RepeatRate, + }, } #[derive(Debug, Clone, Default)] @@ -269,9 +272,16 @@ pub enum ConfigKeymap { Defined { name: String, map: Keymap }, } +#[derive(Debug, Clone)] +pub struct RepeatRate { + pub rate: i32, + pub delay: i32, +} + #[derive(Debug, Clone)] pub struct Config { pub keymap: Option, + pub repeat_rate: Option, pub shortcuts: Vec<(ModifiedKeySym, Action)>, pub on_graphics_initialized: Option, pub on_idle: Option, diff --git a/toml-config/src/config/parsers.rs b/toml-config/src/config/parsers.rs index 3bd9abc6..316cafa0 100644 --- a/toml-config/src/config/parsers.rs +++ b/toml-config/src/config/parsers.rs @@ -25,6 +25,7 @@ mod mode; pub mod modified_keysym; mod output; mod output_match; +mod repeat_rate; pub mod shortcuts; mod status; mod theme; diff --git a/toml-config/src/config/parsers/action.rs b/toml-config/src/config/parsers/action.rs index 16ca5083..009e71ce 100644 --- a/toml-config/src/config/parsers/action.rs +++ b/toml-config/src/config/parsers/action.rs @@ -17,6 +17,7 @@ use { log_level::{LogLevelParser, LogLevelParserError}, output::{OutputParser, OutputParserError}, output_match::{OutputMatchParser, OutputMatchParserError}, + repeat_rate::{RepeatRateParser, RepeatRateParserError}, status::{StatusParser, StatusParserError}, theme::{ThemeParser, ThemeParserError}, StringParser, StringParserError, @@ -77,6 +78,8 @@ pub enum ActionParserError { ConfigureIdle(#[source] IdleParserError), #[error("Could not parse a move-to-output action")] MoveToOutput(#[source] OutputMatchParserError), + #[error("Could not parse a set-repeat-rate action")] + RepeatRate(#[source] RepeatRateParserError), } pub struct ActionParser<'a>(pub &'a Context<'a>); @@ -295,6 +298,14 @@ impl ActionParser<'_> { output, }) } + + fn parse_set_repeat_rate(&mut self, ext: &mut Extractor<'_>) -> ParseResult { + let rate = ext + .extract(val("rate"))? + .parse_map(&mut RepeatRateParser(self.0)) + .map_spanned_err(ActionParserError::RepeatRate)?; + Ok(Action::SetRepeatRate { rate }) + } } impl<'a> Parser for ActionParser<'a> { @@ -345,6 +356,7 @@ impl<'a> Parser for ActionParser<'a> { "set-render-device" => self.parse_set_render_device(&mut ext), "configure-idle" => self.parse_configure_idle(&mut ext), "move-to-output" => self.parse_move_to_output(&mut ext), + "set-repeat-rate" => self.parse_set_repeat_rate(&mut ext), v => { ext.ignore_unused(); return Err(ActionParserError::UnknownType(v.to_string()).spanned(ty.span)); diff --git a/toml-config/src/config/parsers/config.rs b/toml-config/src/config/parsers/config.rs index ea70ab81..89e213b6 100644 --- a/toml-config/src/config/parsers/config.rs +++ b/toml-config/src/config/parsers/config.rs @@ -16,6 +16,7 @@ use { keymap::KeymapParser, log_level::LogLevelParser, output::OutputsParser, + repeat_rate::RepeatRateParser, shortcuts::{ShortcutsParser, ShortcutsParserError}, status::StatusParser, theme::ThemeParser, @@ -95,7 +96,7 @@ impl Parser for ConfigParser<'_> { _, idle_val, ), - (explicit_sync,), + (explicit_sync, repeat_rate_val), ) = ext.extract(( ( opt(val("keymap")), @@ -121,7 +122,7 @@ impl Parser for ConfigParser<'_> { opt(val("$schema")), opt(val("idle")), ), - (recover(opt(bol("explicit-sync"))),), + (recover(opt(bol("explicit-sync"))), opt(val("repeat-rate"))), ))?; let mut keymap = None; if let Some(value) = keymap_val { @@ -256,8 +257,18 @@ impl Parser for ConfigParser<'_> { } } } + let mut repeat_rate = None; + if let Some(value) = repeat_rate_val { + match value.parse(&mut RepeatRateParser(self.0)) { + Ok(v) => repeat_rate = Some(v), + Err(e) => { + log::warn!("Could not parse the repeat rate: {}", self.0.error(e)); + } + } + } Ok(Config { keymap, + repeat_rate, shortcuts, on_graphics_initialized, on_idle, diff --git a/toml-config/src/config/parsers/repeat_rate.rs b/toml-config/src/config/parsers/repeat_rate.rs new file mode 100644 index 00000000..af16ca7b --- /dev/null +++ b/toml-config/src/config/parsers/repeat_rate.rs @@ -0,0 +1,45 @@ +use { + crate::{ + config::{ + context::Context, + extractor::{s32, Extractor, ExtractorError}, + parser::{DataType, ParseResult, Parser, UnexpectedDataType}, + RepeatRate, + }, + toml::{ + toml_span::{Span, Spanned}, + toml_value::Value, + }, + }, + indexmap::IndexMap, + thiserror::Error, +}; + +#[derive(Debug, Error)] +pub enum RepeatRateParserError { + #[error(transparent)] + Expected(#[from] UnexpectedDataType), + #[error(transparent)] + Extract(#[from] ExtractorError), +} + +pub struct RepeatRateParser<'a>(pub &'a Context<'a>); + +impl Parser for RepeatRateParser<'_> { + type Value = RepeatRate; + type Error = RepeatRateParserError; + const EXPECTED: &'static [DataType] = &[DataType::Table]; + + fn parse_table( + &mut self, + span: Span, + table: &IndexMap, Spanned>, + ) -> ParseResult { + let mut ext = Extractor::new(self.0, span, table); + let (rate, delay) = ext.extract((s32("rate"), s32("delay")))?; + Ok(RepeatRate { + rate: rate.value, + delay: delay.value, + }) + } +} diff --git a/toml-config/src/lib.rs b/toml-config/src/lib.rs index cd11f70b..d40318f8 100644 --- a/toml-config/src/lib.rs +++ b/toml-config/src/lib.rs @@ -172,6 +172,9 @@ impl Action { } }) } + Action::SetRepeatRate { rate } => { + Box::new(move || s.set_repeat_rate(rate.rate, rate.delay)) + } } } } @@ -728,6 +731,11 @@ fn load_config(initial_load: bool, persistent: &Rc) { if let Some(keymap) = config.keymap { state.set_keymap(&keymap); } + if let Some(repeat_rate) = config.repeat_rate { + persistent + .seat + .set_repeat_rate(repeat_rate.rate, repeat_rate.delay); + } on_new_connector(move |c| { for connector in &config.connectors { if connector.match_.matches(c) { diff --git a/toml-spec/spec/spec.generated.json b/toml-spec/spec/spec.generated.json index 8fa28507..560ef5b6 100644 --- a/toml-spec/spec/spec.generated.json +++ b/toml-spec/spec/spec.generated.json @@ -284,6 +284,23 @@ "keymap" ] }, + { + "description": "Sets the keyboard repeat rate.\n\n- Example:\n\n ```toml\n [shortcuts]\n alt-x = { type = \"set-repeat-rate\", rate = { rate = 25, delay = 250 } }\n ```\n", + "type": "object", + "properties": { + "type": { + "const": "set-repeat-rate" + }, + "rate": { + "description": "The rate.", + "$ref": "#/$defs/RepeatRate" + } + }, + "required": [ + "type", + "rate" + ] + }, { "description": "Sets the status command.\n\n- Example:\n\n ```toml\n [shortcuts]\n alt-j = { type = \"set-status\", status = { exec = \"i3status\" } }\n ```\n", "type": "object", @@ -418,6 +435,10 @@ "description": "The keymap to use.\n\n- Example:\n\n ```toml\n keymap = \"\"\"\n xkb_keymap {\n xkb_keycodes { include \"evdev+aliases(qwerty)\" };\n xkb_types { include \"complete\" };\n xkb_compat { include \"complete\" };\n xkb_symbols { include \"pc+us+inet(evdev)\" };\n };\n \"\"\"\n ```\n", "$ref": "#/$defs/Keymap" }, + "repeat-rate": { + "description": "The keyboard repeat rate.\n\n- Example:\n \n ```toml\n repeat-rate = { rate = 25, delay = 250 }\n ```\n", + "$ref": "#/$defs/RepeatRate" + }, "shortcuts": { "description": "The compositor shortcuts.\n\nThe keys should be in the following format:\n\n```\n(MOD-)*KEYSYM\n```\n\n`MOD` should be one of `shift`, `lock`, `ctrl`, `mod1`, `mod2`, `mod3`, `mod4`,\n`mod5`, `caps`, `alt`, `num`, or `logo`.\n\n`KEYSYM` should be the name of a keysym. The authorative location for these names\nis [1] with the `XKB_KEY_` prefix removed.\n\nThe keysym should be the unmodified keysym. E.g. `shift-q` not `shift-Q`.\n\n[1]: https://github.com/xkbcommon/libxkbcommon/blob/master/include/xkbcommon/xkbcommon-keysyms.h\n\n- Example:\n\n ```toml\n [shortcuts]\n alt-q = \"quit\"\n ```\n", "type": "object", @@ -985,6 +1006,24 @@ } ] }, + "RepeatRate": { + "description": "Describes a keyboard repeat rate.\n\n- Example:\n\n ```toml\n repeat-rate = { rate = 25, delay = 250 }\n ```\n", + "type": "object", + "properties": { + "rate": { + "type": "integer", + "description": "The number of times to repeat per second." + }, + "delay": { + "type": "integer", + "description": "The number of milliseconds after a key is pressed before repeating begins.\n" + } + }, + "required": [ + "rate", + "delay" + ] + }, "SimpleActionName": { "type": "string", "description": "The name of a `simple` Action.\n\n- Example:\n\n ```toml\n [shortcuts]\n alt-q = \"quit\"\n ```\n", diff --git a/toml-spec/spec/spec.generated.md b/toml-spec/spec/spec.generated.md index a83d4b20..eeaa716d 100644 --- a/toml-spec/spec/spec.generated.md +++ b/toml-spec/spec/spec.generated.md @@ -405,6 +405,25 @@ This table is a tagged union. The variant is determined by the `type` field. It The value of this field should be a [Keymap](#types-Keymap). +- `set-repeat-rate`: + + Sets the keyboard repeat rate. + + - Example: + + ```toml + [shortcuts] + alt-x = { type = "set-repeat-rate", rate = { rate = 25, delay = 250 } } + ``` + + The table has the following fields: + + - `rate` (required): + + The rate. + + The value of this field should be a [RepeatRate](#types-RepeatRate). + - `set-status`: Sets the status command. @@ -652,6 +671,18 @@ The table has the following fields: The value of this field should be a [Keymap](#types-Keymap). +- `repeat-rate` (optional): + + The keyboard repeat rate. + + - Example: + + ```toml + repeat-rate = { rate = 25, delay = 250 } + ``` + + The value of this field should be a [RepeatRate](#types-RepeatRate). + - `shortcuts` (optional): The compositor shortcuts. @@ -2038,6 +2069,38 @@ The table has the following fields: The value of this field should be a string. + +### `RepeatRate` + +Describes a keyboard repeat rate. + +- Example: + + ```toml + repeat-rate = { rate = 25, delay = 250 } + ``` + +Values of this type should be tables. + +The table has the following fields: + +- `rate` (required): + + The number of times to repeat per second. + + The value of this field should be a number. + + The numbers should be integers. + +- `delay` (required): + + The number of milliseconds after a key is pressed before repeating begins. + + The value of this field should be a number. + + The numbers should be integers. + + ### `SimpleActionName` diff --git a/toml-spec/spec/spec.yaml b/toml-spec/spec/spec.yaml index 560ee880..7d2e416b 100644 --- a/toml-spec/spec/spec.yaml +++ b/toml-spec/spec/spec.yaml @@ -382,6 +382,21 @@ Action: description: The keymap. required: true ref: Keymap + set-repeat-rate: + description: | + Sets the keyboard repeat rate. + + - Example: + + ```toml + [shortcuts] + alt-x = { type = "set-repeat-rate", rate = { rate = 25, delay = 250 } } + ``` + fields: + rate: + description: The rate. + required: true + ref: RepeatRate set-status: description: | Sets the status command. @@ -1649,6 +1664,17 @@ Config: }; """ ``` + repeat-rate: + ref: RepeatRate + required: false + description: | + The keyboard repeat rate. + + - Example: + + ```toml + repeat-rate = { rate = 25, delay = 250 } + ``` shortcuts: kind: map values: @@ -1983,3 +2009,27 @@ Idle: integer_only: true minimum: 0 required: false + + +RepeatRate: + kind: table + description: | + Describes a keyboard repeat rate. + + - Example: + + ```toml + repeat-rate = { rate = 25, delay = 250 } + ``` + fields: + rate: + kind: number + integer_only: true + required: true + description: The number of times to repeat per second. + delay: + kind: number + integer_only: true + required: true + description: | + The number of milliseconds after a key is pressed before repeating begins. From b03cdaa4b72ef764d8bac0ee4c08593e180cfbc1 Mon Sep 17 00:00:00 2001 From: Julian Orth Date: Fri, 5 Apr 2024 19:05:43 +0200 Subject: [PATCH 3/3] docs: re-organize documentation --- Cargo.toml | 1 + README.md | 150 +------------- docs/config.md | 455 ++++++++++++++++++++++++++++++++++++++++++ docs/features.md | 161 +++++++++++++++ docs/setup.md | 76 +++++++ jay-config/src/lib.rs | 34 ++-- 6 files changed, 717 insertions(+), 160 deletions(-) create mode 100644 docs/config.md create mode 100644 docs/features.md create mode 100644 docs/setup.md diff --git a/Cargo.toml b/Cargo.toml index c911769d..8f0a12c9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,6 +6,7 @@ build = "build/build.rs" license = "GPL-3.0-only" description = "The Jay compositor" repository = "https://github.com/mahkoh/jay" +default-run = "jay" [[bin]] name = "jay" diff --git a/README.md b/README.md index 2d4a3dab..c16d4d41 100644 --- a/README.md +++ b/README.md @@ -1,158 +1,20 @@ # Jay -Jay is a Wayland compositor written and configured in the rust programming -language with hot-reload support. Jay offers improved flexibility, -configurability, stability, and performance. +Jay is a Wayland compositor. ![screenshot.png](static/screenshot.png) -## Status +## Features -Jay is beta-quality software. For many people it should be possible to use Jay for most -of their work. Jay has a small integration test suite but sometimes there are regressions -that cause features to break. I'm currently looking for people willing to test Jay, -especially on Nvidia hardware. - -### Working Features - -The following features have been implemented and should work: - -- Tiling windows -- Floating windows -- Fullscreen -- Multiple workspaces -- Multiple monitors -- Copy/paste including middle-click paste -- Screenshots -- Screencasting -- Keyboard shortcuts -- Theming -- Configuration reload -- XWayland -- Screensaver (paused during video playback) -- Notifications (via mako) -- Video playback with synced audio (via presentation time) -- Simple games that don't require cursor grabs -- GPU reset recovery -- Screen locking -- Monitor hotplug -- Fractional scaling -- Hardware cursors -- Pointer constraints -- Selecting the primary device in multi-GPU systems -- An OpenGL backend -- A Vulkan backend -- Explicit sync - -### Missing Features - -The following features are known to be missing or broken and will be implemented -later: - -- Touch and tablet support -- Damage tracking (any kind of damage causes a complete re-render currently) - -## Native library dependencies - -Jay is written in rust and will fetch all of its rust dependencies -automatically. It is however unavoidable that Jay depends on a number of native -libraries: - -* **libinput.so**: For input event processing. -* **libgbm.so**: For graphics buffer allocation. -* **libxkbcommon.so**: For keymap handling. -* **libudev.so**: For device enumeration and hotplug support. -* **libpangocairo-1.0.so**: For text rendering. - -These libraries are usually available on any Wayland-capable system. - -## Runtime dependencies - -At runtime, Jay depends on the following services being available on the system: - -* **An up-to-date linux kernel and graphics drivers**: Jay makes aggressive use - of linux features and might not work on older systems. -* **XWayland**: For XWayland support. -* **Pipewire**: For screencasting. -* **A running X server**: For the X backend. (Only required if you want to run - Jay as an X client.) -* **Logind**: For the metal backend. (Only required if you want to run Jay from - a TTY.) -* **libEGL.so**, **libGLESv2.so**: For the OpenGL backend. -* **libvulkan.so**: For the Vulkan backend. - -## Building and Installing - -Install the latest stable version of rustc and cargo. Follow the instructions on -https://rustup.rs or use the packages provided by your distribution. Note that -only the latest stable version is supported. - -You can now build Jay using this command: -```sh -cargo build --release -``` -The resulting binary will be located at `./target/release/jay`. - -Alternatively, cargo can also install the binary for you: -```sh -cargo install --path . -``` -This will install the binary at `$HOME/.cargo/bin/jay`. If you have not already -done so, you can add `$HOME/.cargo/bin` to your path. - -## Running - -You can run Jay as a freestanding compositor or as an application under X. - -To start Jay as a freestanding compositor switch to a virtual terminal by -pressing `CTRL-ALT-F2` (or F3, F4, ...) and run -```sh -jay run -``` - -To start Jay as an X application, execute the same command from a terminal -emulator under X. - -Before running Jay as a freestanding compositor, you might want to familiarize -yourself with the [default keyboard shortcuts][shortcuts]. In particular, you -can quit Jay by typing `ALT-q`. - -[shortcuts]: ./default-config/src/lib.rs +See [features.md](./docs/features.md). ## Configuration -Jay is configured using a shared library. A good starting point for your own -configuration is the [default config crate][default]. - -[default]: ./default-config - -1. Copy this crate to a new directory. -2. In `Cargo.toml` - - Update the path dependency to point to the correct directory. - - Change the name of the crate to `my-jay-config`. -3. Make a useful change to `lib.rs`. -4. Build the crate with `cargo build`. -5. Move `target/debug/libmy_jay_config.so` to `$HOME/.config/jay/config.so`. - -When you start Jay, you will be able to make use of your useful change. At -runtime you can repeat steps 3 to 5 and reload the configuration. By default, -the shortcut to reload the configuration is `ALT-r`. - -If you want to see a more elaborate configuration, take a look at [my personal -configuration][personal]. - -[personal]: https://github.com/mahkoh/my-jay-config - -## Screensharing - -Jay supports [xdg-desktop-portal-wlr][xdpw] but Jay is not currently listed in -xdg-desktop-portal-wlr's wlr.portal file. To get screensharing to work, you have -to manually edit `/usr/share/xdg-desktop-portal/portals/wlr.portal` and add -`jay` to the `UseIn` list. +See [config.md](./docs/config.md). -In the future, Jay will provide a desktop portal itself. +## Building and Setup -[xdpw]: https://github.com/emersion/xdg-desktop-portal-wlr +See [setup.md](./docs/setup.md). ## License diff --git a/docs/config.md b/docs/config.md new file mode 100644 index 00000000..345b35b0 --- /dev/null +++ b/docs/config.md @@ -0,0 +1,455 @@ +# Configuration + +Jay can be configured via + +- a declarative TOML file or +- a shared library that gets injected into the compositor. + +## Shared Library Configuration + +This is described in the [rustdoc](https://docs.rs/jay-config) of the configuration crate. + +## TOML Configuration + +The configuration file is stored under `$HOME/.config/jay/config.toml`. +If you don't have such a file, the default configuration will be used. + +The full format of this file is described in the auto-generated file [spec.generated.md](../toml-spec/spec/spec.generated.md). +You can also get auto completion with the auto-generated JSON Schema linked from that document. + +The following code block contains the annotated default configuration. +Below that we will describe individual usecases. + +```toml +# The keymap that is used for shortcuts and also sent to clients. +keymap = """ + xkb_keymap { + xkb_keycodes { include "evdev+aliases(qwerty)" }; + xkb_types { include "complete" }; + xkb_compat { include "complete" }; + xkb_symbols { include "pc+us+inet(evdev)" }; + }; + """ + +# An action that will be executed when the GPU has been initialized. +on-graphics-initialized = { type = "exec", exec = { prog = "mako", privileged = true } } + +# Shortcuts that are processed by the compositor. +# The left hand side should be a key, possibly prefixed with modifiers. +# The right hand side should be an action. +[shortcuts] +# The focus-X actions move the keyboard focus to next window on the X. +alt-h = "focus-left" +alt-j = "focus-down" +alt-k = "focus-up" +alt-l = "focus-right" + +# The move-X actions move window that has the keyboard focus to the X. +alt-shift-h = "move-left" +alt-shift-j = "move-down" +alt-shift-k = "move-up" +alt-shift-l = "move-right" + +# The split-X action places the currently focused window in a container +# and sets the split direction of the container to X. +alt-d = "split-horizontal" +alt-v = "split-vertical" + +# The toggle-split action changes the split direction of the current +# container. +alt-t = "toggle-split" +# The toggle-mono action changes whether the current container shows +# a single window or all windows next to each other. +alt-m = "toggle-mono" +# The toggle-fullscreen action toggles the current window between +# windowed and fullscreen. +alt-u = "toggle-fullscreen" + +# The focus-parent action moves the keyboard focus to the parrent of +# the currently focused window. +alt-f = "focus-parent" +# The close action requests the currently focused window to close. +alt-shift-c = "close" +# The toggle-floating action changes the currently focused window between +# floating and tiled. +alt-shift-f = "toggle-floating" + +# All actions above are so-called simple actions that are identified by +# a string. More complex actions take parameters and are written as a table. +# For example, the exec action spawns an application and has the exec field +# that describes how to spawn the application. +Super_L = { type = "exec", exec = "alacritty" } +alt-p = { type = "exec", exec = "bemenu-run" } + +# The quit action terminates the compositor. +alt-q = "quit" +# The reload-config-toml action reloads the TOML configuration file. +alt-shift-r = "reload-config-toml" + +# The switch-to-vt action switches to a different virtual terminal. +ctrl-alt-F1 = { type = "switch-to-vt", num = 1 } +ctrl-alt-F2 = { type = "switch-to-vt", num = 2 } +ctrl-alt-F3 = { type = "switch-to-vt", num = 3 } +ctrl-alt-F4 = { type = "switch-to-vt", num = 4 } +ctrl-alt-F5 = { type = "switch-to-vt", num = 5 } +ctrl-alt-F6 = { type = "switch-to-vt", num = 6 } +ctrl-alt-F7 = { type = "switch-to-vt", num = 7 } +ctrl-alt-F8 = { type = "switch-to-vt", num = 8 } +ctrl-alt-F9 = { type = "switch-to-vt", num = 9 } +ctrl-alt-F10 = { type = "switch-to-vt", num = 10 } +ctrl-alt-F11 = { type = "switch-to-vt", num = 11 } +ctrl-alt-F12 = { type = "switch-to-vt", num = 12 } + +# The show-workspace action switches to a workspace. If the workspace is not +# currently being used, it is created on the output that contains the pointer. +alt-F1 = { type = "show-workspace", name = "1" } +alt-F2 = { type = "show-workspace", name = "2" } +alt-F3 = { type = "show-workspace", name = "3" } +alt-F4 = { type = "show-workspace", name = "4" } +alt-F5 = { type = "show-workspace", name = "5" } +alt-F6 = { type = "show-workspace", name = "6" } +alt-F7 = { type = "show-workspace", name = "7" } +alt-F8 = { type = "show-workspace", name = "8" } +alt-F9 = { type = "show-workspace", name = "9" } +alt-F10 = { type = "show-workspace", name = "10" } +alt-F11 = { type = "show-workspace", name = "11" } +alt-F12 = { type = "show-workspace", name = "12" } + +# The move-to-workspace action moves the currently focused window to a workspace. +alt-shift-F1 = { type = "move-to-workspace", name = "1" } +alt-shift-F2 = { type = "move-to-workspace", name = "2" } +alt-shift-F3 = { type = "move-to-workspace", name = "3" } +alt-shift-F4 = { type = "move-to-workspace", name = "4" } +alt-shift-F5 = { type = "move-to-workspace", name = "5" } +alt-shift-F6 = { type = "move-to-workspace", name = "6" } +alt-shift-F7 = { type = "move-to-workspace", name = "7" } +alt-shift-F8 = { type = "move-to-workspace", name = "8" } +alt-shift-F9 = { type = "move-to-workspace", name = "9" } +alt-shift-F10 = { type = "move-to-workspace", name = "10" } +alt-shift-F11 = { type = "move-to-workspace", name = "11" } +alt-shift-F12 = { type = "move-to-workspace", name = "12" } +``` + +### Configuring Keymaps and Repeat Rates + +The keymap can be configured via the top-level `keymap` field. + +```toml +keymap = """ + xkb_keymap { + xkb_keycodes { include "evdev+aliases(qwerty)" }; + xkb_types { include "complete" }; + xkb_compat { include "complete" }; + xkb_symbols { include "pc+us+inet(evdev)" }; + }; + """ +``` + +The format is described in the ArchWiki: https://wiki.archlinux.org/title/X_keyboard_extension + +If you want to use multiple keymaps, you can assign names to them: + +```toml +keymap.name = "laptop" + +[[keymaps]] +name = "laptop" +path = "./laptop-keymap.xkb" + +[[keymaps]] +name = "external" +path = "./external-keymap.xkb" +``` + +Such paths are relative to the configuration file. +You can also write the map inline in this format: + +```toml +[[keymaps]] +name = "external" +map = "..." +``` + +If you want to switch the keymap with a shortcut, use the `set-keymap` action: + +```toml +[shortcuts] +alt-j = { type = "set-keymap", keymap.name = "laptop" } +alt-k = { type = "set-keymap", keymap.name = "external" } +``` + +The keyboard repeat rate is configured via the top-level `repeat-rate` field. + +```toml +repeat-rate = { rate = 25, delay = 250 } +``` + +You can change this at runtime with the `set-repeat-rate` action: + +```toml +[shortcuts] +alt-x = { type = "set-repeat-rate", rate = { rate = 25, delay = 250 } } +``` + +Note that you can change all of this from the command line with the `jay input` command. + +### Configuring Shortcuts + +Shortcuts are configured in the top-level `shortcuts` table. + +```toml +[shortcuts] +alt-h = "focus-left" +``` + +The left-hand side should be a key that can optionally be prefixed with modifiers. + +The right-hand side should be an action. + +See [spec.generated.md](../toml-spec/spec/spec.generated.md) for a full list of actions. + +### Running Multiple Actions + +In every place that accepts an action, you can also run multiple actions by wrapping them +in an array: + +```toml +[shortcuts] +alt-h = ["focus-left", "focus-up"] +``` + +### Spawning Applications + +You can spawn applications by using the `exec` action: + +```toml +Super_L = { type = "exec", exec = "alacritty" } +``` + +The `exec` field can be either a string, an array of strings, or a table. + +When a string is used, it should be the name of the application. + +When an array is used, it should be the name of the application followed by arguments. + +```toml +Super_L = { type = "exec", exec = ["alacritty", "-e", "date"] } +``` + +When a table is used, you can additionally specify + +- environment variables to pass to the application, +- whether the application should have access to privileged protocols. + +See the specification for more details. + +### Running an Action at Startup + +If you want to run an action at startup, you can use the top-level `on-graphics-initialized` +field: + +```toml +on-graphics-initialized = { type = "exec", exec = { prog = "mako", privileged = true } } +``` + +### Setting Environment Variables + +You can set environment variables with the the top level `env` table. + +```toml +[env] +GTK_THEME = "Adwaita:dark" +``` + +These environment variables are passed to all applications started afterwards. + +You can also use the `set-env` action to modify these variables: + +```toml +[shortcuts] +alt-l = { type = "set-env", env.GTK_THEME = "Adwaita:dark" } +``` + +The `unset-env` action is similar. +See the specification for more details. + +### Using a Status Program + +You can configure a status program with the top-level `status` table. + +```toml +[status] +format = "i3bar" +exec = "i3status" +``` + +The `format` field specifies the format used by the status program. +Possible values are `plain`, `pango`, and `i3bar`. + +The `exec` field specifies how to start the status program. + +Note that i3status will not automatically use i3bar format when started this way. +You have to explicitly opt into i3bar format in your i3status configuration. + +See the specification for more details. + +### Configuring Idle Timeout and Actions + +You can configure the idle timeout with the top-level `idle` table. + +```toml +idle.minutes = 10 +``` + +If you want to lock the screen when this timeout happens, you can use the `on-idle` table. + +```toml +on-idle = { type = "exec", exec = { prog = "swaylock", privileged = "true" } } +``` + +See the specification for more details. + +### Configuring GPUs + +You can configure GPUs with the top-level `drm-devices` array. + +```toml +[[drm-devices]] +name = "dedicated" +match = { pci-vendor = 0x1002, pci-model = 0x73ff } + +[[drm-devices]] +name = "integrated" +match = { pci-vendor = 0x1002, pci-model = 0x164e } +gfx-api = "OpenGl" +``` + +For each device, you can configure the following properties: + +- Whether direct scanout is enabled on monitors connected to this device. +- Which API to use for this device (OpenGL or Vulkan). + +You can assign names to these device to refer to them elsewhere. + +The `match` field is used to identify the device. +Unless you have two identical graphics cards installed, using the pci-vendor and model +fields is usually the best choice. +You can get these values by running `jay randr`. + +You can select the device used for rendering the desktop with the top-level `render-device` field. + +```toml +render-device.name = "dedicated" +``` + +You can modify the render device and configure GPUs at runtime with the `set-render-device` +and `configure-drm-device` actions. + +You can use the top-level `gfx-api` field to set the default API used (unless overwritten for specific device). + +```toml +gfx-api = "Vulkan" +``` + +See the specification for more details. + +### Configuring Monitors + +You can configure monitors with the top-level `outputs` field. + +```toml +[[outputs]] +name = "left" +match.serial-number = "33K03894SL0" +x = 0 +y = 0 + +[[outputs]] +name = "right" +match.serial-number = "ETW1M02062SL0" +x = 1920 +y = 0 +``` + +For each output, you can configure the following properties: + +- The x, y coordinates in global compositor space. +- The scale to use for the monitor. +- The transformation to apply to the content (rotation, mirroring). +- The mode to use for the monitor. + +You can query the available modes and modify these properties from the command line with +the `jay randr` command. + +The `match` field selects the monitors the configuration applies to. +The serial number is usually a good unique identifier. + +You can assign a name to monitors to refer to them in other places. + +You can use the `configure-output` action to change this configuration at runtime. + +See the specification for more details. + +### Configuring Connectors + +Connectors are the physical ports at the back of your GPU. +You can configure them with the top-level `connectors` array. + +```toml +[[connectors]] +name = "eDP-1" +enabled = false +``` + +Currently you can only use this to disable or enable connectors. +This is useful to disable the internal monitor of a laptop when the laptop is closed. + +You can use the `configure-connector` action to change this configuration at runtime. + +See the specification for more details. + +### Configuring Input Devices + +You can configure input devices with the top-level `inputs` array. + +```toml +[[inputs]] +tag = "mice" +match.is-pointer = true +left-handed = true +transform-matrix = [[0.35, 0], [0, 0.35]] +tap-enabled = true +``` + +For each input device you can configure the following properties: + +- The libinput acceleration profile. +- The libinput acceleration speed. +- The libinput tap setting. +- The libinput tap-drag setting. +- The libinput tap-drag-lock setting. +- The libinput left-handed setting. +- The libinput natural-scrolling setting. +- The number of pixels to scroll per scroll-wheel dedent. +- A transformation matrix to apply to relative movements. + +You can inspect and modify these settings from the command line with the `jay input` command. + +The `match` field selects the input devices to operate on. + +You can assign a `tag` to input devices to refer to them elsewhere. + +You can use the `configure-input` action to change these settings at runtime. + +See the specification for more details. + +# Theming + +You can configure the colors, sizes, and fonts used by the compositor with the top-level `theme` table. + +```toml +[theme] +bg-color = "#ff000" +``` + +See the specification for more details. diff --git a/docs/features.md b/docs/features.md new file mode 100644 index 00000000..b4c188fa --- /dev/null +++ b/docs/features.md @@ -0,0 +1,161 @@ +# Features + +## Configuration + +Jay can be configured via + +- a declarative TOML file or +- a shared library that gets injected into the compositor. + +See [config.md](config.md) for more details. + +## i3 Look and Feel + +Jay's appearance is based on the default i3 look and feel. + +Colors, sizes, and fonts can be customized. + +## Stability + +Jay has been stable for a long time. +Crashes and incorrect behavior in released versions are very rare. + +Jay also aims to be forward and backward compatible for existing setups, allowing you to +upgrade or downgrade the compositor without having to adjust your configuration. + +There is a small but growing integration test suite that is used to ensure this. + +## CLI + +Jay has a CLI that can be used to configure the compositor at runtime. + +``` +~$ jay +A wayland compositor + +Usage: jay [OPTIONS] + +Commands: + run Run the compositor + generate-completion Generate shell completion scripts for jay + log Open the log file + set-log-level Sets the log level + quit Stop the compositor + unlock Unlocks the compositor + screenshot Take a screenshot + idle Inspect/modify the idle (screensaver) settings + run-privileged Run a privileged program + seat-test Tests the events produced by a seat + portal Run the desktop portal + randr Inspect/modify graphics card and connector settings + input Inspect/modify input settings + help Print this message or the help of the given subcommand(s) + +Options: + --log-level The log level [default: info] [possible values: trace, debug, info, warn, error] + -h, --help Print help +``` + +## Multi-Monitor Support + +Jay can be used with multiple monitors with hot-plug and hot-unplug support. +When a monitor is unplugged, all workspaces are automatically moved one of the remaining +monitors. +When the monitor is plugged in again, these workspaces are restored. + +## Multi-GPU Support + +Jay can be used with multiple GPUs and monitors connected to different GPUs. +One GPU is always used for rendering the desktop. +You can change this GPU at runtime. + +## Screen Sharing + +Jay supports screen sharing via xdg-desktop-portal. + +## Screen Locking + +Jay can automatically lock your screen and disable outputs after inactivity. + +## Notifications + +Jay supports the zwlr_layer_shell_v1 protocol used by notification daemons. + +## Fractional Scaling + +Jay supports per-monitor fractional scaling. + +## OpenGL and Vulkan + +Jay can use either OpenGL or Vulkan for rendering. +Vulkan offers better performance and memory usage but OpenGL is still provided for +older hardware. + +You can change the API at runtime without restarting the compositor. + +## Explicit Sync + +Jay supports explicit sync for compatibility with Nvidia hardware. + +## Clipboard Managers + +Jay supports clipboard managers via `zwlr_data_control_manager_v1`. + +## Privilege Separation + +Jay splits protocols into unprivileged and privileged protocols. +By default, applications only have access to unprivileged protocols. + +You can explicitly opt into giving applications access to privileged protocols via the Jay CLI or shortcuts. + +## Protocol Support + +Jay supports the following wayland protocols: + +| Global | Version | Privileged | +|-----------------------------------------|:-----------------|------------| +| ext_foreign_toplevel_list_v1 | 1 | Yes | +| ext_idle_notifier_v1 | 1 | Yes | +| ext_session_lock_manager_v1 | 1 | Yes | +| org_kde_kwin_server_decoration_manager | 1 | | +| wl_compositor | 6[^no_touch] | | +| wl_data_device_manager | 3 | | +| wl_drm | 2 | | +| wl_output | 4 | | +| wl_seat | 9 | | +| wl_shm | 2 | | +| wl_subcompositor | 1 | | +| wp_content_type_manager_v1 | 1 | | +| wp_cursor_shape_manager_v1 | 1 | | +| wp_fractional_scale_manager_v1 | 1 | | +| wp_linux_drm_syncobj_manager_v1 | 1 | | +| wp_presentation | 1 | | +| wp_single_pixel_buffer_manager_v1 | 1 | | +| wp_tearing_control_manager_v1 | 1[^no_tearing] | | +| wp_viewporter | 1 | | +| xdg_activation_v1 | 1 | | +| xdg_toplevel_drag_manager_v1 | 1 | | +| xdg_wm_base | 6 | | +| zwlr_data_control_manager_v1 | 2 | Yes | +| zwlr_layer_shell_v1 | 4[^no_exclusive] | Yes | +| zwlr_screencopy_manager_v1 | 3 | Yes | +| zwp_idle_inhibit_manager_v1 | 1 | | +| zwp_linux_dmabuf_v1 | 5 | | +| zwp_pointer_constraints_v1 | 1 | | +| zwp_primary_selection_device_manager_v1 | 1 | | +| zwp_relative_pointer_manager_v1 | 1 | | +| zxdg_decoration_manager_v1 | 1 | | +| zxdg_output_manager_v1 | 3 | | + +[^no_touch]: Touch input is not supported. +[^no_tearing]: Tearing screen updates are not supported. +[^no_exclusive]: Exclusive zones are not supported. + +## Missing Features + +The following features are currently not supported but might get implemented in the future: + +- Fine-grained damage tracking. +- Touch support. +- Tablet support. +- Tearing updates of fullscreen games. diff --git a/docs/setup.md b/docs/setup.md new file mode 100644 index 00000000..444d1f75 --- /dev/null +++ b/docs/setup.md @@ -0,0 +1,76 @@ +# Building + +## Compile-time Dependencies + +The following libraries must be installed before compiling Jay: + +- libinput.so +- libgbm.so +- libxkbcommon.so +- libudev.so +- libpangocairo-1.0.so + +You must also have a C compiler (GCC or Clang) and the latest version of rust installed. +You can install rust with [rustup](https://rustup.rs/). + +## Runtime Dependencies + +Most of these dependencies are optional and will enable additional features. + +- Linux 6.7: Required for explicit sync. +- Xwayland: Required for running X applications. +- Pipewire: Required for screen sharing. +- logind (part of systemd): Required when running Jay from a virtual terminal. +- libEGL.so and libGLESv2.so: Required for the OpenGL renderer. +- libvulkan.so: Required for the Vulkan renderer. + +Note that Jay will not work if neither the OpenGL nor the Vulkan renderer are available. + +## Compiling + +To compile the latest stable version of Jay, run + +``` +cargo install --locked jay-compositor +``` + +This will install Jay under `$HOME/.cargo/bin/jay`. + +If you want to use the latest version from git, run + +``` +cargo install --locked --git https://github.com/mahkoh/jay.git jay +``` + +If you only want to build Jay without installing it, run the following command from within this repository: + +``` +cargo build --release +``` + +The binary is then available under `./target/release/jay`. + +# Setup + +## Configuration + +See [config.md](./config.md). + +## Screen Sharing + +This step is only required to enable screen sharing. + +1. Copy `../etc/jay.portal` to `/usr/share/xdg-desktop-portal/portals/jay.portal`. +2. Copy `../etc/jay-portals.conf` to `/usr/share/xdg-desktop-portal/jay-portals.conf`. + +Then restart `xdg-deskop-portal`. + +# Running + +1. Switch to a virtual terminal by pressing `ctrl-alt-F2` (or F3, F4, ...). +2. Run `jay run`. + +If you have not yet changed the default configuration, you can + +- quit Jay by pressing `alt-q`, +- start Alacritty by pressing the left Windows key. diff --git a/jay-config/src/lib.rs b/jay-config/src/lib.rs index 4356d23f..0b94684e 100644 --- a/jay-config/src/lib.rs +++ b/jay-config/src/lib.rs @@ -3,32 +3,34 @@ //! A minimal example configuration looks as follows: //! //! ```rust -//! use jay_config::config; -//! -//! fn configure() { -//! -//! } -//! -//! config!(configure); -//! ``` -//! -//! This configuration will not allow you to exit the compositor. -//! To add at least that much functionality, add the following code to `configure`: -//! -//! ```rust -//! use jay_config::{config, quit}; -//! use jay_config::input::{get_default_seat, input_devices, on_new_input_device}; +//! use jay_config::{config, quit, reload}; +//! use jay_config::input::get_default_seat; //! use jay_config::keyboard::mods::ALT; -//! use jay_config::keyboard::syms::SYM_q; +//! use jay_config::keyboard::syms::{SYM_q, SYM_r}; //! //! fn configure() { //! let seat = get_default_seat(); //! // Create a key binding to exit the compositor. //! seat.bind(ALT | SYM_q, || quit()); +//! // Reload the configuration. +//! seat.bind(ALT | SYM_r, || reload()); //! } //! //! config!(configure); //! ``` +//! +//! You should configure your crate to be compiled as a shared library: +//! +//! ```toml +//! [lib] +//! crate-type = ["cdylib"] +//! ``` +//! +//! After compiling it, copy the shared library to `$HOME/.config/jay/config.so` and restart +//! the compositor. It should then use your configuration file. +//! +//! Note that you do not have to restart the compositor every time you want to reload your +//! configuration afterwards. Instead, simply invoke the [`reload`] function via a shortcut. #![allow( clippy::zero_prefixed_literal,