all: split reusable components into workspace crates
This commit is contained in:
parent
2a079ed800
commit
657e7ce2f7
225 changed files with 7422 additions and 17602 deletions
95
Cargo.lock
generated
95
Cargo.lock
generated
|
|
@ -639,6 +639,13 @@ dependencies = [
|
|||
"libloading",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "jay-cmm"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"jay-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "jay-compositor"
|
||||
version = "1.12.0"
|
||||
|
|
@ -665,8 +672,17 @@ dependencies = [
|
|||
"isnt 0.2.0",
|
||||
"jay-algorithms",
|
||||
"jay-ash",
|
||||
"jay-cmm",
|
||||
"jay-config",
|
||||
"jay-criteria",
|
||||
"jay-edid",
|
||||
"jay-formats",
|
||||
"jay-geometry",
|
||||
"jay-layout-animation",
|
||||
"jay-time",
|
||||
"jay-toml-config",
|
||||
"jay-units",
|
||||
"jay-utils",
|
||||
"kbvm",
|
||||
"libloading",
|
||||
"linearize",
|
||||
|
|
@ -711,6 +727,60 @@ dependencies = [
|
|||
"uapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "jay-config-schema"
|
||||
version = "0.1.0"
|
||||
|
||||
[[package]]
|
||||
name = "jay-criteria"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"ahash",
|
||||
"jay-utils",
|
||||
"linearize",
|
||||
"regex",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "jay-edid"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"bstr",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "jay-formats"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"ahash",
|
||||
"clap",
|
||||
"jay-ash",
|
||||
"jay-config",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "jay-geometry"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"jay-algorithms",
|
||||
"smallvec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "jay-layout-animation"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"jay-geometry",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "jay-time"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"uapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "jay-toml-config"
|
||||
version = "0.12.0"
|
||||
|
|
@ -720,6 +790,7 @@ dependencies = [
|
|||
"error_reporter",
|
||||
"indexmap",
|
||||
"jay-config",
|
||||
"jay-config-schema",
|
||||
"kbvm",
|
||||
"log",
|
||||
"phf",
|
||||
|
|
@ -731,6 +802,30 @@ dependencies = [
|
|||
"walkdir",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "jay-units"
|
||||
version = "0.1.0"
|
||||
|
||||
[[package]]
|
||||
name = "jay-utils"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"ahash",
|
||||
"arrayvec",
|
||||
"bstr",
|
||||
"cfg-if",
|
||||
"isnt 0.2.0",
|
||||
"jay-config",
|
||||
"linearize",
|
||||
"log",
|
||||
"parking_lot",
|
||||
"rand 0.10.0",
|
||||
"serde",
|
||||
"smallvec",
|
||||
"thiserror",
|
||||
"uapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "js-sys"
|
||||
version = "0.3.91"
|
||||
|
|
|
|||
29
Cargo.toml
29
Cargo.toml
|
|
@ -13,7 +13,25 @@ name = "jay"
|
|||
path = "src/main.rs"
|
||||
|
||||
[workspace]
|
||||
members = ["jay-config", "toml-config", "algorithms", "toml-spec", "wire-to-xml", "xml-to-wire"]
|
||||
resolver = "3"
|
||||
members = [
|
||||
"jay-config",
|
||||
"jay-config-schema",
|
||||
"geometry",
|
||||
"layout-animation",
|
||||
"formats",
|
||||
"edid",
|
||||
"units",
|
||||
"utils",
|
||||
"criteria",
|
||||
"cmm",
|
||||
"time",
|
||||
"toml-config",
|
||||
"algorithms",
|
||||
"toml-spec",
|
||||
"wire-to-xml",
|
||||
"xml-to-wire",
|
||||
]
|
||||
|
||||
[profile.release]
|
||||
panic = "abort"
|
||||
|
|
@ -26,6 +44,15 @@ panic = "abort"
|
|||
jay-config = { version = "1.10.0", path = "jay-config" }
|
||||
jay-toml-config = { version = "0.12.0", path = "toml-config" }
|
||||
jay-algorithms = { version = "0.4.0", path = "algorithms" }
|
||||
jay-geometry = { version = "0.1.0", path = "geometry" }
|
||||
jay-layout-animation = { version = "0.1.0", path = "layout-animation" }
|
||||
jay-formats = { version = "0.1.0", path = "formats" }
|
||||
jay-edid = { version = "0.1.0", path = "edid" }
|
||||
jay-units = { version = "0.1.0", path = "units" }
|
||||
jay-utils = { version = "0.1.0", path = "utils" }
|
||||
jay-criteria = { version = "0.1.0", path = "criteria" }
|
||||
jay-cmm = { version = "0.1.0", path = "cmm" }
|
||||
jay-time = { version = "0.1.0", path = "time" }
|
||||
|
||||
uapi = "0.2.13"
|
||||
thiserror = "2.0.11"
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
[](http://crates.io/crates/jay-compositor)
|
||||
|
||||
Jay is a Wayland compositor for Linux with an i3-like tiling layout,
|
||||
Vulkan and OpenGL rendering, multi-GPU support, screen sharing, and more.
|
||||
Vulkan and OpenGL rendering, multi-GPU support, and more.
|
||||
|
||||

|
||||
|
||||
|
|
|
|||
|
|
@ -35,7 +35,6 @@
|
|||
- [Mouse Interactions](mouse.md)
|
||||
- [Input Modes](input-modes.md)
|
||||
- [Window & Client Rules](window-rules.md)
|
||||
- [Screen Sharing](screen-sharing.md)
|
||||
- [HDR & Color Management](hdr.md)
|
||||
|
||||
# Reference
|
||||
|
|
|
|||
|
|
@ -674,18 +674,6 @@ Show color management status:
|
|||
|
||||
## Other Commands
|
||||
|
||||
### `jay portal`
|
||||
|
||||
Run the Jay desktop portal (provides screen sharing and other XDG desktop
|
||||
portal interfaces):
|
||||
|
||||
```shell
|
||||
~$ jay portal
|
||||
```
|
||||
|
||||
Normally the portal is started automatically. This command is for running it
|
||||
manually or debugging.
|
||||
|
||||
### `jay seat-test`
|
||||
|
||||
Test input events from a seat. Prints all keyboard, pointer, touch, gesture,
|
||||
|
|
@ -697,24 +685,6 @@ tablet, and switch events to stdout:
|
|||
~$ jay seat-test -a # test all seats simultaneously
|
||||
```
|
||||
|
||||
### `jay run-privileged`
|
||||
|
||||
Run a program with access to a privileged Wayland socket:
|
||||
|
||||
```shell
|
||||
~$ jay run-privileged my-program --arg1
|
||||
```
|
||||
|
||||
### `jay run-tagged`
|
||||
|
||||
Run a program with a tagged Wayland connection. All Wayland connections from the
|
||||
spawned process tree will carry the specified tag, which can be matched in
|
||||
[client rules](window-rules.md):
|
||||
|
||||
```shell
|
||||
~$ jay run-tagged my-tag firefox
|
||||
```
|
||||
|
||||
### `jay generate-completion`
|
||||
|
||||
Generate shell completion scripts:
|
||||
|
|
|
|||
|
|
@ -62,16 +62,10 @@ on-idle = {
|
|||
type = "exec",
|
||||
exec = {
|
||||
prog = "swaylock",
|
||||
privileged = true,
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
> [!IMPORTANT]
|
||||
> Screen lockers that use the Wayland session lock protocol (like swaylock)
|
||||
> need `privileged = true` in the exec configuration. This grants the process
|
||||
> the necessary permissions to lock the session.
|
||||
|
||||
You can also combine multiple actions:
|
||||
|
||||
```toml
|
||||
|
|
@ -80,7 +74,6 @@ on-idle = [
|
|||
type = "exec",
|
||||
exec = {
|
||||
prog = "swaylock",
|
||||
privileged = true,
|
||||
},
|
||||
},
|
||||
{ type = "exec", exec = ["notify-send", "System locked"] },
|
||||
|
|
@ -100,7 +93,6 @@ on-idle = {
|
|||
type = "exec",
|
||||
exec = {
|
||||
prog = "swaylock",
|
||||
privileged = true,
|
||||
},
|
||||
}
|
||||
```
|
||||
|
|
|
|||
|
|
@ -30,9 +30,8 @@ the color management protocol.
|
|||
## Libei
|
||||
|
||||
[libei](https://gitlab.freedesktop.org/libinput/libei) allows applications to
|
||||
emulate input events. By default, applications can only access libei through
|
||||
the portal (which prompts the user for permission). Setting `enable-socket`
|
||||
exposes an unauthenticated socket that any application can use without a prompt.
|
||||
emulate input events. Setting `enable-socket` exposes an unauthenticated socket
|
||||
that any application can use.
|
||||
|
||||
```toml
|
||||
libei.enable-socket = false # default
|
||||
|
|
|
|||
|
|
@ -145,7 +145,6 @@ alt-shift-r = "reload-config-toml"
|
|||
(the next pressed key identifies the mark). See [Marks](#marks) below.
|
||||
- `enable-window-management`, `disable-window-management` -- programmatically
|
||||
enable or disable [window management mode](../floating.md#window-management-mode)
|
||||
- `reload-config-so` -- reload the shared-library configuration (`config.so`)
|
||||
|
||||
See the [specification](https://github.com/mahkoh/jay/blob/master/toml-spec/spec/spec.generated.md) for the full list of simple
|
||||
actions.
|
||||
|
|
@ -309,7 +308,6 @@ alt-s = {
|
|||
type = "exec",
|
||||
exec = {
|
||||
shell = "grim - | wl-copy",
|
||||
privileged = true,
|
||||
},
|
||||
}
|
||||
```
|
||||
|
|
@ -328,12 +326,6 @@ Table fields:
|
|||
`env`
|
||||
: Per-process environment variables
|
||||
|
||||
`privileged`
|
||||
: If `true`, grants access to privileged Wayland protocols (default: `false`)
|
||||
|
||||
`tag`
|
||||
: Tag to apply to all Wayland connections spawned by this process
|
||||
|
||||
### Practical examples
|
||||
|
||||
Volume control with `pactl`:
|
||||
|
|
@ -362,7 +354,6 @@ Print = {
|
|||
type = "exec",
|
||||
exec = {
|
||||
shell = "grim - | wl-copy",
|
||||
privileged = true,
|
||||
},
|
||||
}
|
||||
```
|
||||
|
|
|
|||
|
|
@ -63,15 +63,10 @@ on-idle = {
|
|||
type = "exec",
|
||||
exec = {
|
||||
prog = "swaylock",
|
||||
privileged = true,
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
> [!NOTE]
|
||||
> Screen lockers need `privileged = true` to access the privileged Wayland
|
||||
> protocols required for locking the session.
|
||||
|
||||
You can combine idle with a grace period. The idle timeout and grace period are
|
||||
configured separately in the `[idle]` section (see [Idle & Screen
|
||||
Locking](idle.md)):
|
||||
|
|
@ -83,7 +78,6 @@ on-idle = {
|
|||
type = "exec",
|
||||
exec = {
|
||||
prog = "swaylock",
|
||||
privileged = true,
|
||||
},
|
||||
}
|
||||
```
|
||||
|
|
@ -97,7 +91,6 @@ on-idle = [
|
|||
type = "exec",
|
||||
exec = {
|
||||
prog = "swaylock",
|
||||
privileged = true,
|
||||
},
|
||||
},
|
||||
]
|
||||
|
|
|
|||
|
|
@ -73,7 +73,7 @@ The available color keys in the `[theme]` table are:
|
|||
|
||||
"Focused-inactive" refers to a window that was most recently focused in its
|
||||
container but whose container is not the active one. The "captured" colors apply
|
||||
when a window is being recorded (e.g. via screen sharing).
|
||||
when a window is being captured.
|
||||
|
||||
### Example
|
||||
|
||||
|
|
|
|||
|
|
@ -87,5 +87,5 @@ Xwayland client itself:
|
|||
```toml
|
||||
[[clients]]
|
||||
match.is-xwayland = true
|
||||
# ... grant capabilities, etc.
|
||||
# ... configure client-specific behavior
|
||||
```
|
||||
|
|
|
|||
|
|
@ -61,10 +61,7 @@ Commands:
|
|||
unlock Unlocks the compositor
|
||||
screenshot Take a screenshot
|
||||
idle Inspect/modify the idle (screensaver) settings
|
||||
run-privileged Run a privileged program
|
||||
run-tagged Run a program with a connection tag
|
||||
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
|
||||
xwayland Inspect/modify xwayland settings
|
||||
|
|
@ -101,17 +98,6 @@ runtime.
|
|||
|
||||
See [GPUs](configuration/gpu.md) for details.
|
||||
|
||||
## Screen Sharing
|
||||
|
||||
Jay supports screen sharing via xdg-desktop-portal. Three capture modes are
|
||||
available:
|
||||
|
||||
- **Window capture** -- share a single window.
|
||||
- **Output capture** -- share an entire monitor.
|
||||
- **Workspace capture** -- like output capture, but only one workspace is shown.
|
||||
|
||||
See [Screen Sharing](screen-sharing.md) for setup instructions.
|
||||
|
||||
## Screen Locking
|
||||
|
||||
Jay can automatically lock your screen and disable outputs after inactivity.
|
||||
|
|
@ -154,20 +140,6 @@ Jay supports running X11 applications seamlessly through Xwayland. See
|
|||
Jay supports clipboard managers via the `zwlr_data_control_manager_v1` and
|
||||
`ext_data_control_manager_v1` protocols.
|
||||
|
||||
## Privilege Separation
|
||||
|
||||
Jay splits protocols into unprivileged and privileged protocols. By default,
|
||||
applications only have access to unprivileged protocols. This means that tools
|
||||
like screen lockers, status bars, and clipboard managers need to be explicitly
|
||||
granted access.
|
||||
|
||||
Jay provides several ways to grant privileges, from giving a program full
|
||||
access to all privileged protocols down to granting individual capabilities to
|
||||
specific tagged processes. See
|
||||
[Granting Privileges](window-rules.md#granting-privileges) for a detailed
|
||||
guide and the [Protocol Support](#protocol-support) section below for the full
|
||||
list of protocols and their privilege requirements.
|
||||
|
||||
## Push to Talk
|
||||
|
||||
Jay's shortcut system allows you to execute an action when a key is pressed and
|
||||
|
|
|
|||
|
|
@ -63,7 +63,6 @@ For Vulkan, you also need the driver for your GPU:
|
|||
|
||||
- **Linux 6.7 or later** -- required for explicit sync (needed for Nvidia GPUs).
|
||||
- **Xwayland** -- required for running X11 applications.
|
||||
- **PipeWire** -- required for screen sharing.
|
||||
- **logind** (part of systemd) -- required when running Jay from a virtual terminal or display manager.
|
||||
|
||||
## Building
|
||||
|
|
@ -129,14 +128,7 @@ retains `CAP_SYS_NICE` solely for creating elevated Vulkan queues later.
|
|||
> [!NOTE]
|
||||
> You need to re-run the `setcap` command each time you update the Jay binary.
|
||||
|
||||
### SCHED_RR and config.so
|
||||
|
||||
`SCHED_RR` and `config.so` are mutually exclusive: running untrusted code at
|
||||
real-time priority would be a security risk. Jay enforces this as follows:
|
||||
|
||||
- If `config.so` exists in the config directory, Jay skips the `SCHED_RR`
|
||||
elevation (elevated Vulkan queues are still created).
|
||||
- If Jay has already elevated to `SCHED_RR`, it refuses to load `config.so`.
|
||||
### SCHED_RR
|
||||
|
||||
You can also skip `SCHED_RR` explicitly by setting `JAY_NO_REALTIME=1`:
|
||||
|
||||
|
|
@ -144,11 +136,7 @@ You can also skip `SCHED_RR` explicitly by setting `JAY_NO_REALTIME=1`:
|
|||
~$ JAY_NO_REALTIME=1 jay run
|
||||
```
|
||||
|
||||
This still allows elevated Vulkan queues and does not affect `config.so`
|
||||
loading.
|
||||
|
||||
The mutual exclusion can be overridden at compile time by building Jay with
|
||||
`JAY_ALLOW_REALTIME_CONFIG_SO=1`.
|
||||
This still allows elevated Vulkan queues.
|
||||
|
||||
## Recommended Applications
|
||||
|
||||
|
|
@ -156,7 +144,6 @@ The following applications work well with Jay:
|
|||
|
||||
- **[Alacritty](https://alacritty.org/)** -- the default terminal emulator in the built-in configuration.
|
||||
- **[bemenu](https://github.com/Cloudef/bemenu)** -- the default application launcher in the built-in configuration.
|
||||
- **[xdg-desktop-portal-gtk4](https://github.com/mahkoh/xdg-desktop-portal-gtk4)** -- a file-picker portal with thumbnail support. Used automatically when installed.
|
||||
- **[wl-tray-bridge](https://github.com/mahkoh/wl-tray-bridge)** -- shows D-Bus StatusNotifierItem applications as tray icons.
|
||||
- **[mako](https://github.com/emersion/mako)** -- a notification daemon. Launched automatically by the default configuration.
|
||||
- **[window-to-tray](https://github.com/mahkoh/wl-proxy/tree/master/apps/window-to-tray)** -- run most Wayland applications as tray applications (e.g. `window-to-tray pavucontrol-qt`).
|
||||
|
|
|
|||
|
|
@ -22,12 +22,11 @@
|
|||
|
||||
Jay is a Wayland compositor for Linux with an i3-inspired tiling layout. It
|
||||
supports Vulkan and OpenGL rendering, multi-GPU setups, fractional scaling,
|
||||
variable refresh rate (VRR), tearing presentation, HDR, and screen sharing via
|
||||
xdg-desktop-portal. X11 applications are supported through Xwayland.
|
||||
variable refresh rate (VRR), tearing presentation, and HDR. X11 applications
|
||||
are supported through Xwayland.
|
||||
|
||||
Jay is configured through a declarative TOML file, with an optional advanced
|
||||
mode that uses a shared library for programmatic control. A comprehensive
|
||||
command-line interface makes scripting and automation straightforward.
|
||||
Jay is configured through a declarative TOML file. A comprehensive command-line
|
||||
interface makes scripting and automation straightforward.
|
||||
|
||||
See the [Features](features.md) chapter for a comprehensive overview of what
|
||||
Jay can do, or jump straight to [Installation](installation.md) to get started.
|
||||
|
|
|
|||
|
|
@ -84,8 +84,8 @@ This is especially useful for:
|
|||
|
||||
## Other
|
||||
|
||||
**Toplevel selection.** Some actions (like screen sharing) ask you to select a
|
||||
window, indicated by a purple overlay. During this selection, right-click a
|
||||
**Toplevel selection.** Some actions ask you to select a window, indicated by a
|
||||
purple overlay. During this selection, right-click a
|
||||
tile's title to select the entire container instead of an individual tile.
|
||||
|
||||
**Canceling interactions.** Press `Escape` to cancel any in-progress mouse
|
||||
|
|
|
|||
|
|
@ -1,111 +0,0 @@
|
|||
# Screen Sharing
|
||||
|
||||
Jay supports screen sharing via
|
||||
[xdg-desktop-portal](https://github.com/flatpak/xdg-desktop-portal). Three
|
||||
capture types are available:
|
||||
|
||||
- **Window capture** -- share a single window.
|
||||
- **Output capture** -- share an entire monitor.
|
||||
- **Workspace capture** -- like output capture, but only a single workspace is
|
||||
shown.
|
||||
|
||||
## Requirements
|
||||
|
||||
[PipeWire](https://pipewire.org/) must be installed and running. Verify with:
|
||||
|
||||
```shell
|
||||
~$ systemctl --user status pipewire
|
||||
```
|
||||
|
||||
## Portal Setup
|
||||
|
||||
Jay implements its own portal backend for the `ScreenCast` and `RemoteDesktop`
|
||||
interfaces. Two configuration files must be installed so that
|
||||
`xdg-desktop-portal` knows to use Jay's backend.
|
||||
|
||||
### If the Repository is Checked Out
|
||||
|
||||
```shell
|
||||
~$ sudo cp etc/jay.portal /usr/share/xdg-desktop-portal/portals/jay.portal
|
||||
~$ sudo cp etc/jay-portals.conf /usr/share/xdg-desktop-portal/jay-portals.conf
|
||||
```
|
||||
|
||||
### If Installed via cargo install
|
||||
|
||||
Create the files manually:
|
||||
|
||||
```shell
|
||||
~$ sudo tee /usr/share/xdg-desktop-portal/portals/jay.portal > /dev/null << 'EOF'
|
||||
[portal]
|
||||
DBusName=org.freedesktop.impl.portal.desktop.jay
|
||||
Interfaces=org.freedesktop.impl.portal.ScreenCast;org.freedesktop.impl.portal.RemoteDesktop;
|
||||
EOF
|
||||
```
|
||||
|
||||
```shell
|
||||
~$ sudo tee /usr/share/xdg-desktop-portal/jay-portals.conf > /dev/null << 'EOF'
|
||||
[preferred]
|
||||
default=gtk
|
||||
org.freedesktop.impl.portal.ScreenCast=jay
|
||||
org.freedesktop.impl.portal.RemoteDesktop=jay
|
||||
org.freedesktop.impl.portal.Inhibit=none
|
||||
org.freedesktop.impl.portal.FileChooser=gtk4
|
||||
EOF
|
||||
```
|
||||
|
||||
### Restart the Portal
|
||||
|
||||
After installing the files, restart the portal service:
|
||||
|
||||
```shell
|
||||
~$ systemctl --user restart xdg-desktop-portal
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
### workspace-capture
|
||||
|
||||
The top-level `workspace-capture` setting controls whether newly created
|
||||
workspaces can be captured via workspace capture. The default is `true`:
|
||||
|
||||
```toml
|
||||
workspace-capture = false
|
||||
```
|
||||
|
||||
Set this to `false` if you want to prevent workspace-level capture by default.
|
||||
|
||||
### Capture Indicator Colors
|
||||
|
||||
When a window is being recorded, its title bar color changes to make the
|
||||
capture visually obvious. You can customize these colors in the `[theme]`
|
||||
table:
|
||||
|
||||
```toml
|
||||
[theme]
|
||||
captured-focused-title-bg-color = "#900000"
|
||||
captured-unfocused-title-bg-color = "#5f0000"
|
||||
```
|
||||
|
||||
- `captured-focused-title-bg-color` -- background color of focused title bars
|
||||
that are being recorded.
|
||||
- `captured-unfocused-title-bg-color` -- background color of unfocused title
|
||||
bars that are being recorded.
|
||||
|
||||
## The jay portal Command
|
||||
|
||||
Jay's portal backend is normally started automatically when a screen-sharing
|
||||
request comes in via D-Bus activation. If you need to start it manually for
|
||||
debugging purposes:
|
||||
|
||||
```shell
|
||||
~$ jay portal
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
If screen sharing does not work:
|
||||
|
||||
1. Verify PipeWire is running: `systemctl --user status pipewire`
|
||||
2. Verify the portal files are installed in `/usr/share/xdg-desktop-portal/`.
|
||||
3. Restart the portal: `systemctl --user restart xdg-desktop-portal`
|
||||
4. Check the Jay log for errors: `jay log`
|
||||
|
|
@ -54,57 +54,6 @@ bindings.
|
|||
> when any config file exists. Always use `jay config init` to start with a
|
||||
> working configuration.
|
||||
|
||||
## Application doesn't have access to a protocol
|
||||
|
||||
Jay splits Wayland protocols into unprivileged and privileged. By default,
|
||||
applications only have access to unprivileged protocols. If a program like a
|
||||
screen locker, status bar, clipboard manager, or screen-capture tool is not
|
||||
working, it likely needs access to one or more privileged protocols.
|
||||
|
||||
Common symptoms include:
|
||||
|
||||
- **swaylock** does nothing or fails to lock the screen (needs `session-lock`).
|
||||
- **waybar** or **i3bar** shows no workspace information (needs
|
||||
`foreign-toplevel-list`).
|
||||
- **wl-copy** / **cliphist** cannot access the clipboard (needs
|
||||
`data-control`).
|
||||
- **grim** or **slurp** cannot capture the screen (needs `screencopy`).
|
||||
|
||||
**Quick fix -- grant all privileges:**
|
||||
|
||||
The simplest approach is to launch the program with full access to all
|
||||
privileged protocols. In your config, set `privileged = true` in the exec
|
||||
action:
|
||||
|
||||
```toml
|
||||
on-idle = {
|
||||
type = "exec",
|
||||
exec = {
|
||||
prog = "swaylock",
|
||||
privileged = true,
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
Or from the command line:
|
||||
|
||||
```shell
|
||||
~$ jay run-privileged waybar
|
||||
```
|
||||
|
||||
**Better fix -- grant only the capabilities needed:**
|
||||
|
||||
Use a client rule to grant specific capabilities:
|
||||
|
||||
```toml
|
||||
[[clients]]
|
||||
match.comm = "waybar"
|
||||
capabilities = ["layer-shell", "foreign-toplevel-list"]
|
||||
```
|
||||
|
||||
See [Granting Privileges](window-rules.md#granting-privileges) for the full
|
||||
list of capabilities and more advanced approaches using connection tags.
|
||||
|
||||
## Wrong keyboard layout
|
||||
|
||||
The default keyboard layout is US QWERTY. To change it:
|
||||
|
|
@ -132,45 +81,6 @@ layout = "de"
|
|||
This takes effect immediately but does not persist across restarts unless
|
||||
configured in the config file.
|
||||
|
||||
## Screen sharing doesn't work
|
||||
|
||||
Screen sharing requires PipeWire and the Jay desktop portal.
|
||||
|
||||
**1. Check that PipeWire is running:**
|
||||
|
||||
```shell
|
||||
~$ systemctl --user status pipewire
|
||||
```
|
||||
|
||||
If it is not running, start it:
|
||||
|
||||
```shell
|
||||
~$ systemctl --user start pipewire
|
||||
```
|
||||
|
||||
**2. Check that the portal files are installed:**
|
||||
|
||||
Jay needs two files to be found by the XDG desktop portal framework:
|
||||
|
||||
- A portal definition file (e.g. `/usr/share/xdg-desktop-portal/portals/jay.portal`).
|
||||
- A portal configuration file (e.g. `/usr/share/xdg-desktop-portal/jay-portals.conf`).
|
||||
|
||||
These files are included in the Jay repository under `etc/`. If you built Jay
|
||||
from source and did not install them, copy them manually:
|
||||
|
||||
```shell
|
||||
~$ sudo cp etc/jay.portal /usr/share/xdg-desktop-portal/portals/
|
||||
~$ sudo cp etc/jay-portals.conf /usr/share/xdg-desktop-portal/
|
||||
```
|
||||
|
||||
**3. Restart the portal:**
|
||||
|
||||
```shell
|
||||
~$ systemctl --user restart xdg-desktop-portal
|
||||
```
|
||||
|
||||
See the [Screen Sharing](screen-sharing.md) chapter for more details.
|
||||
|
||||
## X11 applications don't work
|
||||
|
||||
Jay uses Xwayland to run X11 applications.
|
||||
|
|
|
|||
|
|
@ -31,12 +31,6 @@ Each client rule can have the following fields:
|
|||
`latch`
|
||||
: An action to run when a client stops matching.
|
||||
|
||||
`capabilities`
|
||||
: Wayland protocol access granted to matching clients.
|
||||
|
||||
`sandbox-bounding-capabilities`
|
||||
: Upper bounds for protocols available to child sandboxes.
|
||||
|
||||
### Client Match Criteria
|
||||
|
||||
All client match criteria are constant over the lifetime of a client. If no
|
||||
|
|
@ -70,142 +64,6 @@ implicitly AND-combined.
|
|||
`exe` / `exe-regex`
|
||||
: The client's `/proc/pid/exe` path.
|
||||
|
||||
`tag` / `tag-regex`
|
||||
: The connection tag of the client.
|
||||
|
||||
### Granting Privileges
|
||||
|
||||
Jay splits Wayland protocols into unprivileged and privileged. By default,
|
||||
applications only have access to unprivileged protocols. This means that tools
|
||||
like screen lockers, status bars, screen-capture utilities, and clipboard
|
||||
managers will not work unless you explicitly grant them the necessary
|
||||
privileges.
|
||||
|
||||
See the [Protocol Support](features.md#protocol-support) table in the Features
|
||||
chapter for the full list of protocols and whether they are privileged.
|
||||
|
||||
There are three ways to grant privileges, from simplest to most fine-grained.
|
||||
|
||||
#### 1. Grant all privileges via `privileged = true` (exec) or `jay run-privileged`
|
||||
|
||||
The simplest approach gives a program access to **all** privileged protocols.
|
||||
This is appropriate for trusted tools like screen lockers where you don't want
|
||||
to think about which specific protocols they need.
|
||||
|
||||
In the config, set `privileged = true` in the exec table:
|
||||
|
||||
```toml
|
||||
on-idle = {
|
||||
type = "exec",
|
||||
exec = {
|
||||
prog = "swaylock",
|
||||
privileged = true,
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
From the command line, use `jay run-privileged`:
|
||||
|
||||
```shell
|
||||
~$ jay run-privileged waybar
|
||||
```
|
||||
|
||||
Both methods connect the program to a privileged Wayland socket that grants
|
||||
access to all privileged protocols.
|
||||
|
||||
#### 2. Grant capabilities via connection tags
|
||||
|
||||
Connection tags let you combine the CLI with client rules for precise control.
|
||||
You tag a program at launch time, then write a client rule that matches
|
||||
the tag and grants specific capabilities.
|
||||
|
||||
First, launch the program with a tag -- either from the command line:
|
||||
|
||||
```shell
|
||||
~$ jay run-tagged bar waybar
|
||||
```
|
||||
|
||||
Or from the config using the `tag` field in an exec action:
|
||||
|
||||
```toml
|
||||
[shortcuts]
|
||||
alt-w = {
|
||||
type = "exec",
|
||||
exec = {
|
||||
prog = "waybar",
|
||||
tag = "bar",
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
Then write a client rule that matches the tag and grants capabilities:
|
||||
|
||||
```toml
|
||||
[[clients]]
|
||||
match.tag = "bar"
|
||||
capabilities = ["layer-shell", "foreign-toplevel-list"]
|
||||
```
|
||||
|
||||
This way, only the specific instance you launched with the tag receives the
|
||||
privileges -- other programs with the same binary name do not.
|
||||
|
||||
Available capability values: `none`, `all`, `data-control`,
|
||||
`virtual-keyboard`, `foreign-toplevel-list`, `idle-notifier`, `session-lock`,
|
||||
`layer-shell`, `screencopy`, `seat-manager`, `drm-lease`, `input-method`,
|
||||
`workspace-manager`, `foreign-toplevel-manager`, `head-manager`,
|
||||
`gamma-control-manager`, `virtual-pointer`.
|
||||
|
||||
**Default capabilities:** unsandboxed clients receive `layer-shell` and
|
||||
`drm-lease`. Sandboxed clients receive only `drm-lease`. If any client rule
|
||||
matches, its capabilities **replace** the defaults entirely. If multiple rules
|
||||
match, their capabilities are unioned together, but the defaults are not
|
||||
included unless a matching rule also grants them.
|
||||
|
||||
#### 3. Grant capabilities via client match rules
|
||||
|
||||
Client rules can also match programs by properties like their executable name
|
||||
instead of a tag. This is convenient when you always want a given program to
|
||||
have certain capabilities, regardless of how it was launched:
|
||||
|
||||
```toml
|
||||
[[clients]]
|
||||
match.comm = "waybar"
|
||||
capabilities = ["layer-shell", "foreign-toplevel-list"]
|
||||
|
||||
# Vim 9.2 uses the data-control protocol for seamless wayland integration.
|
||||
[[clients]]
|
||||
match.comm = "vim"
|
||||
match.sandboxed = false
|
||||
capabilities = "data-control"
|
||||
|
||||
# Older versions use wl-copy and wl-paste.
|
||||
[[clients]]
|
||||
match.any = [
|
||||
{ comm = "wl-copy" },
|
||||
{ comm = "wl-paste" },
|
||||
]
|
||||
match.sandboxed = false
|
||||
capabilities = "data-control"
|
||||
```
|
||||
|
||||
> [!NOTE]
|
||||
> Client match criteria like `comm`, `exe`, and `pid` are checked when a
|
||||
> client connects. Any process with a matching name receives the specified
|
||||
> capabilities. If you need to restrict privileges to programs you launch
|
||||
> yourself, use connection tags (method 2) instead.
|
||||
|
||||
#### Bounding capabilities (sandboxes)
|
||||
|
||||
Capabilities can never exceed the client's **bounding capabilities**. Use
|
||||
`sandbox-bounding-capabilities` on a client rule to set the upper bound for
|
||||
protocols available to sandboxes created by that client:
|
||||
|
||||
```toml
|
||||
[[clients]]
|
||||
match.comm = "flatpak-portal"
|
||||
sandbox-bounding-capabilities = ["drm-lease", "layer-shell"]
|
||||
```
|
||||
|
||||
## Window Rules
|
||||
|
||||
Window rules operate on individual windows. They are defined with `[[windows]]`
|
||||
|
|
@ -456,18 +314,6 @@ action = {
|
|||
}
|
||||
```
|
||||
|
||||
### Grant Protocol Access to a Trusted App
|
||||
|
||||
```toml
|
||||
[[clients]]
|
||||
match.comm = "swaylock"
|
||||
capabilities = ["session-lock", "layer-shell"]
|
||||
|
||||
[[clients]]
|
||||
match.comm = "waybar"
|
||||
capabilities = ["layer-shell", "foreign-toplevel-list"]
|
||||
```
|
||||
|
||||
### Suppress Focus Stealing for Chromium Screen-Share Windows
|
||||
|
||||
```toml
|
||||
|
|
|
|||
|
|
@ -123,16 +123,15 @@ laptop.
|
|||
|
||||
## Workspace Capture
|
||||
|
||||
By default, newly created workspaces can be captured for screen sharing. You
|
||||
can disable this globally:
|
||||
By default, newly created workspaces can be captured by capture clients. You can
|
||||
disable this globally:
|
||||
|
||||
```toml
|
||||
workspace-capture = false
|
||||
```
|
||||
|
||||
When workspace capture is enabled, screen-sharing applications can share
|
||||
individual workspaces (in addition to full outputs and individual windows). See
|
||||
[Screen Sharing](screen-sharing.md) for more details.
|
||||
When workspace capture is enabled, compositor-native capture clients may capture
|
||||
individual workspaces instead of whole outputs.
|
||||
|
||||
## Matching Windows by Workspace
|
||||
|
||||
|
|
|
|||
8
cmm/Cargo.toml
Normal file
8
cmm/Cargo.toml
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
[package]
|
||||
name = "jay-cmm"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
license = "GPL-3.0-only"
|
||||
|
||||
[dependencies]
|
||||
jay-utils = { version = "0.1.0", path = "../utils" }
|
||||
|
|
@ -1,15 +1,13 @@
|
|||
use {
|
||||
crate::{
|
||||
cmm::{
|
||||
cmm_eotf::Eotf,
|
||||
cmm_luminance::{Luminance, TargetLuminance, white_balance},
|
||||
cmm_manager::Shared,
|
||||
cmm_primaries::{NamedPrimaries, Primaries},
|
||||
cmm_render_intent::RenderIntent,
|
||||
cmm_transform::{ColorMatrix, Local, Xyz, bradford_adjustment},
|
||||
},
|
||||
utils::ordered_float::F64,
|
||||
cmm_eotf::Eotf,
|
||||
cmm_luminance::{Luminance, TargetLuminance, white_balance},
|
||||
cmm_manager::Shared,
|
||||
cmm_primaries::{NamedPrimaries, Primaries},
|
||||
cmm_render_intent::RenderIntent,
|
||||
cmm_transform::{ColorMatrix, Local, Xyz, bradford_adjustment},
|
||||
},
|
||||
jay_utils::ordered_float::F64,
|
||||
std::rc::Rc,
|
||||
};
|
||||
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
use crate::utils::ordered_float::F32;
|
||||
use jay_utils::ordered_float::F32;
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
|
||||
pub enum Eotf {
|
||||
|
|
@ -1,10 +1,8 @@
|
|||
use crate::{
|
||||
cmm::{
|
||||
cmm_render_intent::RenderIntent,
|
||||
cmm_transform::{ColorMatrix, Xyz},
|
||||
},
|
||||
utils::ordered_float::F64,
|
||||
cmm_render_intent::RenderIntent,
|
||||
cmm_transform::{ColorMatrix, Xyz},
|
||||
};
|
||||
use jay_utils::ordered_float::F64;
|
||||
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
|
||||
pub struct Luminance {
|
||||
|
|
@ -38,7 +36,6 @@ impl Luminance {
|
|||
white: F64(203.0),
|
||||
};
|
||||
|
||||
#[expect(dead_code)]
|
||||
pub const HLG: Self = Self {
|
||||
min: F64(0.005),
|
||||
max: F64(1000.0),
|
||||
|
|
@ -1,16 +1,14 @@
|
|||
use {
|
||||
crate::{
|
||||
cmm::{
|
||||
cmm_description::{
|
||||
ColorDescription, ColorDescriptionIds, LinearColorDescription,
|
||||
LinearColorDescriptionId, LinearColorDescriptionIds,
|
||||
},
|
||||
cmm_eotf::Eotf,
|
||||
cmm_luminance::{Luminance, TargetLuminance},
|
||||
cmm_primaries::{NamedPrimaries, Primaries},
|
||||
cmm_description::{
|
||||
ColorDescription, ColorDescriptionIds, LinearColorDescription,
|
||||
LinearColorDescriptionId, LinearColorDescriptionIds,
|
||||
},
|
||||
utils::{copyhashmap::CopyHashMap, numcell::NumCell, ordered_float::F64},
|
||||
cmm_eotf::Eotf,
|
||||
cmm_luminance::{Luminance, TargetLuminance},
|
||||
cmm_primaries::{NamedPrimaries, Primaries},
|
||||
},
|
||||
jay_utils::{copyhashmap::CopyHashMap, numcell::NumCell, ordered_float::F64},
|
||||
std::rc::{Rc, Weak},
|
||||
};
|
||||
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
use {crate::utils::ordered_float::F64, std::hash::Hash};
|
||||
use {jay_utils::ordered_float::F64, std::hash::Hash};
|
||||
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
|
||||
pub enum NamedPrimaries {
|
||||
|
|
@ -1,11 +1,3 @@
|
|||
use crate::{
|
||||
ifs::color_management::{
|
||||
ABSOLUTE_NO_ADAPTATION_SINCE, RENDER_INTENT_ABSOLUTE_NO_ADAPTATION,
|
||||
RENDER_INTENT_PERCEPTUAL, RENDER_INTENT_RELATIVE, RENDER_INTENT_RELATIVE_BPC,
|
||||
},
|
||||
object::Version,
|
||||
};
|
||||
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Default)]
|
||||
pub enum RenderIntent {
|
||||
#[default]
|
||||
|
|
@ -16,19 +8,6 @@ pub enum RenderIntent {
|
|||
}
|
||||
|
||||
impl RenderIntent {
|
||||
pub fn from_wayland(intent: u32, version: Version) -> Option<Self> {
|
||||
let res = match intent {
|
||||
RENDER_INTENT_PERCEPTUAL => Self::Perceptual,
|
||||
RENDER_INTENT_RELATIVE => Self::Relative,
|
||||
RENDER_INTENT_RELATIVE_BPC => Self::RelativeBpc,
|
||||
RENDER_INTENT_ABSOLUTE_NO_ADAPTATION if version >= ABSOLUTE_NO_ADAPTATION_SINCE => {
|
||||
Self::AbsoluteNoAdaptation
|
||||
}
|
||||
_ => return None,
|
||||
};
|
||||
Some(res)
|
||||
}
|
||||
|
||||
pub fn black_point_compensation(self) -> bool {
|
||||
match self {
|
||||
RenderIntent::Perceptual => true,
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
mod matrices {
|
||||
use crate::{cmm::cmm_primaries::Primaries, utils::ordered_float::F64};
|
||||
use {crate::cmm_primaries::Primaries, jay_utils::ordered_float::F64};
|
||||
|
||||
fn check(primaries: Primaries, expected: [[f64; 4]; 3]) {
|
||||
let (ltg, gtl) = primaries.matrices();
|
||||
|
|
@ -134,7 +134,7 @@ mod matrices {
|
|||
}
|
||||
|
||||
mod transforms {
|
||||
use crate::cmm::{
|
||||
use crate::{
|
||||
cmm_eotf::Eotf, cmm_luminance::Luminance, cmm_manager::ColorManager,
|
||||
cmm_primaries::Primaries, cmm_render_intent::RenderIntent,
|
||||
};
|
||||
|
|
@ -1,10 +1,6 @@
|
|||
use {
|
||||
crate::{
|
||||
cmm::{cmm_eotf::Eotf, cmm_primaries::Primaries},
|
||||
gfx_api::AlphaMode,
|
||||
theme::Color,
|
||||
utils::ordered_float::F64,
|
||||
},
|
||||
crate::cmm_primaries::Primaries,
|
||||
jay_utils::ordered_float::F64,
|
||||
std::{
|
||||
fmt,
|
||||
fmt::{Debug, Formatter},
|
||||
|
|
@ -129,29 +125,6 @@ impl<T, U> Mul<[f64; 3]> for ColorMatrix<T, U> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T, U> Mul<Color> for ColorMatrix<T, U> {
|
||||
type Output = Color;
|
||||
|
||||
fn mul(self, rhs: Color) -> Self::Output {
|
||||
let mut rgba = rhs.to_array(Eotf::Linear);
|
||||
let a = rgba[3];
|
||||
if a < 1.0 && a > 0.0 {
|
||||
for c in &mut rgba[..3] {
|
||||
*c /= a;
|
||||
}
|
||||
}
|
||||
let [r, g, b] = self * [rgba[0] as f64, rgba[1] as f64, rgba[2] as f64];
|
||||
Color::new(
|
||||
Eotf::Linear,
|
||||
AlphaMode::Straight,
|
||||
r as f32,
|
||||
g as f32,
|
||||
b as f32,
|
||||
a,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, U> ColorMatrix<T, U> {
|
||||
pub const fn new(m: [[f64; 4]; 3]) -> Self {
|
||||
let m = [
|
||||
53
cmm/src/lib.rs
Normal file
53
cmm/src/lib.rs
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
macro_rules! linear_ids {
|
||||
($ids:ident, $id:ident, $ty:ty $(,)?) => {
|
||||
#[derive(Debug)]
|
||||
pub struct $ids {
|
||||
next: jay_utils::numcell::NumCell<$ty>,
|
||||
}
|
||||
|
||||
impl Default for $ids {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
next: jay_utils::numcell::NumCell::new(1),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl $ids {
|
||||
pub fn next(&self) -> $id {
|
||||
$id(self.next.fetch_add(1))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Ord, PartialOrd)]
|
||||
pub struct $id($ty);
|
||||
|
||||
impl $id {
|
||||
#[allow(dead_code)]
|
||||
pub fn raw(&self) -> $ty {
|
||||
self.0
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn from_raw(id: $ty) -> Self {
|
||||
Self(id)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for $id {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
std::fmt::Display::fmt(&self.0, f)
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
pub mod cmm_description;
|
||||
pub mod cmm_eotf;
|
||||
pub mod cmm_luminance;
|
||||
pub mod cmm_manager;
|
||||
pub mod cmm_primaries;
|
||||
pub mod cmm_render_intent;
|
||||
#[cfg(test)]
|
||||
mod cmm_tests;
|
||||
pub mod cmm_transform;
|
||||
12
criteria/Cargo.toml
Normal file
12
criteria/Cargo.toml
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
[package]
|
||||
name = "jay-criteria"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
license = "GPL-3.0-only"
|
||||
|
||||
[dependencies]
|
||||
jay-utils = { version = "0.1.0", path = "../utils" }
|
||||
|
||||
ahash = "0.8.7"
|
||||
linearize = { version = "0.1.3", features = ["derive"] }
|
||||
regex = "1.11.1"
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
use {
|
||||
crate::criteria::{
|
||||
crate::{
|
||||
CritMatcherId,
|
||||
crit_graph::{CritTarget, crit_upstream::CritUpstreamNode},
|
||||
},
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
use {
|
||||
crate::criteria::{
|
||||
crate::{
|
||||
CritUpstreamNode,
|
||||
crit_graph::{
|
||||
CritDownstream, CritDownstreamData, CritTarget, CritUpstreamData,
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
use {
|
||||
crate::criteria::{
|
||||
crate::{
|
||||
CritMatcherId, CritUpstreamNode, FixedRootMatcher, RootMatcherMap,
|
||||
crit_graph::{
|
||||
CritTarget, CritUpstreamData,
|
||||
|
|
@ -1,11 +1,9 @@
|
|||
use {
|
||||
crate::{
|
||||
criteria::{
|
||||
CritDestroyListener, CritMatcherId, FixedRootMatcher, crit_leaf::CritLeafEvent,
|
||||
crit_matchers::critm_constant::CritMatchConstant,
|
||||
},
|
||||
utils::{copyhashmap::CopyHashMap, queue::AsyncQueue},
|
||||
CritDestroyListener, CritMatcherId, FixedRootMatcher, crit_leaf::CritLeafEvent,
|
||||
crit_matchers::critm_constant::CritMatchConstant,
|
||||
},
|
||||
jay_utils::{copyhashmap::CopyHashMap, queue::AsyncQueue},
|
||||
std::{
|
||||
hash::Hash,
|
||||
rc::{Rc, Weak},
|
||||
|
|
@ -1,16 +1,14 @@
|
|||
use {
|
||||
crate::{
|
||||
criteria::{
|
||||
CritDestroyListener, CritMatcherId,
|
||||
crit_graph::{
|
||||
WeakCritTargetOwner,
|
||||
crit_downstream::CritDownstream,
|
||||
crit_target::{CritTarget, CritTargetOwner},
|
||||
},
|
||||
crit_per_target_data::CritPerTargetData,
|
||||
CritDestroyListener, CritMatcherId,
|
||||
crit_graph::{
|
||||
WeakCritTargetOwner,
|
||||
crit_downstream::CritDownstream,
|
||||
crit_target::{CritTarget, CritTargetOwner},
|
||||
},
|
||||
utils::copyhashmap::CopyHashMap,
|
||||
crit_per_target_data::CritPerTargetData,
|
||||
},
|
||||
jay_utils::copyhashmap::CopyHashMap,
|
||||
std::{
|
||||
cell::RefMut,
|
||||
mem,
|
||||
|
|
@ -1,12 +1,10 @@
|
|||
use {
|
||||
crate::{
|
||||
criteria::{
|
||||
CritUpstreamNode,
|
||||
crit_graph::{CritDownstream, CritDownstreamData, CritMgr, CritTarget},
|
||||
crit_per_target_data::{CritDestroyListenerBase, CritPerTargetData},
|
||||
},
|
||||
utils::{cell_ext::CellExt, queue::AsyncQueue},
|
||||
CritUpstreamNode,
|
||||
crit_graph::{CritDownstream, CritDownstreamData, CritMgr, CritTarget},
|
||||
crit_per_target_data::{CritDestroyListenerBase, CritPerTargetData},
|
||||
},
|
||||
jay_utils::{cell_ext::CellExt, queue::AsyncQueue},
|
||||
std::{
|
||||
cell::Cell,
|
||||
rc::{Rc, Weak},
|
||||
|
|
@ -24,7 +22,7 @@ where
|
|||
events: Rc<AsyncQueue<CritLeafEvent<Target>>>,
|
||||
}
|
||||
|
||||
pub(in crate::criteria) struct NodeHolder<Target>
|
||||
pub struct NodeHolder<Target>
|
||||
where
|
||||
Target: CritTarget,
|
||||
{
|
||||
|
|
@ -77,7 +75,7 @@ impl<Target> CritLeafMatcher<Target>
|
|||
where
|
||||
Target: CritTarget,
|
||||
{
|
||||
pub(in crate::criteria) fn new(
|
||||
pub(crate) fn new(
|
||||
mgr: &Target::Mgr,
|
||||
upstream: &Rc<dyn CritUpstreamNode<Target>>,
|
||||
on_match: impl Fn(Target::LeafData) -> Box<dyn FnOnce()> + 'static,
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
use {
|
||||
crate::criteria::crit_graph::{CritMiddleCriterion, CritTarget, CritUpstreamNode},
|
||||
crate::crit_graph::{CritMiddleCriterion, CritTarget, CritUpstreamNode},
|
||||
std::{marker::PhantomData, rc::Rc},
|
||||
};
|
||||
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
use {
|
||||
crate::criteria::{
|
||||
crate::{
|
||||
CritMatcherIds, FixedRootMatcher,
|
||||
crit_graph::{
|
||||
CritFixedRootCriterion, CritFixedRootCriterionBase, CritMgr, CritRoot, CritRootFixed,
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
use {
|
||||
crate::criteria::crit_graph::{CritMiddleCriterion, CritTarget, CritUpstreamNode},
|
||||
crate::crit_graph::{CritMiddleCriterion, CritTarget, CritUpstreamNode},
|
||||
std::{marker::PhantomData, rc::Rc},
|
||||
};
|
||||
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
use {
|
||||
crate::criteria::{
|
||||
crate::{
|
||||
CritLiteralOrRegex, RootMatcherMap,
|
||||
crit_graph::{CritRootCriterion, CritTarget},
|
||||
},
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
use {
|
||||
crate::criteria::{
|
||||
crate::{
|
||||
CritMatcherId,
|
||||
crit_graph::{CritTarget, CritTargetOwner, WeakCritTargetOwner},
|
||||
},
|
||||
|
|
@ -28,7 +28,7 @@ where
|
|||
data: T,
|
||||
}
|
||||
|
||||
pub(super) trait CritDestroyListenerBase<Target>: 'static
|
||||
pub trait CritDestroyListenerBase<Target>: 'static
|
||||
where
|
||||
Target: CritTarget,
|
||||
{
|
||||
131
criteria/src/lib.rs
Normal file
131
criteria/src/lib.rs
Normal file
|
|
@ -0,0 +1,131 @@
|
|||
pub mod crit_graph;
|
||||
pub mod crit_leaf;
|
||||
pub mod crit_matchers;
|
||||
pub mod crit_per_target_data;
|
||||
|
||||
use {
|
||||
crate::{
|
||||
crit_graph::{CritMgr, CritMiddle, CritRoot, CritRootCriterion, CritRootFixed},
|
||||
crit_leaf::CritLeafMatcher,
|
||||
crit_matchers::{critm_any_or_all::CritMatchAnyOrAll, critm_exactly::CritMatchExactly},
|
||||
},
|
||||
jay_utils::{copyhashmap::CopyHashMap, numcell::NumCell},
|
||||
linearize::StaticMap,
|
||||
regex::Regex,
|
||||
std::rc::{Rc, Weak},
|
||||
};
|
||||
pub use {
|
||||
crit_graph::{CritTarget, CritUpstreamNode},
|
||||
crit_per_target_data::CritDestroyListener,
|
||||
};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct CritMatcherIds {
|
||||
next: NumCell<u64>,
|
||||
}
|
||||
|
||||
impl Default for CritMatcherIds {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
next: NumCell::new(1),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl CritMatcherIds {
|
||||
pub fn next(&self) -> CritMatcherId {
|
||||
CritMatcherId(self.next.fetch_add(1))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Ord, PartialOrd)]
|
||||
pub struct CritMatcherId(u64);
|
||||
|
||||
impl CritMatcherId {
|
||||
#[allow(clippy::allow_attributes, dead_code)]
|
||||
pub fn raw(&self) -> u64 {
|
||||
self.0
|
||||
}
|
||||
|
||||
#[allow(clippy::allow_attributes, dead_code)]
|
||||
pub fn from_raw(id: u64) -> Self {
|
||||
Self(id)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for CritMatcherId {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
std::fmt::Display::fmt(&self.0, f)
|
||||
}
|
||||
}
|
||||
|
||||
pub type RootMatcherMap<Target, T> = CopyHashMap<CritMatcherId, Weak<CritRoot<Target, T>>>;
|
||||
pub type FixedRootMatcher<Target, T> =
|
||||
StaticMap<bool, Rc<CritRoot<Target, CritRootFixed<Target, T>>>>;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub enum CritLiteralOrRegex {
|
||||
Literal(String),
|
||||
Regex(Regex),
|
||||
}
|
||||
|
||||
impl CritLiteralOrRegex {
|
||||
fn matches(&self, string: &str) -> bool {
|
||||
match self {
|
||||
CritLiteralOrRegex::Literal(p) => string == p,
|
||||
CritLiteralOrRegex::Regex(r) => r.is_match(string),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait CritMgrExt: CritMgr {
|
||||
fn list(
|
||||
&self,
|
||||
upstream: &[Rc<dyn CritUpstreamNode<Self::Target>>],
|
||||
all: bool,
|
||||
) -> Rc<dyn CritUpstreamNode<Self::Target>> {
|
||||
if upstream.is_empty() {
|
||||
return self.match_constant()[all].clone();
|
||||
}
|
||||
CritMiddle::new(self, upstream, CritMatchAnyOrAll::new(upstream, all))
|
||||
}
|
||||
|
||||
fn exactly(
|
||||
&self,
|
||||
upstream: &[Rc<dyn CritUpstreamNode<Self::Target>>],
|
||||
num: usize,
|
||||
) -> Rc<dyn CritUpstreamNode<Self::Target>> {
|
||||
if num > upstream.len() {
|
||||
return self.match_constant()[false].clone();
|
||||
}
|
||||
if num == 0 {
|
||||
let upstream: Vec<_> = upstream.iter().map(|u| u.not(self)).collect();
|
||||
return self.list(&upstream, true);
|
||||
}
|
||||
CritMiddle::new(self, upstream, CritMatchExactly::new(upstream, num))
|
||||
}
|
||||
|
||||
fn leaf(
|
||||
&self,
|
||||
upstream: &Rc<dyn CritUpstreamNode<Self::Target>>,
|
||||
on_match: impl Fn(<Self::Target as CritTarget>::LeafData) -> Box<dyn FnOnce()> + 'static,
|
||||
) -> Rc<CritLeafMatcher<Self::Target>> {
|
||||
CritLeafMatcher::new(self, upstream, on_match)
|
||||
}
|
||||
|
||||
fn not(
|
||||
&self,
|
||||
upstream: &Rc<dyn CritUpstreamNode<Self::Target>>,
|
||||
) -> Rc<dyn CritUpstreamNode<Self::Target>> {
|
||||
upstream.not(self)
|
||||
}
|
||||
|
||||
fn root<T>(&self, criterion: T) -> Rc<dyn CritUpstreamNode<Self::Target>>
|
||||
where
|
||||
T: CritRootCriterion<Self::Target>,
|
||||
{
|
||||
CritRoot::new(self.roots(), self.id(), criterion)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> CritMgrExt for T where T: CritMgr {}
|
||||
11
edid/Cargo.toml
Normal file
11
edid/Cargo.toml
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
[package]
|
||||
name = "jay-edid"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
license = "GPL-3.0-only"
|
||||
description = "EDID parsing for Jay"
|
||||
repository = "https://github.com/mahkoh/jay"
|
||||
|
||||
[dependencies]
|
||||
bstr = { version = "1.9.0", default-features = false, features = ["std"] }
|
||||
thiserror = "2.0.11"
|
||||
1312
edid/src/lib.rs
Normal file
1312
edid/src/lib.rs
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -1,6 +0,0 @@
|
|||
[preferred]
|
||||
default=gtk
|
||||
org.freedesktop.impl.portal.ScreenCast=jay
|
||||
org.freedesktop.impl.portal.RemoteDesktop=jay
|
||||
org.freedesktop.impl.portal.Inhibit=none
|
||||
org.freedesktop.impl.portal.FileChooser=gtk4
|
||||
|
|
@ -1,3 +0,0 @@
|
|||
[portal]
|
||||
DBusName=org.freedesktop.impl.portal.desktop.jay
|
||||
Interfaces=org.freedesktop.impl.portal.ScreenCast;org.freedesktop.impl.portal.RemoteDesktop;
|
||||
13
formats/Cargo.toml
Normal file
13
formats/Cargo.toml
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
[package]
|
||||
name = "jay-formats"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
license = "GPL-3.0-only"
|
||||
description = "Pixel format tables for Jay"
|
||||
repository = "https://github.com/mahkoh/jay"
|
||||
|
||||
[dependencies]
|
||||
ahash = "0.8.7"
|
||||
ash = { package = "jay-ash", version = "0.3.0" }
|
||||
clap = { version = "4.4.18", features = ["derive", "wrap_help"] }
|
||||
jay-config = { version = "1.10.0", path = "../jay-config" }
|
||||
559
formats/src/lib.rs
Normal file
559
formats/src/lib.rs
Normal file
|
|
@ -0,0 +1,559 @@
|
|||
use {
|
||||
ahash::AHashMap,
|
||||
ash::vk,
|
||||
clap::{ValueEnum, builder::PossibleValue},
|
||||
jay_config::video::Format as ConfigFormat,
|
||||
std::{
|
||||
fmt::{self, Debug, Write},
|
||||
sync::LazyLock,
|
||||
},
|
||||
};
|
||||
|
||||
pub type GLenum = u32;
|
||||
pub type GLint = i32;
|
||||
|
||||
const GL_RGBA: GLint = 0x1908;
|
||||
const GL_RGBA8: GLenum = 0x8058;
|
||||
const GL_BGRA_EXT: GLint = 0x80E1;
|
||||
const GL_UNSIGNED_BYTE: GLint = 0x1401;
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct FormatShmInfo {
|
||||
pub gl_format: GLint,
|
||||
pub gl_internal_format: GLenum,
|
||||
pub gl_type: GLint,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct Format {
|
||||
pub name: &'static str,
|
||||
pub vk_format: vk::Format,
|
||||
pub drm: u32,
|
||||
pub wl_id: Option<u32>,
|
||||
pub external_only_guess: bool,
|
||||
pub has_alpha: bool,
|
||||
pub opaque: Option<&'static Format>,
|
||||
pub shm_info: Option<FormatShmInfo>,
|
||||
pub config: ConfigFormat,
|
||||
pub bpp: u32,
|
||||
}
|
||||
|
||||
const fn default(config: ConfigFormat) -> Format {
|
||||
Format {
|
||||
name: "",
|
||||
vk_format: vk::Format::UNDEFINED,
|
||||
drm: 0,
|
||||
wl_id: None,
|
||||
external_only_guess: false,
|
||||
has_alpha: false,
|
||||
opaque: None,
|
||||
shm_info: None,
|
||||
config,
|
||||
bpp: 4,
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for Format {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.drm == other.drm
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for Format {}
|
||||
|
||||
impl ValueEnum for &'static Format {
|
||||
fn value_variants<'a>() -> &'a [Self] {
|
||||
ref_formats()
|
||||
}
|
||||
|
||||
fn to_possible_value(&self) -> Option<PossibleValue> {
|
||||
Some(PossibleValue::new(self.name))
|
||||
}
|
||||
}
|
||||
|
||||
static FORMATS_MAP: LazyLock<AHashMap<u32, &'static Format>> = LazyLock::new(|| {
|
||||
let mut map = AHashMap::new();
|
||||
for format in FORMATS {
|
||||
assert!(map.insert(format.drm, format).is_none());
|
||||
}
|
||||
map
|
||||
});
|
||||
|
||||
static FORMATS_REFS: LazyLock<Vec<&'static Format>> = LazyLock::new(|| FORMATS.iter().collect());
|
||||
|
||||
static FORMATS_NAMES: LazyLock<AHashMap<&'static str, &'static Format>> = LazyLock::new(|| {
|
||||
let mut map = AHashMap::new();
|
||||
for format in FORMATS {
|
||||
assert!(map.insert(format.name, format).is_none());
|
||||
}
|
||||
map
|
||||
});
|
||||
|
||||
static FORMATS_CONFIG: LazyLock<AHashMap<ConfigFormat, &'static Format>> = LazyLock::new(|| {
|
||||
let mut map = AHashMap::new();
|
||||
for format in FORMATS {
|
||||
assert!(map.insert(format.config, format).is_none());
|
||||
}
|
||||
map
|
||||
});
|
||||
|
||||
#[test]
|
||||
fn formats_dont_panic() {
|
||||
formats();
|
||||
named_formats();
|
||||
config_formats();
|
||||
}
|
||||
|
||||
pub fn formats() -> &'static AHashMap<u32, &'static Format> {
|
||||
&FORMATS_MAP
|
||||
}
|
||||
|
||||
pub fn ref_formats() -> &'static [&'static Format] {
|
||||
&FORMATS_REFS
|
||||
}
|
||||
|
||||
pub fn named_formats() -> &'static AHashMap<&'static str, &'static Format> {
|
||||
&FORMATS_NAMES
|
||||
}
|
||||
|
||||
pub fn config_formats() -> &'static AHashMap<ConfigFormat, &'static Format> {
|
||||
&FORMATS_CONFIG
|
||||
}
|
||||
|
||||
const fn fourcc_code(a: char, b: char, c: char, d: char) -> u32 {
|
||||
(a as u32) | ((b as u32) << 8) | ((c as u32) << 16) | ((d as u32) << 24)
|
||||
}
|
||||
|
||||
pub fn debug(fourcc: u32) -> impl Debug {
|
||||
fmt::from_fn(move |fmt| {
|
||||
fmt.write_char(fourcc as u8 as char)?;
|
||||
fmt.write_char((fourcc >> 8) as u8 as char)?;
|
||||
fmt.write_char((fourcc >> 16) as u8 as char)?;
|
||||
fmt.write_char((fourcc >> 24) as u8 as char)?;
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
|
||||
const ARGB8888_ID: u32 = 0;
|
||||
const ARGB8888_DRM: u32 = fourcc_code('A', 'R', '2', '4');
|
||||
|
||||
const XRGB8888_ID: u32 = 1;
|
||||
const XRGB8888_DRM: u32 = fourcc_code('X', 'R', '2', '4');
|
||||
|
||||
pub fn map_wayland_format_id(id: u32) -> u32 {
|
||||
match id {
|
||||
ARGB8888_ID => ARGB8888_DRM,
|
||||
XRGB8888_ID => XRGB8888_DRM,
|
||||
_ => id,
|
||||
}
|
||||
}
|
||||
|
||||
pub static ARGB8888: &Format = &Format {
|
||||
name: "argb8888",
|
||||
shm_info: Some(FormatShmInfo {
|
||||
gl_format: GL_BGRA_EXT,
|
||||
gl_internal_format: GL_RGBA8,
|
||||
gl_type: GL_UNSIGNED_BYTE,
|
||||
}),
|
||||
vk_format: vk::Format::B8G8R8A8_UNORM,
|
||||
bpp: 4,
|
||||
drm: ARGB8888_DRM,
|
||||
wl_id: Some(ARGB8888_ID),
|
||||
external_only_guess: false,
|
||||
has_alpha: true,
|
||||
opaque: Some(XRGB8888),
|
||||
config: ConfigFormat::ARGB8888,
|
||||
};
|
||||
|
||||
pub static XRGB8888: &Format = &Format {
|
||||
name: "xrgb8888",
|
||||
shm_info: Some(FormatShmInfo {
|
||||
gl_format: GL_BGRA_EXT,
|
||||
gl_internal_format: GL_RGBA8,
|
||||
gl_type: GL_UNSIGNED_BYTE,
|
||||
}),
|
||||
vk_format: vk::Format::B8G8R8A8_UNORM,
|
||||
bpp: 4,
|
||||
drm: XRGB8888_DRM,
|
||||
wl_id: Some(XRGB8888_ID),
|
||||
external_only_guess: false,
|
||||
has_alpha: false,
|
||||
opaque: None,
|
||||
config: ConfigFormat::XRGB8888,
|
||||
};
|
||||
|
||||
static ABGR8888: &Format = &Format {
|
||||
name: "abgr8888",
|
||||
shm_info: Some(FormatShmInfo {
|
||||
gl_format: GL_RGBA,
|
||||
gl_internal_format: GL_RGBA8,
|
||||
gl_type: GL_UNSIGNED_BYTE,
|
||||
}),
|
||||
vk_format: vk::Format::R8G8B8A8_UNORM,
|
||||
bpp: 4,
|
||||
drm: fourcc_code('A', 'B', '2', '4'),
|
||||
wl_id: None,
|
||||
external_only_guess: false,
|
||||
has_alpha: true,
|
||||
opaque: Some(XBGR8888),
|
||||
config: ConfigFormat::ABGR8888,
|
||||
};
|
||||
|
||||
static XBGR8888: &Format = &Format {
|
||||
name: "xbgr8888",
|
||||
shm_info: Some(FormatShmInfo {
|
||||
gl_format: GL_RGBA,
|
||||
gl_internal_format: GL_RGBA8,
|
||||
gl_type: GL_UNSIGNED_BYTE,
|
||||
}),
|
||||
vk_format: vk::Format::R8G8B8A8_UNORM,
|
||||
bpp: 4,
|
||||
drm: fourcc_code('X', 'B', '2', '4'),
|
||||
wl_id: None,
|
||||
external_only_guess: false,
|
||||
has_alpha: false,
|
||||
opaque: None,
|
||||
config: ConfigFormat::XBGR8888,
|
||||
};
|
||||
|
||||
static R8: &Format = &Format {
|
||||
name: "r8",
|
||||
vk_format: vk::Format::R8_UNORM,
|
||||
bpp: 1,
|
||||
drm: fourcc_code('R', '8', ' ', ' '),
|
||||
..default(ConfigFormat::R8)
|
||||
};
|
||||
|
||||
static GR88: &Format = &Format {
|
||||
name: "gr88",
|
||||
vk_format: vk::Format::R8G8_UNORM,
|
||||
bpp: 2,
|
||||
drm: fourcc_code('G', 'R', '8', '8'),
|
||||
..default(ConfigFormat::GR88)
|
||||
};
|
||||
|
||||
static RGB888: &Format = &Format {
|
||||
name: "rgb888",
|
||||
vk_format: vk::Format::B8G8R8_UNORM,
|
||||
bpp: 3,
|
||||
drm: fourcc_code('R', 'G', '2', '4'),
|
||||
..default(ConfigFormat::RGB888)
|
||||
};
|
||||
|
||||
static BGR888: &Format = &Format {
|
||||
name: "bgr888",
|
||||
vk_format: vk::Format::R8G8B8_UNORM,
|
||||
bpp: 3,
|
||||
drm: fourcc_code('B', 'G', '2', '4'),
|
||||
..default(ConfigFormat::BGR888)
|
||||
};
|
||||
|
||||
static RGBA4444: &Format = &Format {
|
||||
name: "rgba4444",
|
||||
vk_format: vk::Format::R4G4B4A4_UNORM_PACK16,
|
||||
bpp: 2,
|
||||
drm: fourcc_code('R', 'A', '1', '2'),
|
||||
has_alpha: true,
|
||||
opaque: Some(RGBX4444),
|
||||
..default(ConfigFormat::RGBA4444)
|
||||
};
|
||||
|
||||
static RGBX4444: &Format = &Format {
|
||||
name: "rgbx4444",
|
||||
vk_format: vk::Format::R4G4B4A4_UNORM_PACK16,
|
||||
bpp: 2,
|
||||
drm: fourcc_code('R', 'X', '1', '2'),
|
||||
..default(ConfigFormat::RGBX4444)
|
||||
};
|
||||
|
||||
static BGRA4444: &Format = &Format {
|
||||
name: "bgra4444",
|
||||
vk_format: vk::Format::B4G4R4A4_UNORM_PACK16,
|
||||
bpp: 2,
|
||||
drm: fourcc_code('B', 'A', '1', '2'),
|
||||
has_alpha: true,
|
||||
opaque: Some(BGRX4444),
|
||||
..default(ConfigFormat::BGRA4444)
|
||||
};
|
||||
|
||||
static BGRX4444: &Format = &Format {
|
||||
name: "bgrx4444",
|
||||
vk_format: vk::Format::B4G4R4A4_UNORM_PACK16,
|
||||
bpp: 2,
|
||||
drm: fourcc_code('B', 'X', '1', '2'),
|
||||
..default(ConfigFormat::BGRX4444)
|
||||
};
|
||||
|
||||
static RGB565: &Format = &Format {
|
||||
name: "rgb565",
|
||||
vk_format: vk::Format::R5G6B5_UNORM_PACK16,
|
||||
bpp: 2,
|
||||
drm: fourcc_code('R', 'G', '1', '6'),
|
||||
..default(ConfigFormat::RGB565)
|
||||
};
|
||||
|
||||
static BGR565: &Format = &Format {
|
||||
name: "bgr565",
|
||||
vk_format: vk::Format::B5G6R5_UNORM_PACK16,
|
||||
bpp: 2,
|
||||
drm: fourcc_code('B', 'G', '1', '6'),
|
||||
..default(ConfigFormat::BGR565)
|
||||
};
|
||||
|
||||
static RGBA5551: &Format = &Format {
|
||||
name: "rgba5551",
|
||||
vk_format: vk::Format::R5G5B5A1_UNORM_PACK16,
|
||||
bpp: 2,
|
||||
drm: fourcc_code('R', 'A', '1', '5'),
|
||||
has_alpha: true,
|
||||
opaque: Some(RGBX5551),
|
||||
..default(ConfigFormat::RGBA5551)
|
||||
};
|
||||
|
||||
static RGBX5551: &Format = &Format {
|
||||
name: "rgbx5551",
|
||||
vk_format: vk::Format::R5G5B5A1_UNORM_PACK16,
|
||||
bpp: 2,
|
||||
drm: fourcc_code('R', 'X', '1', '5'),
|
||||
..default(ConfigFormat::RGBX5551)
|
||||
};
|
||||
|
||||
static BGRA5551: &Format = &Format {
|
||||
name: "bgra5551",
|
||||
vk_format: vk::Format::B5G5R5A1_UNORM_PACK16,
|
||||
bpp: 2,
|
||||
drm: fourcc_code('B', 'A', '1', '5'),
|
||||
has_alpha: true,
|
||||
opaque: Some(BGRX5551),
|
||||
..default(ConfigFormat::BGRA5551)
|
||||
};
|
||||
|
||||
static BGRX5551: &Format = &Format {
|
||||
name: "bgrx5551",
|
||||
vk_format: vk::Format::B5G5R5A1_UNORM_PACK16,
|
||||
bpp: 2,
|
||||
drm: fourcc_code('B', 'X', '1', '5'),
|
||||
..default(ConfigFormat::BGRX5551)
|
||||
};
|
||||
|
||||
static ARGB1555: &Format = &Format {
|
||||
name: "argb1555",
|
||||
vk_format: vk::Format::A1R5G5B5_UNORM_PACK16,
|
||||
bpp: 2,
|
||||
drm: fourcc_code('A', 'R', '1', '5'),
|
||||
has_alpha: true,
|
||||
opaque: Some(XRGB1555),
|
||||
..default(ConfigFormat::ARGB1555)
|
||||
};
|
||||
|
||||
static XRGB1555: &Format = &Format {
|
||||
name: "xrgb1555",
|
||||
vk_format: vk::Format::A1R5G5B5_UNORM_PACK16,
|
||||
bpp: 2,
|
||||
drm: fourcc_code('X', 'R', '1', '5'),
|
||||
..default(ConfigFormat::XRGB1555)
|
||||
};
|
||||
|
||||
static ARGB2101010: &Format = &Format {
|
||||
name: "argb2101010",
|
||||
vk_format: vk::Format::A2R10G10B10_UNORM_PACK32,
|
||||
bpp: 4,
|
||||
drm: fourcc_code('A', 'R', '3', '0'),
|
||||
has_alpha: true,
|
||||
opaque: Some(XRGB2101010),
|
||||
..default(ConfigFormat::ARGB2101010)
|
||||
};
|
||||
|
||||
static XRGB2101010: &Format = &Format {
|
||||
name: "xrgb2101010",
|
||||
vk_format: vk::Format::A2R10G10B10_UNORM_PACK32,
|
||||
bpp: 4,
|
||||
drm: fourcc_code('X', 'R', '3', '0'),
|
||||
..default(ConfigFormat::XRGB2101010)
|
||||
};
|
||||
|
||||
static ABGR2101010: &Format = &Format {
|
||||
name: "abgr2101010",
|
||||
vk_format: vk::Format::A2B10G10R10_UNORM_PACK32,
|
||||
bpp: 4,
|
||||
drm: fourcc_code('A', 'B', '3', '0'),
|
||||
has_alpha: true,
|
||||
opaque: Some(XBGR2101010),
|
||||
..default(ConfigFormat::ABGR2101010)
|
||||
};
|
||||
|
||||
static XBGR2101010: &Format = &Format {
|
||||
name: "xbgr2101010",
|
||||
vk_format: vk::Format::A2B10G10R10_UNORM_PACK32,
|
||||
bpp: 4,
|
||||
drm: fourcc_code('X', 'B', '3', '0'),
|
||||
..default(ConfigFormat::XBGR2101010)
|
||||
};
|
||||
|
||||
static ABGR16161616: &Format = &Format {
|
||||
name: "abgr16161616",
|
||||
vk_format: vk::Format::R16G16B16A16_UNORM,
|
||||
bpp: 8,
|
||||
drm: fourcc_code('A', 'B', '4', '8'),
|
||||
has_alpha: true,
|
||||
opaque: Some(XBGR16161616),
|
||||
..default(ConfigFormat::ABGR16161616)
|
||||
};
|
||||
|
||||
static XBGR16161616: &Format = &Format {
|
||||
name: "xbgr16161616",
|
||||
vk_format: vk::Format::R16G16B16A16_UNORM,
|
||||
bpp: 8,
|
||||
drm: fourcc_code('X', 'B', '4', '8'),
|
||||
..default(ConfigFormat::XBGR16161616)
|
||||
};
|
||||
|
||||
pub static ABGR16161616F: &Format = &Format {
|
||||
name: "abgr16161616f",
|
||||
vk_format: vk::Format::R16G16B16A16_SFLOAT,
|
||||
bpp: 8,
|
||||
drm: fourcc_code('A', 'B', '4', 'H'),
|
||||
has_alpha: true,
|
||||
opaque: Some(XBGR16161616F),
|
||||
..default(ConfigFormat::ABGR16161616F)
|
||||
};
|
||||
|
||||
static XBGR16161616F: &Format = &Format {
|
||||
name: "xbgr16161616f",
|
||||
vk_format: vk::Format::R16G16B16A16_SFLOAT,
|
||||
bpp: 8,
|
||||
drm: fourcc_code('X', 'B', '4', 'H'),
|
||||
..default(ConfigFormat::XBGR16161616F)
|
||||
};
|
||||
|
||||
static BGR161616: &Format = &Format {
|
||||
name: "bgr161616",
|
||||
vk_format: vk::Format::R16G16B16_UNORM,
|
||||
bpp: 6,
|
||||
drm: fourcc_code('B', 'G', '4', '8'),
|
||||
..default(ConfigFormat::BGR161616)
|
||||
};
|
||||
|
||||
static R16F: &Format = &Format {
|
||||
name: "r16f",
|
||||
vk_format: vk::Format::R16_SFLOAT,
|
||||
bpp: 2,
|
||||
drm: fourcc_code('R', ' ', ' ', 'H'),
|
||||
..default(ConfigFormat::R16F)
|
||||
};
|
||||
|
||||
static GR1616F: &Format = &Format {
|
||||
name: "gr1616f",
|
||||
vk_format: vk::Format::R16G16_SFLOAT,
|
||||
bpp: 4,
|
||||
drm: fourcc_code('G', 'R', ' ', 'H'),
|
||||
..default(ConfigFormat::GR1616F)
|
||||
};
|
||||
|
||||
static BGR161616F: &Format = &Format {
|
||||
name: "bgr161616f",
|
||||
vk_format: vk::Format::R16G16B16_SFLOAT,
|
||||
bpp: 6,
|
||||
drm: fourcc_code('B', 'G', 'R', 'H'),
|
||||
..default(ConfigFormat::BGR161616F)
|
||||
};
|
||||
|
||||
static R32F: &Format = &Format {
|
||||
name: "r32f",
|
||||
vk_format: vk::Format::R32_SFLOAT,
|
||||
bpp: 4,
|
||||
drm: fourcc_code('R', ' ', ' ', 'F'),
|
||||
..default(ConfigFormat::R32F)
|
||||
};
|
||||
|
||||
static GR3232F: &Format = &Format {
|
||||
name: "gr3232f",
|
||||
vk_format: vk::Format::R32G32_SFLOAT,
|
||||
bpp: 8,
|
||||
drm: fourcc_code('G', 'R', ' ', 'F'),
|
||||
..default(ConfigFormat::GR3232F)
|
||||
};
|
||||
|
||||
static BGR323232F: &Format = &Format {
|
||||
name: "bgr323232f",
|
||||
vk_format: vk::Format::R32G32B32_SFLOAT,
|
||||
bpp: 12,
|
||||
drm: fourcc_code('B', 'G', 'R', 'F'),
|
||||
..default(ConfigFormat::BGR323232F)
|
||||
};
|
||||
|
||||
static ABGR32323232F: &Format = &Format {
|
||||
name: "abgr32323232f",
|
||||
vk_format: vk::Format::R32G32B32A32_SFLOAT,
|
||||
bpp: 16,
|
||||
drm: fourcc_code('A', 'B', '8', 'F'),
|
||||
has_alpha: true,
|
||||
..default(ConfigFormat::ABGR32323232F)
|
||||
};
|
||||
|
||||
pub static FORMATS: &[Format] = &[
|
||||
*ARGB8888,
|
||||
*XRGB8888,
|
||||
*ABGR8888,
|
||||
*XBGR8888,
|
||||
*R8,
|
||||
*GR88,
|
||||
*RGB888,
|
||||
*BGR888,
|
||||
#[cfg(target_endian = "little")]
|
||||
*RGBA4444,
|
||||
#[cfg(target_endian = "little")]
|
||||
*RGBX4444,
|
||||
#[cfg(target_endian = "little")]
|
||||
*BGRA4444,
|
||||
#[cfg(target_endian = "little")]
|
||||
*BGRX4444,
|
||||
#[cfg(target_endian = "little")]
|
||||
*RGB565,
|
||||
#[cfg(target_endian = "little")]
|
||||
*BGR565,
|
||||
#[cfg(target_endian = "little")]
|
||||
*RGBA5551,
|
||||
#[cfg(target_endian = "little")]
|
||||
*RGBX5551,
|
||||
#[cfg(target_endian = "little")]
|
||||
*BGRA5551,
|
||||
#[cfg(target_endian = "little")]
|
||||
*BGRX5551,
|
||||
#[cfg(target_endian = "little")]
|
||||
*ARGB1555,
|
||||
#[cfg(target_endian = "little")]
|
||||
*XRGB1555,
|
||||
#[cfg(target_endian = "little")]
|
||||
*ARGB2101010,
|
||||
#[cfg(target_endian = "little")]
|
||||
*XRGB2101010,
|
||||
#[cfg(target_endian = "little")]
|
||||
*ABGR2101010,
|
||||
#[cfg(target_endian = "little")]
|
||||
*XBGR2101010,
|
||||
#[cfg(target_endian = "little")]
|
||||
*ABGR16161616,
|
||||
#[cfg(target_endian = "little")]
|
||||
*XBGR16161616,
|
||||
#[cfg(target_endian = "little")]
|
||||
*ABGR16161616F,
|
||||
#[cfg(target_endian = "little")]
|
||||
*XBGR16161616F,
|
||||
#[cfg(target_endian = "little")]
|
||||
*BGR161616,
|
||||
#[cfg(target_endian = "little")]
|
||||
*R16F,
|
||||
#[cfg(target_endian = "little")]
|
||||
*GR1616F,
|
||||
#[cfg(target_endian = "little")]
|
||||
*BGR161616F,
|
||||
#[cfg(target_endian = "little")]
|
||||
*R32F,
|
||||
#[cfg(target_endian = "little")]
|
||||
*GR3232F,
|
||||
#[cfg(target_endian = "little")]
|
||||
*BGR323232F,
|
||||
#[cfg(target_endian = "little")]
|
||||
*ABGR32323232F,
|
||||
];
|
||||
11
geometry/Cargo.toml
Normal file
11
geometry/Cargo.toml
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
[package]
|
||||
name = "jay-geometry"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
license = "GPL-3.0-only"
|
||||
description = "Geometry primitives for Jay"
|
||||
repository = "https://github.com/mahkoh/jay"
|
||||
|
||||
[dependencies]
|
||||
jay-algorithms = { version = "0.4.0", path = "../algorithms" }
|
||||
smallvec = { version = "1.11.1", features = ["const_generics", "const_new", "union"] }
|
||||
365
geometry/src/lib.rs
Normal file
365
geometry/src/lib.rs
Normal file
|
|
@ -0,0 +1,365 @@
|
|||
mod region;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
pub use region::{DamageQueue, RegionBuilder};
|
||||
use {
|
||||
jay_algorithms::rect::{NoTag, RectRaw, Tag},
|
||||
smallvec::SmallVec,
|
||||
std::fmt::{Debug, Formatter},
|
||||
};
|
||||
|
||||
#[derive(Copy, Clone, Eq, PartialEq, Default)]
|
||||
#[repr(transparent)]
|
||||
pub struct Rect<T = NoTag>
|
||||
where
|
||||
T: Tag,
|
||||
{
|
||||
raw: RectRaw<T>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Eq, PartialEq, Debug, Default)]
|
||||
pub struct Region<T = NoTag>
|
||||
where
|
||||
T: Tag,
|
||||
{
|
||||
rects: SmallVec<[RectRaw<T>; 1]>,
|
||||
extents: Rect,
|
||||
}
|
||||
|
||||
impl Debug for Rect {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
Debug::fmt(&self.raw, f)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq, Default)]
|
||||
pub struct RectOverflow {
|
||||
pub left: i32,
|
||||
pub right: i32,
|
||||
pub top: i32,
|
||||
pub bottom: i32,
|
||||
}
|
||||
|
||||
impl RectOverflow {
|
||||
pub fn is_contained(&self) -> bool {
|
||||
self.left <= 0 && self.right <= 0 && self.top <= 0 && self.bottom <= 0
|
||||
}
|
||||
|
||||
pub fn x_overflow(&self) -> bool {
|
||||
self.left > 0 || self.right > 0
|
||||
}
|
||||
|
||||
pub fn y_overflow(&self) -> bool {
|
||||
self.top > 0 || self.bottom > 0
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Rect<T>
|
||||
where
|
||||
T: Tag,
|
||||
{
|
||||
pub fn untag(&self) -> Rect {
|
||||
Rect {
|
||||
raw: RectRaw {
|
||||
x1: self.raw.x1,
|
||||
y1: self.raw.y1,
|
||||
x2: self.raw.x2,
|
||||
y2: self.raw.y2,
|
||||
tag: NoTag,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Rect {
|
||||
pub fn new_empty(x: i32, y: i32) -> Self {
|
||||
Self {
|
||||
raw: RectRaw {
|
||||
x1: x,
|
||||
y1: y,
|
||||
x2: x,
|
||||
y2: y,
|
||||
tag: NoTag,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new(x1: i32, y1: i32, x2: i32, y2: i32) -> Option<Self> {
|
||||
if x2 < x1 || y2 < y1 {
|
||||
return None;
|
||||
}
|
||||
Some(Self {
|
||||
raw: RectRaw {
|
||||
x1,
|
||||
y1,
|
||||
x2,
|
||||
y2,
|
||||
tag: NoTag,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg_attr(not(test), expect(dead_code))]
|
||||
fn new_unchecked_danger(x1: i32, y1: i32, x2: i32, y2: i32) -> Self {
|
||||
Self {
|
||||
raw: RectRaw {
|
||||
x1,
|
||||
y1,
|
||||
x2,
|
||||
y2,
|
||||
tag: NoTag,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_sized(x1: i32, y1: i32, width: i32, height: i32) -> Option<Self> {
|
||||
if width < 0 || height < 0 {
|
||||
return None;
|
||||
}
|
||||
Self::new(x1, y1, x1 + width, y1 + height)
|
||||
}
|
||||
|
||||
pub fn new_saturating(x1: i32, y1: i32, x2: i32, y2: i32) -> Self {
|
||||
Self {
|
||||
raw: RectRaw {
|
||||
x1,
|
||||
y1,
|
||||
x2: x2.max(x1),
|
||||
y2: y2.max(y1),
|
||||
tag: NoTag,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_sized_saturating(x1: i32, y1: i32, width: i32, height: i32) -> Self {
|
||||
Self {
|
||||
raw: RectRaw {
|
||||
x1,
|
||||
y1,
|
||||
x2: x1.saturating_add(width.max(0)),
|
||||
y2: y1.saturating_add(height.max(0)),
|
||||
tag: NoTag,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn union(&self, other: Self) -> Self {
|
||||
Self {
|
||||
raw: RectRaw {
|
||||
x1: self.raw.x1.min(other.raw.x1),
|
||||
y1: self.raw.y1.min(other.raw.y1),
|
||||
x2: self.raw.x2.max(other.raw.x2),
|
||||
y2: self.raw.y2.max(other.raw.y2),
|
||||
tag: NoTag,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn intersect(&self, other: Self) -> Self {
|
||||
let x1 = self.raw.x1.max(other.raw.x1);
|
||||
let y1 = self.raw.y1.max(other.raw.y1);
|
||||
let x2 = self.raw.x2.min(other.raw.x2).max(x1);
|
||||
let y2 = self.raw.y2.min(other.raw.y2).max(y1);
|
||||
Self {
|
||||
raw: RectRaw {
|
||||
x1,
|
||||
y1,
|
||||
x2,
|
||||
y2,
|
||||
tag: NoTag,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn with_size_saturating(&self, width: i32, height: i32) -> Self {
|
||||
Self::new_sized_saturating(self.raw.x1, self.raw.y1, width, height)
|
||||
}
|
||||
|
||||
pub fn with_tag(&self, tag: u32) -> Rect<u32> {
|
||||
Rect {
|
||||
raw: RectRaw {
|
||||
x1: self.raw.x1,
|
||||
y1: self.raw.y1,
|
||||
x2: self.raw.x2,
|
||||
y2: self.raw.y2,
|
||||
tag,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Rect<T>
|
||||
where
|
||||
T: Tag,
|
||||
{
|
||||
#[cfg_attr(not(test), expect(dead_code))]
|
||||
fn new_unchecked_danger_tagged(x1: i32, y1: i32, x2: i32, y2: i32, tag: T) -> Self {
|
||||
Self {
|
||||
raw: RectRaw {
|
||||
x1,
|
||||
y1,
|
||||
x2,
|
||||
y2,
|
||||
tag,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn intersects(&self, other: &Self) -> bool {
|
||||
self.raw.x1 < other.raw.x2
|
||||
&& other.raw.x1 < self.raw.x2
|
||||
&& self.raw.y1 < other.raw.y2
|
||||
&& other.raw.y1 < self.raw.y2
|
||||
}
|
||||
|
||||
pub fn contains(&self, x: i32, y: i32) -> bool {
|
||||
self.raw.x1 <= x && self.raw.y1 <= y && self.raw.x2 > x && self.raw.y2 > y
|
||||
}
|
||||
|
||||
pub fn not_contains(&self, x: i32, y: i32) -> bool {
|
||||
!self.contains(x, y)
|
||||
}
|
||||
|
||||
pub fn dist_squared(&self, x: i32, y: i32) -> i128 {
|
||||
let x = x as i64;
|
||||
let y = y as i64;
|
||||
let x1 = self.raw.x1 as i64;
|
||||
let x2 = self.raw.x2 as i64;
|
||||
let y1 = self.raw.y1 as i64;
|
||||
let y2 = self.raw.y2 as i64;
|
||||
let mut dx = 0;
|
||||
if x1 > x {
|
||||
dx = x1 - x;
|
||||
} else if x2 < x {
|
||||
dx = x - x2;
|
||||
}
|
||||
let mut dy = 0;
|
||||
if y1 > y {
|
||||
dy = y1 - y;
|
||||
} else if y2 < y {
|
||||
dy = y - y2;
|
||||
}
|
||||
let dx = dx as i128;
|
||||
let dy = dy as i128;
|
||||
dx * dx + dy * dy
|
||||
}
|
||||
|
||||
pub fn contains_rect<U>(&self, rect: &Rect<U>) -> bool
|
||||
where
|
||||
U: Tag,
|
||||
{
|
||||
self.raw.x1 <= rect.raw.x1
|
||||
&& self.raw.y1 <= rect.raw.x1
|
||||
&& rect.raw.x2 <= self.raw.x2
|
||||
&& rect.raw.y2 <= self.raw.y2
|
||||
}
|
||||
|
||||
pub fn get_overflow<U>(&self, child: &Rect<U>) -> RectOverflow
|
||||
where
|
||||
U: Tag,
|
||||
{
|
||||
RectOverflow {
|
||||
left: self.raw.x1 - child.raw.x1,
|
||||
right: child.raw.x2 - self.raw.x2,
|
||||
top: self.raw.y1 - child.raw.y1,
|
||||
bottom: child.raw.y2 - self.raw.y2,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.raw.x1 == self.raw.x2 || self.raw.y1 == self.raw.y2
|
||||
}
|
||||
|
||||
pub fn is_not_empty(&self) -> bool {
|
||||
!self.is_empty()
|
||||
}
|
||||
|
||||
pub fn to_origin(&self) -> Self {
|
||||
Self {
|
||||
raw: RectRaw {
|
||||
x1: 0,
|
||||
y1: 0,
|
||||
x2: self.raw.x2 - self.raw.x1,
|
||||
y2: self.raw.y2 - self.raw.y1,
|
||||
tag: self.raw.tag,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn move_(&self, dx: i32, dy: i32) -> Self {
|
||||
Self {
|
||||
raw: RectRaw {
|
||||
x1: self.raw.x1.saturating_add(dx),
|
||||
y1: self.raw.y1.saturating_add(dy),
|
||||
x2: self.raw.x2.saturating_add(dx),
|
||||
y2: self.raw.y2.saturating_add(dy),
|
||||
tag: self.raw.tag,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn at_point(&self, x1: i32, y1: i32) -> Self {
|
||||
Self {
|
||||
raw: RectRaw {
|
||||
x1,
|
||||
y1,
|
||||
x2: x1 + self.raw.x2 - self.raw.x1,
|
||||
y2: y1 + self.raw.y2 - self.raw.y1,
|
||||
tag: self.raw.tag,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn translate(&self, x: i32, y: i32) -> (i32, i32) {
|
||||
(x.wrapping_sub(self.raw.x1), y.wrapping_sub(self.raw.y1))
|
||||
}
|
||||
|
||||
pub fn translate_inv(&self, x: i32, y: i32) -> (i32, i32) {
|
||||
(x.wrapping_add(self.raw.x1), y.wrapping_add(self.raw.y1))
|
||||
}
|
||||
|
||||
pub fn x1(&self) -> i32 {
|
||||
self.raw.x1
|
||||
}
|
||||
|
||||
pub fn x2(&self) -> i32 {
|
||||
self.raw.x2
|
||||
}
|
||||
|
||||
pub fn y1(&self) -> i32 {
|
||||
self.raw.y1
|
||||
}
|
||||
|
||||
pub fn y2(&self) -> i32 {
|
||||
self.raw.y2
|
||||
}
|
||||
|
||||
pub fn width(&self) -> i32 {
|
||||
self.raw.x2 - self.raw.x1
|
||||
}
|
||||
|
||||
pub fn height(&self) -> i32 {
|
||||
self.raw.y2 - self.raw.y1
|
||||
}
|
||||
|
||||
pub fn position(&self) -> (i32, i32) {
|
||||
(self.raw.x1, self.raw.y1)
|
||||
}
|
||||
|
||||
pub fn size(&self) -> (i32, i32) {
|
||||
(self.width(), self.height())
|
||||
}
|
||||
|
||||
pub fn center(&self) -> (i32, i32) {
|
||||
(
|
||||
self.raw.x1 + self.width() / 2,
|
||||
self.raw.y1 + self.height() / 2,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn tag(&self) -> T {
|
||||
self.raw.tag
|
||||
}
|
||||
}
|
||||
|
|
@ -1,11 +1,5 @@
|
|||
use {
|
||||
crate::{
|
||||
rect::{Rect, Region},
|
||||
utils::{
|
||||
array,
|
||||
ptr_ext::{MutPtrExt, PtrExt},
|
||||
},
|
||||
},
|
||||
crate::{Rect, Region},
|
||||
jay_algorithms::rect::{
|
||||
RectRaw, Tag,
|
||||
region::{
|
||||
|
|
@ -15,6 +9,7 @@ use {
|
|||
},
|
||||
smallvec::SmallVec,
|
||||
std::{
|
||||
array,
|
||||
borrow::Cow,
|
||||
cell::UnsafeCell,
|
||||
fmt::{Debug, Formatter},
|
||||
|
|
@ -176,7 +171,6 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(not(feature = "it"), expect(dead_code))]
|
||||
pub fn extents(&self) -> Rect {
|
||||
self.extents
|
||||
}
|
||||
|
|
@ -274,7 +268,6 @@ impl RegionBuilder {
|
|||
self.base.clone()
|
||||
}
|
||||
|
||||
#[expect(dead_code)]
|
||||
pub fn clear(&mut self) {
|
||||
self.pending.clear();
|
||||
self.base = Region::empty();
|
||||
|
|
@ -321,26 +314,26 @@ impl DamageQueue {
|
|||
}
|
||||
|
||||
pub fn damage(&self, rects: &[Rect]) {
|
||||
let datas = unsafe { self.datas.get().deref_mut() };
|
||||
let datas = unsafe { &mut *self.datas.get() };
|
||||
for data in datas {
|
||||
data.extend(rects);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn clear(&self) {
|
||||
let data = unsafe { &mut self.datas.get().deref_mut()[self.this] };
|
||||
let data = unsafe { &mut (&mut *self.datas.get())[self.this] };
|
||||
data.clear();
|
||||
}
|
||||
|
||||
pub fn clear_all(&self) {
|
||||
let datas = unsafe { self.datas.get().deref_mut() };
|
||||
let datas = unsafe { &mut *self.datas.get() };
|
||||
for data in datas {
|
||||
data.clear();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get(&self) -> Region {
|
||||
let data = unsafe { &self.datas.get().deref()[self.this] };
|
||||
let data = unsafe { &(&*self.datas.get())[self.this] };
|
||||
Region::from_rects2(data)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
use {
|
||||
crate::rect::{Rect, Region},
|
||||
crate::{Rect, Region},
|
||||
jay_algorithms::rect::{NoTag, RectRaw},
|
||||
};
|
||||
|
||||
9
jay-config-schema/Cargo.toml
Normal file
9
jay-config-schema/Cargo.toml
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
[package]
|
||||
name = "jay-config-schema"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
license = "GPL-3.0-only"
|
||||
description = "Shared configuration schema declarations for the Jay compositor"
|
||||
repository = "https://github.com/mahkoh/jay"
|
||||
|
||||
[dependencies]
|
||||
13
jay-config-schema/src/animations.rs
Normal file
13
jay-config-schema/src/animations.rs
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
#[derive(Debug, Clone, Default)]
|
||||
pub struct Animations {
|
||||
pub enabled: Option<bool>,
|
||||
pub duration_ms: Option<u32>,
|
||||
pub style: Option<String>,
|
||||
pub curve: Option<AnimationCurveConfig>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub enum AnimationCurveConfig {
|
||||
Preset(String),
|
||||
CubicBezier([f32; 4]),
|
||||
}
|
||||
9
jay-config-schema/src/lib.rs
Normal file
9
jay-config-schema/src/lib.rs
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
//! Shared configuration schema declarations for Jay.
|
||||
//!
|
||||
//! This crate is the target home for option structs, defaults, validation
|
||||
//! policy, and docs metadata that need to be consumed by TOML parsing,
|
||||
//! generated config documentation, and compositor-side application code.
|
||||
|
||||
pub mod animations;
|
||||
|
||||
pub use animations::{AnimationCurveConfig, Animations};
|
||||
|
|
@ -12,7 +12,6 @@ use {
|
|||
},
|
||||
bincode::Options,
|
||||
serde::{Deserialize, Serialize},
|
||||
std::marker::PhantomData,
|
||||
};
|
||||
|
||||
pub const VERSION: u32 = 1;
|
||||
|
|
@ -31,12 +30,6 @@ pub struct ConfigEntry {
|
|||
pub handle_msg: unsafe extern "C" fn(data: *const u8, msg: *const u8, size: usize),
|
||||
}
|
||||
|
||||
pub struct ConfigEntryGen<T> {
|
||||
_phantom: PhantomData<T>,
|
||||
}
|
||||
|
||||
impl<T: Config> ConfigEntryGen<T> {}
|
||||
|
||||
pub fn bincode_ops() -> impl Options {
|
||||
bincode::DefaultOptions::new()
|
||||
.with_fixint_encoding()
|
||||
|
|
@ -44,10 +37,6 @@ pub fn bincode_ops() -> impl Options {
|
|||
.with_no_limit()
|
||||
}
|
||||
|
||||
pub trait Config {
|
||||
extern "C" fn configure();
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
pub struct WireMode {
|
||||
pub width: i32,
|
||||
|
|
@ -99,7 +88,6 @@ pub enum ClientCriterionStringField {
|
|||
SandboxInstanceId,
|
||||
Comm,
|
||||
Exe,
|
||||
Tag,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Debug, Hash, Eq, PartialEq)]
|
||||
|
|
|
|||
|
|
@ -3,16 +3,14 @@
|
|||
use {
|
||||
crate::{
|
||||
_private::{
|
||||
ClientCriterionIpc, ClientCriterionStringField, Config, ConfigEntry, ConfigEntryGen,
|
||||
GenericCriterionIpc, PollableId, VERSION, WindowCriterionIpc,
|
||||
WindowCriterionStringField, WireMode, bincode_ops,
|
||||
ClientCriterionIpc, ClientCriterionStringField, GenericCriterionIpc, PollableId,
|
||||
WindowCriterionIpc, WindowCriterionStringField, WireMode, bincode_ops,
|
||||
ipc::{
|
||||
ClientMessage, InitMessage, Response, ServerFeature, ServerMessage, WorkspaceSource,
|
||||
},
|
||||
logging,
|
||||
},
|
||||
Axis, Direction, ModifiedKeySym, PciId, Workspace,
|
||||
client::{Client, ClientCapabilities, ClientCriterion, ClientMatcher, MatchedClient},
|
||||
client::{Client, ClientCriterion, ClientMatcher, MatchedClient},
|
||||
exec::Command,
|
||||
input::{
|
||||
FallbackOutputMode, FocusFollowsMouseMode, InputDevice, LayerDirection, Seat,
|
||||
|
|
@ -199,35 +197,6 @@ unsafe fn with_client<T, F: FnOnce(&ConfigClient) -> T>(data: *const u8, f: F) -
|
|||
})
|
||||
}
|
||||
|
||||
impl<T: Config> ConfigEntryGen<T> {
|
||||
pub const ENTRY: ConfigEntry = ConfigEntry {
|
||||
version: VERSION,
|
||||
init: Self::init,
|
||||
unref,
|
||||
handle_msg,
|
||||
};
|
||||
|
||||
pub unsafe extern "C" fn init(
|
||||
srv_data: *const u8,
|
||||
srv_unref: unsafe extern "C" fn(data: *const u8),
|
||||
srv_handler: unsafe extern "C" fn(data: *const u8, msg: *const u8, size: usize),
|
||||
init_data: *const u8,
|
||||
size: usize,
|
||||
) -> *const u8 {
|
||||
logging::init();
|
||||
unsafe {
|
||||
init(
|
||||
srv_data,
|
||||
srv_unref,
|
||||
srv_handler,
|
||||
init_data,
|
||||
size,
|
||||
T::configure,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub unsafe extern "C" fn init(
|
||||
srv_data: *const u8,
|
||||
srv_unref: unsafe extern "C" fn(data: *const u8),
|
||||
|
|
@ -348,15 +317,7 @@ impl ConfigClient {
|
|||
.drain()
|
||||
.map(|(a, b)| (a, b.into_raw_fd()))
|
||||
.collect();
|
||||
if command.tag.is_some() {
|
||||
self.send(&ClientMessage::Run3 {
|
||||
prog: &command.prog,
|
||||
args: command.args.clone(),
|
||||
env,
|
||||
fds,
|
||||
tag: command.tag.as_deref(),
|
||||
});
|
||||
} else if fds.is_empty() {
|
||||
if fds.is_empty() {
|
||||
self.send(&ClientMessage::Run {
|
||||
prog: &command.prog,
|
||||
args: command.args.clone(),
|
||||
|
|
@ -1556,22 +1517,6 @@ impl ConfigClient {
|
|||
connector
|
||||
}
|
||||
|
||||
pub fn set_client_matcher_capabilities(
|
||||
&self,
|
||||
matcher: ClientMatcher,
|
||||
caps: ClientCapabilities,
|
||||
) {
|
||||
self.send(&ClientMessage::SetClientMatcherCapabilities { matcher, caps });
|
||||
}
|
||||
|
||||
pub fn set_client_matcher_bounding_capabilities(
|
||||
&self,
|
||||
matcher: ClientMatcher,
|
||||
caps: ClientCapabilities,
|
||||
) {
|
||||
self.send(&ClientMessage::SetClientMatcherBoundingCapabilities { matcher, caps });
|
||||
}
|
||||
|
||||
pub fn latch<F: FnOnce() + 'static>(&self, seat: Seat, f: F) {
|
||||
if !self.feat_mod_mask.get() {
|
||||
log::error!("compositor does not support latching");
|
||||
|
|
@ -1673,12 +1618,6 @@ impl ConfigClient {
|
|||
})
|
||||
}
|
||||
|
||||
pub fn get_socket_path(&self) -> Option<String> {
|
||||
let res = self.send_with_response(&ClientMessage::GetSocketPath);
|
||||
get_response!(res, None, GetSocketPath { path });
|
||||
Some(path)
|
||||
}
|
||||
|
||||
pub fn create_pollable(&self, fd: i32) -> Result<PollableId, String> {
|
||||
let res = self.send_with_response(&ClientMessage::AddPollable { fd });
|
||||
get_response!(
|
||||
|
|
@ -1867,8 +1806,6 @@ impl ConfigClient {
|
|||
ClientCriterion::CommRegex(t) => string!(t, Comm, true),
|
||||
ClientCriterion::Exe(t) => string!(t, Exe, false),
|
||||
ClientCriterion::ExeRegex(t) => string!(t, Exe, true),
|
||||
ClientCriterion::Tag(t) => string!(t, Tag, false),
|
||||
ClientCriterion::TagRegex(t) => string!(t, Tag, true),
|
||||
};
|
||||
let res = self.send_with_response(&ClientMessage::CreateClientMatcher { criterion });
|
||||
get_response!(
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ use {
|
|||
crate::{
|
||||
_private::{ClientCriterionIpc, PollableId, WindowCriterionIpc, WireMode},
|
||||
Axis, Direction, PciId, Workspace,
|
||||
client::{Client, ClientCapabilities, ClientMatcher},
|
||||
client::{Client, ClientMatcher},
|
||||
input::{
|
||||
FallbackOutputMode, FocusFollowsMouseMode, InputDevice, LayerDirection, Seat,
|
||||
SwitchEvent, Timeline, acceleration::AccelProfile, capability::Capability,
|
||||
|
|
@ -488,7 +488,6 @@ pub enum ClientMessage<'a> {
|
|||
SetExplicitSyncEnabled {
|
||||
enabled: bool,
|
||||
},
|
||||
GetSocketPath,
|
||||
DeviceSetKeymap {
|
||||
device: InputDevice,
|
||||
keymap: Keymap,
|
||||
|
|
@ -806,14 +805,6 @@ pub enum ClientMessage<'a> {
|
|||
SetTitleFont {
|
||||
font: &'a str,
|
||||
},
|
||||
SetClientMatcherCapabilities {
|
||||
matcher: ClientMatcher,
|
||||
caps: ClientCapabilities,
|
||||
},
|
||||
SetClientMatcherBoundingCapabilities {
|
||||
matcher: ClientMatcher,
|
||||
caps: ClientCapabilities,
|
||||
},
|
||||
ShowWorkspaceOn {
|
||||
seat: Seat,
|
||||
workspace: Workspace,
|
||||
|
|
@ -868,13 +859,6 @@ pub enum ClientMessage<'a> {
|
|||
SetXWaylandEnabled {
|
||||
enabled: bool,
|
||||
},
|
||||
Run3 {
|
||||
prog: &'a str,
|
||||
args: Vec<String>,
|
||||
env: Vec<(String, String)>,
|
||||
fds: Vec<(i32, i32)>,
|
||||
tag: Option<&'a str>,
|
||||
},
|
||||
ConnectorSupportsArbitraryModes {
|
||||
connector: Connector,
|
||||
},
|
||||
|
|
@ -1081,9 +1065,6 @@ pub enum Response {
|
|||
GetInputDeviceDevnode {
|
||||
devnode: String,
|
||||
},
|
||||
GetSocketPath {
|
||||
path: String,
|
||||
},
|
||||
GetFloatAboveFullscreen {
|
||||
above: bool,
|
||||
},
|
||||
|
|
|
|||
|
|
@ -91,10 +91,6 @@ pub enum ClientCriterion<'a> {
|
|||
Exe(&'a str),
|
||||
/// Matches the `/proc/pid/exe` of the client with a regular expression.
|
||||
ExeRegex(&'a str),
|
||||
/// Matches the tag of the client verbatim.
|
||||
Tag(&'a str),
|
||||
/// Matches the tag of the client with a regular expression.
|
||||
TagRegex(&'a str),
|
||||
}
|
||||
|
||||
impl ClientCriterion<'_> {
|
||||
|
|
@ -110,19 +106,6 @@ impl ClientCriterion<'_> {
|
|||
self.to_matcher().bind(cb);
|
||||
}
|
||||
|
||||
/// Sets the capabilities granted to clients matching this matcher.
|
||||
///
|
||||
/// This leaks the matcher.
|
||||
pub fn set_capabilities(self, caps: ClientCapabilities) {
|
||||
self.to_matcher().set_capabilities(caps);
|
||||
}
|
||||
|
||||
/// Sets the upper capability bounds for clients in sandboxes created by this client.
|
||||
///
|
||||
/// This leaks the matcher.
|
||||
pub fn set_sandbox_bounding_capabilities(self, caps: ClientCapabilities) {
|
||||
self.to_matcher().set_sandbox_bounding_capabilities(caps);
|
||||
}
|
||||
}
|
||||
|
||||
impl ClientMatcher {
|
||||
|
|
@ -140,35 +123,6 @@ impl ClientMatcher {
|
|||
get!().set_client_matcher_handler(self, cb);
|
||||
}
|
||||
|
||||
/// Sets the capabilities granted to clients matching this matcher.
|
||||
///
|
||||
/// If multiple matchers match a client, the capabilities are added.
|
||||
///
|
||||
/// If no matcher matches a client, it is granted the default capabilities depending
|
||||
/// on whether it's sandboxed or not. If it is not sandboxed, it is granted the
|
||||
/// capabilities [`CC_LAYER_SHELL`] and [`CC_DRM_LEASE`]. Otherwise it is granted the
|
||||
/// capability [`CC_DRM_LEASE`].
|
||||
///
|
||||
/// Regardless of any capabilities set through this function, the capabilities of the
|
||||
/// client can never exceed its bounding capabilities.
|
||||
pub fn set_capabilities(self, caps: ClientCapabilities) {
|
||||
get!().set_client_matcher_capabilities(self, caps);
|
||||
}
|
||||
|
||||
/// Sets the upper capability bounds for clients in sandboxes created by this client.
|
||||
///
|
||||
/// If multiple matchers match a client, the capabilities are added.
|
||||
///
|
||||
/// If no matcher matches a client, the bounding capabilities for sandboxes depend on
|
||||
/// whether the client is itself sandboxed. If it is sandboxed, the bounding
|
||||
/// capabilities are the effective capabilities of the client. Otherwise the bounding
|
||||
/// capabilities are all capabilities.
|
||||
///
|
||||
/// Regardless of any capabilities set through this function, the capabilities set
|
||||
/// through this function can never exceed the client's bounding capabilities.
|
||||
pub fn set_sandbox_bounding_capabilities(self, caps: ClientCapabilities) {
|
||||
get!().set_client_matcher_bounding_capabilities(self, caps);
|
||||
}
|
||||
}
|
||||
|
||||
impl MatchedClient {
|
||||
|
|
@ -195,45 +149,3 @@ impl Deref for MatchedClient {
|
|||
&self.client
|
||||
}
|
||||
}
|
||||
|
||||
bitflags! {
|
||||
/// Capabilities granted to a client.
|
||||
#[derive(Serialize, Deserialize, Copy, Clone, Hash, Eq, PartialEq)]
|
||||
pub struct ClientCapabilities(pub u64) {
|
||||
/// Grants access to the `ext_data_control_manager_v1` and
|
||||
/// `zwlr_data_control_manager_v1` globals.
|
||||
pub const CC_DATA_CONTROL = 1 << 0,
|
||||
/// Grants access to the `zwp_virtual_keyboard_manager_v1` global.
|
||||
pub const CC_VIRTUAL_KEYBOARD = 1 << 1,
|
||||
/// Grants access to the `ext_foreign_toplevel_list_v1` global.
|
||||
pub const CC_FOREIGN_TOPLEVEL_LIST = 1 << 2,
|
||||
/// Grants access to the `ext_idle_notifier_v1` global.
|
||||
pub const CC_IDLE_NOTIFIER = 1 << 3,
|
||||
/// Grants access to the `ext_session_lock_manager_v1` global.
|
||||
pub const CC_SESSION_LOCK = 1 << 4,
|
||||
/// Grants access to the `zwlr_layer_shell_v1` global.
|
||||
pub const CC_LAYER_SHELL = 1 << 6,
|
||||
/// Grants access to the `ext_image_copy_capture_manager_v1` and
|
||||
/// `zwlr_screencopy_manager_v1` globals.
|
||||
pub const CC_SCREENCOPY = 1 << 7,
|
||||
/// Grants access to the `ext_transient_seat_manager_v1` global.
|
||||
pub const CC_SEAT_MANAGER = 1 << 8,
|
||||
/// Grants access to the `wp_drm_lease_device_v1` global.
|
||||
pub const CC_DRM_LEASE = 1 << 9,
|
||||
/// Grants access to the `zwp_input_method_manager_v2` global.
|
||||
pub const CC_INPUT_METHOD = 1 << 10,
|
||||
/// Grants access to the `ext_workspace_manager_v1` global.
|
||||
pub const CC_WORKSPACE_MANAGER = 1 << 11,
|
||||
/// Grants access to the `zwlr_foreign_toplevel_manager_v1` global.
|
||||
pub const CC_FOREIGN_TOPLEVEL_MANAGER = 1 << 12,
|
||||
/// Grants access to the `jay_head_manager_v1` and `zwlr_output_manager_v1`
|
||||
/// globals.
|
||||
pub const CC_HEAD_MANAGER = 1 << 13,
|
||||
/// Grants access to the `zwlr_gamma_control_manager_v1` global.
|
||||
pub const CC_GAMMA_CONTROL_MANAGER = 1 << 14,
|
||||
/// Grants access to the `zwlr_virtual_pointer_manager_v1` global.
|
||||
pub const CC_VIRTUAL_POINTER = 1 << 15,
|
||||
/// Grants access to the `ext_foreign_toplevel_geometry_tracking_manager_v1` global.
|
||||
pub const CC_FOREIGN_TOPLEVEL_GEOMETRY_TRACKING = 1 << 16,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,7 +22,6 @@ pub struct Command {
|
|||
pub(crate) args: Vec<String>,
|
||||
pub(crate) env: HashMap<String, String>,
|
||||
pub(crate) fds: RefCell<HashMap<i32, OwnedFd>>,
|
||||
pub(crate) tag: Option<String>,
|
||||
}
|
||||
|
||||
impl Command {
|
||||
|
|
@ -38,7 +37,6 @@ impl Command {
|
|||
args: vec![],
|
||||
env: Default::default(),
|
||||
fds: Default::default(),
|
||||
tag: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -84,27 +82,6 @@ impl Command {
|
|||
self.fd(2, fd)
|
||||
}
|
||||
|
||||
/// Runs the application with access to privileged wayland protocols.
|
||||
///
|
||||
/// The default is `false`.
|
||||
pub fn privileged(&mut self) -> &mut Self {
|
||||
match get!(self).get_socket_path() {
|
||||
Some(path) => {
|
||||
self.env("WAYLAND_DISPLAY", &format!("{path}.jay"));
|
||||
}
|
||||
_ => {
|
||||
log::error!("Compositor did not send the socket path");
|
||||
}
|
||||
}
|
||||
self
|
||||
}
|
||||
|
||||
/// Adds a tag to Wayland connections created by the spawned command.
|
||||
pub fn tag(&mut self, tag: &str) -> &mut Self {
|
||||
self.tag = Some(tag.to_owned());
|
||||
self
|
||||
}
|
||||
|
||||
/// Executes the command.
|
||||
///
|
||||
/// This consumes all attached file descriptors.
|
||||
|
|
|
|||
|
|
@ -832,8 +832,6 @@ pub enum SwitchEvent {
|
|||
|
||||
/// Enables or disables the unauthenticated libei socket.
|
||||
///
|
||||
/// Even if the socket is disabled, application can still request access via the portal.
|
||||
///
|
||||
/// The default is `false`.
|
||||
pub fn set_libei_socket_enabled(enabled: bool) {
|
||||
get!().set_ei_socket_enabled(enabled);
|
||||
|
|
|
|||
|
|
@ -1,36 +1,5 @@
|
|||
//! This crate allows you to configure the Jay compositor.
|
||||
//!
|
||||
//! A minimal example configuration looks as follows:
|
||||
//!
|
||||
//! ```rust
|
||||
//! 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, 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.
|
||||
//! Internal Rust configuration API used by Jay's built-in TOML configuration
|
||||
//! implementation.
|
||||
|
||||
#![allow(
|
||||
clippy::zero_prefixed_literal,
|
||||
|
|
|
|||
|
|
@ -1,21 +1,3 @@
|
|||
/// Declares the entry point of the configuration.
|
||||
#[macro_export]
|
||||
macro_rules! config {
|
||||
($f:path) => {
|
||||
#[unsafe(no_mangle)]
|
||||
#[used]
|
||||
pub static mut JAY_CONFIG_ENTRY_V1: $crate::_private::ConfigEntry = {
|
||||
struct X;
|
||||
impl $crate::_private::Config for X {
|
||||
extern "C" fn configure() {
|
||||
$f();
|
||||
}
|
||||
}
|
||||
$crate::_private::ConfigEntryGen::<X>::ENTRY
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! try_get {
|
||||
() => {{
|
||||
unsafe {
|
||||
|
|
|
|||
10
layout-animation/Cargo.toml
Normal file
10
layout-animation/Cargo.toml
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
[package]
|
||||
name = "jay-layout-animation"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
license = "GPL-3.0-only"
|
||||
description = "Layout animation planning for Jay"
|
||||
repository = "https://github.com/mahkoh/jay"
|
||||
|
||||
[dependencies]
|
||||
jay-geometry = { version = "0.1.0", path = "../geometry" }
|
||||
3410
layout-animation/src/lib.rs
Normal file
3410
layout-animation/src/lib.rs
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -1,7 +1,6 @@
|
|||
use {
|
||||
crate::{
|
||||
async_engine::SpawnedFuture,
|
||||
client::ClientCaps,
|
||||
security_context_acceptor::AcceptorMetadata,
|
||||
state::State,
|
||||
utils::{
|
||||
|
|
@ -46,63 +45,49 @@ struct AllocatedSocket {
|
|||
name: String,
|
||||
// /run/user/1000/wayland-x
|
||||
path: Ustring,
|
||||
insecure: Rc<OwnedFd>,
|
||||
socket: Rc<OwnedFd>,
|
||||
// /run/user/1000/wayland-x.lock
|
||||
lock_path: Ustring,
|
||||
_lock_fd: OwnedFd,
|
||||
// /run/user/1000/wayland-x.jay
|
||||
secure_path: Ustring,
|
||||
secure: Rc<OwnedFd>,
|
||||
}
|
||||
|
||||
impl Drop for AllocatedSocket {
|
||||
fn drop(&mut self) {
|
||||
let _ = uapi::unlink(&self.path);
|
||||
let _ = uapi::unlink(&self.lock_path);
|
||||
let _ = uapi::unlink(&self.secure_path);
|
||||
}
|
||||
}
|
||||
|
||||
fn bind_socket(
|
||||
insecure: &Rc<OwnedFd>,
|
||||
secure: &Rc<OwnedFd>,
|
||||
xrd: &str,
|
||||
id: u32,
|
||||
) -> Result<AllocatedSocket, AcceptorError> {
|
||||
fn bind_socket(socket: &Rc<OwnedFd>, xrd: &str, id: u32) -> Result<AllocatedSocket, AcceptorError> {
|
||||
let mut addr: c::sockaddr_un = uapi::pod_zeroed();
|
||||
addr.sun_family = c::AF_UNIX as _;
|
||||
let name = format!("wayland-{}", id);
|
||||
let path = format_ustr!("{}/{}", xrd, name);
|
||||
let jay_path = format_ustr!("{}.jay", path.display());
|
||||
let lock_path = format_ustr!("{}.lock", path.display());
|
||||
if jay_path.len() + 1 > addr.sun_path.len() {
|
||||
if path.len() + 1 > addr.sun_path.len() {
|
||||
return Err(AcceptorError::XrdTooLong(xrd.to_string()));
|
||||
}
|
||||
let lock_fd = uapi::open(&*lock_path, c::O_CREAT | c::O_CLOEXEC | c::O_RDWR, 0o644)
|
||||
.map_os_err(AcceptorError::OpenLockFile)?;
|
||||
uapi::flock(lock_fd.raw(), c::LOCK_EX | c::LOCK_NB).map_os_err(AcceptorError::LockLockFile)?;
|
||||
for (name, fd) in [(&path, insecure), (&jay_path, secure)] {
|
||||
match uapi::lstat(name).to_os_error() {
|
||||
Ok(_) => {
|
||||
log::info!("Unlinking {}", name.display());
|
||||
let _ = uapi::unlink(name);
|
||||
}
|
||||
Err(OsError(c::ENOENT)) => {}
|
||||
Err(e) => return Err(AcceptorError::SocketStat(e)),
|
||||
match uapi::lstat(&path).to_os_error() {
|
||||
Ok(_) => {
|
||||
log::info!("Unlinking {}", path.display());
|
||||
let _ = uapi::unlink(&path);
|
||||
}
|
||||
let sun_path = uapi::as_bytes_mut(&mut addr.sun_path[..]);
|
||||
sun_path[..name.len()].copy_from_slice(name.as_bytes());
|
||||
sun_path[name.len()] = 0;
|
||||
uapi::bind(fd.raw(), &addr).map_os_err(AcceptorError::BindFailed)?;
|
||||
Err(OsError(c::ENOENT)) => {}
|
||||
Err(e) => return Err(AcceptorError::SocketStat(e)),
|
||||
}
|
||||
let sun_path = uapi::as_bytes_mut(&mut addr.sun_path[..]);
|
||||
sun_path[..path.len()].copy_from_slice(path.as_bytes());
|
||||
sun_path[path.len()] = 0;
|
||||
uapi::bind(socket.raw(), &addr).map_os_err(AcceptorError::BindFailed)?;
|
||||
Ok(AllocatedSocket {
|
||||
name,
|
||||
path,
|
||||
insecure: insecure.clone(),
|
||||
socket: socket.clone(),
|
||||
lock_path,
|
||||
_lock_fd: lock_fd,
|
||||
secure_path: jay_path,
|
||||
secure: secure.clone(),
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -111,17 +96,11 @@ fn allocate_socket() -> Result<AllocatedSocket, AcceptorError> {
|
|||
Some(d) => d,
|
||||
_ => return Err(AcceptorError::XrdNotSet),
|
||||
};
|
||||
let mut fds = [None, None];
|
||||
for fd in &mut fds {
|
||||
let socket = uapi::socket(c::AF_UNIX, c::SOCK_STREAM | c::SOCK_CLOEXEC, 0)
|
||||
.map(Rc::new)
|
||||
.map_os_err(AcceptorError::SocketFailed)?;
|
||||
*fd = Some(socket);
|
||||
}
|
||||
let unsecure = fds[0].take().unwrap();
|
||||
let secure = fds[1].take().unwrap();
|
||||
let socket = uapi::socket(c::AF_UNIX, c::SOCK_STREAM | c::SOCK_CLOEXEC, 0)
|
||||
.map(Rc::new)
|
||||
.map_os_err(AcceptorError::SocketFailed)?;
|
||||
for i in 1..1000 {
|
||||
match bind_socket(&unsecure, &secure, &xrd, i) {
|
||||
match bind_socket(&socket, &xrd, i) {
|
||||
Ok(s) => return Ok(s),
|
||||
Err(e) => {
|
||||
log::warn!("Cannot use the wayland-{} socket: {}", i, ErrorFmt(e));
|
||||
|
|
@ -137,19 +116,12 @@ impl Acceptor {
|
|||
) -> Result<(Rc<Acceptor>, Vec<SpawnedFuture<()>>), AcceptorError> {
|
||||
let socket = allocate_socket()?;
|
||||
log::info!("bound to socket {}", socket.path.display());
|
||||
for fd in [&socket.secure, &socket.insecure] {
|
||||
uapi::listen(fd.raw(), 4096).map_os_err(AcceptorError::ListenFailed)?;
|
||||
}
|
||||
uapi::listen(socket.socket.raw(), 4096).map_os_err(AcceptorError::ListenFailed)?;
|
||||
let acc = Rc::new(Acceptor { socket });
|
||||
let futures = vec![
|
||||
state.eng.spawn(
|
||||
"secure acceptor",
|
||||
accept(acc.socket.secure.clone(), state.clone(), true),
|
||||
),
|
||||
state.eng.spawn(
|
||||
"insecure acceptor",
|
||||
accept(acc.socket.insecure.clone(), state.clone(), false),
|
||||
),
|
||||
state
|
||||
.eng
|
||||
.spawn("client acceptor", accept(acc.socket.socket.clone(), state.clone())),
|
||||
];
|
||||
state.acceptor.set(Some(acc.clone()));
|
||||
Ok((acc, futures))
|
||||
|
|
@ -160,16 +132,13 @@ impl Acceptor {
|
|||
}
|
||||
|
||||
#[cfg_attr(not(feature = "it"), expect(dead_code))]
|
||||
pub fn secure_path(&self) -> &Ustr {
|
||||
self.socket.secure_path.as_ustr()
|
||||
pub fn socket_path(&self) -> &Ustr {
|
||||
self.socket.path.as_ustr()
|
||||
}
|
||||
}
|
||||
|
||||
async fn accept(fd: Rc<OwnedFd>, state: Rc<State>, secure: bool) {
|
||||
let metadata = Rc::new(AcceptorMetadata {
|
||||
secure,
|
||||
..Default::default()
|
||||
});
|
||||
async fn accept(fd: Rc<OwnedFd>, state: Rc<State>) {
|
||||
let metadata = Rc::new(AcceptorMetadata::default());
|
||||
loop {
|
||||
let fd = match state.ring.accept(&fd, c::SOCK_CLOEXEC).await {
|
||||
Ok(fd) => fd,
|
||||
|
|
@ -181,7 +150,7 @@ async fn accept(fd: Rc<OwnedFd>, state: Rc<State>, secure: bool) {
|
|||
let id = state.clients.id();
|
||||
if let Err(e) = state
|
||||
.clients
|
||||
.spawn(id, &state, fd, ClientCaps::all(), false, &metadata)
|
||||
.spawn(id, &state, fd, &metadata)
|
||||
{
|
||||
log::error!("Could not spawn a client: {}", ErrorFmt(e));
|
||||
break;
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
36
src/cli.rs
36
src/cli.rs
|
|
@ -14,8 +14,6 @@ mod pid;
|
|||
mod quit;
|
||||
mod randr;
|
||||
mod reexec;
|
||||
mod run_privileged;
|
||||
mod run_tagged;
|
||||
pub mod screenshot;
|
||||
mod seat_test;
|
||||
mod set_log_level;
|
||||
|
|
@ -29,15 +27,13 @@ use {
|
|||
cli::{
|
||||
clients::ClientsArgs, color_management::ColorManagementArgs, config::ConfigArgs,
|
||||
damage_tracking::DamageTrackingArgs, idle::IdleCmd, input::InputArgs,
|
||||
json::VERBOSE_JSON, randr::RandrArgs, reexec::ReexecArgs, run_tagged::RunTaggedArgs,
|
||||
tree::TreeArgs, xwayland::XwaylandArgs,
|
||||
json::VERBOSE_JSON, randr::RandrArgs, reexec::ReexecArgs, tree::TreeArgs,
|
||||
xwayland::XwaylandArgs,
|
||||
},
|
||||
compositor::{LogLevel, start_compositor},
|
||||
format::{Format, ref_formats},
|
||||
portal,
|
||||
pr_caps::drop_all_pr_caps,
|
||||
},
|
||||
clap::{Args, Parser, Subcommand, ValueEnum, ValueHint, builder::PossibleValue},
|
||||
clap::{Args, Parser, Subcommand, ValueEnum, ValueHint},
|
||||
clap_complete::Shell,
|
||||
std::sync::atomic::Ordering::Relaxed,
|
||||
};
|
||||
|
|
@ -88,14 +84,8 @@ pub enum Cmd {
|
|||
Idle(IdleArgs),
|
||||
/// Turn monitors on or off.
|
||||
Dpms(DpmsArgs),
|
||||
/// Run a privileged program.
|
||||
RunPrivileged(RunPrivilegedArgs),
|
||||
/// Run a program with a connection tag.
|
||||
RunTagged(RunTaggedArgs),
|
||||
/// Tests the events produced by a seat.
|
||||
SeatTest(SeatTestArgs),
|
||||
/// Run the desktop portal.
|
||||
Portal,
|
||||
/// Inspect/modify graphics card and connector settings.
|
||||
Randr(RandrArgs),
|
||||
/// Inspect/modify input settings.
|
||||
|
|
@ -147,13 +137,6 @@ pub enum DpmsState {
|
|||
Off,
|
||||
}
|
||||
|
||||
#[derive(Args, Debug)]
|
||||
pub struct RunPrivilegedArgs {
|
||||
/// The program to run
|
||||
#[clap(required = true, trailing_var_arg = true, value_hint = ValueHint::CommandWithArguments)]
|
||||
pub program: Vec<String>,
|
||||
}
|
||||
|
||||
#[derive(ValueEnum, Debug, Copy, Clone, Hash, Default, PartialEq)]
|
||||
pub enum ScreenshotFormat {
|
||||
/// The PNG image format.
|
||||
|
|
@ -240,16 +223,6 @@ pub struct GenerateArgs {
|
|||
shell: Shell,
|
||||
}
|
||||
|
||||
impl ValueEnum for &'static Format {
|
||||
fn value_variants<'a>() -> &'a [Self] {
|
||||
ref_formats()
|
||||
}
|
||||
|
||||
fn to_possible_value(&self) -> Option<PossibleValue> {
|
||||
Some(PossibleValue::new(self.name))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn main() {
|
||||
let cli = Jay::parse();
|
||||
if not_matches!(cli.command, Cmd::Run(_)) {
|
||||
|
|
@ -268,10 +241,7 @@ pub fn main() {
|
|||
Cmd::Idle(a) => idle::main(cli.global, a),
|
||||
Cmd::Dpms(a) => dpms::main(cli.global, a),
|
||||
Cmd::Unlock => unlock::main(cli.global),
|
||||
Cmd::RunPrivileged(a) => run_privileged::main(cli.global, a),
|
||||
Cmd::RunTagged(a) => run_tagged::main(cli.global, a),
|
||||
Cmd::SeatTest(a) => seat_test::main(cli.global, a),
|
||||
Cmd::Portal => portal::run_freestanding(cli.global),
|
||||
Cmd::Randr(a) => randr::main(cli.global, a),
|
||||
Cmd::Input(a) => input::main(cli.global, a),
|
||||
Cmd::DamageTracking(a) => damage_tracking::main(cli.global, a),
|
||||
|
|
|
|||
|
|
@ -167,7 +167,6 @@ pub struct Client {
|
|||
pub is_xwayland: bool,
|
||||
pub comm: Option<String>,
|
||||
pub exe: Option<String>,
|
||||
pub tag: Option<String>,
|
||||
}
|
||||
|
||||
pub async fn handle_client_query(
|
||||
|
|
@ -212,9 +211,6 @@ pub async fn handle_client_query(
|
|||
Exe::handle(tl, id, c.clone(), |c, event| {
|
||||
last!(c).exe = Some(event.exe.to_string());
|
||||
});
|
||||
Tag::handle(tl, id, c.clone(), |c, event| {
|
||||
last!(c).tag = Some(event.tag.to_string());
|
||||
});
|
||||
tl.round_trip().await;
|
||||
mem::take(&mut *c.borrow_mut())
|
||||
.into_iter()
|
||||
|
|
@ -253,7 +249,6 @@ impl ClientPrinter<'_> {
|
|||
bol!(is_xwayland, "xwayland");
|
||||
opt!(comm, "comm");
|
||||
opt!(exe, "exe");
|
||||
opt!(tag, "tag");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -269,6 +264,5 @@ pub fn make_json_client(client: &Client) -> JsonClient<'_> {
|
|||
is_xwayland: client.is_xwayland,
|
||||
comm: client.comm.as_deref(),
|
||||
exe: client.exe.as_deref(),
|
||||
tag: client.tag.as_deref(),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -66,8 +66,6 @@ pub struct JsonClient<'a> {
|
|||
pub comm: Option<&'a str>,
|
||||
#[serde(skip_serializing_if = "is_none")]
|
||||
pub exe: Option<&'a str>,
|
||||
#[serde(skip_serializing_if = "is_none")]
|
||||
pub tag: Option<&'a str>,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
|
|
|
|||
|
|
@ -1,35 +0,0 @@
|
|||
use {
|
||||
crate::{
|
||||
cli::{GlobalArgs, RunPrivilegedArgs},
|
||||
compositor::WAYLAND_DISPLAY,
|
||||
logger::Logger,
|
||||
utils::{errorfmt::ErrorFmt, oserror::OsErrorExt, xrd::xrd},
|
||||
},
|
||||
std::path::PathBuf,
|
||||
uapi::UstrPtr,
|
||||
};
|
||||
|
||||
pub fn main(global: GlobalArgs, args: RunPrivilegedArgs) {
|
||||
Logger::install_stderr(global.log_level);
|
||||
if let Some(xrd) = xrd() {
|
||||
let mut wd = match std::env::var(WAYLAND_DISPLAY) {
|
||||
Ok(v) => v,
|
||||
_ => fatal!("{} is not set", WAYLAND_DISPLAY),
|
||||
};
|
||||
wd.push_str(".jay");
|
||||
let mut path = PathBuf::from(xrd);
|
||||
path.push(&wd);
|
||||
if path.exists() {
|
||||
unsafe {
|
||||
std::env::set_var(WAYLAND_DISPLAY, &wd);
|
||||
}
|
||||
}
|
||||
}
|
||||
let mut argv = UstrPtr::new();
|
||||
for arg in &args.program {
|
||||
argv.push(arg.as_str());
|
||||
}
|
||||
let program = args.program[0].as_str();
|
||||
let res = uapi::execvp(program, &argv).to_os_error().unwrap_err();
|
||||
fatal!("Could not execute `{}`: {}", program, ErrorFmt(res));
|
||||
}
|
||||
|
|
@ -1,70 +0,0 @@
|
|||
use {
|
||||
crate::{
|
||||
cli::GlobalArgs,
|
||||
compositor::WAYLAND_DISPLAY,
|
||||
tools::tool_client::{Handle, ToolClient, with_tool_client},
|
||||
utils::{errorfmt::ErrorFmt, oserror::OsErrorExt},
|
||||
wire::{jay_acceptor_request, jay_compositor},
|
||||
},
|
||||
clap::{Args, ValueHint},
|
||||
std::{cell::Cell, env, rc::Rc},
|
||||
uapi::UstrPtr,
|
||||
};
|
||||
|
||||
#[derive(Args, Debug)]
|
||||
pub struct RunTaggedArgs {
|
||||
/// Specifies a tag to apply to all spawned wayland connections.
|
||||
tag: String,
|
||||
/// The program to run.
|
||||
#[clap(required = true, trailing_var_arg = true, value_hint = ValueHint::CommandWithArguments)]
|
||||
pub program: Vec<String>,
|
||||
}
|
||||
|
||||
pub fn main(global: GlobalArgs, run_tagged_args: RunTaggedArgs) {
|
||||
with_tool_client(global.log_level, |tc| async move {
|
||||
let run_tagged = Rc::new(RunTagged { tc: tc.clone() });
|
||||
run_tagged.run(run_tagged_args).await;
|
||||
});
|
||||
}
|
||||
|
||||
struct RunTagged {
|
||||
tc: Rc<ToolClient>,
|
||||
}
|
||||
|
||||
impl RunTagged {
|
||||
async fn run(&self, args: RunTaggedArgs) {
|
||||
let tc = &self.tc;
|
||||
let comp = tc.jay_compositor().await;
|
||||
let req = tc.id();
|
||||
tc.send(jay_compositor::GetTaggedAcceptor {
|
||||
self_id: comp,
|
||||
id: req,
|
||||
tag: &args.tag,
|
||||
});
|
||||
let res = Rc::new(Cell::new(None));
|
||||
jay_acceptor_request::Done::handle(&tc, req, res.clone(), |res, ev| {
|
||||
res.set(Some(Ok(ev.name.to_owned())));
|
||||
});
|
||||
jay_acceptor_request::Failed::handle(&tc, req, res.clone(), |res, ev| {
|
||||
res.set(Some(Err(ev.msg.to_owned())));
|
||||
});
|
||||
tc.round_trip().await;
|
||||
match res.take().unwrap() {
|
||||
Ok(n) => {
|
||||
unsafe {
|
||||
env::set_var(WAYLAND_DISPLAY, &n);
|
||||
}
|
||||
let mut argv = UstrPtr::new();
|
||||
for arg in &args.program {
|
||||
argv.push(arg.as_str());
|
||||
}
|
||||
let program = args.program[0].as_str();
|
||||
let res = uapi::execvp(program, &argv).to_os_error().unwrap_err();
|
||||
fatal!("Could not execute `{}`: {}", program, ErrorFmt(res));
|
||||
}
|
||||
Err(msg) => {
|
||||
fatal!("Could not create acceptor: {}", msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -25,7 +25,6 @@ use {
|
|||
pending_serial::PendingSerial,
|
||||
pid_info::{PidInfo, get_pid_info, get_socket_creds},
|
||||
pidfd_send_signal::pidfd_send_signal,
|
||||
static_text::StaticText,
|
||||
},
|
||||
wire::WlRegistryId,
|
||||
},
|
||||
|
|
@ -71,35 +70,6 @@ bitflags! {
|
|||
CAP_FOREIGN_TOPLEVEL_GEOMETRY_TRACKING = 1 << 16,
|
||||
}
|
||||
|
||||
impl StaticText for ClientCapsEnum {
|
||||
fn text(&self) -> &'static str {
|
||||
match self {
|
||||
ClientCapsEnum::CAP_DATA_CONTROL_MANAGER => "data-control",
|
||||
ClientCapsEnum::CAP_VIRTUAL_KEYBOARD_MANAGER => "virtual-keyboard",
|
||||
ClientCapsEnum::CAP_FOREIGN_TOPLEVEL_LIST => "foreign-toplevel-list",
|
||||
ClientCapsEnum::CAP_IDLE_NOTIFIER => "idle-notifier",
|
||||
ClientCapsEnum::CAP_SESSION_LOCK_MANAGER => "session-lock",
|
||||
ClientCapsEnum::CAP_JAY_COMPOSITOR => "jay-compositor",
|
||||
ClientCapsEnum::CAP_LAYER_SHELL => "layer-shell",
|
||||
ClientCapsEnum::CAP_SCREENCOPY_MANAGER => "screencopy",
|
||||
ClientCapsEnum::CAP_SEAT_MANAGER => "seat-manager",
|
||||
ClientCapsEnum::CAP_DRM_LEASE => "drm-lease",
|
||||
ClientCapsEnum::CAP_INPUT_METHOD => "input-method",
|
||||
ClientCapsEnum::CAP_WORKSPACE => "workspace-manager",
|
||||
ClientCapsEnum::CAP_FOREIGN_TOPLEVEL_MANAGER => "foreign-toplevel-manager",
|
||||
ClientCapsEnum::CAP_HEAD_MANAGER => "head-manager",
|
||||
ClientCapsEnum::CAP_GAMMA_CONTROL_MANAGER => "gamma-control-manager",
|
||||
ClientCapsEnum::CAP_VIRTUAL_POINTER_MANAGER => "virtual-pointer",
|
||||
ClientCapsEnum::CAP_FOREIGN_TOPLEVEL_GEOMETRY_TRACKING => {
|
||||
"foreign-toplevel-geometry-tracking"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub const CAPS_DEFAULT: ClientCaps = ClientCaps(CAP_LAYER_SHELL.0 | CAP_DRM_LEASE.0);
|
||||
pub const CAPS_DEFAULT_SANDBOXED: ClientCaps = ClientCaps(CAP_DRM_LEASE.0);
|
||||
|
||||
#[derive(Debug, Copy, Clone, Hash, Ord, PartialOrd, Eq, PartialEq)]
|
||||
pub struct ClientId(u64);
|
||||
|
||||
|
|
@ -156,24 +126,12 @@ impl Clients {
|
|||
id: ClientId,
|
||||
global: &Rc<State>,
|
||||
socket: Rc<OwnedFd>,
|
||||
bounding_caps: ClientCaps,
|
||||
set_bounding_caps_for_children: bool,
|
||||
acceptor: &Rc<AcceptorMetadata>,
|
||||
) -> Result<(), ClientError> {
|
||||
let Some((uid, pid)) = get_socket_creds(&socket) else {
|
||||
return Ok(());
|
||||
};
|
||||
self.spawn2(
|
||||
id,
|
||||
global,
|
||||
socket,
|
||||
uid,
|
||||
pid,
|
||||
bounding_caps,
|
||||
set_bounding_caps_for_children,
|
||||
false,
|
||||
acceptor,
|
||||
)?;
|
||||
self.spawn2(id, global, socket, uid, pid, false, acceptor)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
@ -184,15 +142,9 @@ impl Clients {
|
|||
socket: Rc<OwnedFd>,
|
||||
uid: c::uid_t,
|
||||
pid: c::pid_t,
|
||||
bounding_caps: ClientCaps,
|
||||
set_bounding_caps_for_children: bool,
|
||||
is_xwayland: bool,
|
||||
acceptor: &Rc<AcceptorMetadata>,
|
||||
) -> Result<Rc<Client>, ClientError> {
|
||||
let effective_caps = match acceptor.sandboxed {
|
||||
true => CAPS_DEFAULT_SANDBOXED,
|
||||
false => CAPS_DEFAULT,
|
||||
};
|
||||
let data = Rc::new_cyclic(|slf| Client {
|
||||
id,
|
||||
state: global.clone(),
|
||||
|
|
@ -204,8 +156,6 @@ impl Clients {
|
|||
shutdown: Default::default(),
|
||||
tracker: Default::default(),
|
||||
is_xwayland,
|
||||
effective_caps: Cell::new(effective_caps & bounding_caps),
|
||||
bounding_caps_for_children: Cell::new(bounding_caps),
|
||||
last_enter_serial: Default::default(),
|
||||
pid_info: get_pid_info(uid, pid),
|
||||
serials: Default::default(),
|
||||
|
|
@ -226,10 +176,6 @@ impl Clients {
|
|||
acceptor: acceptor.clone(),
|
||||
});
|
||||
track!(data, data);
|
||||
global.update_capabilities(&data, bounding_caps, set_bounding_caps_for_children);
|
||||
if acceptor.secure || is_xwayland {
|
||||
data.effective_caps.set(ClientCaps::all());
|
||||
}
|
||||
let display = Rc::new(WlDisplay::new(&data));
|
||||
track!(data, display);
|
||||
data.objects.display.set(Some(display.clone()));
|
||||
|
|
@ -239,13 +185,12 @@ impl Clients {
|
|||
data: data.clone(),
|
||||
};
|
||||
log::info!(
|
||||
"Client {} connected, pid: {}, uid: {}, fd: {}, comm: {:?}, caps: {:?}",
|
||||
"Client {} connected, pid: {}, uid: {}, fd: {}, comm: {:?}",
|
||||
id,
|
||||
pid,
|
||||
uid,
|
||||
client.data.socket.raw(),
|
||||
data.pid_info.comm,
|
||||
data.effective_caps.get(),
|
||||
);
|
||||
client.data.property_changed(CL_CHANGED_NEW);
|
||||
self.clients.borrow_mut().insert(client.data.id, client);
|
||||
|
|
@ -274,9 +219,8 @@ impl Clients {
|
|||
{
|
||||
let clients = self.clients.borrow();
|
||||
for client in clients.values() {
|
||||
if client.data.effective_caps.get().contains(required_caps)
|
||||
&& (!xwayland_only || client.data.is_xwayland)
|
||||
{
|
||||
let _ = required_caps;
|
||||
if !xwayland_only || client.data.is_xwayland {
|
||||
f(&client.data);
|
||||
}
|
||||
}
|
||||
|
|
@ -336,8 +280,6 @@ pub struct Client {
|
|||
shutdown: AsyncEvent,
|
||||
pub tracker: Tracker<Client>,
|
||||
pub is_xwayland: bool,
|
||||
pub effective_caps: Cell<ClientCaps>,
|
||||
pub bounding_caps_for_children: Cell<ClientCaps>,
|
||||
pub last_enter_serial: Cell<Option<u64>>,
|
||||
pub pid_info: PidInfo,
|
||||
pub serials: RefCell<VecDeque<SerialRange>>,
|
||||
|
|
@ -349,7 +291,7 @@ pub struct Client {
|
|||
pub wire_scale: Cell<Option<i32>>,
|
||||
pub focus_stealing_serial: Cell<Option<u64>>,
|
||||
pub changed_properties: Cell<ClMatcherChange>,
|
||||
pub destroyed: CopyHashMap<CritMatcherId, Weak<dyn CritDestroyListener<Rc<Self>>>>,
|
||||
pub destroyed: CopyHashMap<CritMatcherId, Weak<dyn CritDestroyListener<Self>>>,
|
||||
pub acceptor: Rc<AcceptorMetadata>,
|
||||
}
|
||||
|
||||
|
|
|
|||
57
src/cmm.rs
57
src/cmm.rs
|
|
@ -1,9 +1,48 @@
|
|||
pub mod cmm_description;
|
||||
pub mod cmm_eotf;
|
||||
pub mod cmm_luminance;
|
||||
pub mod cmm_manager;
|
||||
pub mod cmm_primaries;
|
||||
pub mod cmm_render_intent;
|
||||
#[cfg(test)]
|
||||
mod cmm_tests;
|
||||
pub mod cmm_transform;
|
||||
pub mod cmm_description {
|
||||
pub use jay_cmm::cmm_description::*;
|
||||
}
|
||||
|
||||
pub mod cmm_eotf {
|
||||
pub use jay_cmm::cmm_eotf::*;
|
||||
}
|
||||
|
||||
pub mod cmm_luminance {
|
||||
pub use jay_cmm::cmm_luminance::*;
|
||||
}
|
||||
|
||||
pub mod cmm_manager {
|
||||
pub use jay_cmm::cmm_manager::*;
|
||||
}
|
||||
|
||||
pub mod cmm_primaries {
|
||||
pub use jay_cmm::cmm_primaries::*;
|
||||
}
|
||||
|
||||
pub mod cmm_render_intent {
|
||||
use crate::{
|
||||
ifs::color_management::{
|
||||
ABSOLUTE_NO_ADAPTATION_SINCE, RENDER_INTENT_ABSOLUTE_NO_ADAPTATION,
|
||||
RENDER_INTENT_PERCEPTUAL, RENDER_INTENT_RELATIVE, RENDER_INTENT_RELATIVE_BPC,
|
||||
},
|
||||
object::Version,
|
||||
};
|
||||
|
||||
pub use jay_cmm::cmm_render_intent::*;
|
||||
|
||||
pub fn from_wayland(intent: u32, version: Version) -> Option<RenderIntent> {
|
||||
let res = match intent {
|
||||
RENDER_INTENT_PERCEPTUAL => RenderIntent::Perceptual,
|
||||
RENDER_INTENT_RELATIVE => RenderIntent::Relative,
|
||||
RENDER_INTENT_RELATIVE_BPC => RenderIntent::RelativeBpc,
|
||||
RENDER_INTENT_ABSOLUTE_NO_ADAPTATION if version >= ABSOLUTE_NO_ADAPTATION_SINCE => {
|
||||
RenderIntent::AbsoluteNoAdaptation
|
||||
}
|
||||
_ => return None,
|
||||
};
|
||||
Some(res)
|
||||
}
|
||||
}
|
||||
|
||||
pub mod cmm_transform {
|
||||
pub use jay_cmm::cmm_transform::*;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -50,7 +50,6 @@ use {
|
|||
leaks,
|
||||
logger::Logger,
|
||||
output_schedule::OutputSchedule,
|
||||
portal::{self, PortalStartup},
|
||||
pr_caps::{PrCapsThread, pr_caps},
|
||||
scale::Scale,
|
||||
sighand::{self, SighandError},
|
||||
|
|
@ -121,19 +120,10 @@ pub fn start_compositor(global: GlobalArgs, args: RunArgs) {
|
|||
None
|
||||
};
|
||||
let forker = create_forker(reaper_pid);
|
||||
let portal = portal::run_from_compositor(global.log_level);
|
||||
enable_profiler();
|
||||
let logger = Logger::install_compositor(global.log_level);
|
||||
let portal = match portal {
|
||||
Ok(p) => Some(p),
|
||||
Err(e) => {
|
||||
log::error!("Could not spawn portal: {}", ErrorFmt(e));
|
||||
None
|
||||
}
|
||||
};
|
||||
let res = start_compositor2(
|
||||
Some(forker),
|
||||
portal,
|
||||
Some(logger.clone()),
|
||||
args,
|
||||
None,
|
||||
|
|
@ -152,7 +142,7 @@ pub fn start_compositor(global: GlobalArgs, args: RunArgs) {
|
|||
|
||||
#[cfg(feature = "it")]
|
||||
pub fn start_compositor_for_test(future: TestFuture) -> Result<(), CompositorError> {
|
||||
let res = start_compositor2(None, None, None, RunArgs::default(), Some(future), None);
|
||||
let res = start_compositor2(None, None, RunArgs::default(), Some(future), None);
|
||||
leaks::log_leaked();
|
||||
res
|
||||
}
|
||||
|
|
@ -194,7 +184,6 @@ pub type TestFuture = Box<dyn Fn(&Rc<State>) -> Box<dyn Future<Output = ()>>>;
|
|||
|
||||
fn start_compositor2(
|
||||
forker: Option<Rc<ForkerProxy>>,
|
||||
portal: Option<PortalStartup>,
|
||||
logger: Option<Arc<Logger>>,
|
||||
run_args: RunArgs,
|
||||
test_future: Option<TestFuture>,
|
||||
|
|
@ -308,7 +297,6 @@ fn start_compositor2(
|
|||
idle_inhibitor_ids: Default::default(),
|
||||
run_toplevel,
|
||||
config_dir: explicit_config_dir.or_else(config_dir),
|
||||
config_file_id: NumCell::new(1),
|
||||
tracker: Default::default(),
|
||||
data_offer_ids: Default::default(),
|
||||
data_source_ids: Default::default(),
|
||||
|
|
@ -342,7 +330,6 @@ fn start_compositor2(
|
|||
keyboard_state_ids: Default::default(),
|
||||
physical_keyboard_ids: Default::default(),
|
||||
security_context_acceptors: Default::default(),
|
||||
tagged_acceptors: Default::default(),
|
||||
cursor_user_group_ids: Default::default(),
|
||||
cursor_user_ids: Default::default(),
|
||||
cursor_user_groups: Default::default(),
|
||||
|
|
@ -420,13 +407,6 @@ fn start_compositor2(
|
|||
forker.setenv(key.as_bytes(), val.as_bytes());
|
||||
}
|
||||
}
|
||||
let mut _portal = None;
|
||||
if let (Some(portal), Some(logger)) = (portal, &logger) {
|
||||
_portal = Some(engine.spawn(
|
||||
"portal",
|
||||
portal.spawn(engine.clone(), ring.clone(), logger.clone()),
|
||||
));
|
||||
}
|
||||
let _compositor = engine.spawn("compositor", start_compositor3(state.clone(), test_future));
|
||||
ring.run()?;
|
||||
state.clear();
|
||||
|
|
@ -487,14 +467,7 @@ fn load_config(
|
|||
if for_test {
|
||||
return ConfigProxy::for_test(state);
|
||||
}
|
||||
match ConfigProxy::from_config_dir(state) {
|
||||
Ok(c) => c,
|
||||
Err(e) => {
|
||||
log::warn!("Could not load config.so: {}", ErrorFmt(e));
|
||||
log::warn!("Using default config");
|
||||
ConfigProxy::default(state)
|
||||
}
|
||||
}
|
||||
ConfigProxy::default(state)
|
||||
}
|
||||
|
||||
fn start_global_event_handlers(state: &Rc<State>) -> Vec<SpawnedFuture<()>> {
|
||||
|
|
|
|||
124
src/config.rs
124
src/config.rs
|
|
@ -5,18 +5,14 @@ use crate::it::test_config::TEST_CONFIG_ENTRY;
|
|||
use {
|
||||
crate::{
|
||||
backend::{ConnectorId, DrmDeviceId, InputDeviceId},
|
||||
client::{Client, ClientCaps},
|
||||
config::handler::ConfigProxyHandler,
|
||||
ifs::wl_seat::SeatId,
|
||||
state::State,
|
||||
tree::{TileState, ToplevelData, ToplevelIdentifier},
|
||||
utils::{
|
||||
clonecell::CloneCell,
|
||||
nice::{JAY_NO_REALTIME, dont_allow_config_so},
|
||||
numcell::NumCell,
|
||||
ptr_ext::PtrExt,
|
||||
unlink_on_drop::UnlinkOnDrop,
|
||||
xrd::xrd,
|
||||
},
|
||||
},
|
||||
bincode::Options,
|
||||
|
|
@ -30,27 +26,9 @@ use {
|
|||
video::{Connector, DrmDevice},
|
||||
window::{self},
|
||||
},
|
||||
libloading::Library,
|
||||
std::{cell::Cell, io, mem, path::Path, ptr, rc::Rc},
|
||||
thiserror::Error,
|
||||
std::{cell::Cell, mem, ptr, rc::Rc},
|
||||
};
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum ConfigError {
|
||||
#[error("Could not load the config library")]
|
||||
CouldNotLoadLibrary(#[source] libloading::Error),
|
||||
#[error("Config library does not contain the entry symbol")]
|
||||
LibraryDoesNotContainEntry(#[source] libloading::Error),
|
||||
#[error("Could not determine the config directory")]
|
||||
ConfigDirNotSet,
|
||||
#[error("Could not copy the config file")]
|
||||
CopyConfigFile(#[source] io::Error),
|
||||
#[error("XDG_RUNTIME_DIR is not set")]
|
||||
XrdNotSet,
|
||||
#[error("Custom config.so is not permitted")]
|
||||
NotPermitted,
|
||||
}
|
||||
|
||||
pub struct ConfigProxy {
|
||||
handler: CloneCell<Option<Rc<ConfigProxyHandler>>>,
|
||||
}
|
||||
|
|
@ -181,16 +159,6 @@ impl ConfigProxy {
|
|||
self.handler.get()?.initial_tile_state(data)
|
||||
}
|
||||
|
||||
pub fn update_capabilities(
|
||||
&self,
|
||||
data: &Rc<Client>,
|
||||
bounding_caps: ClientCaps,
|
||||
set_bounding_caps: bool,
|
||||
) {
|
||||
if let Some(handler) = self.handler.get() {
|
||||
handler.update_capabilities(data, bounding_caps, set_bounding_caps);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for ConfigProxy {
|
||||
|
|
@ -215,18 +183,11 @@ unsafe extern "C" fn default_client_init(
|
|||
}
|
||||
|
||||
impl ConfigProxy {
|
||||
fn new(
|
||||
lib: Option<Library>,
|
||||
entry: &ConfigEntry,
|
||||
state: &Rc<State>,
|
||||
path: Option<String>,
|
||||
) -> Self {
|
||||
fn new(entry: &ConfigEntry, state: &Rc<State>) -> Self {
|
||||
let version = entry.version.min(VERSION);
|
||||
let data = Rc::new(ConfigProxyHandler {
|
||||
path,
|
||||
client_data: Cell::new(ptr::null()),
|
||||
dropped: Cell::new(false),
|
||||
_lib: lib,
|
||||
_version: version,
|
||||
unref: entry.unref,
|
||||
handle_msg: entry.handle_msg,
|
||||
|
|
@ -249,8 +210,6 @@ impl ConfigProxy {
|
|||
client_matchers: Default::default(),
|
||||
client_matcher_cache: Default::default(),
|
||||
client_matcher_leafs: Default::default(),
|
||||
client_matcher_capabilities: Default::default(),
|
||||
client_matcher_bounding_capabilities: Default::default(),
|
||||
window_matcher_ids: NumCell::new(1),
|
||||
window_matchers: Default::default(),
|
||||
window_matcher_cache: Default::default(),
|
||||
|
|
@ -291,75 +250,12 @@ impl ConfigProxy {
|
|||
unref: jay_config::_private::client::unref,
|
||||
handle_msg: jay_config::_private::client::handle_msg,
|
||||
};
|
||||
Self::new(None, &entry, state, None)
|
||||
Self::new(&entry, state)
|
||||
}
|
||||
|
||||
#[cfg(feature = "it")]
|
||||
pub fn for_test(state: &Rc<State>) -> Self {
|
||||
Self::new(None, &TEST_CONFIG_ENTRY, state, None)
|
||||
}
|
||||
|
||||
pub fn from_config_dir(state: &Rc<State>) -> Result<Self, ConfigError> {
|
||||
if dont_allow_config_so() {
|
||||
if have_config_so(state.config_dir.as_deref()) {
|
||||
log::warn!("Not loading config.so because");
|
||||
log::warn!(" 1. Jay was started with CAP_SYS_NICE");
|
||||
log::warn!(" 2. Jay was not started with {}=1", JAY_NO_REALTIME);
|
||||
log::warn!(" 3. The scheduler was elevated to SCHED_RR");
|
||||
log::warn!(
|
||||
" 4. Jay was not compiled with {}=1",
|
||||
jay_allow_realtime_config_so!(),
|
||||
);
|
||||
}
|
||||
return Err(ConfigError::NotPermitted);
|
||||
}
|
||||
let dir = match state.config_dir.as_deref() {
|
||||
Some(d) => d,
|
||||
_ => return Err(ConfigError::ConfigDirNotSet),
|
||||
};
|
||||
let file = format!("{}/{CONFIG_SO}", dir);
|
||||
unsafe { Self::from_file(&file, state) }
|
||||
}
|
||||
|
||||
pub unsafe fn from_file(path: &str, state: &Rc<State>) -> Result<Self, ConfigError> {
|
||||
// Here we have to do a bit of a dance to support reloading. glibc will
|
||||
// never load a library twice unless it has been unloaded in between.
|
||||
// glibc identifies libraries by their file path and by their inode
|
||||
// number. If either of those match, glibc considers the libraries
|
||||
// identical. If the inode has not changed then this is not a problem
|
||||
// for us since we don't want glibc to do any unnecessary work.
|
||||
// However, if the user has created a new config with a new inode, then
|
||||
// glibc will still not reload the library if we try to load it from
|
||||
// the canonical location ~/.config/jay/config.so since it already has
|
||||
// a library with that path loaded. To work around this, create a
|
||||
// temporary copy with an incrementing number and load the library
|
||||
// from there.
|
||||
let xrd = match xrd() {
|
||||
Some(x) => x,
|
||||
_ => return Err(ConfigError::XrdNotSet),
|
||||
};
|
||||
let copy = format!(
|
||||
"{}/.jay_config.so.{}.{}",
|
||||
xrd,
|
||||
uapi::getpid(),
|
||||
state.config_file_id.fetch_add(1)
|
||||
);
|
||||
let _ = uapi::unlink(copy.as_str());
|
||||
if let Err(e) = std::fs::copy(path, ©) {
|
||||
return Err(ConfigError::CopyConfigFile(e));
|
||||
}
|
||||
let unlink = UnlinkOnDrop(©);
|
||||
let lib = match unsafe { Library::new(©) } {
|
||||
Ok(l) => l,
|
||||
Err(e) => return Err(ConfigError::CouldNotLoadLibrary(e)),
|
||||
};
|
||||
let entry = unsafe { lib.get::<&'static ConfigEntry>(b"JAY_CONFIG_ENTRY_V1\0") };
|
||||
let entry = match entry {
|
||||
Ok(e) => *e,
|
||||
Err(e) => return Err(ConfigError::LibraryDoesNotContainEntry(e)),
|
||||
};
|
||||
mem::forget(unlink);
|
||||
Ok(Self::new(Some(lib), entry, state, Some(copy)))
|
||||
Self::new(&TEST_CONFIG_ENTRY, state)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -388,15 +284,3 @@ pub struct InvokedShortcut {
|
|||
pub effective_mods: Modifiers,
|
||||
pub sym: KeySym,
|
||||
}
|
||||
|
||||
const CONFIG_SO: &str = "config.so";
|
||||
|
||||
pub fn have_config_so(config_dir: Option<&str>) -> bool {
|
||||
let Some(dir) = config_dir else {
|
||||
return false;
|
||||
};
|
||||
let mut dir = dir.to_owned();
|
||||
dir.push_str("/");
|
||||
dir.push_str(CONFIG_SO);
|
||||
Path::new(&dir).exists()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,9 +6,9 @@ use {
|
|||
InputDeviceAccelProfile, InputDeviceCapability, InputDeviceClickMethod, InputDeviceId,
|
||||
transaction::BackendConnectorTransactionError,
|
||||
},
|
||||
client::{CAP_JAY_COMPOSITOR, Client, ClientCaps, ClientId},
|
||||
client::{Client, ClientId},
|
||||
cmm::cmm_eotf::Eotf,
|
||||
compositor::{MAX_EXTENTS, WAYLAND_DISPLAY},
|
||||
compositor::MAX_EXTENTS,
|
||||
criteria::{
|
||||
CritLiteralOrRegex, CritMgrExt, CritTarget, CritUpstreamNode,
|
||||
clm::ClmLeafMatcher,
|
||||
|
|
@ -25,7 +25,6 @@ use {
|
|||
output_schedule::map_cursor_hz,
|
||||
scale::Scale,
|
||||
state::{ConnectorData, DeviceHandlerData, DrmDevData, OutputData, State},
|
||||
tagged_acceptor::TaggedAcceptorError,
|
||||
theme::{ThemeColor, ThemeSized},
|
||||
tree::{
|
||||
ContainerSplit, OutputNode, TearingMode, TileState, ToplevelData, ToplevelIdentifier,
|
||||
|
|
@ -37,7 +36,7 @@ use {
|
|||
copyhashmap::CopyHashMap,
|
||||
errorfmt::ErrorFmt,
|
||||
numcell::NumCell,
|
||||
oserror::{OsError, OsErrorExt},
|
||||
oserror::OsErrorExt,
|
||||
stack::Stack,
|
||||
timer::{TimerError, TimerFd},
|
||||
},
|
||||
|
|
@ -50,7 +49,7 @@ use {
|
|||
ipc::{ClientMessage, Response, ServerMessage, WorkspaceSource},
|
||||
},
|
||||
Axis, Direction, Workspace,
|
||||
client::{Client as ConfigClient, ClientCapabilities, ClientMatcher},
|
||||
client::{Client as ConfigClient, ClientMatcher},
|
||||
input::{
|
||||
FallbackOutputMode, FocusFollowsMouseMode, InputDevice, LayerDirection, Seat, Timeline,
|
||||
acceleration::{ACCEL_PROFILE_ADAPTIVE, ACCEL_PROFILE_FLAT, AccelProfile},
|
||||
|
|
@ -76,7 +75,6 @@ use {
|
|||
xwayland::XScalingMode,
|
||||
},
|
||||
kbvm::Keycode,
|
||||
libloading::Library,
|
||||
log::Level,
|
||||
regex::Regex,
|
||||
std::{
|
||||
|
|
@ -92,10 +90,8 @@ use {
|
|||
};
|
||||
|
||||
pub(super) struct ConfigProxyHandler {
|
||||
pub path: Option<String>,
|
||||
pub client_data: Cell<*const u8>,
|
||||
pub dropped: Cell<bool>,
|
||||
pub _lib: Option<Library>,
|
||||
pub _version: u32,
|
||||
pub unref: unsafe extern "C" fn(data: *const u8),
|
||||
pub handle_msg: unsafe extern "C" fn(data: *const u8, msg: *const u8, size: usize),
|
||||
|
|
@ -121,24 +117,9 @@ pub(super) struct ConfigProxyHandler {
|
|||
|
||||
pub client_matcher_ids: NumCell<u64>,
|
||||
pub client_matchers:
|
||||
CopyHashMap<ClientMatcher, Rc<CachedCriterion<ClientCriterionIpc, Rc<Client>>>>,
|
||||
pub client_matcher_cache: CriterionCache<ClientCriterionIpc, Rc<Client>>,
|
||||
CopyHashMap<ClientMatcher, Rc<CachedCriterion<ClientCriterionIpc, Client>>>,
|
||||
pub client_matcher_cache: CriterionCache<ClientCriterionIpc, Client>,
|
||||
pub client_matcher_leafs: CopyHashMap<ClientMatcher, Rc<ClmLeafMatcher>>,
|
||||
pub client_matcher_capabilities: CopyHashMap<
|
||||
ClientMatcher,
|
||||
(
|
||||
Rc<CachedCriterion<ClientCriterionIpc, Rc<Client>>>,
|
||||
ClientCaps,
|
||||
),
|
||||
>,
|
||||
pub client_matcher_bounding_capabilities: CopyHashMap<
|
||||
ClientMatcher,
|
||||
(
|
||||
Rc<CachedCriterion<ClientCriterionIpc, Rc<Client>>>,
|
||||
ClientCaps,
|
||||
),
|
||||
>,
|
||||
|
||||
pub window_matcher_ids: NumCell<u64>,
|
||||
pub window_matchers:
|
||||
CopyHashMap<WindowMatcher, Rc<CachedCriterion<WindowCriterionIpc, ToplevelData>>>,
|
||||
|
|
@ -218,11 +199,6 @@ impl ConfigProxyHandler {
|
|||
self.window_matcher_leafs.clear();
|
||||
self.window_matchers.clear();
|
||||
|
||||
if let Some(path) = &self.path
|
||||
&& let Err(e) = uapi::unlink(path.as_str())
|
||||
{
|
||||
log::error!("Could not unlink {}: {}", path, ErrorFmt(OsError(e.0)));
|
||||
}
|
||||
}
|
||||
|
||||
pub fn send(&self, msg: &ServerMessage) {
|
||||
|
|
@ -1185,19 +1161,6 @@ impl ConfigProxyHandler {
|
|||
self.state.set_color_management_enabled(enabled);
|
||||
}
|
||||
|
||||
fn handle_get_socket_path(&self) {
|
||||
match self.state.acceptor.get() {
|
||||
Some(a) => {
|
||||
self.respond(Response::GetSocketPath {
|
||||
path: a.socket_name().to_string(),
|
||||
});
|
||||
}
|
||||
_ => {
|
||||
log::warn!("There is no acceptor");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_connector_connected(&self, connector: Connector) -> Result<(), CphError> {
|
||||
let connector = self.get_connector(connector)?;
|
||||
self.respond(Response::ConnectorConnected {
|
||||
|
|
@ -1937,18 +1900,9 @@ impl ConfigProxyHandler {
|
|||
&self,
|
||||
prog: &str,
|
||||
args: Vec<String>,
|
||||
mut env: Vec<(String, String)>,
|
||||
env: Vec<(String, String)>,
|
||||
fds: Vec<(i32, i32)>,
|
||||
tag: Option<&str>,
|
||||
) -> Result<(), CphError> {
|
||||
if let Some(tag) = tag {
|
||||
let display = self
|
||||
.state
|
||||
.tagged_acceptors
|
||||
.get(&self.state, tag)
|
||||
.map_err(CphError::CreateTaggedAcceptor)?;
|
||||
env.push((WAYLAND_DISPLAY.to_string(), display.to_string()));
|
||||
}
|
||||
let fds: Vec<_> = fds
|
||||
.into_iter()
|
||||
.map(|(a, b)| (a, Rc::new(OwnedFd::new(b))))
|
||||
|
|
@ -2125,7 +2079,7 @@ impl ConfigProxyHandler {
|
|||
fn get_client_matcher(
|
||||
&self,
|
||||
matcher: ClientMatcher,
|
||||
) -> Result<Rc<CachedCriterion<ClientCriterionIpc, Rc<Client>>>, CphError> {
|
||||
) -> Result<Rc<CachedCriterion<ClientCriterionIpc, Client>>, CphError> {
|
||||
self.client_matchers
|
||||
.get(&matcher)
|
||||
.ok_or(CphError::ClientMatcherDoesNotExist(matcher))
|
||||
|
|
@ -2226,7 +2180,6 @@ impl ConfigProxyHandler {
|
|||
}
|
||||
ClientCriterionStringField::Comm => mgr.comm(needle),
|
||||
ClientCriterionStringField::Exe => mgr.exe(needle),
|
||||
ClientCriterionStringField::Tag => mgr.tag(needle),
|
||||
}
|
||||
}
|
||||
ClientCriterionIpc::Sandboxed => mgr.sandboxed(),
|
||||
|
|
@ -2249,8 +2202,6 @@ impl ConfigProxyHandler {
|
|||
fn handle_destroy_client_matcher(&self, matcher: ClientMatcher) {
|
||||
self.client_matchers.remove(&matcher);
|
||||
self.client_matcher_leafs.remove(&matcher);
|
||||
self.client_matcher_capabilities.remove(&matcher);
|
||||
self.client_matcher_bounding_capabilities.remove(&matcher);
|
||||
}
|
||||
|
||||
fn handle_enable_client_matcher_events(
|
||||
|
|
@ -2862,28 +2813,6 @@ impl ConfigProxyHandler {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn handle_set_client_matcher_capabilities(
|
||||
&self,
|
||||
matcher: ClientMatcher,
|
||||
caps: ClientCapabilities,
|
||||
) -> Result<(), CphError> {
|
||||
let m = self.get_client_matcher(matcher)?;
|
||||
self.client_matcher_capabilities
|
||||
.set(matcher, (m, caps.to_client_caps()));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn handle_set_client_matcher_bounding_capabilities(
|
||||
&self,
|
||||
matcher: ClientMatcher,
|
||||
caps: ClientCapabilities,
|
||||
) -> Result<(), CphError> {
|
||||
let m = self.get_client_matcher(matcher)?;
|
||||
self.client_matcher_bounding_capabilities
|
||||
.set(matcher, (m, caps.to_client_caps()));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn handle_request(self: &Rc<Self>, msg: &[u8]) {
|
||||
if let Err(e) = self.handle_request_(msg) {
|
||||
log::error!("Could not handle client request: {}", ErrorFmt(e));
|
||||
|
|
@ -2946,7 +2875,7 @@ impl ConfigProxyHandler {
|
|||
ClientMessage::GetSeats => self.handle_get_seats(),
|
||||
ClientMessage::RemoveSeat { .. } => {}
|
||||
ClientMessage::Run { prog, args, env } => {
|
||||
self.handle_run(prog, args, env, vec![], None).wrn("run")?
|
||||
self.handle_run(prog, args, env, vec![]).wrn("run")?
|
||||
}
|
||||
ClientMessage::GrabKb { kb, grab } => self.handle_grab(kb, grab).wrn("grab")?,
|
||||
ClientMessage::SetColor { colorable, color } => {
|
||||
|
|
@ -3154,7 +3083,7 @@ impl ConfigProxyHandler {
|
|||
args,
|
||||
env,
|
||||
fds,
|
||||
} => self.handle_run(prog, args, env, fds, None).wrn("run")?,
|
||||
} => self.handle_run(prog, args, env, fds).wrn("run")?,
|
||||
ClientMessage::DisableDefaultSeat => self.state.create_default_seat.set(false),
|
||||
ClientMessage::DestroyKeymap { keymap } => self.handle_destroy_keymap(keymap),
|
||||
ClientMessage::GetConnectorName { connector } => self
|
||||
|
|
@ -3207,7 +3136,6 @@ impl ConfigProxyHandler {
|
|||
ClientMessage::SetExplicitSyncEnabled { enabled } => {
|
||||
self.handle_set_explicit_sync_enabled(enabled)
|
||||
}
|
||||
ClientMessage::GetSocketPath => self.handle_get_socket_path(),
|
||||
ClientMessage::DeviceSetKeymap { device, keymap } => self
|
||||
.handle_set_device_keymap(device, keymap)
|
||||
.wrn("set_device_keymap")?,
|
||||
|
|
@ -3508,12 +3436,6 @@ impl ConfigProxyHandler {
|
|||
.wrn("connector_set_blend_space")?,
|
||||
ClientMessage::SetBarFont { font } => self.handle_set_bar_font(font),
|
||||
ClientMessage::SetTitleFont { font } => self.handle_set_title_font(font),
|
||||
ClientMessage::SetClientMatcherCapabilities { matcher, caps } => self
|
||||
.handle_set_client_matcher_capabilities(matcher, caps)
|
||||
.wrn("set_client_matcher_capabilities")?,
|
||||
ClientMessage::SetClientMatcherBoundingCapabilities { matcher, caps } => self
|
||||
.handle_set_client_matcher_bounding_capabilities(matcher, caps)
|
||||
.wrn("set_client_matcher_bounding_capabilities")?,
|
||||
ClientMessage::ShowWorkspaceOn {
|
||||
seat,
|
||||
workspace,
|
||||
|
|
@ -3559,13 +3481,6 @@ impl ConfigProxyHandler {
|
|||
ClientMessage::SetXWaylandEnabled { enabled } => self
|
||||
.handle_set_x_wayland_enabled(enabled)
|
||||
.wrn("set_x_wayland_enabled")?,
|
||||
ClientMessage::Run3 {
|
||||
prog,
|
||||
args,
|
||||
env,
|
||||
fds,
|
||||
tag,
|
||||
} => self.handle_run(prog, args, env, fds, tag).wrn("run")?,
|
||||
ClientMessage::ConnectorSupportsArbitraryModes { connector } => self
|
||||
.handle_connector_supports_arbitrary_modes(connector)
|
||||
.wrn("connector_supports_arbitrary_modes")?,
|
||||
|
|
@ -3638,41 +3553,6 @@ impl ConfigProxyHandler {
|
|||
None
|
||||
}
|
||||
|
||||
pub fn update_capabilities(
|
||||
&self,
|
||||
data: &Rc<Client>,
|
||||
bounding_caps: ClientCaps,
|
||||
set_bounding_caps: bool,
|
||||
) {
|
||||
let mut have_caps = false;
|
||||
let mut have_bounding_caps = false;
|
||||
let mut caps = ClientCaps::none();
|
||||
let mut new_bounding_caps = ClientCaps::none();
|
||||
for (matcher, state) in self.client_matcher_capabilities.lock().values() {
|
||||
if matcher.node.pull(data) {
|
||||
have_caps = true;
|
||||
caps |= *state;
|
||||
}
|
||||
}
|
||||
for (matcher, state) in self.client_matcher_bounding_capabilities.lock().values() {
|
||||
if matcher.node.pull(data) {
|
||||
have_bounding_caps = true;
|
||||
new_bounding_caps |= *state;
|
||||
}
|
||||
}
|
||||
if have_caps {
|
||||
caps &= bounding_caps;
|
||||
data.effective_caps.set(caps);
|
||||
}
|
||||
if !have_bounding_caps && set_bounding_caps {
|
||||
have_bounding_caps = true;
|
||||
new_bounding_caps = data.effective_caps.get();
|
||||
}
|
||||
if have_bounding_caps {
|
||||
new_bounding_caps &= bounding_caps;
|
||||
data.bounding_caps_for_children.set(new_bounding_caps);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
|
|
@ -3771,8 +3651,6 @@ enum CphError {
|
|||
UnknownFallbackOutputMode(FallbackOutputMode),
|
||||
#[error("Unknown tile state {0:?}")]
|
||||
UnknownTileState(ConfigTileState),
|
||||
#[error("Could not create a tagged acceptor")]
|
||||
CreateTaggedAcceptor(#[source] TaggedAcceptorError),
|
||||
}
|
||||
|
||||
trait WithRequestName {
|
||||
|
|
@ -3784,13 +3662,3 @@ impl WithRequestName for Result<(), CphError> {
|
|||
self.map_err(move |e| CphError::FailedRequest(request, Box::new(e)))
|
||||
}
|
||||
}
|
||||
|
||||
trait ClientCapabilitiesExt {
|
||||
fn to_client_caps(self) -> ClientCaps;
|
||||
}
|
||||
|
||||
impl ClientCapabilitiesExt for ClientCapabilities {
|
||||
fn to_client_caps(self) -> ClientCaps {
|
||||
ClientCaps(self.0 as u32) & !CAP_JAY_COMPOSITOR & ClientCaps::all()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,96 +1,4 @@
|
|||
pub mod clm;
|
||||
mod crit_graph;
|
||||
pub mod crit_leaf;
|
||||
mod crit_matchers;
|
||||
mod crit_per_target_data;
|
||||
pub mod tlm;
|
||||
|
||||
use {
|
||||
crate::{
|
||||
criteria::{
|
||||
crit_graph::{CritMgr, CritMiddle, CritRoot, CritRootCriterion, CritRootFixed},
|
||||
crit_leaf::CritLeafMatcher,
|
||||
crit_matchers::{critm_any_or_all::CritMatchAnyOrAll, critm_exactly::CritMatchExactly},
|
||||
},
|
||||
utils::copyhashmap::CopyHashMap,
|
||||
},
|
||||
linearize::StaticMap,
|
||||
regex::Regex,
|
||||
std::rc::{Rc, Weak},
|
||||
};
|
||||
pub use {
|
||||
crit_graph::{CritTarget, CritUpstreamNode},
|
||||
crit_per_target_data::CritDestroyListener,
|
||||
};
|
||||
|
||||
linear_ids!(CritMatcherIds, CritMatcherId, u64);
|
||||
|
||||
type RootMatcherMap<Target, T> = CopyHashMap<CritMatcherId, Weak<CritRoot<Target, T>>>;
|
||||
type FixedRootMatcher<Target, T> = StaticMap<bool, Rc<CritRoot<Target, CritRootFixed<Target, T>>>>;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub enum CritLiteralOrRegex {
|
||||
Literal(String),
|
||||
Regex(Regex),
|
||||
}
|
||||
|
||||
impl CritLiteralOrRegex {
|
||||
fn matches(&self, string: &str) -> bool {
|
||||
match self {
|
||||
CritLiteralOrRegex::Literal(p) => string == p,
|
||||
CritLiteralOrRegex::Regex(r) => r.is_match(string),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait CritMgrExt: CritMgr {
|
||||
fn list(
|
||||
&self,
|
||||
upstream: &[Rc<dyn CritUpstreamNode<Self::Target>>],
|
||||
all: bool,
|
||||
) -> Rc<dyn CritUpstreamNode<Self::Target>> {
|
||||
if upstream.is_empty() {
|
||||
return self.match_constant()[all].clone();
|
||||
}
|
||||
CritMiddle::new(self, upstream, CritMatchAnyOrAll::new(upstream, all))
|
||||
}
|
||||
|
||||
fn exactly(
|
||||
&self,
|
||||
upstream: &[Rc<dyn CritUpstreamNode<Self::Target>>],
|
||||
num: usize,
|
||||
) -> Rc<dyn CritUpstreamNode<Self::Target>> {
|
||||
if num > upstream.len() {
|
||||
return self.match_constant()[false].clone();
|
||||
}
|
||||
if num == 0 {
|
||||
let upstream: Vec<_> = upstream.iter().map(|u| u.not(self)).collect();
|
||||
return self.list(&upstream, true);
|
||||
}
|
||||
CritMiddle::new(self, upstream, CritMatchExactly::new(upstream, num))
|
||||
}
|
||||
|
||||
fn leaf(
|
||||
&self,
|
||||
upstream: &Rc<dyn CritUpstreamNode<Self::Target>>,
|
||||
on_match: impl Fn(<Self::Target as CritTarget>::LeafData) -> Box<dyn FnOnce()> + 'static,
|
||||
) -> Rc<CritLeafMatcher<Self::Target>> {
|
||||
CritLeafMatcher::new(self, upstream, on_match)
|
||||
}
|
||||
|
||||
fn not(
|
||||
&self,
|
||||
upstream: &Rc<dyn CritUpstreamNode<Self::Target>>,
|
||||
) -> Rc<dyn CritUpstreamNode<Self::Target>> {
|
||||
upstream.not(self)
|
||||
}
|
||||
|
||||
fn root<T>(&self, criterion: T) -> Rc<dyn CritUpstreamNode<Self::Target>>
|
||||
where
|
||||
T: CritRootCriterion<Self::Target>,
|
||||
{
|
||||
CritRoot::new(self.roots(), self.id(), criterion)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> CritMgrExt for T where T: CritMgr {}
|
||||
pub use jay_criteria::*;
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ use {
|
|||
clmm_sandboxed::ClmMatchSandboxed,
|
||||
clmm_string::{
|
||||
ClmMatchComm, ClmMatchExe, ClmMatchSandboxAppId, ClmMatchSandboxEngine,
|
||||
ClmMatchSandboxInstanceId, ClmMatchTag,
|
||||
ClmMatchSandboxInstanceId,
|
||||
},
|
||||
clmm_uid::ClmMatchUid,
|
||||
},
|
||||
|
|
@ -39,19 +39,19 @@ bitflags! {
|
|||
CL_CHANGED_NEW,
|
||||
}
|
||||
|
||||
type ClmFixedRootMatcher<T> = FixedRootMatcher<Rc<Client>, T>;
|
||||
type ClmFixedRootMatcher<T> = FixedRootMatcher<Client, T>;
|
||||
|
||||
pub struct ClMatcherManager {
|
||||
ids: Rc<CritMatcherIds>,
|
||||
changes: AsyncQueue<Rc<Client>>,
|
||||
leaf_events: Rc<AsyncQueue<CritLeafEvent<Rc<Client>>>>,
|
||||
constant: ClmFixedRootMatcher<CritMatchConstant<Rc<Client>>>,
|
||||
leaf_events: Rc<AsyncQueue<CritLeafEvent<Client>>>,
|
||||
constant: ClmFixedRootMatcher<CritMatchConstant<Client>>,
|
||||
sandboxed: ClmFixedRootMatcher<ClmMatchSandboxed>,
|
||||
is_xwayland: ClmFixedRootMatcher<ClmMatchIsXwayland>,
|
||||
matchers: Rc<RootMatchers>,
|
||||
}
|
||||
|
||||
type ClmRootMatcherMap<T> = RootMatcherMap<Rc<Client>, T>;
|
||||
type ClmRootMatcherMap<T> = RootMatcherMap<Client, T>;
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct RootMatchers {
|
||||
|
|
@ -62,7 +62,6 @@ pub struct RootMatchers {
|
|||
pid: ClmRootMatcherMap<ClmMatchPid>,
|
||||
comm: ClmRootMatcherMap<ClmMatchComm>,
|
||||
exe: ClmRootMatcherMap<ClmMatchExe>,
|
||||
tag: ClmRootMatcherMap<ClmMatchTag>,
|
||||
id: ClmRootMatcherMap<ClmMatchId>,
|
||||
}
|
||||
|
||||
|
|
@ -75,7 +74,6 @@ impl RootMatchers {
|
|||
self.pid.clear();
|
||||
self.comm.clear();
|
||||
self.exe.clear();
|
||||
self.tag.clear();
|
||||
self.id.clear();
|
||||
}
|
||||
}
|
||||
|
|
@ -98,8 +96,8 @@ pub async fn handle_cl_leaf_events(state: Rc<State>) {
|
|||
}
|
||||
}
|
||||
|
||||
pub type ClmUpstreamNode = dyn CritUpstreamNode<Rc<Client>>;
|
||||
pub type ClmLeafMatcher = CritLeafMatcher<Rc<Client>>;
|
||||
pub type ClmUpstreamNode = dyn CritUpstreamNode<Client>;
|
||||
pub type ClmLeafMatcher = CritLeafMatcher<Client>;
|
||||
|
||||
impl ClMatcherManager {
|
||||
pub fn new(ids: &Rc<CritMatcherIds>) -> Self {
|
||||
|
|
@ -146,6 +144,7 @@ impl ClMatcherManager {
|
|||
}
|
||||
|
||||
fn update_matches(&self, data: &Rc<Client>) {
|
||||
let data = data.as_ref();
|
||||
let mut changed = data.changed_properties.take();
|
||||
if changed.contains(CL_CHANGED_DESTROYED) {
|
||||
for destroyed in data.destroyed.lock().drain_values() {
|
||||
|
|
@ -186,7 +185,6 @@ impl ClMatcherManager {
|
|||
unconditional!(pid);
|
||||
unconditional!(comm);
|
||||
unconditional!(exe);
|
||||
unconditional!(tag);
|
||||
unconditional!(id);
|
||||
fixed!(sandboxed);
|
||||
fixed!(is_xwayland);
|
||||
|
|
@ -230,20 +228,29 @@ impl ClMatcherManager {
|
|||
self.root(ClmMatchExe::new(string))
|
||||
}
|
||||
|
||||
pub fn tag(&self, string: CritLiteralOrRegex) -> Rc<ClmUpstreamNode> {
|
||||
self.root(ClmMatchTag::new(string))
|
||||
}
|
||||
}
|
||||
|
||||
impl CritTarget for Rc<Client> {
|
||||
pub struct ClientTargetOwner {
|
||||
client: Rc<Client>,
|
||||
}
|
||||
|
||||
pub struct WeakClientTargetOwner {
|
||||
state: Weak<State>,
|
||||
id: ClientId,
|
||||
}
|
||||
|
||||
impl CritTarget for Client {
|
||||
type Id = ClientId;
|
||||
type Mgr = ClMatcherManager;
|
||||
type RootMatchers = RootMatchers;
|
||||
type LeafData = ClientId;
|
||||
type Owner = Weak<Client>;
|
||||
type Owner = WeakClientTargetOwner;
|
||||
|
||||
fn owner(&self) -> Self::Owner {
|
||||
Rc::downgrade(self)
|
||||
WeakClientTargetOwner {
|
||||
state: Rc::downgrade(&self.state),
|
||||
id: self.id,
|
||||
}
|
||||
}
|
||||
|
||||
fn id(&self) -> Self::Id {
|
||||
|
|
@ -259,25 +266,27 @@ impl CritTarget for Rc<Client> {
|
|||
}
|
||||
}
|
||||
|
||||
impl CritTargetOwner for Rc<Client> {
|
||||
type Target = Rc<Client>;
|
||||
impl CritTargetOwner for ClientTargetOwner {
|
||||
type Target = Client;
|
||||
|
||||
fn data(&self) -> &Self::Target {
|
||||
self
|
||||
&self.client
|
||||
}
|
||||
}
|
||||
|
||||
impl WeakCritTargetOwner for Weak<Client> {
|
||||
type Target = Rc<Client>;
|
||||
type Owner = Rc<Client>;
|
||||
impl WeakCritTargetOwner for WeakClientTargetOwner {
|
||||
type Target = Client;
|
||||
type Owner = ClientTargetOwner;
|
||||
|
||||
fn upgrade(&self) -> Option<Self::Owner> {
|
||||
self.upgrade()
|
||||
let state = self.state.upgrade()?;
|
||||
let client = state.clients.get(self.id).ok()?;
|
||||
Some(ClientTargetOwner { client })
|
||||
}
|
||||
}
|
||||
|
||||
impl CritMgr for ClMatcherManager {
|
||||
type Target = Rc<Client>;
|
||||
type Target = Client;
|
||||
|
||||
fn id(&self) -> CritMatcherId {
|
||||
self.ids.next()
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
macro_rules! fixed_root_criterion {
|
||||
($ty:ty, $field:ident) => {
|
||||
impl crate::criteria::crit_graph::CritFixedRootCriterionBase<Rc<crate::client::Client>>
|
||||
impl crate::criteria::crit_graph::CritFixedRootCriterionBase<crate::client::Client>
|
||||
for $ty
|
||||
{
|
||||
fn constant(&self) -> bool {
|
||||
|
|
@ -10,7 +10,7 @@ macro_rules! fixed_root_criterion {
|
|||
fn not<'a>(
|
||||
&self,
|
||||
mgr: &'a crate::criteria::clm::ClMatcherManager,
|
||||
) -> &'a crate::criteria::FixedRootMatcher<Rc<crate::client::Client>, Self> {
|
||||
) -> &'a crate::criteria::FixedRootMatcher<crate::client::Client, Self> {
|
||||
&mgr.$field
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,17 +3,16 @@ use {
|
|||
client::{Client, ClientId},
|
||||
criteria::{RootMatcherMap, clm::RootMatchers, crit_graph::CritRootCriterion},
|
||||
},
|
||||
std::rc::Rc,
|
||||
};
|
||||
|
||||
pub struct ClmMatchId(pub ClientId);
|
||||
|
||||
impl CritRootCriterion<Rc<Client>> for ClmMatchId {
|
||||
fn matches(&self, data: &Rc<Client>) -> bool {
|
||||
impl CritRootCriterion<Client> for ClmMatchId {
|
||||
fn matches(&self, data: &Client) -> bool {
|
||||
data.id == self.0
|
||||
}
|
||||
|
||||
fn nodes(roots: &RootMatchers) -> Option<&RootMatcherMap<Rc<Client>, Self>> {
|
||||
fn nodes(roots: &RootMatchers) -> Option<&RootMatcherMap<Client, Self>> {
|
||||
Some(&roots.id)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,14 +1,13 @@
|
|||
use {
|
||||
crate::{client::Client, criteria::crit_graph::CritFixedRootCriterion},
|
||||
std::rc::Rc,
|
||||
};
|
||||
|
||||
pub struct ClmMatchIsXwayland(pub bool);
|
||||
|
||||
fixed_root_criterion!(ClmMatchIsXwayland, is_xwayland);
|
||||
|
||||
impl CritFixedRootCriterion<Rc<Client>> for ClmMatchIsXwayland {
|
||||
fn matches(&self, data: &Rc<Client>) -> bool {
|
||||
impl CritFixedRootCriterion<Client> for ClmMatchIsXwayland {
|
||||
fn matches(&self, data: &Client) -> bool {
|
||||
data.is_xwayland
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,18 +3,17 @@ use {
|
|||
client::Client,
|
||||
criteria::{RootMatcherMap, clm::RootMatchers, crit_graph::CritRootCriterion},
|
||||
},
|
||||
std::rc::Rc,
|
||||
uapi::c,
|
||||
};
|
||||
|
||||
pub struct ClmMatchPid(pub c::pid_t);
|
||||
|
||||
impl CritRootCriterion<Rc<Client>> for ClmMatchPid {
|
||||
fn matches(&self, data: &Rc<Client>) -> bool {
|
||||
impl CritRootCriterion<Client> for ClmMatchPid {
|
||||
fn matches(&self, data: &Client) -> bool {
|
||||
data.pid_info.pid == self.0
|
||||
}
|
||||
|
||||
fn nodes(roots: &RootMatchers) -> Option<&RootMatcherMap<Rc<Client>, Self>> {
|
||||
fn nodes(roots: &RootMatchers) -> Option<&RootMatcherMap<Client, Self>> {
|
||||
Some(&roots.pid)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,14 +1,13 @@
|
|||
use {
|
||||
crate::{client::Client, criteria::crit_graph::CritFixedRootCriterion},
|
||||
std::rc::Rc,
|
||||
};
|
||||
|
||||
pub struct ClmMatchSandboxed(pub bool);
|
||||
|
||||
fixed_root_criterion!(ClmMatchSandboxed, sandboxed);
|
||||
|
||||
impl CritFixedRootCriterion<Rc<Client>> for ClmMatchSandboxed {
|
||||
fn matches(&self, data: &Rc<Client>) -> bool {
|
||||
impl CritFixedRootCriterion<Client> for ClmMatchSandboxed {
|
||||
fn matches(&self, data: &Client) -> bool {
|
||||
data.acceptor.sandboxed
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,15 +7,14 @@ use {
|
|||
},
|
||||
security_context_acceptor::AcceptorMetadata,
|
||||
},
|
||||
std::{marker::PhantomData, rc::Rc},
|
||||
std::marker::PhantomData,
|
||||
};
|
||||
|
||||
pub type ClmMatchString<T> = CritMatchString<Rc<Client>, T>;
|
||||
pub type ClmMatchString<T> = CritMatchString<Client, T>;
|
||||
|
||||
pub type ClmMatchSandboxEngine = ClmMatchString<AcceptorMetadataAccess<SandboxEngineField>>;
|
||||
pub type ClmMatchSandboxAppId = ClmMatchString<AcceptorMetadataAccess<SandboxAppIdField>>;
|
||||
pub type ClmMatchSandboxInstanceId = ClmMatchString<AcceptorMetadataAccess<SandboxInstanceIdField>>;
|
||||
pub type ClmMatchTag = ClmMatchString<AcceptorMetadataAccess<TagField>>;
|
||||
pub type ClmMatchComm = ClmMatchString<CommAccess>;
|
||||
pub type ClmMatchExe = ClmMatchString<ExeAccess>;
|
||||
|
||||
|
|
@ -33,13 +32,12 @@ trait AcceptorMetadataField: Sized + 'static {
|
|||
pub struct SandboxEngineField;
|
||||
pub struct SandboxAppIdField;
|
||||
pub struct SandboxInstanceIdField;
|
||||
pub struct TagField;
|
||||
|
||||
impl<T> StringAccess<Rc<Client>> for AcceptorMetadataAccess<T>
|
||||
impl<T> StringAccess<Client> for AcceptorMetadataAccess<T>
|
||||
where
|
||||
T: AcceptorMetadataField,
|
||||
{
|
||||
fn with_string(data: &Rc<Client>, f: impl FnOnce(&str) -> bool) -> bool {
|
||||
fn with_string(data: &Client, f: impl FnOnce(&str) -> bool) -> bool {
|
||||
f(T::field(&data.acceptor).as_deref().unwrap_or_default())
|
||||
}
|
||||
|
||||
|
|
@ -84,20 +82,8 @@ impl AcceptorMetadataField for SandboxInstanceIdField {
|
|||
}
|
||||
}
|
||||
|
||||
impl AcceptorMetadataField for TagField {
|
||||
fn field(meta: &AcceptorMetadata) -> &Option<String> {
|
||||
&meta.tag
|
||||
}
|
||||
|
||||
fn nodes(
|
||||
roots: &RootMatchers,
|
||||
) -> &ClmRootMatcherMap<ClmMatchString<AcceptorMetadataAccess<Self>>> {
|
||||
&roots.tag
|
||||
}
|
||||
}
|
||||
|
||||
impl StringAccess<Rc<Client>> for CommAccess {
|
||||
fn with_string(data: &Rc<Client>, f: impl FnOnce(&str) -> bool) -> bool {
|
||||
impl StringAccess<Client> for CommAccess {
|
||||
fn with_string(data: &Client, f: impl FnOnce(&str) -> bool) -> bool {
|
||||
f(&data.pid_info.comm)
|
||||
}
|
||||
|
||||
|
|
@ -106,8 +92,8 @@ impl StringAccess<Rc<Client>> for CommAccess {
|
|||
}
|
||||
}
|
||||
|
||||
impl StringAccess<Rc<Client>> for ExeAccess {
|
||||
fn with_string(data: &Rc<Client>, f: impl FnOnce(&str) -> bool) -> bool {
|
||||
impl StringAccess<Client> for ExeAccess {
|
||||
fn with_string(data: &Client, f: impl FnOnce(&str) -> bool) -> bool {
|
||||
f(&data.pid_info.exe)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,18 +3,17 @@ use {
|
|||
client::Client,
|
||||
criteria::{RootMatcherMap, clm::RootMatchers, crit_graph::CritRootCriterion},
|
||||
},
|
||||
std::rc::Rc,
|
||||
uapi::c,
|
||||
};
|
||||
|
||||
pub struct ClmMatchUid(pub c::uid_t);
|
||||
|
||||
impl CritRootCriterion<Rc<Client>> for ClmMatchUid {
|
||||
fn matches(&self, data: &Rc<Client>) -> bool {
|
||||
impl CritRootCriterion<Client> for ClmMatchUid {
|
||||
fn matches(&self, data: &Client) -> bool {
|
||||
data.pid_info.uid == self.0
|
||||
}
|
||||
|
||||
fn nodes(roots: &RootMatchers) -> Option<&RootMatcherMap<Rc<Client>, Self>> {
|
||||
fn nodes(roots: &RootMatchers) -> Option<&RootMatcherMap<Client, Self>> {
|
||||
Some(&roots.uid)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -408,10 +408,10 @@ impl CritTarget for ToplevelData {
|
|||
type Mgr = TlMatcherManager;
|
||||
type RootMatchers = RootMatchers;
|
||||
type LeafData = ToplevelIdentifier;
|
||||
type Owner = Weak<dyn ToplevelNode>;
|
||||
type Owner = WeakToplevelTargetOwner;
|
||||
|
||||
fn owner(&self) -> Self::Owner {
|
||||
self.slf.clone()
|
||||
WeakToplevelTargetOwner(self.slf.clone())
|
||||
}
|
||||
|
||||
fn id(&self) -> Self::Id {
|
||||
|
|
@ -427,20 +427,24 @@ impl CritTarget for ToplevelData {
|
|||
}
|
||||
}
|
||||
|
||||
impl CritTargetOwner for Rc<dyn ToplevelNode> {
|
||||
pub struct ToplevelTargetOwner(Rc<dyn ToplevelNode>);
|
||||
|
||||
pub struct WeakToplevelTargetOwner(Weak<dyn ToplevelNode>);
|
||||
|
||||
impl CritTargetOwner for ToplevelTargetOwner {
|
||||
type Target = ToplevelData;
|
||||
|
||||
fn data(&self) -> &Self::Target {
|
||||
self.tl_data()
|
||||
self.0.tl_data()
|
||||
}
|
||||
}
|
||||
|
||||
impl WeakCritTargetOwner for Weak<dyn ToplevelNode> {
|
||||
impl WeakCritTargetOwner for WeakToplevelTargetOwner {
|
||||
type Target = ToplevelData;
|
||||
type Owner = Rc<dyn ToplevelNode>;
|
||||
type Owner = ToplevelTargetOwner;
|
||||
|
||||
fn upgrade(&self) -> Option<Self::Owner> {
|
||||
self.upgrade()
|
||||
self.0.upgrade().map(ToplevelTargetOwner)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ pub struct TlmMatchClient {
|
|||
id: CritMatcherId,
|
||||
state: Rc<State>,
|
||||
node: Rc<ClmUpstreamNode>,
|
||||
upstream: CritDownstreamData<Rc<Client>>,
|
||||
upstream: CritDownstreamData<Client>,
|
||||
downstream: CritUpstreamData<ToplevelData, ()>,
|
||||
}
|
||||
|
||||
|
|
@ -73,8 +73,8 @@ impl CritUpstreamNodeBase<ToplevelData> for TlmMatchClient {
|
|||
}
|
||||
}
|
||||
|
||||
impl CritDownstream<Rc<Client>> for TlmMatchClient {
|
||||
fn update_matched(self: Rc<Self>, target: &Rc<Client>, matched: bool) {
|
||||
impl CritDownstream<Client> for TlmMatchClient {
|
||||
fn update_matched(self: Rc<Self>, target: &Client, matched: bool) {
|
||||
let handle = |data: &ToplevelData| {
|
||||
let node = match matched {
|
||||
true => self.downstream.get_or_create(data),
|
||||
|
|
|
|||
1303
src/edid.rs
1303
src/edid.rs
File diff suppressed because it is too large
Load diff
138
src/fixed.rs
138
src/fixed.rs
|
|
@ -1,137 +1 @@
|
|||
use std::{
|
||||
cmp::Ordering,
|
||||
fmt::{Debug, Display, Formatter},
|
||||
ops::{Add, AddAssign, Div, Mul, Sub, SubAssign},
|
||||
};
|
||||
|
||||
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Default)]
|
||||
#[repr(transparent)]
|
||||
pub struct Fixed(pub i32);
|
||||
|
||||
impl Fixed {
|
||||
pub const EPSILON: Self = Fixed(1);
|
||||
|
||||
pub fn is_integer(self) -> bool {
|
||||
self.0 & 255 == 0
|
||||
}
|
||||
|
||||
pub fn from_f64(f: f64) -> Self {
|
||||
Self((f * 256.0) as i32)
|
||||
}
|
||||
|
||||
pub fn from_f32(f: f32) -> Self {
|
||||
Self::from_f64(f as f64)
|
||||
}
|
||||
|
||||
pub fn to_f64(self) -> f64 {
|
||||
self.0 as f64 / 256.0
|
||||
}
|
||||
|
||||
pub fn to_f32(self) -> f32 {
|
||||
self.0 as f32 / 256.0
|
||||
}
|
||||
|
||||
pub fn from_1616(i: i32) -> Self {
|
||||
Self(i >> 8)
|
||||
}
|
||||
|
||||
pub fn to_int(self) -> i32 {
|
||||
self.0 >> 8
|
||||
}
|
||||
|
||||
pub fn from_int(i: i32) -> Self {
|
||||
Self(i << 8)
|
||||
}
|
||||
|
||||
pub fn round_down(self) -> i32 {
|
||||
self.0 >> 8
|
||||
}
|
||||
|
||||
pub fn apply_fract(self, i: i32) -> Self {
|
||||
Self((i << 8) | (self.0 & 255))
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<i32> for Fixed {
|
||||
fn eq(&self, other: &i32) -> bool {
|
||||
self.0 == *other << 8
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd<i32> for Fixed {
|
||||
fn partial_cmp(&self, other: &i32) -> Option<Ordering> {
|
||||
self.0.partial_cmp(&(*other << 8))
|
||||
}
|
||||
}
|
||||
|
||||
impl Debug for Fixed {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
Debug::fmt(&self.to_f64(), f)
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Fixed {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
Display::fmt(&self.to_f64(), f)
|
||||
}
|
||||
}
|
||||
|
||||
impl Sub for Fixed {
|
||||
type Output = Self;
|
||||
|
||||
fn sub(self, rhs: Self) -> Self::Output {
|
||||
Self(self.0 - rhs.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl Add for Fixed {
|
||||
type Output = Self;
|
||||
|
||||
fn add(self, rhs: Self) -> Self::Output {
|
||||
Self(self.0 + rhs.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl Sub<i32> for Fixed {
|
||||
type Output = Self;
|
||||
|
||||
fn sub(self, rhs: i32) -> Self::Output {
|
||||
Self(self.0 - (rhs << 8))
|
||||
}
|
||||
}
|
||||
|
||||
impl Add<i32> for Fixed {
|
||||
type Output = Self;
|
||||
|
||||
fn add(self, rhs: i32) -> Self::Output {
|
||||
Self(self.0 + (rhs << 8))
|
||||
}
|
||||
}
|
||||
|
||||
impl Mul<i32> for Fixed {
|
||||
type Output = Self;
|
||||
|
||||
fn mul(self, rhs: i32) -> Self::Output {
|
||||
Self(self.0 * rhs)
|
||||
}
|
||||
}
|
||||
|
||||
impl Div<i32> for Fixed {
|
||||
type Output = Self;
|
||||
|
||||
fn div(self, rhs: i32) -> Self::Output {
|
||||
Self(self.0 / rhs)
|
||||
}
|
||||
}
|
||||
|
||||
impl AddAssign for Fixed {
|
||||
fn add_assign(&mut self, rhs: Self) {
|
||||
self.0 += rhs.0;
|
||||
}
|
||||
}
|
||||
|
||||
impl SubAssign for Fixed {
|
||||
fn sub_assign(&mut self, rhs: Self) {
|
||||
self.0 -= rhs.0;
|
||||
}
|
||||
}
|
||||
pub use jay_units::fixed::*;
|
||||
|
|
|
|||
584
src/format.rs
584
src/format.rs
|
|
@ -1,583 +1 @@
|
|||
use {
|
||||
crate::{
|
||||
gfx_apis::gl::sys::{GL_BGRA_EXT, GL_RGBA, GL_RGBA8, GL_UNSIGNED_BYTE, GLenum, GLint},
|
||||
pipewire::pw_pod::{
|
||||
SPA_VIDEO_FORMAT_ABGR_210LE, SPA_VIDEO_FORMAT_ARGB_210LE, SPA_VIDEO_FORMAT_BGR,
|
||||
SPA_VIDEO_FORMAT_BGR15, SPA_VIDEO_FORMAT_BGR16, SPA_VIDEO_FORMAT_BGRA,
|
||||
SPA_VIDEO_FORMAT_BGRx, SPA_VIDEO_FORMAT_GRAY8, SPA_VIDEO_FORMAT_RGB,
|
||||
SPA_VIDEO_FORMAT_RGB16, SPA_VIDEO_FORMAT_RGBA, SPA_VIDEO_FORMAT_RGBx,
|
||||
SPA_VIDEO_FORMAT_UNKNOWN, SPA_VIDEO_FORMAT_xBGR_210LE, SPA_VIDEO_FORMAT_xRGB_210LE,
|
||||
SpaVideoFormat,
|
||||
},
|
||||
},
|
||||
ahash::AHashMap,
|
||||
ash::vk,
|
||||
jay_config::video::Format as ConfigFormat,
|
||||
std::{
|
||||
fmt::{self, Debug, Write},
|
||||
sync::LazyLock,
|
||||
},
|
||||
};
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct FormatShmInfo {
|
||||
pub gl_format: GLint,
|
||||
pub gl_internal_format: GLenum,
|
||||
pub gl_type: GLint,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct Format {
|
||||
pub name: &'static str,
|
||||
pub vk_format: vk::Format,
|
||||
pub drm: u32,
|
||||
pub wl_id: Option<u32>,
|
||||
pub external_only_guess: bool,
|
||||
pub has_alpha: bool,
|
||||
pub pipewire: SpaVideoFormat,
|
||||
pub opaque: Option<&'static Format>,
|
||||
pub shm_info: Option<FormatShmInfo>,
|
||||
pub config: ConfigFormat,
|
||||
pub bpp: u32,
|
||||
}
|
||||
|
||||
const fn default(config: ConfigFormat) -> Format {
|
||||
Format {
|
||||
name: "",
|
||||
vk_format: vk::Format::UNDEFINED,
|
||||
drm: 0,
|
||||
wl_id: None,
|
||||
external_only_guess: false,
|
||||
has_alpha: false,
|
||||
pipewire: SPA_VIDEO_FORMAT_UNKNOWN,
|
||||
opaque: None,
|
||||
shm_info: None,
|
||||
config,
|
||||
bpp: 4,
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for Format {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.drm == other.drm
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for Format {}
|
||||
|
||||
static FORMATS_MAP: LazyLock<AHashMap<u32, &'static Format>> = LazyLock::new(|| {
|
||||
let mut map = AHashMap::new();
|
||||
for format in FORMATS {
|
||||
assert!(map.insert(format.drm, format).is_none());
|
||||
}
|
||||
map
|
||||
});
|
||||
|
||||
static PW_FORMATS_MAP: LazyLock<AHashMap<SpaVideoFormat, &'static Format>> = LazyLock::new(|| {
|
||||
let mut map = AHashMap::new();
|
||||
for format in FORMATS {
|
||||
if format.pipewire != SPA_VIDEO_FORMAT_UNKNOWN {
|
||||
assert!(map.insert(format.pipewire, format).is_none());
|
||||
}
|
||||
}
|
||||
map
|
||||
});
|
||||
|
||||
static FORMATS_REFS: LazyLock<Vec<&'static Format>> = LazyLock::new(|| FORMATS.iter().collect());
|
||||
|
||||
static FORMATS_NAMES: LazyLock<AHashMap<&'static str, &'static Format>> = LazyLock::new(|| {
|
||||
let mut map = AHashMap::new();
|
||||
for format in FORMATS {
|
||||
assert!(map.insert(format.name, format).is_none());
|
||||
}
|
||||
map
|
||||
});
|
||||
|
||||
static FORMATS_CONFIG: LazyLock<AHashMap<ConfigFormat, &'static Format>> = LazyLock::new(|| {
|
||||
let mut map = AHashMap::new();
|
||||
for format in FORMATS {
|
||||
assert!(map.insert(format.config, format).is_none());
|
||||
}
|
||||
map
|
||||
});
|
||||
|
||||
#[test]
|
||||
fn formats_dont_panic() {
|
||||
formats();
|
||||
pw_formats();
|
||||
named_formats();
|
||||
config_formats();
|
||||
}
|
||||
|
||||
pub fn formats() -> &'static AHashMap<u32, &'static Format> {
|
||||
&FORMATS_MAP
|
||||
}
|
||||
|
||||
pub fn pw_formats() -> &'static AHashMap<SpaVideoFormat, &'static Format> {
|
||||
&PW_FORMATS_MAP
|
||||
}
|
||||
|
||||
pub fn ref_formats() -> &'static [&'static Format] {
|
||||
&FORMATS_REFS
|
||||
}
|
||||
|
||||
pub fn named_formats() -> &'static AHashMap<&'static str, &'static Format> {
|
||||
&FORMATS_NAMES
|
||||
}
|
||||
|
||||
pub fn config_formats() -> &'static AHashMap<ConfigFormat, &'static Format> {
|
||||
&FORMATS_CONFIG
|
||||
}
|
||||
|
||||
const fn fourcc_code(a: char, b: char, c: char, d: char) -> u32 {
|
||||
(a as u32) | ((b as u32) << 8) | ((c as u32) << 16) | ((d as u32) << 24)
|
||||
}
|
||||
|
||||
#[expect(dead_code)]
|
||||
pub fn debug(fourcc: u32) -> impl Debug {
|
||||
fmt::from_fn(move |fmt| {
|
||||
fmt.write_char(fourcc as u8 as char)?;
|
||||
fmt.write_char((fourcc >> 8) as u8 as char)?;
|
||||
fmt.write_char((fourcc >> 16) as u8 as char)?;
|
||||
fmt.write_char((fourcc >> 24) as u8 as char)?;
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
|
||||
const ARGB8888_ID: u32 = 0;
|
||||
const ARGB8888_DRM: u32 = fourcc_code('A', 'R', '2', '4');
|
||||
|
||||
const XRGB8888_ID: u32 = 1;
|
||||
const XRGB8888_DRM: u32 = fourcc_code('X', 'R', '2', '4');
|
||||
|
||||
pub fn map_wayland_format_id(id: u32) -> u32 {
|
||||
match id {
|
||||
ARGB8888_ID => ARGB8888_DRM,
|
||||
XRGB8888_ID => XRGB8888_DRM,
|
||||
_ => id,
|
||||
}
|
||||
}
|
||||
|
||||
pub static ARGB8888: &Format = &Format {
|
||||
name: "argb8888",
|
||||
shm_info: Some(FormatShmInfo {
|
||||
gl_format: GL_BGRA_EXT,
|
||||
gl_internal_format: GL_RGBA8,
|
||||
gl_type: GL_UNSIGNED_BYTE,
|
||||
}),
|
||||
vk_format: vk::Format::B8G8R8A8_UNORM,
|
||||
bpp: 4,
|
||||
drm: ARGB8888_DRM,
|
||||
wl_id: Some(ARGB8888_ID),
|
||||
external_only_guess: false,
|
||||
has_alpha: true,
|
||||
pipewire: SPA_VIDEO_FORMAT_BGRA,
|
||||
opaque: Some(XRGB8888),
|
||||
config: ConfigFormat::ARGB8888,
|
||||
};
|
||||
|
||||
pub static XRGB8888: &Format = &Format {
|
||||
name: "xrgb8888",
|
||||
shm_info: Some(FormatShmInfo {
|
||||
gl_format: GL_BGRA_EXT,
|
||||
gl_internal_format: GL_RGBA8,
|
||||
gl_type: GL_UNSIGNED_BYTE,
|
||||
}),
|
||||
vk_format: vk::Format::B8G8R8A8_UNORM,
|
||||
bpp: 4,
|
||||
drm: XRGB8888_DRM,
|
||||
wl_id: Some(XRGB8888_ID),
|
||||
external_only_guess: false,
|
||||
has_alpha: false,
|
||||
pipewire: SPA_VIDEO_FORMAT_BGRx,
|
||||
opaque: None,
|
||||
config: ConfigFormat::XRGB8888,
|
||||
};
|
||||
|
||||
static ABGR8888: &Format = &Format {
|
||||
name: "abgr8888",
|
||||
shm_info: Some(FormatShmInfo {
|
||||
gl_format: GL_RGBA,
|
||||
gl_internal_format: GL_RGBA8,
|
||||
gl_type: GL_UNSIGNED_BYTE,
|
||||
}),
|
||||
vk_format: vk::Format::R8G8B8A8_UNORM,
|
||||
bpp: 4,
|
||||
drm: fourcc_code('A', 'B', '2', '4'),
|
||||
wl_id: None,
|
||||
external_only_guess: false,
|
||||
has_alpha: true,
|
||||
pipewire: SPA_VIDEO_FORMAT_RGBA,
|
||||
opaque: Some(XBGR8888),
|
||||
config: ConfigFormat::ABGR8888,
|
||||
};
|
||||
|
||||
static XBGR8888: &Format = &Format {
|
||||
name: "xbgr8888",
|
||||
shm_info: Some(FormatShmInfo {
|
||||
gl_format: GL_RGBA,
|
||||
gl_internal_format: GL_RGBA8,
|
||||
gl_type: GL_UNSIGNED_BYTE,
|
||||
}),
|
||||
vk_format: vk::Format::R8G8B8A8_UNORM,
|
||||
bpp: 4,
|
||||
drm: fourcc_code('X', 'B', '2', '4'),
|
||||
wl_id: None,
|
||||
external_only_guess: false,
|
||||
has_alpha: false,
|
||||
pipewire: SPA_VIDEO_FORMAT_RGBx,
|
||||
opaque: None,
|
||||
config: ConfigFormat::XBGR8888,
|
||||
};
|
||||
|
||||
static R8: &Format = &Format {
|
||||
name: "r8",
|
||||
vk_format: vk::Format::R8_UNORM,
|
||||
bpp: 1,
|
||||
drm: fourcc_code('R', '8', ' ', ' '),
|
||||
pipewire: SPA_VIDEO_FORMAT_GRAY8,
|
||||
..default(ConfigFormat::R8)
|
||||
};
|
||||
|
||||
static GR88: &Format = &Format {
|
||||
name: "gr88",
|
||||
vk_format: vk::Format::R8G8_UNORM,
|
||||
bpp: 2,
|
||||
drm: fourcc_code('G', 'R', '8', '8'),
|
||||
..default(ConfigFormat::GR88)
|
||||
};
|
||||
|
||||
static RGB888: &Format = &Format {
|
||||
name: "rgb888",
|
||||
vk_format: vk::Format::B8G8R8_UNORM,
|
||||
bpp: 3,
|
||||
drm: fourcc_code('R', 'G', '2', '4'),
|
||||
pipewire: SPA_VIDEO_FORMAT_BGR,
|
||||
..default(ConfigFormat::RGB888)
|
||||
};
|
||||
|
||||
static BGR888: &Format = &Format {
|
||||
name: "bgr888",
|
||||
vk_format: vk::Format::R8G8B8_UNORM,
|
||||
bpp: 3,
|
||||
drm: fourcc_code('B', 'G', '2', '4'),
|
||||
pipewire: SPA_VIDEO_FORMAT_RGB,
|
||||
..default(ConfigFormat::BGR888)
|
||||
};
|
||||
|
||||
static RGBA4444: &Format = &Format {
|
||||
name: "rgba4444",
|
||||
vk_format: vk::Format::R4G4B4A4_UNORM_PACK16,
|
||||
bpp: 2,
|
||||
drm: fourcc_code('R', 'A', '1', '2'),
|
||||
has_alpha: true,
|
||||
opaque: Some(RGBX4444),
|
||||
..default(ConfigFormat::RGBA4444)
|
||||
};
|
||||
|
||||
static RGBX4444: &Format = &Format {
|
||||
name: "rgbx4444",
|
||||
vk_format: vk::Format::R4G4B4A4_UNORM_PACK16,
|
||||
bpp: 2,
|
||||
drm: fourcc_code('R', 'X', '1', '2'),
|
||||
..default(ConfigFormat::RGBX4444)
|
||||
};
|
||||
|
||||
static BGRA4444: &Format = &Format {
|
||||
name: "bgra4444",
|
||||
vk_format: vk::Format::B4G4R4A4_UNORM_PACK16,
|
||||
bpp: 2,
|
||||
drm: fourcc_code('B', 'A', '1', '2'),
|
||||
has_alpha: true,
|
||||
opaque: Some(BGRX4444),
|
||||
..default(ConfigFormat::BGRA4444)
|
||||
};
|
||||
|
||||
static BGRX4444: &Format = &Format {
|
||||
name: "bgrx4444",
|
||||
vk_format: vk::Format::B4G4R4A4_UNORM_PACK16,
|
||||
bpp: 2,
|
||||
drm: fourcc_code('B', 'X', '1', '2'),
|
||||
..default(ConfigFormat::BGRX4444)
|
||||
};
|
||||
|
||||
static RGB565: &Format = &Format {
|
||||
name: "rgb565",
|
||||
vk_format: vk::Format::R5G6B5_UNORM_PACK16,
|
||||
bpp: 2,
|
||||
drm: fourcc_code('R', 'G', '1', '6'),
|
||||
pipewire: SPA_VIDEO_FORMAT_BGR16,
|
||||
..default(ConfigFormat::RGB565)
|
||||
};
|
||||
|
||||
static BGR565: &Format = &Format {
|
||||
name: "bgr565",
|
||||
vk_format: vk::Format::B5G6R5_UNORM_PACK16,
|
||||
bpp: 2,
|
||||
drm: fourcc_code('B', 'G', '1', '6'),
|
||||
pipewire: SPA_VIDEO_FORMAT_RGB16,
|
||||
..default(ConfigFormat::BGR565)
|
||||
};
|
||||
|
||||
static RGBA5551: &Format = &Format {
|
||||
name: "rgba5551",
|
||||
vk_format: vk::Format::R5G5B5A1_UNORM_PACK16,
|
||||
bpp: 2,
|
||||
drm: fourcc_code('R', 'A', '1', '5'),
|
||||
has_alpha: true,
|
||||
opaque: Some(RGBX5551),
|
||||
..default(ConfigFormat::RGBA5551)
|
||||
};
|
||||
|
||||
static RGBX5551: &Format = &Format {
|
||||
name: "rgbx5551",
|
||||
vk_format: vk::Format::R5G5B5A1_UNORM_PACK16,
|
||||
bpp: 2,
|
||||
drm: fourcc_code('R', 'X', '1', '5'),
|
||||
..default(ConfigFormat::RGBX5551)
|
||||
};
|
||||
|
||||
static BGRA5551: &Format = &Format {
|
||||
name: "bgra5551",
|
||||
vk_format: vk::Format::B5G5R5A1_UNORM_PACK16,
|
||||
bpp: 2,
|
||||
drm: fourcc_code('B', 'A', '1', '5'),
|
||||
has_alpha: true,
|
||||
opaque: Some(BGRX5551),
|
||||
..default(ConfigFormat::BGRA5551)
|
||||
};
|
||||
|
||||
static BGRX5551: &Format = &Format {
|
||||
name: "bgrx5551",
|
||||
vk_format: vk::Format::B5G5R5A1_UNORM_PACK16,
|
||||
bpp: 2,
|
||||
drm: fourcc_code('B', 'X', '1', '5'),
|
||||
..default(ConfigFormat::BGRX5551)
|
||||
};
|
||||
|
||||
static ARGB1555: &Format = &Format {
|
||||
name: "argb1555",
|
||||
vk_format: vk::Format::A1R5G5B5_UNORM_PACK16,
|
||||
bpp: 2,
|
||||
drm: fourcc_code('A', 'R', '1', '5'),
|
||||
has_alpha: true,
|
||||
opaque: Some(XRGB1555),
|
||||
..default(ConfigFormat::ARGB1555)
|
||||
};
|
||||
|
||||
static XRGB1555: &Format = &Format {
|
||||
name: "xrgb1555",
|
||||
vk_format: vk::Format::A1R5G5B5_UNORM_PACK16,
|
||||
bpp: 2,
|
||||
drm: fourcc_code('X', 'R', '1', '5'),
|
||||
pipewire: SPA_VIDEO_FORMAT_BGR15,
|
||||
..default(ConfigFormat::XRGB1555)
|
||||
};
|
||||
|
||||
static ARGB2101010: &Format = &Format {
|
||||
name: "argb2101010",
|
||||
vk_format: vk::Format::A2R10G10B10_UNORM_PACK32,
|
||||
bpp: 4,
|
||||
drm: fourcc_code('A', 'R', '3', '0'),
|
||||
has_alpha: true,
|
||||
opaque: Some(XRGB2101010),
|
||||
pipewire: SPA_VIDEO_FORMAT_ARGB_210LE,
|
||||
..default(ConfigFormat::ARGB2101010)
|
||||
};
|
||||
|
||||
static XRGB2101010: &Format = &Format {
|
||||
name: "xrgb2101010",
|
||||
vk_format: vk::Format::A2R10G10B10_UNORM_PACK32,
|
||||
bpp: 4,
|
||||
drm: fourcc_code('X', 'R', '3', '0'),
|
||||
pipewire: SPA_VIDEO_FORMAT_xRGB_210LE,
|
||||
..default(ConfigFormat::XRGB2101010)
|
||||
};
|
||||
|
||||
static ABGR2101010: &Format = &Format {
|
||||
name: "abgr2101010",
|
||||
vk_format: vk::Format::A2B10G10R10_UNORM_PACK32,
|
||||
bpp: 4,
|
||||
drm: fourcc_code('A', 'B', '3', '0'),
|
||||
has_alpha: true,
|
||||
opaque: Some(XBGR2101010),
|
||||
pipewire: SPA_VIDEO_FORMAT_ABGR_210LE,
|
||||
..default(ConfigFormat::ABGR2101010)
|
||||
};
|
||||
|
||||
static XBGR2101010: &Format = &Format {
|
||||
name: "xbgr2101010",
|
||||
vk_format: vk::Format::A2B10G10R10_UNORM_PACK32,
|
||||
bpp: 4,
|
||||
drm: fourcc_code('X', 'B', '3', '0'),
|
||||
pipewire: SPA_VIDEO_FORMAT_xBGR_210LE,
|
||||
..default(ConfigFormat::XBGR2101010)
|
||||
};
|
||||
|
||||
static ABGR16161616: &Format = &Format {
|
||||
name: "abgr16161616",
|
||||
vk_format: vk::Format::R16G16B16A16_UNORM,
|
||||
bpp: 8,
|
||||
drm: fourcc_code('A', 'B', '4', '8'),
|
||||
has_alpha: true,
|
||||
opaque: Some(XBGR16161616),
|
||||
..default(ConfigFormat::ABGR16161616)
|
||||
};
|
||||
|
||||
static XBGR16161616: &Format = &Format {
|
||||
name: "xbgr16161616",
|
||||
vk_format: vk::Format::R16G16B16A16_UNORM,
|
||||
bpp: 8,
|
||||
drm: fourcc_code('X', 'B', '4', '8'),
|
||||
..default(ConfigFormat::XBGR16161616)
|
||||
};
|
||||
|
||||
pub static ABGR16161616F: &Format = &Format {
|
||||
name: "abgr16161616f",
|
||||
vk_format: vk::Format::R16G16B16A16_SFLOAT,
|
||||
bpp: 8,
|
||||
drm: fourcc_code('A', 'B', '4', 'H'),
|
||||
has_alpha: true,
|
||||
opaque: Some(XBGR16161616F),
|
||||
..default(ConfigFormat::ABGR16161616F)
|
||||
};
|
||||
|
||||
static XBGR16161616F: &Format = &Format {
|
||||
name: "xbgr16161616f",
|
||||
vk_format: vk::Format::R16G16B16A16_SFLOAT,
|
||||
bpp: 8,
|
||||
drm: fourcc_code('X', 'B', '4', 'H'),
|
||||
..default(ConfigFormat::XBGR16161616F)
|
||||
};
|
||||
|
||||
static BGR161616: &Format = &Format {
|
||||
name: "bgr161616",
|
||||
vk_format: vk::Format::R16G16B16_UNORM,
|
||||
bpp: 6,
|
||||
drm: fourcc_code('B', 'G', '4', '8'),
|
||||
..default(ConfigFormat::BGR161616)
|
||||
};
|
||||
|
||||
static R16F: &Format = &Format {
|
||||
name: "r16f",
|
||||
vk_format: vk::Format::R16_SFLOAT,
|
||||
bpp: 2,
|
||||
drm: fourcc_code('R', ' ', ' ', 'H'),
|
||||
..default(ConfigFormat::R16F)
|
||||
};
|
||||
|
||||
static GR1616F: &Format = &Format {
|
||||
name: "gr1616f",
|
||||
vk_format: vk::Format::R16G16_SFLOAT,
|
||||
bpp: 4,
|
||||
drm: fourcc_code('G', 'R', ' ', 'H'),
|
||||
..default(ConfigFormat::GR1616F)
|
||||
};
|
||||
|
||||
static BGR161616F: &Format = &Format {
|
||||
name: "bgr161616f",
|
||||
vk_format: vk::Format::R16G16B16_SFLOAT,
|
||||
bpp: 6,
|
||||
drm: fourcc_code('B', 'G', 'R', 'H'),
|
||||
..default(ConfigFormat::BGR161616F)
|
||||
};
|
||||
|
||||
static R32F: &Format = &Format {
|
||||
name: "r32f",
|
||||
vk_format: vk::Format::R32_SFLOAT,
|
||||
bpp: 4,
|
||||
drm: fourcc_code('R', ' ', ' ', 'F'),
|
||||
..default(ConfigFormat::R32F)
|
||||
};
|
||||
|
||||
static GR3232F: &Format = &Format {
|
||||
name: "gr3232f",
|
||||
vk_format: vk::Format::R32G32_SFLOAT,
|
||||
bpp: 8,
|
||||
drm: fourcc_code('G', 'R', ' ', 'F'),
|
||||
..default(ConfigFormat::GR3232F)
|
||||
};
|
||||
|
||||
static BGR323232F: &Format = &Format {
|
||||
name: "bgr323232f",
|
||||
vk_format: vk::Format::R32G32B32_SFLOAT,
|
||||
bpp: 12,
|
||||
drm: fourcc_code('B', 'G', 'R', 'F'),
|
||||
..default(ConfigFormat::BGR323232F)
|
||||
};
|
||||
|
||||
static ABGR32323232F: &Format = &Format {
|
||||
name: "abgr32323232f",
|
||||
vk_format: vk::Format::R32G32B32A32_SFLOAT,
|
||||
bpp: 16,
|
||||
drm: fourcc_code('A', 'B', '8', 'F'),
|
||||
has_alpha: true,
|
||||
..default(ConfigFormat::ABGR32323232F)
|
||||
};
|
||||
|
||||
pub static FORMATS: &[Format] = &[
|
||||
*ARGB8888,
|
||||
*XRGB8888,
|
||||
*ABGR8888,
|
||||
*XBGR8888,
|
||||
*R8,
|
||||
*GR88,
|
||||
*RGB888,
|
||||
*BGR888,
|
||||
#[cfg(target_endian = "little")]
|
||||
*RGBA4444,
|
||||
#[cfg(target_endian = "little")]
|
||||
*RGBX4444,
|
||||
#[cfg(target_endian = "little")]
|
||||
*BGRA4444,
|
||||
#[cfg(target_endian = "little")]
|
||||
*BGRX4444,
|
||||
#[cfg(target_endian = "little")]
|
||||
*RGB565,
|
||||
#[cfg(target_endian = "little")]
|
||||
*BGR565,
|
||||
#[cfg(target_endian = "little")]
|
||||
*RGBA5551,
|
||||
#[cfg(target_endian = "little")]
|
||||
*RGBX5551,
|
||||
#[cfg(target_endian = "little")]
|
||||
*BGRA5551,
|
||||
#[cfg(target_endian = "little")]
|
||||
*BGRX5551,
|
||||
#[cfg(target_endian = "little")]
|
||||
*ARGB1555,
|
||||
#[cfg(target_endian = "little")]
|
||||
*XRGB1555,
|
||||
#[cfg(target_endian = "little")]
|
||||
*ARGB2101010,
|
||||
#[cfg(target_endian = "little")]
|
||||
*XRGB2101010,
|
||||
#[cfg(target_endian = "little")]
|
||||
*ABGR2101010,
|
||||
#[cfg(target_endian = "little")]
|
||||
*XBGR2101010,
|
||||
#[cfg(target_endian = "little")]
|
||||
*ABGR16161616,
|
||||
#[cfg(target_endian = "little")]
|
||||
*XBGR16161616,
|
||||
#[cfg(target_endian = "little")]
|
||||
*ABGR16161616F,
|
||||
#[cfg(target_endian = "little")]
|
||||
*XBGR16161616F,
|
||||
#[cfg(target_endian = "little")]
|
||||
*BGR161616,
|
||||
#[cfg(target_endian = "little")]
|
||||
*R16F,
|
||||
#[cfg(target_endian = "little")]
|
||||
*GR1616F,
|
||||
#[cfg(target_endian = "little")]
|
||||
*BGR161616F,
|
||||
#[cfg(target_endian = "little")]
|
||||
*R32F,
|
||||
#[cfg(target_endian = "little")]
|
||||
*GR3232F,
|
||||
#[cfg(target_endian = "little")]
|
||||
*BGR323232F,
|
||||
#[cfg(target_endian = "little")]
|
||||
*ABGR32323232F,
|
||||
];
|
||||
pub use jay_formats::*;
|
||||
|
|
|
|||
|
|
@ -13,9 +13,6 @@ pub type GLuint = c::c_uint;
|
|||
|
||||
egl_transparent!(GLeglImageOES);
|
||||
|
||||
pub const GL_RGBA: GLint = 0x1908;
|
||||
pub const GL_RGBA8: GLenum = 0x8058;
|
||||
pub const GL_BGRA_EXT: GLint = 0x80E1;
|
||||
pub const GL_CLAMP_TO_EDGE: GLint = 0x812F;
|
||||
pub const GL_COLOR_ATTACHMENT0: GLenum = 0x8CE0;
|
||||
pub const GL_COLOR_BUFFER_BIT: GLbitfield = 0x00004000;
|
||||
|
|
@ -40,7 +37,6 @@ pub const GL_TEXTURE_WRAP_T: GLenum = 0x2803;
|
|||
pub const GL_TRIANGLE_STRIP: GLenum = 0x0005;
|
||||
pub const GL_TRIANGLES: GLenum = 0x0004;
|
||||
pub const GL_UNPACK_ROW_LENGTH_EXT: GLenum = 0x0CF2;
|
||||
pub const GL_UNSIGNED_BYTE: GLint = 0x1401;
|
||||
pub const GL_VERTEX_SHADER: GLenum = 0x8B31;
|
||||
pub const GL_BLEND: GLenum = 0x0BE2;
|
||||
pub const GL_ONE: GLenum = 1;
|
||||
|
|
|
|||
|
|
@ -2871,7 +2871,7 @@ impl ColorTransforms {
|
|||
mut color: Color,
|
||||
) -> Color {
|
||||
if let Some(ct) = self.get_or_create(src, dst, intent) {
|
||||
color = ct.matrix * color;
|
||||
color = apply_color_matrix(ct.matrix, color);
|
||||
};
|
||||
color
|
||||
}
|
||||
|
|
@ -2896,6 +2896,25 @@ impl ColorTransforms {
|
|||
}
|
||||
}
|
||||
|
||||
fn apply_color_matrix(matrix: ColorMatrix, color: Color) -> Color {
|
||||
let mut rgba = color.to_array(Eotf::Linear);
|
||||
let a = rgba[3];
|
||||
if a < 1.0 && a > 0.0 {
|
||||
for c in &mut rgba[..3] {
|
||||
*c /= a;
|
||||
}
|
||||
}
|
||||
let [r, g, b] = matrix * [rgba[0] as f64, rgba[1] as f64, rgba[2] as f64];
|
||||
Color::new(
|
||||
Eotf::Linear,
|
||||
AlphaMode::Straight,
|
||||
r as f32,
|
||||
g as f32,
|
||||
b as f32,
|
||||
a,
|
||||
)
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
struct EotfArgsCache {
|
||||
map: AHashMap<(EotfCacheKey, bool), EotfArg>,
|
||||
|
|
|
|||
|
|
@ -156,7 +156,8 @@ pub trait Global: GlobalBase {
|
|||
true
|
||||
}
|
||||
fn permitted(&self, caps: ClientCaps, xwayland: bool) -> bool {
|
||||
caps.contains(self.required_caps()) && (xwayland || !self.xwayland_only())
|
||||
let _ = caps;
|
||||
xwayland || !self.xwayland_only()
|
||||
}
|
||||
fn not_permitted(&self, caps: ClientCaps, xwayland: bool) -> bool {
|
||||
!self.permitted(caps, xwayland)
|
||||
|
|
@ -345,7 +346,7 @@ impl Globals {
|
|||
}
|
||||
|
||||
pub fn notify_all(&self, registry: &Rc<WlRegistry>) {
|
||||
let caps = registry.client.effective_caps.get();
|
||||
let caps = ClientCaps::all();
|
||||
let xwayland = registry.client.is_xwayland;
|
||||
let globals = self.registry.lock();
|
||||
macro_rules! emit {
|
||||
|
|
@ -429,7 +430,7 @@ impl Globals {
|
|||
}
|
||||
for client in state.clients.clients.borrow().values() {
|
||||
let client = &client.data;
|
||||
let caps = client.effective_caps.get();
|
||||
let caps = ClientCaps::all();
|
||||
let xwayland = client.is_xwayland;
|
||||
for global in &singletons {
|
||||
if global.permitted(caps, xwayland) {
|
||||
|
|
|
|||
|
|
@ -13,7 +13,6 @@ pub mod head_management;
|
|||
pub mod hyprland_focus_grab_manager_v1;
|
||||
pub mod hyprland_focus_grab_v1;
|
||||
pub mod ipc;
|
||||
pub mod jay_acceptor_request;
|
||||
pub mod jay_client_query;
|
||||
pub mod jay_color_management;
|
||||
pub mod jay_compositor;
|
||||
|
|
|
|||
|
|
@ -1,60 +0,0 @@
|
|||
use {
|
||||
crate::{
|
||||
client::{Client, ClientError},
|
||||
leaks::Tracker,
|
||||
object::{Object, Version},
|
||||
utils::errorfmt::ErrorFmt,
|
||||
wire::{JayAcceptorRequestId, jay_acceptor_request::*},
|
||||
},
|
||||
std::{error::Error, rc::Rc},
|
||||
thiserror::Error,
|
||||
};
|
||||
|
||||
pub struct JayAcceptorRequest {
|
||||
pub id: JayAcceptorRequestId,
|
||||
pub client: Rc<Client>,
|
||||
pub tracker: Tracker<Self>,
|
||||
pub version: Version,
|
||||
}
|
||||
|
||||
impl JayAcceptorRequest {
|
||||
pub fn send_done(&self, name: &str) {
|
||||
self.client.event(Done {
|
||||
self_id: self.id,
|
||||
name,
|
||||
});
|
||||
}
|
||||
|
||||
pub fn send_failed(&self, err: impl Error) {
|
||||
let msg = &ErrorFmt(err).to_string();
|
||||
self.client.event(Failed {
|
||||
self_id: self.id,
|
||||
msg,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
impl JayAcceptorRequestRequestHandler for JayAcceptorRequest {
|
||||
type Error = JayAcceptorRequestError;
|
||||
|
||||
fn destroy(&self, _req: Destroy, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||
self.client.remove_obj(self)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
object_base! {
|
||||
self = JayAcceptorRequest;
|
||||
version = self.version;
|
||||
}
|
||||
|
||||
impl Object for JayAcceptorRequest {}
|
||||
|
||||
simple_add_obj!(JayAcceptorRequest);
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum JayAcceptorRequestError {
|
||||
#[error(transparent)]
|
||||
ClientError(Box<ClientError>),
|
||||
}
|
||||
efrom!(JayAcceptorRequestError, ClientError);
|
||||
|
|
@ -9,7 +9,7 @@ use {
|
|||
jay_client_query::{
|
||||
AddAll, AddId, Comm, Destroy, Done, End, Exe, Execute, IsXwayland,
|
||||
JayClientQueryRequestHandler, Pid, SandboxAppId, SandboxEngine, SandboxInstanceId,
|
||||
Sandboxed, Start, Tag, Uid,
|
||||
Sandboxed, Start, Uid,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
@ -26,8 +26,6 @@ pub struct JayClientQuery {
|
|||
all: Cell<bool>,
|
||||
}
|
||||
|
||||
const TAG_SINCE: Version = Version(25);
|
||||
|
||||
impl JayClientQuery {
|
||||
pub fn new(client: &Rc<Client>, id: JayClientQueryId, version: Version) -> Self {
|
||||
Self {
|
||||
|
|
@ -97,14 +95,6 @@ impl JayClientQueryRequestHandler for JayClientQuery {
|
|||
instance_id,
|
||||
});
|
||||
}
|
||||
if self.version >= TAG_SINCE
|
||||
&& let Some(tag) = &client.acceptor.tag
|
||||
{
|
||||
self.client.event(Tag {
|
||||
self_id: self.id,
|
||||
tag,
|
||||
});
|
||||
}
|
||||
self.client.event(End { self_id: self.id });
|
||||
};
|
||||
if self.all.get() {
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@ use {
|
|||
compositor::LogLevel,
|
||||
globals::{Global, GlobalName},
|
||||
ifs::{
|
||||
jay_acceptor_request::JayAcceptorRequest,
|
||||
jay_client_query::JayClientQuery,
|
||||
jay_color_management::JayColorManagement,
|
||||
jay_ei_session_builder::JayEiSessionBuilder,
|
||||
|
|
@ -503,27 +502,6 @@ impl JayCompositorRequestHandler for JayCompositor {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn get_tagged_acceptor(
|
||||
&self,
|
||||
req: GetTaggedAcceptor<'_>,
|
||||
_slf: &Rc<Self>,
|
||||
) -> Result<(), Self::Error> {
|
||||
let obj = Rc::new(JayAcceptorRequest {
|
||||
id: req.id,
|
||||
client: self.client.clone(),
|
||||
tracker: Default::default(),
|
||||
version: self.version,
|
||||
});
|
||||
track!(self.client, obj);
|
||||
self.client.add_client_obj(&obj)?;
|
||||
let state = &self.client.state;
|
||||
match state.tagged_acceptors.get(state, req.tag) {
|
||||
Ok(d) => obj.send_done(&d),
|
||||
Err(e) => obj.send_failed(e),
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn get_sync_file_surface(
|
||||
&self,
|
||||
req: GetSyncFileSurface,
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue