Fix niri compatibility, add versioned niri-ipc dependencies
Using multiple niri-ipc versions need an ugly workaround where we vendor and re-publish old versions to crates.io See deps/README.md Fixes issue: https://github.com/gergo-salyi/multibg-wayland/issues/16
This commit is contained in:
parent
620219e18e
commit
9005a99289
13 changed files with 2192 additions and 12 deletions
17
Cargo.lock
generated
17
Cargo.lock
generated
|
@ -640,6 +640,7 @@ dependencies = [
|
|||
"image",
|
||||
"libc",
|
||||
"log",
|
||||
"multibg-wayland-niri-ipc",
|
||||
"niri-ipc",
|
||||
"rustix",
|
||||
"scopeguard",
|
||||
|
@ -650,10 +651,20 @@ dependencies = [
|
|||
]
|
||||
|
||||
[[package]]
|
||||
name = "niri-ipc"
|
||||
version = "25.2.0"
|
||||
name = "multibg-wayland-niri-ipc"
|
||||
version = "0.250200.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "01515d0a7e73f1f3bd0347100542c4c3f6ebc280688add12e7ed2af4c35af4fb"
|
||||
checksum = "57a296f0c9e420f45cc2671130f99e9291c99c644934ad948c8a2f34e75ba368"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"serde_json",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "niri-ipc"
|
||||
version = "25.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dc3e165f7854b2f83054a2e8f7024baa49666ad25cdb95b8fb9fd17c48045605"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"serde_json",
|
||||
|
|
|
@ -11,7 +11,7 @@ repository = "https://github.com/gergo-salyi/multibg-wayland"
|
|||
license = "MIT OR Apache-2.0"
|
||||
keywords = ["wallpaper", "background", "desktop", "wayland", "sway"]
|
||||
categories = ["command-line-utilities", "multimedia::images"]
|
||||
exclude = ["/PKGBUILD", "/PKGBUILD.in", "/scripts/"]
|
||||
exclude = ["/PKGBUILD", "/PKGBUILD.in", "/deps/", "/scripts/"]
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1.0.97"
|
||||
|
@ -21,7 +21,8 @@ env_logger = "0.11.3"
|
|||
fast_image_resize = "5.0.0"
|
||||
libc = "0.2.171"
|
||||
log = "0.4.21"
|
||||
niri-ipc = "=25.2.0"
|
||||
niri-ipc-25-2-0 = { package = "multibg-wayland-niri-ipc", version = "=0.250200.0" }
|
||||
niri-ipc-25-5-1 = { package = "niri-ipc", version = "=25.5.1" }
|
||||
rustix = { version = "0.38.44", features = ["event", "fs", "pipe"] }
|
||||
scopeguard = "1.2.0"
|
||||
serde = { version = "1.0.219", features = ["derive"] }
|
||||
|
|
|
@ -119,6 +119,8 @@ If using the --gpu option also consider installing Vulkan validation layers from
|
|||
|
||||
## License
|
||||
|
||||
Source files in this project are distributed under MIT OR Apache-2.0
|
||||
Source files in this project (except vendored dependencies under `deps/`) are distributed under MIT OR Apache-2.0.
|
||||
|
||||
Vendored dependencies under `deps/` are distributed under their respective licenses.
|
||||
|
||||
Objects resulting from building this project might be under GPL-3.0-or-later due to licenses of statically linked dependencies. Open an issue if you need compile time features gating such dependencies.
|
||||
|
|
41
deps/README.md
vendored
Normal file
41
deps/README.md
vendored
Normal file
|
@ -0,0 +1,41 @@
|
|||
# Vendored dependencies
|
||||
|
||||
We need to use multiple versions of the `niri-ipc` crate dependency to maintain compatibility with multiple version of niri. Ideally we would do this:
|
||||
|
||||
```toml
|
||||
# Cargo.toml
|
||||
[dependencies]
|
||||
niri-ipc-25-2-0 = { package = "niri-ipc", version = "=25.2.0" }
|
||||
niri-ipc-25-5-1 = { package = "niri-ipc", version = "=25.5.1" }
|
||||
```
|
||||
|
||||
However for some braindamaged reasons `cargo` refuses to allow this if any of the multiple versions are semver compatible (see [cargo issue](https://github.com/rust-lang/cargo/issues/12787))
|
||||
|
||||
So we do a disgusting workaround here where we vendor older versions of the `niri-ipc` crate and re-publish them on crates.io under the name `multibg-wayland-niri-ipc` with semver incompatible versions e.g. `"25.2.0"` => `"0.250200.0"`
|
||||
|
||||
## License
|
||||
|
||||
Vendored dependencies are included here under their respective licenses
|
||||
|
||||
## Workflow
|
||||
|
||||
Example:
|
||||
|
||||
Download the crate:
|
||||
```sh
|
||||
curl --fail --proto '=https' --tlsv1.2 https://static.crates.io/crates/niri-ipc/niri-ipc-25.2.0.crate | tar -xz
|
||||
```
|
||||
|
||||
Remove crates.io artifacts:
|
||||
```sh
|
||||
rm -f .cargo_vcs_info.json Cargo.toml.orig
|
||||
```
|
||||
|
||||
Edit `Cargo.toml`:
|
||||
- `name = "niri-ipc"` => `name = "multibg-wayland-niri-ipc"`
|
||||
- `version = "25.2.0"` => `version = "0.250200.0"`
|
||||
|
||||
Re-publish:
|
||||
```sh
|
||||
cargo publish
|
||||
```
|
338
deps/niri-ipc-25.2.0/Cargo.lock
generated
vendored
Normal file
338
deps/niri-ipc-25.2.0/Cargo.lock
generated
vendored
Normal file
|
@ -0,0 +1,338 @@
|
|||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 4
|
||||
|
||||
[[package]]
|
||||
name = "anstream"
|
||||
version = "0.6.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b"
|
||||
dependencies = [
|
||||
"anstyle",
|
||||
"anstyle-parse",
|
||||
"anstyle-query",
|
||||
"anstyle-wincon",
|
||||
"colorchoice",
|
||||
"is_terminal_polyfill",
|
||||
"utf8parse",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstyle"
|
||||
version = "1.0.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9"
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-parse"
|
||||
version = "0.2.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9"
|
||||
dependencies = [
|
||||
"utf8parse",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-query"
|
||||
version = "1.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c"
|
||||
dependencies = [
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-wincon"
|
||||
version = "3.0.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ca3534e77181a9cc07539ad51f2141fe32f6c3ffd4df76db8ad92346b003ae4e"
|
||||
dependencies = [
|
||||
"anstyle",
|
||||
"once_cell",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "4.5.30"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "92b7b18d71fad5313a1e320fa9897994228ce274b60faa4d694fe0ea89cd9e6d"
|
||||
dependencies = [
|
||||
"clap_builder",
|
||||
"clap_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_builder"
|
||||
version = "4.5.30"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a35db2071778a7344791a4fb4f95308b5673d219dee3ae348b86642574ecc90c"
|
||||
dependencies = [
|
||||
"anstream",
|
||||
"anstyle",
|
||||
"clap_lex",
|
||||
"strsim",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_derive"
|
||||
version = "4.5.28"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bf4ced95c6f4a675af3da73304b9ac4ed991640c36374e4b46795c49e17cf1ed"
|
||||
dependencies = [
|
||||
"heck",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_lex"
|
||||
version = "0.7.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6"
|
||||
|
||||
[[package]]
|
||||
name = "colorchoice"
|
||||
version = "1.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990"
|
||||
|
||||
[[package]]
|
||||
name = "dyn-clone"
|
||||
version = "1.0.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "feeef44e73baff3a26d371801df019877a9866a8c493d315ab00177843314f35"
|
||||
|
||||
[[package]]
|
||||
name = "heck"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
|
||||
|
||||
[[package]]
|
||||
name = "is_terminal_polyfill"
|
||||
version = "1.70.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf"
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "1.0.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674"
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.7.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
|
||||
|
||||
[[package]]
|
||||
name = "multibg-wayland-niri-ipc"
|
||||
version = "0.250200.0"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"schemars",
|
||||
"serde",
|
||||
"serde_json",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.20.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "945462a4b81e43c4e3ba96bd7b49d834c6f61198356aa858733bc4acf3cbe62e"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.93"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "60946a68e5f9d28b0dc1c21bb8a97ee7d018a8b322fa57838ba31cc878e22d99"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.38"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ryu"
|
||||
version = "1.0.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6ea1a2d0a644769cc99faa24c3ad26b379b786fe7c36fd3c546254801650e6dd"
|
||||
|
||||
[[package]]
|
||||
name = "schemars"
|
||||
version = "0.8.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "09c024468a378b7e36765cd36702b7a90cc3cba11654f6685c8f233408e89e92"
|
||||
dependencies = [
|
||||
"dyn-clone",
|
||||
"schemars_derive",
|
||||
"serde",
|
||||
"serde_json",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "schemars_derive"
|
||||
version = "0.8.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b1eee588578aff73f856ab961cd2f79e36bc45d7ded33a7562adba4667aecc0e"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"serde_derive_internals",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.218"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e8dfc9d19bdbf6d17e22319da49161d5d0108e4188e8b680aef6299eed22df60"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.218"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f09503e191f4e797cb8aac08e9a4a4695c5edf6a2e70e376d961ddd5c969f82b"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive_internals"
|
||||
version = "0.29.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.139"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "44f86c3acccc9c65b153fe1b85a3be07fe5515274ec9f0653b4a0875731c72a6"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"memchr",
|
||||
"ryu",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "strsim"
|
||||
version = "0.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.98"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "36147f1a48ae0ec2b5b3bc5b537d267457555a10dc06f3dbc8cb11ba3006d3b1"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "00e2473a93778eb0bad35909dff6a10d28e63f792f16ed15e404fca9d5eeedbe"
|
||||
|
||||
[[package]]
|
||||
name = "utf8parse"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.59.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
|
||||
dependencies = [
|
||||
"windows-targets",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-targets"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
|
||||
dependencies = [
|
||||
"windows_aarch64_gnullvm",
|
||||
"windows_aarch64_msvc",
|
||||
"windows_i686_gnu",
|
||||
"windows_i686_gnullvm",
|
||||
"windows_i686_msvc",
|
||||
"windows_x86_64_gnu",
|
||||
"windows_x86_64_gnullvm",
|
||||
"windows_x86_64_msvc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_gnullvm"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnullvm"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnullvm"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
|
55
deps/niri-ipc-25.2.0/Cargo.toml
vendored
Normal file
55
deps/niri-ipc-25.2.0/Cargo.toml
vendored
Normal file
|
@ -0,0 +1,55 @@
|
|||
# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
|
||||
#
|
||||
# When uploading crates to the registry Cargo will automatically
|
||||
# "normalize" Cargo.toml files for maximal compatibility
|
||||
# with all versions of Cargo and also rewrite `path` dependencies
|
||||
# to registry (e.g., crates.io) dependencies.
|
||||
#
|
||||
# If you are reading this file be aware that the original Cargo.toml
|
||||
# will likely look very different (and much more reasonable).
|
||||
# See Cargo.toml.orig for the original contents.
|
||||
|
||||
[package]
|
||||
edition = "2021"
|
||||
name = "multibg-wayland-niri-ipc" # name = "niri-ipc"
|
||||
version = "0.250200.0" # version = "25.2.0"
|
||||
authors = ["Ivan Molodetskikh <yalterz@gmail.com>"]
|
||||
build = false
|
||||
autolib = false
|
||||
autobins = false
|
||||
autoexamples = false
|
||||
autotests = false
|
||||
autobenches = false
|
||||
description = "Types and helpers for interfacing with the niri Wayland compositor."
|
||||
readme = "README.md"
|
||||
keywords = ["wayland"]
|
||||
categories = [
|
||||
"api-bindings",
|
||||
"os",
|
||||
]
|
||||
license = "GPL-3.0-or-later"
|
||||
repository = "https://github.com/YaLTeR/niri"
|
||||
|
||||
[features]
|
||||
clap = ["dep:clap"]
|
||||
json-schema = ["dep:schemars"]
|
||||
|
||||
[lib]
|
||||
name = "niri_ipc"
|
||||
path = "src/lib.rs"
|
||||
|
||||
[dependencies.clap]
|
||||
version = "4.5.30"
|
||||
features = ["derive"]
|
||||
optional = true
|
||||
|
||||
[dependencies.schemars]
|
||||
version = "0.8.21"
|
||||
optional = true
|
||||
|
||||
[dependencies.serde]
|
||||
version = "1.0.218"
|
||||
features = ["derive"]
|
||||
|
||||
[dependencies.serde_json]
|
||||
version = "1.0.139"
|
16
deps/niri-ipc-25.2.0/README.md
vendored
Normal file
16
deps/niri-ipc-25.2.0/README.md
vendored
Normal file
|
@ -0,0 +1,16 @@
|
|||
# niri-ipc
|
||||
|
||||
Types and helpers for interfacing with the [niri](https://github.com/YaLTeR/niri) Wayland compositor.
|
||||
|
||||
## Backwards compatibility
|
||||
|
||||
This crate follows the niri version.
|
||||
It is **not** API-stable in terms of the Rust semver.
|
||||
In particular, expect new struct fields and enum variants to be added in patch version bumps.
|
||||
|
||||
Use an exact version requirement to avoid breaking changes:
|
||||
|
||||
```toml
|
||||
[dependencies]
|
||||
niri-ipc = "=25.2.0"
|
||||
```
|
1308
deps/niri-ipc-25.2.0/src/lib.rs
vendored
Normal file
1308
deps/niri-ipc-25.2.0/src/lib.rs
vendored
Normal file
File diff suppressed because it is too large
Load diff
77
deps/niri-ipc-25.2.0/src/socket.rs
vendored
Normal file
77
deps/niri-ipc-25.2.0/src/socket.rs
vendored
Normal file
|
@ -0,0 +1,77 @@
|
|||
//! Helper for blocking communication over the niri socket.
|
||||
|
||||
use std::env;
|
||||
use std::io::{self, BufRead, BufReader, Write};
|
||||
use std::net::Shutdown;
|
||||
use std::os::unix::net::UnixStream;
|
||||
use std::path::Path;
|
||||
|
||||
use crate::{Event, Reply, Request};
|
||||
|
||||
/// Name of the environment variable containing the niri IPC socket path.
|
||||
pub const SOCKET_PATH_ENV: &str = "NIRI_SOCKET";
|
||||
|
||||
/// Helper for blocking communication over the niri socket.
|
||||
///
|
||||
/// This struct is used to communicate with the niri IPC server. It handles the socket connection
|
||||
/// and serialization/deserialization of messages.
|
||||
pub struct Socket {
|
||||
stream: UnixStream,
|
||||
}
|
||||
|
||||
impl Socket {
|
||||
/// Connects to the default niri IPC socket.
|
||||
///
|
||||
/// This is equivalent to calling [`Self::connect_to`] with the path taken from the
|
||||
/// [`SOCKET_PATH_ENV`] environment variable.
|
||||
pub fn connect() -> io::Result<Self> {
|
||||
let socket_path = env::var_os(SOCKET_PATH_ENV).ok_or_else(|| {
|
||||
io::Error::new(
|
||||
io::ErrorKind::NotFound,
|
||||
format!("{SOCKET_PATH_ENV} is not set, are you running this within niri?"),
|
||||
)
|
||||
})?;
|
||||
Self::connect_to(socket_path)
|
||||
}
|
||||
|
||||
/// Connects to the niri IPC socket at the given path.
|
||||
pub fn connect_to(path: impl AsRef<Path>) -> io::Result<Self> {
|
||||
let stream = UnixStream::connect(path.as_ref())?;
|
||||
Ok(Self { stream })
|
||||
}
|
||||
|
||||
/// Sends a request to niri and returns the response.
|
||||
///
|
||||
/// Return values:
|
||||
///
|
||||
/// * `Ok(Ok(response))`: successful [`Response`](crate::Response) from niri
|
||||
/// * `Ok(Err(message))`: error message from niri
|
||||
/// * `Err(error)`: error communicating with niri
|
||||
///
|
||||
/// This method also returns a blocking function that you can call to keep reading [`Event`]s
|
||||
/// after requesting an [`EventStream`][Request::EventStream]. This function is not useful
|
||||
/// otherwise.
|
||||
pub fn send(self, request: Request) -> io::Result<(Reply, impl FnMut() -> io::Result<Event>)> {
|
||||
let Self { mut stream } = self;
|
||||
|
||||
let mut buf = serde_json::to_string(&request).unwrap();
|
||||
stream.write_all(buf.as_bytes())?;
|
||||
stream.shutdown(Shutdown::Write)?;
|
||||
|
||||
let mut reader = BufReader::new(stream);
|
||||
|
||||
buf.clear();
|
||||
reader.read_line(&mut buf)?;
|
||||
|
||||
let reply = serde_json::from_str(&buf)?;
|
||||
|
||||
let events = move || {
|
||||
buf.clear();
|
||||
reader.read_line(&mut buf)?;
|
||||
let event = serde_json::from_str(&buf)?;
|
||||
Ok(event)
|
||||
};
|
||||
|
||||
Ok((reply, events))
|
||||
}
|
||||
}
|
194
deps/niri-ipc-25.2.0/src/state.rs
vendored
Normal file
194
deps/niri-ipc-25.2.0/src/state.rs
vendored
Normal file
|
@ -0,0 +1,194 @@
|
|||
//! Helpers for keeping track of the event stream state.
|
||||
//!
|
||||
//! 1. Create an [`EventStreamState`] using `Default::default()`, or any individual state part if
|
||||
//! you only care about part of the state.
|
||||
//! 2. Connect to the niri socket and request an event stream.
|
||||
//! 3. Pass every [`Event`] to [`EventStreamStatePart::apply`] on your state.
|
||||
//! 4. Read the fields of the state as needed.
|
||||
|
||||
use std::collections::hash_map::Entry;
|
||||
use std::collections::HashMap;
|
||||
|
||||
use crate::{Event, KeyboardLayouts, Window, Workspace};
|
||||
|
||||
/// Part of the state communicated via the event stream.
|
||||
pub trait EventStreamStatePart {
|
||||
/// Returns a sequence of events that replicates this state from default initialization.
|
||||
fn replicate(&self) -> Vec<Event>;
|
||||
|
||||
/// Applies the event to this state.
|
||||
///
|
||||
/// Returns `None` after applying the event, and `Some(event)` if the event is ignored by this
|
||||
/// part of the state.
|
||||
fn apply(&mut self, event: Event) -> Option<Event>;
|
||||
}
|
||||
|
||||
/// The full state communicated over the event stream.
|
||||
///
|
||||
/// Different parts of the state are not guaranteed to be consistent across every single event
|
||||
/// sent by niri. For example, you may receive the first [`Event::WindowOpenedOrChanged`] for a
|
||||
/// just-opened window *after* an [`Event::WorkspaceActiveWindowChanged`] for that window. Between
|
||||
/// these two events, the workspace active window id refers to a window that does not yet exist in
|
||||
/// the windows state part.
|
||||
#[derive(Debug, Default)]
|
||||
pub struct EventStreamState {
|
||||
/// State of workspaces.
|
||||
pub workspaces: WorkspacesState,
|
||||
|
||||
/// State of workspaces.
|
||||
pub windows: WindowsState,
|
||||
|
||||
/// State of the keyboard layouts.
|
||||
pub keyboard_layouts: KeyboardLayoutsState,
|
||||
}
|
||||
|
||||
/// The workspaces state communicated over the event stream.
|
||||
#[derive(Debug, Default)]
|
||||
pub struct WorkspacesState {
|
||||
/// Map from a workspace id to the workspace.
|
||||
pub workspaces: HashMap<u64, Workspace>,
|
||||
}
|
||||
|
||||
/// The windows state communicated over the event stream.
|
||||
#[derive(Debug, Default)]
|
||||
pub struct WindowsState {
|
||||
/// Map from a window id to the window.
|
||||
pub windows: HashMap<u64, Window>,
|
||||
}
|
||||
|
||||
/// The keyboard layout state communicated over the event stream.
|
||||
#[derive(Debug, Default)]
|
||||
pub struct KeyboardLayoutsState {
|
||||
/// Configured keyboard layouts.
|
||||
pub keyboard_layouts: Option<KeyboardLayouts>,
|
||||
}
|
||||
|
||||
impl EventStreamStatePart for EventStreamState {
|
||||
fn replicate(&self) -> Vec<Event> {
|
||||
let mut events = Vec::new();
|
||||
events.extend(self.workspaces.replicate());
|
||||
events.extend(self.windows.replicate());
|
||||
events.extend(self.keyboard_layouts.replicate());
|
||||
events
|
||||
}
|
||||
|
||||
fn apply(&mut self, event: Event) -> Option<Event> {
|
||||
let event = self.workspaces.apply(event)?;
|
||||
let event = self.windows.apply(event)?;
|
||||
let event = self.keyboard_layouts.apply(event)?;
|
||||
Some(event)
|
||||
}
|
||||
}
|
||||
|
||||
impl EventStreamStatePart for WorkspacesState {
|
||||
fn replicate(&self) -> Vec<Event> {
|
||||
let workspaces = self.workspaces.values().cloned().collect();
|
||||
vec![Event::WorkspacesChanged { workspaces }]
|
||||
}
|
||||
|
||||
fn apply(&mut self, event: Event) -> Option<Event> {
|
||||
match event {
|
||||
Event::WorkspacesChanged { workspaces } => {
|
||||
self.workspaces = workspaces.into_iter().map(|ws| (ws.id, ws)).collect();
|
||||
}
|
||||
Event::WorkspaceActivated { id, focused } => {
|
||||
let ws = self.workspaces.get(&id);
|
||||
let ws = ws.expect("activated workspace was missing from the map");
|
||||
let output = ws.output.clone();
|
||||
|
||||
for ws in self.workspaces.values_mut() {
|
||||
let got_activated = ws.id == id;
|
||||
if ws.output == output {
|
||||
ws.is_active = got_activated;
|
||||
}
|
||||
|
||||
if focused {
|
||||
ws.is_focused = got_activated;
|
||||
}
|
||||
}
|
||||
}
|
||||
Event::WorkspaceActiveWindowChanged {
|
||||
workspace_id,
|
||||
active_window_id,
|
||||
} => {
|
||||
let ws = self.workspaces.get_mut(&workspace_id);
|
||||
let ws = ws.expect("changed workspace was missing from the map");
|
||||
ws.active_window_id = active_window_id;
|
||||
}
|
||||
event => return Some(event),
|
||||
}
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
impl EventStreamStatePart for WindowsState {
|
||||
fn replicate(&self) -> Vec<Event> {
|
||||
let windows = self.windows.values().cloned().collect();
|
||||
vec![Event::WindowsChanged { windows }]
|
||||
}
|
||||
|
||||
fn apply(&mut self, event: Event) -> Option<Event> {
|
||||
match event {
|
||||
Event::WindowsChanged { windows } => {
|
||||
self.windows = windows.into_iter().map(|win| (win.id, win)).collect();
|
||||
}
|
||||
Event::WindowOpenedOrChanged { window } => {
|
||||
let (id, is_focused) = match self.windows.entry(window.id) {
|
||||
Entry::Occupied(mut entry) => {
|
||||
let entry = entry.get_mut();
|
||||
*entry = window;
|
||||
(entry.id, entry.is_focused)
|
||||
}
|
||||
Entry::Vacant(entry) => {
|
||||
let entry = entry.insert(window);
|
||||
(entry.id, entry.is_focused)
|
||||
}
|
||||
};
|
||||
|
||||
if is_focused {
|
||||
for win in self.windows.values_mut() {
|
||||
if win.id != id {
|
||||
win.is_focused = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Event::WindowClosed { id } => {
|
||||
let win = self.windows.remove(&id);
|
||||
win.expect("closed window was missing from the map");
|
||||
}
|
||||
Event::WindowFocusChanged { id } => {
|
||||
for win in self.windows.values_mut() {
|
||||
win.is_focused = Some(win.id) == id;
|
||||
}
|
||||
}
|
||||
event => return Some(event),
|
||||
}
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
impl EventStreamStatePart for KeyboardLayoutsState {
|
||||
fn replicate(&self) -> Vec<Event> {
|
||||
if let Some(keyboard_layouts) = self.keyboard_layouts.clone() {
|
||||
vec![Event::KeyboardLayoutsChanged { keyboard_layouts }]
|
||||
} else {
|
||||
vec![]
|
||||
}
|
||||
}
|
||||
|
||||
fn apply(&mut self, event: Event) -> Option<Event> {
|
||||
match event {
|
||||
Event::KeyboardLayoutsChanged { keyboard_layouts } => {
|
||||
self.keyboard_layouts = Some(keyboard_layouts);
|
||||
}
|
||||
Event::KeyboardLayoutSwitched { idx } => {
|
||||
let kb = self.keyboard_layouts.as_mut();
|
||||
let kb = kb.expect("keyboard layouts must be set before a layout can be switched");
|
||||
kb.current_idx = idx;
|
||||
}
|
||||
event => return Some(event),
|
||||
}
|
||||
None
|
||||
}
|
||||
}
|
|
@ -1,14 +1,18 @@
|
|||
mod hyprland;
|
||||
mod niri;
|
||||
mod niri2502;
|
||||
mod niri2505;
|
||||
mod sway;
|
||||
|
||||
use std::{
|
||||
env,
|
||||
os::unix::ffi::OsStrExt,
|
||||
process::Command,
|
||||
sync::{mpsc::Sender, Arc},
|
||||
thread,
|
||||
};
|
||||
|
||||
use anyhow::{bail, Context};
|
||||
use serde::Deserialize;
|
||||
use log::{debug, warn};
|
||||
|
||||
use crate::poll::Waker;
|
||||
|
@ -116,7 +120,17 @@ impl ConnectionTask {
|
|||
Compositor::Hyprland => Box::new(
|
||||
hyprland::HyprlandConnectionTask::new()
|
||||
),
|
||||
Compositor::Niri => Box::new(niri::NiriConnectionTask::new()),
|
||||
Compositor::Niri => match get_niri_version() {
|
||||
Ok(niri_verison) => if niri_verison >= niri_ver(25, 5) {
|
||||
Box::new(niri2505::NiriConnectionTask::new())
|
||||
} else {
|
||||
Box::new(niri2502::NiriConnectionTask::new())
|
||||
},
|
||||
Err(e) => {
|
||||
warn!("Failed to get niri version: {e:#}");
|
||||
Box::new(niri2505::NiriConnectionTask::new())
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
ConnectionTask {
|
||||
|
@ -144,9 +158,19 @@ impl ConnectionTask {
|
|||
hyprland::HyprlandConnectionTask::new();
|
||||
composer_interface.subscribe_event_loop(event_sender);
|
||||
}
|
||||
Compositor::Niri => {
|
||||
let composer_interface = niri::NiriConnectionTask::new();
|
||||
composer_interface.subscribe_event_loop(event_sender);
|
||||
Compositor::Niri => match get_niri_version() {
|
||||
Ok(niri_verison) => if niri_verison >= niri_ver(25, 5) {
|
||||
niri2505::NiriConnectionTask::new()
|
||||
.subscribe_event_loop(event_sender)
|
||||
} else {
|
||||
niri2502::NiriConnectionTask::new()
|
||||
.subscribe_event_loop(event_sender)
|
||||
},
|
||||
Err(e) => {
|
||||
warn!("Failed to get niri version: {e:#}");
|
||||
niri2505::NiriConnectionTask::new()
|
||||
.subscribe_event_loop(event_sender)
|
||||
}
|
||||
}
|
||||
})
|
||||
.unwrap();
|
||||
|
@ -191,3 +215,39 @@ pub struct WorkspaceVisible {
|
|||
pub output: String,
|
||||
pub workspace_name: String,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct NiriVersionJson {
|
||||
compositor: String,
|
||||
}
|
||||
|
||||
// Example:
|
||||
// $ niri msg --json version
|
||||
// {"cli":"25.02 (unknown commit)","compositor":"25.02 (unknown commit)"}
|
||||
fn get_niri_version() -> anyhow::Result<u64> {
|
||||
let out = Command::new("niri")
|
||||
.args(["msg", "--json", "version"])
|
||||
.output().context("Command niri msg version failed")?;
|
||||
if !out.status.success() {
|
||||
bail!("Command niri msg version exited with {}: {}",
|
||||
out.status, String::from_utf8_lossy(&out.stderr));
|
||||
}
|
||||
let version_json: NiriVersionJson = serde_json::from_slice(&out.stdout)
|
||||
.context("Failed to deserialize niri msg version json")?;
|
||||
debug!("Niri version: {}", version_json.compositor);
|
||||
let version = parse_niri_version(&version_json.compositor)
|
||||
.context("Failed to parse niri version")?;
|
||||
Ok(version)
|
||||
}
|
||||
|
||||
fn parse_niri_version(version_str: &str) -> Option<u64> {
|
||||
// Example: "25.02 (unknown commit)"
|
||||
let mut iter = version_str.split(|c: char| !c.is_ascii_digit());
|
||||
let major = iter.next()?.parse::<u32>().ok()?;
|
||||
let minor = iter.next()?.parse::<u32>().ok()?;
|
||||
Some(niri_ver(major, minor))
|
||||
}
|
||||
|
||||
fn niri_ver(major: u32, minor: u32) -> u64 {
|
||||
((major as u64) << 32) | (minor as u64)
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use std::io;
|
||||
|
||||
use log::debug;
|
||||
use niri_ipc::{socket::Socket, Event, Request, Response, Workspace};
|
||||
use niri_ipc_25_2_0::{socket::Socket, Event, Request, Response, Workspace};
|
||||
|
||||
use super::{CompositorInterface, EventSender, WorkspaceVisible};
|
||||
|
77
src/compositors/niri2505.rs
Normal file
77
src/compositors/niri2505.rs
Normal file
|
@ -0,0 +1,77 @@
|
|||
use std::io;
|
||||
|
||||
use log::debug;
|
||||
use niri_ipc_25_5_1::{socket::Socket, Event, Request, Response, Workspace};
|
||||
|
||||
use super::{CompositorInterface, EventSender, WorkspaceVisible};
|
||||
|
||||
pub struct NiriConnectionTask {}
|
||||
|
||||
impl NiriConnectionTask {
|
||||
pub fn new() -> Self {
|
||||
NiriConnectionTask {}
|
||||
}
|
||||
}
|
||||
|
||||
impl CompositorInterface for NiriConnectionTask {
|
||||
fn request_visible_workspaces(&mut self) -> Vec<WorkspaceVisible> {
|
||||
request_workspaces().into_iter()
|
||||
.filter(|w| w.is_active)
|
||||
.map(|workspace| WorkspaceVisible {
|
||||
output: workspace.output.unwrap_or_default(),
|
||||
workspace_name: workspace.name
|
||||
.unwrap_or_else(|| format!("{}", workspace.idx)),
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn subscribe_event_loop(self, event_sender: EventSender) {
|
||||
let mut workspaces_state = request_workspaces();
|
||||
let mut callback = request_event_stream();
|
||||
while let Ok(event) = callback() {
|
||||
match event {
|
||||
Event::WorkspaceActivated { id, focused: _ } => {
|
||||
debug!("Niri event: workspace id {id} activated");
|
||||
let visible_workspace =
|
||||
find_workspace(&workspaces_state, id);
|
||||
event_sender.send(visible_workspace);
|
||||
},
|
||||
Event::WorkspacesChanged { workspaces } => {
|
||||
debug!("Niri event: workspaces changed: {workspaces:?}");
|
||||
workspaces_state = workspaces
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn find_workspace(workspaces: &[Workspace], id: u64) -> WorkspaceVisible {
|
||||
let workspace = workspaces.iter()
|
||||
.find(|workspace| workspace.id == id)
|
||||
.unwrap_or_else(|| panic!("Unknown niri workspace id {id}"));
|
||||
let workspace_name = workspace.name.clone()
|
||||
.unwrap_or_else(|| format!("{}", workspace.idx));
|
||||
let output = workspace.output.clone().unwrap_or_default();
|
||||
WorkspaceVisible { output, workspace_name }
|
||||
}
|
||||
|
||||
fn request_event_stream() -> impl FnMut() -> Result<Event, io::Error> {
|
||||
let mut socket = Socket::connect().expect("failed to connect to niri socket");
|
||||
let Ok(Ok(Response::Handled)) = socket.send(Request::EventStream) else {
|
||||
panic!("failed to subscribe to event stream");
|
||||
};
|
||||
socket.read_events()
|
||||
}
|
||||
|
||||
fn request_workspaces() -> Vec<Workspace> {
|
||||
let response = Socket::connect()
|
||||
.expect("failed to connect to niri socket")
|
||||
.send(Request::Workspaces)
|
||||
.expect("failed to send niri ipc request")
|
||||
.expect("niri workspace query failed");
|
||||
let Response::Workspaces(workspaces) = response else {
|
||||
panic!("unexpected response from niri");
|
||||
};
|
||||
workspaces
|
||||
}
|
Loading…
Add table
Reference in a new issue