diff --git a/.github/workflows/build-full.yml b/.github/workflows/build-full.yml index daf008e..69313fb 100644 --- a/.github/workflows/build-full.yml +++ b/.github/workflows/build-full.yml @@ -21,7 +21,7 @@ jobs: sudo add-apt-repository -syn universe sudo add-apt-repository -syn ppa:pipewire-debian/pipewire-upstream || sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 25088A0359807596 sudo apt-get update -y - sudo apt-get install -y fuse cmake pkg-config fontconfig libasound2-dev libxkbcommon-dev libopenxr-dev libfontconfig-dev libdbus-1-dev libpipewire-0.3-0 libpipewire-0.3-dev libspa-0.2-dev libx11-6 libxext6 libxrandr2 libx11-dev libxext-dev libxrandr-dev libopenvr-dev libopenvr-api1 + sudo apt-get install -y fuse cmake pkg-config fontconfig libasound2-dev libxkbcommon-dev libxkbcommon-x11-0 libxkbcommon-x11-dev libopenxr-dev libfontconfig-dev libdbus-1-dev libpipewire-0.3-0 libpipewire-0.3-dev libspa-0.2-dev libx11-6 libxext6 libxrandr2 libx11-dev libxext-dev libxrandr-dev libopenvr-dev libopenvr-api1 - name: Build run: cargo build --verbose - name: Run tests diff --git a/.github/workflows/build-wayland-openvr.yml b/.github/workflows/build-wayland-openvr.yml index 27094cf..5c8166d 100644 --- a/.github/workflows/build-wayland-openvr.yml +++ b/.github/workflows/build-wayland-openvr.yml @@ -21,7 +21,7 @@ jobs: sudo add-apt-repository -syn universe sudo add-apt-repository -syn ppa:pipewire-debian/pipewire-upstream || sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 25088A0359807596 sudo apt-get update -y - sudo apt-get install -y fuse cmake pkg-config fontconfig libasound2-dev libxkbcommon-dev libopenxr-dev libfontconfig-dev libdbus-1-dev libpipewire-0.3-0 libpipewire-0.3-dev libspa-0.2-dev libx11-6 libxext6 libxrandr2 libx11-dev libxext-dev libxrandr-dev libopenvr-dev libopenvr-api1 + sudo apt-get install -y fuse cmake pkg-config fontconfig libasound2-dev libxkbcommon-dev libxkbcommon-x11-0 libxkbcommon-x11-dev libopenxr-dev libfontconfig-dev libdbus-1-dev libpipewire-0.3-0 libpipewire-0.3-dev libspa-0.2-dev libx11-6 libxext6 libxrandr2 libx11-dev libxext-dev libxrandr-dev libopenvr-dev libopenvr-api1 - name: Build run: cargo build --verbose --no-default-features --features=wayland,openvr - name: Run tests diff --git a/.github/workflows/build-wayland-openxr.yml b/.github/workflows/build-wayland-openxr.yml index 2edcb77..3c24bb6 100644 --- a/.github/workflows/build-wayland-openxr.yml +++ b/.github/workflows/build-wayland-openxr.yml @@ -21,7 +21,7 @@ jobs: sudo add-apt-repository -syn universe sudo add-apt-repository -syn ppa:pipewire-debian/pipewire-upstream || sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 25088A0359807596 sudo apt-get update -y - sudo apt-get install -y fuse cmake pkg-config fontconfig libasound2-dev libxkbcommon-dev libopenxr-dev libfontconfig-dev libdbus-1-dev libpipewire-0.3-0 libpipewire-0.3-dev libspa-0.2-dev libx11-6 libxext6 libxrandr2 libx11-dev libxext-dev libxrandr-dev libopenvr-dev libopenvr-api1 + sudo apt-get install -y fuse cmake pkg-config fontconfig libasound2-dev libxkbcommon-dev libxkbcommon-x11-0 libxkbcommon-x11-dev libopenxr-dev libfontconfig-dev libdbus-1-dev libpipewire-0.3-0 libpipewire-0.3-dev libspa-0.2-dev libx11-6 libxext6 libxrandr2 libx11-dev libxext-dev libxrandr-dev libopenvr-dev libopenvr-api1 - name: Build run: cargo build --verbose --no-default-features --features=wayland,openxr - name: Run tests diff --git a/.github/workflows/build-x11-openvr.yml b/.github/workflows/build-x11-openvr.yml index cab1a26..2605501 100644 --- a/.github/workflows/build-x11-openvr.yml +++ b/.github/workflows/build-x11-openvr.yml @@ -21,7 +21,7 @@ jobs: sudo add-apt-repository -syn universe sudo add-apt-repository -syn ppa:pipewire-debian/pipewire-upstream || sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 25088A0359807596 sudo apt-get update -y - sudo apt-get install -y fuse cmake pkg-config fontconfig libasound2-dev libxkbcommon-dev libopenxr-dev libfontconfig-dev libdbus-1-dev libpipewire-0.3-0 libpipewire-0.3-dev libspa-0.2-dev libx11-6 libxext6 libxrandr2 libx11-dev libxext-dev libxrandr-dev libopenvr-dev libopenvr-api1 + sudo apt-get install -y fuse cmake pkg-config fontconfig libasound2-dev libxkbcommon-dev libxkbcommon-x11-0 libxkbcommon-x11-dev libopenxr-dev libfontconfig-dev libdbus-1-dev libpipewire-0.3-0 libpipewire-0.3-dev libspa-0.2-dev libx11-6 libxext6 libxrandr2 libx11-dev libxext-dev libxrandr-dev libopenvr-dev libopenvr-api1 - name: Build run: cargo build --verbose --no-default-features --features=x11,openvr - name: Run tests diff --git a/.github/workflows/build-x11-openxr.yml b/.github/workflows/build-x11-openxr.yml index 3291a19..b44e43e 100644 --- a/.github/workflows/build-x11-openxr.yml +++ b/.github/workflows/build-x11-openxr.yml @@ -21,7 +21,7 @@ jobs: sudo add-apt-repository -syn universe sudo add-apt-repository -syn ppa:pipewire-debian/pipewire-upstream || sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 25088A0359807596 sudo apt-get update -y - sudo apt-get install -y fuse cmake pkg-config fontconfig libasound2-dev libxkbcommon-dev libopenxr-dev libfontconfig-dev libdbus-1-dev libpipewire-0.3-0 libpipewire-0.3-dev libspa-0.2-dev libx11-6 libxext6 libxrandr2 libx11-dev libxext-dev libxrandr-dev libopenvr-dev libopenvr-api1 + sudo apt-get install -y fuse cmake pkg-config fontconfig libasound2-dev libxkbcommon-dev libxkbcommon-x11-0 libxkbcommon-x11-dev libopenxr-dev libfontconfig-dev libdbus-1-dev libpipewire-0.3-0 libpipewire-0.3-dev libspa-0.2-dev libx11-6 libxext6 libxrandr2 libx11-dev libxext-dev libxrandr-dev libopenvr-dev libopenvr-api1 - name: Build run: cargo build --verbose --no-default-features --features=x11,openxr - name: Run tests diff --git a/.github/workflows/make-release.yml b/.github/workflows/make-release.yml index e0d36f7..9290211 100644 --- a/.github/workflows/make-release.yml +++ b/.github/workflows/make-release.yml @@ -23,7 +23,7 @@ jobs: sudo add-apt-repository -syn universe sudo add-apt-repository -syn ppa:pipewire-debian/pipewire-upstream || sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 25088A0359807596 sudo apt-get update - sudo apt-get install fuse cmake pkg-config fontconfig libasound2-dev libxkbcommon-dev libopenxr-dev libfontconfig-dev libdbus-1-dev libpipewire-0.3-0 libpipewire-0.3-dev libspa-0.2-dev libx11-6 libxext6 libxrandr2 libx11-dev libxext-dev libxrandr-dev libopenvr-dev libopenvr-api1 + sudo apt-get install -y fuse cmake pkg-config fontconfig libasound2-dev libxkbcommon-dev libxkbcommon-x11-0 libxkbcommon-x11-dev libopenxr-dev libfontconfig-dev libdbus-1-dev libpipewire-0.3-0 libpipewire-0.3-dev libspa-0.2-dev libx11-6 libxext6 libxrandr2 libx11-dev libxext-dev libxrandr-dev libopenvr-dev libopenvr-api1 rustup update test -f linuxdeploy-x86_64.AppImage || wget -q "https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/linuxdeploy-x86_64.AppImage" diff --git a/Cargo.lock b/Cargo.lock index 23b0d3d..75cfe1f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "ab_glyph" -version = "0.2.25" +version = "0.2.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f90148830dac590fac7ccfe78ec4a8ea404c60f75a24e16407a71f0f40de775" +checksum = "2e53b0a3d5760cd2ba9b787ae0c6440ad18ee294ff71b05e3381c900a7d16cfd" dependencies = [ "ab_glyph_rasterizer", "owned_ttf_parser", @@ -20,9 +20,9 @@ checksum = "c71b1793ee61086797f5c80b6efa2b8ffa6d5dd703f118545808a7f2e27f7046" [[package]] name = "addr2line" -version = "0.21.0" +version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" +checksum = "6e4503c46a5c0c7844e948c9a4d6acd9f50cccb4de1c48eb9e291ea17470c678" dependencies = [ "gimli", ] @@ -130,47 +130,48 @@ dependencies = [ [[package]] name = "anstream" -version = "0.6.13" +version = "0.6.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d96bd03f33fe50a863e394ee9718a706f988b9079b20c3784fb726e7678b62fb" +checksum = "418c75fa768af9c03be99d17643f93f79bbba589895012a80e3452a19ddda15b" dependencies = [ "anstyle", "anstyle-parse", "anstyle-query", "anstyle-wincon", "colorchoice", + "is_terminal_polyfill", "utf8parse", ] [[package]] name = "anstyle" -version = "1.0.6" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8901269c6307e8d93993578286ac0edf7f195079ffff5ebdeea6a59ffb7e36bc" +checksum = "038dfcf04a5feb68e9c60b21c9625a54c2c0616e79b72b0fd87075a056ae1d1b" [[package]] name = "anstyle-parse" -version = "0.2.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c75ac65da39e5fe5ab759307499ddad880d724eed2f6ce5b5e8a26f4f387928c" +checksum = "c03a11a9034d92058ceb6ee011ce58af4a9bf61491aa7e1e59ecd24bd40d22d4" dependencies = [ "utf8parse", ] [[package]] name = "anstyle-query" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e28923312444cdd728e4738b3f9c9cac739500909bb3d3c94b43551b16517648" +checksum = "a64c907d4e79225ac72e2a354c9ce84d50ebb4586dee56c82b3ee73004f537f5" dependencies = [ "windows-sys 0.52.0", ] [[package]] name = "anstyle-wincon" -version = "3.0.2" +version = "3.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cd54b81ec8d6180e24654d0b371ad22fc3dd083b6ff8ba325b72e00c87660a7" +checksum = "61a38449feb7068f52bb06c12759005cf459ee52bb4adc1d5a7c4322d716fb19" dependencies = [ "anstyle", "windows-sys 0.52.0", @@ -178,9 +179,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.81" +version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0952808a6c2afd1aa8947271f3a60f1a6763c7b912d210184c5149b5cf147247" +checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" [[package]] name = "approx" @@ -251,36 +252,34 @@ dependencies = [ [[package]] name = "async-broadcast" -version = "0.7.0" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "258b52a1aa741b9f09783b2d86cf0aeeb617bbf847f6933340a39644227acbdb" +checksum = "20cd0e2e25ea8e5f7e9df04578dc6cf5c83577fd09b1a46aaf5c85e1c33f2a7e" dependencies = [ - "event-listener 5.3.0", - "event-listener-strategy 0.5.1", + "event-listener", + "event-listener-strategy", "futures-core", "pin-project-lite", ] [[package]] name = "async-channel" -version = "2.2.0" +version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f28243a43d821d11341ab73c80bed182dc015c514b951616cf79bd4af39af0c3" +checksum = "89b47800b0be77592da0afd425cc03468052844aff33b84e33cc696f64e77b6a" dependencies = [ "concurrent-queue", - "event-listener 5.3.0", - "event-listener-strategy 0.5.1", + "event-listener-strategy", "futures-core", "pin-project-lite", ] [[package]] name = "async-executor" -version = "1.10.0" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f98c37cf288e302c16ef6c8472aad1e034c6c84ce5ea7b8101c98eb4a802fee" +checksum = "c8828ec6e544c02b0d6691d21ed9f9218d0384a82542855073c2a3f58304aaf0" dependencies = [ - "async-lock 3.3.0", "async-task", "concurrent-queue", "fastrand", @@ -290,22 +289,22 @@ dependencies = [ [[package]] name = "async-fs" -version = "2.1.1" +version = "2.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc19683171f287921f2405677dd2ed2549c3b3bda697a563ebc3a121ace2aba1" +checksum = "ebcd09b382f40fcd159c2d695175b2ae620ffa5f3bd6f664131efff4e8b9e04a" dependencies = [ - "async-lock 3.3.0", + "async-lock", "blocking", "futures-lite", ] [[package]] name = "async-io" -version = "2.3.2" +version = "2.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcccb0f599cfa2f8ace422d3555572f47424da5648a4382a9dd0310ff8210884" +checksum = "0d6baa8f0178795da0e71bc42c9e5d13261aac7ee549853162e66a241ba17964" dependencies = [ - "async-lock 3.3.0", + "async-lock", "cfg-if", "concurrent-queue", "futures-io", @@ -320,21 +319,12 @@ dependencies = [ [[package]] name = "async-lock" -version = "2.8.0" +version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "287272293e9d8c41773cec55e365490fe034813a2f172f502d6ddcf75b2f582b" +checksum = "ff6e472cdea888a4bd64f342f09b3f50e1886d32afe8df3d663c01140b811b18" dependencies = [ - "event-listener 2.5.3", -] - -[[package]] -name = "async-lock" -version = "3.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d034b430882f8381900d3fe6f0aaa3ad94f2cb4ac519b429692a1bc2dda4ae7b" -dependencies = [ - "event-listener 4.0.3", - "event-listener-strategy 0.4.0", + "event-listener", + "event-listener-strategy", "pin-project-lite", ] @@ -351,18 +341,18 @@ dependencies = [ [[package]] name = "async-process" -version = "2.2.0" +version = "2.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d999d925640d51b662b7b4e404224dd81de70f4aa4a199383c2c5e5b86885fa3" +checksum = "f7eda79bbd84e29c2b308d1dc099d7de8dcc7035e48f4bf5dc4a531a44ff5e2a" dependencies = [ "async-channel", "async-io", - "async-lock 3.3.0", + "async-lock", "async-signal", "async-task", "blocking", "cfg-if", - "event-listener 5.3.0", + "event-listener", "futures-lite", "rustix", "tracing", @@ -371,23 +361,23 @@ dependencies = [ [[package]] name = "async-recursion" -version = "1.1.0" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30c5ef0ede93efbf733c1a727f3b6b5a1060bbedd5600183e66f6e4be4af0ec5" +checksum = "3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11" dependencies = [ "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.66", ] [[package]] name = "async-signal" -version = "0.2.5" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e47d90f65a225c4527103a8d747001fc56e375203592b25ad103e1ca13124c5" +checksum = "329972aa325176e89114919f2a80fdae4f4c040f66a370b1a1159c6c0f94e7aa" dependencies = [ "async-io", - "async-lock 2.8.0", + "async-lock", "atomic-waker", "cfg-if", "futures-core", @@ -395,24 +385,24 @@ dependencies = [ "rustix", "signal-hook-registry", "slab", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] name = "async-task" -version = "4.7.0" +version = "4.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbb36e985947064623dbd357f727af08ffd077f93d696782f3c56365fa2e2799" +checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de" [[package]] name = "async-trait" -version = "0.1.79" +version = "0.1.80" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a507401cad91ec6a857ed5513a2073c82a9b9048762b885bb98655b306964681" +checksum = "c6fa2087f2753a7da8cc1c0dbfcf89579dd57458e36769de5ac750b4671737ca" dependencies = [ "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.66", ] [[package]] @@ -434,9 +424,9 @@ dependencies = [ [[package]] name = "autocfg" -version = "1.2.0" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1fdabc7756949593fe60f30ec81974b613357de856987752631dea1e3394c80" +checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" [[package]] name = "autocxx" @@ -470,7 +460,7 @@ dependencies = [ "regex", "rustc-hash", "shlex", - "syn 2.0.58", + "syn 2.0.66", "which", ] @@ -483,7 +473,7 @@ dependencies = [ "autocxx-engine", "env_logger", "indexmap 1.9.3", - "syn 2.0.58", + "syn 2.0.66", ] [[package]] @@ -510,7 +500,7 @@ dependencies = [ "rustversion", "serde_json", "strum_macros 0.24.3", - "syn 2.0.58", + "syn 2.0.66", "tempfile", "thiserror", "version_check", @@ -526,7 +516,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.66", ] [[package]] @@ -543,15 +533,15 @@ dependencies = [ "quote", "serde", "serde_json", - "syn 2.0.58", + "syn 2.0.66", "thiserror", ] [[package]] name = "backtrace" -version = "0.3.71" +version = "0.3.72" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26b05800d2e817c8b3b4b54abd461726265fa9789ae34330622f2db9ee696f9d" +checksum = "17c6a35df3749d2e8bb1b7b21a976d82b15548788d2735b9d82f329268f71a11" dependencies = [ "addr2line", "cc", @@ -586,7 +576,7 @@ dependencies = [ "regex", "rustc-hash", "shlex", - "syn 2.0.58", + "syn 2.0.66", ] [[package]] @@ -634,18 +624,15 @@ dependencies = [ [[package]] name = "blocking" -version = "1.5.1" +version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a37913e8dc4ddcc604f0c6d3bf2887c995153af3611de9e23c352b44c1b9118" +checksum = "703f41c54fc768e63e091340b424302bb1c29ef4aa0c7f10fe849dfb114d29ea" dependencies = [ "async-channel", - "async-lock 3.3.0", "async-task", - "fastrand", "futures-io", "futures-lite", "piper", - "tracing", ] [[package]] @@ -656,22 +643,22 @@ checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" [[package]] name = "bytemuck" -version = "1.15.0" +version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d6d68c57235a3a081186990eca2867354726650f42f7516ca50c28d6281fd15" +checksum = "78834c15cb5d5efe3452d58b1e8ba890dd62d21907f867f383358198e56ebca5" dependencies = [ "bytemuck_derive", ] [[package]] name = "bytemuck_derive" -version = "1.6.0" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4da9a32f3fed317401fa3c862968128267c3106685286e15d5aaa3d7389c2f60" +checksum = "1ee891b04274a59bd38b412188e24b849617b2e45a0fd8d057deb63e7403761b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.66", ] [[package]] @@ -714,12 +701,13 @@ dependencies = [ [[package]] name = "cc" -version = "1.0.92" +version = "1.0.98" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2678b2e3449475e95b0aa6f9b506a28e61b3dc8996592b983695e8ebb58a8b41" +checksum = "41c270e7540d725e65ac7f1b212ac8ce349719624d7bcff99f8e2e488e8cf03f" dependencies = [ "jobserver", "libc", + "once_cell", ] [[package]] @@ -739,9 +727,9 @@ dependencies = [ [[package]] name = "cfg-expr" -version = "0.15.7" +version = "0.15.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa50868b64a9a6fda9d593ce778849ea8715cd2a3d2cc17ffdb4a2f2f2f1961d" +checksum = "d067ad48b8650848b989a59a86c6c36a995d02d2bf778d45c3c5d57bc2718f02" dependencies = [ "smallvec", "target-lexicon", @@ -761,16 +749,16 @@ checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e" [[package]] name = "chrono" -version = "0.4.37" +version = "0.4.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a0d04d43504c61aa6c7531f1871dd0d418d91130162063b789da00fd7057a5e" +checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" dependencies = [ "android-tzdata", "iana-time-zone", "js-sys", "num-traits", "wasm-bindgen", - "windows-targets 0.52.4", + "windows-targets 0.52.5", ] [[package]] @@ -797,9 +785,9 @@ dependencies = [ [[package]] name = "clang-sys" -version = "1.7.0" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67523a3b4be3ce1989d607a828d036249522dd9c1c8de7f4dd2dae43a37369d1" +checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4" dependencies = [ "glob", "libc", @@ -837,7 +825,7 @@ dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.66", ] [[package]] @@ -867,15 +855,15 @@ dependencies = [ [[package]] name = "colorchoice" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" +checksum = "0b6a852b24ab71dffc585bcb46eaf7959d175cb865a7152e35b348d1b2960422" [[package]] name = "combine" -version = "4.6.6" +version = "4.6.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35ed6e9d84f0b51a7f52daf1c7d71dd136fd7a3f41a8462b8cdb8c78d920fad4" +checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd" dependencies = [ "bytes", "memchr", @@ -883,9 +871,9 @@ dependencies = [ [[package]] name = "concurrent-queue" -version = "2.4.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d16048cd947b08fa32c24458a22f5dc5e835264f689f4f5653210c69fd107363" +checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" dependencies = [ "crossbeam-utils", ] @@ -1040,7 +1028,7 @@ dependencies = [ "wasm-bindgen", "wasm-bindgen-futures", "web-sys", - "windows", + "windows 0.54.0", ] [[package]] @@ -1052,6 +1040,25 @@ dependencies = [ "libc", ] +[[package]] +name = "crossbeam-deque" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +dependencies = [ + "crossbeam-utils", +] + [[package]] name = "crossbeam-queue" version = "0.3.11" @@ -1063,9 +1070,9 @@ dependencies = [ [[package]] name = "crossbeam-utils" -version = "0.8.19" +version = "0.8.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345" +checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" [[package]] name = "crunchy" @@ -1111,9 +1118,9 @@ checksum = "96a6ac251f4a2aca6b3f91340350eab87ae57c3f127ffeb585e92bd336717991" [[package]] name = "cxx" -version = "1.0.121" +version = "1.0.122" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21db378d04296a84d8b7d047c36bb3954f0b46529db725d7e62fb02f9ba53ccc" +checksum = "bb497fad022245b29c2a0351df572e2d67c1046bcef2260ebc022aec81efea82" dependencies = [ "cc", "cxxbridge-flags", @@ -1123,38 +1130,38 @@ dependencies = [ [[package]] name = "cxx-gen" -version = "0.7.121" +version = "0.7.122" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "383ecb9f96a536a1c7a2a61c5786f583da84f9240da149d78d005a4413c9a71e" +checksum = "a476ac5d29b1957ad93669eef9a030e9fc139103f9bb1ff9f15504c3f21236b0" dependencies = [ "codespan-reporting", "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.66", ] [[package]] name = "cxxbridge-flags" -version = "1.0.121" +version = "1.0.122" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be8dcadd2e2fb4a501e1d9e93d6e88e6ea494306d8272069c92d5a9edf8855c0" +checksum = "688c799a4a846f1c0acb9f36bb9c6272d9b3d9457f3633c7753c6057270df13c" [[package]] name = "cxxbridge-macro" -version = "1.0.121" +version = "1.0.122" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad08a837629ad949b73d032c637653d069e909cffe4ee7870b02301939ce39cc" +checksum = "928bc249a7e3cd554fd2e8e08a426e9670c50bbfc9a621653cfa9accc9641783" dependencies = [ "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.66", ] [[package]] name = "darling" -version = "0.20.8" +version = "0.20.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54e36fcd13ed84ffdfda6f5be89b31287cbb80c439841fe69e04841435464391" +checksum = "83b2eb4d90d12bdda5ed17de686c2acb4c57914f8f921b8da7e112b5a36f3fe1" dependencies = [ "darling_core", "darling_macro", @@ -1162,26 +1169,26 @@ dependencies = [ [[package]] name = "darling_core" -version = "0.20.8" +version = "0.20.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c2cf1c23a687a1feeb728783b993c4e1ad83d99f351801977dd809b48d0a70f" +checksum = "622687fe0bac72a04e5599029151f5796111b90f1baaa9b544d807a5e31cd120" dependencies = [ "fnv", "ident_case", "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.66", ] [[package]] name = "darling_macro" -version = "0.20.8" +version = "0.20.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a668eda54683121533a393014d8692171709ff57a7d61f187b6e782719f8933f" +checksum = "733cabb43482b1a1b53eee8583c2b9e8684d592215ea83efd305dd31bc2f0178" dependencies = [ "darling_core", "quote", - "syn 2.0.58", + "syn 2.0.66", ] [[package]] @@ -1273,9 +1280,9 @@ checksum = "0aafbcdb8afc29c1a7ee5fbe53b5d62f4565b35a042a662ca9fecd0b54dae6f4" [[package]] name = "either" -version = "1.10.0" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11157ac094ffbdde99aa67b23417ebdd801842852b500e395a45a9c0aac03e4a" +checksum = "3dca9240753cf90908d7e4aac30f630662b02aebaa1b58a3cadabdb23385b58b" [[package]] name = "endi" @@ -1301,7 +1308,7 @@ checksum = "5c785274071b1b420972453b306eeca06acf4633829db4223b58a2a8c5953bc4" dependencies = [ "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.66", ] [[package]] @@ -1322,7 +1329,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.66", ] [[package]] @@ -1346,9 +1353,9 @@ checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] name = "errno" -version = "0.3.8" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" +checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" dependencies = [ "libc", "windows-sys 0.52.0", @@ -1356,57 +1363,30 @@ dependencies = [ [[package]] name = "event-listener" -version = "2.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" - -[[package]] -name = "event-listener" -version = "4.0.3" +version = "5.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67b215c49b2b248c855fb73579eb1f4f26c38ffdc12973e20e07b91d78d5646e" +checksum = "6032be9bd27023a771701cc49f9f053c751055f71efb2e0ae5c15809093675ba" dependencies = [ "concurrent-queue", "parking", "pin-project-lite", ] -[[package]] -name = "event-listener" -version = "5.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d9944b8ca13534cdfb2800775f8dd4902ff3fc75a50101466decadfdf322a24" -dependencies = [ - "concurrent-queue", - "parking", - "pin-project-lite", -] - -[[package]] -name = "event-listener-strategy" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "958e4d70b6d5e81971bebec42271ec641e7ff4e170a6fa605f2b8a8b65cb97d3" -dependencies = [ - "event-listener 4.0.3", - "pin-project-lite", -] - [[package]] name = "event-listener-strategy" -version = "0.5.1" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "332f51cb23d20b0de8458b86580878211da09bcd4503cb579c225b3d124cabb3" +checksum = "0f214dc438f977e6d4e3500aaa277f5ad94ca83fbbd9b1a15713ce2344ccc5a1" dependencies = [ - "event-listener 5.3.0", + "event-listener", "pin-project-lite", ] [[package]] name = "fastrand" -version = "2.0.2" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "658bd65b1cf4c852a3cc96f18a8ce7b5640f6b703f905c7d74532294c2a63984" +checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a" [[package]] name = "fixedbitset" @@ -1416,9 +1396,9 @@ checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" [[package]] name = "flexi_logger" -version = "0.28.0" +version = "0.28.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f248c29a6d4bc5d065c9e9068d858761a0dcd796759f7801cc14db35db23abd8" +checksum = "419c99d8fc346ea0eaeaac2cc3945024d8fe82aa435aefc2fb9fcda1065f8774" dependencies = [ "chrono", "glob", @@ -1465,7 +1445,7 @@ checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742" dependencies = [ "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.66", ] [[package]] @@ -1574,7 +1554,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.66", ] [[package]] @@ -1629,9 +1609,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.14" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94b22e06ecb0110981051723910cbf0b5f5e09a2062dd7663334ee79a9d1286c" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" dependencies = [ "cfg-if", "libc", @@ -1640,9 +1620,9 @@ dependencies = [ [[package]] name = "gimli" -version = "0.28.1" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" +checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd" [[package]] name = "glam" @@ -1685,9 +1665,9 @@ checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" [[package]] name = "hashbrown" -version = "0.14.3" +version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" [[package]] name = "heck" @@ -1832,7 +1812,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" dependencies = [ "equivalent", - "hashbrown 0.14.3", + "hashbrown 0.14.5", ] [[package]] @@ -1872,6 +1852,12 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "is_terminal_polyfill" +version = "1.70.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8478577c03552c21db0e2724ffb8986a5ce7af88107e6be5d2ee6e158c12800" + [[package]] name = "itertools" version = "0.9.0" @@ -1943,9 +1929,9 @@ checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" [[package]] name = "jobserver" -version = "0.1.28" +version = "0.1.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab46a6e9526ddef3ae7f787c06f0f2600639ba80ea3eade3d8e670a2230f51d6" +checksum = "d2b099aaa34a9751c5bf0878add70444e1ed2dd73f347be99003d4577277de6e" dependencies = [ "libc", ] @@ -1990,9 +1976,9 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" [[package]] name = "libc" -version = "0.2.153" +version = "0.2.155" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" +checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" [[package]] name = "libdbus-sys" @@ -2020,7 +2006,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c2a198fb6b0eada2a8df47933734e6d35d350665a33a3593d7164fa52c75c19" dependencies = [ "cfg-if", - "windows-targets 0.52.4", + "windows-targets 0.52.5", ] [[package]] @@ -2079,15 +2065,15 @@ checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" [[package]] name = "linux-raw-sys" -version = "0.4.13" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c" +checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" [[package]] name = "lock_api" -version = "0.4.11" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45" +checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" dependencies = [ "autocfg", "scopeguard", @@ -2189,7 +2175,7 @@ checksum = "49e7bc1560b95a3c4a25d03de42fe76ca718ab92d1a22a55b9b4cf67b3ae635c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.66", ] [[package]] @@ -2200,9 +2186,9 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] name = "miniz_oxide" -version = "0.7.2" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d811f3e15f28568be3407c8e7fdb6514c1cda3cb30683f15b6a1a1dc4ea14a7" +checksum = "87dfd01fe195c66b572b37921ad8803d010623c0aca821bea2302239d155cdae" dependencies = [ "adler", ] @@ -2302,11 +2288,20 @@ dependencies = [ "winapi", ] +[[package]] +name = "ntapi" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8a3895c6391c39d7fe7ebc444a87eb2991b2a0bc718fdabd071eec617fc68e4" +dependencies = [ + "winapi", +] + [[package]] name = "nu-ansi-term" -version = "0.49.0" +version = "0.50.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c073d3c1930d0751774acf49e66653acecb416c3a54c6ec095a9b11caddb5a68" +checksum = "dd2800e1520bdc966782168a627aa5d1ad92e33b984bf7c7615d31280c83ff14" dependencies = [ "windows-sys 0.48.0", ] @@ -2319,14 +2314,14 @@ checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" dependencies = [ "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.66", ] [[package]] name = "num-traits" -version = "0.2.18" +version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da0df0e5185db44f69b44f26786fe401b6c293d1907744beaa7fa62b2e5a517a" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ "autocfg", ] @@ -2349,7 +2344,7 @@ dependencies = [ "proc-macro-crate 2.0.2", "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.66", ] [[package]] @@ -2363,9 +2358,9 @@ dependencies = [ [[package]] name = "objc-sys" -version = "0.3.2" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7c71324e4180d0899963fc83d9d241ac39e699609fc1025a850aadac8257459" +checksum = "cdb91bdd390c7ce1a8607f35f3ca7151b65afc0ff5ff3b34fa350f7d7c7e4310" [[package]] name = "objc2" @@ -2385,9 +2380,9 @@ checksum = "d079845b37af429bfe5dfa76e6d087d788031045b25cfc6fd898486fd9847666" [[package]] name = "object" -version = "0.32.2" +version = "0.35.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" +checksum = "b8ec7ab813848ba4522158d5517a6093db1ded27575b070f4177b8d12b41db5e" dependencies = [ "memchr", ] @@ -2475,7 +2470,7 @@ dependencies = [ [[package]] name = "ovr_overlay" version = "0.0.0" -source = "git+https://github.com/galister/ovr_overlay_oyasumi#61e0e77770212d64a76775a8c76637d1ca935942" +source = "git+https://github.com/galister/ovr_overlay_oyasumi#e8ac3d9dd6577b3c896f9288eab4887e84e780a1" dependencies = [ "byteorder", "derive_more", @@ -2490,7 +2485,7 @@ dependencies = [ [[package]] name = "ovr_overlay_sys" version = "0.0.0" -source = "git+https://github.com/galister/ovr_overlay_oyasumi#61e0e77770212d64a76775a8c76637d1ca935942" +source = "git+https://github.com/galister/ovr_overlay_oyasumi#e8ac3d9dd6577b3c896f9288eab4887e84e780a1" dependencies = [ "autocxx", "autocxx-build", @@ -2500,9 +2495,9 @@ dependencies = [ [[package]] name = "owned_ttf_parser" -version = "0.20.0" +version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4586edfe4c648c71797a74c84bacb32b52b212eff5dfe2bb9f2c599844023e7" +checksum = "6b41438d2fc63c46c74a2203bf5ccd82c41ba04347b2fcf5754f230b167067d5" dependencies = [ "ttf-parser", ] @@ -2515,9 +2510,9 @@ checksum = "bb813b8af86854136c6922af0598d719255ecb2179515e6e7730d468f05c9cae" [[package]] name = "parking_lot" -version = "0.12.1" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" +checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" dependencies = [ "lock_api", "parking_lot_core", @@ -2525,22 +2520,22 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.9" +version = "0.9.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e" +checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" dependencies = [ "cfg-if", "libc", - "redox_syscall 0.4.1", + "redox_syscall 0.5.1", "smallvec", - "windows-targets 0.48.5", + "windows-targets 0.52.5", ] [[package]] name = "parse-zoneinfo" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c705f256449c60da65e11ff6626e0c16a0a0b96aaa348de61376b249bc340f41" +checksum = "1f2a05b18d44e2957b88f96ba460715e295bc1d7510468a2f3d3b44535d26c24" dependencies = [ "regex", ] @@ -2565,9 +2560,9 @@ checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] name = "pest" -version = "2.7.9" +version = "2.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "311fb059dee1a7b802f036316d790138c613a4e8b180c822e3925a662e9f0c95" +checksum = "560131c633294438da9f7c4b08189194b20946c8274c6b9e38881a7874dc8ee8" dependencies = [ "memchr", "thiserror", @@ -2576,9 +2571,9 @@ dependencies = [ [[package]] name = "pest_derive" -version = "2.7.9" +version = "2.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f73541b156d32197eecda1a4014d7f868fd2bcb3c550d5386087cfba442bf69c" +checksum = "26293c9193fbca7b1a3bf9b79dc1e388e927e6cacaa78b4a3ab705a1d3d41459" dependencies = [ "pest", "pest_generator", @@ -2586,22 +2581,22 @@ dependencies = [ [[package]] name = "pest_generator" -version = "2.7.9" +version = "2.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c35eeed0a3fab112f75165fdc026b3913f4183133f19b49be773ac9ea966e8bd" +checksum = "3ec22af7d3fb470a85dd2ca96b7c577a1eb4ef6f1683a9fe9a8c16e136c04687" dependencies = [ "pest", "pest_meta", "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.66", ] [[package]] name = "pest_meta" -version = "2.7.9" +version = "2.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2adbf29bb9776f28caece835398781ab24435585fe0d4dc1374a61db5accedca" +checksum = "d7a240022f37c361ec1878d646fc5b7d7c4d28d5946e1a80ad5a7a4f4ca0bdcd" dependencies = [ "once_cell", "pest", @@ -2660,9 +2655,9 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "piper" -version = "0.2.1" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "668d31b1c4eba19242f2088b2bf3316b82ca31082a8335764db4e083db7485d4" +checksum = "ae1d5c74c9876f070d3e8fd503d748c7d974c3e48da8f41350fa5222ef9b4391" dependencies = [ "atomic-waker", "fastrand", @@ -2705,9 +2700,9 @@ checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" [[package]] name = "polling" -version = "3.6.0" +version = "3.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0c976a60b2d7e99d6f229e414670a9b85d13ac305cc6d1e9c134de58c5aaaf6" +checksum = "5e6a007746f34ed64099e88783b0ae369eaa3da6392868ba262e2af9b8fbaea1" dependencies = [ "cfg-if", "concurrent-queue", @@ -2726,12 +2721,12 @@ checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" [[package]] name = "prettyplease" -version = "0.2.17" +version = "0.2.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d3928fb5db768cb86f891ff014f0144589297e3c6a1aba6ed7cecfdace270c7" +checksum = "5f12335488a2f3b0a83b14edad48dca9879ce89b2edd10e80237e4e852dd645e" dependencies = [ "proc-macro2", - "syn 2.0.58", + "syn 2.0.66", ] [[package]] @@ -2780,9 +2775,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.79" +version = "1.0.85" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e835ff2298f5721608eb1a980ecaee1aef2c132bf95ecc026a11b7bf3c01c02e" +checksum = "22244ce15aa966053a896d1accb3a6e68469b97c7f33f284b99f0d576879fc23" dependencies = [ "unicode-ident", ] @@ -2807,9 +2802,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.35" +version = "1.0.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" +checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" dependencies = [ "proc-macro2", ] @@ -2846,9 +2841,29 @@ dependencies = [ [[package]] name = "raw-window-handle" -version = "0.6.0" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20675572f6f24e9e76ef639bc5552774ed45f1c30e2951e1e99c59888861c539" + +[[package]] +name = "rayon" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42a9830a0e1b9fb145ebb365b8bc4ccd75f290f98c0247deafbbe2c75cefb544" +checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", +] [[package]] name = "redox_syscall" @@ -2868,6 +2883,15 @@ dependencies = [ "bitflags 1.3.2", ] +[[package]] +name = "redox_syscall" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "469052894dcb553421e483e4209ee581a45100d31b4018de03e5a7ad86374a7e" +dependencies = [ + "bitflags 2.5.0", +] + [[package]] name = "regex" version = "1.10.4" @@ -2950,9 +2974,9 @@ dependencies = [ [[package]] name = "rustc-demangle" -version = "0.1.23" +version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" +checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" [[package]] name = "rustc-hash" @@ -2971,9 +2995,9 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.32" +version = "0.38.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65e04861e65f21776e67888bfbea442b3642beaa0138fdb1dd7a84a52dffdb89" +checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" dependencies = [ "bitflags 2.5.0", "errno", @@ -2984,9 +3008,9 @@ dependencies = [ [[package]] name = "rustversion" -version = "1.0.15" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80af6f9131f277a45a3fba6ce8e2258037bb0477a67e610d3c1fe046ab31de47" +checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6" [[package]] name = "rxscreen" @@ -2999,9 +3023,9 @@ dependencies = [ [[package]] name = "ryu" -version = "1.0.17" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1" +checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" [[package]] name = "same-file" @@ -3039,41 +3063,52 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.22" +version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92d43fe69e652f3df9bdc2b85b2854a0825b86e4fb76bc44d945137d053639ca" +checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" [[package]] name = "serde" -version = "1.0.197" +version = "1.0.203" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2" +checksum = "7253ab4de971e72fb7be983802300c30b5a7f0c2e56fab8abfc6a214307c0094" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.197" +version = "1.0.203" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" +checksum = "500cbc0ebeb6f46627f50f3f5811ccf6bf00643be300b4c3eabc0ef55dc5b5ba" dependencies = [ "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.66", ] [[package]] name = "serde_json" -version = "1.0.115" +version = "1.0.117" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12dc5c46daa8e9fdf4f5e71b6cf9a53f2487da0e86e55808e2d35539666497dd" +checksum = "455182ea6142b14f93f4bc5320a2b31c1f266b66a4a5c858b013302a5d8cbfc3" dependencies = [ "itoa", "ryu", "serde", ] +[[package]] +name = "serde_json5" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a6b754515e1a7bd79fc2edeaecee526fc80cb3a918607e5ca149225a3a9586" +dependencies = [ + "pest", + "pest_derive", + "serde", +] + [[package]] name = "serde_repr" version = "0.1.19" @@ -3082,14 +3117,14 @@ checksum = "6c64451ba24fc7a6a2d60fc75dd9c83c90903b19028d4eff35e88fc1e86564e9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.66", ] [[package]] name = "serde_spanned" -version = "0.6.5" +version = "0.6.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb3622f419d1296904700073ea6cc23ad690adbd66f13ea683df73298736f0c1" +checksum = "79e674e01f999af37c49f70a6ede167a8a60b2503e56c5599532a65baa5969a0" dependencies = [ "serde", ] @@ -3158,9 +3193,9 @@ checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" [[package]] name = "signal-hook-registry" -version = "1.4.1" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1" +checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1" dependencies = [ "libc", ] @@ -3222,9 +3257,9 @@ dependencies = [ [[package]] name = "smol_str" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6845563ada680337a52d43bb0b29f396f2d911616f6573012645b9e3d048a49" +checksum = "dd538fb6910ac1099850255cf94a94df6551fbdd602454387d0adb2d1ca6dead" dependencies = [ "serde", ] @@ -3253,7 +3288,7 @@ version = "0.26.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5d8cec3501a5194c432b2b7976db6b7d10ec95c253208b45f83f7136aa985e29" dependencies = [ - "strum_macros 0.26.2", + "strum_macros 0.26.3", ] [[package]] @@ -3271,15 +3306,15 @@ dependencies = [ [[package]] name = "strum_macros" -version = "0.26.2" +version = "0.26.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6cf59daf282c0a494ba14fd21610a0325f9f90ec9d1231dea26bcb1d696c946" +checksum = "f7993a8e3a9e88a00351486baae9522c91b123a088f76469e5bd5cc17198ea87" dependencies = [ - "heck 0.4.1", + "heck 0.5.0", "proc-macro2", "quote", "rustversion", - "syn 2.0.58", + "syn 2.0.66", ] [[package]] @@ -3295,15 +3330,30 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.58" +version = "2.0.66" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44cfb93f38070beee36b3fef7d4f5a16f27751d94b187b666a5cc5e9b0d30687" +checksum = "c42f3f41a2de00b01c0aaad383c5a45241efc8b2d1eda5661812fda5f3cdcff5" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] +[[package]] +name = "sysinfo" +version = "0.30.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "732ffa00f53e6b2af46208fba5718d9662a421049204e156328b66791ffa15ae" +dependencies = [ + "cfg-if", + "core-foundation-sys", + "libc", + "ntapi", + "once_cell", + "rayon", + "windows 0.52.0", +] + [[package]] name = "system-deps" version = "6.2.2" @@ -3346,22 +3396,22 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.58" +version = "1.0.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03468839009160513471e86a034bb2c5c0e4baae3b43f79ffc55c4a5427b3297" +checksum = "c546c80d6be4bc6a00c0f01730c08df82eaa7a7a61f11d656526506112cc1709" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.58" +version = "1.0.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c61f3ba182994efc43764a46c018c347bc492c79f024e705f46567b418f6d4f7" +checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533" dependencies = [ "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.66", ] [[package]] @@ -3487,7 +3537,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.66", ] [[package]] @@ -3501,9 +3551,9 @@ dependencies = [ [[package]] name = "ttf-parser" -version = "0.20.0" +version = "0.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17f77d76d837a7830fe1d4f12b7b4ba4192c1888001c7164257e4bc6d21d96b4" +checksum = "2c591d83f69777866b9126b24c6dd9a18351f177e49d625920d19f989fd31cf8" [[package]] name = "typenum" @@ -3557,9 +3607,9 @@ checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202" [[package]] name = "unicode-width" -version = "0.1.11" +version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85" +checksum = "68f5e5f3158ecfd4b8ff6fe086db7c8467a2dfdac97fe420f2b7c4aa97af66d6" [[package]] name = "unsafe-libyaml" @@ -3643,7 +3693,7 @@ dependencies = [ "proc-macro-crate 2.0.2", "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.66", ] [[package]] @@ -3656,7 +3706,7 @@ dependencies = [ "proc-macro2", "quote", "shaderc", - "syn 2.0.58", + "syn 2.0.66", "vulkano", ] @@ -3697,7 +3747,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.66", "wasm-bindgen-shared", ] @@ -3731,7 +3781,7 @@ checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.66", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -3744,9 +3794,9 @@ checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" [[package]] name = "wayland-backend" -version = "0.3.3" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d50fa61ce90d76474c87f5fc002828d81b32677340112b4ef08079a9d459a40" +checksum = "34e9e6b6d4a2bb4e7e69433e0b35c7923b95d4dc8503a84d25ec917a4bbfdf07" dependencies = [ "cc", "downcast-rs", @@ -3758,9 +3808,9 @@ dependencies = [ [[package]] name = "wayland-client" -version = "0.31.2" +version = "0.31.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82fb96ee935c2cea6668ccb470fb7771f6215d1691746c2d896b447a00ad3f1f" +checksum = "1e63801c85358a431f986cffa74ba9599ff571fc5774ac113ed3b490c19a1133" dependencies = [ "bitflags 2.5.0", "rustix", @@ -3781,9 +3831,9 @@ dependencies = [ [[package]] name = "wayland-cursor" -version = "0.31.1" +version = "0.31.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71ce5fa868dd13d11a0d04c5e2e65726d0897be8de247c0c5a65886e283231ba" +checksum = "a206e8b2b53b1d3fcb9428fec72bc278ce539e2fa81fe2bfc1ab27703d5187b9" dependencies = [ "rustix", "wayland-client", @@ -3830,9 +3880,9 @@ dependencies = [ [[package]] name = "wayland-scanner" -version = "0.31.1" +version = "0.31.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63b3a62929287001986fb58c789dce9b67604a397c15c611ad9f747300b6c283" +checksum = "67da50b9f80159dec0ea4c11c13e24ef9e7574bd6ce24b01860a175010cea565" dependencies = [ "proc-macro2", "quick-xml 0.31.0", @@ -3841,9 +3891,9 @@ dependencies = [ [[package]] name = "wayland-sys" -version = "0.31.1" +version = "0.31.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15a0c8eaff5216d07f226cb7a549159267f3467b289d9a2e52fd3ef5aae2b7af" +checksum = "105b1842da6554f91526c14a2a2172897b7f745a805d62af4ce698706be79c12" dependencies = [ "dlib", "log", @@ -3901,11 +3951,11 @@ checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-util" -version = "0.1.6" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596" +checksum = "4d4cc384e1e73b93bafa6fb4f1df8c41695c8a91cf9c4c64358067d15a7b6c6b" dependencies = [ - "winapi", + "windows-sys 0.52.0", ] [[package]] @@ -3914,6 +3964,16 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "windows" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e48a53791691ab099e5e2ad123536d0fff50652600abaf43bbf952894110d0be" +dependencies = [ + "windows-core 0.52.0", + "windows-targets 0.52.5", +] + [[package]] name = "windows" version = "0.54.0" @@ -3921,7 +3981,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9252e5725dbed82865af151df558e754e4a3c2c30818359eb17465f1346a1b49" dependencies = [ "windows-core 0.54.0", - "windows-targets 0.52.4", + "windows-targets 0.52.5", ] [[package]] @@ -3930,7 +3990,7 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" dependencies = [ - "windows-targets 0.52.4", + "windows-targets 0.52.5", ] [[package]] @@ -3940,16 +4000,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "12661b9c89351d684a50a8a643ce5f608e20243b9fb84687800163429f161d65" dependencies = [ "windows-result", - "windows-targets 0.52.4", + "windows-targets 0.52.5", ] [[package]] name = "windows-result" -version = "0.1.0" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd19df78e5168dfb0aedc343d1d1b8d422ab2db6756d2dc3fef75035402a3f64" +checksum = "749f0da9cc72d82e600d8d2e44cadd0b9eedb9038f71a1c58556ac1c5791813b" dependencies = [ - "windows-targets 0.52.4", + "windows-targets 0.52.5", ] [[package]] @@ -3976,7 +4036,7 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets 0.52.4", + "windows-targets 0.52.5", ] [[package]] @@ -4011,17 +4071,18 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.52.4" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7dd37b7e5ab9018759f893a1952c9420d060016fc19a472b4bb20d1bdd694d1b" +checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" dependencies = [ - "windows_aarch64_gnullvm 0.52.4", - "windows_aarch64_msvc 0.52.4", - "windows_i686_gnu 0.52.4", - "windows_i686_msvc 0.52.4", - "windows_x86_64_gnu 0.52.4", - "windows_x86_64_gnullvm 0.52.4", - "windows_x86_64_msvc 0.52.4", + "windows_aarch64_gnullvm 0.52.5", + "windows_aarch64_msvc 0.52.5", + "windows_i686_gnu 0.52.5", + "windows_i686_gnullvm", + "windows_i686_msvc 0.52.5", + "windows_x86_64_gnu 0.52.5", + "windows_x86_64_gnullvm 0.52.5", + "windows_x86_64_msvc 0.52.5", ] [[package]] @@ -4038,9 +4099,9 @@ checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" [[package]] name = "windows_aarch64_gnullvm" -version = "0.52.4" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcf46cf4c365c6f2d1cc93ce535f2c8b244591df96ceee75d8e83deb70a9cac9" +checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" [[package]] name = "windows_aarch64_msvc" @@ -4056,9 +4117,9 @@ checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] name = "windows_aarch64_msvc" -version = "0.52.4" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da9f259dd3bcf6990b55bffd094c4f7235817ba4ceebde8e6d11cd0c5633b675" +checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" [[package]] name = "windows_i686_gnu" @@ -4074,9 +4135,15 @@ checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] name = "windows_i686_gnu" -version = "0.52.4" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b474d8268f99e0995f25b9f095bc7434632601028cf86590aea5c8a5cb7801d3" +checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" [[package]] name = "windows_i686_msvc" @@ -4092,9 +4159,9 @@ checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" [[package]] name = "windows_i686_msvc" -version = "0.52.4" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1515e9a29e5bed743cb4415a9ecf5dfca648ce85ee42e15873c3cd8610ff8e02" +checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" [[package]] name = "windows_x86_64_gnu" @@ -4110,9 +4177,9 @@ checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] name = "windows_x86_64_gnu" -version = "0.52.4" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5eee091590e89cc02ad514ffe3ead9eb6b660aedca2183455434b93546371a03" +checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" [[package]] name = "windows_x86_64_gnullvm" @@ -4128,9 +4195,9 @@ checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" [[package]] name = "windows_x86_64_gnullvm" -version = "0.52.4" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77ca79f2451b49fa9e2af39f0747fe999fcda4f5e241b2898624dca97a1f2177" +checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" [[package]] name = "windows_x86_64_msvc" @@ -4146,9 +4213,9 @@ checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "windows_x86_64_msvc" -version = "0.52.4" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32b752e52a2da0ddfbdbcc6fceadfeede4c939ed16d13e648833a61dfb611ed8" +checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" [[package]] name = "winit" @@ -4209,8 +4276,8 @@ dependencies = [ [[package]] name = "wlx-capture" -version = "0.3.8" -source = "git+https://github.com/galister/wlx-capture?tag=v0.3.8#e88ff6c0ceb360c61c5f26ede6a339a2daa09d8b" +version = "0.3.9" +source = "git+https://github.com/galister/wlx-capture?tag=v0.3.10#dacce353e4a0a4778323e96540c053ffefe82bfe" dependencies = [ "ashpd", "drm-fourcc", @@ -4250,6 +4317,7 @@ dependencies = [ "json", "json5", "libc", + "libloading 0.8.3", "log", "log-panics", "once_cell", @@ -4260,15 +4328,19 @@ dependencies = [ "rosc", "serde", "serde_json", + "serde_json5", "serde_yaml", "smallvec", "strum", + "sysinfo", "thiserror", "vulkano", "vulkano-shaders", "winit", "wlx-capture", + "xcb", "xdg", + "xkbcommon", ] [[package]] @@ -4284,9 +4356,9 @@ dependencies = [ [[package]] name = "x11rb" -version = "0.13.0" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8f25ead8c7e4cba123243a6367da5d3990e0d3affa708ea19dce96356bd9f1a" +checksum = "5d91ffca73ee7f68ce055750bf9f6eca0780b8c85eff9bc046a3b0da41755e12" dependencies = [ "as-raw-xcb-connection", "gethostname", @@ -4299,16 +4371,17 @@ dependencies = [ [[package]] name = "x11rb-protocol" -version = "0.13.0" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e63e71c4b8bd9ffec2c963173a4dc4cbde9ee96961d4fcb4429db9929b606c34" +checksum = "ec107c4503ea0b4a98ef47356329af139c0a4f7750e621cf2973cd3385ebcb3d" [[package]] name = "xcb" -version = "1.3.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d27b37e69b8c05bfadcd968eb1a4fe27c9c52565b727f88512f43b89567e262" +checksum = "02e75181b5a62b6eeaa72f303d3cef7dbb841e22885bf6d3e66fe23e88c55dc6" dependencies = [ + "as-raw-xcb-connection", "bitflags 1.3.2", "libc", "quick-xml 0.30.0", @@ -4342,6 +4415,7 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13867d259930edc7091a6c41b4ce6eee464328c6ff9659b7e4c668ca20d4c91e" dependencies = [ + "as-raw-xcb-connection", "libc", "memmap2 0.8.0", "xkeysym", @@ -4421,7 +4495,7 @@ dependencies = [ "async-executor", "async-fs", "async-io", - "async-lock 3.3.0", + "async-lock", "async-process", "async-recursion", "async-task", @@ -4429,7 +4503,7 @@ dependencies = [ "blocking", "derivative", "enumflags2", - "event-listener 5.3.0", + "event-listener", "futures-core", "futures-sink", "futures-util", @@ -4477,22 +4551,22 @@ dependencies = [ [[package]] name = "zerocopy" -version = "0.7.32" +version = "0.7.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74d4d3961e53fa4c9a25a8637fc2bfaf2595b3d3ae34875568a5cf64787716be" +checksum = "ae87e3fcd617500e5d106f0380cf7b77f3c6092aae37191433159dda23cfb087" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.7.32" +version = "0.7.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" +checksum = "15e934569e47891f7d9411f1a451d947a60e000ab3bd24fbb970f000387d1b3b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.66", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 4e4c112..f0bd930 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -30,6 +30,7 @@ input-linux = "0.6.0" json = { version = "0.12.4", optional = true } json5 = "0.4.1" libc = "0.2.153" +libloading = "0.8.3" log = "0.4.21" once_cell = "1.19.0" openxr = { version = "0.17.1", features = ["linked"], optional = true } @@ -48,20 +49,29 @@ serde_json = "1.0.113" serde_yaml = "0.9.34" smallvec = "1.11.0" strum = { version = "0.26.2", features = ["derive"] } +sysinfo = { version = "0.30.0" } thiserror = "1.0.56" vulkano = { git = "https://github.com/vulkano-rs/vulkano", rev = "94f50f1" } vulkano-shaders = { git = "https://github.com/vulkano-rs/vulkano", rev = "94f50f1" } -wlx-capture = { git = "https://github.com/galister/wlx-capture", tag = "v0.3.8", default-features = false } +wlx-capture = { git = "https://github.com/galister/wlx-capture", tag = "v0.3.10", default-features = false } winit = { version = "0.29.15", optional = true } xdg = "2.5.2" log-panics = { version = "2.1.0", features = ["with-backtrace"] } +serde_json5 = "0.1.0" +xkbcommon = { version = "0.7.0" } +xcb = { version = "1.4.0", optional = true, features = [ + "as-raw-xcb-connection", +] } [features] default = ["openvr", "openxr", "osc", "x11", "wayland"] openvr = ["dep:ovr_overlay", "dep:json"] openxr = ["dep:openxr"] osc = ["dep:rosc"] -x11 = ["wlx-capture/xshm"] -wayland = ["wlx-capture/pipewire", "wlx-capture/wlr"] +x11 = ["dep:xcb", "wlx-capture/xshm", "xkbcommon/x11"] +wayland = ["pipewire", "wlx-capture/wlr", "xkbcommon/wayland"] +pipewire = ["wlx-capture/pipewire"] uidev = ["dep:winit"] no-dmabuf = [] +xcb = ["dep:xcb"] +as-raw-xcb-connection = [] diff --git a/src/backend/common.rs b/src/backend/common.rs index 2d9a9c8..888fdc5 100644 --- a/src/backend/common.rs +++ b/src/backend/common.rs @@ -11,6 +11,7 @@ use thiserror::Error; use crate::{ config::AStrSetExt, + hid::{get_keymap_wl, get_keymap_x11}, overlays::{ anchor::create_anchor, keyboard::create_keyboard, @@ -63,17 +64,27 @@ where let mut overlays = IdMap::new(); let mut wl = create_wl_client(); + let keymap; + app.screens.clear(); let data = if let Some(wl) = wl.as_mut() { + keymap = get_keymap_wl().ok(); crate::overlays::screen::create_screens_wayland(wl, app)? } else { - crate::overlays::screen::create_screens_x11(app)? + keymap = get_keymap_x11().ok(); + match crate::overlays::screen::create_screens_x11pw(app) { + Ok(data) => data, + Err(e) => { + log::info!("Will not use PipeWire capture: {:?}", e); + crate::overlays::screen::create_screens_xshm(app)? + } + } }; let mut show_screens = app.session.config.show_screens.clone(); if show_screens.is_empty() { if let Some((_, s, _)) = data.screens.first() { - show_screens.arc_ins(s.name.clone()); + show_screens.arc_set(s.name.clone()); } } @@ -100,7 +111,7 @@ where watch.state.want_visible = true; overlays.insert(watch.state.id, watch); - let mut keyboard = create_keyboard(app)?; + let mut keyboard = create_keyboard(app, keymap)?; keyboard.state.show_hide = true; keyboard.state.want_visible = false; overlays.insert(keyboard.state.id, keyboard); diff --git a/src/backend/input.rs b/src/backend/input.rs index b4bf674..9ca6a7b 100644 --- a/src/backend/input.rs +++ b/src/backend/input.rs @@ -6,7 +6,7 @@ use glam::{Affine3A, Vec2, Vec3, Vec3A, Vec3Swizzles}; use smallvec::{smallvec, SmallVec}; use crate::backend::common::{snap_upright, OverlaySelector}; -use crate::config::{save_state, AStrMapExt, GeneralConfig}; +use crate::config::{AStrMapExt, GeneralConfig}; use crate::overlays::anchor::ANCHOR_NAME; use crate::state::AppState; @@ -531,26 +531,24 @@ impl Pointer { self.interaction.grabbed = None; } } else { - overlay.state.saved_transform = - Some(snap_upright(*anchor, Vec3A::Y).inverse() * overlay.state.transform); - - if let Some(grab_data) = self.interaction.grabbed.as_ref() { - if overlay.state.curvature != grab_data.old_curvature { - if let Some(val) = overlay.state.curvature { - config.curve_values.arc_ins(overlay.state.name.clone(), val); - } else { - let ref_name = overlay.state.name.as_ref(); - config.curve_values.arc_rm(ref_name); + if overlay.state.anchored { + overlay.state.saved_transform = + Some(snap_upright(*anchor, Vec3A::Y).inverse() * overlay.state.transform); + + if let Some(grab_data) = self.interaction.grabbed.as_ref() { + if overlay.state.curvature != grab_data.old_curvature { + if let Some(val) = overlay.state.curvature { + config.curve_values.arc_set(overlay.state.name.clone(), val); + } else { + let ref_name = overlay.state.name.as_ref(); + config.curve_values.arc_rm(ref_name); + } } } - config.transform_values.arc_ins( + config.transform_values.arc_set( overlay.state.name.clone(), overlay.state.saved_transform.unwrap(), ); - match save_state(config) { - Ok(_) => log::debug!("Saved state"), - Err(e) => log::error!("Failed to save state: {:?}", e), - } } self.interaction.grabbed = None; diff --git a/src/backend/openvr/input.rs b/src/backend/openvr/input.rs index 5ee5a81..329d633 100644 --- a/src/backend/openvr/input.rs +++ b/src/backend/openvr/input.rs @@ -318,7 +318,11 @@ fn get_tracked_device( pub fn set_action_manifest(input: &mut InputManager) -> anyhow::Result<()> { let action_path = CONFIG_ROOT_PATH.join("actions.json"); - File::create(&action_path)?.write_all(include_bytes!("../../res/actions.json"))?; + if let Err(e) = File::create(&action_path) + .and_then(|mut f| f.write_all(include_bytes!("../../res/actions.json"))) + { + log::warn!("Could not write action manifest: {}", e); + } let binding_path = CONFIG_ROOT_PATH.join("actions_binding_knuckles.json"); if !binding_path.is_file() { diff --git a/src/backend/openvr/lines.rs b/src/backend/openvr/lines.rs index 547cb9f..ae53a0a 100644 --- a/src/backend/openvr/lines.rs +++ b/src/backend/openvr/lines.rs @@ -80,7 +80,7 @@ impl LinePool { }, ..Default::default() }; - data.data.sort_order = 69; + data.state.z_order = 69; data.state.dirty = true; self.lines.insert(id, data); diff --git a/src/backend/openvr/mod.rs b/src/backend/openvr/mod.rs index dc1e1e8..7966dbd 100644 --- a/src/backend/openvr/mod.rs +++ b/src/backend/openvr/mod.rs @@ -296,6 +296,8 @@ pub fn openvr_run(running: Arc) -> Result<(), BackendError> { } } + state.hid_provider.commit(); + lines.update(universe.clone(), &mut overlay_mgr, &mut state)?; for o in overlays.iter_mut() { @@ -324,8 +326,6 @@ pub fn openvr_run(running: Arc) -> Result<(), BackendError> { // chaperone // close font handles? - - state.hid_provider.on_new_frame(); } log::warn!("OpenVR shutdown"); diff --git a/src/backend/openvr/overlay.rs b/src/backend/openvr/overlay.rs index 897cb72..f300680 100644 --- a/src/backend/openvr/overlay.rs +++ b/src/backend/openvr/overlay.rs @@ -11,7 +11,6 @@ use vulkano::{Handle, VulkanObject}; use crate::{ backend::overlay::{OverlayData, RelativeTo}, graphics::WlxGraphics, - overlays::{anchor::ANCHOR_NAME, watch::WATCH_NAME}, state::AppState, }; @@ -23,7 +22,6 @@ pub(super) struct OpenVrOverlayData { pub(super) last_image: Option, pub(super) visible: bool, pub(super) color: Vec4, - pub(super) sort_order: u32, pub(crate) width: f32, pub(super) override_width: bool, pub(super) relative_to: RelativeTo, @@ -45,15 +43,6 @@ impl OverlayData { }; log::debug!("{}: initialize", self.state.name); - //watch - if *self.state.name == *WATCH_NAME { - self.data.sort_order = 68; - } - - if *self.state.name == *ANCHOR_NAME.as_ref() { - self.data.sort_order = 67; - } - self.data.handle = Some(handle); self.data.color = Vec4::ONE; @@ -193,7 +182,7 @@ impl OverlayData { log::debug!("{}: No overlay handle", self.state.name); return; }; - if let Err(e) = overlay.set_sort_order(handle, self.data.sort_order) { + if let Err(e) = overlay.set_sort_order(handle, self.state.z_order) { log::error!("{}: Failed to set overlay z order: {}", self.state.name, e); } } diff --git a/src/backend/openxr/helpers.rs b/src/backend/openxr/helpers.rs index aadce8d..e3b295e 100644 --- a/src/backend/openxr/helpers.rs +++ b/src/backend/openxr/helpers.rs @@ -1,6 +1,9 @@ +use std::path::PathBuf; + use anyhow::{bail, ensure}; use glam::{Affine3A, Quat, Vec3, Vec3A}; use openxr as xr; +use sysinfo::Process; use xr::OverlaySessionCreateFlagsEXTX; pub(super) fn init_xr() -> Result<(xr::Instance, xr::SystemId), anyhow::Error> { @@ -85,6 +88,7 @@ pub(super) fn init_xr() -> Result<(xr::Instance, xr::SystemId), anyhow::Error> { Ok((xr_instance, system)) } + pub(super) unsafe fn create_overlay_session( instance: &xr::Instance, system: xr::SystemId, @@ -169,3 +173,44 @@ pub(super) fn transform_to_posef(transform: &Affine3A) -> xr::Posef { let rotation = transform_to_norm_quat(transform); translation_rotation_to_posef(translation, rotation) } + +pub(super) fn find_libmonado() -> anyhow::Result { + //check env var first + if let Ok(path) = std::env::var("LIBMONADO_PATH") { + let path = PathBuf::from(path); + if path.exists() { + return Ok(unsafe { libloading::Library::new(path)? }); + } else { + bail!("LIBMONADO_PATH points to a non-existing file."); + } + } + + const PROC_NAMES: [&str; 1] = ["monado-service"]; + let mut system = sysinfo::System::new(); + system.refresh_processes(); + for p in system.processes().values() { + for proc_name in PROC_NAMES.iter() { + if p.name().contains(proc_name) { + if let Some(lib) = proc_load_libmonado(p) { + return Ok(lib); + } + } + } + } + bail!("Could not find libmonado."); +} + +fn proc_load_libmonado(proc: &Process) -> Option { + let path = proc + .exe()? + .parent()? + .parent()? + .join("lib") + .join("libmonado.so"); + + if path.exists() { + Some(unsafe { libloading::Library::new(path).ok()? }) + } else { + None + } +} diff --git a/src/backend/openxr/input.rs b/src/backend/openxr/input.rs index bcc2ef3..0bc055f 100644 --- a/src/backend/openxr/input.rs +++ b/src/backend/openxr/input.rs @@ -2,9 +2,11 @@ use std::time::{Duration, Instant}; use glam::{bool, Affine3A, Quat, Vec3}; use openxr as xr; +use serde::{Deserialize, Serialize}; use crate::{ backend::input::{Haptics, Pointer}, + config_io, state::{AppSession, AppState}, }; @@ -13,52 +15,136 @@ use super::XrState; type XrSession = xr::Session; static DOUBLE_CLICK_TIME: Duration = Duration::from_millis(500); -pub(super) struct DoubleClickCounter { - pub(super) last_click: Option, +pub(super) struct OpenXrAction {} + +pub(super) struct OpenXrInputSource { + action_set: xr::ActionSet, + hands: [OpenXrHand; 2], +} + +pub(super) struct OpenXrHand { + source: OpenXrHandSource, + space: xr::Space, } -impl DoubleClickCounter { - pub(super) fn new() -> Self { - Self { last_click: None } +pub struct CustomClickAction { + action_f32: xr::Action, + action_bool: xr::Action, + action_f32_double: xr::Action, + action_bool_double: xr::Action, + last_click: Option, + held: bool, +} + +impl CustomClickAction { + pub fn new(action_set: &xr::ActionSet, name: &str, side: &str) -> anyhow::Result { + let action_f32 = action_set.create_action::( + &format!("{}_{}_value", side, name), + &format!("{} hand {} value", side, name), + &[], + )?; + let action_f32_double = action_set.create_action::( + &format!("{}_{}_value_double", side, name), + &format!("{} hand {} value double", side, name), + &[], + )?; + + let action_bool = action_set.create_action::( + &format!("{}_{}", side, name), + &format!("{} hand {}", side, name), + &[], + )?; + + let action_bool_double = action_set.create_action::( + &format!("{}_{}_double", side, name), + &format!("{} hand {} double", side, name), + &[], + )?; + + Ok(Self { + action_f32, + action_f32_double, + action_bool, + action_bool_double, + last_click: None, + held: false, + }) + } + pub fn state( + &mut self, + before: bool, + state: &XrState, + session: &AppSession, + ) -> anyhow::Result { + let res = self.action_bool.state(&state.session, xr::Path::NULL)?; + if res.is_active && res.current_state { + return Ok(true); + } + + let res = self + .action_bool_double + .state(&state.session, xr::Path::NULL)?; + if res.is_active && self.check_double_click(res.current_state) { + return Ok(true); + } + + let threshold = if before { + session.config.xr_click_sensitivity_release + } else { + session.config.xr_click_sensitivity + }; + + let res = self.action_f32.state(&state.session, xr::Path::NULL)?; + if res.is_active && res.current_state > threshold { + return Ok(true); + } + + let res = self.action_f32.state(&state.session, xr::Path::NULL)?; + if res.is_active && self.check_double_click(res.current_state > threshold) { + return Ok(true); + } + + Ok(false) } // submit a click. returns true if it should count as a double click - pub(super) fn click(&mut self) -> bool { + fn check_double_click(&mut self, state: bool) -> bool { + if !state { + self.held = false; + return false; + } + + if self.held { + return false; + } + let now = Instant::now(); let double_click = match self.last_click { Some(last_click) => now - last_click < DOUBLE_CLICK_TIME, None => false, }; self.last_click = if double_click { None } else { Some(now) }; + self.held = true; double_click } } -pub(super) struct OpenXrInputSource { - action_set: xr::ActionSet, - hands: [OpenXrHand; 2], -} - -pub(super) struct OpenXrHand { - source: OpenXrHandSource, - space: xr::Space, -} - pub(super) struct OpenXrHandSource { action_pose: xr::Action, - action_click: xr::Action, - action_grab: xr::Action, + action_click: CustomClickAction, + action_grab: CustomClickAction, + action_alt_click: CustomClickAction, + action_show_hide: CustomClickAction, + action_space_drag: CustomClickAction, + action_modifier_right: CustomClickAction, + action_modifier_middle: CustomClickAction, + action_move_mouse: CustomClickAction, action_scroll: xr::Action, - action_alt_click: xr::Action, - action_show_hide: xr::Action, - action_click_modifier_right: xr::Action, - action_click_modifier_middle: xr::Action, - action_move_mouse: xr::Action, action_haptics: xr::Action, } impl OpenXrInputSource { - pub fn new(xr: &XrState) -> Result { + pub fn new(xr: &XrState) -> anyhow::Result { let mut action_set = xr.session .instance() @@ -95,7 +181,7 @@ impl OpenXrInputSource { ); } - pub fn update(&self, xr: &XrState, state: &mut AppState) -> Result<(), xr::sys::Result> { + pub fn update(&mut self, xr: &XrState, state: &mut AppState) -> anyhow::Result<()> { xr.session.sync_actions(&[(&self.action_set).into()])?; for i in 0..2 { @@ -117,11 +203,11 @@ impl OpenXrHand { } pub(super) fn update( - &self, + &mut self, pointer: &mut Pointer, xr: &XrState, session: &AppSession, - ) -> Result<(), xr::sys::Result> { + ) -> anyhow::Result<()> { let location = self.space.locate(&xr.stage, xr.predicted_display_time)?; if location .location_flags @@ -132,31 +218,15 @@ impl OpenXrHand { pointer.pose = Affine3A::from_rotation_translation(quat, pos); } - let click_sensitivity = if pointer.before.click { - session.config.xr_click_sensitivity_release - } else { - session.config.xr_click_sensitivity - }; - pointer.now.click = self .source .action_click - .state(&xr.session, xr::Path::NULL)? - .current_state - > click_sensitivity; - - let grab_sensitivity = if pointer.before.grab { - session.config.xr_grab_sensitivity_release - } else { - session.config.xr_grab_sensitivity - }; + .state(pointer.before.click, xr, session)?; pointer.now.grab = self .source .action_grab - .state(&xr.session, xr::Path::NULL)? - .current_state - > grab_sensitivity; + .state(pointer.before.grab, xr, session)?; pointer.now.scroll = self .source @@ -164,42 +234,37 @@ impl OpenXrHand { .state(&xr.session, xr::Path::NULL)? .current_state; - let alt_click_sensitivity = if pointer.before.alt_click { - session.config.xr_alt_click_sensitivity_release - } else { - session.config.xr_alt_click_sensitivity - }; + pointer.now.alt_click = + self.source + .action_alt_click + .state(pointer.before.alt_click, xr, session)?; - pointer.now.alt_click = self - .source - .action_alt_click - .state(&xr.session, xr::Path::NULL)? - .current_state - > alt_click_sensitivity; + pointer.now.show_hide = + self.source + .action_show_hide + .state(pointer.before.show_hide, xr, session)?; - pointer.now.show_hide = self - .source - .action_show_hide - .state(&xr.session, xr::Path::NULL)? - .current_state; + pointer.now.click_modifier_right = self.source.action_modifier_right.state( + pointer.before.click_modifier_right, + xr, + session, + )?; - pointer.now.click_modifier_right = self - .source - .action_click_modifier_right - .state(&xr.session, xr::Path::NULL)? - .current_state; + pointer.now.click_modifier_middle = self.source.action_modifier_middle.state( + pointer.before.click_modifier_middle, + xr, + session, + )?; - pointer.now.click_modifier_middle = self - .source - .action_click_modifier_middle - .state(&xr.session, xr::Path::NULL)? - .current_state; + pointer.now.move_mouse = + self.source + .action_move_mouse + .state(pointer.before.move_mouse, xr, session)?; - pointer.now.move_mouse = self - .source - .action_move_mouse - .state(&xr.session, xr::Path::NULL)? - .current_state; + pointer.now.space_drag = + self.source + .action_space_drag + .state(pointer.before.space_drag, xr, session)?; Ok(()) } @@ -207,53 +272,18 @@ impl OpenXrHand { // supported action types: Haptic, Posef, Vector2f, f32, bool impl OpenXrHandSource { - pub(super) fn new(action_set: &mut xr::ActionSet, side: &str) -> Result { + pub(super) fn new(action_set: &mut xr::ActionSet, side: &str) -> anyhow::Result { let action_pose = action_set.create_action::( &format!("{}_hand", side), &format!("{} hand pose", side), &[], )?; - let action_click = action_set.create_action::( - &format!("{}_click", side), - &format!("{} hand click", side), - &[], - )?; - let action_grab = action_set.create_action::( - &format!("{}_grab", side), - &format!("{} hand grab", side), - &[], - )?; let action_scroll = action_set.create_action::( &format!("{}_scroll", side), &format!("{} hand scroll", side), &[], )?; - let action_alt_click = action_set.create_action::( - &format!("{}_alt_click", side), - &format!("{} hand alt click", side), - &[], - )?; - let action_show_hide = action_set.create_action::( - &format!("{}_show_hide", side), - &format!("{} hand show/hide", side), - &[], - )?; - let action_click_modifier_right = action_set.create_action::( - &format!("{}_click_modifier_right", side), - &format!("{} hand right click modifier", side), - &[], - )?; - let action_click_modifier_middle = action_set.create_action::( - &format!("{}_click_modifier_middle", side), - &format!("{} hand middle click modifier", side), - &[], - )?; - let action_move_mouse = action_set.create_action::( - &format!("{}_move_mouse", side), - &format!("{} hand mouse move", side), - &[], - )?; let action_haptics = action_set.create_action::( &format!("{}_haptics", side), &format!("{} hand haptics", side), @@ -262,390 +292,247 @@ impl OpenXrHandSource { Ok(Self { action_pose, - action_click, - action_grab, + action_click: CustomClickAction::new(action_set, "click", side)?, + action_grab: CustomClickAction::new(action_set, "grab", side)?, action_scroll, - action_alt_click, - action_show_hide, - action_click_modifier_right, - action_click_modifier_middle, - action_move_mouse, + action_alt_click: CustomClickAction::new(action_set, "alt_click", side)?, + action_show_hide: CustomClickAction::new(action_set, "show_hide", side)?, + action_space_drag: CustomClickAction::new(action_set, "space_drag", side)?, + action_modifier_right: CustomClickAction::new( + action_set, + "click_modifier_right", + side, + )?, + action_modifier_middle: CustomClickAction::new( + action_set, + "click_modifier_middle", + side, + )?, + action_move_mouse: CustomClickAction::new(action_set, "move_mouse", side)?, action_haptics, }) } } -fn suggest_bindings( - instance: &xr::Instance, - hands: &[&OpenXrHandSource; 2], -) -> Result<(), xr::sys::Result> { - let path = instance.string_to_path("/interaction_profiles/khr/simple_controller")?; - - // not fully functional, but helpful for debugging - instance.suggest_interaction_profile_bindings( - path, - &[ - xr::Binding::new( - &hands[0].action_pose, - instance.string_to_path("/user/hand/left/input/aim/pose")?, - ), - xr::Binding::new( - &hands[1].action_pose, - instance.string_to_path("/user/hand/right/input/aim/pose")?, - ), - xr::Binding::new( - &hands[0].action_click, - instance.string_to_path("/user/hand/left/input/select/click")?, - ), - xr::Binding::new( - &hands[1].action_click, - instance.string_to_path("/user/hand/right/input/select/click")?, - ), - xr::Binding::new( - &hands[0].action_show_hide, - instance.string_to_path("/user/hand/left/input/menu/click")?, - ), - xr::Binding::new( - &hands[0].action_haptics, - instance.string_to_path("/user/hand/left/output/haptic")?, - ), - xr::Binding::new( - &hands[1].action_haptics, - instance.string_to_path("/user/hand/right/output/haptic")?, - ), - ], - )?; - - let path = instance.string_to_path("/interaction_profiles/oculus/touch_controller")?; - instance.suggest_interaction_profile_bindings( - path, - &[ - xr::Binding::new( - &hands[0].action_pose, - instance.string_to_path("/user/hand/left/input/aim/pose")?, - ), - xr::Binding::new( - &hands[1].action_pose, - instance.string_to_path("/user/hand/right/input/aim/pose")?, - ), - xr::Binding::new( - &hands[0].action_click, - instance.string_to_path("/user/hand/left/input/trigger/value")?, - ), - xr::Binding::new( - &hands[1].action_click, - instance.string_to_path("/user/hand/right/input/trigger/value")?, - ), - xr::Binding::new( - &hands[0].action_grab, - instance.string_to_path("/user/hand/left/input/squeeze/value")?, - ), - xr::Binding::new( - &hands[1].action_grab, - instance.string_to_path("/user/hand/right/input/squeeze/value")?, - ), - xr::Binding::new( - &hands[0].action_scroll, - instance.string_to_path("/user/hand/left/input/thumbstick/y")?, - ), - xr::Binding::new( - &hands[1].action_scroll, - instance.string_to_path("/user/hand/right/input/thumbstick/y")?, - ), - xr::Binding::new( - &hands[0].action_show_hide, - instance.string_to_path("/user/hand/left/input/y/click")?, - ), - xr::Binding::new( - &hands[0].action_click_modifier_right, - instance.string_to_path("/user/hand/left/input/y/touch")?, - ), - xr::Binding::new( - &hands[1].action_click_modifier_right, - instance.string_to_path("/user/hand/right/input/b/touch")?, - ), - xr::Binding::new( - &hands[0].action_click_modifier_middle, - instance.string_to_path("/user/hand/left/input/x/touch")?, - ), - xr::Binding::new( - &hands[1].action_click_modifier_middle, - instance.string_to_path("/user/hand/right/input/a/touch")?, - ), - xr::Binding::new( - &hands[0].action_move_mouse, - instance.string_to_path("/user/hand/left/input/trigger/touch")?, - ), - xr::Binding::new( - &hands[1].action_move_mouse, - instance.string_to_path("/user/hand/right/input/trigger/touch")?, - ), - xr::Binding::new( - &hands[0].action_haptics, - instance.string_to_path("/user/hand/left/output/haptic")?, - ), - xr::Binding::new( - &hands[1].action_haptics, - instance.string_to_path("/user/hand/right/output/haptic")?, - ), - ], - )?; - - let path = instance.string_to_path("/interaction_profiles/valve/index_controller")?; - instance.suggest_interaction_profile_bindings( - path, - &[ - xr::Binding::new( - &hands[0].action_pose, - instance.string_to_path("/user/hand/left/input/aim/pose")?, - ), - xr::Binding::new( - &hands[1].action_pose, - instance.string_to_path("/user/hand/right/input/aim/pose")?, - ), - xr::Binding::new( - &hands[0].action_click, - instance.string_to_path("/user/hand/left/input/trigger/value")?, - ), - xr::Binding::new( - &hands[1].action_click, - instance.string_to_path("/user/hand/right/input/trigger/value")?, - ), - xr::Binding::new( - &hands[0].action_grab, - instance.string_to_path("/user/hand/left/input/squeeze/force")?, - ), - xr::Binding::new( - &hands[1].action_grab, - instance.string_to_path("/user/hand/right/input/squeeze/force")?, - ), - xr::Binding::new( - &hands[0].action_scroll, - instance.string_to_path("/user/hand/left/input/thumbstick/y")?, - ), - xr::Binding::new( - &hands[1].action_scroll, - instance.string_to_path("/user/hand/right/input/thumbstick/y")?, - ), - xr::Binding::new( - &hands[0].action_alt_click, - instance.string_to_path("/user/hand/left/input/trackpad/force")?, - ), - xr::Binding::new( - &hands[1].action_alt_click, - instance.string_to_path("/user/hand/right/input/trackpad/force")?, - ), - xr::Binding::new( - &hands[0].action_show_hide, - instance.string_to_path("/user/hand/left/input/b/click")?, - ), - xr::Binding::new( - &hands[0].action_click_modifier_right, - instance.string_to_path("/user/hand/left/input/b/touch")?, - ), - xr::Binding::new( - &hands[1].action_click_modifier_right, - instance.string_to_path("/user/hand/right/input/b/touch")?, - ), - xr::Binding::new( - &hands[0].action_click_modifier_middle, - instance.string_to_path("/user/hand/left/input/a/touch")?, - ), - xr::Binding::new( - &hands[1].action_click_modifier_middle, - instance.string_to_path("/user/hand/right/input/a/touch")?, - ), - xr::Binding::new( - &hands[0].action_move_mouse, - instance.string_to_path("/user/hand/left/input/trigger/touch")?, - ), - xr::Binding::new( - &hands[1].action_move_mouse, - instance.string_to_path("/user/hand/right/input/trigger/touch")?, - ), - xr::Binding::new( - &hands[0].action_haptics, - instance.string_to_path("/user/hand/left/output/haptic")?, - ), - xr::Binding::new( - &hands[1].action_haptics, - instance.string_to_path("/user/hand/right/output/haptic")?, - ), - ], - )?; - - let path = instance.string_to_path("/interaction_profiles/htc/vive_controller")?; - instance.suggest_interaction_profile_bindings( - path, - &[ - xr::Binding::new( - &hands[0].action_pose, - instance.string_to_path("/user/hand/left/input/aim/pose")?, - ), - xr::Binding::new( - &hands[1].action_pose, - instance.string_to_path("/user/hand/right/input/aim/pose")?, - ), - xr::Binding::new( - &hands[1].action_click, - instance.string_to_path("/user/hand/right/input/trigger/value")?, - ), - xr::Binding::new( - &hands[0].action_grab, - instance.string_to_path("/user/hand/left/input/squeeze/click")?, - ), - xr::Binding::new( - &hands[1].action_grab, - instance.string_to_path("/user/hand/right/input/squeeze/click")?, - ), - xr::Binding::new( - &hands[0].action_scroll, - instance.string_to_path("/user/hand/left/input/trackpad/y")?, - ), - xr::Binding::new( - &hands[1].action_scroll, - instance.string_to_path("/user/hand/right/input/trackpad/y")?, - ), - xr::Binding::new( - &hands[0].action_show_hide, - instance.string_to_path("/user/hand/left/input/menu/click")?, - ), - xr::Binding::new( - &hands[0].action_haptics, - instance.string_to_path("/user/hand/left/output/haptic")?, - ), - xr::Binding::new( - &hands[1].action_haptics, - instance.string_to_path("/user/hand/right/output/haptic")?, - ), - ], - )?; - - let path = instance.string_to_path("/interaction_profiles/microsoft/motion_controller")?; - instance.suggest_interaction_profile_bindings( - path, - &[ - xr::Binding::new( - &hands[0].action_pose, - instance.string_to_path("/user/hand/left/input/aim/pose")?, - ), - xr::Binding::new( - &hands[1].action_pose, - instance.string_to_path("/user/hand/right/input/aim/pose")?, - ), - xr::Binding::new( - &hands[1].action_click, - instance.string_to_path("/user/hand/right/input/trigger/value")?, - ), - xr::Binding::new( - &hands[0].action_grab, - instance.string_to_path("/user/hand/left/input/squeeze/click")?, - ), - xr::Binding::new( - &hands[1].action_grab, - instance.string_to_path("/user/hand/right/input/squeeze/click")?, - ), - xr::Binding::new( - &hands[0].action_click_modifier_right, - instance.string_to_path("/user/hand/left/input/trackpad/dpad_up")?, - ), - xr::Binding::new( - &hands[1].action_click_modifier_right, - instance.string_to_path("/user/hand/right/input/trackpad/dpad_up")?, - ), - xr::Binding::new( - &hands[0].action_click_modifier_middle, - instance.string_to_path("/user/hand/left/input/trackpad/dpad_down")?, - ), - xr::Binding::new( - &hands[1].action_click_modifier_middle, - instance.string_to_path("/user/hand/right/input/trackpad/dpad_down")?, - ), - xr::Binding::new( - &hands[0].action_scroll, - instance.string_to_path("/user/hand/left/input/thumbstick/y")?, - ), - xr::Binding::new( - &hands[1].action_scroll, - instance.string_to_path("/user/hand/right/input/thumbstick/y")?, - ), - xr::Binding::new( - &hands[0].action_show_hide, - instance.string_to_path("/user/hand/left/input/menu/click")?, - ), - xr::Binding::new( - &hands[0].action_haptics, - instance.string_to_path("/user/hand/left/output/haptic")?, - ), - xr::Binding::new( - &hands[1].action_haptics, - instance.string_to_path("/user/hand/right/output/haptic")?, - ), - ], - )?; - - let path = instance.string_to_path("/interaction_profiles/hp/mixed_reality_controller")?; - instance.suggest_interaction_profile_bindings( - path, - &[ - xr::Binding::new( - &hands[0].action_pose, - instance.string_to_path("/user/hand/left/input/aim/pose")?, - ), - xr::Binding::new( - &hands[1].action_pose, - instance.string_to_path("/user/hand/right/input/aim/pose")?, - ), - xr::Binding::new( - &hands[1].action_click, - instance.string_to_path("/user/hand/right/input/trigger/value")?, - ), - xr::Binding::new( - &hands[0].action_grab, - instance.string_to_path("/user/hand/left/input/squeeze/value")?, - ), - xr::Binding::new( - &hands[1].action_grab, - instance.string_to_path("/user/hand/right/input/squeeze/value")?, - ), - xr::Binding::new( - &hands[0].action_click_modifier_right, - instance.string_to_path("/user/hand/left/input/y/click")?, - ), - xr::Binding::new( - &hands[1].action_click_modifier_right, - instance.string_to_path("/user/hand/right/input/b/click")?, - ), - xr::Binding::new( - &hands[0].action_click_modifier_middle, - instance.string_to_path("/user/hand/left/input/x/click")?, - ), - xr::Binding::new( - &hands[1].action_click_modifier_middle, - instance.string_to_path("/user/hand/right/input/a/click")?, - ), - xr::Binding::new( - &hands[0].action_scroll, - instance.string_to_path("/user/hand/left/input/thumbstick/y")?, - ), - xr::Binding::new( - &hands[1].action_scroll, - instance.string_to_path("/user/hand/right/input/thumbstick/y")?, - ), - xr::Binding::new( - &hands[0].action_show_hide, - instance.string_to_path("/user/hand/left/input/menu/click")?, - ), - xr::Binding::new( - &hands[0].action_haptics, - instance.string_to_path("/user/hand/left/output/haptic")?, - ), - xr::Binding::new( - &hands[1].action_haptics, - instance.string_to_path("/user/hand/right/output/haptic")?, - ), - ], - )?; +fn to_path(maybe_path_str: &Option, instance: &xr::Instance) -> Option { + maybe_path_str + .as_ref() + .and_then(|s| match instance.string_to_path(s) { + Ok(path) => Some(path), + Err(_) => { + log::warn!("Invalid binding path: {}", s); + None + } + }) +} + +fn is_bool(maybe_type_str: &Option) -> bool { + maybe_type_str + .as_ref() + .unwrap() + .split('/') + .last() + .map(|last| matches!(last, "click" | "touch")) + .unwrap_or(false) +} + +macro_rules! add_custom { + ($action:expr, $left:expr, $right:expr, $bindings:expr, $instance:expr) => { + if let Some(action) = $action.as_ref() { + if let Some(p) = to_path(&action.left, $instance) { + if is_bool(&action.left) { + if action.double_click.unwrap_or(false) { + $bindings.push(xr::Binding::new(&$left.action_bool_double, p)); + } else { + $bindings.push(xr::Binding::new(&$left.action_bool, p)); + } + } else { + if action.double_click.unwrap_or(false) { + $bindings.push(xr::Binding::new(&$left.action_f32_double, p)); + } else { + $bindings.push(xr::Binding::new(&$left.action_f32, p)); + } + } + } + if let Some(p) = to_path(&action.right, $instance) { + if is_bool(&action.right) { + if action.double_click.unwrap_or(false) { + $bindings.push(xr::Binding::new(&$right.action_bool_double, p)); + } else { + $bindings.push(xr::Binding::new(&$right.action_bool, p)); + } + } else { + if action.double_click.unwrap_or(false) { + $bindings.push(xr::Binding::new(&$right.action_f32_double, p)); + } else { + $bindings.push(xr::Binding::new(&$right.action_f32, p)); + } + } + } + } + }; +} + +fn suggest_bindings(instance: &xr::Instance, hands: &[&OpenXrHandSource; 2]) -> anyhow::Result<()> { + let profiles = load_action_profiles()?; + + for profile in profiles { + let Ok(profile_path) = instance.string_to_path(&profile.profile) else { + log::debug!("Profile not supported: {}", profile.profile); + continue; + }; + + let mut bindings: Vec = vec![]; + + if let Some(action) = profile.pose { + if let Some(p) = to_path(&action.left, instance) { + bindings.push(xr::Binding::new(&hands[0].action_pose, p)); + } + if let Some(p) = to_path(&action.right, instance) { + bindings.push(xr::Binding::new(&hands[1].action_pose, p)); + } + } + + if let Some(action) = profile.haptic { + if let Some(p) = to_path(&action.left, instance) { + bindings.push(xr::Binding::new(&hands[0].action_haptics, p)); + } + if let Some(p) = to_path(&action.right, instance) { + bindings.push(xr::Binding::new(&hands[1].action_haptics, p)); + } + } + + if let Some(action) = profile.scroll { + if let Some(p) = to_path(&action.left, instance) { + bindings.push(xr::Binding::new(&hands[0].action_scroll, p)); + } + if let Some(p) = to_path(&action.right, instance) { + bindings.push(xr::Binding::new(&hands[1].action_scroll, p)); + } + } + + add_custom!( + profile.click, + hands[0].action_click, + hands[1].action_click, + bindings, + instance + ); + + add_custom!( + profile.alt_click, + &hands[0].action_alt_click, + &hands[1].action_alt_click, + bindings, + instance + ); + + add_custom!( + profile.grab, + &hands[0].action_grab, + &hands[1].action_grab, + bindings, + instance + ); + + add_custom!( + profile.show_hide, + &hands[0].action_show_hide, + &hands[1].action_show_hide, + bindings, + instance + ); + + add_custom!( + profile.space_drag, + &hands[0].action_space_drag, + &hands[1].action_space_drag, + bindings, + instance + ); + + add_custom!( + profile.click_modifier_right, + &hands[0].action_modifier_right, + &hands[1].action_modifier_right, + bindings, + instance + ); + + add_custom!( + profile.click_modifier_middle, + &hands[0].action_modifier_middle, + &hands[1].action_modifier_middle, + bindings, + instance + ); + + add_custom!( + profile.move_mouse, + &hands[0].action_move_mouse, + &hands[1].action_move_mouse, + bindings, + instance + ); + + if instance + .suggest_interaction_profile_bindings(profile_path, &bindings) + .is_err() + { + log::error!("Bad bindings for {}", &profile.profile[22..]); + log::error!("Verify config: ~/.config/wlxoverlay/openxr_actions.json5"); + } + } Ok(()) } + +#[derive(Debug, Clone, Serialize, Deserialize)] +struct OpenXrActionConfAction { + left: Option, + right: Option, + threshold: Option<[f32; 2]>, + double_click: Option, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +struct OpenXrActionConfProfile { + profile: String, + pose: Option, + click: Option, + grab: Option, + alt_click: Option, + show_hide: Option, + space_drag: Option, + click_modifier_right: Option, + click_modifier_middle: Option, + move_mouse: Option, + scroll: Option, + haptic: Option, +} + +const DEFAULT_PROFILES: &str = include_str!("openxr_actions.json5"); + +fn load_action_profiles() -> anyhow::Result> { + let mut profiles: Vec = + serde_json5::from_str(DEFAULT_PROFILES).unwrap(); // want panic + + let Some(conf) = config_io::load("openxr_actions.json5") else { + return Ok(profiles); + }; + + match serde_json5::from_str::>(&conf) { + Ok(override_profiles) => { + override_profiles.into_iter().for_each(|new| { + if let Some(i) = profiles.iter().position(|old| old.profile == new.profile) { + profiles[i] = new; + } + }); + } + Err(e) => { + log::error!("Failed to load openxr_actions.json5: {}", e); + } + } + + Ok(profiles) +} diff --git a/src/backend/openxr/lines.rs b/src/backend/openxr/lines.rs index e616b9a..0f53663 100644 --- a/src/backend/openxr/lines.rs +++ b/src/backend/openxr/lines.rs @@ -148,7 +148,6 @@ impl LinePool { 1.0, )?) .eye_visibility(xr::EyeVisibility::BOTH) - .layer_flags(xr::CompositionLayerFlags::CORRECT_CHROMATIC_ABERRATION) .space(&xr.stage) .size(xr::Extent2Df { width: LINE_WIDTH, diff --git a/src/backend/openxr/mod.rs b/src/backend/openxr/mod.rs index c409564..4ccb39e 100644 --- a/src/backend/openxr/mod.rs +++ b/src/backend/openxr/mod.rs @@ -16,9 +16,9 @@ use crate::{ common::{BackendError, OverlayContainer}, input::interact, notifications::NotificationManager, - openxr::{input::DoubleClickCounter, lines::LinePool, overlay::OpenXrOverlayData}, + openxr::{lines::LinePool, overlay::OpenXrOverlayData}, overlay::OverlayData, - task::TaskType, + task::{SystemTask, TaskType}, }, graphics::WlxGraphics, overlays::{ @@ -32,6 +32,7 @@ mod helpers; mod input; mod lines; mod overlay; +mod playspace; mod swapchain; const VIEW_TYPE: xr::ViewConfigurationType = xr::ViewConfigurationType::PRIMARY_STEREO; @@ -44,6 +45,7 @@ struct XrState { session: xr::Session, predicted_display_time: xr::Time, stage: Arc, + stage_offset: Affine3A, } pub fn openxr_run(running: Arc) -> Result<(), BackendError> { @@ -72,6 +74,9 @@ pub fn openxr_run(running: Arc) -> Result<(), BackendError> { notifications.run_udp(); let mut delete_queue = vec![]; + let mut playspace = playspace::PlayspaceMover::try_new() + .map_err(|e| log::warn!("Will not use Monado playspace mover: {}", e)) + .ok(); #[cfg(feature = "osc")] let mut osc_sender = @@ -106,6 +111,7 @@ pub fn openxr_run(running: Arc) -> Result<(), BackendError> { session, predicted_display_time: xr::Time::from_nanos(0), stage: Arc::new(stage), + stage_offset: Affine3A::IDENTITY, }; let pointer_lines = [ @@ -115,12 +121,11 @@ pub fn openxr_run(running: Arc) -> Result<(), BackendError> { let watch_id = overlays.get_by_name(WATCH_NAME).unwrap().state.id; // want panic - let input_source = input::OpenXrInputSource::new(&xr_state)?; + let mut input_source = input::OpenXrInputSource::new(&xr_state)?; let mut session_running = false; let mut event_storage = xr::EventDataBuffer::new(); - let mut show_hide_counter = DoubleClickCounter::new(); let mut due_tasks = VecDeque::with_capacity(4); 'main_loop: loop { @@ -198,12 +203,14 @@ pub fn openxr_run(running: Arc) -> Result<(), BackendError> { .pointers .iter() .any(|p| p.now.show_hide && !p.before.show_hide) - && show_hide_counter.click() { overlays.show_hide(&mut app_state); } watch_fade(&mut app_state, overlays.mut_by_id(watch_id).unwrap()); // want panic + if let Some(ref mut space_mover) = playspace { + space_mover.update(&mut overlays, &app_state); + } for o in overlays.iter_mut() { o.after_input(&mut app_state)?; @@ -251,6 +258,8 @@ pub fn openxr_run(running: Arc) -> Result<(), BackendError> { } } + app_state.hid_provider.commit(); + let watch = overlays.mut_by_id(watch_id).unwrap(); // want panic let watch_transform = watch.state.transform; if !watch.state.want_visible { @@ -280,7 +289,8 @@ pub fn openxr_run(running: Arc) -> Result<(), BackendError> { o.render(&mut app_state)?; let dist_sq = (app_state.input_state.hmd.translation - o.state.transform.translation) - .length_squared(); + .length_squared() + + (100f32 - o.state.z_order as f32); if !dist_sq.is_normal() { continue; @@ -363,16 +373,24 @@ pub fn openxr_run(running: Arc) -> Result<(), BackendError> { } } } - TaskType::System(_task) => { - // Not implemented - } + TaskType::System(task) => match task { + SystemTask::FixFloor => { + if let Some(ref mut playspace) = playspace { + playspace.fix_floor(&app_state.input_state); + } + } + SystemTask::ResetPlayspace => { + if let Some(ref mut playspace) = playspace { + playspace.reset_offset(); + } + } + _ => {} + }, } } delete_queue.retain(|(_, frame)| *frame > cur_frame); - app_state.hid_provider.on_new_frame(); - let watch = overlays.mut_by_id(watch_id).unwrap(); // want panic watch.state.transform = watch_transform; } diff --git a/src/backend/openxr/openxr_actions.json5 b/src/backend/openxr/openxr_actions.json5 new file mode 100644 index 0000000..86618c2 --- /dev/null +++ b/src/backend/openxr/openxr_actions.json5 @@ -0,0 +1,243 @@ +// Available bindings: +// +// -- click -- +// primary click to interact with the watch or overlays. required +// +// -- grab -- +// used to manipulate position, size, orientation of overlays in 3D space +// +// -- show_hide -- +// used to quickly hide and show your last selection of screens + keyboard +// +// -- space_drag -- +// move your stage (playspace drag) +// +// -- space_rotate -- +// rotate your stage (playspace rotate, WIP) +// +// -- click_modifier_right -- +// while this is held, your pointer will turn ORANGE and your mouse clicks will be RIGHT clicks +// +// -- click_modifier_middle -- +// while this is held, your pointer will turn PURPLE and your mouse clicks will be MIDDLE clicks +// +// -- move_mouse -- +// when using `focus_follows_mouse_mode`, you need to hold this for the mouse to move +// +// -- pose, haptic -- +// do not mess with these, unless you know what you're doing + +[ + // Fallback controller, intended for testing + { + profile: "/interaction_profiles/khr/simple_controller", + pose: { + left: "/user/hand/left/input/aim/pose", + right: "/user/hand/right/input/aim/pose" + }, + haptic: { + left: "/user/hand/left/output/haptic", + right: "/user/hand/right/output/haptic" + }, + click: { + // left trigger is click + left: "/user/hand/left/input/select/click", + }, + grab: { + // right trigger is grab + right: "/user/hand/right/input/select/click" + }, + show_hide: { + left: "/user/hand/left/input/menu/click" + } + }, + + // Oculus Touch Controller. Compatible with Quest 2, Quest 3, Quest Pro + { + profile: "/interaction_profiles/oculus/touch_controller", + pose: { + left: "/user/hand/left/input/aim/pose", + right: "/user/hand/right/input/aim/pose" + }, + haptic: { + left: "/user/hand/left/output/haptic", + right: "/user/hand/right/output/haptic" + }, + click: { + left: "/user/hand/left/input/trigger/value", + right: "/user/hand/right/input/trigger/value" + }, + grab: { + left: "/user/hand/left/input/squeeze/value", + right: "/user/hand/right/input/squeeze/value" + }, + scroll: { + left: "/user/hand/left/input/thumbstick/y", + right: "/user/hand/right/input/thumbstick/y" + }, + show_hide: { + double_click: true, + left: "/user/hand/left/input/y/click", + }, + space_drag: { + left: "/user/hand/left/input/menu/click", + }, + click_modifier_right: { + left: "/user/hand/left/input/y/touch", + right: "/user/hand/right/input/b/touch" + }, + click_modifier_middle: { + left: "/user/hand/left/input/x/touch", + right: "/user/hand/right/input/a/touch" + }, + mouse_move: { + // used with focus_follows_mouse_mode + left: "/user/hand/left/input/trigger/touch", + right: "/user/hand/right/input/trigger/touch" + } + }, + + // Index controller + { + profile: "/interaction_profiles/valve/index_controller", + pose: { + left: "/user/hand/left/input/aim/pose", + right: "/user/hand/right/input/aim/pose" + }, + haptic: { + left: "/user/hand/left/output/haptic", + right: "/user/hand/right/output/haptic" + }, + click: { + left: "/user/hand/left/input/trigger/value", + right: "/user/hand/right/input/trigger/value" + }, + alt_click: { + // left trackpad is space_drag + right: "/user/hand/right/input/trackpad/force", + }, + grab: { + left: "/user/hand/left/input/squeeze/force", + right: "/user/hand/right/input/squeeze/force" + }, + scroll: { + left: "/user/hand/left/input/thumbstick/y", + right: "/user/hand/right/input/thumbstick/y" + }, + show_hide: { + double_click: true, + left: "/user/hand/left/input/b/click", + }, + space_drag: { + left: "/user/hand/left/input/trackpad/force", + // right trackpad is alt_click + }, + click_modifier_right: { + left: "/user/hand/left/input/b/touch", + right: "/user/hand/right/input/b/touch" + }, + click_modifier_middle: { + left: "/user/hand/left/input/a/touch", + right: "/user/hand/right/input/a/touch" + }, + mouse_move: { + // used with focus_follows_mouse_mode + left: "/user/hand/left/input/trigger/touch", + right: "/user/hand/right/input/trigger/touch" + } + }, + + // Vive controller + { + profile: "/interaction_profiles/htc/vive_controller", + pose: { + left: "/user/hand/left/input/aim/pose", + right: "/user/hand/right/input/aim/pose" + }, + click: { + left: "/user/hand/left/input/trigger/value", + right: "/user/hand/right/input/trigger/value" + }, + grab: { + left: "/user/hand/left/input/squeeze/click", + right: "/user/hand/right/input/squeeze/click" + }, + scroll: { + left: "/user/hand/left/input/trackpad/y", + right: "/user/hand/right/input/trackpad/y" + }, + show_hide: { + left: "/user/hand/left/input/menu/click", + }, + space_drag: { + right: "/user/hand/right/input/menu/click", + }, + haptic: { + left: "/user/hand/left/output/haptic", + right: "/user/hand/right/output/haptic" + } + }, + + // Windows Mixed Reality controller + { + profile: "/interaction_profiles/microsoft/motion_controller", + pose: { + left: "/user/hand/left/input/aim/pose", + right: "/user/hand/right/input/aim/pose" + }, + haptic: { + left: "/user/hand/left/output/haptic", + right: "/user/hand/right/output/haptic" + }, + click: { + left: "/user/hand/left/input/trigger/value", + right: "/user/hand/right/input/trigger/value" + }, + grab: { + left: "/user/hand/left/input/squeeze/click", + right: "/user/hand/right/input/squeeze/click" + }, + scroll: { + left: "/user/hand/left/input/thumbstick/y", + right: "/user/hand/right/input/thumbstick/y" + }, + show_hide: { + left: "/user/hand/left/input/menu/click", + }, + space_drag: { + right: "/user/hand/right/input/menu/click", + }, + }, + + // HP Reverb G2 controller + { + profile: "/interaction_profiles/hp/mixed_reality_controller", + pose: { + left: "/user/hand/left/input/aim/pose", + right: "/user/hand/right/input/aim/pose" + }, + haptic: { + left: "/user/hand/left/output/haptic", + right: "/user/hand/right/output/haptic" + }, + click: { + left: "/user/hand/left/input/trigger/value", + right: "/user/hand/right/input/trigger/value" + }, + grab: { + left: "/user/hand/left/input/squeeze/value", + right: "/user/hand/right/input/squeeze/value" + }, + scroll: { + left: "/user/hand/left/input/thumbstick/y", + right: "/user/hand/right/input/thumbstick/y" + }, + show_hide: { + left: "/user/hand/left/input/menu/click", + }, + space_drag: { + right: "/user/hand/right/input/menu/click", + }, + }, + +] diff --git a/src/backend/openxr/overlay.rs b/src/backend/openxr/overlay.rs index 1d362af..33889ae 100644 --- a/src/backend/openxr/overlay.rs +++ b/src/backend/openxr/overlay.rs @@ -1,7 +1,7 @@ use glam::Vec3A; use openxr as xr; use std::{f32::consts::PI, sync::Arc}; -use xr::{CompositionLayerFlags, EyeVisibility}; +use xr::EyeVisibility; use super::{helpers, swapchain::SwapchainRenderData, CompositionLayer, XrState}; use crate::{ @@ -78,7 +78,6 @@ impl OverlayData { .pose(posef) .sub_image(sub_image) .eye_visibility(EyeVisibility::BOTH) - .layer_flags(CompositionLayerFlags::CORRECT_CHROMATIC_ABERRATION) .space(&xr.stage) .radius(radius) .central_angle(angle) @@ -90,7 +89,6 @@ impl OverlayData { .pose(posef) .sub_image(sub_image) .eye_visibility(EyeVisibility::BOTH) - .layer_flags(CompositionLayerFlags::CORRECT_CHROMATIC_ABERRATION) .space(&xr.stage) .size(xr::Extent2Df { width: scale_x, diff --git a/src/backend/openxr/playspace.rs b/src/backend/openxr/playspace.rs new file mode 100644 index 0000000..f801f55 --- /dev/null +++ b/src/backend/openxr/playspace.rs @@ -0,0 +1,180 @@ +use std::ffi::c_void; + +use glam::{Affine3A, Quat, Vec3A}; +use libloading::{Library, Symbol}; + +use crate::{ + backend::{common::OverlayContainer, input::InputState}, + state::AppState, +}; + +use super::{helpers, overlay::OpenXrOverlayData}; + +#[repr(C)] +struct XrtPose { + orientation: [f32; 4], + position: [f32; 3], +} + +struct MoverData { + pose: Affine3A, + hand: usize, + hand_pose: T, +} + +// Legacy implementation +type PlaySpaceMove = extern "C" fn(*mut c_void, f32, f32, f32) -> i32; + +// New implementation +type ApplyStageOffset = extern "C" fn(*mut c_void, *const XrtPose) -> i32; + +enum ApiImpl { + None, + PlaySpaceMove(PlaySpaceMove), + ApplyStageOffset(ApplyStageOffset), +} + +pub(super) struct PlayspaceMover { + last_transform: Affine3A, + drag: Option>, + + libmonado: Library, + mnd_root: *mut c_void, + api_impl: ApiImpl, +} + +impl PlayspaceMover { + pub fn try_new() -> anyhow::Result { + unsafe { + let libmonado = helpers::find_libmonado()?; + + let root_create: Symbol i32> = + libmonado.get(b"mnd_root_create\0")?; + + let mut api_impl = ApiImpl::None; + if let Ok(playspace_move) = libmonado.get(b"mnd_root_playspace_move\0") { + log::info!("Monado: using playspace_move"); + api_impl = ApiImpl::PlaySpaceMove(*playspace_move); + } else if let Ok(apply_stage_offset) = libmonado.get(b"mnd_root_apply_stage_offset\0") { + log::info!("Monado: using apply_stage_offset"); + api_impl = ApiImpl::ApplyStageOffset(*apply_stage_offset); + } + + if let ApiImpl::None = api_impl { + anyhow::bail!("Monado does not support playspace mover."); + } + + let mut root: *mut c_void = std::ptr::null_mut(); + + let ret = root_create(&mut root); + + if ret != 0 { + anyhow::bail!("Failed to create root, code: {}", ret); + } + + Ok(Self { + last_transform: Affine3A::IDENTITY, + drag: None, + + libmonado, + mnd_root: root, + api_impl, + }) + } + } + + pub fn update(&mut self, overlays: &mut OverlayContainer, state: &AppState) { + if let Some(mut data) = self.drag.take() { + let pointer = &state.input_state.pointers[data.hand]; + if !pointer.now.space_drag { + self.last_transform = data.pose; + log::info!("End space drag"); + return; + } + + let new_hand = data + .pose + .transform_point3a(state.input_state.pointers[data.hand].pose.translation); + let relative_pos = new_hand - data.hand_pose; + + if relative_pos.length_squared() > 1000.0 { + log::warn!("Space drag too fast, ignoring"); + return; + } + + let overlay_offset = data.pose.inverse().transform_vector3a(relative_pos) * -1.0; + + overlays.iter_mut().for_each(|overlay| { + if overlay.state.grabbable { + overlay.state.dirty = true; + overlay.state.transform.translation += overlay_offset; + } + }); + + data.pose.translation += relative_pos; + data.hand_pose = new_hand; + + self.apply_offset(data.pose); + self.drag = Some(data); + } else { + for (i, pointer) in state.input_state.pointers.iter().enumerate() { + if pointer.now.space_drag { + let hand_pos = self + .last_transform + .transform_point3a(pointer.pose.translation); + self.drag = Some(MoverData { + pose: self.last_transform, + hand: i, + hand_pose: hand_pos, + }); + log::info!("Start space drag"); + return; + } + } + } + } + + pub fn reset_offset(&mut self) { + if self.drag.is_some() { + log::info!("Cannot reset offset while dragging."); + return; + } + + self.last_transform = Affine3A::IDENTITY; + self.apply_offset(self.last_transform); + } + + pub fn fix_floor(&mut self, input: &InputState) { + if self.drag.is_some() { + log::info!("Cannot fix floor while dragging."); + return; + } + + let y1 = input.pointers[0].pose.translation.y; + let y2 = input.pointers[1].pose.translation.y; + let delta = y1.min(y2) - 0.03; + self.last_transform.translation.y += delta; + self.apply_offset(self.last_transform); + } + + fn apply_offset(&self, transform: Affine3A) { + match self.api_impl { + ApiImpl::PlaySpaceMove(playspace_move) => { + (playspace_move)( + self.mnd_root, + transform.translation.x, + transform.translation.y, + transform.translation.z, + ); + } + ApiImpl::ApplyStageOffset(apply_stage_offset) => { + let xrt_pose = XrtPose { + orientation: Quat::from_affine3(&transform).into(), + position: transform.translation.into(), + }; + (apply_stage_offset)(self.mnd_root, &xrt_pose); + } + ApiImpl::None => {} + } + } +} diff --git a/src/backend/overlay.rs b/src/backend/overlay.rs index a1bff02..4244aa9 100644 --- a/src/backend/overlay.rs +++ b/src/backend/overlay.rs @@ -29,8 +29,10 @@ pub struct OverlayState { pub grabbable: bool, pub interactable: bool, pub recenter: bool, + pub anchored: bool, pub dirty: bool, pub alpha: f32, + pub z_order: u32, pub transform: Affine3A, pub spawn_scale: f32, // aka width pub spawn_point: Vec3A, @@ -53,8 +55,10 @@ impl Default for OverlayState { grabbable: false, recenter: false, interactable: false, + anchored: false, dirty: true, alpha: 1.0, + z_order: 0, relative_to: RelativeTo::None, curvature: None, spawn_scale: 1.0, @@ -96,9 +100,18 @@ where impl OverlayState { pub fn parent_transform(&self, app: &AppState) -> Option { match self.relative_to { - RelativeTo::None => None, RelativeTo::Head => Some(app.input_state.hmd), RelativeTo::Hand(idx) => Some(app.input_state.pointers[idx].pose), + _ => None, + } + } + + fn get_anchor(&self, app: &AppState) -> Affine3A { + if self.anchored { + app.anchor + } else { + // fake anchor that's always in front of HMD + app.input_state.hmd } } @@ -124,7 +137,10 @@ impl OverlayState { self.saved_transform = None; } - self.transform = self.parent_transform(app).unwrap_or(app.anchor) * self.get_transform(); + self.transform = self + .parent_transform(app) + .unwrap_or_else(|| self.get_anchor(app)) + * self.get_transform(); if self.grabbable && hard_reset { self.realign(&app.input_state.hmd); @@ -185,19 +201,21 @@ where .arc_get(self.state.name.as_ref()) .copied(); - let hard_reset; - if let Some(transform) = app - .session - .config - .transform_values - .arc_get(self.state.name.as_ref()) - { - self.state.saved_transform = Some(*transform); - hard_reset = false; - } else { - hard_reset = true; + if matches!(self.state.relative_to, RelativeTo::None) { + let hard_reset; + if let Some(transform) = app + .session + .config + .transform_values + .arc_get(self.state.name.as_ref()) + { + self.state.saved_transform = Some(*transform); + hard_reset = false; + } else { + hard_reset = true; + } + self.state.reset(app, hard_reset); } - self.state.reset(app, hard_reset); self.backend.init(app) } pub fn render(&mut self, app: &mut AppState) -> anyhow::Result<()> { @@ -251,10 +269,15 @@ impl OverlayRenderer for FallbackRenderer { #[derive(Clone, Copy, Debug, Default)] pub enum RelativeTo { + /// Stays in place unless rencentered #[default] None, + /// Stays in position relative to HMD Head, + /// Stays in position relative to hand Hand(usize), + /// Stays in place, no recentering + Stage, } pub struct SplitOverlayBackend { diff --git a/src/config.rs b/src/config.rs index cba7ccc..d544a6f 100644 --- a/src/config.rs +++ b/src/config.rs @@ -23,16 +23,15 @@ use serde::Serialize; pub type AStrMap = Vec<(Arc, V)>; pub trait AStrMapExt { - fn arc_ins(&mut self, key: Arc, value: V) -> bool; + fn arc_set(&mut self, key: Arc, value: V) -> bool; fn arc_get(&self, key: &str) -> Option<&V>; fn arc_rm(&mut self, key: &str) -> Option; } impl AStrMapExt for AStrMap { - fn arc_ins(&mut self, key: Arc, value: V) -> bool { - if self.iter().any(|(k, _)| k.as_ref().eq(key.as_ref())) { - return false; - } + fn arc_set(&mut self, key: Arc, value: V) -> bool { + let index = self.iter().position(|(k, _)| k.as_ref().eq(key.as_ref())); + index.map(|i| self.remove(i).1); self.push((key, value)); true } @@ -51,13 +50,13 @@ impl AStrMapExt for AStrMap { pub type AStrSet = Vec>; pub trait AStrSetExt { - fn arc_ins(&mut self, value: Arc) -> bool; + fn arc_set(&mut self, value: Arc) -> bool; fn arc_get(&self, value: &str) -> bool; fn arc_rm(&mut self, value: &str) -> bool; } impl AStrSetExt for AStrSet { - fn arc_ins(&mut self, value: Arc) -> bool { + fn arc_set(&mut self, value: Arc) -> bool { if self.iter().any(|v| v.as_ref().eq(value.as_ref())) { return false; } @@ -416,7 +415,7 @@ fn get_state_path() -> PathBuf { path } -pub fn save_state(config: &GeneralConfig) -> anyhow::Result<()> { +pub fn save_layout(config: &GeneralConfig) -> anyhow::Result<()> { let conf = AutoState { show_screens: config.show_screens.clone(), curve_values: config.curve_values.clone(), diff --git a/src/graphics.rs b/src/graphics.rs index 1cb4c4e..762f89d 100644 --- a/src/graphics.rs +++ b/src/graphics.rs @@ -92,10 +92,12 @@ use vulkano::{ }; use wlx_capture::frame::{ - DmabufFrame, FourCC, DRM_FORMAT_ABGR8888, DRM_FORMAT_ARGB8888, DRM_FORMAT_XBGR8888, - DRM_FORMAT_XRGB8888, + DmabufFrame, FourCC, DRM_FORMAT_ABGR2101010, DRM_FORMAT_ABGR8888, DRM_FORMAT_ARGB8888, + DRM_FORMAT_XBGR2101010, DRM_FORMAT_XBGR8888, DRM_FORMAT_XRGB8888, }; +pub const DRM_FORMAT_MOD_INVALID: u64 = 0xff_ffff_ffff_ffff; + #[repr(C)] #[derive(BufferContents, Vertex, Copy, Clone, Debug)] pub struct Vert2Uv { @@ -107,11 +109,6 @@ pub struct Vert2Uv { pub const INDICES: [u16; 6] = [2, 1, 0, 1, 2, 3]; -#[cfg(not(feature = "no-dmabuf"))] -pub const DMA_BUF_SUPPORTED: bool = true; -#[cfg(feature = "no-dmabuf")] -pub const DMA_BUF_SUPPORTED: bool = false; - pub const BLEND_ALPHA: AttachmentBlend = AttachmentBlend { src_color_blend_factor: BlendFactor::SrcAlpha, dst_color_blend_factor: BlendFactor::OneMinusSrcAlpha, @@ -261,7 +258,14 @@ impl WlxGraphics { .position(|(_, q)| q.queue_flags.intersects(QueueFlags::GRAPHICS)) .expect("Vulkan device has no graphics queue") as u32; - let device_extensions = get_device_extensions(); + let mut device_extensions = get_device_extensions(); + if !physical_device + .supported_extensions() + .ext_image_drm_format_modifier + { + device_extensions.ext_image_drm_format_modifier = false; + } + let device_extensions_raw = device_extensions .into_iter() .filter_map(|(name, enabled)| { @@ -404,10 +408,16 @@ impl WlxGraphics { p.properties().device_name, &runtime_extensions ); - let my_extensions = runtime_extensions.union(&device_extensions); + let mut my_extensions = runtime_extensions.union(&device_extensions); if p.supported_extensions().contains(&my_extensions) { Some((p, my_extensions)) } else { + // try without DRM format modifiers + my_extensions.ext_image_drm_format_modifier = false; + if p.supported_extensions().contains(&my_extensions) { + return Some((p, my_extensions)); + } + log::debug!( "Not using {} because it does not implement the following device extensions:", p.properties().device_name, @@ -742,18 +752,24 @@ impl WlxGraphics { let format = fourcc_to_vk(frame.format.fourcc)?; - let layouts: Vec = (0..frame.num_planes) - .map(|i| { + let mut tiling: ImageTiling = ImageTiling::Optimal; + let mut modifiers: Vec = vec![]; + let mut layouts: Vec = vec![]; + + if frame.format.modifier != DRM_FORMAT_MOD_INVALID { + (0..frame.num_planes).for_each(|i| { let plane = &frame.planes[i]; - SubresourceLayout { + layouts.push(SubresourceLayout { offset: plane.offset as _, size: 0, row_pitch: plane.stride as _, array_pitch: None, depth_pitch: None, - } - }) - .collect(); + }); + modifiers.push(frame.format.modifier); + }); + tiling = ImageTiling::DrmFormatModifier; + }; let image = unsafe { RawImage::new_unchecked( @@ -763,8 +779,8 @@ impl WlxGraphics { extent, usage: ImageUsage::SAMPLED, external_memory_handle_types: ExternalMemoryHandleTypes::DMA_BUF, - tiling: ImageTiling::DrmFormatModifier, - drm_format_modifiers: vec![frame.format.modifier], + tiling, + drm_format_modifiers: modifiers, drm_format_modifier_plane_layouts: layouts, ..Default::default() }, @@ -1556,6 +1572,8 @@ pub fn fourcc_to_vk(fourcc: FourCC) -> anyhow::Result { DRM_FORMAT_XBGR8888 => Ok(Format::R8G8B8A8_UNORM), DRM_FORMAT_ARGB8888 => Ok(Format::B8G8R8A8_UNORM), DRM_FORMAT_XRGB8888 => Ok(Format::B8G8R8A8_UNORM), + DRM_FORMAT_ABGR2101010 => Ok(Format::A2B10G10R10_UNORM_PACK32), + DRM_FORMAT_XBGR2101010 => Ok(Format::A2B10G10R10_UNORM_PACK32), _ => bail!("Unsupported format {}", fourcc), } } diff --git a/src/gui/font.rs b/src/gui/font.rs index b320c24..73363b6 100644 --- a/src/gui/font.rs +++ b/src/gui/font.rs @@ -17,6 +17,7 @@ pub struct FontCache { struct FontCollection { fonts: Vec, cp_map: IdMap, + zero_glyph: Rc, } struct Font { @@ -96,6 +97,14 @@ impl FontCache { FontCollection { fonts: Vec::new(), cp_map: IdMap::new(), + zero_glyph: Rc::new(Glyph { + tex: None, + top: 0., + left: 0., + width: 0., + height: 0., + advance: size as f32 / 3., + }), }, ); } @@ -181,7 +190,7 @@ impl FontCache { let Some(font) = &mut self.collections[size].fonts.get_mut(key) else { log::warn!("No font found for codepoint: {}", cp); - return Ok(self.collections[size].fonts[0].glyphs[0].clone()); + return Ok(self.collections[size].zero_glyph.clone()); }; if let Some(glyph) = font.glyphs.get(cp) { @@ -189,18 +198,18 @@ impl FontCache { } if font.face.load_char(cp, LoadFlag::DEFAULT).is_err() { - return Ok(font.glyphs[0].clone()); + return Ok(self.collections[size].zero_glyph.clone()); } let glyph = font.face.glyph(); if glyph.render_glyph(freetype::RenderMode::Normal).is_err() { - return Ok(font.glyphs[0].clone()); + return Ok(self.collections[size].zero_glyph.clone()); } let bmp = glyph.bitmap(); let buf = bmp.buffer().to_vec(); if buf.is_empty() { - return Ok(font.glyphs[0].clone()); + return Ok(self.collections[size].zero_glyph.clone()); } let metrics = glyph.metrics(); @@ -209,7 +218,7 @@ impl FontCache { Ok(PixelMode::Gray) => Format::R8_UNORM, Ok(PixelMode::Gray2) => Format::R16_SFLOAT, Ok(PixelMode::Gray4) => Format::R32_SFLOAT, - _ => return Ok(font.glyphs[0].clone()), + _ => return Ok(self.collections[size].zero_glyph.clone()), }; let mut cmd_buffer = graphics.create_command_buffer(CommandBufferUsage::OneTimeSubmit)?; diff --git a/src/gui/mod.rs b/src/gui/mod.rs index ac9ee3a..9b3fdbb 100644 --- a/src/gui/mod.rs +++ b/src/gui/mod.rs @@ -171,6 +171,7 @@ impl CanvasBuilder { y: f32, w: f32, h: f32, + cap_type: KeyCapType, label: &[String], ) -> &mut Control { let idx = self.canvas.controls.len(); @@ -184,27 +185,88 @@ impl CanvasBuilder { ..Control::new() }); - for (i, item) in label.iter().enumerate().take(label.len().min(2)) { + let renders = match cap_type { + KeyCapType::Regular => { + let render: ControlRenderer = Control::render_text_centered; + let rect = Rect { + x, + y, + w, + h: h - self.font_size as f32, + }; + vec![(render, rect, 1f32)] + } + KeyCapType::RegularAltGr => { + let render: ControlRenderer = Control::render_text; + let rect0 = Rect { + x: x + 12., + y: y + (self.font_size as f32) + 12., + w, + h, + }; + let rect1 = Rect { + x: x + w * 0.5 + 12., + y: y + h - (self.font_size as f32) + 8., + w, + h, + }; + vec![(render, rect0, 1.0), (render, rect1, 0.8)] + } + KeyCapType::Reversed => { + let render: ControlRenderer = Control::render_text_centered; + let rect0 = Rect { + x, + y: y + 2.0, + w, + h: h * 0.5, + }; + let rect1 = Rect { + x, + y: y + h * 0.5 + 2.0, + w, + h: h * 0.5, + }; + vec![(render, rect1, 1.0), (render, rect0, 0.8)] + } + KeyCapType::ReversedAltGr => { + let render: ControlRenderer = Control::render_text; + let rect0 = Rect { + x: x + 12., + y: y + (self.font_size as f32) + 8., + w, + h, + }; + let rect1 = Rect { + x: x + 12., + y: y + h - (self.font_size as f32) + 4., + w, + h, + }; + let rect2 = Rect { + x: x + w * 0.5 + 8., + y: y + h - (self.font_size as f32) + 4., + w, + h, + }; + vec![ + (render, rect1, 1.0), + (render, rect0, 0.8), + (render, rect2, 0.8), + ] + } + }; + + for (idx, (render, rect, alpha)) in renders.into_iter().enumerate() { + if idx >= label.len() { + break; + } + self.canvas.controls.push(Control { - rect: if i == 0 { - Rect { - x: x + 4., - y: y + (self.font_size as f32) + 4., - w, - h, - } - } else { - Rect { - x: x + w * 0.5, - y: y + h - (self.font_size as f32) + 4., - w, - h, - } - }, - text: Arc::from(item.as_str()), - fg_color: self.fg_color, + rect, + text: Arc::from(label[idx].as_str()), + fg_color: self.fg_color * alpha, size: self.font_size, - on_render_fg: Some(Control::render_text), + on_render_fg: Some(render), ..Control::new() }); } @@ -232,7 +294,7 @@ pub struct Canvas { hover_controls: [Option; 2], pressed_controls: [Option; 2], - interact_map: Vec>, + interact_map: Vec>, interact_stride: usize, interact_rows: usize, @@ -341,7 +403,7 @@ impl Canvas { for y in y_min..y_max { for x in x_min..x_max { - self.interact_map[y * self.interact_stride + x] = Some(idx as u8); + self.interact_map[y * self.interact_stride + x] = Some(idx as u16); } } } @@ -540,6 +602,17 @@ impl OverlayBackend for Canvas { fn set_interaction(&mut self, _interaction: Box) {} } +pub type ControlRenderer = + fn(&Control, &CanvasData, &mut AppState, &mut WlxCommandBuffer) -> anyhow::Result<()>; + +pub type ControlRendererHl = fn( + &Control, + &CanvasData, + &mut AppState, + &mut WlxCommandBuffer, + Vec4, +) -> anyhow::Result<()>; + pub struct Control { pub state: Option, rect: Rect, @@ -555,15 +628,9 @@ pub struct Control { pub on_scroll: Option, pub test_highlight: Option Option>, - on_render_bg: Option< - fn(&Self, &CanvasData, &mut AppState, &mut WlxCommandBuffer) -> anyhow::Result<()>, - >, - on_render_hl: Option< - fn(&Self, &CanvasData, &mut AppState, &mut WlxCommandBuffer, Vec4) -> anyhow::Result<()>, - >, - on_render_fg: Option< - fn(&Self, &CanvasData, &mut AppState, &mut WlxCommandBuffer) -> anyhow::Result<()>, - >, + on_render_bg: Option>, + on_render_hl: Option>, + on_render_fg: Option>, } impl Control { @@ -762,3 +829,18 @@ impl Control { Ok(()) } } + +pub enum KeyCapType { + /// Label is in center of keycap + Regular, + /// Label on the top + /// AltGr symbol on bottom + RegularAltGr, + /// Primary symbol on bottom + /// Shift symbol on top + Reversed, + /// Primary symbol on bottom-left + /// Shift symbol on top-left + /// AltGr symbol on bottom-right + ReversedAltGr, +} diff --git a/src/gui/modular/button.rs b/src/gui/modular/button.rs index 9384e99..190bb3a 100644 --- a/src/gui/modular/button.rs +++ b/src/gui/modular/button.rs @@ -16,7 +16,7 @@ use crate::{ overlay::RelativeTo, task::{ColorChannel, SystemTask, TaskType}, }, - config::{save_settings, save_state, AStrSetExt}, + config::{save_layout, save_settings, AStrSetExt}, overlays::{ toast::{Toast, ToastTopic}, watch::WATCH_NAME, @@ -59,6 +59,7 @@ pub enum SystemAction { PlayspaceFixFloor, RecalculateExtent, PersistConfig, + PersistLayout, } #[derive(Deserialize, Clone)] @@ -418,6 +419,11 @@ fn run_system(action: &SystemAction, app: &mut AppState) { log::error!("Failed to save config: {:?}", e); } } + SystemAction::PersistLayout => { + if let Err(e) = save_layout(&app.session.config) { + log::error!("Failed to save layout: {:?}", e); + } + } } } @@ -540,7 +546,7 @@ fn run_watch(data: &WatchAction, app: &mut AppState) { OverlaySelector::Name(WATCH_NAME.into()), Box::new(move |app, o| { o.spawn_rotation *= rot; - app.session.config.watch_rot = o.spawn_rotation.into(); + app.session.config.watch_rot = o.spawn_rotation; o.dirty = true; }), )); @@ -556,7 +562,7 @@ fn run_watch(data: &WatchAction, app: &mut AppState) { OverlaySelector::Name(WATCH_NAME.into()), Box::new(move |app, o| { o.spawn_point[axis] += delta; - app.session.config.watch_pos = o.spawn_point.into(); + app.session.config.watch_pos = o.spawn_point; o.dirty = true; }), )); @@ -594,11 +600,11 @@ fn run_overlay(overlay: &OverlaySelector, action: &OverlayAction, app: &mut AppS if !o.want_visible { state_dirty |= app.session.config.show_screens.arc_rm(o.name.as_ref()); } else if o.want_visible { - state_dirty |= app.session.config.show_screens.arc_ins(o.name.clone()); + state_dirty |= app.session.config.show_screens.arc_set(o.name.clone()); } if state_dirty { - match save_state(&app.session.config) { + match save_layout(&app.session.config) { Ok(_) => log::debug!("Saved state"), Err(e) => log::error!("Failed to save state: {:?}", e), } diff --git a/src/gui/modular/mod.rs b/src/gui/modular/mod.rs index 4916dd4..239ea0a 100644 --- a/src/gui/modular/mod.rs +++ b/src/gui/modular/mod.rs @@ -158,7 +158,7 @@ pub fn modular_canvas( } => { canvas.font_size = *font_size; canvas.fg_color = color_parse(fg_color).unwrap_or(*FALLBACK_COLOR); - let label = canvas.label(*x, *y, *w, *h, empty_str.clone()); + let label = canvas.label_centered(*x, *y, *w, *h, empty_str.clone()); modular_label_init(label, data); } ModularElement::Button { diff --git a/src/hid.rs b/src/hid/mod.rs similarity index 68% rename from src/hid.rs rename to src/hid/mod.rs index 1d49e6f..3cab578 100644 --- a/src/hid.rs +++ b/src/hid/mod.rs @@ -10,6 +10,13 @@ use once_cell::sync::Lazy; use std::mem::transmute; use std::{fs::File, sync::atomic::AtomicBool}; use strum::{EnumIter, EnumString, IntoEnumIterator}; +use xkbcommon::xkb; + +#[cfg(feature = "wayland")] +mod wayland; + +#[cfg(feature = "x11")] +mod x11; pub static USE_UINPUT: AtomicBool = AtomicBool::new(true); @@ -37,21 +44,34 @@ pub fn initialize() -> Box { pub trait HidProvider { fn mouse_move(&mut self, pos: Vec2); - fn send_button(&self, button: u16, down: bool); - fn wheel(&self, delta: i32); + fn send_button(&mut self, button: u16, down: bool); + fn wheel(&mut self, delta: i32); fn set_modifiers(&mut self, mods: u8); - fn send_key(&self, key: u16, down: bool); + fn send_key(&self, key: VirtualKey, down: bool); fn set_desktop_extent(&mut self, extent: Vec2); fn set_desktop_origin(&mut self, origin: Vec2); - fn on_new_frame(&mut self); + fn commit(&mut self); +} + +struct MouseButtonAction { + button: u16, + down: bool, +} + +#[derive(Default)] +struct MouseAction { + last_requested_pos: Option, + pos: Option, + button: Option, + scroll: Option, } pub struct UInputProvider { handle: UInputHandle, desktop_extent: Vec2, desktop_origin: Vec2, - mouse_moved: bool, cur_modifiers: u8, + current_action: MouseAction, } pub struct DummyProvider; @@ -145,22 +165,25 @@ impl UInputProvider { handle, desktop_extent: Vec2::ZERO, desktop_origin: Vec2::ZERO, - mouse_moved: false, + current_action: Default::default(), cur_modifiers: 0, }); } } None } -} -impl HidProvider for UInputProvider { - fn mouse_move(&mut self, pos: Vec2) { - if self.mouse_moved { - return; + fn send_button_internal(&self, button: u16, down: bool) { + let time = get_time(); + let events = [ + new_event(time, EV_KEY, button, down as _), + new_event(time, EV_SYN, 0, 0), + ]; + if let Err(res) = self.handle.write(&events) { + log::error!("send_button: {}", res.to_string()); } - self.mouse_moved = true; - + } + fn mouse_move_internal(&mut self, pos: Vec2) { #[cfg(debug_assertions)] log::trace!("Mouse move: {:?}", pos); @@ -176,17 +199,7 @@ impl HidProvider for UInputProvider { log::error!("{}", res.to_string()); } } - fn send_button(&self, button: u16, down: bool) { - let time = get_time(); - let events = [ - new_event(time, EV_KEY, button, down as _), - new_event(time, EV_SYN, 0, 0), - ]; - if let Err(res) = self.handle.write(&events) { - log::error!("send_button: {}", res.to_string()); - } - } - fn wheel(&self, delta: i32) { + fn wheel_internal(&self, delta: i32) { let time = get_time(); let events = [ new_event(time, EV_REL, RelativeAxis::Wheel as _, delta), @@ -196,22 +209,26 @@ impl HidProvider for UInputProvider { log::error!("wheel: {}", res.to_string()); } } +} + +impl HidProvider for UInputProvider { fn set_modifiers(&mut self, modifiers: u8) { let changed = self.cur_modifiers ^ modifiers; - for i in 0..7 { + for i in 0..8 { let m = 1 << i; if changed & m != 0 { if let Some(vk) = MODS_TO_KEYS.get(m).into_iter().flatten().next() { - self.send_key(*vk as u16, modifiers & m != 0); + self.send_key(*vk, modifiers & m != 0); } } } self.cur_modifiers = modifiers; } - fn send_key(&self, key: u16, down: bool) { + fn send_key(&self, key: VirtualKey, down: bool) { + log::debug!("send_key: {:?} {}", key, down); let time = get_time(); let events = [ - new_event(time, EV_KEY, key - 8, down as _), + new_event(time, EV_KEY, (key as u16) - 8, down as _), new_event(time, EV_SYN, 0, 0), ]; if let Err(res) = self.handle.write(&events) { @@ -224,20 +241,45 @@ impl HidProvider for UInputProvider { fn set_desktop_origin(&mut self, origin: Vec2) { self.desktop_origin = origin; } - fn on_new_frame(&mut self) { - self.mouse_moved = false; + fn mouse_move(&mut self, pos: Vec2) { + if self.current_action.pos.is_none() { + self.current_action.pos = Some(pos); + } + self.current_action.last_requested_pos = Some(pos); + } + fn send_button(&mut self, button: u16, down: bool) { + if self.current_action.button.is_none() { + self.current_action.button = Some(MouseButtonAction { button, down }); + self.current_action.pos = self.current_action.last_requested_pos; + } + } + fn wheel(&mut self, delta: i32) { + if self.current_action.scroll.is_none() { + self.current_action.scroll = Some(delta); + } + } + fn commit(&mut self) { + if let Some(pos) = self.current_action.pos.take() { + self.mouse_move_internal(pos); + } + if let Some(button) = self.current_action.button.take() { + self.send_button_internal(button.button, button.down); + } + if let Some(scroll) = self.current_action.scroll.take() { + self.wheel_internal(scroll); + } } } impl HidProvider for DummyProvider { fn mouse_move(&mut self, _pos: Vec2) {} - fn send_button(&self, _button: u16, _down: bool) {} - fn wheel(&self, _delta: i32) {} + fn send_button(&mut self, _button: u16, _down: bool) {} + fn wheel(&mut self, _delta: i32) {} fn set_modifiers(&mut self, _modifiers: u8) {} - fn send_key(&self, _key: u16, _down: bool) {} + fn send_key(&self, _key: VirtualKey, _down: bool) {} fn set_desktop_extent(&mut self, _extent: Vec2) {} fn set_desktop_origin(&mut self, _origin: Vec2) {} - fn on_new_frame(&mut self) {} + fn commit(&mut self) {} } #[inline] @@ -453,3 +495,104 @@ pub static MODS_TO_KEYS: Lazy>> = Lazy::new(| META => vec![VirtualKey::Meta], } }); + +pub enum KeyType { + Symbol, + NumPad, + Other, +} + +macro_rules! key_between { + ($key:expr, $start:expr, $end:expr) => { + $key as u32 >= $start as u32 && $key as u32 <= $end as u32 + }; +} + +macro_rules! key_is { + ($key:expr, $val:expr) => { + $key as u32 == $val as u32 + }; +} + +pub fn get_key_type(key: VirtualKey) -> KeyType { + if key_between!(key, VirtualKey::N1, VirtualKey::Plus) + || key_between!(key, VirtualKey::Q, VirtualKey::Oem6) + || key_between!(key, VirtualKey::A, VirtualKey::Oem3) + || key_between!(key, VirtualKey::Oem5, VirtualKey::Oem2) + || key_is!(key, VirtualKey::Oem102) + { + KeyType::Symbol + } else if key_between!(key, VirtualKey::KP_7, VirtualKey::KP_0) + && !key_is!(key, VirtualKey::KP_Subtract) + && !key_is!(key, VirtualKey::KP_Add) + { + KeyType::NumPad + } else { + KeyType::Other + } +} + +pub struct XkbKeymap { + pub context: xkb::Context, + pub keymap: xkb::Keymap, +} + +impl XkbKeymap { + pub fn label_for_key(&self, key: VirtualKey, modifier: KeyModifier) -> String { + let mut state = xkb::State::new(&self.keymap); + if modifier > 0 { + if let Some(mod_key) = MODS_TO_KEYS.get(modifier) { + state.update_key( + xkb::Keycode::from(mod_key[0] as u32), + xkb::KeyDirection::Down, + ); + } + } + state.key_get_utf8(xkb::Keycode::from(key as u32)) + } + + pub fn has_altgr(&self) -> bool { + let state0 = xkb::State::new(&self.keymap); + let mut state1 = xkb::State::new(&self.keymap); + state1.update_key( + xkb::Keycode::from(VirtualKey::Meta as u32), + xkb::KeyDirection::Down, + ); + + for key in [ + VirtualKey::N0, + VirtualKey::N1, + VirtualKey::N2, + VirtualKey::N3, + VirtualKey::N4, + VirtualKey::N5, + VirtualKey::N6, + VirtualKey::N7, + VirtualKey::N8, + VirtualKey::N9, + ] { + let sym0 = state0.key_get_one_sym(xkb::Keycode::from(key as u32)); + let sym1 = state1.key_get_one_sym(xkb::Keycode::from(key as u32)); + if sym0 != sym1 { + return true; + } + } + false + } +} + +#[cfg(feature = "wayland")] +pub use wayland::get_keymap_wl; + +#[cfg(not(feature = "wayland"))] +pub fn get_keymap_wl() -> anyhow::Result { + anyhow::bail!("Wayland support not enabled.") +} + +#[cfg(feature = "x11")] +pub use x11::get_keymap_x11; + +#[cfg(not(feature = "x11"))] +pub fn get_keymap_x11() -> anyhow::Result { + anyhow::bail!("X11 support not enabled.") +} diff --git a/src/hid/wayland.rs b/src/hid/wayland.rs new file mode 100644 index 0000000..0e251a8 --- /dev/null +++ b/src/hid/wayland.rs @@ -0,0 +1,142 @@ +use wlx_capture::wayland::wayland_client::{ + globals::{registry_queue_init, GlobalListContents}, + protocol::{ + wl_keyboard::{self, WlKeyboard}, + wl_registry::WlRegistry, + wl_seat::{self, Capability, WlSeat}, + }, + Connection, Dispatch, Proxy, QueueHandle, +}; +use xkbcommon::xkb; + +use super::XkbKeymap; + +struct WlKeymapHandler { + seat: WlSeat, + keyboard: Option, + keymap: Option, +} + +impl Drop for WlKeymapHandler { + fn drop(&mut self) { + if let Some(keyboard) = &self.keyboard { + keyboard.release(); + } + self.seat.release(); + } +} + +pub fn get_keymap_wl() -> anyhow::Result { + let connection = Connection::connect_to_env()?; + let (globals, mut queue) = registry_queue_init::(&connection)?; + let qh = queue.handle(); + let seat: WlSeat = globals + .bind(&qh, 4..=9, ()) + .expect(WlSeat::interface().name); + + let mut me = WlKeymapHandler { + seat, + keyboard: None, + keymap: None, + }; + + // this gets us the wl_seat + let _ = queue.blocking_dispatch(&mut me); + + // this gets us the wl_keyboard + let _ = queue.blocking_dispatch(&mut me); + + if let Some(keymap) = me.keymap.take() { + Ok(keymap) + } else { + Err(anyhow::anyhow!("Could not load keymap")) + } +} + +impl Dispatch for WlKeymapHandler { + fn event( + _state: &mut Self, + _proxy: &WlRegistry, + _event: ::Event, + _data: &GlobalListContents, + _conn: &Connection, + _qhandle: &QueueHandle, + ) { + } +} + +impl Dispatch for WlKeymapHandler { + fn event( + state: &mut Self, + proxy: &WlSeat, + event: ::Event, + _data: &(), + _conn: &Connection, + qhandle: &QueueHandle, + ) { + match event { + wl_seat::Event::Capabilities { capabilities } => { + let capability = capabilities + .into_result() + .unwrap_or(wl_seat::Capability::empty()); + if capability.contains(Capability::Keyboard) { + state.keyboard = Some(proxy.get_keyboard(qhandle, ())); + } + } + wl_seat::Event::Name { name } => { + log::debug!("Using WlSeat: {}", name); + } + _ => {} + } + } +} + +impl Dispatch for WlKeymapHandler { + fn event( + state: &mut Self, + _proxy: &WlKeyboard, + event: ::Event, + _data: &(), + _conn: &Connection, + _qhandle: &QueueHandle, + ) { + match event { + wl_keyboard::Event::Keymap { format, fd, size } => { + let format = format + .into_result() + .unwrap_or(wl_keyboard::KeymapFormat::NoKeymap); + + if matches!(format, wl_keyboard::KeymapFormat::XkbV1) { + let context = xkb::Context::new(xkb::CONTEXT_NO_DEFAULT_INCLUDES); + let maybe_keymap = unsafe { + xkb::Keymap::new_from_fd( + &context, + fd, + size as _, + xkb::KEYMAP_FORMAT_TEXT_V1, + xkb::KEYMAP_COMPILE_NO_FLAGS, + ) + }; + + match maybe_keymap { + Ok(Some(keymap)) => { + state.keymap = Some(XkbKeymap { context, keymap }); + } + Ok(None) => { + log::error!("Could not load keymap: no keymap"); + log::error!("Default layout will be used."); + } + Err(err) => { + log::error!("Could not load keymap: {}", err); + log::error!("Default layout will be used."); + } + } + } + } + wl_keyboard::Event::RepeatInfo { rate, delay } => { + log::debug!("WlKeyboard RepeatInfo rate: {}, delay: {}", rate, delay); + } + _ => {} + } + } +} diff --git a/src/hid/x11.rs b/src/hid/x11.rs new file mode 100644 index 0000000..c6d9a63 --- /dev/null +++ b/src/hid/x11.rs @@ -0,0 +1,16 @@ +use xkbcommon::xkb::{ + self, + x11::{get_core_keyboard_device_id, keymap_new_from_device}, +}; + +use super::XkbKeymap; + +pub fn get_keymap_x11() -> anyhow::Result { + let context = xkb::Context::new(xkb::CONTEXT_NO_FLAGS); + + let (conn, _) = xcb::Connection::connect(None)?; + let device_id = get_core_keyboard_device_id(&conn); + let keymap = keymap_new_from_device(&context, &conn, device_id, xkb::KEYMAP_COMPILE_NO_FLAGS); + + Ok(XkbKeymap { context, keymap }) +} diff --git a/src/main.rs b/src/main.rs index 413b1f1..9a4e6a8 100644 --- a/src/main.rs +++ b/src/main.rs @@ -38,6 +38,14 @@ struct Args { #[arg(long)] uninstall: bool, + /// Replace running WlxOverlay-S instance + #[arg(long)] + replace: bool, + + /// Allow multiple running instances of WlxOverlay-S (things may break!) + #[arg(long)] + multi: bool, + /// Path to write logs to #[arg(short, long, value_name = "FILE_PATH")] log_to: Option, @@ -50,6 +58,13 @@ struct Args { fn main() -> Result<(), Box> { let mut args = Args::parse(); + + if !args.multi && !ensure_single_instance(args.replace) { + println!("Looks like WlxOverlay-S is already running."); + println!("Use --replace and I will terminate it for you."); + return Ok(()); + } + logging_init(&mut args)?; log::info!( @@ -187,3 +202,33 @@ fn file_logging_init(log_to: &str) -> anyhow::Result<()> { println!("Logging to: {}", log_to); Ok(()) } + +fn ensure_single_instance(replace: bool) -> bool { + let mut path = std::env::var("XDG_RUNTIME_DIR") + .map(PathBuf::from) + .unwrap_or_else(|_| PathBuf::from("/tmp")); + path.push("wlx-overlay-s.pid"); + + if path.exists() { + // load contents + if let Ok(pid_str) = std::fs::read_to_string(&path) { + if let Ok(pid) = pid_str.trim().parse::() { + let mut system = sysinfo::System::new(); + system.refresh_processes(); + if let Some(proc) = system.process(sysinfo::Pid::from_u32(pid)) { + if replace { + proc.kill_with(sysinfo::Signal::Term); + proc.wait(); + } else { + return false; + } + } + } + } + } + + let pid = std::process::id().to_string(); + std::fs::write(path, pid).unwrap(); + + true +} diff --git a/src/overlays/anchor.rs b/src/overlays/anchor.rs index ab265f4..dcbe9fd 100644 --- a/src/overlays/anchor.rs +++ b/src/overlays/anchor.rs @@ -2,7 +2,7 @@ use glam::Vec3A; use once_cell::sync::Lazy; use std::sync::Arc; -use crate::backend::overlay::{OverlayData, OverlayState}; +use crate::backend::overlay::{OverlayData, OverlayState, RelativeTo}; use crate::config::{load_known_yaml, ConfigType}; use crate::gui::modular::{modular_canvas, ModularUiConfig}; use crate::state::AppState; @@ -21,8 +21,10 @@ where want_visible: false, interactable: false, grabbable: false, + z_order: 67, spawn_scale: config.width, spawn_point: Vec3A::NEG_Z * 0.5, + relative_to: RelativeTo::Stage, ..Default::default() }, backend: Box::new(modular_canvas(&config.size, &config.elements, state)?), diff --git a/src/overlays/keyboard.rs b/src/overlays/keyboard.rs index 37617cf..064d028 100644 --- a/src/overlays/keyboard.rs +++ b/src/overlays/keyboard.rs @@ -10,8 +10,11 @@ use crate::{ overlay::{OverlayData, OverlayState}, }, config::{self, ConfigType}, - gui::{color_parse, CanvasBuilder, Control}, - hid::{KeyModifier, VirtualKey, ALT, CTRL, KEYS_TO_MODS, META, SHIFT, SUPER}, + gui::{color_parse, CanvasBuilder, Control, KeyCapType}, + hid::{ + get_key_type, KeyModifier, KeyType, VirtualKey, XkbKeymap, ALT, CTRL, KEYS_TO_MODS, META, + NUM_LOCK, SHIFT, SUPER, + }, state::AppState, }; use glam::{vec2, vec3a, Affine2, Vec4}; @@ -25,7 +28,10 @@ const AUTO_RELEASE_MODS: [KeyModifier; 5] = [SHIFT, CTRL, ALT, SUPER, META]; pub const KEYBOARD_NAME: &str = "kbd"; -pub fn create_keyboard(app: &AppState) -> anyhow::Result> +pub fn create_keyboard( + app: &AppState, + keymap: Option, +) -> anyhow::Result> where O: Default, { @@ -53,6 +59,8 @@ where canvas.font_size = 18; canvas.bg_color = color_parse("#202020").unwrap(); //safe + let has_altgr = keymap.as_ref().map_or(false, |k| k.has_altgr()); + let unit_size = size.x / LAYOUT.row_size; let h = unit_size - 2. * BUTTON_PADDING; @@ -66,8 +74,43 @@ where let w = unit_size * my_size - 2. * BUTTON_PADDING; if let Some(key) = LAYOUT.main_layout[row][col].as_ref() { + let mut label = Vec::with_capacity(2); let mut maybe_state: Option = None; + let mut cap_type = KeyCapType::Regular; + if let Ok(vk) = VirtualKey::from_str(key) { + if let Some(keymap) = keymap.as_ref() { + match get_key_type(vk) { + KeyType::Symbol => { + let label0 = keymap.label_for_key(vk, 0); + let label1 = keymap.label_for_key(vk, SHIFT); + + if label0.chars().next().map_or(false, |f| f.is_alphabetic()) { + label.push(label1); + if has_altgr { + cap_type = KeyCapType::RegularAltGr; + label.push(keymap.label_for_key(vk, META)); + } else { + cap_type = KeyCapType::Regular; + } + } else { + label.push(label0); + label.push(label1); + if has_altgr { + label.push(keymap.label_for_key(vk, META)); + cap_type = KeyCapType::ReversedAltGr; + } else { + cap_type = KeyCapType::Reversed; + } + } + } + KeyType::NumPad => { + label.push(keymap.label_for_key(vk, NUM_LOCK)); + } + KeyType::Other => {} + } + } + if let Some(mods) = KEYS_TO_MODS.get(vk) { maybe_state = Some(KeyButtonData::Modifier { modifier: *mods, @@ -97,8 +140,10 @@ where } if let Some(state) = maybe_state { - let label = LAYOUT.label_for_key(key); - let button = canvas.key_button(x, y, w, h, &label); + if label.is_empty() { + label = LAYOUT.label_for_key(key); + } + let button = canvas.key_button(x, y, w, h, cap_type, &label); button.state = Some(state); button.on_press = Some(key_press); button.on_release = Some(key_release); @@ -122,6 +167,7 @@ where name: KEYBOARD_NAME.into(), grabbable: true, recenter: true, + anchored: true, interactable: true, spawn_scale: width, spawn_point: vec3a(0., -0.5, 0.), @@ -148,7 +194,7 @@ fn key_press( app.hid_provider.set_modifiers(data.modifiers); } - app.hid_provider.send_key(*vk as _, true); + app.hid_provider.send_key(*vk, true); *pressed = true; } Some(KeyButtonData::Modifier { modifier, sticky }) => { @@ -160,7 +206,7 @@ fn key_press( Some(KeyButtonData::Macro { verbs }) => { data.key_click(app); for (vk, press) in verbs { - app.hid_provider.send_key(*vk as _, *press); + app.hid_provider.send_key(*vk, *press); } } Some(KeyButtonData::Exec { program, args, .. }) => { @@ -184,7 +230,7 @@ fn key_release( ) { match control.state.as_mut() { Some(KeyButtonData::Key { vk, pressed }) => { - app.hid_provider.send_key(*vk as _, false); + app.hid_provider.send_key(*vk, false); *pressed = false; for m in AUTO_RELEASE_MODS.iter() { diff --git a/src/overlays/mirror.rs b/src/overlays/mirror.rs index dc5407f..c756062 100644 --- a/src/overlays/mirror.rs +++ b/src/overlays/mirror.rs @@ -31,7 +31,7 @@ pub struct MirrorRenderer { } impl MirrorRenderer { pub fn new(name: Arc) -> Self { - let selector = Box::pin(pipewire_select_screen(None, false, false, false)); + let selector = Box::pin(pipewire_select_screen(None, false, false, false, false)); Self { name, renderer: None, @@ -58,12 +58,9 @@ impl OverlayRenderer for MirrorRenderer { }; if let Ok(pw_result) = maybe_pw_result { - log::info!( - "{}: PipeWire node selected: {}", - self.name.clone(), - pw_result.node_id - ); - let capture = PipewireCapture::new(self.name.clone(), pw_result.node_id, 60); + let node_id = pw_result.streams.first().unwrap().node_id; // streams guaranteed to have at least one element + log::info!("{}: PipeWire node selected: {}", self.name.clone(), node_id,); + let capture = PipewireCapture::new(self.name.clone(), node_id); self.renderer = Some(ScreenRenderer::new_raw( self.name.clone(), Box::new(capture), diff --git a/src/overlays/screen.rs b/src/overlays/screen.rs index 246af36..2832265 100644 --- a/src/overlays/screen.rs +++ b/src/overlays/screen.rs @@ -1,10 +1,11 @@ use core::slice; +use once_cell::sync::Lazy; use serde::{Deserialize, Serialize}; use std::{ f32::consts::PI, ops::Add, ptr, - sync::Arc, + sync::{atomic::AtomicU64, Arc}, time::{Duration, Instant}, }; use vulkano::{ @@ -14,19 +15,24 @@ use vulkano::{ }; use wlx_capture::{ frame::{ - DrmFormat, MouseMeta, WlxFrame, DRM_FORMAT_ABGR8888, DRM_FORMAT_ARGB8888, - DRM_FORMAT_XBGR8888, DRM_FORMAT_XRGB8888, + DrmFormat, MouseMeta, WlxFrame, DRM_FORMAT_ABGR2101010, DRM_FORMAT_ABGR8888, + DRM_FORMAT_ARGB8888, DRM_FORMAT_XBGR2101010, DRM_FORMAT_XBGR8888, DRM_FORMAT_XRGB8888, }, WlxCapture, }; +#[cfg(feature = "pipewire")] +use { + crate::config_io, + std::error::Error, + std::{ops::Deref, path::PathBuf}, + wlx_capture::pipewire::{pipewire_select_screen, PipewireCapture, PipewireStream}, +}; + #[cfg(feature = "wayland")] use { crate::config::AStrMapExt, - crate::config_io, - std::{error::Error, ops::Deref, path::PathBuf}, wlx_capture::{ - pipewire::{pipewire_select_screen, PipewireCapture}, wayland::{wayland_client::protocol::wl_output, WlxClient, WlxOutput}, wlr_dmabuf::WlrDmabufCapture, wlr_screencopy::WlrScreencopyCapture, @@ -44,7 +50,9 @@ use crate::{ overlay::{OverlayRenderer, OverlayState, SplitOverlayBackend}, }, config::{def_pw_tokens, PwTokenMap}, - graphics::{fourcc_to_vk, WlxCommandBuffer, WlxPipeline, WlxPipelineLegacy, DMA_BUF_SUPPORTED}, + graphics::{ + fourcc_to_vk, WlxCommandBuffer, WlxPipeline, WlxPipelineLegacy, DRM_FORMAT_MOD_INVALID, + }, hid::{MOUSE_LEFT, MOUSE_MIDDLE, MOUSE_RIGHT}, state::{AppSession, AppState, ScreenMeta}, }; @@ -59,9 +67,22 @@ const CURSOR_SIZE: f32 = 16. / 1440.; static DRM_FORMATS: once_cell::sync::OnceCell> = once_cell::sync::OnceCell::new(); +static START: Lazy = Lazy::new(Instant::now); +static NEXT_MOVE: AtomicU64 = AtomicU64::new(0); + +fn can_move() -> bool { + START.elapsed().as_millis() as u64 > NEXT_MOVE.load(std::sync::atomic::Ordering::Relaxed) +} + +fn set_next_move(millis_from_now: u64) { + NEXT_MOVE.store( + START.elapsed().as_millis() as u64 + millis_from_now, + std::sync::atomic::Ordering::Relaxed, + ); +} + pub struct ScreenInteractionHandler { next_scroll: Instant, - next_move: Instant, mouse_transform: Affine2, } impl ScreenInteractionHandler { @@ -87,7 +108,6 @@ impl ScreenInteractionHandler { ScreenInteractionHandler { next_scroll: Instant::now(), - next_move: Instant::now(), mouse_transform: transform, } } @@ -97,7 +117,7 @@ impl InteractionHandler for ScreenInteractionHandler { fn on_hover(&mut self, app: &mut AppState, hit: &PointerHit) -> Option { #[cfg(debug_assertions)] log::trace!("Hover: {:?}", hit.uv); - if self.next_move < Instant::now() + if can_move() && (!app.session.config.focus_follows_mouse_mode || app.input_state.pointers[hit.pointer].now.move_mouse) { @@ -114,8 +134,7 @@ impl InteractionHandler for ScreenInteractionHandler { }; if pressed { - self.next_move = Instant::now() - + Duration::from_millis(app.session.config.click_freeze_time_ms as u64); + set_next_move(app.session.config.click_freeze_time_ms as u64); } app.hid_provider.send_button(btn, pressed); @@ -313,10 +332,17 @@ impl ScreenRenderer { )> { let name = output.name.clone(); let embed_mouse = !session.config.double_cursor_fix; - let select_screen_result = - futures::executor::block_on(pipewire_select_screen(token, embed_mouse, true, true))?; + let select_screen_result = futures::executor::block_on(pipewire_select_screen( + token, + embed_mouse, + true, + true, + false, + ))?; - let capture = PipewireCapture::new(name, select_screen_result.node_id, 60); + let node_id = select_screen_result.streams.first().unwrap().node_id; // streams guaranteed to have at least one element + + let capture = PipewireCapture::new(name, node_id); Ok(( ScreenRenderer { @@ -350,10 +376,18 @@ impl OverlayRenderer for ScreenRenderer { } fn render(&mut self, app: &mut AppState) -> anyhow::Result<()> { if !self.capture.is_ready() { - let supports_dmabuf = DMA_BUF_SUPPORTED && self.capture.supports_dmbuf(); + let supports_dmabuf = app + .graphics + .device + .enabled_extensions() + .ext_external_memory_dma_buf + && self.capture.supports_dmbuf(); + let allow_dmabuf = &*app.session.config.capture_method != "pw_fallback" && &*app.session.config.capture_method != "screencopy"; + let capture_method = app.session.config.capture_method.clone(); + let drm_formats = DRM_FORMATS.get_or_init({ let graphics = app.graphics.clone(); move || { @@ -362,7 +396,7 @@ impl OverlayRenderer for ScreenRenderer { return vec![]; } if !allow_dmabuf { - log::info!("Not using DMA-buf capture due to pw_fallback"); + log::info!("Not using DMA-buf capture due to {}", capture_method); return vec![]; } log::warn!("Using DMA-buf capture. If screens are blank for you, switch to SHM using:"); @@ -373,7 +407,10 @@ impl OverlayRenderer for ScreenRenderer { DRM_FORMAT_XBGR8888.into(), DRM_FORMAT_ARGB8888.into(), DRM_FORMAT_XRGB8888.into(), + DRM_FORMAT_ABGR2101010.into(), + DRM_FORMAT_XBGR2101010.into(), ]; + let mut final_formats = vec![]; for &f in &possible_formats { @@ -384,7 +421,7 @@ impl OverlayRenderer for ScreenRenderer { else { continue; }; - final_formats.push(DrmFormat { + let mut fmt = DrmFormat { fourcc: f, modifiers: props .drm_format_modifier_properties @@ -393,7 +430,13 @@ impl OverlayRenderer for ScreenRenderer { .filter(|m| m.drm_format_modifier_plane_count == 1) .map(|m| m.drm_format_modifier) .collect(), - }) + }; + fmt.modifiers.push(DRM_FORMAT_MOD_INVALID); // implicit modifiers support + final_formats.push(fmt); + } + log::debug!("Supported DRM formats:"); + for f in &final_formats { + log::debug!(" {} {:?}", f.fourcc, f.modifiers); } final_formats } @@ -556,7 +599,7 @@ pub fn create_screen_renderer_wl( capture = Some(renderer); if let Some(token) = restore_token { - if pw_token_store.arc_ins(display_name.into(), token.clone()) { + if pw_token_store.arc_set(display_name.into(), token.clone()) { log::info!("Adding Pipewire token {}", token); } } @@ -620,6 +663,7 @@ fn create_screen_state( name: name.clone(), grabbable: true, recenter: true, + anchored: true, interactable: true, spawn_scale: 1.5 * session.config.desktop_view_scale, spawn_point: vec3a(0., 0.5, 0.), @@ -635,14 +679,14 @@ pub struct TokenConf { pub pw_tokens: PwTokenMap, } -#[cfg(feature = "wayland")] +#[cfg(feature = "pipewire")] fn get_pw_token_path() -> PathBuf { let mut path = config_io::get_conf_d_path(); path.push("pw_tokens.yaml"); path } -#[cfg(feature = "wayland")] +#[cfg(feature = "pipewire")] pub fn save_pw_token_config(tokens: PwTokenMap) -> Result<(), Box> { let conf = TokenConf { pw_tokens: tokens }; let yaml = serde_yaml::to_string(&conf)?; @@ -651,7 +695,7 @@ pub fn save_pw_token_config(tokens: PwTokenMap) -> Result<(), Box> { Ok(()) } -#[cfg(feature = "wayland")] +#[cfg(feature = "pipewire")] pub fn load_pw_token_config() -> Result> { let yaml = std::fs::read_to_string(get_pw_token_path())?; let conf: TokenConf = serde_yaml::from_str(yaml.as_str())?; @@ -750,12 +794,102 @@ pub fn create_screens_wayland( } #[cfg(not(feature = "x11"))] -pub fn create_screens_x11(_app: &mut AppState) -> anyhow::Result { +pub fn create_screens_xshm(_app: &mut AppState) -> anyhow::Result { anyhow::bail!("X11 support not enabled") } +#[cfg(not(all(feature = "x11", feature = "pipewire")))] +pub fn create_screens_x11pw(_app: &mut AppState) -> anyhow::Result { + anyhow::bail!("Pipewire support not enabled") +} + +#[cfg(all(feature = "x11", feature = "pipewire"))] +pub fn create_screens_x11pw(app: &mut AppState) -> anyhow::Result { + use crate::config::{AStrMap, AStrMapExt}; + use anyhow::bail; + + // Load existing Pipewire tokens from file + let mut pw_tokens: PwTokenMap = if let Ok(conf) = load_pw_token_config() { + conf + } else { + AStrMap::new() + }; + let pw_tokens_copy = pw_tokens.clone(); + let token = pw_tokens.arc_get("x11").map(|s| s.as_str()); + let embed_mouse = !app.session.config.double_cursor_fix; + let select_screen_result = + futures::executor::block_on(pipewire_select_screen(token, embed_mouse, true, true, true))?; + if let Some(restore_token) = select_screen_result.restore_token { + if pw_tokens.arc_set("x11".into(), restore_token.clone()) { + log::info!("Adding Pipewire token {}", restore_token); + } + } + if pw_tokens_copy != pw_tokens { + // Token list changed, re-create token config file + if let Err(err) = save_pw_token_config(pw_tokens) { + log::error!("Failed to save Pipewire token config: {}", err); + } + } + + let monitors = match XshmCapture::get_monitors() { + Ok(m) => m, + Err(e) => { + bail!(e.to_string()); + } + }; + log::info!("Got {} monitors", monitors.len()); + log::info!("Got {} streams", select_screen_result.streams.len()); + + let mut extent = vec2(0., 0.); + let screens = select_screen_result + .streams + .into_iter() + .enumerate() + .map(|(i, s)| { + let m = best_match(&s, monitors.iter().map(AsRef::as_ref)).unwrap(); + log::info!("Stream {i} is {}", m.name); + extent.x = extent.x.max((m.monitor.x() + m.monitor.width()) as f32); + extent.y = extent.y.max((m.monitor.y() + m.monitor.height()) as f32); + + let size = (m.monitor.width(), m.monitor.height()); + let interaction = create_screen_interaction( + vec2(m.monitor.x() as f32, m.monitor.y() as f32), + vec2(m.monitor.width() as f32, m.monitor.height() as f32), + Transform::Normal, + ); + + let state = create_screen_state(m.name.clone(), size, Transform::Normal, &app.session); + + let meta = ScreenMeta { + name: m.name.clone(), + id: state.id, + native_handle: 0, + }; + + let renderer = ScreenRenderer { + name: m.name.clone(), + capture: Box::new(PipewireCapture::new(m.name.clone(), s.node_id)), + pipeline: None, + last_view: None, + extent: extent_from_res(size), + }; + + let backend = Box::new(SplitOverlayBackend { + renderer: Box::new(renderer), + interaction: Box::new(interaction), + }); + (meta, state, backend) + }) + .collect(); + + app.hid_provider.set_desktop_extent(extent); + app.hid_provider.set_desktop_origin(vec2(0.0, 0.0)); + + Ok(ScreenCreateData { screens }) +} + #[cfg(feature = "x11")] -pub fn create_screens_x11(app: &mut AppState) -> anyhow::Result { +pub fn create_screens_xshm(app: &mut AppState) -> anyhow::Result { use anyhow::bail; let mut extent = vec2(0., 0.); @@ -807,6 +941,7 @@ pub fn create_screens_x11(app: &mut AppState) -> anyhow::Result [u32; 3] { let h = (res.1 as f32 / res.0 as f32 * w as f32) as u32; [w, h, 1] } + +#[cfg(all(feature = "pipewire", feature = "x11"))] +fn best_match<'a>( + stream: &PipewireStream, + mut streams: impl Iterator, +) -> Option<&'a XshmScreen> { + let mut best = streams.next(); + log::debug!("stream: {:?}", stream.position); + log::debug!("first: {:?}", best.map(|b| &b.monitor)); + let Some(position) = stream.position else { + return best; + }; + + let mut best_dist = best + .map(|b| (b.monitor.x() - position.0).abs() + (b.monitor.y() - position.1).abs()) + .unwrap_or(i32::MAX); + for stream in streams { + log::debug!("checking: {:?}", stream.monitor); + let dist = + (stream.monitor.x() - position.0).abs() + (stream.monitor.y() - position.1).abs(); + if dist < best_dist { + best = Some(stream); + best_dist = dist; + } + } + log::debug!("best: {:?}", best.map(|b| &b.monitor)); + best +} diff --git a/src/overlays/toast.rs b/src/overlays/toast.rs index 1a2585b..1d6d884 100644 --- a/src/overlays/toast.rs +++ b/src/overlays/toast.rs @@ -199,6 +199,7 @@ fn new_toast(toast: Toast, app: &mut AppState) -> Option<(OverlayState, Box"] - "Oem1": [" ;", ":"] - "Oem2": [" /", "?"] - "Oem3": ["`", "~"] - "Oem4": [" [", "{"] - "Oem5": [" \\", "|"] - "Oem6": [" ]", "}"] - "Oem7": [" '", "\""] - "Oem102": [" \\", "|"] "KP_Divide": [" /"] "KP_Add": [" +"] "KP_Multiply": [" *"] "KP_Decimal": [" ."] "KP_Subtract": [" -"] "KP_Enter": ["Ent"] + "Print": ["Prn"] + "Scroll": ["Scr"] + "Pause": ["Brk"] "XF86Favorites": ["Rofi"] diff --git a/src/res/settings.yaml b/src/res/settings.yaml index 39f1839..cdb7ca0 100644 --- a/src/res/settings.yaml +++ b/src/res/settings.yaml @@ -591,4 +591,18 @@ elements: click_down: - type: System action: PersistConfig + - type: Toast + message: Settings saved successfully. + + - type: Button + rect: [30, 625, 250, 30] + font_size: 12 + fg_color: "#ffffff" + bg_color: "#206060" + text: "Save Overlay Layout" + click_down: + - type: System + action: PersistLayout + - type: Toast + message: Saved. You will see this layout on next startup.