1
0
Fork 0
forked from wry/wry

Merge pull request #152 from mahkoh/jorth/release-cleanup

Various changes for the first stable release
This commit is contained in:
mahkoh 2024-04-05 20:42:18 +02:00 committed by GitHub
commit 1f9797d76d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
23 changed files with 990 additions and 183 deletions

18
Cargo.lock generated
View file

@ -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",

View file

@ -1,8 +1,16 @@
[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"
default-run = "jay"
[[bin]]
name = "jay"
path = "src/main.rs"
[workspace]
members = ["jay-config", "toml-config", "algorithms", "toml-spec"]
@ -14,6 +22,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 +41,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 +66,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"]

150
README.md
View file

@ -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].
See [config.md](./docs/config.md).
[default]: ./default-config
## Building and Setup
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.
In the future, Jay will provide a desktop portal itself.
[xdpw]: https://github.com/emersion/xdg-desktop-portal-wlr
See [setup.md](./docs/setup.md).
## License

View file

@ -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"] }

455
docs/config.md Normal file
View file

@ -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.

161
docs/features.md Normal file
View file

@ -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] <COMMAND>
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 <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.

76
docs/setup.md Normal file
View file

@ -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.

View file

@ -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"

View file

@ -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,

View file

@ -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,
};

View file

@ -5,7 +5,7 @@ mod tests;
pub use region::RegionBuilder;
use {
algorithms::rect::RectRaw,
jay_algorithms::rect::RectRaw,
smallvec::SmallVec,
std::fmt::{Debug, Formatter},
};

View file

@ -1,6 +1,6 @@
use {
crate::rect::{Rect, Region},
algorithms::rect::{
jay_algorithms::rect::{
region::{extents, rects_to_bands, subtract, union},
RectRaw,
},

View file

@ -1,6 +1,6 @@
use {
crate::rect::{Rect, Region},
algorithms::rect::RectRaw,
jay_algorithms::rect::RectRaw,
};
#[test]

View file

@ -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"]

View file

@ -117,6 +117,9 @@ pub enum Action {
workspace: Option<Workspace>,
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<ConfigKeymap>,
pub repeat_rate: Option<RepeatRate>,
pub shortcuts: Vec<(ModifiedKeySym, Action)>,
pub on_graphics_initialized: Option<Action>,
pub on_idle: Option<Action>,

View file

@ -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;

View file

@ -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<Self> {
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));

View file

@ -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,

View file

@ -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<String>, Spanned<Value>>,
) -> ParseResult<Self> {
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,
})
}
}

View file

@ -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<PersistentState>) {
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) {

View file

@ -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",

View file

@ -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.
<a name="types-RepeatRate"></a>
### `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.
<a name="types-SimpleActionName"></a>
### `SimpleActionName`

View file

@ -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.