mirror of
https://gitlab.com/gabmus/envision.git
synced 2025-08-02 14:18:49 +00:00
Merge branch 'feat/integrate-libmonado' into 'main'
feat: integrate libmonado See merge request gabmus/envision!13
This commit is contained in:
commit
356e1152e8
15 changed files with 784 additions and 248 deletions
|
@ -23,7 +23,11 @@ cargo:test:
|
||||||
- echo 'deb http://deb.debian.org/debian experimental main' > /etc/apt/sources.list.d/experimental.list
|
- echo 'deb http://deb.debian.org/debian experimental main' > /etc/apt/sources.list.d/experimental.list
|
||||||
- apt-get update
|
- apt-get update
|
||||||
- apt-get -t experimental install libgtk-4-dev libadwaita-1-dev libgtksourceview-5-dev libssl-dev -y
|
- apt-get -t experimental install libgtk-4-dev libadwaita-1-dev libgtksourceview-5-dev libssl-dev -y
|
||||||
- apt-get install rust-all cargo meson ninja-build git desktop-file-utils gettext libjxl-dev file libusb-dev libusb-1.0-0-dev -y
|
- apt-get install meson ninja-build git desktop-file-utils gettext libjxl-dev file libusb-dev libusb-1.0-0-dev curl -y
|
||||||
|
- curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs -o /tmp/rustup.sh
|
||||||
|
- chmod +x /tmp/rustup.sh
|
||||||
|
- /tmp/rustup.sh -y
|
||||||
|
- source "$HOME/.cargo/env"
|
||||||
- rustc --version && cargo --version # Print version info for debugging
|
- rustc --version && cargo --version # Print version info for debugging
|
||||||
- meson setup build -Dprefix="$PWD/build/localprefix" -Dprofile=development
|
- meson setup build -Dprefix="$PWD/build/localprefix" -Dprofile=development
|
||||||
- ninja -C build
|
- ninja -C build
|
||||||
|
@ -38,7 +42,11 @@ appimage:
|
||||||
- echo 'deb http://deb.debian.org/debian experimental main' > /etc/apt/sources.list.d/experimental.list
|
- echo 'deb http://deb.debian.org/debian experimental main' > /etc/apt/sources.list.d/experimental.list
|
||||||
- apt-get update
|
- apt-get update
|
||||||
- apt-get -t experimental install libgtk-4-dev libadwaita-1-dev libgtksourceview-5-dev libssl-dev -y
|
- apt-get -t experimental install libgtk-4-dev libadwaita-1-dev libgtksourceview-5-dev libssl-dev -y
|
||||||
- apt-get install rust-all cargo meson ninja-build git desktop-file-utils gettext libjxl-dev file libusb-dev libusb-1.0-0-dev -y
|
- apt-get install meson ninja-build git desktop-file-utils gettext libjxl-dev file libusb-dev libusb-1.0-0-dev curl -y
|
||||||
|
- curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs -o /tmp/rustup.sh
|
||||||
|
- chmod +x /tmp/rustup.sh
|
||||||
|
- /tmp/rustup.sh -y
|
||||||
|
- source "$HOME/.cargo/env"
|
||||||
- bash ./dist/appimage/build_appimage.sh
|
- bash ./dist/appimage/build_appimage.sh
|
||||||
artifacts:
|
artifacts:
|
||||||
paths:
|
paths:
|
||||||
|
|
204
Cargo.lock
generated
204
Cargo.lock
generated
|
@ -70,6 +70,29 @@ version = "0.21.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9ba43ea6f343b788c8764558649e08df62f86c6ef251fdaeb1ffd010a9ae50a2"
|
checksum = "9ba43ea6f343b788c8764558649e08df62f86c6ef251fdaeb1ffd010a9ae50a2"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bindgen"
|
||||||
|
version = "0.68.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "726e4313eb6ec35d2730258ad4e15b547ee75d6afaa1361a922e78e59b7d8078"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags 2.4.0",
|
||||||
|
"cexpr",
|
||||||
|
"clang-sys",
|
||||||
|
"lazy_static",
|
||||||
|
"lazycell",
|
||||||
|
"log",
|
||||||
|
"peeking_take_while",
|
||||||
|
"prettyplease",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"regex",
|
||||||
|
"rustc-hash",
|
||||||
|
"shlex",
|
||||||
|
"syn 2.0.33",
|
||||||
|
"which",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bit-set"
|
name = "bit-set"
|
||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
|
@ -150,6 +173,15 @@ dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cexpr"
|
||||||
|
version = "0.6.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766"
|
||||||
|
dependencies = [
|
||||||
|
"nom",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cfg-expr"
|
name = "cfg-expr"
|
||||||
version = "0.15.5"
|
version = "0.15.5"
|
||||||
|
@ -166,6 +198,35 @@ version = "1.0.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "clang-sys"
|
||||||
|
version = "1.6.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c688fc74432808e3eb684cae8830a86be1d66a2bd58e1f248ed0960a590baf6f"
|
||||||
|
dependencies = [
|
||||||
|
"glob",
|
||||||
|
"libc",
|
||||||
|
"libloading",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cmake"
|
||||||
|
version = "0.1.50"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a31c789563b815f77f4250caee12365734369f942439b7defd71e18a48197130"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "convert_case"
|
||||||
|
version = "0.6.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ec182b0ca2f35d8fc196cf3404988fd8b8c739a4d270ff118a398feb0cbec1ca"
|
||||||
|
dependencies = [
|
||||||
|
"unicode-segmentation",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "core-foundation"
|
name = "core-foundation"
|
||||||
version = "0.9.3"
|
version = "0.9.3"
|
||||||
|
@ -182,6 +243,35 @@ version = "0.8.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa"
|
checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "dlopen2"
|
||||||
|
version = "0.6.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6bc2c7ed06fd72a8513ded8d0d2f6fd2655a85d6885c48cae8625d80faf28c03"
|
||||||
|
dependencies = [
|
||||||
|
"dlopen2_derive",
|
||||||
|
"libc",
|
||||||
|
"once_cell",
|
||||||
|
"winapi",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "dlopen2_derive"
|
||||||
|
version = "0.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f2b99bf03862d7f545ebc28ddd33a665b50865f4dfd84031a393823879bd4c54"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 2.0.33",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "either"
|
||||||
|
version = "1.9.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "encoding_rs"
|
name = "encoding_rs"
|
||||||
version = "0.8.33"
|
version = "0.8.33"
|
||||||
|
@ -199,7 +289,9 @@ dependencies = [
|
||||||
"gettext-rs",
|
"gettext-rs",
|
||||||
"git2",
|
"git2",
|
||||||
"gtk4",
|
"gtk4",
|
||||||
|
"lazy_static",
|
||||||
"libadwaita",
|
"libadwaita",
|
||||||
|
"libmonado-rs",
|
||||||
"libusb",
|
"libusb",
|
||||||
"nix",
|
"nix",
|
||||||
"phf",
|
"phf",
|
||||||
|
@ -257,6 +349,12 @@ dependencies = [
|
||||||
"rustc_version",
|
"rustc_version",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "flagset"
|
||||||
|
version = "0.4.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d52a7e408202050813e6f1d9addadcaafef3dca7530c7ddfb005d4081cce6779"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "flume"
|
name = "flume"
|
||||||
version = "0.11.0"
|
version = "0.11.0"
|
||||||
|
@ -585,6 +683,12 @@ dependencies = [
|
||||||
"system-deps",
|
"system-deps",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "glob"
|
||||||
|
version = "0.3.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "gobject-sys"
|
name = "gobject-sys"
|
||||||
version = "0.18.0"
|
version = "0.18.0"
|
||||||
|
@ -747,6 +851,15 @@ version = "0.3.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "443144c8cdadd93ebf52ddb4056d257f5b52c04d3c804e657d19eb73fc33668b"
|
checksum = "443144c8cdadd93ebf52ddb4056d257f5b52c04d3c804e657d19eb73fc33668b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "home"
|
||||||
|
version = "0.5.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5444c27eef6923071f7ebcc33e3444508466a76f7a2b93da00ed6e19f30c1ddb"
|
||||||
|
dependencies = [
|
||||||
|
"windows-sys",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "http"
|
name = "http"
|
||||||
version = "0.2.9"
|
version = "0.2.9"
|
||||||
|
@ -884,6 +997,12 @@ version = "1.4.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "lazycell"
|
||||||
|
version = "1.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libadwaita"
|
name = "libadwaita"
|
||||||
version = "0.5.2"
|
version = "0.5.2"
|
||||||
|
@ -936,6 +1055,29 @@ dependencies = [
|
||||||
"pkg-config",
|
"pkg-config",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libloading"
|
||||||
|
version = "0.7.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"winapi",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libmonado-rs"
|
||||||
|
version = "0.1.0"
|
||||||
|
source = "git+https://github.com/technobaboo/libmonado-rs#3b3f098cb131843ee90f078e26362fcefe02b822"
|
||||||
|
dependencies = [
|
||||||
|
"bindgen",
|
||||||
|
"cmake",
|
||||||
|
"convert_case",
|
||||||
|
"dlopen2",
|
||||||
|
"flagset",
|
||||||
|
"semver",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libssh2-sys"
|
name = "libssh2-sys"
|
||||||
version = "0.3.0"
|
version = "0.3.0"
|
||||||
|
@ -1057,6 +1199,12 @@ version = "0.3.17"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a"
|
checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "minimal-lexical"
|
||||||
|
version = "0.2.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "miniz_oxide"
|
name = "miniz_oxide"
|
||||||
version = "0.7.1"
|
version = "0.7.1"
|
||||||
|
@ -1117,6 +1265,16 @@ dependencies = [
|
||||||
"pin-utils",
|
"pin-utils",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "nom"
|
||||||
|
version = "7.1.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a"
|
||||||
|
dependencies = [
|
||||||
|
"memchr",
|
||||||
|
"minimal-lexical",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "num_cpus"
|
name = "num_cpus"
|
||||||
version = "1.16.0"
|
version = "1.16.0"
|
||||||
|
@ -1240,6 +1398,12 @@ dependencies = [
|
||||||
"system-deps",
|
"system-deps",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "peeking_take_while"
|
||||||
|
version = "0.1.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "percent-encoding"
|
name = "percent-encoding"
|
||||||
version = "2.3.0"
|
version = "2.3.0"
|
||||||
|
@ -1311,6 +1475,16 @@ version = "0.2.17"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
|
checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "prettyplease"
|
||||||
|
version = "0.2.15"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ae005bd773ab59b4725093fd7df83fd7892f7d8eafb48dbd7de6e024e4215f9d"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"syn 2.0.33",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proc-macro-crate"
|
name = "proc-macro-crate"
|
||||||
version = "1.3.1"
|
version = "1.3.1"
|
||||||
|
@ -1514,6 +1688,12 @@ version = "0.1.23"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76"
|
checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rustc-hash"
|
||||||
|
version = "1.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustc_version"
|
name = "rustc_version"
|
||||||
version = "0.4.0"
|
version = "0.4.0"
|
||||||
|
@ -1638,6 +1818,12 @@ dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "shlex"
|
||||||
|
version = "1.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a7cee0529a6d40f580e7a5e6c495c8fbfe21b7b52795ed4bb5e62cdf92bc6380"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "siphasher"
|
name = "siphasher"
|
||||||
version = "0.3.11"
|
version = "0.3.11"
|
||||||
|
@ -1977,6 +2163,12 @@ dependencies = [
|
||||||
"tinyvec",
|
"tinyvec",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unicode-segmentation"
|
||||||
|
version = "1.10.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "url"
|
name = "url"
|
||||||
version = "2.4.1"
|
version = "2.4.1"
|
||||||
|
@ -2107,6 +2299,18 @@ dependencies = [
|
||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "which"
|
||||||
|
version = "4.4.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7"
|
||||||
|
dependencies = [
|
||||||
|
"either",
|
||||||
|
"home",
|
||||||
|
"once_cell",
|
||||||
|
"rustix",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "winapi"
|
name = "winapi"
|
||||||
version = "0.3.9"
|
version = "0.3.9"
|
||||||
|
|
|
@ -14,9 +14,11 @@ git2 = "0.17.2"
|
||||||
gtk4 = { version = "0.7.2", features = [
|
gtk4 = { version = "0.7.2", features = [
|
||||||
"v4_10",
|
"v4_10",
|
||||||
] }
|
] }
|
||||||
|
lazy_static = "1.4.0"
|
||||||
libadwaita = { version = "0.5.2", features = [
|
libadwaita = { version = "0.5.2", features = [
|
||||||
"v1_3"
|
"v1_3"
|
||||||
] }
|
] }
|
||||||
|
libmonado-rs = { git = "https://github.com/technobaboo/libmonado-rs", version = "0.1.0" }
|
||||||
libusb = "0.3.0"
|
libusb = "0.3.0"
|
||||||
nix = { version = "0.26.4", features = [
|
nix = { version = "0.26.4", features = [
|
||||||
"fs"
|
"fs"
|
||||||
|
|
|
@ -33,6 +33,12 @@ cd envision
|
||||||
./dist/appimage/build_appimage.sh
|
./dist/appimage/build_appimage.sh
|
||||||
```
|
```
|
||||||
|
|
||||||
|
# Feature flags
|
||||||
|
|
||||||
|
|Env var|Values|Default|
|
||||||
|
|---|---|---|
|
||||||
|
|`ENVISION_FF_USE_LIBMONADO`|`1`: enabled; `0`: disabled|`0`|
|
||||||
|
|
||||||
# Common issues
|
# Common issues
|
||||||
|
|
||||||
## NOSUID with systemd-homed
|
## NOSUID with systemd-homed
|
||||||
|
|
|
@ -30,6 +30,7 @@ pub mod func_runner;
|
||||||
pub mod gpu_profile;
|
pub mod gpu_profile;
|
||||||
pub mod log_level;
|
pub mod log_level;
|
||||||
pub mod log_parser;
|
pub mod log_parser;
|
||||||
|
pub mod monado_utils;
|
||||||
pub mod paths;
|
pub mod paths;
|
||||||
pub mod profile;
|
pub mod profile;
|
||||||
pub mod profiles;
|
pub mod profiles;
|
||||||
|
|
11
src/monado_utils.rs
Normal file
11
src/monado_utils.rs
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
use crate::profile::Profile;
|
||||||
|
|
||||||
|
pub fn get_devs(prof: &Profile) {
|
||||||
|
if let Ok(monado) = libmonado_rs::Monado::create(prof.libmonado_so().unwrap()) {
|
||||||
|
if let Ok(devs) = monado.devices() {
|
||||||
|
for dev in devs {
|
||||||
|
println!(">>> {}", dev.name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -350,6 +350,23 @@ impl Profile {
|
||||||
pub fn can_start(&self) -> bool {
|
pub fn can_start(&self) -> bool {
|
||||||
Path::new(&self.xrservice_binary()).is_file()
|
Path::new(&self.xrservice_binary()).is_file()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn libmonado_so(&self) -> Option<String> {
|
||||||
|
let mut res = format!("{}/lib/libmonado.so", self.prefix);
|
||||||
|
if Path::new(&res).is_file() {
|
||||||
|
return Some(res);
|
||||||
|
}
|
||||||
|
res = format!("{}/lib64/libmonado.so", self.prefix);
|
||||||
|
if Path::new(&res).is_file() {
|
||||||
|
return Some(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn has_libmonado(&self) -> bool {
|
||||||
|
self.libmonado_so().is_some()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|
|
@ -3,6 +3,7 @@ use super::alert::alert;
|
||||||
use super::build_window::{BuildStatus, BuildWindow};
|
use super::build_window::{BuildStatus, BuildWindow};
|
||||||
use super::debug_view::{DebugView, DebugViewMsg};
|
use super::debug_view::{DebugView, DebugViewMsg};
|
||||||
use super::fbt_config_editor::{FbtConfigEditor, FbtConfigEditorInit, FbtConfigEditorMsg};
|
use super::fbt_config_editor::{FbtConfigEditor, FbtConfigEditorInit, FbtConfigEditorMsg};
|
||||||
|
use super::feature_flags::FF_LIBMONADO_DEVICE_ENUMERATION_ENABLED;
|
||||||
use super::job_worker::internal_worker::JobWorkerOut;
|
use super::job_worker::internal_worker::JobWorkerOut;
|
||||||
use super::job_worker::job::WorkerJob;
|
use super::job_worker::job::WorkerJob;
|
||||||
use super::job_worker::JobWorker;
|
use super::job_worker::JobWorker;
|
||||||
|
@ -43,7 +44,7 @@ use crate::ui::build_window::{BuildWindowMsg, BuildWindowOutMsg};
|
||||||
use crate::ui::debug_view::DebugViewInit;
|
use crate::ui::debug_view::DebugViewInit;
|
||||||
use crate::ui::libsurvive_setup_window::LibsurviveSetupMsg;
|
use crate::ui::libsurvive_setup_window::LibsurviveSetupMsg;
|
||||||
use crate::ui::main_view::{MainView, MainViewInit, MainViewOutMsg};
|
use crate::ui::main_view::{MainView, MainViewInit, MainViewOutMsg};
|
||||||
use crate::xr_devices::XRDevices;
|
use crate::xr_devices::XRDevice;
|
||||||
use crate::{stateless_action, withclones};
|
use crate::{stateless_action, withclones};
|
||||||
use gtk::prelude::*;
|
use gtk::prelude::*;
|
||||||
use relm4::actions::{AccelsPlus, ActionGroupName, RelmAction, RelmActionGroup};
|
use relm4::actions::{AccelsPlus, ActionGroupName, RelmAction, RelmActionGroup};
|
||||||
|
@ -91,9 +92,11 @@ pub struct App {
|
||||||
#[tracker::do_not_track]
|
#[tracker::do_not_track]
|
||||||
profiles: Vec<Profile>,
|
profiles: Vec<Profile>,
|
||||||
#[tracker::do_not_track]
|
#[tracker::do_not_track]
|
||||||
xr_devices: XRDevices,
|
xr_devices: Vec<XRDevice>,
|
||||||
#[tracker::do_not_track]
|
#[tracker::do_not_track]
|
||||||
fbt_config_editor: Option<Controller<FbtConfigEditor>>,
|
fbt_config_editor: Option<Controller<FbtConfigEditor>>,
|
||||||
|
#[tracker::do_not_track]
|
||||||
|
libmonado: Option<libmonado_rs::Monado>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -162,7 +165,7 @@ impl App {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
self.debug_view.sender().emit(DebugViewMsg::ClearLog);
|
self.debug_view.sender().emit(DebugViewMsg::ClearLog);
|
||||||
self.xr_devices = XRDevices::default();
|
self.xr_devices = vec![];
|
||||||
if prof.can_start() {
|
if prof.can_start() {
|
||||||
remove_file(&get_ipc_file_path(&prof.xrservice_type))
|
remove_file(&get_ipc_file_path(&prof.xrservice_type))
|
||||||
.is_err()
|
.is_err()
|
||||||
|
@ -218,11 +221,12 @@ impl App {
|
||||||
if let Some(worker) = self.xrservice_worker.as_ref() {
|
if let Some(worker) = self.xrservice_worker.as_ref() {
|
||||||
worker.stop();
|
worker.stop();
|
||||||
}
|
}
|
||||||
|
self.libmonado = None;
|
||||||
self.restore_openxr_openvr_files();
|
self.restore_openxr_openvr_files();
|
||||||
self.main_view
|
self.main_view
|
||||||
.sender()
|
.sender()
|
||||||
.emit(MainViewMsg::XRServiceActiveChanged(false, None));
|
.emit(MainViewMsg::XRServiceActiveChanged(false, None));
|
||||||
self.xr_devices = XRDevices::default();
|
self.xr_devices = vec![];
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn profiles_list(config: &Config) -> Vec<Profile> {
|
pub fn profiles_list(config: &Config) -> Vec<Profile> {
|
||||||
|
@ -309,26 +313,49 @@ impl SimpleComponent for App {
|
||||||
}
|
}
|
||||||
Msg::ClockTicking => {
|
Msg::ClockTicking => {
|
||||||
self.main_view.sender().emit(MainViewMsg::ClockTicking);
|
self.main_view.sender().emit(MainViewMsg::ClockTicking);
|
||||||
|
if *FF_LIBMONADO_DEVICE_ENUMERATION_ENABLED {
|
||||||
|
if let Some(w) = self.xrservice_worker.as_ref() {
|
||||||
|
if {
|
||||||
|
let state = w.state.lock().unwrap();
|
||||||
|
state.exit_status.is_none() && !state.stop_requested
|
||||||
|
} {
|
||||||
|
if let Some(monado) = self.libmonado.as_ref() {
|
||||||
|
self.xr_devices = XRDevice::merge(
|
||||||
|
&self.xr_devices,
|
||||||
|
&XRDevice::from_libmonado(monado),
|
||||||
|
);
|
||||||
|
self.main_view
|
||||||
|
.sender()
|
||||||
|
.emit(MainViewMsg::UpdateDevices(self.xr_devices.clone()));
|
||||||
|
} else {
|
||||||
|
if let Some(so) = self.get_selected_profile().libmonado_so() {
|
||||||
|
self.libmonado = libmonado_rs::Monado::create(so).ok();
|
||||||
|
if self.libmonado.is_some() {
|
||||||
|
sender.input(Msg::ClockTicking);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Msg::ParseLog(rows) => {
|
Msg::ParseLog(rows) => {
|
||||||
for row in rows {
|
for row in rows {
|
||||||
match MonadoLog::new_from_str(row.as_str()) {
|
match MonadoLog::new_from_str(row.as_str()) {
|
||||||
None => {}
|
None => {}
|
||||||
Some(parsed) => {
|
Some(parsed) => {
|
||||||
if parsed.func == "p_create_system" {
|
if !*FF_LIBMONADO_DEVICE_ENUMERATION_ENABLED
|
||||||
match XRDevices::from_log_message(parsed.message.as_str()) {
|
&& parsed.func == "p_create_system"
|
||||||
None => {}
|
{
|
||||||
Some(devices) => {
|
let n_devs = XRDevice::from_log_message(parsed.message.as_str());
|
||||||
self.xr_devices.merge(devices.clone());
|
self.xr_devices = XRDevice::merge(&self.xr_devices, &n_devs);
|
||||||
self.main_view.sender().emit(MainViewMsg::UpdateDevices(
|
self.main_view
|
||||||
Some(self.xr_devices.clone()),
|
.sender()
|
||||||
));
|
.emit(MainViewMsg::UpdateDevices(self.xr_devices.clone()));
|
||||||
break;
|
} else if let Some(tracker) =
|
||||||
}
|
XRDevice::generic_tracker_from_log_row(parsed.message.as_str())
|
||||||
};
|
{
|
||||||
} else {
|
self.xr_devices.push(tracker);
|
||||||
self.xr_devices
|
|
||||||
.search_log_for_generic_trackers(parsed.message.as_str());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -364,7 +391,7 @@ impl SimpleComponent for App {
|
||||||
self.start_xrservice(sender);
|
self.start_xrservice(sender);
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
worker.stop();
|
self.shutdown_xrservice();
|
||||||
self.restart_xrservice = true;
|
self.restart_xrservice = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -643,9 +670,10 @@ impl SimpleComponent for App {
|
||||||
profiles,
|
profiles,
|
||||||
xrservice_worker: None,
|
xrservice_worker: None,
|
||||||
build_worker: None,
|
build_worker: None,
|
||||||
xr_devices: XRDevices::default(),
|
xr_devices: vec![],
|
||||||
fbt_config_editor: None,
|
fbt_config_editor: None,
|
||||||
restart_xrservice: false,
|
restart_xrservice: false,
|
||||||
|
libmonado: None,
|
||||||
};
|
};
|
||||||
let widgets = view_output!();
|
let widgets = view_output!();
|
||||||
|
|
||||||
|
|
|
@ -1,48 +1,43 @@
|
||||||
|
use super::{
|
||||||
|
alert::alert,
|
||||||
|
factories::device_row_factory::{DeviceRowModel, DeviceRowModelInit, DeviceRowState},
|
||||||
|
};
|
||||||
use crate::{
|
use crate::{
|
||||||
file_builders::monado_config_v0::dump_generic_trackers,
|
file_builders::monado_config_v0::dump_generic_trackers,
|
||||||
xr_devices::{XRDevice, XRDevices},
|
xr_devices::{XRDevice, XRDeviceType},
|
||||||
};
|
};
|
||||||
use adw::prelude::*;
|
use adw::prelude::*;
|
||||||
use relm4::prelude::*;
|
use relm4::{factory::FactoryVecDeque, prelude::*, Sender};
|
||||||
|
|
||||||
use super::alert::alert;
|
|
||||||
|
|
||||||
#[tracker::track]
|
#[tracker::track]
|
||||||
pub struct DevicesBox {
|
pub struct DevicesBox {
|
||||||
devices: Option<XRDevices>,
|
devices: Vec<XRDevice>,
|
||||||
|
|
||||||
|
#[tracker::do_not_track]
|
||||||
|
device_rows: FactoryVecDeque<DeviceRowModel>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum DevicesBoxMsg {
|
pub enum DevicesBoxMsg {
|
||||||
UpdateDevices(Option<XRDevices>),
|
UpdateDevices(Vec<XRDevice>),
|
||||||
DumpGenericTrackers,
|
DumpGenericTrackers,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DevicesBox {
|
impl DevicesBox {
|
||||||
fn get_dev(&self, key: XRDevice) -> Option<String> {
|
fn create_save_trackers_btn(sender: Sender<DevicesBoxMsg>) -> gtk::Button {
|
||||||
match &self.devices {
|
let btn = gtk::Button::builder()
|
||||||
None => None,
|
.halign(gtk::Align::Center)
|
||||||
Some(devs) => match key {
|
.valign(gtk::Align::Center)
|
||||||
XRDevice::Head => devs.head.clone(),
|
.icon_name("document-save-symbolic")
|
||||||
XRDevice::Left => devs.left.clone(),
|
.tooltip_text("Save current trackers")
|
||||||
XRDevice::Right => devs.right.clone(),
|
.css_classes(["circular", "flat"])
|
||||||
XRDevice::Gamepad => devs.gamepad.clone(),
|
.build();
|
||||||
XRDevice::Eyes => devs.eyes.clone(),
|
|
||||||
XRDevice::HandTrackingLeft => devs.hand_tracking_left.clone(),
|
|
||||||
XRDevice::HandTrackingRight => devs.hand_tracking_right.clone(),
|
|
||||||
XRDevice::GenericTracker => {
|
|
||||||
if devs.generic_trackers.is_empty() {
|
|
||||||
return None;
|
|
||||||
} else {
|
|
||||||
return Some(devs.generic_trackers.join(", "));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_dev_or_none(&self, key: XRDevice) -> String {
|
btn.connect_clicked(move |_| {
|
||||||
self.get_dev(key).unwrap_or("None".into())
|
sender.emit(DevicesBoxMsg::DumpGenericTrackers);
|
||||||
|
});
|
||||||
|
|
||||||
|
btn
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -60,159 +55,151 @@ impl SimpleComponent for DevicesBox {
|
||||||
set_spacing: 12,
|
set_spacing: 12,
|
||||||
set_margin_top: 12,
|
set_margin_top: 12,
|
||||||
#[track = "model.changed(Self::devices())"]
|
#[track = "model.changed(Self::devices())"]
|
||||||
set_visible: model.devices.is_some(),
|
set_visible: !model.devices.is_empty(),
|
||||||
gtk::ListBox {
|
|
||||||
add_css_class: "boxed-list",
|
append: &devices_listbox,
|
||||||
set_selection_mode: gtk::SelectionMode::None,
|
|
||||||
set_margin_all: 12,
|
|
||||||
// Head
|
|
||||||
adw::ActionRow {
|
|
||||||
#[track = "model.changed(Self::devices())"]
|
|
||||||
set_icon_name: Some(match model.get_dev(XRDevice::Head) {
|
|
||||||
Some(name) => match name.as_str() {
|
|
||||||
"Simulated HMD" => "dialog-warning-symbolic",
|
|
||||||
_ => "emblem-ok-symbolic",
|
|
||||||
},
|
|
||||||
None => "dialog-question-symbolic",
|
|
||||||
}),
|
|
||||||
#[track = "model.changed(Self::devices())"]
|
|
||||||
set_class_active: ("error", model.get_dev(XRDevice::Head).is_none()),
|
|
||||||
#[track = "model.changed(Self::devices())"]
|
|
||||||
set_class_active: ("warning", model.get_dev_or_none(XRDevice::Head) == "Simulated HMD"),
|
|
||||||
set_title: "Head",
|
|
||||||
#[track = "model.changed(Self::devices())"]
|
|
||||||
set_subtitle: match model.get_dev_or_none(XRDevice::Head).as_str() {
|
|
||||||
"Simulated HMD" => "No HMD detected (Simulated HMD)",
|
|
||||||
s => s,
|
|
||||||
},
|
|
||||||
// TODO: status icon with popover
|
|
||||||
},
|
|
||||||
// Left
|
|
||||||
adw::ActionRow {
|
|
||||||
#[track = "model.changed(Self::devices())"]
|
|
||||||
set_icon_name: Some(match model.get_dev(XRDevice::Left) {
|
|
||||||
Some(_) => "emblem-ok-symbolic",
|
|
||||||
None => "dialog-question-symbolic",
|
|
||||||
}),
|
|
||||||
#[track = "model.changed(Self::devices())"]
|
|
||||||
set_class_active: ("error", model.get_dev(XRDevice::Left).is_none()),
|
|
||||||
set_title: "Left",
|
|
||||||
#[track = "model.changed(Self::devices())"]
|
|
||||||
set_subtitle: model.get_dev_or_none(XRDevice::Left).as_str(),
|
|
||||||
// TODO: status icon with popover
|
|
||||||
},
|
|
||||||
// Right
|
|
||||||
adw::ActionRow {
|
|
||||||
#[track = "model.changed(Self::devices())"]
|
|
||||||
set_icon_name: Some(match model.get_dev(XRDevice::Right) {
|
|
||||||
Some(_) => "emblem-ok-symbolic",
|
|
||||||
None => "dialog-question-symbolic",
|
|
||||||
}),
|
|
||||||
#[track = "model.changed(Self::devices())"]
|
|
||||||
set_class_active: ("error", model.get_dev(XRDevice::Right).is_none()),
|
|
||||||
set_title: "Right",
|
|
||||||
#[track = "model.changed(Self::devices())"]
|
|
||||||
set_subtitle: model.get_dev_or_none(XRDevice::Right).as_str(),
|
|
||||||
// TODO: status icon with popover
|
|
||||||
},
|
|
||||||
// Gamepad
|
|
||||||
adw::ActionRow {
|
|
||||||
#[track = "model.changed(Self::devices())"]
|
|
||||||
set_visible: model.get_dev(XRDevice::Gamepad).is_some(),
|
|
||||||
set_icon_name: Some("emblem-ok-symbolic"),
|
|
||||||
set_title: "Gamepad",
|
|
||||||
#[track = "model.changed(Self::devices())"]
|
|
||||||
set_subtitle: model.get_dev_or_none(XRDevice::Gamepad).as_str(),
|
|
||||||
},
|
|
||||||
// Eyes
|
|
||||||
adw::ActionRow {
|
|
||||||
#[track = "model.changed(Self::devices())"]
|
|
||||||
set_visible: model.get_dev(XRDevice::Eyes).is_some(),
|
|
||||||
set_icon_name: Some("emblem-ok-symbolic"),
|
|
||||||
set_title: "Eye Tracking",
|
|
||||||
#[track = "model.changed(Self::devices())"]
|
|
||||||
set_subtitle: model.get_dev_or_none(XRDevice::Eyes).as_str(),
|
|
||||||
},
|
|
||||||
// Hand Tracking Left
|
|
||||||
adw::ActionRow {
|
|
||||||
#[track = "model.changed(Self::devices())"]
|
|
||||||
set_visible: model.get_dev(XRDevice::HandTrackingLeft).is_some(),
|
|
||||||
set_icon_name: Some("emblem-ok-symbolic"),
|
|
||||||
set_title: "Hand Tracking Left",
|
|
||||||
#[track = "model.changed(Self::devices())"]
|
|
||||||
set_subtitle: model.get_dev_or_none(XRDevice::HandTrackingLeft).as_str(),
|
|
||||||
},
|
|
||||||
// Hand Tracking Right
|
|
||||||
adw::ActionRow {
|
|
||||||
#[track = "model.changed(Self::devices())"]
|
|
||||||
set_visible: model.get_dev(XRDevice::HandTrackingRight).is_some(),
|
|
||||||
set_icon_name: Some("emblem-ok-symbolic"),
|
|
||||||
set_title: "Hand Tracking Right",
|
|
||||||
#[track = "model.changed(Self::devices())"]
|
|
||||||
set_subtitle: model.get_dev_or_none(XRDevice::HandTrackingRight).as_str(),
|
|
||||||
},
|
|
||||||
// Generic Trackers
|
|
||||||
adw::ActionRow {
|
|
||||||
#[track = "model.changed(Self::devices())"]
|
|
||||||
set_visible: model.get_dev(XRDevice::GenericTracker).is_some(),
|
|
||||||
set_icon_name: Some("emblem-ok-symbolic"),
|
|
||||||
set_title: "Generic Trackers",
|
|
||||||
#[track = "model.changed(Self::devices())"]
|
|
||||||
set_subtitle: model.get_dev_or_none(XRDevice::GenericTracker).as_str(),
|
|
||||||
add_suffix: save_trackers_btn = >k::Button {
|
|
||||||
set_halign: gtk::Align::Center,
|
|
||||||
set_valign: gtk::Align::Center,
|
|
||||||
set_icon_name: "document-save-symbolic",
|
|
||||||
set_tooltip_text: Some("Save current trackers"),
|
|
||||||
set_css_classes: &["circular", "flat"],
|
|
||||||
connect_clicked => move |_| {
|
|
||||||
sender.input(Self::Input::DumpGenericTrackers);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update(&mut self, message: Self::Input, _sender: ComponentSender<Self>) {
|
fn update(&mut self, message: Self::Input, sender: ComponentSender<Self>) {
|
||||||
self.reset();
|
self.reset();
|
||||||
|
|
||||||
match message {
|
match message {
|
||||||
Self::Input::UpdateDevices(devs) => {
|
Self::Input::UpdateDevices(devs) => {
|
||||||
self.set_devices(devs);
|
self.set_devices(devs);
|
||||||
|
let mut guard = self.device_rows.guard();
|
||||||
|
guard.clear();
|
||||||
|
if !self.devices.is_empty() {
|
||||||
|
let mut has_head = false;
|
||||||
|
let mut has_left = false;
|
||||||
|
let mut has_right = false;
|
||||||
|
let mut models: Vec<DeviceRowModelInit> = vec![];
|
||||||
|
let mut generic: Vec<&XRDevice> = vec![];
|
||||||
|
for dev in &self.devices {
|
||||||
|
match dev.dev_type {
|
||||||
|
XRDeviceType::Head => {
|
||||||
|
has_head = true;
|
||||||
|
let mut init = DeviceRowModelInit::from_xr_device(&dev);
|
||||||
|
if dev.name == "Simulated HMD" {
|
||||||
|
init.state = Some(DeviceRowState::Warning);
|
||||||
|
init.subtitle = Some("No HMD detected (Simulated HMD)".into());
|
||||||
|
}
|
||||||
|
models.push(init);
|
||||||
|
}
|
||||||
|
XRDeviceType::Left => {
|
||||||
|
has_left = true;
|
||||||
|
models.push(DeviceRowModelInit::from_xr_device(&dev));
|
||||||
|
}
|
||||||
|
XRDeviceType::Right => {
|
||||||
|
has_right = true;
|
||||||
|
models.push(DeviceRowModelInit::from_xr_device(&dev));
|
||||||
|
}
|
||||||
|
XRDeviceType::GenericTracker => {
|
||||||
|
generic.push(dev);
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
models.push(DeviceRowModelInit::from_xr_device(&dev));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if !generic.is_empty() {
|
||||||
|
models.push(DeviceRowModelInit {
|
||||||
|
title: Some(XRDeviceType::GenericTracker.to_string()),
|
||||||
|
subtitle: Some(
|
||||||
|
generic
|
||||||
|
.iter()
|
||||||
|
.map(|d| d.id.as_str())
|
||||||
|
.collect::<Vec<&str>>()
|
||||||
|
.join(", "),
|
||||||
|
),
|
||||||
|
suffix: Some(
|
||||||
|
Self::create_save_trackers_btn(sender.input_sender().clone())
|
||||||
|
.upcast::<gtk::Widget>(),
|
||||||
|
),
|
||||||
|
..Default::default()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if !has_right {
|
||||||
|
models.push(DeviceRowModelInit::new_missing(XRDeviceType::Right));
|
||||||
|
}
|
||||||
|
if !has_left {
|
||||||
|
models.push(DeviceRowModelInit::new_missing(XRDeviceType::Left));
|
||||||
|
}
|
||||||
|
if !has_head {
|
||||||
|
models.push(DeviceRowModelInit::new_missing(XRDeviceType::Head));
|
||||||
|
}
|
||||||
|
|
||||||
|
models.sort_by(|m1, m2| {
|
||||||
|
let dt1 = XRDeviceType::from_display_str(
|
||||||
|
m1.title.as_ref().unwrap_or(&String::new()),
|
||||||
|
);
|
||||||
|
let dt2 = XRDeviceType::from_display_str(
|
||||||
|
m2.title.as_ref().unwrap_or(&String::new()),
|
||||||
|
);
|
||||||
|
dt1.cmp(&dt2)
|
||||||
|
});
|
||||||
|
|
||||||
|
for model in models {
|
||||||
|
guard.push_back(model);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Self::Input::DumpGenericTrackers => {
|
Self::Input::DumpGenericTrackers => {
|
||||||
if let Some(devs) = self.devices.as_ref() {
|
let added = dump_generic_trackers(
|
||||||
let added = dump_generic_trackers(&devs.generic_trackers);
|
&self
|
||||||
|
.devices
|
||||||
|
.iter()
|
||||||
|
.filter(|d| d.dev_type == XRDeviceType::GenericTracker)
|
||||||
|
.map(|d| d.id.clone())
|
||||||
|
.collect::<Vec<String>>(),
|
||||||
|
);
|
||||||
let multi_title = format!("Added {} new trackers", added);
|
let multi_title = format!("Added {} new trackers", added);
|
||||||
let (title, msg) = match added {
|
let (title, msg) = match added {
|
||||||
0 => (
|
0 => (
|
||||||
"No new trackers found",
|
"No new trackers found",
|
||||||
"All the currently connected trackers are already present in your configuration"
|
concat!(
|
||||||
|
"All the currently connected trackers ",
|
||||||
|
"are already present in your configuration"
|
||||||
|
),
|
||||||
),
|
),
|
||||||
1 => (
|
1 => (
|
||||||
"Added 1 new tracker",
|
"Added 1 new tracker",
|
||||||
"Edit your configuration to make sure that all the trackers have the appropriate roles assigned"
|
concat!(
|
||||||
|
"Edit your configuration to make sure that ",
|
||||||
|
"all the trackers have the appropriate roles assigned"
|
||||||
|
),
|
||||||
),
|
),
|
||||||
_ => (
|
_ => (
|
||||||
multi_title.as_str(),
|
multi_title.as_str(),
|
||||||
"Edit your configuration to make sure that all the trackers have the appropriate roles assigned"
|
concat!(
|
||||||
|
"Edit your configuration to make sure that ",
|
||||||
|
"all the trackers have the appropriate roles assigned"
|
||||||
|
),
|
||||||
),
|
),
|
||||||
};
|
};
|
||||||
alert(title, Some(msg), None);
|
alert(title, Some(msg), None);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
fn init(
|
fn init(
|
||||||
_init: Self::Init,
|
_init: Self::Init,
|
||||||
root: &Self::Root,
|
root: &Self::Root,
|
||||||
sender: ComponentSender<Self>,
|
sender: ComponentSender<Self>,
|
||||||
) -> ComponentParts<Self> {
|
) -> ComponentParts<Self> {
|
||||||
|
let devices_listbox = gtk::ListBox::builder()
|
||||||
|
.css_classes(["boxed-list"])
|
||||||
|
.selection_mode(gtk::SelectionMode::None)
|
||||||
|
.margin_start(12)
|
||||||
|
.margin_end(12)
|
||||||
|
.margin_top(12)
|
||||||
|
.margin_bottom(12)
|
||||||
|
.build();
|
||||||
|
|
||||||
let model = Self {
|
let model = Self {
|
||||||
tracker: 0,
|
tracker: 0,
|
||||||
devices: None,
|
devices: vec![],
|
||||||
|
device_rows: FactoryVecDeque::new(devices_listbox.clone(), sender.input_sender()),
|
||||||
};
|
};
|
||||||
|
|
||||||
let widgets = view_output!();
|
let widgets = view_output!();
|
||||||
|
|
124
src/ui/factories/device_row_factory.rs
Normal file
124
src/ui/factories/device_row_factory.rs
Normal file
|
@ -0,0 +1,124 @@
|
||||||
|
use adw::prelude::*;
|
||||||
|
use relm4::prelude::*;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
ui::devices_box::DevicesBoxMsg,
|
||||||
|
xr_devices::{XRDevice, XRDeviceType},
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
|
pub enum DeviceRowState {
|
||||||
|
Ok,
|
||||||
|
Error,
|
||||||
|
Warning,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for DeviceRowState {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::Ok
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DeviceRowState {
|
||||||
|
pub fn icon(&self) -> &str {
|
||||||
|
match &self {
|
||||||
|
Self::Ok => "emblem-ok-symbolic",
|
||||||
|
Self::Error => "dialog-question-symbolic",
|
||||||
|
Self::Warning => "dialog-warning-symbolic",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn class_name(&self) -> Option<&str> {
|
||||||
|
match &self {
|
||||||
|
Self::Ok => None,
|
||||||
|
Self::Error => Some("error"),
|
||||||
|
Self::Warning => Some("warning"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct DeviceRowModel {
|
||||||
|
title: String,
|
||||||
|
subtitle: String,
|
||||||
|
state: DeviceRowState,
|
||||||
|
suffix: Option<gtk::Widget>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Default)]
|
||||||
|
pub struct DeviceRowModelInit {
|
||||||
|
pub title: Option<String>,
|
||||||
|
pub subtitle: Option<String>,
|
||||||
|
pub state: Option<DeviceRowState>,
|
||||||
|
pub suffix: Option<gtk::Widget>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DeviceRowModelInit {
|
||||||
|
pub fn from_xr_device(d: &XRDevice) -> Self {
|
||||||
|
Self {
|
||||||
|
title: Some(d.dev_type.to_string()),
|
||||||
|
subtitle: Some(d.name.clone()),
|
||||||
|
..Default::default()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new_missing(t: XRDeviceType) -> Self {
|
||||||
|
DeviceRowModelInit {
|
||||||
|
title: Some(t.to_string()),
|
||||||
|
subtitle: Some("None".into()),
|
||||||
|
state: Some(DeviceRowState::Error),
|
||||||
|
..Default::default()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[relm4::factory(pub)]
|
||||||
|
impl FactoryComponent for DeviceRowModel {
|
||||||
|
type Init = DeviceRowModelInit;
|
||||||
|
type Input = ();
|
||||||
|
type Output = ();
|
||||||
|
type CommandOutput = ();
|
||||||
|
type Widgets = DeviceRowModelWidgets;
|
||||||
|
type ParentInput = DevicesBoxMsg;
|
||||||
|
type ParentWidget = gtk::ListBox;
|
||||||
|
|
||||||
|
view! {
|
||||||
|
root = adw::ActionRow {
|
||||||
|
// TODO: replace with flat button that spawns popover
|
||||||
|
add_prefix: icon = >k::Image {
|
||||||
|
set_icon_name: Some(self.state.icon()),
|
||||||
|
},
|
||||||
|
set_title: self.title.as_str(),
|
||||||
|
set_subtitle: self.subtitle.as_str(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn init_widgets(
|
||||||
|
&mut self,
|
||||||
|
_index: &Self::Index,
|
||||||
|
root: &Self::Root,
|
||||||
|
_returned_widget: &<Self::ParentWidget as relm4::factory::FactoryView>::ReturnedWidget,
|
||||||
|
_sender: FactorySender<Self>,
|
||||||
|
) -> Self::Widgets {
|
||||||
|
let widgets = view_output!();
|
||||||
|
|
||||||
|
if let Some(suffix) = self.suffix.as_ref() {
|
||||||
|
widgets.root.add_suffix(suffix);
|
||||||
|
}
|
||||||
|
if let Some(cls) = self.state.class_name() {
|
||||||
|
widgets.root.add_css_class(cls);
|
||||||
|
widgets.icon.add_css_class(cls);
|
||||||
|
}
|
||||||
|
|
||||||
|
widgets
|
||||||
|
}
|
||||||
|
|
||||||
|
fn init_model(init: Self::Init, _index: &Self::Index, _sender: FactorySender<Self>) -> Self {
|
||||||
|
Self {
|
||||||
|
title: init.title.unwrap_or_default(),
|
||||||
|
subtitle: init.subtitle.unwrap_or_default(),
|
||||||
|
state: init.state.unwrap_or_default(),
|
||||||
|
suffix: init.suffix,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,2 +1,3 @@
|
||||||
|
pub mod device_row_factory;
|
||||||
pub mod env_var_row_factory;
|
pub mod env_var_row_factory;
|
||||||
pub mod tracker_role_group_factory;
|
pub mod tracker_role_group_factory;
|
||||||
|
|
11
src/ui/feature_flags.rs
Normal file
11
src/ui/feature_flags.rs
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
use lazy_static::lazy_static;
|
||||||
|
use std::env;
|
||||||
|
|
||||||
|
fn get_ff_libmonado_device_enumeration_enabled() -> bool {
|
||||||
|
env::var("ENVISION_FF_USE_LIBMONADO").unwrap_or_default() == "1"
|
||||||
|
}
|
||||||
|
|
||||||
|
lazy_static! {
|
||||||
|
pub static ref FF_LIBMONADO_DEVICE_ENUMERATION_ENABLED: bool =
|
||||||
|
get_ff_libmonado_device_enumeration_enabled();
|
||||||
|
}
|
|
@ -18,7 +18,7 @@ use crate::ui::app::{
|
||||||
};
|
};
|
||||||
use crate::ui::profile_editor::ProfileEditorInit;
|
use crate::ui::profile_editor::ProfileEditorInit;
|
||||||
use crate::ui::util::{limit_dropdown_width, warning_heading};
|
use crate::ui::util::{limit_dropdown_width, warning_heading};
|
||||||
use crate::xr_devices::XRDevices;
|
use crate::xr_devices::XRDevice;
|
||||||
use gtk::prelude::*;
|
use gtk::prelude::*;
|
||||||
use relm4::adw::traits::MessageDialogExt;
|
use relm4::adw::traits::MessageDialogExt;
|
||||||
use relm4::adw::ResponseAppearance;
|
use relm4::adw::ResponseAppearance;
|
||||||
|
@ -66,7 +66,7 @@ pub enum MainViewMsg {
|
||||||
DeleteProfile,
|
DeleteProfile,
|
||||||
DuplicateProfile,
|
DuplicateProfile,
|
||||||
SaveProfile(Profile),
|
SaveProfile(Profile),
|
||||||
UpdateDevices(Option<XRDevices>),
|
UpdateDevices(Vec<XRDevice>),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -462,7 +462,7 @@ impl SimpleComponent for MainView {
|
||||||
Self::Input::XRServiceActiveChanged(active, profile) => {
|
Self::Input::XRServiceActiveChanged(active, profile) => {
|
||||||
self.set_xrservice_active(active);
|
self.set_xrservice_active(active);
|
||||||
if !active {
|
if !active {
|
||||||
sender.input(Self::Input::UpdateDevices(None));
|
sender.input(Self::Input::UpdateDevices(vec![]));
|
||||||
}
|
}
|
||||||
self.steam_launch_options_box
|
self.steam_launch_options_box
|
||||||
.sender()
|
.sender()
|
||||||
|
|
|
@ -6,6 +6,7 @@ pub mod debug_view;
|
||||||
pub mod devices_box;
|
pub mod devices_box;
|
||||||
pub mod factories;
|
pub mod factories;
|
||||||
pub mod fbt_config_editor;
|
pub mod fbt_config_editor;
|
||||||
|
pub mod feature_flags;
|
||||||
pub mod install_wivrn_box;
|
pub mod install_wivrn_box;
|
||||||
pub mod job_worker;
|
pub mod job_worker;
|
||||||
pub mod libsurvive_setup_window;
|
pub mod libsurvive_setup_window;
|
||||||
|
|
|
@ -1,5 +1,9 @@
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
use std::{fmt::Display, slice::Iter};
|
||||||
pub enum XRDevice {
|
|
||||||
|
const GENERIC_TRACKER_PREFIX: &str = "Found generic tracker device: ";
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq, Copy)]
|
||||||
|
pub enum XRDeviceType {
|
||||||
Head,
|
Head,
|
||||||
Left,
|
Left,
|
||||||
Right,
|
Right,
|
||||||
|
@ -10,25 +14,162 @@ pub enum XRDevice {
|
||||||
GenericTracker,
|
GenericTracker,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Default, Clone, PartialEq, Eq)]
|
impl Display for XRDeviceType {
|
||||||
pub struct XRDevices {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
pub head: Option<String>,
|
f.write_str(match self {
|
||||||
pub left: Option<String>,
|
Self::Head => "Head",
|
||||||
pub right: Option<String>,
|
Self::Left => "Left",
|
||||||
pub gamepad: Option<String>,
|
Self::Right => "Right",
|
||||||
pub eyes: Option<String>,
|
Self::Gamepad => "Gamepad",
|
||||||
pub hand_tracking_left: Option<String>,
|
Self::Eyes => "Eye Tracking",
|
||||||
pub hand_tracking_right: Option<String>,
|
Self::HandTrackingLeft => "Hand tracking left",
|
||||||
pub generic_trackers: Vec<String>,
|
Self::HandTrackingRight => "Hand tracking right",
|
||||||
|
Self::GenericTracker => "Generic tracker",
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const GENERIC_TRACKER_PREFIX: &str = "Found generic tracker device: ";
|
impl PartialOrd for XRDeviceType {
|
||||||
|
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
|
||||||
|
Some(self.as_number().cmp(&other.as_number()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl XRDevices {
|
impl Ord for XRDeviceType {
|
||||||
pub fn from_log_message(s: &str) -> Option<Self> {
|
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
|
||||||
|
self.partial_cmp(other).unwrap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl XRDeviceType {
|
||||||
|
pub fn iter() -> Iter<'static, Self> {
|
||||||
|
[
|
||||||
|
Self::Head,
|
||||||
|
Self::Left,
|
||||||
|
Self::Right,
|
||||||
|
Self::Gamepad,
|
||||||
|
Self::Eyes,
|
||||||
|
Self::HandTrackingLeft,
|
||||||
|
Self::HandTrackingRight,
|
||||||
|
Self::GenericTracker,
|
||||||
|
]
|
||||||
|
.iter()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn to_monado_str(&self) -> &str {
|
||||||
|
match self {
|
||||||
|
Self::Head => "head",
|
||||||
|
Self::Left => "left",
|
||||||
|
Self::Right => "right",
|
||||||
|
Self::Gamepad => "gamepad",
|
||||||
|
Self::Eyes => "eyes",
|
||||||
|
Self::HandTrackingLeft => "hand_tracking.left",
|
||||||
|
Self::HandTrackingRight => "hand_tracking.right",
|
||||||
|
Self::GenericTracker => "generic_tracker",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_number(&self) -> u32 {
|
||||||
|
match self {
|
||||||
|
Self::Head => 0,
|
||||||
|
Self::Left => 1,
|
||||||
|
Self::Right => 2,
|
||||||
|
Self::Gamepad => 3,
|
||||||
|
Self::Eyes => 4,
|
||||||
|
Self::HandTrackingLeft => 5,
|
||||||
|
Self::HandTrackingRight => 6,
|
||||||
|
Self::GenericTracker => 7,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_monado_str(s: &str) -> Option<Self> {
|
||||||
|
match s {
|
||||||
|
"head" => Some(Self::Head),
|
||||||
|
"left" => Some(Self::Left),
|
||||||
|
"right" => Some(Self::Right),
|
||||||
|
"gamepad" => Some(Self::Gamepad),
|
||||||
|
"eyes" => Some(Self::Eyes),
|
||||||
|
"hand_tracking.left" => Some(Self::HandTrackingLeft),
|
||||||
|
"hand_tracking.right" => Some(Self::HandTrackingRight),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_display_str(s: &str) -> Self {
|
||||||
|
match s {
|
||||||
|
"Head" => Self::Head,
|
||||||
|
"Left" => Self::Left,
|
||||||
|
"Right" => Self::Right,
|
||||||
|
"Gamepad" => Self::Gamepad,
|
||||||
|
"Eye Tracking" => Self::Eyes,
|
||||||
|
"Hand tracking left" => Self::HandTrackingLeft,
|
||||||
|
"Hand tracking right" => Self::HandTrackingRight,
|
||||||
|
"Generic tracker" => Self::GenericTracker,
|
||||||
|
_ => Self::GenericTracker,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
|
pub struct XRDevice {
|
||||||
|
pub dev_type: XRDeviceType,
|
||||||
|
pub name: String,
|
||||||
|
pub id: String,
|
||||||
|
pub battery: f32, // battery percentage, from 0 to 1 maybe
|
||||||
|
// still need to implement it in monado & gui
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for XRDevice {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
dev_type: XRDeviceType::GenericTracker,
|
||||||
|
name: String::default(),
|
||||||
|
id: String::default(),
|
||||||
|
battery: f32::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl XRDevice {
|
||||||
|
pub fn generic_tracker_from_log_row(s: &str) -> Option<Self> {
|
||||||
|
if s.starts_with(GENERIC_TRACKER_PREFIX) {
|
||||||
|
let n_tracker = s.trim_start_matches(GENERIC_TRACKER_PREFIX);
|
||||||
|
return Some(Self {
|
||||||
|
dev_type: XRDeviceType::GenericTracker,
|
||||||
|
id: n_tracker.into(),
|
||||||
|
..Default::default()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_libmonado(monado: &libmonado_rs::Monado) -> Vec<Self> {
|
||||||
|
let mut res = vec![];
|
||||||
|
[
|
||||||
|
XRDeviceType::Head,
|
||||||
|
XRDeviceType::Left,
|
||||||
|
XRDeviceType::Right,
|
||||||
|
XRDeviceType::Gamepad,
|
||||||
|
XRDeviceType::Eyes,
|
||||||
|
]
|
||||||
|
.iter()
|
||||||
|
.for_each(|xrd| {
|
||||||
|
if let Ok(dev) = monado.device_from_role(xrd.to_monado_str()) {
|
||||||
|
res.push(Self {
|
||||||
|
name: dev.name,
|
||||||
|
id: dev.id.to_string(),
|
||||||
|
dev_type: xrd.clone(),
|
||||||
|
..Default::default()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
});
|
||||||
|
res
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_log_message(s: &str) -> Vec<Self> {
|
||||||
|
let mut res = vec![];
|
||||||
let rows = s.split('\n');
|
let rows = s.split('\n');
|
||||||
let mut in_section = false;
|
let mut in_section = false;
|
||||||
let mut devs = Self::default();
|
|
||||||
for row in rows {
|
for row in rows {
|
||||||
if !in_section && row.starts_with("\tIn roles:") {
|
if !in_section && row.starts_with("\tIn roles:") {
|
||||||
in_section = true;
|
in_section = true;
|
||||||
|
@ -40,64 +181,58 @@ impl XRDevices {
|
||||||
}
|
}
|
||||||
match row.trim().split(": ").collect::<Vec<&str>>()[..] {
|
match row.trim().split(": ").collect::<Vec<&str>>()[..] {
|
||||||
[_, "<none>"] => {}
|
[_, "<none>"] => {}
|
||||||
["head", val] => devs.head = Some(val.to_string()),
|
[dev_type_s, name] => {
|
||||||
["left", val] => devs.left = Some(val.to_string()),
|
if let Some(xrdt) = XRDeviceType::from_monado_str(dev_type_s) {
|
||||||
["right", val] => devs.right = Some(val.to_string()),
|
res.push(Self {
|
||||||
["gamepad", val] => devs.gamepad = Some(val.to_string()),
|
dev_type: xrdt,
|
||||||
["eyes", val] => devs.eyes = Some(val.to_string()),
|
name: name.to_string(),
|
||||||
["hand_tracking.left", val] => devs.hand_tracking_left = Some(val.to_string()),
|
..Default::default()
|
||||||
["hand_tracking.right", val] => {
|
});
|
||||||
devs.hand_tracking_right = Some(val.to_string())
|
}
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if in_section {
|
res
|
||||||
return Some(devs);
|
}
|
||||||
|
|
||||||
|
pub fn merge(old: &[Self], new: &[Self]) -> Vec<Self> {
|
||||||
|
if old.is_empty() {
|
||||||
|
return Vec::from(new);
|
||||||
|
}
|
||||||
|
let new_dev_types = new
|
||||||
|
.iter()
|
||||||
|
.filter_map(|d| {
|
||||||
|
if d.dev_type == XRDeviceType::GenericTracker {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
Some(d.dev_type)
|
||||||
|
})
|
||||||
|
.collect::<Vec<XRDeviceType>>();
|
||||||
|
let mut res = old
|
||||||
|
.iter()
|
||||||
|
.filter(|d| !new_dev_types.contains(&d.dev_type))
|
||||||
|
.map(Self::clone)
|
||||||
|
.collect::<Vec<Self>>();
|
||||||
|
let old_tracker_ids = old
|
||||||
|
.iter()
|
||||||
|
.filter_map(|d| {
|
||||||
|
if d.dev_type == XRDeviceType::GenericTracker {
|
||||||
|
return Some(d.id.clone());
|
||||||
}
|
}
|
||||||
None
|
None
|
||||||
|
})
|
||||||
|
.collect::<Vec<String>>();
|
||||||
|
for n_dev in new {
|
||||||
|
if n_dev.dev_type == XRDeviceType::GenericTracker {
|
||||||
|
if !old_tracker_ids.contains(&n_dev.id) {
|
||||||
|
res.push(n_dev.clone());
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
pub fn merge(&mut self, new: Self) {
|
res.push(n_dev.clone());
|
||||||
if new.head.is_some() {
|
|
||||||
self.head = new.head;
|
|
||||||
}
|
|
||||||
if new.left.is_some() {
|
|
||||||
self.left = new.left;
|
|
||||||
}
|
|
||||||
if new.right.is_some() {
|
|
||||||
self.right = new.right;
|
|
||||||
}
|
|
||||||
if new.gamepad.is_some() {
|
|
||||||
self.gamepad = new.gamepad;
|
|
||||||
}
|
|
||||||
if new.eyes.is_some() {
|
|
||||||
self.eyes = new.eyes;
|
|
||||||
}
|
|
||||||
if new.hand_tracking_left.is_some() {
|
|
||||||
self.hand_tracking_left = new.hand_tracking_left;
|
|
||||||
}
|
|
||||||
if new.hand_tracking_right.is_some() {
|
|
||||||
self.hand_tracking_right = new.hand_tracking_right;
|
|
||||||
}
|
|
||||||
if !new.generic_trackers.is_empty() {
|
|
||||||
self.generic_trackers.extend(
|
|
||||||
new.generic_trackers
|
|
||||||
.iter()
|
|
||||||
.filter(|t| !self.generic_trackers.contains(t))
|
|
||||||
.cloned()
|
|
||||||
.collect::<Vec<String>>(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn search_log_for_generic_trackers(&mut self, s: &str) {
|
|
||||||
if s.starts_with(GENERIC_TRACKER_PREFIX) {
|
|
||||||
let n_tracker = s.trim_start_matches(GENERIC_TRACKER_PREFIX);
|
|
||||||
if !self.generic_trackers.contains(&n_tracker.to_string()) {
|
|
||||||
self.generic_trackers.push(n_tracker.into());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
res
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue