From e392ba1055dba18fc38b5fa01a74036877da75bc Mon Sep 17 00:00:00 2001 From: Harivansh Rathi Date: Wed, 25 Mar 2026 12:28:23 -0400 Subject: [PATCH] Rewrite X11 backend to drop xcap Use x11rb directly for screenshot capture and window metadata so the Linux build no longer drags in Wayland build dependencies. Co-authored-by: Codex --- Cargo.lock | 1921 +-------------------------------------- Cargo.toml | 1 - src/backend/annotate.rs | 16 +- src/backend/mod.rs | 2 +- src/backend/x11.rs | 409 +++++++-- src/cli/connection.rs | 10 +- src/cli/mod.rs | 109 +-- src/core/protocol.rs | 24 +- src/core/refs.rs | 15 +- src/daemon/handler.rs | 98 +- src/daemon/mod.rs | 11 +- 11 files changed, 488 insertions(+), 2128 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 11573be..958922a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -24,15 +24,6 @@ version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" -[[package]] -name = "aho-corasick" -version = "1.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" -dependencies = [ - "memchr", -] - [[package]] name = "aligned" version = "0.4.3" @@ -51,16 +42,6 @@ dependencies = [ "equator", ] -[[package]] -name = "annotate-snippets" -version = "0.11.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "710e8eae58854cdc1790fcb56cca04d712a17be849eeb81da2a724bf4bae2bc4" -dependencies = [ - "anstyle", - "unicode-width", -] - [[package]] name = "anstream" version = "1.0.0" @@ -97,7 +78,7 @@ version = "1.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc" dependencies = [ - "windows-sys 0.61.2", + "windows-sys", ] [[package]] @@ -108,7 +89,7 @@ checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d" dependencies = [ "anstyle", "once_cell_polyfill", - "windows-sys 0.61.2", + "windows-sys", ] [[package]] @@ -158,143 +139,6 @@ dependencies = [ "stable_deref_trait", ] -[[package]] -name = "async-broadcast" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "435a87a52755b8f27fcf321ac4f04b2802e337c8c4872923137471ec39c37532" -dependencies = [ - "event-listener", - "event-listener-strategy", - "futures-core", - "pin-project-lite", -] - -[[package]] -name = "async-channel" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "924ed96dd52d1b75e9c1a3e6275715fd320f5f9439fb5a4a11fa51f4221158d2" -dependencies = [ - "concurrent-queue", - "event-listener-strategy", - "futures-core", - "pin-project-lite", -] - -[[package]] -name = "async-executor" -version = "1.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c96bf972d85afc50bf5ab8fe2d54d1586b4e0b46c97c50a0c9e71e2f7bcd812a" -dependencies = [ - "async-task", - "concurrent-queue", - "fastrand", - "futures-lite", - "pin-project-lite", - "slab", -] - -[[package]] -name = "async-io" -version = "2.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "456b8a8feb6f42d237746d4b3e9a178494627745c3c56c6ea55d92ba50d026fc" -dependencies = [ - "autocfg", - "cfg-if", - "concurrent-queue", - "futures-io", - "futures-lite", - "parking", - "polling", - "rustix 1.1.4", - "slab", - "windows-sys 0.61.2", -] - -[[package]] -name = "async-lock" -version = "3.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "290f7f2596bd5b78a9fec8088ccd89180d7f9f55b94b0576823bbbdc72ee8311" -dependencies = [ - "event-listener", - "event-listener-strategy", - "pin-project-lite", -] - -[[package]] -name = "async-process" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc50921ec0055cdd8a16de48773bfeec5c972598674347252c0399676be7da75" -dependencies = [ - "async-channel", - "async-io", - "async-lock", - "async-signal", - "async-task", - "blocking", - "cfg-if", - "event-listener", - "futures-lite", - "rustix 1.1.4", -] - -[[package]] -name = "async-recursion" -version = "1.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "async-signal" -version = "0.2.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43c070bbf59cd3570b6b2dd54cd772527c7c3620fce8be898406dd3ed6adc64c" -dependencies = [ - "async-io", - "async-lock", - "atomic-waker", - "cfg-if", - "futures-core", - "futures-io", - "rustix 1.1.4", - "signal-hook-registry", - "slab", - "windows-sys 0.61.2", -] - -[[package]] -name = "async-task" -version = "4.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de" - -[[package]] -name = "async-trait" -version = "0.1.89" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "atomic-waker" -version = "1.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" - [[package]] name = "autocfg" version = "1.5.0" @@ -330,7 +174,7 @@ dependencies = [ "anyhow", "arrayvec", "log", - "nom 8.0.0", + "nom", "num-rational", "v_frame", ] @@ -344,37 +188,12 @@ dependencies = [ "arrayvec", ] -[[package]] -name = "bindgen" -version = "0.72.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "993776b509cfb49c750f11b8f07a46fa23e0a1386ffc01fb1e7d343efc387895" -dependencies = [ - "annotate-snippets", - "bitflags 2.11.0", - "cexpr", - "clang-sys", - "itertools 0.13.0", - "proc-macro2", - "quote", - "regex", - "rustc-hash", - "shlex", - "syn", -] - [[package]] name = "bit_field" version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e4b40c7323adcfc0a41c4b88143ed58346ff65a288fc144329c5c45e05d70c6" -[[package]] -name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - [[package]] name = "bitflags" version = "2.11.0" @@ -390,28 +209,6 @@ dependencies = [ "core2", ] -[[package]] -name = "block2" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdeb9d870516001442e364c5220d3574d2da8dc765554b4a617230d33fa58ef5" -dependencies = [ - "objc2", -] - -[[package]] -name = "blocking" -version = "1.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e83f8d02be6967315521be875afa792a316e28d57b5a2d401897e2a7921b7f21" -dependencies = [ - "async-channel", - "async-task", - "futures-io", - "futures-lite", - "piper", -] - [[package]] name = "built" version = "0.8.0" @@ -429,20 +226,6 @@ name = "bytemuck" version = "1.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c8efb64bd706a16a1bdde310ae86b351e4d21550d98d056f22f8a7f7a2183fec" -dependencies = [ - "bytemuck_derive", -] - -[[package]] -name = "bytemuck_derive" -version = "1.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9abbd1bc6865053c427f7198e6af43bfdedc55ab791faed4fbd361d789575ff" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] [[package]] name = "byteorder-lite" @@ -468,48 +251,12 @@ dependencies = [ "shlex", ] -[[package]] -name = "cexpr" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" -dependencies = [ - "nom 7.1.3", -] - -[[package]] -name = "cfg-expr" -version = "0.20.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c6b04e07d8080154ed4ac03546d9a2b303cc2fe1901ba0b35b301516e289368" -dependencies = [ - "smallvec", - "target-lexicon", -] - [[package]] name = "cfg-if" version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" -[[package]] -name = "cfg_aliases" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" - -[[package]] -name = "clang-sys" -version = "1.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4" -dependencies = [ - "glob", - "libc", - "libloading", -] - [[package]] name = "clap" version = "4.6.0" @@ -562,30 +309,6 @@ version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1d07550c9036bf2ae0c684c4297d503f838287c83c53686d05370d0e139ae570" -[[package]] -name = "concurrent-queue" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" -dependencies = [ - "crossbeam-utils", -] - -[[package]] -name = "convert_case" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baaaa0ecca5b51987b9423ccdc971514dd8b0bb7b4060b983d3664dad3f1f89f" -dependencies = [ - "unicode-segmentation", -] - -[[package]] -name = "cookie-factory" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9885fa71e26b8ab7855e2ec7cae6e9b380edff76cd052e07c683a0319d51b3a2" - [[package]] name = "core-foundation" version = "0.10.1" @@ -608,7 +331,7 @@ version = "0.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "064badf302c3194842cf2c5d61f56cc88e54a759313879cdf03abdd27d0c3b97" dependencies = [ - "bitflags 2.11.0", + "bitflags", "core-foundation", "core-graphics-types", "foreign-types", @@ -621,7 +344,7 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d44a101f213f6c4cdc1853d4b78aef6db6bdfa3468798cc1d9912f4735013eb" dependencies = [ - "bitflags 2.11.0", + "bitflags", "core-foundation", "libc", ] @@ -692,7 +415,6 @@ dependencies = [ "tokio", "uuid", "x11rb", - "xcap", ] [[package]] @@ -713,7 +435,7 @@ dependencies = [ "libc", "option-ext", "redox_users", - "windows-sys 0.61.2", + "windows-sys", ] [[package]] @@ -722,90 +444,16 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e0e367e4e7da84520dedcac1901e4da967309406d1e51017ae1abfb97adbd38" dependencies = [ - "bitflags 2.11.0", - "block2", - "libc", + "bitflags", "objc2", ] -[[package]] -name = "displaydoc" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "dlib" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab8ecd87370524b461f8557c119c405552c396ed91fc0a8eec68679eab26f94a" -dependencies = [ - "libloading", -] - -[[package]] -name = "downcast-rs" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2" - -[[package]] -name = "drm" -version = "0.14.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80bc8c5c6c2941f70a55c15f8d9f00f9710ebda3ffda98075f996a0e6c92756f" -dependencies = [ - "bitflags 2.11.0", - "bytemuck", - "drm-ffi", - "drm-fourcc", - "libc", - "rustix 0.38.44", -] - -[[package]] -name = "drm-ffi" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51a91c9b32ac4e8105dec255e849e0d66e27d7c34d184364fb93e469db08f690" -dependencies = [ - "drm-sys", - "rustix 1.1.4", -] - -[[package]] -name = "drm-fourcc" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0aafbcdb8afc29c1a7ee5fbe53b5d62f4565b35a042a662ca9fecd0b54dae6f4" - -[[package]] -name = "drm-sys" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ecc8e1361066d91f5ffccff060a3c3be9c3ecde15be2959c1937595f7a82a9f8" -dependencies = [ - "libc", - "linux-raw-sys 0.9.4", -] - [[package]] name = "either" version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" -[[package]] -name = "endi" -version = "1.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66b7e2430c6dff6a955451e2cfc438f09cea1965a9d6f87f7e3b90decc014099" - [[package]] name = "enigo" version = "0.6.1" @@ -817,37 +465,16 @@ dependencies = [ "foreign-types-shared", "libc", "log", - "nom 8.0.0", + "nom", "objc2", "objc2-app-kit", "objc2-foundation", - "windows 0.61.3", + "windows", "x11rb", "xkbcommon", "xkeysym", ] -[[package]] -name = "enumflags2" -version = "0.7.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1027f7680c853e056ebcec683615fb6fbbc07dbaa13b4d5d9442b146ded4ecef" -dependencies = [ - "enumflags2_derive", - "serde", -] - -[[package]] -name = "enumflags2_derive" -version = "0.7.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67c78a4d8fdf9953a5c9d458f9efe940fd97a0cab0941c075a813ac594733827" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "equator" version = "0.4.2" @@ -881,28 +508,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" dependencies = [ "libc", - "windows-sys 0.61.2", -] - -[[package]] -name = "event-listener" -version = "5.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e13b66accf52311f30a0db42147dadea9850cb48cd070028831ae5f5d4b856ab" -dependencies = [ - "concurrent-queue", - "parking", - "pin-project-lite", -] - -[[package]] -name = "event-listener-strategy" -version = "0.5.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8be9f3dfaaffdae2972880079a491a1a8bb7cbed0b8dd7a347f668b4150a3b93" -dependencies = [ - "event-listener", - "pin-project-lite", + "windows-sys", ] [[package]] @@ -920,12 +526,6 @@ dependencies = [ "zune-inflate", ] -[[package]] -name = "fastrand" -version = "2.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" - [[package]] name = "fax" version = "0.2.6" @@ -1004,71 +604,13 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "aa9a19cbb55df58761df49b23516a86d432839add4af60fc256da840f66ed35b" -[[package]] -name = "form_urlencoded" -version = "1.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" -dependencies = [ - "percent-encoding", -] - -[[package]] -name = "futures-core" -version = "0.3.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d" - -[[package]] -name = "futures-io" -version = "0.3.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cecba35d7ad927e23624b22ad55235f2239cfa44fd10428eecbeba6d6a717718" - -[[package]] -name = "futures-lite" -version = "2.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f78e10609fe0e0b3f4157ffab1876319b5b0db102a2c60dc4626306dc46b44ad" -dependencies = [ - "fastrand", - "futures-core", - "futures-io", - "parking", - "pin-project-lite", -] - -[[package]] -name = "gbm" -version = "0.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce852e998d3ca5e4a97014fb31c940dc5ef344ec7d364984525fd11e8a547e6a" -dependencies = [ - "bitflags 2.11.0", - "drm", - "drm-fourcc", - "gbm-sys", - "libc", - "wayland-backend", - "wayland-server", -] - -[[package]] -name = "gbm-sys" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c13a5f2acc785d8fb6bf6b7ab6bfb0ef5dad4f4d97e8e70bb8e470722312f76f" -dependencies = [ - "libc", -] - [[package]] name = "gethostname" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1bd49230192a3797a9a4d6abe9b3eed6f7fa4c8a8a4947977c6f80025f92cbd8" dependencies = [ - "rustix 1.1.4", + "rustix", "windows-link 0.2.1", ] @@ -1120,26 +662,6 @@ dependencies = [ "weezl", ] -[[package]] -name = "gl" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a94edab108827d67608095e269cf862e60d920f144a5026d3dbcfd8b877fb404" -dependencies = [ - "gl_generator", -] - -[[package]] -name = "gl_generator" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a95dfc23a2b4a9a2f5ab41d194f8bfda3cabec42af4e39f08c339eb2a0c124d" -dependencies = [ - "khronos_api", - "log", - "xml-rs", -] - [[package]] name = "glam" version = "0.14.0" @@ -1236,12 +758,6 @@ version = "0.30.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "19fc433e8437a212d1b6f1e68c7824af3aed907da60afa994e7f542d18d12aa9" -[[package]] -name = "glob" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" - [[package]] name = "half" version = "2.7.1" @@ -1274,126 +790,12 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" -[[package]] -name = "hermit-abi" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" - -[[package]] -name = "hex" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" - -[[package]] -name = "icu_collections" -version = "2.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c6b649701667bbe825c3b7e6388cb521c23d88644678e83c0c4d0a621a34b43" -dependencies = [ - "displaydoc", - "potential_utf", - "yoke", - "zerofrom", - "zerovec", -] - -[[package]] -name = "icu_locale_core" -version = "2.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edba7861004dd3714265b4db54a3c390e880ab658fec5f7db895fae2046b5bb6" -dependencies = [ - "displaydoc", - "litemap", - "tinystr", - "writeable", - "zerovec", -] - -[[package]] -name = "icu_normalizer" -version = "2.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f6c8828b67bf8908d82127b2054ea1b4427ff0230ee9141c54251934ab1b599" -dependencies = [ - "icu_collections", - "icu_normalizer_data", - "icu_properties", - "icu_provider", - "smallvec", - "zerovec", -] - -[[package]] -name = "icu_normalizer_data" -version = "2.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7aedcccd01fc5fe81e6b489c15b247b8b0690feb23304303a9e560f37efc560a" - -[[package]] -name = "icu_properties" -version = "2.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "020bfc02fe870ec3a66d93e677ccca0562506e5872c650f893269e08615d74ec" -dependencies = [ - "icu_collections", - "icu_locale_core", - "icu_properties_data", - "icu_provider", - "zerotrie", - "zerovec", -] - -[[package]] -name = "icu_properties_data" -version = "2.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "616c294cf8d725c6afcd8f55abc17c56464ef6211f9ed59cccffe534129c77af" - -[[package]] -name = "icu_provider" -version = "2.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85962cf0ce02e1e0a629cc34e7ca3e373ce20dda4c4d7294bbd0bf1fdb59e614" -dependencies = [ - "displaydoc", - "icu_locale_core", - "writeable", - "yoke", - "zerofrom", - "zerotrie", - "zerovec", -] - [[package]] name = "id-arena" version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954" -[[package]] -name = "idna" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" -dependencies = [ - "idna_adapter", - "smallvec", - "utf8_iter", -] - -[[package]] -name = "idna_adapter" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" -dependencies = [ - "icu_normalizer", - "icu_properties", -] - [[package]] name = "image" version = "0.25.10" @@ -1438,7 +840,7 @@ dependencies = [ "approx", "getrandom 0.3.4", "image", - "itertools 0.14.0", + "itertools", "nalgebra", "num", "rand", @@ -1482,15 +884,6 @@ version = "1.70.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" -[[package]] -name = "itertools" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" -dependencies = [ - "either", -] - [[package]] name = "itertools" version = "0.14.0" @@ -1526,28 +919,6 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "khronos-egl" -version = "6.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6aae1df220ece3c0ada96b8153459b67eebe9ae9212258bb0134ae60416fdf76" -dependencies = [ - "libc", - "pkg-config", -] - -[[package]] -name = "khronos_api" -version = "3.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2db585e1d738fc771bf08a151420d3ed193d9d895a36df7f6f8a9456b911ddc" - -[[package]] -name = "lazy_static" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" - [[package]] name = "leb128fmt" version = "0.1.0" @@ -1576,16 +947,6 @@ dependencies = [ "cc", ] -[[package]] -name = "libloading" -version = "0.8.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7c4b02199fee7c5d21a5ae7d8cfa79a6ef5bb2fc834d6e9058e89c825efdc55" -dependencies = [ - "cfg-if", - "windows-link 0.2.1", -] - [[package]] name = "libm" version = "0.2.16" @@ -1601,79 +962,12 @@ dependencies = [ "libc", ] -[[package]] -name = "libspa" -version = "0.9.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6b8cfa2a7656627b4c92c6b9ef929433acd673d5ab3708cda1b18478ac00df4" -dependencies = [ - "bitflags 2.11.0", - "cc", - "convert_case", - "cookie-factory", - "libc", - "libspa-sys", - "nix", - "nom 8.0.0", - "system-deps", -] - -[[package]] -name = "libspa-sys" -version = "0.9.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "901049455d2eb6decf9058235d745237952f4804bc584c5fcb41412e6adcc6e0" -dependencies = [ - "bindgen", - "cc", - "system-deps", -] - -[[package]] -name = "libwayshot-xcap" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "558a3a7ca16a17a14adf8f051b3adcd7766d397532f5f6d6a48034db11e54c22" -dependencies = [ - "drm", - "gbm", - "gl", - "image", - "khronos-egl", - "memmap2", - "rustix 1.1.4", - "thiserror", - "tracing", - "wayland-backend", - "wayland-client", - "wayland-protocols", - "wayland-protocols-wlr", -] - -[[package]] -name = "linux-raw-sys" -version = "0.4.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" - -[[package]] -name = "linux-raw-sys" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12" - [[package]] name = "linux-raw-sys" version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53" -[[package]] -name = "litemap" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6373607a59f0be73a39b6fe456b8192fcc3585f602af20751600e974dd455e77" - [[package]] name = "lock_api" version = "0.4.14" @@ -1733,21 +1027,6 @@ dependencies = [ "libc", ] -[[package]] -name = "memoffset" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a" -dependencies = [ - "autocfg", -] - -[[package]] -name = "minimal-lexical" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" - [[package]] name = "miniz_oxide" version = "0.8.9" @@ -1766,7 +1045,7 @@ checksum = "a69bcab0ad47271a0234d9422b131806bf3968021e5dc9328caf2d4cd58557fc" dependencies = [ "libc", "wasi", - "windows-sys 0.61.2", + "windows-sys", ] [[package]] @@ -1816,28 +1095,6 @@ version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" -[[package]] -name = "nix" -version = "0.30.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74523f3a35e05aba87a1d978330aef40f67b0304ac79c1c00b294c9830543db6" -dependencies = [ - "bitflags 2.11.0", - "cfg-if", - "cfg_aliases", - "libc", -] - -[[package]] -name = "nom" -version = "7.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" -dependencies = [ - "memchr", - "minimal-lexical", -] - [[package]] name = "nom" version = "8.0.0" @@ -1952,93 +1209,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d49e936b501e5c5bf01fda3a9452ff86dc3ea98ad5f283e1455153142d97518c" dependencies = [ - "bitflags 2.11.0", - "block2", - "libc", - "objc2", - "objc2-cloud-kit", - "objc2-core-data", - "objc2-core-foundation", - "objc2-core-graphics", - "objc2-core-image", - "objc2-core-text", - "objc2-core-video", - "objc2-foundation", - "objc2-quartz-core", -] - -[[package]] -name = "objc2-av-foundation" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "478ae33fcac9df0a18db8302387c666b8ef08a3e2d62b510ca4fc278a384b6c0" -dependencies = [ - "bitflags 2.11.0", - "block2", - "dispatch2", - "objc2", - "objc2-avf-audio", - "objc2-core-audio-types", - "objc2-core-foundation", - "objc2-core-graphics", - "objc2-core-image", - "objc2-core-video", - "objc2-foundation", - "objc2-image-io", - "objc2-media-toolbox", - "objc2-quartz-core", -] - -[[package]] -name = "objc2-avf-audio" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13a380031deed8e99db00065c45937da434ca987c034e13b87e4441f9e4090be" -dependencies = [ - "objc2", - "objc2-foundation", -] - -[[package]] -name = "objc2-cloud-kit" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73ad74d880bb43877038da939b7427bba67e9dd42004a18b809ba7d87cee241c" -dependencies = [ - "bitflags 2.11.0", - "objc2", - "objc2-foundation", -] - -[[package]] -name = "objc2-core-audio" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1eebcea8b0dbff5f7c8504f3107c68fc061a3eb44932051c8cf8a68d969c3b2" -dependencies = [ - "dispatch2", - "objc2", - "objc2-core-audio-types", - "objc2-core-foundation", -] - -[[package]] -name = "objc2-core-audio-types" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a89f2ec274a0cf4a32642b2991e8b351a404d290da87bb6a9a9d8632490bd1c" -dependencies = [ - "bitflags 2.11.0", - "objc2", -] - -[[package]] -name = "objc2-core-data" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b402a653efbb5e82ce4df10683b6b28027616a2715e90009947d50b8dd298fa" -dependencies = [ - "bitflags 2.11.0", + "bitflags", "objc2", "objc2-foundation", ] @@ -2049,80 +1220,9 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2a180dd8642fa45cdb7dd721cd4c11b1cadd4929ce112ebd8b9f5803cc79d536" dependencies = [ - "bitflags 2.11.0", - "block2", - "dispatch2", - "libc", - "objc2", -] - -[[package]] -name = "objc2-core-graphics" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e022c9d066895efa1345f8e33e584b9f958da2fd4cd116792e15e07e4720a807" -dependencies = [ - "bitflags 2.11.0", - "block2", - "dispatch2", - "libc", - "objc2", - "objc2-core-foundation", - "objc2-io-surface", - "objc2-metal", -] - -[[package]] -name = "objc2-core-image" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5d563b38d2b97209f8e861173de434bd0214cf020e3423a52624cd1d989f006" -dependencies = [ - "objc2", - "objc2-foundation", -] - -[[package]] -name = "objc2-core-media" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05ec576860167a15dd9fce7fbee7512beb4e31f532159d3482d1f9c6caedf31d" -dependencies = [ - "bitflags 2.11.0", - "block2", + "bitflags", "dispatch2", "objc2", - "objc2-core-audio", - "objc2-core-audio-types", - "objc2-core-foundation", - "objc2-core-video", -] - -[[package]] -name = "objc2-core-text" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0cde0dfb48d25d2b4862161a4d5fcc0e3c24367869ad306b0c9ec0073bfed92d" -dependencies = [ - "bitflags 2.11.0", - "objc2", - "objc2-core-foundation", - "objc2-core-graphics", -] - -[[package]] -name = "objc2-core-video" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d425caf1df73233f29fd8a5c3e5edbc30d2d4307870f802d18f00d83dc5141a6" -dependencies = [ - "bitflags 2.11.0", - "block2", - "objc2", - "objc2-core-foundation", - "objc2-core-graphics", - "objc2-io-surface", - "objc2-metal", ] [[package]] @@ -2137,69 +1237,11 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3e0adef53c21f888deb4fa59fc59f7eb17404926ee8a6f59f5df0fd7f9f3272" dependencies = [ - "bitflags 2.11.0", - "block2", - "libc", + "bitflags", "objc2", "objc2-core-foundation", ] -[[package]] -name = "objc2-image-io" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32b0446e98cf4a784cc7a0177715ff317eeaa8463841c616cfc78aa4f953c4ea" -dependencies = [ - "objc2", - "objc2-core-foundation", - "objc2-core-graphics", -] - -[[package]] -name = "objc2-io-surface" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "180788110936d59bab6bd83b6060ffdfffb3b922ba1396b312ae795e1de9d81d" -dependencies = [ - "bitflags 2.11.0", - "objc2", - "objc2-core-foundation", -] - -[[package]] -name = "objc2-media-toolbox" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edd9fdde720df3da7046bb9097811000c1e7ab5cd579fa89d96b27d56781fb30" -dependencies = [ - "objc2", - "objc2-core-audio-types", - "objc2-core-foundation", - "objc2-core-media", -] - -[[package]] -name = "objc2-metal" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0125f776a10d00af4152d74616409f0d4a2053a6f57fa5b7d6aa2854ac04794" -dependencies = [ - "bitflags 2.11.0", - "objc2", - "objc2-foundation", -] - -[[package]] -name = "objc2-quartz-core" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96c1358452b371bf9f104e21ec536d37a650eb10f7ee379fff67d2e08d537f1f" -dependencies = [ - "bitflags 2.11.0", - "objc2", - "objc2-foundation", -] - [[package]] name = "once_cell" version = "1.21.4" @@ -2218,16 +1260,6 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" -[[package]] -name = "ordered-stream" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9aa2b01e1d916879f73a53d01d1d6cee68adbb31d6d9177a8cfce093cced1d50" -dependencies = [ - "futures-core", - "pin-project-lite", -] - [[package]] name = "owned_ttf_parser" version = "0.25.1" @@ -2237,12 +1269,6 @@ dependencies = [ "ttf-parser", ] -[[package]] -name = "parking" -version = "2.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" - [[package]] name = "parking_lot" version = "0.12.5" @@ -2278,99 +1304,25 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "35fb2e5f958ec131621fdd531e9fc186ed768cbe395337403ae56c17a74c68ec" -[[package]] -name = "percent-encoding" -version = "2.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" - [[package]] name = "pin-project-lite" version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" -[[package]] -name = "piper" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c835479a4443ded371d6c535cbfd8d31ad92c5d23ae9770a61bc155e4992a3c1" -dependencies = [ - "atomic-waker", - "fastrand", - "futures-io", -] - -[[package]] -name = "pipewire" -version = "0.9.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9688b89abf11d756499f7c6190711d6dbe5a3acdb30c8fbf001d6596d06a8d44" -dependencies = [ - "anyhow", - "bitflags 2.11.0", - "libc", - "libspa", - "libspa-sys", - "nix", - "once_cell", - "pipewire-sys", - "thiserror", -] - -[[package]] -name = "pipewire-sys" -version = "0.9.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb028afee0d6ca17020b090e3b8fa2d7de23305aef975c7e5192a5050246ea36" -dependencies = [ - "bindgen", - "libspa-sys", - "system-deps", -] - -[[package]] -name = "pkg-config" -version = "0.3.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" - [[package]] name = "png" version = "0.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "60769b8b31b2a9f263dae2776c37b1b28ae246943cf719eb6946a1db05128a61" dependencies = [ - "bitflags 2.11.0", + "bitflags", "crc32fast", "fdeflate", "flate2", "miniz_oxide", ] -[[package]] -name = "polling" -version = "3.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d0e4f59085d47d8241c88ead0f274e8a0cb551f3625263c05eb8dd897c34218" -dependencies = [ - "cfg-if", - "concurrent-queue", - "hermit-abi", - "pin-project-lite", - "rustix 1.1.4", - "windows-sys 0.61.2", -] - -[[package]] -name = "potential_utf" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b73949432f5e2a09657003c25bca5e19a0e9c84f8058ca374f49e0ebe605af77" -dependencies = [ - "zerovec", -] - [[package]] name = "ppv-lite86" version = "0.2.21" @@ -2399,15 +1351,6 @@ dependencies = [ "num-integer", ] -[[package]] -name = "proc-macro-crate" -version = "3.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e67ba7e9b2b56446f1d419b1d807906278ffa1a658a8a5d8a39dcb1f5a78614f" -dependencies = [ - "toml_edit", -] - [[package]] name = "proc-macro2" version = "1.0.106" @@ -2457,24 +1400,6 @@ version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3" -[[package]] -name = "quick-xml" -version = "0.30.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eff6510e86862b57b210fd8cbe8ed3f0d7d600b9c2863cd4549a2e033c66e956" -dependencies = [ - "memchr", -] - -[[package]] -name = "quick-xml" -version = "0.39.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "958f21e8e7ceb5a1aa7fa87fab28e7c75976e0bfe7e23ff069e0a260f894067d" -dependencies = [ - "memchr", -] - [[package]] name = "quote" version = "1.0.45" @@ -2551,7 +1476,7 @@ dependencies = [ "built", "cfg-if", "interpolate_name", - "itertools 0.14.0", + "itertools", "libc", "libfuzzer-sys", "log", @@ -2617,7 +1542,7 @@ version = "0.5.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" dependencies = [ - "bitflags 2.11.0", + "bitflags", ] [[package]] @@ -2631,47 +1556,12 @@ dependencies = [ "thiserror", ] -[[package]] -name = "regex" -version = "1.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276" -dependencies = [ - "aho-corasick", - "memchr", - "regex-automata", - "regex-syntax", -] - -[[package]] -name = "regex-automata" -version = "0.4.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f" -dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax", -] - -[[package]] -name = "regex-syntax" -version = "0.8.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a" - [[package]] name = "rgb" version = "0.8.53" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "47b34b781b31e5d73e9fbc8689c70551fd1ade9a19e3e28cfec8580a79290cc4" -[[package]] -name = "rustc-hash" -version = "2.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" - [[package]] name = "rustdct" version = "0.7.1" @@ -2695,30 +1585,17 @@ dependencies = [ "transpose", ] -[[package]] -name = "rustix" -version = "0.38.44" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" -dependencies = [ - "bitflags 2.11.0", - "errno", - "libc", - "linux-raw-sys 0.4.15", - "windows-sys 0.59.0", -] - [[package]] name = "rustix" version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190" dependencies = [ - "bitflags 2.11.0", + "bitflags", "errno", "libc", - "linux-raw-sys 0.12.1", - "windows-sys 0.61.2", + "linux-raw-sys", + "windows-sys", ] [[package]] @@ -2736,12 +1613,6 @@ dependencies = [ "bytemuck", ] -[[package]] -name = "scoped-tls" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" - [[package]] name = "scopeguard" version = "1.2.0" @@ -2797,26 +1668,6 @@ dependencies = [ "zmij", ] -[[package]] -name = "serde_repr" -version = "0.1.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "175ee3e80ae9982737ca543e96133087cbd9a485eecc3bc4de9c1a37b47ea59c" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "serde_spanned" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "876ac351060d4f882bb1032b6369eb0aef79ad9df1ea8bc404874d8cc3d0cd98" -dependencies = [ - "serde_core", -] - [[package]] name = "shlex" version = "1.3.0" @@ -2861,12 +1712,6 @@ dependencies = [ "quote", ] -[[package]] -name = "slab" -version = "0.4.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" - [[package]] name = "smallvec" version = "1.15.1" @@ -2880,7 +1725,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3a766e1110788c36f4fa1c2b71b387a7815aa65f88ce0229841826633d93723e" dependencies = [ "libc", - "windows-sys 0.61.2", + "windows-sys", ] [[package]] @@ -2912,49 +1757,6 @@ dependencies = [ "unicode-ident", ] -[[package]] -name = "synstructure" -version = "0.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "system-deps" -version = "7.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48c8f33736f986f16d69b6cb8b03f55ddcad5c41acc4ccc39dd88e84aa805e7f" -dependencies = [ - "cfg-expr", - "heck", - "pkg-config", - "toml", - "version-compare", -] - -[[package]] -name = "target-lexicon" -version = "0.13.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df7f62577c25e07834649fc3b39fafdc597c0a3527dc1c60129201ccfcbaa50c" - -[[package]] -name = "tempfile" -version = "3.27.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd" -dependencies = [ - "fastrand", - "getrandom 0.4.2", - "once_cell", - "rustix 1.1.4", - "windows-sys 0.61.2", -] - [[package]] name = "thiserror" version = "2.0.18" @@ -2989,16 +1791,6 @@ dependencies = [ "zune-jpeg", ] -[[package]] -name = "tinystr" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42d3e9c45c09de15d06dd8acf5f4e0e399e85927b7f00711024eb7ae10fa4869" -dependencies = [ - "displaydoc", - "zerovec", -] - [[package]] name = "tokio" version = "1.50.0" @@ -3013,7 +1805,7 @@ dependencies = [ "signal-hook-registry", "socket2", "tokio-macros", - "windows-sys 0.61.2", + "windows-sys", ] [[package]] @@ -3027,97 +1819,6 @@ dependencies = [ "syn", ] -[[package]] -name = "toml" -version = "0.9.12+spec-1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf92845e79fc2e2def6a5d828f0801e29a2f8acc037becc5ab08595c7d5e9863" -dependencies = [ - "indexmap", - "serde_core", - "serde_spanned", - "toml_datetime 0.7.5+spec-1.1.0", - "toml_parser", - "toml_writer", - "winnow 0.7.15", -] - -[[package]] -name = "toml_datetime" -version = "0.7.5+spec-1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92e1cfed4a3038bc5a127e35a2d360f145e1f4b971b551a2ba5fd7aedf7e1347" -dependencies = [ - "serde_core", -] - -[[package]] -name = "toml_datetime" -version = "1.1.0+spec-1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97251a7c317e03ad83774a8752a7e81fb6067740609f75ea2b585b569a59198f" -dependencies = [ - "serde_core", -] - -[[package]] -name = "toml_edit" -version = "0.25.8+spec-1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16bff38f1d86c47f9ff0647e6838d7bb362522bdf44006c7068c2b1e606f1f3c" -dependencies = [ - "indexmap", - "toml_datetime 1.1.0+spec-1.1.0", - "toml_parser", - "winnow 1.0.0", -] - -[[package]] -name = "toml_parser" -version = "1.1.0+spec-1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2334f11ee363607eb04df9b8fc8a13ca1715a72ba8662a26ac285c98aabb4011" -dependencies = [ - "winnow 1.0.0", -] - -[[package]] -name = "toml_writer" -version = "1.1.0+spec-1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d282ade6016312faf3e41e57ebbba0c073e4056dab1232ab1cb624199648f8ed" - -[[package]] -name = "tracing" -version = "0.1.44" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" -dependencies = [ - "pin-project-lite", - "tracing-attributes", - "tracing-core", -] - -[[package]] -name = "tracing-attributes" -version = "0.1.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "tracing-core" -version = "0.1.36" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a" -dependencies = [ - "once_cell", -] - [[package]] name = "transpose" version = "0.2.3" @@ -3140,59 +1841,18 @@ version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" -[[package]] -name = "uds_windows" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2f6fb2847f6742cd76af783a2a2c49e9375d0a111c7bef6f71cd9e738c72d6e" -dependencies = [ - "memoffset", - "tempfile", - "windows-sys 0.61.2", -] - [[package]] name = "unicode-ident" version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" -[[package]] -name = "unicode-segmentation" -version = "1.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da36089a805484bcccfffe0739803392c8298778a2d2f09febf76fac5ad9025b" - -[[package]] -name = "unicode-width" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254" - [[package]] name = "unicode-xid" version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" -[[package]] -name = "url" -version = "2.5.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed" -dependencies = [ - "form_urlencoded", - "idna", - "percent-encoding", - "serde", -] - -[[package]] -name = "utf8_iter" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" - [[package]] name = "utf8parse" version = "0.2.2" @@ -3207,7 +1867,6 @@ checksum = "a68d3c8f01c0cfa54a75291d83601161799e4a89a39e0929f4b0354d88757a37" dependencies = [ "getrandom 0.4.2", "js-sys", - "serde_core", "wasm-bindgen", ] @@ -3222,12 +1881,6 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "version-compare" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03c2856837ef78f57382f06b2b8563a2f512f7185d732608fd9176cb3b8edf0e" - [[package]] name = "wasi" version = "0.11.1+wasi-snapshot-preview1" @@ -3325,100 +1978,12 @@ version = "0.244.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe" dependencies = [ - "bitflags 2.11.0", + "bitflags", "hashbrown 0.15.5", "indexmap", "semver", ] -[[package]] -name = "wayland-backend" -version = "0.3.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa75f400b7f719bcd68b3f47cd939ba654cedeef690f486db71331eec4c6a406" -dependencies = [ - "cc", - "downcast-rs", - "rustix 1.1.4", - "scoped-tls", - "smallvec", - "wayland-sys", -] - -[[package]] -name = "wayland-client" -version = "0.31.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab51d9f7c071abeee76007e2b742499e535148035bb835f97aaed1338cf516c3" -dependencies = [ - "bitflags 2.11.0", - "rustix 1.1.4", - "wayland-backend", - "wayland-scanner", -] - -[[package]] -name = "wayland-protocols" -version = "0.32.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b23b5df31ceff1328f06ac607591d5ba360cf58f90c8fad4ac8d3a55a3c4aec7" -dependencies = [ - "bitflags 2.11.0", - "wayland-backend", - "wayland-client", - "wayland-scanner", -] - -[[package]] -name = "wayland-protocols-wlr" -version = "0.3.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78248e4cc0eff8163370ba5c158630dcae1f3497a586b826eca2ef5f348d6235" -dependencies = [ - "bitflags 2.11.0", - "wayland-backend", - "wayland-client", - "wayland-protocols", - "wayland-scanner", -] - -[[package]] -name = "wayland-scanner" -version = "0.31.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c86287151a309799b821ca709b7345a048a2956af05957c89cb824ab919fa4e3" -dependencies = [ - "proc-macro2", - "quick-xml 0.39.2", - "quote", -] - -[[package]] -name = "wayland-server" -version = "0.31.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63736a4a73e781cf6a736aa32c5d6773c3eb5389197562742a8c611b49b5e359" -dependencies = [ - "bitflags 2.11.0", - "downcast-rs", - "rustix 1.1.4", - "wayland-backend", - "wayland-scanner", -] - -[[package]] -name = "wayland-sys" -version = "0.31.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "374f6b70e8e0d6bf9461a32988fd553b59ff630964924dad6e4a4eb6bd538d17" -dependencies = [ - "dlib", - "libc", - "log", - "memoffset", - "pkg-config", -] - [[package]] name = "weezl" version = "0.1.12" @@ -3435,35 +2000,17 @@ dependencies = [ "safe_arch", ] -[[package]] -name = "widestring" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72069c3113ab32ab29e5584db3c6ec55d416895e60715417b5b883a357c3e471" - [[package]] name = "windows" version = "0.61.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9babd3a767a4c1aef6900409f85f5d53ce2544ccdfaa86dad48c91782c6d6893" dependencies = [ - "windows-collections 0.2.0", - "windows-core 0.61.2", - "windows-future 0.2.1", + "windows-collections", + "windows-core", + "windows-future", "windows-link 0.1.3", - "windows-numerics 0.2.0", -] - -[[package]] -name = "windows" -version = "0.62.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "527fadee13e0c05939a6a05d5bd6eec6cd2e3dbd648b9f8e447c6518133d8580" -dependencies = [ - "windows-collections 0.3.2", - "windows-core 0.62.2", - "windows-future 0.3.2", - "windows-numerics 0.3.1", + "windows-numerics", ] [[package]] @@ -3472,16 +2019,7 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3beeceb5e5cfd9eb1d76b381630e82c4241ccd0d27f1a39ed41b2760b255c5e8" dependencies = [ - "windows-core 0.61.2", -] - -[[package]] -name = "windows-collections" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23b2d95af1a8a14a3c7367e1ed4fc9c20e0a26e79551b1454d72583c97cc6610" -dependencies = [ - "windows-core 0.62.2", + "windows-core", ] [[package]] @@ -3493,21 +2031,8 @@ dependencies = [ "windows-implement", "windows-interface", "windows-link 0.1.3", - "windows-result 0.3.4", - "windows-strings 0.4.2", -] - -[[package]] -name = "windows-core" -version = "0.62.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb" -dependencies = [ - "windows-implement", - "windows-interface", - "windows-link 0.2.1", - "windows-result 0.4.1", - "windows-strings 0.5.1", + "windows-result", + "windows-strings", ] [[package]] @@ -3516,20 +2041,9 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc6a41e98427b19fe4b73c550f060b59fa592d7d686537eebf9385621bfbad8e" dependencies = [ - "windows-core 0.61.2", + "windows-core", "windows-link 0.1.3", - "windows-threading 0.1.0", -] - -[[package]] -name = "windows-future" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1d6f90251fe18a279739e78025bd6ddc52a7e22f921070ccdc67dde84c605cb" -dependencies = [ - "windows-core 0.62.2", - "windows-link 0.2.1", - "windows-threading 0.2.1", + "windows-threading", ] [[package]] @@ -3572,20 +2086,10 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9150af68066c4c5c07ddc0ce30421554771e528bde427614c61038bc2c92c2b1" dependencies = [ - "windows-core 0.61.2", + "windows-core", "windows-link 0.1.3", ] -[[package]] -name = "windows-numerics" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e2e40844ac143cdb44aead537bbf727de9b044e107a0f1220392177d15b0f26" -dependencies = [ - "windows-core 0.62.2", - "windows-link 0.2.1", -] - [[package]] name = "windows-result" version = "0.3.4" @@ -3595,15 +2099,6 @@ dependencies = [ "windows-link 0.1.3", ] -[[package]] -name = "windows-result" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" -dependencies = [ - "windows-link 0.2.1", -] - [[package]] name = "windows-strings" version = "0.4.2" @@ -3613,24 +2108,6 @@ dependencies = [ "windows-link 0.1.3", ] -[[package]] -name = "windows-strings" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" -dependencies = [ - "windows-link 0.2.1", -] - -[[package]] -name = "windows-sys" -version = "0.59.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" -dependencies = [ - "windows-targets", -] - [[package]] name = "windows-sys" version = "0.61.2" @@ -3640,22 +2117,6 @@ dependencies = [ "windows-link 0.2.1", ] -[[package]] -name = "windows-targets" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" -dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_gnullvm", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", -] - [[package]] name = "windows-threading" version = "0.1.0" @@ -3665,81 +2126,6 @@ dependencies = [ "windows-link 0.1.3", ] -[[package]] -name = "windows-threading" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3949bd5b99cafdf1c7ca86b43ca564028dfe27d66958f2470940f73d86d75b37" -dependencies = [ - "windows-link 0.2.1", -] - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" - -[[package]] -name = "windows_i686_gnu" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" - -[[package]] -name = "windows_i686_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" - -[[package]] -name = "windows_i686_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" - -[[package]] -name = "winnow" -version = "0.7.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df79d97927682d2fd8adb29682d1140b343be4ac0f08fd68b7765d9c059d3945" -dependencies = [ - "memchr", -] - -[[package]] -name = "winnow" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a90e88e4667264a994d34e6d1ab2d26d398dcdca8b7f52bec8668957517fc7d8" -dependencies = [ - "memchr", -] - [[package]] name = "wit-bindgen" version = "0.51.0" @@ -3798,7 +2184,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2" dependencies = [ "anyhow", - "bitflags 2.11.0", + "bitflags", "indexmap", "log", "serde", @@ -3828,12 +2214,6 @@ dependencies = [ "wasmparser", ] -[[package]] -name = "writeable" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9" - [[package]] name = "x11rb" version = "0.13.2" @@ -3841,7 +2221,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9993aa5be5a26815fe2c3eacfc1fde061fc1a1f094bf1ad2a18bf9c495dd7414" dependencies = [ "gethostname", - "rustix 1.1.4", + "rustix", "x11rb-protocol", ] @@ -3851,49 +2231,6 @@ version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ea6fc2961e4ef194dcbfe56bb845534d0dc8098940c7e5c012a258bfec6701bd" -[[package]] -name = "xcap" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bdf4c8d4c33dfab96fb585cdf991a7bd86d754ac35edd4b80477a9b739892b2" -dependencies = [ - "dispatch2", - "image", - "lazy_static", - "libwayshot-xcap", - "log", - "objc2", - "objc2-app-kit", - "objc2-av-foundation", - "objc2-core-foundation", - "objc2-core-graphics", - "objc2-core-media", - "objc2-core-video", - "objc2-foundation", - "percent-encoding", - "pipewire", - "rand", - "scopeguard", - "serde", - "thiserror", - "url", - "widestring", - "windows 0.62.2", - "xcb", - "zbus", -] - -[[package]] -name = "xcb" -version = "1.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee4c580d8205abb0a5cf4eb7e927bd664e425b6c3263f9c5310583da96970cf6" -dependencies = [ - "bitflags 1.3.2", - "libc", - "quick-xml 0.30.0", -] - [[package]] name = "xkbcommon" version = "0.9.0" @@ -3911,102 +2248,12 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b9cc00251562a284751c9973bace760d86c0276c471b4be569fe6b068ee97a56" -[[package]] -name = "xml-rs" -version = "0.8.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ae8337f8a065cfc972643663ea4279e04e7256de865aa66fe25cec5fb912d3f" - [[package]] name = "y4m" version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a5a4b21e1a62b67a2970e6831bc091d7b87e119e7f9791aef9702e3bef04448" -[[package]] -name = "yoke" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72d6e5c6afb84d73944e5cedb052c4680d5657337201555f9f2a16b7406d4954" -dependencies = [ - "stable_deref_trait", - "yoke-derive", - "zerofrom", -] - -[[package]] -name = "yoke-derive" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d" -dependencies = [ - "proc-macro2", - "quote", - "syn", - "synstructure", -] - -[[package]] -name = "zbus" -version = "5.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca82f95dbd3943a40a53cfded6c2d0a2ca26192011846a1810c4256ef92c60bc" -dependencies = [ - "async-broadcast", - "async-executor", - "async-io", - "async-lock", - "async-process", - "async-recursion", - "async-task", - "async-trait", - "blocking", - "enumflags2", - "event-listener", - "futures-core", - "futures-lite", - "hex", - "libc", - "ordered-stream", - "rustix 1.1.4", - "serde", - "serde_repr", - "tracing", - "uds_windows", - "uuid", - "windows-sys 0.61.2", - "winnow 0.7.15", - "zbus_macros", - "zbus_names", - "zvariant", -] - -[[package]] -name = "zbus_macros" -version = "5.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "897e79616e84aac4b2c46e9132a4f63b93105d54fe8c0e8f6bffc21fa8d49222" -dependencies = [ - "proc-macro-crate", - "proc-macro2", - "quote", - "syn", - "zbus_names", - "zvariant", - "zvariant_utils", -] - -[[package]] -name = "zbus_names" -version = "4.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffd8af6d5b78619bab301ff3c560a5bd22426150253db278f164d6cf3b72c50f" -dependencies = [ - "serde", - "winnow 0.7.15", - "zvariant", -] - [[package]] name = "zerocopy" version = "0.8.47" @@ -4027,60 +2274,6 @@ dependencies = [ "syn", ] -[[package]] -name = "zerofrom" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" -dependencies = [ - "zerofrom-derive", -] - -[[package]] -name = "zerofrom-derive" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" -dependencies = [ - "proc-macro2", - "quote", - "syn", - "synstructure", -] - -[[package]] -name = "zerotrie" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a59c17a5562d507e4b54960e8569ebee33bee890c70aa3fe7b97e85a9fd7851" -dependencies = [ - "displaydoc", - "yoke", - "zerofrom", -] - -[[package]] -name = "zerovec" -version = "0.11.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c28719294829477f525be0186d13efa9a3c602f7ec202ca9e353d310fb9a002" -dependencies = [ - "yoke", - "zerofrom", - "zerovec-derive", -] - -[[package]] -name = "zerovec-derive" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "zmij" version = "1.0.21" @@ -4110,43 +2303,3 @@ checksum = "0b7a1c0af6e5d8d1363f4994b7a091ccf963d8b694f7da5b0b9cceb82da2c0a6" dependencies = [ "zune-core", ] - -[[package]] -name = "zvariant" -version = "5.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5708299b21903bbe348e94729f22c49c55d04720a004aa350f1f9c122fd2540b" -dependencies = [ - "endi", - "enumflags2", - "serde", - "winnow 0.7.15", - "zvariant_derive", - "zvariant_utils", -] - -[[package]] -name = "zvariant_derive" -version = "5.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b59b012ebe9c46656f9cc08d8da8b4c726510aef12559da3e5f1bf72780752c" -dependencies = [ - "proc-macro-crate", - "proc-macro2", - "quote", - "syn", - "zvariant_utils", -] - -[[package]] -name = "zvariant_utils" -version = "3.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f75c23a64ef8f40f13a6989991e643554d9bef1d682a281160cf0c1bc389c5e9" -dependencies = [ - "proc-macro2", - "quote", - "serde", - "syn", - "winnow 0.7.15", -] diff --git a/Cargo.toml b/Cargo.toml index 89d19d4..fad78ca 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,7 +15,6 @@ anyhow = "1" dirs = "6" libc = "0.2" uuid = { version = "1", features = ["v4"] } -xcap = "0.8" image = { version = "0.25", features = ["png"] } imageproc = "0.26" ab_glyph = "0.2" diff --git a/src/backend/annotate.rs b/src/backend/annotate.rs index 7036f93..d4f4fed 100644 --- a/src/backend/annotate.rs +++ b/src/backend/annotate.rs @@ -45,11 +45,7 @@ pub fn annotate_screenshot(image: &mut RgbaImage, windows: &[WindowInfo]) { if w > 0 && h > 0 { draw_hollow_rect_mut(image, Rect::at(x, y).of_size(w, h), color); if w > 2 && h > 2 { - draw_hollow_rect_mut( - image, - Rect::at(x + 1, y + 1).of_size(w - 2, h - 2), - color, - ); + draw_hollow_rect_mut(image, Rect::at(x + 1, y + 1).of_size(w - 2, h - 2), color); } } @@ -67,6 +63,14 @@ pub fn annotate_screenshot(image: &mut RgbaImage, windows: &[WindowInfo]) { ); // Label text - draw_text_mut(image, LABEL_FG, label_x + 3, label_y + 2, scale, &font, &label); + draw_text_mut( + image, + LABEL_FG, + label_x + 3, + label_y + 2, + scale, + &font, + &label, + ); } } diff --git a/src/backend/mod.rs b/src/backend/mod.rs index 1d0b36a..4d1767a 100644 --- a/src/backend/mod.rs +++ b/src/backend/mod.rs @@ -1,8 +1,8 @@ pub mod annotate; pub mod x11; -use anyhow::Result; use crate::core::types::Snapshot; +use anyhow::Result; #[allow(dead_code)] pub trait DesktopBackend: Send { diff --git a/src/backend/x11.rs b/src/backend/x11.rs index 4333b22..9502281 100644 --- a/src/backend/x11.rs +++ b/src/backend/x11.rs @@ -1,86 +1,240 @@ use anyhow::{Context, Result}; -use enigo::{ - Axis, Button, Coordinate, Direction, Enigo, Key, Keyboard, Mouse, Settings, -}; +use enigo::{Axis, Button, Coordinate, Direction, Enigo, Key, Keyboard, Mouse, Settings}; +use image::RgbaImage; use x11rb::connection::Connection; use x11rb::protocol::xproto::{ - ClientMessageEvent, ConfigureWindowAux, ConnectionExt as XprotoConnectionExt, - EventMask, + Atom, AtomEnum, ClientMessageData, ClientMessageEvent, ConfigureWindowAux, + ConnectionExt as XprotoConnectionExt, EventMask, GetPropertyReply, ImageFormat, ImageOrder, + Window, }; use x11rb::rust_connection::RustConnection; use super::annotate::annotate_screenshot; use crate::core::types::{Snapshot, WindowInfo}; +struct Atoms { + client_list_stacking: Atom, + active_window: Atom, + net_wm_name: Atom, + utf8_string: Atom, + wm_name: Atom, + wm_class: Atom, + net_wm_state: Atom, + net_wm_state_hidden: Atom, +} + pub struct X11Backend { enigo: Enigo, conn: RustConnection, - root: u32, + root: Window, + atoms: Atoms, } impl X11Backend { pub fn new() -> Result { let enigo = Enigo::new(&Settings::default()) .map_err(|e| anyhow::anyhow!("Failed to initialize enigo: {e}"))?; - let (conn, screen_num) = x11rb::connect(None) - .context("Failed to connect to X11 server")?; + let (conn, screen_num) = x11rb::connect(None).context("Failed to connect to X11 server")?; let root = conn.setup().roots[screen_num].root; - Ok(Self { enigo, conn, root }) + let atoms = Atoms::new(&conn)?; + Ok(Self { + enigo, + conn, + root, + atoms, + }) } -} -impl super::DesktopBackend for X11Backend { - fn snapshot(&mut self, annotate: bool) -> Result { - // Get z-ordered window list via xcap (topmost first internally) - let windows = xcap::Window::all().context("Failed to enumerate windows")?; + fn stacked_windows(&self) -> Result> { + let mut windows = self + .get_property_u32( + self.root, + self.atoms.client_list_stacking, + AtomEnum::WINDOW.into(), + 1024, + )? + .into_iter() + .map(|id| id as Window) + .collect::>(); - // Get primary monitor for screenshot - let monitors = xcap::Monitor::all().context("Failed to enumerate monitors")?; - let monitor = monitors.into_iter().next().context("No monitor found")?; + if windows.is_empty() { + windows = self + .conn + .query_tree(self.root)? + .reply() + .context("Failed to query root window tree")? + .children; + } - let mut image = monitor - .capture_image() - .context("Failed to capture screenshot")?; + // EWMH exposes bottom-to-top stacking order. Reverse it so @w1 is the topmost window. + windows.reverse(); + Ok(windows) + } - // Build window info list + fn collect_window_infos(&self) -> Result> { + let active_window = self.active_window()?; let mut window_infos = Vec::new(); let mut ref_counter = 1usize; - for win in &windows { - // Each xcap method returns XCapResult - skip windows where metadata fails - let title = win.title().unwrap_or_default(); - let app_name = win.app_name().unwrap_or_default(); - - // Skip windows with empty titles and app names (desktop, panels, etc.) + for window in self.stacked_windows()? { + let title = self.window_title(window).unwrap_or_default(); + let app_name = self.window_app_name(window).unwrap_or_default(); if title.is_empty() && app_name.is_empty() { continue; } - let xcb_id = win.id().unwrap_or(0); - let x = win.x().unwrap_or(0); - let y = win.y().unwrap_or(0); - let width = win.width().unwrap_or(0); - let height = win.height().unwrap_or(0); - let focused = win.is_focused().unwrap_or(false); - let minimized = win.is_minimized().unwrap_or(false); - - let ref_id = format!("w{ref_counter}"); - ref_counter += 1; + let (x, y, width, height) = match self.window_geometry(window) { + Ok(geometry) => geometry, + Err(_) => continue, + }; + let minimized = self.window_is_minimized(window).unwrap_or(false); window_infos.push(WindowInfo { - ref_id, - xcb_id, + ref_id: format!("w{ref_counter}"), + xcb_id: window, title, app_name, x, y, width, height, - focused, + focused: active_window == Some(window), minimized, }); + ref_counter += 1; } + Ok(window_infos) + } + + fn capture_root_image(&self) -> Result { + let (width, height) = self.root_geometry()?; + let reply = self + .conn + .get_image( + ImageFormat::Z_PIXMAP, + self.root, + 0, + 0, + width as u16, + height as u16, + u32::MAX, + )? + .reply() + .context("Failed to capture root window image")?; + + rgba_from_image_reply(self.conn.setup(), width, height, &reply) + } + + fn root_geometry(&self) -> Result<(u32, u32)> { + let geometry = self + .conn + .get_geometry(self.root)? + .reply() + .context("Failed to get root geometry")?; + Ok((geometry.width.into(), geometry.height.into())) + } + + fn window_geometry(&self, window: Window) -> Result<(i32, i32, u32, u32)> { + let geometry = self + .conn + .get_geometry(window)? + .reply() + .context("Failed to get window geometry")?; + let translated = self + .conn + .translate_coordinates(window, self.root, 0, 0)? + .reply() + .context("Failed to translate window coordinates to root")?; + + Ok(( + i32::from(translated.dst_x), + i32::from(translated.dst_y), + geometry.width.into(), + geometry.height.into(), + )) + } + + fn active_window(&self) -> Result> { + Ok(self + .get_property_u32( + self.root, + self.atoms.active_window, + AtomEnum::WINDOW.into(), + 1, + )? + .into_iter() + .next() + .map(|id| id as Window)) + } + + fn window_title(&self, window: Window) -> Result { + let title = + self.read_text_property(window, self.atoms.net_wm_name, self.atoms.utf8_string)?; + if !title.is_empty() { + return Ok(title); + } + + self.read_text_property(window, self.atoms.wm_name, AtomEnum::ANY.into()) + } + + fn window_app_name(&self, window: Window) -> Result { + let wm_class = + self.read_text_property(window, self.atoms.wm_class, AtomEnum::STRING.into())?; + let mut parts = wm_class.split('\0').filter(|part| !part.is_empty()); + Ok(parts + .nth(1) + .or_else(|| parts.next()) + .unwrap_or("") + .to_string()) + } + + fn window_is_minimized(&self, window: Window) -> Result { + let states = + self.get_property_u32(window, self.atoms.net_wm_state, AtomEnum::ATOM.into(), 32)?; + Ok(states.contains(&self.atoms.net_wm_state_hidden)) + } + + fn read_text_property(&self, window: Window, property: Atom, type_: Atom) -> Result { + let reply = self.get_property(window, property, type_, 1024)?; + Ok(String::from_utf8_lossy(&reply.value) + .trim_end_matches('\0') + .to_string()) + } + + fn get_property_u32( + &self, + window: Window, + property: Atom, + type_: Atom, + long_length: u32, + ) -> Result> { + let reply = self.get_property(window, property, type_, long_length)?; + Ok(reply + .value32() + .map(|iter| iter.collect::>()) + .unwrap_or_default()) + } + + fn get_property( + &self, + window: Window, + property: Atom, + type_: Atom, + long_length: u32, + ) -> Result { + self.conn + .get_property(false, window, property, type_, 0, long_length)? + .reply() + .with_context(|| format!("Failed to read property {property} from window {window}")) + } +} + +impl super::DesktopBackend for X11Backend { + fn snapshot(&mut self, annotate: bool) -> Result { + let window_infos = self.collect_window_infos()?; + let mut image = self.capture_root_image()?; + // Annotate if requested - draw bounding boxes and @wN labels if annotate { annotate_screenshot(&mut image, &window_infos); @@ -117,7 +271,7 @@ impl super::DesktopBackend for X11Backend { sequence: 0, window: xcb_id, type_: net_active, - data: x11rb::protocol::xproto::ClientMessageData::from([ + data: ClientMessageData::from([ 2u32, 0, 0, 0, 0, // source=2 (pager), timestamp=0, currently_active=0 ]), }; @@ -128,21 +282,27 @@ impl super::DesktopBackend for X11Backend { EventMask::SUBSTRUCTURE_REDIRECT | EventMask::SUBSTRUCTURE_NOTIFY, event, )?; - self.conn.flush().context("Failed to flush X11 connection")?; + self.conn + .flush() + .context("Failed to flush X11 connection")?; Ok(()) } fn move_window(&mut self, xcb_id: u32, x: i32, y: i32) -> Result<()> { self.conn .configure_window(xcb_id, &ConfigureWindowAux::new().x(x).y(y))?; - self.conn.flush().context("Failed to flush X11 connection")?; + self.conn + .flush() + .context("Failed to flush X11 connection")?; Ok(()) } fn resize_window(&mut self, xcb_id: u32, w: u32, h: u32) -> Result<()> { self.conn .configure_window(xcb_id, &ConfigureWindowAux::new().width(w).height(h))?; - self.conn.flush().context("Failed to flush X11 connection")?; + self.conn + .flush() + .context("Failed to flush X11 connection")?; Ok(()) } @@ -161,7 +321,7 @@ impl super::DesktopBackend for X11Backend { sequence: 0, window: xcb_id, type_: net_close, - data: x11rb::protocol::xproto::ClientMessageData::from([ + data: ClientMessageData::from([ 0u32, 2, 0, 0, 0, // timestamp=0, source=2 (pager) ]), }; @@ -172,7 +332,9 @@ impl super::DesktopBackend for X11Backend { EventMask::SUBSTRUCTURE_REDIRECT | EventMask::SUBSTRUCTURE_NOTIFY, event, )?; - self.conn.flush().context("Failed to flush X11 connection")?; + self.conn + .flush() + .context("Failed to flush X11 connection")?; Ok(()) } @@ -289,11 +451,7 @@ impl super::DesktopBackend for X11Backend { } fn screen_size(&self) -> Result<(u32, u32)> { - let monitors = xcap::Monitor::all().context("Failed to enumerate monitors")?; - let monitor = monitors.into_iter().next().context("No monitor found")?; - let w = monitor.width().context("Failed to get monitor width")?; - let h = monitor.height().context("Failed to get monitor height")?; - Ok((w, h)) + self.root_geometry() } fn mouse_position(&self) -> Result<(i32, i32)> { @@ -306,37 +464,10 @@ impl super::DesktopBackend for X11Backend { } fn screenshot(&mut self, path: &str, annotate: bool) -> Result { - let monitors = xcap::Monitor::all().context("Failed to enumerate monitors")?; - let monitor = monitors.into_iter().next().context("No monitor found")?; - - let mut image = monitor - .capture_image() - .context("Failed to capture screenshot")?; + let mut image = self.capture_root_image()?; if annotate { - let windows = xcap::Window::all().unwrap_or_default(); - let mut window_infos = Vec::new(); - let mut ref_counter = 1usize; - for win in &windows { - let title = win.title().unwrap_or_default(); - let app_name = win.app_name().unwrap_or_default(); - if title.is_empty() && app_name.is_empty() { - continue; - } - window_infos.push(crate::core::types::WindowInfo { - ref_id: format!("w{ref_counter}"), - xcb_id: win.id().unwrap_or(0), - title, - app_name, - x: win.x().unwrap_or(0), - y: win.y().unwrap_or(0), - width: win.width().unwrap_or(0), - height: win.height().unwrap_or(0), - focused: win.is_focused().unwrap_or(false), - minimized: win.is_minimized().unwrap_or(false), - }); - ref_counter += 1; - } + let window_infos = self.collect_window_infos()?; annotate_screenshot(&mut image, &window_infos); } @@ -404,3 +535,121 @@ fn parse_key(name: &str) -> Result { other => anyhow::bail!("Unknown key: {other}"), } } + +impl Atoms { + fn new(conn: &RustConnection) -> Result { + Ok(Self { + client_list_stacking: intern_atom(conn, b"_NET_CLIENT_LIST_STACKING")?, + active_window: intern_atom(conn, b"_NET_ACTIVE_WINDOW")?, + net_wm_name: intern_atom(conn, b"_NET_WM_NAME")?, + utf8_string: intern_atom(conn, b"UTF8_STRING")?, + wm_name: intern_atom(conn, b"WM_NAME")?, + wm_class: intern_atom(conn, b"WM_CLASS")?, + net_wm_state: intern_atom(conn, b"_NET_WM_STATE")?, + net_wm_state_hidden: intern_atom(conn, b"_NET_WM_STATE_HIDDEN")?, + }) + } +} + +fn intern_atom(conn: &RustConnection, name: &[u8]) -> Result { + conn.intern_atom(false, name)? + .reply() + .with_context(|| format!("Failed to intern atom {}", String::from_utf8_lossy(name))) + .map(|reply| reply.atom) +} + +fn rgba_from_image_reply( + setup: &x11rb::protocol::xproto::Setup, + width: u32, + height: u32, + reply: &x11rb::protocol::xproto::GetImageReply, +) -> Result { + let pixmap_format = setup + .pixmap_formats + .iter() + .find(|format| format.depth == reply.depth) + .context("Failed to find pixmap format for captured image depth")?; + let bits_per_pixel = u32::from(pixmap_format.bits_per_pixel); + let bit_order = setup.bitmap_format_bit_order; + let bytes = reply.data.as_slice(); + + let get_pixel_rgba = match reply.depth { + 8 => pixel8_rgba, + 16 => pixel16_rgba, + 24 | 32 => pixel24_32_rgba, + depth => anyhow::bail!("Unsupported X11 image depth: {depth}"), + }; + + let mut rgba = vec![0u8; (width * height * 4) as usize]; + for y in 0..height { + for x in 0..width { + let index = ((y * width + x) * 4) as usize; + let (r, g, b, a) = get_pixel_rgba(bytes, x, y, width, bits_per_pixel, bit_order); + rgba[index] = r; + rgba[index + 1] = g; + rgba[index + 2] = b; + rgba[index + 3] = a; + } + } + + RgbaImage::from_raw(width, height, rgba) + .context("Failed to convert captured X11 image into RGBA buffer") +} + +fn pixel8_rgba( + bytes: &[u8], + x: u32, + y: u32, + width: u32, + bits_per_pixel: u32, + bit_order: ImageOrder, +) -> (u8, u8, u8, u8) { + let index = ((y * width + x) * bits_per_pixel / 8) as usize; + let pixel = if bit_order == ImageOrder::LSB_FIRST { + bytes[index] + } else { + bytes[index] & (7 << 4) | (bytes[index] >> 4) + }; + + let r = (pixel >> 6) as f32 / 3.0 * 255.0; + let g = ((pixel >> 2) & 7) as f32 / 7.0 * 255.0; + let b = (pixel & 3) as f32 / 3.0 * 255.0; + (r as u8, g as u8, b as u8, 255) +} + +fn pixel16_rgba( + bytes: &[u8], + x: u32, + y: u32, + width: u32, + bits_per_pixel: u32, + bit_order: ImageOrder, +) -> (u8, u8, u8, u8) { + let index = ((y * width + x) * bits_per_pixel / 8) as usize; + let pixel = if bit_order == ImageOrder::LSB_FIRST { + u16::from(bytes[index]) | (u16::from(bytes[index + 1]) << 8) + } else { + (u16::from(bytes[index]) << 8) | u16::from(bytes[index + 1]) + }; + + let r = (pixel >> 11) as f32 / 31.0 * 255.0; + let g = ((pixel >> 5) & 63) as f32 / 63.0 * 255.0; + let b = (pixel & 31) as f32 / 31.0 * 255.0; + (r as u8, g as u8, b as u8, 255) +} + +fn pixel24_32_rgba( + bytes: &[u8], + x: u32, + y: u32, + width: u32, + bits_per_pixel: u32, + bit_order: ImageOrder, +) -> (u8, u8, u8, u8) { + let index = ((y * width + x) * bits_per_pixel / 8) as usize; + if bit_order == ImageOrder::LSB_FIRST { + (bytes[index + 2], bytes[index + 1], bytes[index], 255) + } else { + (bytes[index], bytes[index + 1], bytes[index + 2], 255) + } +} diff --git a/src/cli/connection.rs b/src/cli/connection.rs index 20527f5..f960ee3 100644 --- a/src/cli/connection.rs +++ b/src/cli/connection.rs @@ -39,12 +39,10 @@ fn try_connect(opts: &GlobalOpts) -> Option { } fn spawn_daemon(opts: &GlobalOpts) -> Result<()> { - let exe = std::env::current_exe() - .context("Failed to determine executable path")?; + let exe = std::env::current_exe().context("Failed to determine executable path")?; let sock_dir = socket_dir(); - std::fs::create_dir_all(&sock_dir) - .context("Failed to create socket directory")?; + std::fs::create_dir_all(&sock_dir).context("Failed to create socket directory")?; let mut cmd = Command::new(exe); cmd.env("DESKCTL_DAEMON", "1") @@ -109,8 +107,8 @@ pub fn send_command(opts: &GlobalOpts, request: &Request) -> Result { let mut line = String::new(); reader.read_line(&mut line)?; - let response: Response = serde_json::from_str(line.trim()) - .context("Failed to parse daemon response")?; + let response: Response = + serde_json::from_str(line.trim()).context("Failed to parse daemon response")?; Ok(response) } diff --git a/src/cli/mod.rs b/src/cli/mod.rs index 6ee3373..51891c0 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -1,8 +1,8 @@ mod connection; +use anyhow::Result; use clap::{Args, Parser, Subcommand}; use std::path::PathBuf; -use anyhow::Result; use crate::core::protocol::{Request, Response}; @@ -196,84 +196,57 @@ fn build_request(cmd: &Command) -> Result { use serde_json::json; let req = match cmd { Command::Snapshot { annotate } => { - Request::new("snapshot") - .with_extra("annotate", json!(annotate)) + Request::new("snapshot").with_extra("annotate", json!(annotate)) } Command::Click { selector } => { - Request::new("click") - .with_extra("selector", json!(selector)) + Request::new("click").with_extra("selector", json!(selector)) } Command::Dblclick { selector } => { - Request::new("dblclick") - .with_extra("selector", json!(selector)) - } - Command::Type { text } => { - Request::new("type") - .with_extra("text", json!(text)) - } - Command::Press { key } => { - Request::new("press") - .with_extra("key", json!(key)) - } - Command::Hotkey { keys } => { - Request::new("hotkey") - .with_extra("keys", json!(keys)) + Request::new("dblclick").with_extra("selector", json!(selector)) } + Command::Type { text } => Request::new("type").with_extra("text", json!(text)), + Command::Press { key } => Request::new("press").with_extra("key", json!(key)), + Command::Hotkey { keys } => Request::new("hotkey").with_extra("keys", json!(keys)), Command::Mouse(sub) => match sub { - MouseCmd::Move { x, y } => { - Request::new("mouse-move") - .with_extra("x", json!(x)) - .with_extra("y", json!(y)) - } - MouseCmd::Scroll { amount, axis } => { - Request::new("mouse-scroll") - .with_extra("amount", json!(amount)) - .with_extra("axis", json!(axis)) - } - MouseCmd::Drag { x1, y1, x2, y2 } => { - Request::new("mouse-drag") - .with_extra("x1", json!(x1)) - .with_extra("y1", json!(y1)) - .with_extra("x2", json!(x2)) - .with_extra("y2", json!(y2)) - } + MouseCmd::Move { x, y } => Request::new("mouse-move") + .with_extra("x", json!(x)) + .with_extra("y", json!(y)), + MouseCmd::Scroll { amount, axis } => Request::new("mouse-scroll") + .with_extra("amount", json!(amount)) + .with_extra("axis", json!(axis)), + MouseCmd::Drag { x1, y1, x2, y2 } => Request::new("mouse-drag") + .with_extra("x1", json!(x1)) + .with_extra("y1", json!(y1)) + .with_extra("x2", json!(x2)) + .with_extra("y2", json!(y2)), }, Command::Focus { selector } => { - Request::new("focus") - .with_extra("selector", json!(selector)) + Request::new("focus").with_extra("selector", json!(selector)) } Command::Close { selector } => { - Request::new("close") - .with_extra("selector", json!(selector)) - } - Command::MoveWindow { selector, x, y } => { - Request::new("move-window") - .with_extra("selector", json!(selector)) - .with_extra("x", json!(x)) - .with_extra("y", json!(y)) - } - Command::ResizeWindow { selector, w, h } => { - Request::new("resize-window") - .with_extra("selector", json!(selector)) - .with_extra("w", json!(w)) - .with_extra("h", json!(h)) + Request::new("close").with_extra("selector", json!(selector)) } + Command::MoveWindow { selector, x, y } => Request::new("move-window") + .with_extra("selector", json!(selector)) + .with_extra("x", json!(x)) + .with_extra("y", json!(y)), + Command::ResizeWindow { selector, w, h } => Request::new("resize-window") + .with_extra("selector", json!(selector)) + .with_extra("w", json!(w)) + .with_extra("h", json!(h)), Command::ListWindows => Request::new("list-windows"), Command::GetScreenSize => Request::new("get-screen-size"), Command::GetMousePosition => Request::new("get-mouse-position"), Command::Screenshot { path, annotate } => { - let mut req = Request::new("screenshot") - .with_extra("annotate", json!(annotate)); + let mut req = Request::new("screenshot").with_extra("annotate", json!(annotate)); if let Some(p) = path { req = req.with_extra("path", json!(p.to_string_lossy())); } req } - Command::Launch { command, args } => { - Request::new("launch") - .with_extra("command", json!(command)) - .with_extra("args", json!(args)) - } + Command::Launch { command, args } => Request::new("launch") + .with_extra("command", json!(command)) + .with_extra("args", json!(args)), Command::Daemon(_) => unreachable!(), }; Ok(req) @@ -298,18 +271,30 @@ fn print_response(cmd: &Command, response: &Response) -> Result<()> { let ref_id = w.get("ref_id").and_then(|v| v.as_str()).unwrap_or("?"); let title = w.get("title").and_then(|v| v.as_str()).unwrap_or(""); let focused = w.get("focused").and_then(|v| v.as_bool()).unwrap_or(false); - let minimized = w.get("minimized").and_then(|v| v.as_bool()).unwrap_or(false); + let minimized = w + .get("minimized") + .and_then(|v| v.as_bool()) + .unwrap_or(false); let x = w.get("x").and_then(|v| v.as_i64()).unwrap_or(0); let y = w.get("y").and_then(|v| v.as_i64()).unwrap_or(0); let width = w.get("width").and_then(|v| v.as_u64()).unwrap_or(0); let height = w.get("height").and_then(|v| v.as_u64()).unwrap_or(0); - let state = if focused { "focused" } else if minimized { "hidden" } else { "visible" }; + let state = if focused { + "focused" + } else if minimized { + "hidden" + } else { + "visible" + }; let display_title = if title.len() > 30 { format!("{}...", &title[..27]) } else { title.to_string() }; - println!("@{:<4} {:<30} ({:<7}) {},{} {}x{}", ref_id, display_title, state, x, y, width, height); + println!( + "@{:<4} {:<30} ({:<7}) {},{} {}x{}", + ref_id, display_title, state, x, y, width, height + ); } } } else { diff --git a/src/core/protocol.rs b/src/core/protocol.rs index 3a165c2..c0ead03 100644 --- a/src/core/protocol.rs +++ b/src/core/protocol.rs @@ -21,10 +21,14 @@ pub struct Response { impl Request { pub fn new(action: &str) -> Self { Self { - id: format!("r{}", std::time::SystemTime::now() - .duration_since(std::time::UNIX_EPOCH) - .unwrap_or_default() - .as_micros() % 1_000_000), + id: format!( + "r{}", + std::time::SystemTime::now() + .duration_since(std::time::UNIX_EPOCH) + .unwrap_or_default() + .as_micros() + % 1_000_000 + ), action: action.to_string(), extra: Value::Object(serde_json::Map::new()), } @@ -40,10 +44,18 @@ impl Request { impl Response { pub fn ok(data: Value) -> Self { - Self { success: true, data: Some(data), error: None } + Self { + success: true, + data: Some(data), + error: None, + } } pub fn err(msg: impl Into) -> Self { - Self { success: false, data: None, error: Some(msg.into()) } + Self { + success: false, + data: None, + error: Some(msg.into()), + } } } diff --git a/src/core/refs.rs b/src/core/refs.rs index a18d59a..7909d0e 100644 --- a/src/core/refs.rs +++ b/src/core/refs.rs @@ -1,5 +1,5 @@ -use std::collections::HashMap; use serde::{Deserialize, Serialize}; +use std::collections::HashMap; #[derive(Debug, Clone, Serialize, Deserialize)] #[allow(dead_code)] @@ -26,7 +26,10 @@ pub struct RefMap { #[allow(dead_code)] impl RefMap { pub fn new() -> Self { - Self { map: HashMap::new(), next_ref: 1 } + Self { + map: HashMap::new(), + next_ref: 1, + } } pub fn clear(&mut self) { @@ -57,16 +60,14 @@ impl RefMap { // Try substring match on app_class or title (case-insensitive) let lower = selector.to_lowercase(); self.map.values().find(|e| { - e.app_class.to_lowercase().contains(&lower) - || e.title.to_lowercase().contains(&lower) + e.app_class.to_lowercase().contains(&lower) || e.title.to_lowercase().contains(&lower) }) } /// Resolve a selector to the center coordinates of the window. pub fn resolve_to_center(&self, selector: &str) -> Option<(i32, i32)> { - self.resolve(selector).map(|e| { - (e.x + e.width as i32 / 2, e.y + e.height as i32 / 2) - }) + self.resolve(selector) + .map(|e| (e.x + e.width as i32 / 2, e.y + e.height as i32 / 2)) } pub fn entries(&self) -> impl Iterator { diff --git a/src/daemon/handler.rs b/src/daemon/handler.rs index f9068e3..5a3fc2e 100644 --- a/src/daemon/handler.rs +++ b/src/daemon/handler.rs @@ -1,15 +1,12 @@ use std::sync::Arc; use tokio::sync::Mutex; +use super::state::DaemonState; use crate::backend::DesktopBackend; use crate::core::protocol::{Request, Response}; use crate::core::refs::RefEntry; -use super::state::DaemonState; -pub async fn handle_request( - request: &Request, - state: &Arc>, -) -> Response { +pub async fn handle_request(request: &Request, state: &Arc>) -> Response { match request.action.as_str() { "snapshot" => handle_snapshot(request, state).await, "click" => handle_click(request, state).await, @@ -33,10 +30,7 @@ pub async fn handle_request( } } -async fn handle_snapshot( - request: &Request, - state: &Arc>, -) -> Response { +async fn handle_snapshot(request: &Request, state: &Arc>) -> Response { let annotate = request .extra .get("annotate") @@ -70,10 +64,7 @@ async fn handle_snapshot( } } -async fn handle_click( - request: &Request, - state: &Arc>, -) -> Response { +async fn handle_click(request: &Request, state: &Arc>) -> Response { let selector = match request.extra.get("selector").and_then(|v| v.as_str()) { Some(s) => s.to_string(), None => return Response::err("Missing 'selector' field"), @@ -92,19 +83,16 @@ async fn handle_click( // Resolve as window ref match state.ref_map.resolve_to_center(&selector) { Some((x, y)) => match state.backend.click(x, y) { - Ok(()) => Response::ok( - serde_json::json!({"clicked": {"x": x, "y": y, "ref": selector}}), - ), + Ok(()) => { + Response::ok(serde_json::json!({"clicked": {"x": x, "y": y, "ref": selector}})) + } Err(e) => Response::err(format!("Click failed: {e}")), }, None => Response::err(format!("Could not resolve selector: {selector}")), } } -async fn handle_dblclick( - request: &Request, - state: &Arc>, -) -> Response { +async fn handle_dblclick(request: &Request, state: &Arc>) -> Response { let selector = match request.extra.get("selector").and_then(|v| v.as_str()) { Some(s) => s.to_string(), None => return Response::err("Missing 'selector' field"), @@ -130,10 +118,7 @@ async fn handle_dblclick( } } -async fn handle_type( - request: &Request, - state: &Arc>, -) -> Response { +async fn handle_type(request: &Request, state: &Arc>) -> Response { let text = match request.extra.get("text").and_then(|v| v.as_str()) { Some(t) => t.to_string(), None => return Response::err("Missing 'text' field"), @@ -147,10 +132,7 @@ async fn handle_type( } } -async fn handle_press( - request: &Request, - state: &Arc>, -) -> Response { +async fn handle_press(request: &Request, state: &Arc>) -> Response { let key = match request.extra.get("key").and_then(|v| v.as_str()) { Some(k) => k.to_string(), None => return Response::err("Missing 'key' field"), @@ -164,10 +146,7 @@ async fn handle_press( } } -async fn handle_hotkey( - request: &Request, - state: &Arc>, -) -> Response { +async fn handle_hotkey(request: &Request, state: &Arc>) -> Response { let keys: Vec = match request.extra.get("keys").and_then(|v| v.as_array()) { Some(arr) => arr .iter() @@ -184,10 +163,7 @@ async fn handle_hotkey( } } -async fn handle_mouse_move( - request: &Request, - state: &Arc>, -) -> Response { +async fn handle_mouse_move(request: &Request, state: &Arc>) -> Response { let x = match request.extra.get("x").and_then(|v| v.as_i64()) { Some(v) => v as i32, None => return Response::err("Missing 'x' field"), @@ -205,10 +181,7 @@ async fn handle_mouse_move( } } -async fn handle_mouse_scroll( - request: &Request, - state: &Arc>, -) -> Response { +async fn handle_mouse_scroll(request: &Request, state: &Arc>) -> Response { let amount = match request.extra.get("amount").and_then(|v| v.as_i64()) { Some(v) => v as i32, None => return Response::err("Missing 'amount' field"), @@ -223,17 +196,12 @@ async fn handle_mouse_scroll( let mut state = state.lock().await; match state.backend.scroll(amount, &axis) { - Ok(()) => { - Response::ok(serde_json::json!({"scrolled": {"amount": amount, "axis": axis}})) - } + Ok(()) => Response::ok(serde_json::json!({"scrolled": {"amount": amount, "axis": axis}})), Err(e) => Response::err(format!("Scroll failed: {e}")), } } -async fn handle_mouse_drag( - request: &Request, - state: &Arc>, -) -> Response { +async fn handle_mouse_drag(request: &Request, state: &Arc>) -> Response { let x1 = match request.extra.get("x1").and_then(|v| v.as_i64()) { Some(v) => v as i32, None => return Response::err("Missing 'x1' field"), @@ -297,10 +265,7 @@ async fn handle_window_action( } } -async fn handle_move_window( - request: &Request, - state: &Arc>, -) -> Response { +async fn handle_move_window(request: &Request, state: &Arc>) -> Response { let selector = match request.extra.get("selector").and_then(|v| v.as_str()) { Some(s) => s.to_string(), None => return Response::err("Missing 'selector' field"), @@ -322,16 +287,21 @@ async fn handle_move_window( } } -async fn handle_resize_window( - request: &Request, - state: &Arc>, -) -> Response { +async fn handle_resize_window(request: &Request, state: &Arc>) -> Response { let selector = match request.extra.get("selector").and_then(|v| v.as_str()) { Some(s) => s.to_string(), None => return Response::err("Missing 'selector' field"), }; - let w = request.extra.get("w").and_then(|v| v.as_u64()).unwrap_or(800) as u32; - let h = request.extra.get("h").and_then(|v| v.as_u64()).unwrap_or(600) as u32; + let w = request + .extra + .get("w") + .and_then(|v| v.as_u64()) + .unwrap_or(800) as u32; + let h = request + .extra + .get("h") + .and_then(|v| v.as_u64()) + .unwrap_or(600) as u32; let mut state = state.lock().await; let entry = match state.ref_map.resolve(&selector) { @@ -347,9 +317,7 @@ async fn handle_resize_window( } } -async fn handle_list_windows( - state: &Arc>, -) -> Response { +async fn handle_list_windows(state: &Arc>) -> Response { let mut state = state.lock().await; // Re-run snapshot without screenshot, just to get current window list match state.backend.snapshot(false) { @@ -392,10 +360,7 @@ async fn handle_get_mouse_position(state: &Arc>) -> Response } } -async fn handle_screenshot( - request: &Request, - state: &Arc>, -) -> Response { +async fn handle_screenshot(request: &Request, state: &Arc>) -> Response { let annotate = request .extra .get("annotate") @@ -420,10 +385,7 @@ async fn handle_screenshot( } } -async fn handle_launch( - request: &Request, - state: &Arc>, -) -> Response { +async fn handle_launch(request: &Request, state: &Arc>) -> Response { let command = match request.extra.get("command").and_then(|v| v.as_str()) { Some(c) => c.to_string(), None => return Response::err("Missing 'command' field"), diff --git a/src/daemon/mod.rs b/src/daemon/mod.rs index 4873bc2..f838bbf 100644 --- a/src/daemon/mod.rs +++ b/src/daemon/mod.rs @@ -28,9 +28,7 @@ async fn async_run() -> Result<()> { .map(PathBuf::from) .context("DESKCTL_SOCKET_PATH not set")?; - let pid_path = std::env::var("DESKCTL_PID_PATH") - .map(PathBuf::from) - .ok(); + let pid_path = std::env::var("DESKCTL_PID_PATH").map(PathBuf::from).ok(); // Clean up stale socket if socket_path.exists() { @@ -48,7 +46,7 @@ async fn async_run() -> Result<()> { let session = std::env::var("DESKCTL_SESSION").unwrap_or_else(|_| "default".to_string()); let state = Arc::new(Mutex::new( DaemonState::new(session, socket_path.clone()) - .context("Failed to initialize daemon state")? + .context("Failed to initialize daemon state")?, )); let shutdown = Arc::new(tokio::sync::Notify::new()); @@ -111,9 +109,8 @@ async fn handle_connection( // exits even if the client has already closed the connection. if request.action == "shutdown" { shutdown.notify_one(); - let response = crate::core::protocol::Response::ok( - serde_json::json!({"message": "Shutting down"}) - ); + let response = + crate::core::protocol::Response::ok(serde_json::json!({"message": "Shutting down"})); let json = serde_json::to_string(&response)?; // Ignore write errors - client may have already closed the connection. let _ = writer.write_all(format!("{json}\n").as_bytes()).await;