diff --git a/docs/content.en/docs/release-notes/_index.md b/docs/content.en/docs/release-notes/_index.md index 265f9b6d..cb0f592a 100644 --- a/docs/content.en/docs/release-notes/_index.md +++ b/docs/content.en/docs/release-notes/_index.md @@ -24,6 +24,7 @@ Information about release notes of Coco App is provided here. - feat: support context menu in debug mode #882 - feat: file search for Linux/GNOME #884 - feat: file search for Linux/KDE #886 +- feat: extension Window Management for macOS #892 ### 🐛 Bug fix diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index f960c90c..eeafb8a9 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -13,9 +13,9 @@ dependencies = [ [[package]] name = "adler2" -version = "2.0.0" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" +checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" [[package]] name = "aes" @@ -62,9 +62,12 @@ dependencies = [ [[package]] name = "aligned-vec" -version = "0.5.0" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4aa90d7ce82d4be67b64039a3d588d38dbcc6736577de4a847025ce5b0c468d1" +checksum = "dc890384c8602f339876ded803c97ad529f3842aba97f6392b3dba0dd171769b" +dependencies = [ + "equator", +] [[package]] name = "alloc-no-stdlib" @@ -101,9 +104,9 @@ checksum = "84521a3cf562bc62942e294181d9eef17eb38ceb8c68677bc49f144e4c3d4f8d" [[package]] name = "android_logger" -version = "0.15.0" +version = "0.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6f39be698127218cca460cb624878c9aa4e2b47dba3b277963d2bf00bad263b" +checksum = "dbb4e440d04be07da1f1bf44fb4495ebd58669372fe0cffa6e48595ac5bd88a3" dependencies = [ "android_log-sys", "env_filter", @@ -121,9 +124,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.98" +version = "1.0.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487" +checksum = "b0674a1ddeecb70197781e945de4b3b8ffb61fa939a5597bcf48503737663100" [[package]] name = "applications" @@ -135,8 +138,8 @@ dependencies = [ "freedesktop-file-parser", "glob", "lnk", - "nix 0.30.1", - "notify 8.0.0", + "nix", + "notify 8.2.0", "parselnk", "plist", "serde", @@ -151,9 +154,9 @@ dependencies = [ [[package]] name = "arbitrary" -version = "1.4.1" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dde20b3d026af13f561bdd0f15edf01fc734f0dafcedbaf42bba506a9517f223" +checksum = "c3d036a3c4ab069c7b410a2ce876bd74808d2d0888a82667669f8e783a898bf1" dependencies = [ "derive_arbitrary", ] @@ -166,7 +169,7 @@ checksum = "0ae92a5119aa49cdbcf6b9f893fe4e1d98b04ccbf82ee0584ad948a44a734dea" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.106", ] [[package]] @@ -184,12 +187,15 @@ dependencies = [ "enumflags2", "futures-channel", "futures-util", - "rand 0.9.1", + "rand 0.9.2", "raw-window-handle", "serde", "serde_repr", "tokio", "url", + "wayland-backend", + "wayland-client", + "wayland-protocols", "zbus", ] @@ -207,9 +213,9 @@ dependencies = [ [[package]] name = "async-channel" -version = "2.3.1" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89b47800b0be77592da0afd425cc03468052844aff33b84e33cc696f64e77b6a" +checksum = "924ed96dd52d1b75e9c1a3e6275715fd320f5f9439fb5a4a11fa51f4221158d2" dependencies = [ "concurrent-queue", "event-listener-strategy", @@ -219,9 +225,9 @@ dependencies = [ [[package]] name = "async-executor" -version = "1.13.2" +version = "1.13.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb812ffb58524bdd10860d7d974e2f01cc0950c2438a74ee5ec2e2280c6c4ffa" +checksum = "497c00e0fd83a72a79a39fcbd8e3e2f055d6f6c7e025f3b3d91f4f8e76527fb8" dependencies = [ "async-task", "concurrent-queue", @@ -233,9 +239,9 @@ dependencies = [ [[package]] name = "async-io" -version = "2.4.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43a2b323ccce0a1d90b449fd71f2a06ca7faa7c54c2751f06c9bd851fc061059" +checksum = "19634d6336019ef220f09fd31168ce5c184b295cbf80345437cc36094ef223ca" dependencies = [ "async-lock", "cfg-if", @@ -244,17 +250,16 @@ dependencies = [ "futures-lite", "parking", "polling", - "rustix 0.38.44", + "rustix", "slab", - "tracing", - "windows-sys 0.59.0", + "windows-sys 0.60.2", ] [[package]] name = "async-lock" -version = "3.4.0" +version = "3.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff6e472cdea888a4bd64f342f09b3f50e1886d32afe8df3d663c01140b811b18" +checksum = "5fd03604047cee9b6ce9de9f70c6cd540a0520c813cbd49bae61f33ab80ed1dc" dependencies = [ "event-listener", "event-listener-strategy", @@ -263,9 +268,9 @@ dependencies = [ [[package]] name = "async-process" -version = "2.3.0" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63255f1dc2381611000436537bbedfe83183faa303a5a0edaf191edef06526bb" +checksum = "65daa13722ad51e6ab1a1b9c01299142bc75135b337923cfa10e79bbbd669f00" dependencies = [ "async-channel", "async-io", @@ -276,8 +281,7 @@ dependencies = [ "cfg-if", "event-listener", "futures-lite", - "rustix 0.38.44", - "tracing", + "rustix", ] [[package]] @@ -288,14 +292,14 @@ checksum = "3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.106", ] [[package]] name = "async-signal" -version = "0.2.10" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "637e00349800c0bdf8bfc21ebbc0b6524abea702b0da4168ac00d070d0c0b9f3" +checksum = "f567af260ef69e1d52c2b560ce0ea230763e6fbb9214a85d768760a920e3e3c1" dependencies = [ "async-io", "async-lock", @@ -303,10 +307,10 @@ dependencies = [ "cfg-if", "futures-core", "futures-io", - "rustix 0.38.44", + "rustix", "signal-hook-registry", "slab", - "windows-sys 0.59.0", + "windows-sys 0.60.2", ] [[package]] @@ -317,13 +321,13 @@ checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de" [[package]] name = "async-trait" -version = "0.1.88" +version = "0.1.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e539d3fca749fcee5236ab05e93a52867dd549cc157c8cb7f99595f3cedffdb5" +checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.106", ] [[package]] @@ -368,15 +372,15 @@ dependencies = [ [[package]] name = "autocfg" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" [[package]] name = "av1-grain" -version = "0.2.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6678909d8c5d46a42abcf571271e15fdbc0a225e3646cf23762cd415046c78bf" +checksum = "4f3efb2ca85bc610acfa917b5aaa36f3fcbebed5b3182d7f877b02531c4b80c8" dependencies = [ "anyhow", "arrayvec", @@ -388,9 +392,9 @@ dependencies = [ [[package]] name = "avif-serialize" -version = "0.8.3" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98922d6a4cfbcb08820c69d8eeccc05bb1f29bfa06b4f5b1dbfe9a868bd7608e" +checksum = "47c8fbc0f831f4519fe8b810b6a7a91410ec83031b8233f730a0480029f6a23f" dependencies = [ "arrayvec", ] @@ -430,9 +434,9 @@ checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" [[package]] name = "bit_field" -version = "0.10.2" +version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc827186963e592360843fb5ba4b973e145841266c1357f7180c43526f2e5b61" +checksum = "1e4b40c7323adcfc0a41c4b88143ed58346ff65a288fc144329c5c45e05d70c6" [[package]] name = "bitflags" @@ -442,9 +446,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.9.0" +version = "2.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd" +checksum = "2261d10cca569e4643e526d8dc2e62e433cc8aba21ab764233731f8d369bf394" dependencies = [ "serde", ] @@ -497,14 +501,14 @@ version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "340d2f0bdb2a43c1d3cd40513185b2bd7def0aa1052f956455114bc98f82dcf2" dependencies = [ - "objc2 0.6.1", + "objc2 0.6.2", ] [[package]] name = "blocking" -version = "1.6.1" +version = "1.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "703f41c54fc768e63e091340b424302bb1c29ef4aa0c7f10fe849dfb114d29ea" +checksum = "e83f8d02be6967315521be875afa792a316e28d57b5a2d401897e2a7921b7f21" dependencies = [ "async-channel", "async-task", @@ -530,7 +534,7 @@ checksum = "b00f4d9b344db5782c18429dac7a9af047d522f1d9ba1617d715aaffbdc040d0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.106", ] [[package]] @@ -553,14 +557,14 @@ dependencies = [ "proc-macro-crate 3.3.0", "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.106", ] [[package]] name = "brotli" -version = "7.0.0" +version = "8.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc97b8f16f944bba54f0433f07e30be199b6dc2bd25937444bbad560bcea29bd" +checksum = "4bd8b9603c7aa97359dbd97ecf258968c95f3adddd6db2f7e7a5bef101c84560" dependencies = [ "alloc-no-stdlib", "alloc-stdlib", @@ -569,9 +573,9 @@ dependencies = [ [[package]] name = "brotli-decompressor" -version = "4.0.3" +version = "5.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a334ef7c9e23abf0ce748e8cd309037da93e606ad52eb372e4ce327a0dcfbdfd" +checksum = "874bb8112abecc98cbd6d81ea4fa7e94fb9449648c93cc89aa40c81c24d7de03" dependencies = [ "alloc-no-stdlib", "alloc-stdlib", @@ -585,9 +589,9 @@ checksum = "56ed6191a7e78c36abdb16ab65341eefd73d64d303fffccdbb00d51e4205967b" [[package]] name = "bumpalo" -version = "3.17.0" +version = "3.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf" +checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" [[package]] name = "byte-unit" @@ -624,9 +628,9 @@ dependencies = [ [[package]] name = "bytemuck" -version = "1.23.0" +version = "1.23.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9134a6ef01ce4b366b50689c94f82c14bc72bc5d0386829828a2e2752ef7958c" +checksum = "3995eaeebcdf32f91f980d360f78732ddc061097ab4e39991ae7a6ace9194677" [[package]] name = "byteorder" @@ -651,21 +655,11 @@ dependencies = [ [[package]] name = "bzip2" -version = "0.5.2" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49ecfb22d906f800d4fe833b6282cf4dc1c298f5057ca0b5445e5c209735ca47" +checksum = "bea8dcd42434048e4f7a304411d9273a411f647446c1234a65ce0554923f4cff" dependencies = [ - "bzip2-sys", -] - -[[package]] -name = "bzip2-sys" -version = "0.1.13+1.0.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "225bff33b2141874fe80d71e07d6eec4f85c5c216453dd96388240f96e1acc14" -dependencies = [ - "cc", - "pkg-config", + "libbz2-rs-sys", ] [[package]] @@ -674,7 +668,7 @@ version = "0.18.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ca26ef0159422fb77631dc9d17b102f253b876fe1586b03b803e63a309b4ee2" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.4", "cairo-sys-rs", "glib 0.18.5", "libc", @@ -695,9 +689,9 @@ dependencies = [ [[package]] name = "camino" -version = "1.1.10" +version = "1.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0da45bc31171d8d6960122e222a67740df867c1dd53b4d51caa297084c185cab" +checksum = "dd0b03af37dad7a14518b7691d81acb0f8222604ad3d1b02f6b4bed5188c0cd5" dependencies = [ "serde", ] @@ -722,25 +716,26 @@ dependencies = [ "semver", "serde", "serde_json", - "thiserror 2.0.12", + "thiserror 2.0.16", ] [[package]] name = "cargo_toml" -version = "0.22.1" +version = "0.22.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02260d489095346e5cafd04dea8e8cb54d1d74fcd759022a9b72986ebe9a1257" +checksum = "374b7c592d9c00c1f4972ea58390ac6b18cbb6ab79011f3bdc90a0b82ca06b77" dependencies = [ "serde", - "toml", + "toml 0.9.5", ] [[package]] name = "cc" -version = "1.2.21" +version = "1.2.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8691782945451c1c383942c4874dbe63814f61cb57ef773cda2972682b7bb3c0" +checksum = "590f9024a68a8c40351881787f1934dc11afd69090f5edb6831464694d836ea3" dependencies = [ + "find-msvc-tools", "jobserver", "libc", "shlex", @@ -770,24 +765,24 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d067ad48b8650848b989a59a86c6c36a995d02d2bf778d45c3c5d57bc2718f02" dependencies = [ "smallvec", - "target-lexicon", + "target-lexicon 0.12.16", ] [[package]] name = "cfg-expr" -version = "0.17.2" +version = "0.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d4ba6e40bd1184518716a6e1a781bf9160e286d219ccdb8ab2612e74cfe4789" +checksum = "c8d458d63f0f0f482c8da9b7c8b76c21bd885a02056cc94c6404d861ca2b8206" dependencies = [ "smallvec", - "target-lexicon", + "target-lexicon 0.13.2", ] [[package]] name = "cfg-if" -version = "1.0.1" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9555578bc9e57714c812a1f84e4fc5b4d21fcb063490c624de019f7464c91268" +checksum = "2fd1289c04a9ea8cb22300a459a72a385d7c73d3259e2ed7dcb2af674838cfa9" [[package]] name = "cfg_aliases" @@ -847,6 +842,7 @@ dependencies = [ "async-recursion", "async-trait", "base64 0.13.1", + "bitflags 2.9.4", "borrowme", "camino", "cfg-if", @@ -862,14 +858,19 @@ dependencies = [ "hostname", "http 1.3.1", "hyper 0.14.32", - "indexmap 2.10.0", + "indexmap 2.11.0", "lazy_static", "log", "meval", "notify 5.2.0", "num2words", + "objc2 0.6.2", "objc2-app-kit 0.3.1", + "objc2-application-services", + "objc2-core-foundation", + "objc2-core-graphics", "once_cell", + "oneshot", "ordered-float", "pizza-common", "plist", @@ -918,19 +919,19 @@ dependencies = [ "walkdir", "which", "windows 0.61.3", - "zip 4.0.0", + "zip 4.6.1", ] [[package]] name = "cocoa" -version = "0.26.0" +version = "0.26.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f79398230a6e2c08f5c9760610eb6924b52aa9e7950a619602baba59dcbbdbb2" +checksum = "ad36507aeb7e16159dfe68db81ccc27571c3ccd4b76fb2fb72fc59e7a4b1b64c" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.4", "block", "cocoa-foundation", - "core-foundation 0.10.0", + "core-foundation 0.10.1", "core-graphics 0.24.0", "foreign-types 0.5.0", "libc", @@ -939,15 +940,14 @@ dependencies = [ [[package]] name = "cocoa-foundation" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e14045fb83be07b5acf1c0884b2180461635b433455fa35d1cd6f17f1450679d" +checksum = "81411967c50ee9a1fc11365f8c585f863a22a9697c89239c452292c40ba79b0d" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.4", "block", - "core-foundation 0.10.0", + "core-foundation 0.10.1", "core-graphics-types", - "libc", "objc", ] @@ -1049,9 +1049,9 @@ dependencies = [ [[package]] name = "core-foundation" -version = "0.10.0" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b55271e5c8c478ad3f38ad24ef34923091e0548492a266d19b3c0b4d82574c63" +checksum = "b2a6cd9ae233e7f62ba4e9353e81a88df7fc8a5987b8d445b4d90c879bd156f6" dependencies = [ "core-foundation-sys", "libc", @@ -1069,8 +1069,8 @@ version = "0.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fa95a34622365fa5bbf40b20b75dba8dfa8c94c734aea8ac9a5ca38af14316f1" dependencies = [ - "bitflags 2.9.0", - "core-foundation 0.10.0", + "bitflags 2.9.4", + "core-foundation 0.10.1", "core-graphics-types", "foreign-types 0.5.0", "libc", @@ -1082,8 +1082,8 @@ version = "0.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "064badf302c3194842cf2c5d61f56cc88e54a759313879cdf03abdd27d0c3b97" dependencies = [ - "bitflags 2.9.0", - "core-foundation 0.10.0", + "bitflags 2.9.4", + "core-foundation 0.10.1", "core-graphics-types", "foreign-types 0.5.0", "libc", @@ -1095,8 +1095,8 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d44a101f213f6c4cdc1853d4b78aef6db6bdfa3468798cc1d9912f4735013eb" dependencies = [ - "bitflags 2.9.0", - "core-foundation 0.10.0", + "bitflags 2.9.4", + "core-foundation 0.10.1", "libc", ] @@ -1111,9 +1111,9 @@ dependencies = [ [[package]] name = "crc32fast" -version = "1.4.2" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" +checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511" dependencies = [ "cfg-if", ] @@ -1154,9 +1154,9 @@ checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" [[package]] name = "crunchy" -version = "0.2.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43da5946c66ffcc7745f48db692ffbb10a83bfe0afd96235c5c2a4fb23994929" +checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" [[package]] name = "crypto-common" @@ -1170,15 +1170,15 @@ dependencies = [ [[package]] name = "cssparser" -version = "0.27.2" +version = "0.29.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "754b69d351cdc2d8ee09ae203db831e005560fc6030da058f86ad60c92a9cb0a" +checksum = "f93d03419cb5950ccfd3daf3ff1c7a36ace64609a1a8746d493df1ca0afde0fa" dependencies = [ "cssparser-macros", "dtoa-short", - "itoa 0.4.8", + "itoa", "matches", - "phf 0.8.0", + "phf 0.10.1", "proc-macro2", "quote", "smallvec", @@ -1192,7 +1192,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13b588ba4ac1a99f7f2964d24b3d896ddc6bf847ee3855dbd4366f058cfcd331" dependencies = [ "quote", - "syn 2.0.101", + "syn 2.0.106", ] [[package]] @@ -1202,7 +1202,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a2785755761f3ddc1492979ce1e48d2c00d09311c39e4466429188f3dd6501" dependencies = [ "quote", - "syn 2.0.101", + "syn 2.0.106", ] [[package]] @@ -1226,7 +1226,7 @@ dependencies = [ "proc-macro2", "quote", "strsim 0.11.1", - "syn 2.0.101", + "syn 2.0.106", ] [[package]] @@ -1237,7 +1237,7 @@ checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead" dependencies = [ "darling_core", "quote", - "syn 2.0.101", + "syn 2.0.106", ] [[package]] @@ -1248,19 +1248,19 @@ checksum = "2a2330da5de22e8a3cb63252ce2abb30116bf5265e89c0e01bc17015ce30a476" [[package]] name = "data-url" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c297a1c74b71ae29df00c3e22dd9534821d60eb9af5a0192823fa2acea70c2a" +checksum = "be1e0bca6c3637f992fc1cc7cbc52a78c1ef6db076dbf1059c4323d6a2048376" [[package]] name = "dbus" -version = "0.9.7" +version = "0.9.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bb21987b9fb1613058ba3843121dd18b163b254d8a6e797e144cbac14d96d1b" +checksum = "190b6255e8ab55a7b568df5a883e9497edc3e4821c06396612048b430e5ad1e9" dependencies = [ "libc", "libdbus-sys", - "winapi", + "windows-sys 0.59.0", ] [[package]] @@ -1271,9 +1271,9 @@ checksum = "da692b8d1080ea3045efaab14434d40468c3d8657e42abddfffca87b428f4c1b" [[package]] name = "deranged" -version = "0.4.0" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c9e6a11ca8224451684bc0d7d5a7adbf8f2fd6887261a1cfc3c0432f9d4068e" +checksum = "d630bccd429a5bb5a64b5e94f693bfc48c9f8566418fda4c494cc94f911f87cc" dependencies = [ "powerfmt", "serde", @@ -1281,13 +1281,13 @@ dependencies = [ [[package]] name = "derive_arbitrary" -version = "1.4.1" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30542c1ad912e0e3d22a1935c290e12e8a29d704a420177a31faad4a601a0800" +checksum = "1e567bd82dcff979e4b03460c307b3cdc9e96fde3d73bed1496d2bc75d9dd62a" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.106", ] [[package]] @@ -1300,7 +1300,7 @@ dependencies = [ "proc-macro2", "quote", "rustc_version", - "syn 2.0.101", + "syn 2.0.106", ] [[package]] @@ -1320,7 +1320,7 @@ checksum = "bda628edc44c4bb645fbe0f758797143e4e07926f7ebf4e9bdfbd3d2ce621df3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.106", "unicode-xid", ] @@ -1393,8 +1393,8 @@ checksum = "e01a3366d27ee9890022452ee61b2b63a67e6f13f58900b651ff5665f0bb1fab" dependencies = [ "libc", "option-ext", - "redox_users 0.5.0", - "windows-sys 0.59.0", + "redox_users 0.5.2", + "windows-sys 0.60.2", ] [[package]] @@ -1403,26 +1403,16 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bd0c93bb4b0c6d9b77f4435b0ae98c24d17f1c45b2ff844c6151a07256ca923b" -[[package]] -name = "dispatch2" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a0d569e003ff27784e0e14e4a594048698e0c0f0b66cabcb51511be55a7caa0" -dependencies = [ - "bitflags 2.9.0", - "block2 0.6.1", - "libc", - "objc2 0.6.1", -] - [[package]] name = "dispatch2" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "89a09f22a6c6069a18470eb92d2298acf25463f14256d24778e1230d789a2aec" dependencies = [ - "bitflags 2.9.0", - "objc2 0.6.1", + "bitflags 2.9.4", + "block2 0.6.1", + "libc", + "objc2 0.6.2", ] [[package]] @@ -1433,14 +1423,23 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.106", +] + +[[package]] +name = "dlib" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "330c60081dcc4c72131f8eb70510f1ac07223e5d4163db481a04a0befcffa412" +dependencies = [ + "libloading 0.8.8", ] [[package]] name = "dlopen2" -version = "0.7.0" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e1297103d2bbaea85724fcee6294c2d50b1081f9ad47d0f6f6f61eda65315a6" +checksum = "b54f373ccf864bf587a89e880fb7610f8d73f3045f13580948ccbcaff26febff" dependencies = [ "dlopen2_derive", "libc", @@ -1450,13 +1449,13 @@ dependencies = [ [[package]] name = "dlopen2_derive" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2b99bf03862d7f545ebc28ddd33a665b50865f4dfd84031a393823879bd4c54" +checksum = "788160fb30de9cdd857af31c6a2675904b16ece8fc2737b2c7127ba368c9d0f4" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.106", ] [[package]] @@ -1477,6 +1476,12 @@ dependencies = [ "litrs", ] +[[package]] +name = "downcast-rs" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2" + [[package]] name = "dpi" version = "0.1.2" @@ -1530,9 +1535,9 @@ checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" [[package]] name = "dyn-clone" -version = "1.0.19" +version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c7a8fb8a9fbf66c1f703fe16184d10ca0ee9d23be5b4436400408ba54a95005" +checksum = "d0881ea181b1df73ff77ffaaf9c7544ecc11e82fba9b5f27b262a3c73a332555" [[package]] name = "either" @@ -1542,16 +1547,16 @@ checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" [[package]] name = "embed-resource" -version = "3.0.2" +version = "3.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fbc6e0d8e0c03a655b53ca813f0463d2c956bc4db8138dbc89f120b066551e3" +checksum = "4c6d81016d6c977deefb2ef8d8290da019e27cc26167e102185da528e6c0ab38" dependencies = [ "cc", "memchr", "rustc_version", - "toml", + "toml 0.9.5", "vswhom", - "winreg 0.52.0", + "winreg 0.55.0", ] [[package]] @@ -1581,7 +1586,7 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0cf6f550bbbdd5fe66f39d429cb2604bcdacbf00dca0f5bbe2e9306a0009b7c6" dependencies = [ - "core-foundation 0.10.0", + "core-foundation 0.10.1", "core-graphics 0.24.0", "foreign-types-shared 0.3.1", "libc", @@ -1611,14 +1616,14 @@ checksum = "0d28318a75d4aead5c4db25382e8ef717932d0346600cacae6357eb5941bc5ff" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.106", ] [[package]] name = "enumflags2" -version = "0.7.11" +version = "0.7.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba2f4b465f5318854c6f8dd686ede6c0a9dc67d4b1ac241cf0eb51521a309147" +checksum = "1027f7680c853e056ebcec683615fb6fbbc07dbaa13b4d5d9442b146ded4ecef" dependencies = [ "enumflags2_derive", "serde", @@ -1626,13 +1631,13 @@ dependencies = [ [[package]] name = "enumflags2_derive" -version = "0.7.11" +version = "0.7.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc4caf64a58d7a6d65ab00639b046ff54399a39f5f2554728895ace4b297cd79" +checksum = "67c78a4d8fdf9953a5c9d458f9efe940fd97a0cab0941c075a813ac594733827" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.106", ] [[package]] @@ -1651,6 +1656,26 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c7f84e12ccf0a7ddc17a6c41c93326024c42920d7ee630d04950e6926645c0fe" +[[package]] +name = "equator" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4711b213838dfee0117e3be6ac926007d7f433d7bbe33595975d4190cb07e6fc" +dependencies = [ + "equator-macro", +] + +[[package]] +name = "equator-macro" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44f23cf4b44bfce11a86ace86f8a73ffdec849c9fd00a386a53d278bd9e81fb3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", +] + [[package]] name = "equivalent" version = "1.0.2" @@ -1669,19 +1694,19 @@ dependencies = [ [[package]] name = "errno" -version = "0.3.11" +version = "0.3.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "976dd42dc7e85965fe702eb8164f21f450704bdde31faefd6471dba214cb594e" +checksum = "778e2ac28f6c47af28e4907f13ffd1e1ddbd400980a9abd7c8df189bf578a5ad" dependencies = [ "libc", - "windows-sys 0.59.0", + "windows-sys 0.60.2", ] [[package]] name = "event-listener" -version = "5.4.0" +version = "5.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3492acde4c3fc54c845eaab3eed8bd00c7a7d881f78bfc801e43a93dec1331ae" +checksum = "e13b66accf52311f30a0db42147dadea9850cb48cd070028831ae5f5d4b856ab" dependencies = [ "concurrent-queue", "parking", @@ -1719,6 +1744,26 @@ version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" +[[package]] +name = "fax" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f05de7d48f37cd6730705cbca900770cab77a89f413d23e100ad7fad7795a0ab" +dependencies = [ + "fax_derive", +] + +[[package]] +name = "fax_derive" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0aca10fb742cb43f9e7bb8467c91aa9bcb8e3ffbc6a6f7389bb93ffc920577d" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", +] + [[package]] name = "fdeflate" version = "0.3.7" @@ -1764,21 +1809,27 @@ dependencies = [ [[package]] name = "filetime" -version = "0.2.25" +version = "0.2.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35c0522e981e68cbfa8c3f978441a5f34b30b96e146b33cd3359176b50fe8586" +checksum = "bc0505cd1b6fa6580283f6bdf70a73fcf4aba1184038c90902b92b3dd0df63ed" dependencies = [ "cfg-if", "libc", "libredox", - "windows-sys 0.59.0", + "windows-sys 0.60.2", ] [[package]] -name = "flate2" -version = "1.1.1" +name = "find-msvc-tools" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ced92e76e966ca2fd84c8f7aa01a4aea65b0eb6648d72f7c8f3e2764a67fece" +checksum = "e178e4fba8a2726903f6ba98a6d221e76f9c12c650d5dc0e6afdc50677b49650" + +[[package]] +name = "flate2" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a3d7db9596fecd151c5f638c0ee5d5bd487b6e0ea232e5dc96d5250f6f94b1d" dependencies = [ "crc32fast", "libz-rs-sys", @@ -1818,7 +1869,7 @@ checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.106", ] [[package]] @@ -1835,21 +1886,21 @@ checksum = "aa9a19cbb55df58761df49b23516a86d432839add4af60fc256da840f66ed35b" [[package]] name = "form_urlencoded" -version = "1.2.1" +version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" +checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" dependencies = [ "percent-encoding", ] [[package]] name = "freedesktop-file-parser" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "896344fc2c460ea34728f8f9a5685c28762a910d310c35a5001f6a8f6e0467bb" +checksum = "b1998b5ee36700463150124ac6d6d6128a5a4da453a6f6777a26810f05539f41" dependencies = [ "freedesktop-icons", - "thiserror 2.0.12", + "thiserror 2.0.16", ] [[package]] @@ -1962,9 +2013,9 @@ checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" [[package]] name = "futures-lite" -version = "2.6.0" +version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5edaec856126859abb19ed65f39e90fea3a9574b9707f13539acf4abf7eb532" +checksum = "f78e10609fe0e0b3f4157ffab1876319b5b0db102a2c60dc4626306dc46b44ad" dependencies = [ "fastrand", "futures-core", @@ -1981,7 +2032,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.106", ] [[package]] @@ -2138,7 +2189,7 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc257fdb4038301ce4b9cd1b3b51704509692bb3ff716a410cbd07925d9dae55" dependencies = [ - "rustix 1.0.7", + "rustix", "windows-targets 0.52.6", ] @@ -2162,29 +2213,29 @@ dependencies = [ "cfg-if", "js-sys", "libc", - "wasi 0.11.0+wasi-snapshot-preview1", + "wasi 0.11.1+wasi-snapshot-preview1", "wasm-bindgen", ] [[package]] name = "getrandom" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73fea8450eea4bac3940448fb7ae50d91f034f941199fcd9d909a5a07aa455f0" +checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" dependencies = [ "cfg-if", "js-sys", "libc", "r-efi", - "wasi 0.14.2+wasi-0.2.4", + "wasi 0.14.3+wasi-0.2.4", "wasm-bindgen", ] [[package]] name = "gif" -version = "0.13.1" +version = "0.13.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fb2d69b19215e18bb912fa30f7ce15846e301408695e44e0ef719f1da9e19f2" +checksum = "4ae047235e33e2829703574b54fdec96bfbad892062d97fed2f76022287de61b" dependencies = [ "color_quant", "weezl", @@ -2225,8 +2276,8 @@ dependencies = [ "futures-core", "futures-io", "futures-util", - "gio-sys 0.20.9", - "glib 0.20.9", + "gio-sys 0.20.10", + "glib 0.20.12", "libc", "pin-project-lite", "smallvec", @@ -2247,14 +2298,14 @@ dependencies = [ [[package]] name = "gio-sys" -version = "0.20.9" +version = "0.20.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "160eb5250a26998c3e1b54e6a3d4ea15c6c7762a6062a19a7b63eff6e2b33f9e" +checksum = "521e93a7e56fc89e84aea9a52cfc9436816a4b363b030260b699950ff1336c83" dependencies = [ - "glib-sys 0.20.9", - "gobject-sys 0.20.9", + "glib-sys 0.20.10", + "gobject-sys 0.20.10", "libc", - "system-deps 7.0.3", + "system-deps 7.0.5", "windows-sys 0.59.0", ] @@ -2264,7 +2315,7 @@ version = "0.18.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "233daaf6e83ae6a12a52055f568f9d7cf4671dabb78ff9560ab6da230ce00ee5" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.4", "futures-channel", "futures-core", "futures-executor", @@ -2283,20 +2334,20 @@ dependencies = [ [[package]] name = "glib" -version = "0.20.9" +version = "0.20.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "707b819af8059ee5395a2de9f2317d87a53dbad8846a2f089f0bb44703f37686" +checksum = "ffc4b6e352d4716d84d7dde562dd9aee2a7d48beb872dd9ece7f2d1515b2d683" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.4", "futures-channel", "futures-core", "futures-executor", "futures-task", "futures-util", - "gio-sys 0.20.9", - "glib-macros 0.20.7", - "glib-sys 0.20.9", - "gobject-sys 0.20.9", + "gio-sys 0.20.10", + "glib-macros 0.20.12", + "glib-sys 0.20.10", + "gobject-sys 0.20.10", "libc", "memchr", "smallvec", @@ -2313,20 +2364,20 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.106", ] [[package]] name = "glib-macros" -version = "0.20.7" +version = "0.20.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "715601f8f02e71baef9c1f94a657a9a77c192aea6097cf9ae7e5e177cd8cde68" +checksum = "e8084af62f09475a3f529b1629c10c429d7600ee1398ae12dd3bf175d74e7145" dependencies = [ "heck 0.5.0", "proc-macro-crate 3.3.0", "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.106", ] [[package]] @@ -2341,35 +2392,36 @@ dependencies = [ [[package]] name = "glib-sys" -version = "0.20.9" +version = "0.20.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8928869a44cfdd1fccb17d6746e4ff82c8f82e41ce705aa026a52ca8dc3aefb" +checksum = "8ab79e1ed126803a8fb827e3de0e2ff95191912b8db65cee467edb56fc4cc215" dependencies = [ "libc", - "system-deps 7.0.3", + "system-deps 7.0.5", ] [[package]] name = "glob" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2" +checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" [[package]] name = "global-hotkey" -version = "0.6.4" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41fbb3a4e56c901ee66c190fdb3fa08344e6d09593cc6c61f8eb9add7144b271" +checksum = "b9247516746aa8e53411a0db9b62b0e24efbcf6a76e0ba73e5a91b512ddabed7" dependencies = [ "crossbeam-channel", "keyboard-types", - "objc2 0.6.1", + "objc2 0.6.2", "objc2-app-kit 0.3.1", "once_cell", "serde", - "thiserror 2.0.12", + "thiserror 2.0.16", "windows-sys 0.59.0", - "x11-dl", + "x11rb", + "xkeysym", ] [[package]] @@ -2385,13 +2437,13 @@ dependencies = [ [[package]] name = "gobject-sys" -version = "0.20.9" +version = "0.20.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c773a3cb38a419ad9c26c81d177d96b4b08980e8bdbbf32dace883e96e96e7e3" +checksum = "ec9aca94bb73989e3cfdbf8f2e0f1f6da04db4d291c431f444838925c4c63eda" dependencies = [ - "glib-sys 0.20.9", + "glib-sys 0.20.10", "libc", - "system-deps 7.0.3", + "system-deps 7.0.5", ] [[package]] @@ -2443,14 +2495,14 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.106", ] [[package]] name = "h2" -version = "0.4.10" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9421a676d1b147b16b82c9225157dc629087ef8ec4d5e2960f9437a90dac0a5" +checksum = "f3c0b69cfcb4e1b9f1bf2f53f95f766e4661169728ec61cd3fe5a0166f2d1386" dependencies = [ "atomic-waker", "bytes", @@ -2458,7 +2510,7 @@ dependencies = [ "futures-core", "futures-sink", "http 1.3.1", - "indexmap 2.10.0", + "indexmap 2.11.0", "slab", "tokio", "tokio-util", @@ -2496,9 +2548,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.15.3" +version = "0.15.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84b26c544d002229e640969970a2e74021aadf6e2f96372b9c58eff97de08eb3" +checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" [[package]] name = "heck" @@ -2514,9 +2566,9 @@ checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" [[package]] name = "hermit-abi" -version = "0.4.0" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc" +checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" [[package]] name = "hex" @@ -2546,16 +2598,14 @@ dependencies = [ [[package]] name = "html5ever" -version = "0.26.0" +version = "0.29.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bea68cab48b8459f17cf1c944c67ddc572d272d9f2b274140f223ecb1da4a3b7" +checksum = "3b7410cae13cbc75623c98ac4cbfd1f0bedddf3227afc24f370cf0f50a44a11c" dependencies = [ "log", "mac", "markup5ever", - "proc-macro2", - "quote", - "syn 1.0.109", + "match_token", ] [[package]] @@ -2566,7 +2616,7 @@ checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" dependencies = [ "bytes", "fnv", - "itoa 1.0.15", + "itoa", ] [[package]] @@ -2577,7 +2627,7 @@ checksum = "f4a85d31aea989eead29a3aaf9e1115a180df8282431156e533de47660892565" dependencies = [ "bytes", "fnv", - "itoa 1.0.15", + "itoa", ] [[package]] @@ -2646,7 +2696,7 @@ dependencies = [ "http-body 0.4.6", "httparse", "httpdate", - "itoa 1.0.15", + "itoa", "pin-project-lite", "tokio", "tower-service", @@ -2656,19 +2706,21 @@ dependencies = [ [[package]] name = "hyper" -version = "1.6.0" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc2b571658e38e0c01b1fdca3bbbe93c00d3d71693ff2770043f8c29bc7d6f80" +checksum = "eb3aa54a13a0dfe7fbe3a59e0c76093041720fdc77b110cc0fc260fafb4dc51e" dependencies = [ + "atomic-waker", "bytes", "futures-channel", - "futures-util", + "futures-core", "h2", "http 1.3.1", "http-body 1.0.1", "httparse", - "itoa 1.0.15", + "itoa", "pin-project-lite", + "pin-utils", "smallvec", "tokio", "want", @@ -2676,20 +2728,19 @@ dependencies = [ [[package]] name = "hyper-rustls" -version = "0.27.5" +version = "0.27.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d191583f3da1305256f22463b9bb0471acad48a4e534a5218b9963e9c1f59b2" +checksum = "e3c93eb611681b207e1fe55d5a71ecf91572ec8a6705cdb6857f7d8d5242cf58" dependencies = [ - "futures-util", "http 1.3.1", - "hyper 1.6.0", + "hyper 1.7.0", "hyper-util", "rustls", "rustls-pki-types", "tokio", "tokio-rustls", "tower-service", - "webpki-roots 0.26.11", + "webpki-roots", ] [[package]] @@ -2700,7 +2751,7 @@ checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" dependencies = [ "bytes", "http-body-util", - "hyper 1.6.0", + "hyper 1.7.0", "hyper-util", "native-tls", "tokio", @@ -2710,22 +2761,28 @@ dependencies = [ [[package]] name = "hyper-util" -version = "0.1.11" +version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "497bbc33a26fdd4af9ed9c70d63f61cf56a938375fbb32df34db9b1cd6d643f2" +checksum = "8d9b05277c7e8da2c93a568989bb6207bef0112e8d17df7a6eda4a3cf143bc5e" dependencies = [ + "base64 0.22.1", "bytes", "futures-channel", + "futures-core", "futures-util", "http 1.3.1", "http-body 1.0.1", - "hyper 1.6.0", + "hyper 1.7.0", + "ipnet", "libc", + "percent-encoding", "pin-project-lite", "socket2", + "system-configuration", "tokio", "tower-service", "tracing", + "windows-registry", ] [[package]] @@ -2759,7 +2816,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cc50b891e4acf8fe0e71ef88ec43ad82ee07b3810ad09de10f1d01f072ed4b98" dependencies = [ "byteorder", - "png", + "png 0.17.16", ] [[package]] @@ -2811,9 +2868,9 @@ checksum = "00210d6893afc98edb752b664b8890f0ef174c8adbb8d0be9710fa66fbbf72d3" [[package]] name = "icu_properties" -version = "2.0.0" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2549ca8c7241c82f59c80ba2a6f415d931c5b58d24fb8412caa1a1f02c49139a" +checksum = "016c619c1eeb94efb86809b015c58f479963de65bdb6253345c1a1276f22e32b" dependencies = [ "displaydoc", "icu_collections", @@ -2827,9 +2884,9 @@ dependencies = [ [[package]] name = "icu_properties_data" -version = "2.0.0" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8197e866e47b68f8f7d95249e172903bec06004b18b2937f1095d40a0c57de04" +checksum = "298459143998310acd25ffe6810ed544932242d3f07083eee1084d83a71bd632" [[package]] name = "icu_provider" @@ -2856,9 +2913,9 @@ checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" [[package]] name = "idna" -version = "1.0.3" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" +checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" dependencies = [ "idna_adapter", "smallvec", @@ -2877,9 +2934,9 @@ dependencies = [ [[package]] name = "image" -version = "0.25.6" +version = "0.25.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db35664ce6b9810857a38a906215e75a9c879f0696556a39f59c62829710251a" +checksum = "529feb3e6769d234375c4cf1ee2ce713682b8e76538cb13f9fc23e1400a591e7" dependencies = [ "bytemuck", "byteorder-lite", @@ -2887,8 +2944,9 @@ dependencies = [ "exr", "gif", "image-webp", + "moxcms", "num-traits", - "png", + "png 0.18.0", "qoi", "ravif", "rayon", @@ -2900,9 +2958,9 @@ dependencies = [ [[package]] name = "image-webp" -version = "0.2.1" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b77d01e822461baa8409e156015a1d91735549f0f2c17691bd2d996bef238f7f" +checksum = "525e9ff3e1a4be2fbea1fdf0e98686a6d98b4d8f937e1bf7402245af1909e8c3" dependencies = [ "byteorder-lite", "quick-error", @@ -2927,12 +2985,12 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.10.0" +version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe4cd85333e22411419a0bcae1297d25e58c9443848b11dc6a86fefe8c78a661" +checksum = "f2481980430f9f78649238835720ddccc57e52df14ffce1c6f37391d61b563e9" dependencies = [ "equivalent", - "hashbrown 0.15.3", + "hashbrown 0.15.5", "serde", ] @@ -2971,7 +3029,7 @@ version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f37dccff2791ab604f9babef0ba14fbe0be30bd368dc541e2b08d07c8aa908f3" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.4", "inotify-sys", "libc", ] @@ -3002,7 +3060,18 @@ checksum = "c34819042dc3d3971c46c2190835914dfbe0c3c13f61449b2997f4e9722dfa60" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.106", +] + +[[package]] +name = "io-uring" +version = "0.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "046fa2d4d00aea763528b4950358d0ead425372445dc8ff86312b3c69ff7727b" +dependencies = [ + "bitflags 2.9.4", + "cfg-if", + "libc", ] [[package]] @@ -3011,6 +3080,16 @@ version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130" +[[package]] +name = "iri-string" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbc5ebe9c3a1a7a5127f920a418f7585e9e758e911d0466ed004f393b0e380b2" +dependencies = [ + "memchr", + "serde", +] + [[package]] name = "is-docker" version = "0.2.0" @@ -3048,12 +3127,6 @@ dependencies = [ "either", ] -[[package]] -name = "itoa" -version = "0.4.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4" - [[package]] name = "itoa" version = "1.0.15" @@ -3107,20 +3180,14 @@ checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" [[package]] name = "jobserver" -version = "0.1.33" +version = "0.1.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38f262f097c174adebe41eb73d66ae9c06b2844fb0da69969647bbddd9b0538a" +checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33" dependencies = [ - "getrandom 0.3.2", + "getrandom 0.3.3", "libc", ] -[[package]] -name = "jpeg-decoder" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5d4a7da358eff58addd2877a45865158f0d78c911d43a5784ceb7bbf52833b0" - [[package]] name = "js-sys" version = "0.3.77" @@ -3159,7 +3226,7 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b750dcadc39a09dbadd74e118f6dd6598df77fa01df0cfcdc52c28dece74528a" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.4", "serde", "unicode-segmentation", ] @@ -3186,14 +3253,13 @@ dependencies = [ [[package]] name = "kuchikiki" -version = "0.8.2" +version = "0.8.8-speedreader" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f29e4755b7b995046f510a7520c42b2fed58b77bd94d5a87a8eb43d2fd126da8" +checksum = "02cb977175687f33fa4afa0c95c112b987ea1443e5a51c8f8ff27dc618270cc2" dependencies = [ "cssparser", "html5ever", - "indexmap 1.9.3", - "matches", + "indexmap 2.11.0", "selectors", ] @@ -3229,10 +3295,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6e9ec52138abedcc58dc17a7c6c0c00a2bdb4f3427c7f63fa97fd0d859155caf" dependencies = [ "gtk-sys", - "libloading", + "libloading 0.7.4", "once_cell", ] +[[package]] +name = "libbz2-rs-sys" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c4a545a15244c7d945065b5d392b2d2d7f21526fba56ce51467b06ed445e8f7" + [[package]] name = "libc" version = "0.2.175" @@ -3241,18 +3313,18 @@ checksum = "6a82ae493e598baaea5209805c49bbf2ea7de956d50d7da0da1164f9c6d28543" [[package]] name = "libdbus-sys" -version = "0.2.5" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06085512b750d640299b79be4bad3d2fa90a9c00b1fd9e1b46364f66f0485c72" +checksum = "5cbe856efeb50e4681f010e9aaa2bf0a644e10139e54cde10fc83a307c23bd9f" dependencies = [ "pkg-config", ] [[package]] name = "libfuzzer-sys" -version = "0.4.9" +version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf78f52d400cf2d84a3a973a78a592b4adc535739e0a5597a0da6f0c357adc75" +checksum = "5037190e1f70cbeef565bd267599242926f724d3b8a9f510fd7e0b540cfa4404" dependencies = [ "arbitrary", "cc", @@ -3269,10 +3341,20 @@ dependencies = [ ] [[package]] -name = "liblzma" -version = "0.4.1" +name = "libloading" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66352d7a8ac12d4877b6e6ea5a9b7650ee094257dc40889955bea5bc5b08c1d0" +checksum = "07033963ba89ebaf1584d767badaa2e8fcec21aedea6b8c0346d487d49c28667" +dependencies = [ + "cfg-if", + "windows-targets 0.53.3", +] + +[[package]] +name = "liblzma" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10bf66f4598dc77ff96677c8e763655494f00ff9c1cf79e2eb5bb07bc31f807d" dependencies = [ "liblzma-sys", ] @@ -3290,30 +3372,24 @@ dependencies = [ [[package]] name = "libredox" -version = "0.1.3" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" +checksum = "391290121bad3d37fbddad76d8f5d1c1c314cfc646d143d7e07a3086ddff0ce3" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.4", "libc", "redox_syscall", ] [[package]] name = "libz-rs-sys" -version = "0.5.1" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "172a788537a2221661b480fee8dc5f96c580eb34fa88764d3205dc356c7e4221" +checksum = "840db8cf39d9ec4dd794376f38acc40d0fc65eec2a8f484f7fd375b84602becd" dependencies = [ "zlib-rs", ] -[[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" @@ -3328,9 +3404,9 @@ checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956" [[package]] name = "litrs" -version = "0.4.1" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4ce301924b7887e9d637144fdade93f9dfff9b60981d4ac161db09720d39aa5" +checksum = "f5e54036fe321fd421e10d732f155734c4e4afd610dd556d9a82833ab3ee0bed" [[package]] name = "lnk" @@ -3348,9 +3424,9 @@ dependencies = [ [[package]] name = "lock_api" -version = "0.4.12" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" +checksum = "96936507f153605bddfcda068dd804796c84324ed2510809e5b2a624c81da765" dependencies = [ "autocfg", "scopeguard", @@ -3358,9 +3434,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.27" +version = "0.4.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" +checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432" dependencies = [ "value-bag", ] @@ -3374,6 +3450,12 @@ dependencies = [ "imgref", ] +[[package]] +name = "lru-slab" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154" + [[package]] name = "mac" version = "0.1.1" @@ -3401,13 +3483,13 @@ dependencies = [ [[package]] name = "markup5ever" -version = "0.11.0" +version = "0.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a2629bb1404f3d34c2e921f21fd34ba00b206124c81f65c50b43b6aaefeb016" +checksum = "c7a7213d12e1864c0f002f52c2923d4556935a43dec5e71355c2760e0f6e7a18" dependencies = [ "log", - "phf 0.10.1", - "phf_codegen 0.10.0", + "phf 0.11.3", + "phf_codegen 0.11.3", "string_cache", "string_cache_codegen", "tendril", @@ -3419,6 +3501,17 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ffbee8634e0d45d258acb448e7eaab3fce7a0a467395d4d9f228e3c1f01fb2e4" +[[package]] +name = "match_token" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88a9689d8d44bf9964484516275f5cd4c9b59457a6940c1d5d0ecbb94510a36b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", +] + [[package]] name = "matches" version = "0.1.10" @@ -3437,15 +3530,15 @@ dependencies = [ [[package]] name = "memchr" -version = "2.7.4" +version = "2.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" +checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0" [[package]] name = "memmap2" -version = "0.9.5" +version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd3f7eed9d3848f8b98834af67102b720745c4ec028fcd0aa0239277e7de374f" +checksum = "843a98750cd611cc2965a8213b53b43e715f13c37a9e096c6408e69990961db7" dependencies = [ "libc", ] @@ -3462,7 +3555,7 @@ dependencies = [ [[package]] name = "meval" version = "0.2.0" -source = "git+https://github.com/infinilabs/meval-rs#8113cdae751b7ca060d28a08ecbfbcededfd4304" +source = "git+https://github.com/infinilabs/meval-rs#3d374250ab12cf1deae765bfc6683ce2d9b14f7d" dependencies = [ "fnv", "nom 8.0.0", @@ -3492,15 +3585,15 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] name = "minisign-verify" -version = "0.2.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6367d84fb54d4242af283086402907277715b8fe46976963af5ebf173f8efba3" +checksum = "e856fdd13623a2f5f2f54676a4ee49502a96a80ef4a62bcedd23d52427c44d43" [[package]] name = "miniz_oxide" -version = "0.8.8" +version = "0.8.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3be647b768db090acb35d5ec5db2b0e1f1de11133ca123b9eacf5137868f892a" +checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" dependencies = [ "adler2", "simd-adler32", @@ -3514,41 +3607,51 @@ checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" dependencies = [ "libc", "log", - "wasi 0.11.0+wasi-snapshot-preview1", + "wasi 0.11.1+wasi-snapshot-preview1", "windows-sys 0.48.0", ] [[package]] name = "mio" -version = "1.0.3" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd" +checksum = "78bed444cc8a2160f01cbcf811ef18cac863ad68ae8ca62092e8db51d51c761c" dependencies = [ "libc", "log", - "wasi 0.11.0+wasi-snapshot-preview1", - "windows-sys 0.52.0", + "wasi 0.11.1+wasi-snapshot-preview1", + "windows-sys 0.59.0", +] + +[[package]] +name = "moxcms" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddd32fa8935aeadb8a8a6b6b351e40225570a37c43de67690383d87ef170cd08" +dependencies = [ + "num-traits", + "pxfm", ] [[package]] name = "muda" -version = "0.16.1" +version = "0.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4de14a9b5d569ca68d7c891d613b390cf5ab4f851c77aaa2f9e435555d3d9492" +checksum = "01c1738382f66ed56b3b9c8119e794a2e23148ac8ea214eda86622d4cb9d415a" dependencies = [ "crossbeam-channel", "dpi", "gtk", "keyboard-types", - "objc2 0.6.1", + "objc2 0.6.2", "objc2-app-kit 0.3.1", "objc2-core-foundation", "objc2-foundation 0.3.1", "once_cell", - "png", + "png 0.17.16", "serde", - "thiserror 2.0.12", - "windows-sys 0.59.0", + "thiserror 2.0.16", + "windows-sys 0.60.2", ] [[package]] @@ -3574,7 +3677,7 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3f42e7bbe13d351b6bead8286a43aac9534b82bd3cc43e47037f012ebfd62d4" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.4", "jni-sys", "log", "ndk-sys", @@ -3604,29 +3707,17 @@ version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" -[[package]] -name = "nix" -version = "0.29.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46" -dependencies = [ - "bitflags 2.9.0", - "cfg-if", - "cfg_aliases", - "libc", - "memoffset", -] - [[package]] name = "nix" version = "0.30.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "74523f3a35e05aba87a1d978330aef40f67b0304ac79c1c00b294c9830543db6" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.4", "cfg-if", "cfg_aliases", "libc", + "memoffset", ] [[package]] @@ -3680,21 +3771,20 @@ dependencies = [ [[package]] name = "notify" -version = "8.0.0" +version = "8.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fee8403b3d66ac7b26aee6e40a897d85dc5ce26f44da36b8b73e987cc52e943" +checksum = "4d3d07927151ff8575b7087f245456e549fea62edf0ec4e565a5ee50c8402bc3" dependencies = [ - "bitflags 2.9.0", - "filetime", + "bitflags 2.9.4", "fsevent-sys", "inotify 0.11.0", "kqueue", "libc", "log", - "mio 1.0.3", + "mio 1.0.4", "notify-types", "walkdir", - "windows-sys 0.59.0", + "windows-sys 0.60.2", ] [[package]] @@ -3753,7 +3843,7 @@ checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.106", ] [[package]] @@ -3796,23 +3886,24 @@ dependencies = [ [[package]] name = "num_enum" -version = "0.7.3" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e613fc340b2220f734a8595782c551f1250e969d87d3be1ae0579e8d4065179" +checksum = "a973b4e44ce6cad84ce69d797acf9a044532e4184c4f267913d1b546a0727b7a" dependencies = [ "num_enum_derive", + "rustversion", ] [[package]] name = "num_enum_derive" -version = "0.7.3" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af1844ef2428cc3e1cb900be36181049ef3d3193c63e43026cfe202983b27a56" +checksum = "77e878c846a8abae00dd069496dbe8751b16ac1c3d6bd2a7283a938e8228f90d" dependencies = [ "proc-macro-crate 3.3.0", "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.106", ] [[package]] @@ -3862,9 +3953,9 @@ dependencies = [ [[package]] name = "objc2" -version = "0.6.1" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88c6597e14493ab2e44ce58f2fdecf095a51f12ca57bec060a11c57332520551" +checksum = "561f357ba7f3a2a61563a186a163d0a3a5247e1089524a3981d49adb775078bc" dependencies = [ "objc2-encode", "objc2-exception-helper", @@ -3876,7 +3967,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e4e89ad9e3d7d297152b17d39ed92cd50ca8063a89a9fa569046d41568891eff" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.4", "block2 0.5.1", "libc", "objc2 0.5.2", @@ -3892,10 +3983,10 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6f29f568bec459b0ddff777cec4fe3fd8666d82d5a40ebd0ff7e66134f89bcc" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.4", "block2 0.6.1", "libc", - "objc2 0.6.1", + "objc2 0.6.2", "objc2-cloud-kit", "objc2-core-data 0.3.1", "objc2-core-foundation", @@ -3905,14 +3996,29 @@ dependencies = [ "objc2-quartz-core 0.3.1", ] +[[package]] +name = "objc2-application-services" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9abc05b1f757ebfbd72f4f3f9a515662c67dfe66b26e71b37d818f56a1c2f17" +dependencies = [ + "bitflags 2.9.4", + "libc", + "objc2 0.6.2", + "objc2-core-foundation", + "objc2-core-graphics", + "objc2-core-services", + "objc2-foundation 0.3.1", +] + [[package]] name = "objc2-cloud-kit" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "17614fdcd9b411e6ff1117dfb1d0150f908ba83a7df81b1f118005fe0a8ea15d" dependencies = [ - "bitflags 2.9.0", - "objc2 0.6.1", + "bitflags 2.9.4", + "objc2 0.6.2", "objc2-foundation 0.3.1", ] @@ -3922,7 +4028,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "617fbf49e071c178c0b24c080767db52958f716d9eabdf0890523aeae54773ef" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.4", "block2 0.5.1", "objc2 0.5.2", "objc2-foundation 0.2.2", @@ -3934,8 +4040,8 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "291fbbf7d29287518e8686417cf7239c74700fd4b607623140a7d4a3c834329d" dependencies = [ - "bitflags 2.9.0", - "objc2 0.6.1", + "bitflags 2.9.4", + "objc2 0.6.2", "objc2-foundation 0.3.1", ] @@ -3945,11 +4051,11 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1c10c2894a6fed806ade6027bcd50662746363a9589d3ec9d9bef30a4e4bc166" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.4", "block2 0.6.1", - "dispatch2 0.3.0", + "dispatch2", "libc", - "objc2 0.6.1", + "objc2 0.6.2", ] [[package]] @@ -3958,11 +4064,11 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "989c6c68c13021b5c2d6b71456ebb0f9dc78d752e86a98da7c716f4f9470f5a4" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.4", "block2 0.6.1", - "dispatch2 0.3.0", + "dispatch2", "libc", - "objc2 0.6.1", + "objc2 0.6.2", "objc2-core-foundation", "objc2-io-surface", "objc2-metal 0.3.1", @@ -3986,10 +4092,22 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "79b3dc0cc4386b6ccf21c157591b34a7f44c8e75b064f85502901ab2188c007e" dependencies = [ - "objc2 0.6.1", + "objc2 0.6.2", "objc2-foundation 0.3.1", ] +[[package]] +name = "objc2-core-services" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "159be6e4cd366c7d236d798daa2aa71855230e5691cde045a0670ce01a06d664" +dependencies = [ + "dispatch2", + "objc2 0.6.2", + "objc2-core-foundation", + "objc2-security", +] + [[package]] name = "objc2-encode" version = "4.1.0" @@ -4011,7 +4129,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ee638a5da3799329310ad4cfa62fbf045d5f56e3ef5ba4149e7452dcf89d5a8" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.4", "block2 0.5.1", "libc", "objc2 0.5.2", @@ -4023,10 +4141,10 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "900831247d2fe1a09a683278e5384cfb8c80c79fe6b166f9d14bfdde0ea1b03c" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.4", "block2 0.6.1", "libc", - "objc2 0.6.1", + "objc2 0.6.2", "objc2-core-foundation", ] @@ -4046,8 +4164,18 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7282e9ac92529fa3457ce90ebb15f4ecbc383e8338060960760fa2cf75420c3c" dependencies = [ - "bitflags 2.9.0", - "objc2 0.6.1", + "bitflags 2.9.4", + "objc2 0.6.2", + "objc2-core-foundation", +] + +[[package]] +name = "objc2-javascript-core" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9052cb1bb50a4c161d934befcf879526fb87ae9a68858f241e693ca46225cf5a" +dependencies = [ + "objc2 0.6.2", "objc2-core-foundation", ] @@ -4057,7 +4185,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd0cba1276f6023976a406a14ffa85e1fdd19df6b0f737b063b95f6c8c7aadd6" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.4", "block2 0.5.1", "objc2 0.5.2", "objc2-foundation 0.2.2", @@ -4069,8 +4197,8 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f246c183239540aab1782457b35ab2040d4259175bd1d0c58e46ada7b47a874" dependencies = [ - "bitflags 2.9.0", - "objc2 0.6.1", + "bitflags 2.9.4", + "objc2 0.6.2", "objc2-foundation 0.3.1", ] @@ -4080,8 +4208,8 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "26bb88504b5a050dbba515d2414607bf5e57dd56b107bc5f0351197a3e7bdc5d" dependencies = [ - "bitflags 2.9.0", - "objc2 0.6.1", + "bitflags 2.9.4", + "objc2 0.6.2", "objc2-app-kit 0.3.1", "objc2-foundation 0.3.1", ] @@ -4092,7 +4220,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e42bee7bff906b14b167da2bac5efe6b6a07e6f7c0a21a7308d40c960242dc7a" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.4", "block2 0.5.1", "objc2 0.5.2", "objc2-foundation 0.2.2", @@ -4105,19 +4233,30 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "90ffb6a0cd5f182dc964334388560b12a57f7b74b3e2dec5e2722aa2dfb2ccd5" dependencies = [ - "bitflags 2.9.0", - "objc2 0.6.1", + "bitflags 2.9.4", + "objc2 0.6.2", "objc2-foundation 0.3.1", ] +[[package]] +name = "objc2-security" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1f8e0ef3ab66b08c42644dcb34dba6ec0a574bbd8adbb8bdbdc7a2779731a44" +dependencies = [ + "bitflags 2.9.4", + "objc2 0.6.2", + "objc2-core-foundation", +] + [[package]] name = "objc2-ui-kit" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "25b1312ad7bc8a0e92adae17aa10f90aae1fb618832f9b993b022b591027daed" dependencies = [ - "bitflags 2.9.0", - "objc2 0.6.1", + "bitflags 2.9.4", + "objc2 0.6.2", "objc2-core-foundation", "objc2-foundation 0.3.1", ] @@ -4128,12 +4267,14 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "91672909de8b1ce1c2252e95bbee8c1649c9ad9d14b9248b3d7b4c47903c47ad" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.4", "block2 0.6.1", - "objc2 0.6.1", + "objc2 0.6.2", "objc2-app-kit 0.3.1", "objc2-core-foundation", "objc2-foundation 0.3.1", + "objc2-javascript-core", + "objc2-security", ] [[package]] @@ -4160,6 +4301,12 @@ version = "1.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" +[[package]] +name = "oneshot" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4ce411919553d3f9fa53a0880544cda985a112117a0444d5ff1e870a893d6ea" + [[package]] name = "open" version = "5.3.2" @@ -4174,11 +4321,11 @@ dependencies = [ [[package]] name = "openssl" -version = "0.10.72" +version = "0.10.73" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fedfea7d58a1f73118430a55da6a286e7b044961736ce96a16a17068ea25e5da" +checksum = "8505734d46c8ab1e19a1dce3aef597ad87dcb4c37e7188231769bd6bd51cebf8" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.4", "cfg-if", "foreign-types 0.3.2", "libc", @@ -4195,7 +4342,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.106", ] [[package]] @@ -4206,9 +4353,9 @@ checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" [[package]] name = "openssl-sys" -version = "0.9.108" +version = "0.9.109" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e145e1651e858e820e4860f7b9c5e169bc1d8ce1c86043be79fa7b7634821847" +checksum = "90096e2e47630d78b7d1c20952dc621f957103f8bc2c8359ec81290d75238571" dependencies = [ "cc", "libc", @@ -4253,20 +4400,21 @@ dependencies = [ [[package]] name = "os_info" -version = "3.10.0" +version = "3.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a604e53c24761286860eba4e2c8b23a0161526476b1de520139d69cdb85a6b5" +checksum = "d0e1ac5fde8d43c34139135df8ea9ee9465394b2d8d20f032d38998f64afffc3" dependencies = [ "log", + "plist", "serde", "windows-sys 0.52.0", ] [[package]] name = "os_pipe" -version = "1.2.1" +version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ffd2b0a5634335b135d5728d84c5e0fd726954b87111f7506a61c502280d982" +checksum = "db335f4760b14ead6290116f2427bf33a14d4f0617d49f78a246de10c1831224" dependencies = [ "libc", "windows-sys 0.59.0", @@ -4278,12 +4426,12 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "732c71caeaa72c065bb69d7ea08717bd3f4863a4f451402fc9513e29dbd5261b" dependencies = [ - "objc2 0.6.1", + "objc2 0.6.2", "objc2-foundation 0.3.1", "objc2-osa-kit", "serde", "serde_json", - "thiserror 2.0.12", + "thiserror 2.0.16", ] [[package]] @@ -4319,9 +4467,9 @@ checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" [[package]] name = "parking_lot" -version = "0.12.3" +version = "0.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" +checksum = "70d58bf43669b5795d1576d0641cfb6fbb2057bf629506267a92807158584a13" dependencies = [ "lock_api", "parking_lot_core", @@ -4329,9 +4477,9 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.10" +version = "0.9.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" +checksum = "bc838d2a56b5b1a6c25f55575dfc605fabb63bb2365f6c2353ef9159aa69e4a5" dependencies = [ "cfg-if", "libc", @@ -4377,9 +4525,9 @@ dependencies = [ [[package]] name = "percent-encoding" -version = "2.3.1" +version = "2.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" +checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" [[package]] name = "phf" @@ -4387,9 +4535,7 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3dfb61232e34fcb633f43d12c58f83c1df82962dcdfa565a4e866ffc17dafe12" dependencies = [ - "phf_macros 0.8.0", "phf_shared 0.8.0", - "proc-macro-hack", ] [[package]] @@ -4398,7 +4544,9 @@ version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fabbf1ead8a5bcbc20f5f8b939ee3f5b0f6f281b6ad3468b84656b658b455259" dependencies = [ + "phf_macros 0.10.0", "phf_shared 0.10.0", + "proc-macro-hack", ] [[package]] @@ -4423,12 +4571,12 @@ dependencies = [ [[package]] name = "phf_codegen" -version = "0.10.0" +version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fb1c3a8bc4dd4e5cfce29b44ffc14bedd2ee294559a294e2a4d4c9e9a6a13cd" +checksum = "aef8048c789fa5e851558d709946d6d79a8ff88c0440c587967f8e94bfb1216a" dependencies = [ - "phf_generator 0.10.0", - "phf_shared 0.10.0", + "phf_generator 0.11.3", + "phf_shared 0.11.3", ] [[package]] @@ -4463,12 +4611,12 @@ dependencies = [ [[package]] name = "phf_macros" -version = "0.8.0" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f6fde18ff429ffc8fe78e2bf7f8b7a5a5a6e2a8b58bc5a9ac69198bbda9189c" +checksum = "58fdf3184dd560f160dd73922bea2d5cd6e8f064bf4b13110abd81b03697b4e0" dependencies = [ - "phf_generator 0.8.0", - "phf_shared 0.8.0", + "phf_generator 0.10.0", + "phf_shared 0.10.0", "proc-macro-hack", "proc-macro2", "quote", @@ -4485,7 +4633,7 @@ dependencies = [ "phf_shared 0.11.3", "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.106", ] [[package]] @@ -4564,13 +4712,13 @@ checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" [[package]] name = "plist" -version = "1.7.1" +version = "1.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eac26e981c03a6e53e0aee43c113e3202f5581d5360dae7bd2c70e800dd0451d" +checksum = "3af6b589e163c5a788fab00ce0c0366f6efbb9959c2f9874b224936af7fce7e1" dependencies = [ "base64 0.22.1", - "indexmap 2.10.0", - "quick-xml 0.32.0", + "indexmap 2.11.0", + "quick-xml 0.38.3", "serde", "time", ] @@ -4589,25 +4737,37 @@ dependencies = [ ] [[package]] -name = "polling" -version = "3.7.4" +name = "png" +version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a604568c3202727d1507653cb121dbd627a58684eb09a820fd746bee38b4442f" +checksum = "97baced388464909d42d89643fe4361939af9b7ce7a31ee32a168f832a70f2a0" +dependencies = [ + "bitflags 2.9.4", + "crc32fast", + "fdeflate", + "flate2", + "miniz_oxide", +] + +[[package]] +name = "polling" +version = "3.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5bd19146350fe804f7cb2669c851c03d69da628803dab0d98018142aaa5d829" dependencies = [ "cfg-if", "concurrent-queue", "hermit-abi", "pin-project-lite", - "rustix 0.38.44", - "tracing", - "windows-sys 0.59.0", + "rustix", + "windows-sys 0.60.2", ] [[package]] name = "potential_utf" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5a7c30837279ca13e7c867e9e40053bc68740f988cb07f7ca6df43cc734b585" +checksum = "84df19adbe5b5a0782edcab45899906947ab039ccf4573713735ee7de1e6b08a" dependencies = [ "zerovec", ] @@ -4618,6 +4778,12 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" +[[package]] +name = "ppmd-rust" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c834641d8ad1b348c9ee86dec3b9840d805acd5f24daa5f90c788951a52ff59b" + [[package]] name = "ppv-lite86" version = "0.2.21" @@ -4658,7 +4824,7 @@ version = "3.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "edce586971a4dfaa28950c6f18ed55e0406c1ab88bbce2c6f6293a7aaba73d35" dependencies = [ - "toml_edit 0.22.26", + "toml_edit 0.22.27", ] [[package]] @@ -4693,30 +4859,30 @@ checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068" [[package]] name = "proc-macro2" -version = "1.0.95" +version = "1.0.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" +checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de" dependencies = [ "unicode-ident", ] [[package]] name = "profiling" -version = "1.0.16" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afbdc74edc00b6f6a218ca6a5364d6226a259d4b8ea1af4a0ea063f27e179f4d" +checksum = "3eb8486b569e12e2c32ad3e204dbaba5e4b5b216e9367044f25f1dba42341773" dependencies = [ "profiling-procmacros", ] [[package]] name = "profiling-procmacros" -version = "1.0.16" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a65f2e60fbf1063868558d69c6beacf412dc755f9fc020f514b7955fc914fe30" +checksum = "52717f9a02b6965224f95ca2a81e2e0c5c43baacd28ca057577988930b6c3d5b" dependencies = [ "quote", - "syn 2.0.101", + "syn 2.0.106", ] [[package]] @@ -4755,6 +4921,15 @@ dependencies = [ "psl-types", ] +[[package]] +name = "pxfm" +version = "0.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e790881194f6f6e86945f0a42a6981977323669aeb6c40e9c7ec253133b96f8" +dependencies = [ + "num-traits", +] + [[package]] name = "qoi" version = "0.4.1" @@ -4781,18 +4956,27 @@ dependencies = [ [[package]] name = "quick-xml" -version = "0.32.0" +version = "0.37.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d3a6e5838b60e0e8fa7a43f22ade549a37d61f8bdbe636d0d7816191de969c2" +checksum = "331e97a1af0bf59823e6eadffe373d7b27f485be8748f71471c662c1f269b7fb" +dependencies = [ + "memchr", +] + +[[package]] +name = "quick-xml" +version = "0.38.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42a232e7487fc2ef313d96dde7948e7a3c05101870d8985e4fd8d26aedd27b89" dependencies = [ "memchr", ] [[package]] name = "quinn" -version = "0.11.7" +version = "0.11.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3bd15a6f2967aef83887dcb9fec0014580467e33720d073560cf015a5683012" +checksum = "b9e20a958963c291dc322d98411f541009df2ced7b5a4f2bd52337638cfccf20" dependencies = [ "bytes", "cfg_aliases", @@ -4802,7 +4986,7 @@ dependencies = [ "rustc-hash", "rustls", "socket2", - "thiserror 2.0.12", + "thiserror 2.0.16", "tokio", "tracing", "web-time", @@ -4810,19 +4994,20 @@ dependencies = [ [[package]] name = "quinn-proto" -version = "0.11.11" +version = "0.11.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcbafbbdbb0f638fe3f35f3c56739f77a8a1d070cb25603226c83339b391472b" +checksum = "f1906b49b0c3bc04b5fe5d86a77925ae6524a19b816ae38ce1e426255f1d8a31" dependencies = [ "bytes", - "getrandom 0.3.2", - "rand 0.9.1", + "getrandom 0.3.3", + "lru-slab", + "rand 0.9.2", "ring", "rustc-hash", "rustls", "rustls-pki-types", "slab", - "thiserror 2.0.12", + "thiserror 2.0.16", "tinyvec", "tracing", "web-time", @@ -4830,16 +5015,16 @@ dependencies = [ [[package]] name = "quinn-udp" -version = "0.5.12" +version = "0.5.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee4e529991f949c5e25755532370b8af5d114acae52326361d68d47af64aa842" +checksum = "addec6a0dcad8a8d96a771f815f0eaf55f9d1805756410b39f5fa81332574cbd" dependencies = [ "cfg_aliases", "libc", "once_cell", "socket2", "tracing", - "windows-sys 0.59.0", + "windows-sys 0.60.2", ] [[package]] @@ -4853,9 +5038,9 @@ dependencies = [ [[package]] name = "r-efi" -version = "5.2.0" +version = "5.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" [[package]] name = "radium" @@ -4890,9 +5075,9 @@ dependencies = [ [[package]] name = "rand" -version = "0.9.1" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fbfd9d094a40bf3ae768db9361049ace4c0e04a4fd6b359518bd7b73a73dd97" +checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" dependencies = [ "rand_chacha 0.9.0", "rand_core 0.9.3", @@ -4952,7 +5137,7 @@ version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" dependencies = [ - "getrandom 0.3.2", + "getrandom 0.3.3", ] [[package]] @@ -5010,9 +5195,9 @@ dependencies = [ [[package]] name = "ravif" -version = "0.11.12" +version = "0.11.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6a5f31fcf7500f9401fea858ea4ab5525c99f2322cfcee732c0e6c74208c0c6" +checksum = "5825c26fddd16ab9f515930d49028a630efec172e903483c94796cfe31893e6b" dependencies = [ "avif-serialize", "imgref", @@ -5031,9 +5216,9 @@ checksum = "20675572f6f24e9e76ef639bc5552774ed45f1c30e2951e1e99c59888861c539" [[package]] name = "rayon" -version = "1.10.0" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" +checksum = "368f01d005bf8fd9b1206fb6fa653e6c4a81ceb1466406b81792d87c5677a58f" dependencies = [ "either", "rayon-core", @@ -5041,9 +5226,9 @@ dependencies = [ [[package]] name = "rayon-core" -version = "1.12.1" +version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" +checksum = "22e18b0f0062d30d4230b2e85ff77fdfe4326feb054b9783a3460d8435c8ab91" dependencies = [ "crossbeam-deque", "crossbeam-utils", @@ -5051,11 +5236,11 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.5.12" +version = "0.5.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "928fca9cf2aa042393a8325b9ead81d2f0df4cb12e1e24cef072922ccd99c5af" +checksum = "5407465600fb0548f1442edf71dd20683c6ed326200ace4b1ef0763521bb3b77" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.4", ] [[package]] @@ -5071,20 +5256,40 @@ dependencies = [ [[package]] name = "redox_users" -version = "0.5.0" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd6f9d3d47bdd2ad6945c5015a226ec6155d0bcdfd8f7cd29f86b71f8de99d2b" +checksum = "a4e608c6638b9c18977b00b475ac1f28d14e84b27d8d42f70e0bf1e3dec127ac" dependencies = [ "getrandom 0.2.16", "libredox", - "thiserror 2.0.12", + "thiserror 2.0.16", +] + +[[package]] +name = "ref-cast" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a0ae411dbe946a674d89546582cea4ba2bb8defac896622d6496f14c23ba5cf" +dependencies = [ + "ref-cast-impl", +] + +[[package]] +name = "ref-cast-impl" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1165225c21bff1f3bbce98f5a1f889949bc902d3575308cc7b0de30b4f6d27c7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", ] [[package]] name = "regex" -version = "1.11.1" +version = "1.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" +checksum = "23d7fd106d8c02486a8d64e778353d1cffe08ce79ac2e82f540c86d0facf6912" dependencies = [ "aho-corasick", "memchr", @@ -5094,9 +5299,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.9" +version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" +checksum = "6b9458fa0bfeeac22b5ca447c63aaf45f28439a709ccd244698632f9aa6394d6" dependencies = [ "aho-corasick", "memchr", @@ -5105,9 +5310,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.8.5" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" +checksum = "caf4aa5b0f434c91fe5c7f1ecb6a5ece2130b02ad2a590589dda5146df959001" [[package]] name = "rend" @@ -5120,9 +5325,9 @@ dependencies = [ [[package]] name = "reqwest" -version = "0.12.15" +version = "0.12.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d19c46a6fdd48bc4dab94b6103fccc55d34c67cc0ad04653aad4ea2a07cd7bbb" +checksum = "d429f34c8092b2d42c7c93cec323bb4adeb7c67698f70839adec842ec10c7ceb" dependencies = [ "base64 0.22.1", "bytes", @@ -5135,58 +5340,54 @@ dependencies = [ "http 1.3.1", "http-body 1.0.1", "http-body-util", - "hyper 1.6.0", + "hyper 1.7.0", "hyper-rustls", "hyper-tls", "hyper-util", - "ipnet", "js-sys", "log", "mime", "mime_guess", "native-tls", - "once_cell", "percent-encoding", "pin-project-lite", "quinn", "rustls", - "rustls-pemfile", "rustls-pki-types", "serde", "serde_json", "serde_urlencoded", "sync_wrapper", - "system-configuration", "tokio", "tokio-native-tls", "tokio-rustls", "tokio-util", "tower", + "tower-http", "tower-service", "url", "wasm-bindgen", "wasm-bindgen-futures", "wasm-streams", "web-sys", - "webpki-roots 0.26.11", - "windows-registry 0.4.0", + "webpki-roots", ] [[package]] name = "rfd" -version = "0.15.3" +version = "0.15.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80c844748fdc82aae252ee4594a89b6e7ebef1063de7951545564cbc4e57075d" +checksum = "ef2bee61e6cffa4635c72d7d81a84294e28f0930db0ddcb0f66d10244674ebed" dependencies = [ "ashpd", "block2 0.6.1", - "dispatch2 0.2.0", + "dispatch2", "glib-sys 0.18.1", "gobject-sys 0.18.0", "gtk-sys", "js-sys", "log", - "objc2 0.6.1", + "objc2 0.6.2", "objc2-app-kit 0.3.1", "objc2-core-foundation", "objc2-foundation 0.3.1", @@ -5199,9 +5400,9 @@ dependencies = [ [[package]] name = "rgb" -version = "0.8.50" +version = "0.8.52" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57397d16646700483b67d2dd6511d79318f9d057fdbd21a4066aeac8b41d310a" +checksum = "0c6a884d2998352bb4daf0183589aec883f16a6da1f4dde84d8e2e9a5409a1ce" [[package]] name = "ring" @@ -5248,20 +5449,19 @@ dependencies = [ [[package]] name = "rust-ini" -version = "0.21.1" +version = "0.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e310ef0e1b6eeb79169a1171daf9abcb87a2e17c03bee2c4bb100b55c75409f" +checksum = "796e8d2b6696392a43bea58116b667fb4c29727dc5abd27d6acf338bb4f688c7" dependencies = [ "cfg-if", "ordered-multimap", - "trim-in-place", ] [[package]] name = "rust_decimal" -version = "1.37.1" +version = "1.37.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "faa7de2ba56ac291bd90c6b9bece784a52ae1411f9506544b3eae36dd2356d50" +checksum = "b203a6425500a03e0919c42d3c47caca51e79f1132046626d2c8871c5092035d" dependencies = [ "arrayvec", "borsh", @@ -5275,9 +5475,9 @@ dependencies = [ [[package]] name = "rustc-demangle" -version = "0.1.24" +version = "0.1.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" +checksum = "56f7d92ca342cea22a06f2121d944b4fd82af56988c270852495420f961d4ace" [[package]] name = "rustc-hash" @@ -5296,35 +5496,22 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.44" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" +checksum = "11181fbabf243db407ef8df94a6ce0b2f9a733bd8be4ad02b4eda9602296cac8" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.4", "errno", "libc", - "linux-raw-sys 0.4.15", - "windows-sys 0.59.0", -] - -[[package]] -name = "rustix" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c71e83d6afe7ff64890ec6b71d6a69bb8a610ab78ce364b3352876bb4c801266" -dependencies = [ - "bitflags 2.9.0", - "errno", - "libc", - "linux-raw-sys 0.9.4", - "windows-sys 0.59.0", + "linux-raw-sys", + "windows-sys 0.60.2", ] [[package]] name = "rustls" -version = "0.23.27" +version = "0.23.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "730944ca083c1c233a75c09f199e973ca499344a2b7ba9e755c457e86fb4a321" +checksum = "c0ebcbd2f03de0fc1122ad9bb24b127a5a6cd51d72604a3f3c50ac459762b6cc" dependencies = [ "once_cell", "ring", @@ -5334,15 +5521,6 @@ dependencies = [ "zeroize", ] -[[package]] -name = "rustls-pemfile" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50" -dependencies = [ - "rustls-pki-types", -] - [[package]] name = "rustls-pki-types" version = "1.12.0" @@ -5355,9 +5533,9 @@ dependencies = [ [[package]] name = "rustls-webpki" -version = "0.103.2" +version = "0.103.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7149975849f1abb3832b246010ef62ccc80d3a76169517ada7188252b9cfb437" +checksum = "0a17884ae0c1b773f1ccd2bd4a8c72f16da897310a98b0e84bf349ad5ead92fc" dependencies = [ "ring", "rustls-pki-types", @@ -5366,9 +5544,9 @@ dependencies = [ [[package]] name = "rustversion" -version = "1.0.20" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eded382c5f5f786b989652c49544c4877d9f015cc22e145a5ea8ea66c2921cd2" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" [[package]] name = "ryu" @@ -5409,6 +5587,30 @@ dependencies = [ "uuid", ] +[[package]] +name = "schemars" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cd191f9397d57d581cddd31014772520aa448f65ef991055d7f61582c65165f" +dependencies = [ + "dyn-clone", + "ref-cast", + "serde", + "serde_json", +] + +[[package]] +name = "schemars" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82d20c4491bc164fa2f6c5d44565947a52ad80b9505d8e36f8d54c27c739fcd0" +dependencies = [ + "dyn-clone", + "ref-cast", + "serde", + "serde_json", +] + [[package]] name = "schemars_derive" version = "0.8.22" @@ -5418,9 +5620,15 @@ dependencies = [ "proc-macro2", "quote", "serde_derive_internals", - "syn 2.0.101", + "syn 2.0.106", ] +[[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" @@ -5439,7 +5647,7 @@ version = "2.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.4", "core-foundation 0.9.4", "core-foundation-sys", "libc", @@ -5458,22 +5666,20 @@ dependencies = [ [[package]] name = "selectors" -version = "0.22.0" +version = "0.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df320f1889ac4ba6bc0cdc9c9af7af4bd64bb927bccdf32d81140dc1f9be12fe" +checksum = "0c37578180969d00692904465fb7f6b3d50b9a2b952b87c23d0e2e5cb5013416" dependencies = [ "bitflags 1.3.2", "cssparser", "derive_more 0.99.20", "fxhash", "log", - "matches", "phf 0.8.0", "phf_codegen 0.8.0", "precomputed-hash", "servo_arc", "smallvec", - "thin-slice", ] [[package]] @@ -5496,9 +5702,9 @@ dependencies = [ [[package]] name = "serde-untagged" -version = "0.1.7" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "299d9c19d7d466db4ab10addd5703e4c615dec2a5a16dbbafe191045e87ee66e" +checksum = "34836a629bcbc6f1afdf0907a744870039b1e14c0561cb26094fa683b158eff3" dependencies = [ "erased-serde", "serde", @@ -5513,7 +5719,7 @@ checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.106", ] [[package]] @@ -5524,17 +5730,17 @@ checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.106", ] [[package]] name = "serde_json" -version = "1.0.140" +version = "1.0.143" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373" +checksum = "d401abef1d108fbd9cbaebc3e46611f4b1021f714a0597a71f41ee463f5f4a5a" dependencies = [ - "indexmap 2.10.0", - "itoa 1.0.15", + "indexmap 2.11.0", + "itoa", "memchr", "ryu", "serde", @@ -5557,14 +5763,23 @@ checksum = "175ee3e80ae9982737ca543e96133087cbd9a485eecc3bc4de9c1a37b47ea59c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.106", ] [[package]] name = "serde_spanned" -version = "0.6.8" +version = "0.6.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1" +checksum = "bf41e0cfaf7226dca15e8197172c295a782857fcb97fad1808a166870dee75a3" +dependencies = [ + "serde", +] + +[[package]] +name = "serde_spanned" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40734c41988f7306bb04f0ecf60ec0f3f1caa34290e4e8ea471dcd3346483b83" dependencies = [ "serde", ] @@ -5576,22 +5791,24 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" dependencies = [ "form_urlencoded", - "itoa 1.0.15", + "itoa", "ryu", "serde", ] [[package]] name = "serde_with" -version = "3.12.0" +version = "3.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6b6f7f2fcb69f747921f79f3926bd1e203fce4fef62c268dd3abfb6d86029aa" +checksum = "f2c45cd61fefa9db6f254525d46e392b852e0e61d9a1fd36e5bd183450a556d5" dependencies = [ "base64 0.22.1", "chrono", "hex", "indexmap 1.9.3", - "indexmap 2.10.0", + "indexmap 2.11.0", + "schemars 0.9.0", + "schemars 1.0.4", "serde", "serde_derive", "serde_json", @@ -5601,21 +5818,21 @@ dependencies = [ [[package]] name = "serde_with_macros" -version = "3.12.0" +version = "3.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d00caa5193a3c8362ac2b73be6b9e768aa5a4b2f721d8f4b339600c3cb51f8e" +checksum = "de90945e6565ce0d9a25098082ed4ee4002e047cb59892c318d66821e14bb30f" dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.106", ] [[package]] name = "serialize-to-javascript" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9823f2d3b6a81d98228151fdeaf848206a7855a7a042bbf9bf870449a66cafb" +checksum = "04f3666a07a197cdb77cdf306c32be9b7f598d7060d50cfd4d5aa04bfd92f6c5" dependencies = [ "serde", "serde_json", @@ -5624,20 +5841,20 @@ dependencies = [ [[package]] name = "serialize-to-javascript-impl" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74064874e9f6a15f04c1f3cb627902d0e6b410abbf36668afa873c61889f1763" +checksum = "772ee033c0916d670af7860b6e1ef7d658a4629a6d0b4c8c3e67f09b3765b75d" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.106", ] [[package]] name = "servo_arc" -version = "0.1.1" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d98238b800e0d1576d8b6e3de32827c2d74bee68bb97748dcf5071fb53965432" +checksum = "d52aa42f8fdf0fed91e5ce7f23d8138441002fa31dca008acf47e6fd4721f741" dependencies = [ "nodrop", "stable_deref_trait", @@ -5667,12 +5884,13 @@ dependencies = [ [[package]] name = "shared_child" -version = "1.0.2" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e297bd52991bbe0686c086957bee142f13df85d1e79b0b21630a99d374ae9dc" +checksum = "1e362d9935bc50f019969e2f9ecd66786612daae13e8f277be7bfb66e8bed3f7" dependencies = [ "libc", - "windows-sys 0.59.0", + "sigchld", + "windows-sys 0.60.2", ] [[package]] @@ -5682,10 +5900,31 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" [[package]] -name = "signal-hook-registry" -version = "1.4.5" +name = "sigchld" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9203b8055f63a2a00e2f593bb0510367fe707d7ff1e5c872de2f537b339e5410" +checksum = "47106eded3c154e70176fc83df9737335c94ce22f821c32d17ed1db1f83badb1" +dependencies = [ + "libc", + "os_pipe", + "signal-hook", +] + +[[package]] +name = "signal-hook" +version = "0.3.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d881a16cf4426aa584979d30bd82cb33429027e42122b169753d6ef1085ed6e2" +dependencies = [ + "libc", + "signal-hook-registry", +] + +[[package]] +name = "signal-hook-registry" +version = "1.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2a4719bff48cee6b39d12c020eeb490953ad2443b7055bd0b21fca26bd8c28b" dependencies = [ "libc", ] @@ -5725,27 +5964,24 @@ checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d" [[package]] name = "slab" -version = "0.4.9" +version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" -dependencies = [ - "autocfg", -] +checksum = "7a2ae44ef20feb57a68b23d846850f861394c2e02dc425a50098ae8c90267589" [[package]] name = "smallvec" -version = "1.15.0" +version = "1.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8917285742e9f3e1683f0a9c4e6b57960b7314d0b08d30d1ecd426713ee2eee9" +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" [[package]] name = "socket2" -version = "0.5.9" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f5fd57c80058a56cf5c777ab8a126398ece8e442983605d280a44ce79d0edef" +checksum = "233504af464074f9d066d7b5416c5f9b894a5862a6506e306f7b816cdd6f1807" dependencies = [ "libc", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -5863,7 +6099,7 @@ dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.106", ] [[package]] @@ -5896,9 +6132,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.101" +version = "2.0.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ce2b7fc941b3a24138a0a7cf8e858bfc6a992e7978a068a5c760deb0ed43caf" +checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6" dependencies = [ "proc-macro2", "quote", @@ -5922,7 +6158,7 @@ checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.106", ] [[package]] @@ -5954,7 +6190,7 @@ version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.4", "core-foundation 0.9.4", "system-configuration-sys", ] @@ -5978,31 +6214,32 @@ dependencies = [ "cfg-expr 0.15.8", "heck 0.5.0", "pkg-config", - "toml", + "toml 0.8.23", "version-compare", ] [[package]] name = "system-deps" -version = "7.0.3" +version = "7.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66d23aaf9f331227789a99e8de4c91bf46703add012bdfd45fdecdfb2975a005" +checksum = "e4be53aa0cba896d2dc615bd42bbc130acdcffa239e0a2d965ea5b3b2a86ffdb" dependencies = [ - "cfg-expr 0.17.2", + "cfg-expr 0.20.2", "heck 0.5.0", "pkg-config", - "toml", + "toml 0.8.23", "version-compare", ] [[package]] name = "tao" -version = "0.33.0" +version = "0.34.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e59c1f38e657351a2e822eadf40d6a2ad4627b9c25557bc1180ec1b3295ef82" +checksum = "959469667dbcea91e5485fc48ba7dd6023face91bb0f1a14681a70f99847c3f7" dependencies = [ - "bitflags 2.9.0", - "core-foundation 0.10.0", + "bitflags 2.9.4", + "block2 0.6.1", + "core-foundation 0.10.1", "core-graphics 0.24.0", "crossbeam-channel", "dispatch", @@ -6018,7 +6255,7 @@ dependencies = [ "ndk", "ndk-context", "ndk-sys", - "objc2 0.6.1", + "objc2 0.6.2", "objc2-app-kit 0.3.1", "objc2-foundation 0.3.1", "once_cell", @@ -6042,7 +6279,7 @@ checksum = "f4e16beb8b2ac17db28eab8bca40e62dbfbb34c0fcdc6d9826b11b7b5d047dfd" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.106", ] [[package]] @@ -6069,18 +6306,24 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1" [[package]] -name = "tauri" -version = "2.5.1" +name = "target-lexicon" +version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7b0bc1aec81bda6bc455ea98fcaed26b3c98c1648c627ad6ff1c704e8bf8cbc" +checksum = "e502f78cdbb8ba4718f566c418c52bc729126ffd16baee5baa718cf25dd5a69a" + +[[package]] +name = "tauri" +version = "2.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4d1d3b3dc4c101ac989fd7db77e045cc6d91a25349cd410455cb5c57d510c1c" dependencies = [ "anyhow", "bytes", + "cookie", "dirs 6.0.0", "dunce", "embed_plist", - "futures-util", - "getrandom 0.2.16", + "getrandom 0.3.3", "glob", "gtk", "heck 0.5.0", @@ -6092,10 +6335,11 @@ dependencies = [ "log", "mime", "muda", - "objc2 0.6.1", + "objc2 0.6.2", "objc2-app-kit 0.3.1", "objc2-foundation 0.3.1", "objc2-ui-kit", + "objc2-web-kit", "percent-encoding", "plist", "raw-window-handle", @@ -6110,7 +6354,7 @@ dependencies = [ "tauri-runtime", "tauri-runtime-wry", "tauri-utils", - "thiserror 2.0.12", + "thiserror 2.0.16", "tokio", "tray-icon", "url", @@ -6123,9 +6367,9 @@ dependencies = [ [[package]] name = "tauri-build" -version = "2.2.0" +version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7a0350f0df1db385ca5c02888a83e0e66655c245b7443db8b78a70da7d7f8fc" +checksum = "9c432ccc9ff661803dab74c6cd78de11026a578a9307610bbc39d3c55be7943f" dependencies = [ "anyhow", "cargo_toml", @@ -6133,37 +6377,37 @@ dependencies = [ "glob", "heck 0.5.0", "json-patch", - "schemars", + "schemars 0.8.22", "semver", "serde", "serde_json", "tauri-utils", "tauri-winres", - "toml", + "toml 0.9.5", "walkdir", ] [[package]] name = "tauri-codegen" -version = "2.2.0" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f93f035551bf7b11b3f51ad9bc231ebbe5e085565527991c16cf326aa38cdf47" +checksum = "1ab3a62cf2e6253936a8b267c2e95839674e7439f104fa96ad0025e149d54d8a" dependencies = [ "base64 0.22.1", "brotli", "ico", "json-patch", "plist", - "png", + "png 0.17.16", "proc-macro2", "quote", "semver", "serde", "serde_json", "sha2", - "syn 2.0.101", + "syn 2.0.106", "tauri-utils", - "thiserror 2.0.12", + "thiserror 2.0.16", "time", "url", "uuid", @@ -6177,19 +6421,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "03b7eb4d0d43724ba9ba6a6717420ee68aee377816a3edbb45db8c18862b1431" dependencies = [ "byteorder", - "png", + "png 0.17.16", ] [[package]] name = "tauri-macros" -version = "2.2.0" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8db4df25e2d9d45de0c4c910da61cd5500190da14ae4830749fee3466dddd112" +checksum = "4368ea8094e7045217edb690f493b55b30caf9f3e61f79b4c24b6db91f07995e" dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.106", "tauri-codegen", "tauri-utils", ] @@ -6199,10 +6443,10 @@ name = "tauri-nspanel" version = "2.0.1" source = "git+https://github.com/ahkohd/tauri-nspanel?branch=v2#18ffb9a201fbf6fedfaa382fd4b92315ea30ab1a" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.4", "block", "cocoa", - "core-foundation 0.10.0", + "core-foundation 0.10.1", "core-graphics 0.25.0", "objc", "objc-foundation", @@ -6212,60 +6456,61 @@ dependencies = [ [[package]] name = "tauri-plugin" -version = "2.2.0" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37a5ebe6a610d1b78a94650896e6f7c9796323f408800cef436e0fa0539de601" +checksum = "9946a3cede302eac0c6eb6c6070ac47b1768e326092d32efbb91f21ed58d978f" dependencies = [ "anyhow", "glob", "plist", - "schemars", + "schemars 0.8.22", "serde", "serde_json", "tauri-utils", - "toml", + "toml 0.9.5", "walkdir", ] [[package]] name = "tauri-plugin-autostart" -version = "2.3.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c58593aafcb03892dbf9998b35a96ead3b8e597435c7af46aff1654d076d5d03" +checksum = "062cdcd483d5e3148c9a64dabf8c574e239e2aa1193cf208d95cf89a676f87a5" dependencies = [ "auto-launch", "serde", "serde_json", "tauri", "tauri-plugin", - "thiserror 2.0.12", + "thiserror 2.0.16", ] [[package]] name = "tauri-plugin-deep-link" -version = "2.2.1" +version = "2.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dba4412f30eaff6f5d210e20383c2d6835593977402092e95b72497a4f8632fa" +checksum = "cd67112fb1131834c2a7398ffcba520dbbf62c17de3b10329acd1a3554b1a9bb" dependencies = [ "dunce", + "plist", "rust-ini", "serde", "serde_json", "tauri", "tauri-plugin", "tauri-utils", - "thiserror 2.0.12", + "thiserror 2.0.16", "tracing", "url", - "windows-registry 0.5.1", + "windows-registry", "windows-result 0.3.4", ] [[package]] name = "tauri-plugin-dialog" -version = "2.2.1" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcaf6e5d6062423a0f711a23c2a573ccba222b6a16a9322d8499928f27e41376" +checksum = "0beee42a4002bc695550599b011728d9dfabf82f767f134754ed6655e434824e" dependencies = [ "log", "raw-window-handle", @@ -6275,7 +6520,7 @@ dependencies = [ "tauri", "tauri-plugin", "tauri-plugin-fs", - "thiserror 2.0.12", + "thiserror 2.0.16", "url", ] @@ -6296,25 +6541,24 @@ dependencies = [ [[package]] name = "tauri-plugin-fs" -version = "2.2.1" +version = "2.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88371e340ad2f07409a3b68294abe73f20bc9c1bc1b631a31dc37a3d0161f682" +checksum = "315784ec4be45e90a987687bae7235e6be3d6e9e350d2b75c16b8a4bf22c1db7" dependencies = [ "anyhow", "dunce", "glob", "percent-encoding", - "schemars", + "schemars 0.8.22", "serde", "serde_json", "serde_repr", "tauri", "tauri-plugin", "tauri-utils", - "thiserror 2.0.12", - "toml", + "thiserror 2.0.16", + "toml 0.9.5", "url", - "uuid", ] [[package]] @@ -6331,14 +6575,14 @@ dependencies = [ "tar", "tauri", "tauri-plugin", - "thiserror 2.0.12", + "thiserror 2.0.16", ] [[package]] name = "tauri-plugin-global-shortcut" -version = "2.2.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00f646a09511e8d283267dcdaa08c2ef27c4116bf271d9114849d9ca215606c3" +checksum = "6df9f0f7bf2fe768b85fee4951c2505a35b72c44df1f6403e74e110bc13c5f58" dependencies = [ "global-hotkey", "log", @@ -6346,14 +6590,14 @@ dependencies = [ "serde_json", "tauri", "tauri-plugin", - "thiserror 2.0.12", + "thiserror 2.0.16", ] [[package]] name = "tauri-plugin-http" -version = "2.4.3" +version = "2.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40dcd6c922a1885e1f0bcebc6768fec6e005bd4b9001c5d90a2f5d4cab297729" +checksum = "938a3d7051c9a82b431e3a0f3468f85715b3442b3c3a3913095e9fa509e2652c" dependencies = [ "bytes", "cookie_store", @@ -6361,13 +6605,13 @@ dependencies = [ "http 1.3.1", "regex", "reqwest", - "schemars", + "schemars 0.8.22", "serde", "serde_json", "tauri", "tauri-plugin", "tauri-plugin-fs", - "thiserror 2.0.12", + "thiserror 2.0.16", "tokio", "url", "urlpattern", @@ -6375,15 +6619,15 @@ dependencies = [ [[package]] name = "tauri-plugin-log" -version = "2.4.0" +version = "2.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d2b582d860eb214f28323f4ce4f2797ae3b78f197e27b11677f976f9f52aedb" +checksum = "61c1438bc7662acd16d508c919b3c087efd63669a4c75625dff829b1c75975ec" dependencies = [ "android_logger", "byte-unit", "fern", "log", - "objc2 0.6.1", + "objc2 0.6.2", "objc2-foundation 0.3.1", "serde", "serde_json", @@ -6391,7 +6635,7 @@ dependencies = [ "swift-rs", "tauri", "tauri-plugin", - "thiserror 2.0.12", + "thiserror 2.0.16", "time", ] @@ -6402,31 +6646,31 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5607e0707d37d7b20e287cf0ce396d1efebe7b833b8e9cbd2ea4257091d9c604" dependencies = [ "macos-accessibility-client", - "objc2 0.6.1", + "objc2 0.6.2", "objc2-foundation 0.3.1", "serde", "tauri", "tauri-plugin", - "thiserror 2.0.12", + "thiserror 2.0.16", ] [[package]] name = "tauri-plugin-opener" -version = "2.2.7" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66644b71a31ec1a8a52c4a16575edd28cf763c87cf4a7da24c884122b5c77097" +checksum = "786156aa8e89e03d271fbd3fe642207da8e65f3c961baa9e2930f332bf80a1f5" dependencies = [ "dunce", "glob", "objc2-app-kit 0.3.1", "objc2-foundation 0.3.1", "open", - "schemars", + "schemars 0.8.22", "serde", "serde_json", "tauri", "tauri-plugin", - "thiserror 2.0.12", + "thiserror 2.0.16", "url", "windows 0.61.3", "zbus", @@ -6434,9 +6678,9 @@ dependencies = [ [[package]] name = "tauri-plugin-os" -version = "2.2.1" +version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "424f19432397850c2ddd42aa58078630c15287bbce3866eb1d90e7dbee680637" +checksum = "77a1c77ebf6f20417ab2a74e8c310820ba52151406d0c80fbcea7df232e3f6ba" dependencies = [ "gethostname", "log", @@ -6447,7 +6691,7 @@ dependencies = [ "sys-locale", "tauri", "tauri-plugin", - "thiserror 2.0.12", + "thiserror 2.0.16", ] [[package]] @@ -6456,20 +6700,20 @@ version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "20327367bca73bc4a08973592b0e6fe716321566207c52c79234876a5467c4ac" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.4", "itertools 0.14.0", "serde", "strum", "tauri", "tauri-plugin", - "thiserror 2.0.12", + "thiserror 2.0.16", ] [[package]] name = "tauri-plugin-process" -version = "2.2.1" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57da5888533e802b6206b9685091f8714aa1f5266dc80051a82388449558b773" +checksum = "7461c622a5ea00eb9cd9f7a08dbd3bf79484499fd5c21aa2964677f64ca651ab" dependencies = [ "tauri", "tauri-plugin", @@ -6484,59 +6728,59 @@ dependencies = [ "serde", "tauri", "tauri-plugin", - "thiserror 2.0.12", + "thiserror 2.0.16", "xcap", ] [[package]] name = "tauri-plugin-shell" -version = "2.2.1" +version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69d5eb3368b959937ad2aeaf6ef9a8f5d11e01ffe03629d3530707bbcb27ff5d" +checksum = "54777d0c0d8add34eea3ced84378619ef5b97996bd967d3038c668feefd21071" dependencies = [ "encoding_rs", "log", "open", "os_pipe", "regex", - "schemars", + "schemars 0.8.22", "serde", "serde_json", "shared_child", "tauri", "tauri-plugin", - "thiserror 2.0.12", + "thiserror 2.0.16", "tokio", ] [[package]] name = "tauri-plugin-single-instance" -version = "2.2.3" +version = "2.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1320af4d866a7fb5f5721d299d14d0dd9e4e6bc0359ff3e263124a2bf6814efa" +checksum = "fb9cac815bf11c4a80fb498666bcdad66d65b89e3ae24669e47806febb76389c" dependencies = [ "serde", "serde_json", "tauri", "tauri-plugin-deep-link", - "thiserror 2.0.12", + "thiserror 2.0.16", "tracing", - "windows-sys 0.59.0", + "windows-sys 0.60.2", "zbus", ] [[package]] name = "tauri-plugin-store" -version = "2.2.0" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c0c08fae6995909f5e9a0da6038273b750221319f2c0f3b526d6de1cde21505" +checksum = "d85dd80d60a76ee2c2fdce09e9ef30877b239c2a6bb76e6d7d03708aa5f13a19" dependencies = [ "dunce", "serde", "serde_json", "tauri", "tauri-plugin", - "thiserror 2.0.12", + "thiserror 2.0.16", "tokio", "tracing", ] @@ -6564,12 +6808,12 @@ dependencies = [ "tauri", "tauri-plugin", "tempfile", - "thiserror 2.0.12", + "thiserror 2.0.16", "time", "tokio", "url", "windows-sys 0.59.0", - "zip 2.6.1", + "zip 2.4.2", ] [[package]] @@ -6581,43 +6825,46 @@ dependencies = [ "serde", "tauri", "tauri-plugin", - "thiserror 2.0.12", + "thiserror 2.0.16", "windows-version", ] [[package]] name = "tauri-runtime" -version = "2.6.0" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00f004905d549854069e6774533d742b03cacfd6f03deb08940a8677586cbe39" +checksum = "d4cfc9ad45b487d3fded5a4731a567872a4812e9552e3964161b08edabf93846" dependencies = [ "cookie", "dpi", "gtk", "http 1.3.1", "jni", - "objc2 0.6.1", + "objc2 0.6.2", "objc2-ui-kit", + "objc2-web-kit", "raw-window-handle", "serde", "serde_json", "tauri-utils", - "thiserror 2.0.12", + "thiserror 2.0.16", "url", + "webkit2gtk", + "webview2-com", "windows 0.61.3", ] [[package]] name = "tauri-runtime-wry" -version = "2.6.0" +version = "2.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f85d056f4d4b014fe874814034f3416d57114b617a493a4fe552580851a3f3a2" +checksum = "c1fe9d48bd122ff002064e88cfcd7027090d789c4302714e68fcccba0f4b7807" dependencies = [ "gtk", "http 1.3.1", "jni", "log", - "objc2 0.6.1", + "objc2 0.6.2", "objc2-app-kit 0.3.1", "objc2-foundation 0.3.1", "once_cell", @@ -6636,9 +6883,9 @@ dependencies = [ [[package]] name = "tauri-utils" -version = "2.4.0" +version = "2.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2900399c239a471bcff7f15c4399eb1a8c4fe511ba2853e07c996d771a5e0a4" +checksum = "41a3852fdf9a4f8fbeaa63dc3e9a85284dd6ef7200751f0bd66ceee30c93f212" dependencies = [ "anyhow", "brotli", @@ -6657,15 +6904,15 @@ dependencies = [ "proc-macro2", "quote", "regex", - "schemars", + "schemars 0.8.22", "semver", "serde", "serde-untagged", "serde_json", "serde_with", "swift-rs", - "thiserror 2.0.12", - "toml", + "thiserror 2.0.16", + "toml 0.9.5", "url", "urlpattern", "uuid", @@ -6674,26 +6921,25 @@ dependencies = [ [[package]] name = "tauri-winres" -version = "0.3.1" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8d321dbc6f998d825ab3f0d62673e810c861aac2d0de2cc2c395328f1d113b4" +checksum = "fd21509dd1fa9bd355dc29894a6ff10635880732396aa38c0066c1e6c1ab8074" dependencies = [ "embed-resource", - "indexmap 2.10.0", - "toml", + "toml 0.9.5", ] [[package]] name = "tempfile" -version = "3.19.1" +version = "3.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7437ac7763b9b123ccf33c338a5cc1bac6f69b45a136c19bdd8a65e3916435bf" +checksum = "15b61f8f20e3a6f7e0649d825294eaf317edce30f82cf6026e7e4cb9222a7d1e" dependencies = [ "fastrand", - "getrandom 0.3.2", + "getrandom 0.3.3", "once_cell", - "rustix 1.0.7", - "windows-sys 0.59.0", + "rustix", + "windows-sys 0.60.2", ] [[package]] @@ -6707,12 +6953,6 @@ dependencies = [ "utf-8", ] -[[package]] -name = "thin-slice" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8eaa81235c7058867fa8c0e7314f33dcce9c215f535d1913822a2b3f5e289f3c" - [[package]] name = "thiserror" version = "1.0.69" @@ -6724,11 +6964,11 @@ dependencies = [ [[package]] name = "thiserror" -version = "2.0.12" +version = "2.0.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708" +checksum = "3467d614147380f2e4e374161426ff399c91084acd2363eaf549172b3d5e60c0" dependencies = [ - "thiserror-impl 2.0.12", + "thiserror-impl 2.0.16", ] [[package]] @@ -6739,39 +6979,41 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.106", ] [[package]] name = "thiserror-impl" -version = "2.0.12" +version = "2.0.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d" +checksum = "6c5e1be1c48b9172ee610da68fd9cd2770e7a4056cb3fc98710ee6906f0c7960" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.106", ] [[package]] name = "tiff" -version = "0.9.1" +version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba1310fcea54c6a9a4fd1aad794ecc02c31682f6bfbecdf460bf19533eed1e3e" +checksum = "af9605de7fee8d9551863fd692cce7637f548dbd9db9180fcc07ccc6d26c336f" dependencies = [ + "fax", "flate2", - "jpeg-decoder", + "half", + "quick-error", "weezl", + "zune-jpeg", ] [[package]] name = "time" -version = "0.3.41" +version = "0.3.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a7619e19bc266e0f9c5e6686659d394bc57973859340060a69221e57dbc0c40" +checksum = "83bde6f1ec10e72d583d91623c939f623002284ef622b87de38cfd546cbf2031" dependencies = [ "deranged", - "itoa 1.0.15", "libc", "num-conv", "num_threads", @@ -6783,15 +7025,15 @@ dependencies = [ [[package]] name = "time-core" -version = "0.1.4" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9e9a38711f559d9e3ce1cdb06dd7c5b8ea546bc90052da6d06bb76da74bb07c" +checksum = "40868e7c1d2f0b8d73e4a8c7f0ff63af4f6d19be117e90bd73eb1d62cf831c6b" [[package]] name = "time-macros" -version = "0.2.22" +version = "0.2.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3526739392ec93fd8b359c8e98514cb3e8e021beb4e5f597b00a0221f8ed8a49" +checksum = "30cfb0125f12d9c277f35663a0a33f8c30190f4e4574868a330595412d34ebf3" dependencies = [ "num-conv", "time-core", @@ -6818,9 +7060,9 @@ dependencies = [ [[package]] name = "tinyvec" -version = "1.9.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09b3661f17e86524eccd4371ab0429194e0d7c008abb45f7a7495b1719463c71" +checksum = "bfa5fdc3bce6191a1dbc8c02d5c8bffcf557bafa17c124c5264a458f1b0613fa" dependencies = [ "tinyvec_macros", ] @@ -6833,21 +7075,23 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.45.0" +version = "1.47.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2513ca694ef9ede0fb23fe71a4ee4107cb102b9dc1930f6d0fd77aae068ae165" +checksum = "89e49afdadebb872d3145a5638b59eb0691ea23e46ca484037cfab3b76b95038" dependencies = [ "backtrace", "bytes", + "io-uring", "libc", - "mio 1.0.3", + "mio 1.0.4", "parking_lot", "pin-project-lite", "signal-hook-registry", + "slab", "socket2", "tokio-macros", "tracing", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -6858,7 +7102,7 @@ checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.106", ] [[package]] @@ -6908,9 +7152,9 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.15" +version = "0.7.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66a539a9ad6d5d281510d5bd368c973d636c02dbf8a67300bfb6b950696ad7df" +checksum = "14307c986784f72ef81c89db7d9e28d6ac26d16213b109ea501696195e6e3ce5" dependencies = [ "bytes", "futures-core", @@ -6921,21 +7165,45 @@ dependencies = [ [[package]] name = "toml" -version = "0.8.22" +version = "0.8.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05ae329d1f08c4d17a59bed7ff5b5a769d062e64a62d34a3261b219e62cd5aae" +checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362" dependencies = [ "serde", - "serde_spanned", - "toml_datetime", - "toml_edit 0.22.26", + "serde_spanned 0.6.9", + "toml_datetime 0.6.11", + "toml_edit 0.22.27", +] + +[[package]] +name = "toml" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75129e1dc5000bfbaa9fee9d1b21f974f9fbad9daec557a521ee6e080825f6e8" +dependencies = [ + "indexmap 2.11.0", + "serde", + "serde_spanned 1.0.0", + "toml_datetime 0.7.0", + "toml_parser", + "toml_writer", + "winnow 0.7.13", ] [[package]] name = "toml_datetime" -version = "0.6.9" +version = "0.6.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3da5db5a963e24bc68be8b17b6fa82814bb22ee8660f192bb182771d498f09a3" +checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_datetime" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bade1c3e902f58d73d3f294cd7f20391c1cb2fbcb643b73566bc773971df91e3" dependencies = [ "serde", ] @@ -6946,8 +7214,8 @@ version = "0.19.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" dependencies = [ - "indexmap 2.10.0", - "toml_datetime", + "indexmap 2.11.0", + "toml_datetime 0.6.11", "winnow 0.5.40", ] @@ -6957,30 +7225,38 @@ version = "0.20.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "70f427fce4d84c72b5b732388bf4a9f4531b53f74e2887e3ecb2481f68f66d81" dependencies = [ - "indexmap 2.10.0", - "toml_datetime", + "indexmap 2.11.0", + "toml_datetime 0.6.11", "winnow 0.5.40", ] [[package]] name = "toml_edit" -version = "0.22.26" +version = "0.22.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "310068873db2c5b3e7659d2cc35d21855dbafa50d1ce336397c666e3cb08137e" +checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a" dependencies = [ - "indexmap 2.10.0", + "indexmap 2.11.0", "serde", - "serde_spanned", - "toml_datetime", - "toml_write", - "winnow 0.7.10", + "serde_spanned 0.6.9", + "toml_datetime 0.6.11", + "winnow 0.7.13", ] [[package]] -name = "toml_write" -version = "0.1.1" +name = "toml_parser" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfb942dfe1d8e29a7ee7fcbde5bd2b9a25fb89aa70caea2eba3bee836ff41076" +checksum = "b551886f449aa90d4fe2bdaa9f4a2577ad2dde302c61ecf262d80b116db95c10" +dependencies = [ + "winnow 0.7.13", +] + +[[package]] +name = "toml_writer" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcc842091f2def52017664b53082ecbbeb5c7731092bad69d2c63050401dfd64" [[package]] name = "tower" @@ -6997,6 +7273,24 @@ dependencies = [ "tower-service", ] +[[package]] +name = "tower-http" +version = "0.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adc82fd73de2a9722ac5da747f12383d2bfdb93591ee6c58486e0097890f05f2" +dependencies = [ + "bitflags 2.9.4", + "bytes", + "futures-util", + "http 1.3.1", + "http-body 1.0.1", + "iri-string", + "pin-project-lite", + "tower", + "tower-layer", + "tower-service", +] + [[package]] name = "tower-layer" version = "0.3.3" @@ -7022,20 +7316,20 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.28" +version = "0.1.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d" +checksum = "81383ab64e72a7a8b8e13130c49e3dab29def6d0c7d76a03087b3cf71c5c6903" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.106", ] [[package]] name = "tracing-core" -version = "0.1.33" +version = "0.1.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c" +checksum = "b9d12581f227e93f094d3af2ae690a574abb8a2b9b7a96e7cfe9647b2b617678" dependencies = [ "once_cell", ] @@ -7046,10 +7340,10 @@ version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cc48e3b6e7a94b6c90b6905f157f2a875dfb5866cf19429476fd803c9c84eafc" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.4", "gio 0.20.12", - "glib 0.20.9", - "glib-sys 0.20.9", + "glib 0.20.12", + "glib-sys 0.20.10", "libc", "tracker-sys", ] @@ -7060,41 +7354,35 @@ version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8814f2bd279c6fa3eb22921a5394df6109c6ec18f805e5973fa633a4e9a57785" dependencies = [ - "gio-sys 0.20.9", - "glib-sys 0.20.9", - "gobject-sys 0.20.9", + "gio-sys 0.20.10", + "glib-sys 0.20.10", + "gobject-sys 0.20.10", "libc", - "system-deps 7.0.3", + "system-deps 7.0.5", ] [[package]] name = "tray-icon" -version = "0.20.1" +version = "0.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f7eee98ec5c90daf179d55c20a49d8c0d043054ce7c26336c09a24d31f14fa0" +checksum = "a0d92153331e7d02ec09137538996a7786fe679c629c279e82a6be762b7e6fe2" dependencies = [ "crossbeam-channel", "dirs 6.0.0", "libappindicator", "muda", - "objc2 0.6.1", + "objc2 0.6.2", "objc2-app-kit 0.3.1", "objc2-core-foundation", "objc2-core-graphics", "objc2-foundation 0.3.1", "once_cell", - "png", + "png 0.17.16", "serde", - "thiserror 2.0.12", + "thiserror 2.0.16", "windows-sys 0.59.0", ] -[[package]] -name = "trim-in-place" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "343e926fc669bc8cde4fa3129ab681c63671bae288b1f1081ceee6d9d37904fc" - [[package]] name = "try-lock" version = "0.2.5" @@ -7235,9 +7523,9 @@ checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" [[package]] name = "url" -version = "2.5.4" +version = "2.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60" +checksum = "08bc136a29a3d1758e07a9cca267be308aeebf5cfd5a10f3f67ab2097683ef5b" dependencies = [ "form_urlencoded", "idna", @@ -7277,19 +7565,21 @@ checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" [[package]] name = "uuid" -version = "1.16.0" +version = "1.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "458f7a779bf54acc9f347480ac654f68407d3aab21269a6e3c9f922acd9e2da9" +checksum = "2f87b8aa10b915a06587d0dec516c282ff295b475d94abf425d62b57710070a2" dependencies = [ - "getrandom 0.3.2", + "getrandom 0.3.3", + "js-sys", "serde", + "wasm-bindgen", ] [[package]] name = "v_frame" -version = "0.3.8" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6f32aaa24bacd11e488aa9ba66369c7cd514885742c9fe08cfe85884db3e92b" +checksum = "666b7727c8875d6ab5db9533418d7c764233ac9c0cff1d469aec8fa127597be2" dependencies = [ "aligned-vec", "num-traits", @@ -7367,17 +7657,17 @@ checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" [[package]] name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" +version = "0.11.1+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" [[package]] name = "wasi" -version = "0.14.2+wasi-0.2.4" +version = "0.14.3+wasi-0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3" +checksum = "6a51ae83037bdd272a9e28ce236db8c07016dd0d50c27038b3f407533c030c95" dependencies = [ - "wit-bindgen-rt", + "wit-bindgen", ] [[package]] @@ -7402,7 +7692,7 @@ dependencies = [ "log", "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.106", "wasm-bindgen-shared", ] @@ -7437,7 +7727,7 @@ checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.106", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -7464,6 +7754,66 @@ dependencies = [ "web-sys", ] +[[package]] +name = "wayland-backend" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "673a33c33048a5ade91a6b139580fa174e19fb0d23f396dca9fa15f2e1e49b35" +dependencies = [ + "cc", + "downcast-rs", + "rustix", + "scoped-tls", + "smallvec", + "wayland-sys", +] + +[[package]] +name = "wayland-client" +version = "0.31.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c66a47e840dc20793f2264eb4b3e4ecb4b75d91c0dd4af04b456128e0bdd449d" +dependencies = [ + "bitflags 2.9.4", + "rustix", + "wayland-backend", + "wayland-scanner", +] + +[[package]] +name = "wayland-protocols" +version = "0.32.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "efa790ed75fbfd71283bd2521a1cfdc022aabcc28bdcff00851f9e4ae88d9901" +dependencies = [ + "bitflags 2.9.4", + "wayland-backend", + "wayland-client", + "wayland-scanner", +] + +[[package]] +name = "wayland-scanner" +version = "0.31.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54cb1e9dc49da91950bdfd8b848c49330536d9d1fb03d4bfec8cae50caa50ae3" +dependencies = [ + "proc-macro2", + "quick-xml 0.37.5", + "quote", +] + +[[package]] +name = "wayland-sys" +version = "0.31.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34949b42822155826b41db8e5d0c1be3a2bd296c747577a43a3e6daefc296142" +dependencies = [ + "dlib", + "log", + "pkg-config", +] + [[package]] name = "web-sys" version = "0.3.77" @@ -7530,27 +7880,18 @@ dependencies = [ [[package]] name = "webpki-roots" -version = "0.26.11" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "521bc38abb08001b01866da9f51eb7c5d647a19260e00054a8c7fd5f9e57f7a9" -dependencies = [ - "webpki-roots 1.0.0", -] - -[[package]] -name = "webpki-roots" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2853738d1cc4f2da3a225c18ec6c3721abb31961096e9dbf5ab35fa88b19cfdb" +checksum = "7e8983c3ab33d6fb807cfcdad2491c4ea8cbc8ed839181c7dfd9c67c83e261b2" dependencies = [ "rustls-pki-types", ] [[package]] name = "webview2-com" -version = "0.37.0" +version = "0.38.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b542b5cfbd9618c46c2784e4d41ba218c336ac70d44c55e47b251033e7d85601" +checksum = "d4ba622a989277ef3886dd5afb3e280e3dd6d974b766118950a08f8f678ad6a4" dependencies = [ "webview2-com-macros", "webview2-com-sys", @@ -7568,25 +7909,25 @@ checksum = "1d228f15bba3b9d56dde8bddbee66fa24545bd17b48d5128ccf4a8742b18e431" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.106", ] [[package]] name = "webview2-com-sys" -version = "0.37.0" +version = "0.38.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ae2d11c4a686e4409659d7891791254cf9286d3cfe0eef54df1523533d22295" +checksum = "36695906a1b53a3bf5c4289621efedac12b73eeb0b89e7e1a89b517302d5d75c" dependencies = [ - "thiserror 2.0.12", + "thiserror 2.0.16", "windows 0.61.3", "windows-core 0.61.2", ] [[package]] name = "weezl" -version = "0.1.8" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53a85b86a771b1c87058196170769dd264f66c0782acf1ae6cc51bfd64b39082" +checksum = "a751b3277700db47d3e574514de2eced5e54dc8a5436a3bf7a0b248b2cee16f3" [[package]] name = "which" @@ -7595,7 +7936,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3fabb953106c3c8eea8306e4393700d7657561cb43122571b172bbfb7c7ba1d" dependencies = [ "env_home", - "rustix 1.0.7", + "rustix", "winsafe", ] @@ -7629,11 +7970,11 @@ checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-util" -version = "0.1.9" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" +checksum = "0978bf7171b3d90bac376700cb56d606feb40f251a475a5d6634613564460b22" dependencies = [ - "windows-sys 0.59.0", + "windows-sys 0.60.2", ] [[package]] @@ -7648,7 +7989,7 @@ version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d9bec5a31f3f9362f2258fd0e9c9dd61a9ca432e7306cc78c444258f0dce9a9c" dependencies = [ - "objc2 0.6.1", + "objc2 0.6.2", "objc2-app-kit 0.3.1", "objc2-core-foundation", "objc2-foundation 0.3.1", @@ -7686,7 +8027,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f919aee0a93304be7f62e8e5027811bbba96bcb1de84d6618be56e43f8a32a1" dependencies = [ "windows-core 0.59.0", - "windows-targets 0.53.0", + "windows-targets 0.53.3", ] [[package]] @@ -7743,7 +8084,7 @@ dependencies = [ "windows-interface 0.59.1", "windows-result 0.3.4", "windows-strings 0.3.1", - "windows-targets 0.53.0", + "windows-targets 0.53.3", ] [[package]] @@ -7791,7 +8132,7 @@ checksum = "12168c33176773b86799be25e2a2ba07c7aab9968b37541f1094dbd7a60c8946" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.106", ] [[package]] @@ -7802,7 +8143,7 @@ checksum = "2bbd5b46c938e506ecbce286b6628a02171d56153ba733b6c741fc627ec9579b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.106", ] [[package]] @@ -7813,7 +8154,7 @@ checksum = "83577b051e2f49a058c308f17f273b570a6a758386fc291b5f6a934dd84e48c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.106", ] [[package]] @@ -7824,7 +8165,7 @@ checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.106", ] [[package]] @@ -7835,7 +8176,7 @@ checksum = "9d8dc32e0095a7eeccebd0e3f09e9509365ecb3fc6ac4d6f5f14a3f6392942d1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.106", ] [[package]] @@ -7846,7 +8187,7 @@ checksum = "053c4c462dc91d3b1504c6fe5a726dd15e216ba718e84a0e46a88fbe5ded3515" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.106", ] [[package]] @@ -7857,7 +8198,7 @@ checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.106", ] [[package]] @@ -7878,20 +8219,9 @@ dependencies = [ [[package]] name = "windows-registry" -version = "0.4.0" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4286ad90ddb45071efd1a66dfa43eb02dd0dfbae1545ad6cc3c51cf34d7e8ba3" -dependencies = [ - "windows-result 0.3.4", - "windows-strings 0.3.1", - "windows-targets 0.53.0", -] - -[[package]] -name = "windows-registry" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad1da3e436dc7653dfdf3da67332e22bff09bb0e28b0239e1624499c7830842e" +checksum = "5b8a9ed28765efc97bbc954883f4e6796c33a06546ebafacbabee9696967499e" dependencies = [ "windows-link", "windows-result 0.3.4", @@ -7980,6 +8310,15 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "windows-sys" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" +dependencies = [ + "windows-targets 0.53.3", +] + [[package]] name = "windows-targets" version = "0.42.2" @@ -8028,10 +8367,11 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.53.0" +version = "0.53.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1e4c7e8ceaaf9cb7d7507c974735728ab453b67ef8f18febdd7c11fe59dca8b" +checksum = "d5fe6031c4041849d7c496a8ded650796e7b6ecc19df1a431c1a363342e5dc91" dependencies = [ + "windows-link", "windows_aarch64_gnullvm 0.53.0", "windows_aarch64_msvc 0.53.0", "windows_i686_gnu 0.53.0", @@ -8251,9 +8591,9 @@ dependencies = [ [[package]] name = "winnow" -version = "0.7.10" +version = "0.7.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c06928c8748d81b05c9be96aad92e1b6ff01833332f281e8cfca3be4b35fc9ec" +checksum = "21a0236b59786fed61e2a80582dd500fe61f18b5dca67a4a067d0bc9039339cf" dependencies = [ "memchr", ] @@ -8277,6 +8617,16 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "winreg" +version = "0.55.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb5a765337c50e9ec252c2069be9bf91c7df47afb103b642ba3a53bf8101be97" +dependencies = [ + "cfg-if", + "windows-sys 0.59.0", +] + [[package]] name = "winsafe" version = "0.0.19" @@ -8284,13 +8634,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d135d17ab770252ad95e9a872d365cf3090e3be864a34ab46f48555993efc904" [[package]] -name = "wit-bindgen-rt" -version = "0.39.0" +name = "wit-bindgen" +version = "0.45.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" -dependencies = [ - "bitflags 2.9.0", -] +checksum = "052283831dbae3d879dc7f51f3d92703a316ca49f91540417d38591826127814" [[package]] name = "writeable" @@ -8300,14 +8647,15 @@ checksum = "ea2f10b9bb0928dfb1b42b65e1f9e36f7f54dbdf08457afefb38afcdec4fa2bb" [[package]] name = "wry" -version = "0.51.2" +version = "0.53.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c886a0a9d2a94fd90cfa1d929629b79cfefb1546e2c7430c63a47f0664c0e4e2" +checksum = "31f0e9642a0d061f6236c54ccae64c2722a7879ad4ec7dff59bd376d446d8e90" dependencies = [ "base64 0.22.1", "block2 0.6.1", "cookie", "crossbeam-channel", + "dirs 6.0.0", "dpi", "dunce", "gdkx11", @@ -8319,7 +8667,7 @@ dependencies = [ "kuchikiki", "libc", "ndk", - "objc2 0.6.1", + "objc2 0.6.2", "objc2-app-kit 0.3.1", "objc2-core-foundation", "objc2-foundation 0.3.1", @@ -8331,7 +8679,7 @@ dependencies = [ "sha2", "soup3", "tao-macros", - "thiserror 2.0.12", + "thiserror 2.0.16", "url", "webkit2gtk", "webkit2gtk-sys", @@ -8373,13 +8721,30 @@ dependencies = [ ] [[package]] -name = "xattr" -version = "1.5.0" +name = "x11rb" +version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d65cbf2f12c15564212d48f4e3dfb87923d25d611f2aed18f4cb23f0413d89e" +checksum = "9993aa5be5a26815fe2c3eacfc1fde061fc1a1f094bf1ad2a18bf9c495dd7414" +dependencies = [ + "gethostname", + "rustix", + "x11rb-protocol", +] + +[[package]] +name = "x11rb-protocol" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea6fc2961e4ef194dcbfe56bb845534d0dc8098940c7e5c012a258bfec6701bd" + +[[package]] +name = "xattr" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af3a19837351dc82ba89f8a125e22a3c475f05aba604acc023d62b2739ae2909" dependencies = [ "libc", - "rustix 1.0.7", + "rustix", ] [[package]] @@ -8391,14 +8756,14 @@ dependencies = [ "dbus", "image", "log", - "objc2 0.6.1", + "objc2 0.6.2", "objc2-app-kit 0.3.1", "objc2-core-foundation", "objc2-core-graphics", "objc2-foundation 0.3.1", "percent-encoding", "scopeguard", - "thiserror 2.0.12", + "thiserror 2.0.16", "widestring 1.2.0", "windows 0.59.0", "xcb", @@ -8406,9 +8771,9 @@ dependencies = [ [[package]] name = "xcb" -version = "1.5.0" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1e2f212bb1a92cd8caac8051b829a6582ede155ccb60b5d5908b81b100952be" +checksum = "f07c123b796139bfe0603e654eaf08e132e52387ba95b252c78bad3640ba37ea" dependencies = [ "bitflags 1.3.2", "libc", @@ -8458,15 +8823,15 @@ checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.106", "synstructure", ] [[package]] name = "zbus" -version = "5.6.0" +version = "5.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2522b82023923eecb0b366da727ec883ace092e7887b61d3da5139f26b44da58" +checksum = "67a073be99ace1adc48af593701c8015cd9817df372e14a1a6b0ee8f8bf043be" dependencies = [ "async-broadcast", "async-executor", @@ -8482,15 +8847,15 @@ dependencies = [ "futures-core", "futures-lite", "hex", - "nix 0.29.0", + "nix", "ordered-stream", "serde", "serde_repr", "tokio", "tracing", "uds_windows", - "windows-sys 0.59.0", - "winnow 0.7.10", + "windows-sys 0.60.2", + "winnow 0.7.13", "zbus_macros", "zbus_names", "zvariant", @@ -8498,14 +8863,14 @@ dependencies = [ [[package]] name = "zbus_macros" -version = "5.6.0" +version = "5.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05d2e12843c75108c00c618c2e8ef9675b50b6ec095b36dc965f2e5aed463c15" +checksum = "0e80cd713a45a49859dcb648053f63265f4f2851b6420d47a958e5697c68b131" dependencies = [ "proc-macro-crate 3.3.0", "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.106", "zbus_names", "zvariant", "zvariant_utils", @@ -8519,28 +8884,28 @@ checksum = "7be68e64bf6ce8db94f63e72f0c7eb9a60d733f7e0499e628dfab0f84d6bcb97" dependencies = [ "serde", "static_assertions", - "winnow 0.7.10", + "winnow 0.7.13", "zvariant", ] [[package]] name = "zerocopy" -version = "0.8.25" +version = "0.8.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1702d9583232ddb9174e01bb7c15a2ab8fb1bc6f227aa1233858c351a3ba0cb" +checksum = "1039dd0d3c310cf05de012d8a39ff557cb0d23087fd44cad61df08fc31907a2f" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.25" +version = "0.8.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28a6e20d751156648aa063f3800b706ee209a32c0b4d9f24be3d980b01be55ef" +checksum = "9ecf5b4cc5364572d7f4c329661bcc82724222973f2cab6f050a4e5c22f75181" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.106", ] [[package]] @@ -8560,7 +8925,7 @@ checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.106", "synstructure", ] @@ -8581,7 +8946,7 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.106", ] [[package]] @@ -8597,9 +8962,9 @@ dependencies = [ [[package]] name = "zerovec" -version = "0.11.2" +version = "0.11.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a05eb080e015ba39cc9e23bbe5e7fb04d5fb040350f99f34e338d5fdd294428" +checksum = "e7aa2bd55086f1ab526693ecbe444205da57e25f4489879da80635a46d90e73b" dependencies = [ "yoke", "zerofrom", @@ -8614,27 +8979,29 @@ checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.106", ] [[package]] name = "zip" -version = "2.6.1" +version = "2.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1dcb24d0152526ae49b9b96c1dcf71850ca1e0b882e4e28ed898a93c41334744" +checksum = "fabe6324e908f85a1c52063ce7aa26b68dcb7eb6dbc83a2d148403c9bc3eba50" dependencies = [ "arbitrary", "crc32fast", "crossbeam-utils", - "indexmap 2.10.0", + "displaydoc", + "indexmap 2.11.0", "memchr", + "thiserror 2.0.16", ] [[package]] name = "zip" -version = "4.0.0" +version = "4.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "153a6fff49d264c4babdcfa6b4d534747f520e56e8f0f384f3b808c4b64cc1fd" +checksum = "caa8cd6af31c3b31c6631b8f483848b91589021b28fffe50adada48d4f4d2ed1" dependencies = [ "aes", "arbitrary", @@ -8643,12 +9010,13 @@ dependencies = [ "crc32fast", "deflate64", "flate2", - "getrandom 0.3.2", + "getrandom 0.3.3", "hmac", - "indexmap 2.10.0", + "indexmap 2.11.0", "liblzma", "memchr", "pbkdf2", + "ppmd-rust", "sha1", "time", "zeroize", @@ -8658,9 +9026,9 @@ dependencies = [ [[package]] name = "zlib-rs" -version = "0.5.1" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "626bd9fa9734751fc50d6060752170984d7053f5a39061f524cda68023d4db8a" +checksum = "2f06ae92f42f5e5c42443fd094f245eb656abf56dd7cce9b8b263236565e00f2" [[package]] name = "zopfli" @@ -8719,51 +9087,50 @@ dependencies = [ [[package]] name = "zune-jpeg" -version = "0.4.14" +version = "0.4.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99a5bab8d7dedf81405c4bb1f2b83ea057643d9cb28778cea9eecddeedd2e028" +checksum = "fc1f7e205ce79eb2da3cd71c5f55f3589785cb7c79f6a03d1c8d1491bda5d089" dependencies = [ "zune-core", ] [[package]] name = "zvariant" -version = "5.5.1" +version = "5.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "557e89d54880377a507c94cd5452f20e35d14325faf9d2958ebeadce0966c1b2" +checksum = "999dd3be73c52b1fccd109a4a81e4fcd20fab1d3599c8121b38d04e1419498db" dependencies = [ "endi", "enumflags2", "serde", "url", - "winnow 0.7.10", + "winnow 0.7.13", "zvariant_derive", "zvariant_utils", ] [[package]] name = "zvariant_derive" -version = "5.5.1" +version = "5.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "757779842a0d242061d24c28be589ce392e45350dfb9186dfd7a042a2e19870c" +checksum = "6643fd0b26a46d226bd90d3f07c1b5321fe9bb7f04673cb37ac6d6883885b68e" dependencies = [ "proc-macro-crate 3.3.0", "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.106", "zvariant_utils", ] [[package]] name = "zvariant_utils" -version = "3.2.0" +version = "3.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e16edfee43e5d7b553b77872d99bc36afdda75c223ca7ad5e3fbecd82ca5fc34" +checksum = "c6949d142f89f6916deca2232cf26a8afacf2b9fdc35ce766105e104478be599" dependencies = [ "proc-macro2", "quote", "serde", - "static_assertions", - "syn 2.0.101", - "winnow 0.7.10", + "syn 2.0.106", + "winnow 0.7.13", ] diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index 61c31663..78edb1f8 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -109,11 +109,16 @@ indexmap = { version = "2.10.0", features = ["serde"] } strum = { version = "0.27.2", features = ["derive"] } sys-locale = "0.3.2" tauri-plugin-prevent-default = "1" +oneshot = "0.1.11" +bitflags = "2.9.3" [target."cfg(target_os = \"macos\")".dependencies] tauri-nspanel = { git = "https://github.com/ahkohd/tauri-nspanel", branch = "v2" } objc2-app-kit = { version = "0.3.1", features = ["NSWindow"] } - +objc2 = "0.6.2" +objc2-core-foundation = {version = "0.3.1", features = ["CFString", "CFCGTypes", "CFArray"] } +objc2-application-services = { version = "0.3.1", features = ["HIServices"] } +objc2-core-graphics = { version = "=0.3.1", features = ["CGEvent"] } [target."cfg(target_os = \"linux\")".dependencies] gio = "0.20.12" @@ -122,6 +127,8 @@ which = "8.0.0" [target."cfg(any(target_os = \"macos\", windows, target_os = \"linux\"))".dependencies] tauri-plugin-single-instance = { version = "2.0.0", features = ["deep-link"] } +serde = { version = "1.0.219", features = ["derive"], optional = true } + [profile.dev] incremental = true # Compile your binary in smaller steps. diff --git a/src-tauri/src/common/document.rs b/src-tauri/src/common/document.rs index d8e27edc..604a2e74 100644 --- a/src-tauri/src/common/document.rs +++ b/src-tauri/src/common/document.rs @@ -1,4 +1,6 @@ use crate::extension::ExtensionSettings; +#[cfg(target_os = "macos")] +use crate::extension::built_in::window_management::actions::Action; use serde::{Deserialize, Serialize}; use std::collections::HashMap; use tauri::AppHandle; @@ -43,6 +45,9 @@ pub(crate) enum OnOpened { Application { app_path: String }, /// Open the URL. Document { url: String }, + /// Perform this WM action. + #[cfg(target_os = "macos")] + WindowManagementAction { action: Action }, /// The document is an extension. Extension(ExtensionOnOpened), } @@ -81,6 +86,11 @@ impl OnOpened { match self { Self::Application { app_path } => app_path.clone(), Self::Document { url } => url.clone(), + #[cfg(target_os = "macos")] + Self::WindowManagementAction { action: _ } => { + // We don't have URL for this + String::from("N/A") + } Self::Extension(ext_on_opened) => { match &ext_on_opened.ty { ExtensionOnOpenedType::Command { action } => { @@ -123,6 +133,15 @@ pub(crate) async fn open( homemade_tauri_shell_open(tauri_app_handle.clone(), url).await? } + #[cfg(target_os = "macos")] + OnOpened::WindowManagementAction { action } => { + log::debug!("perform Window Management action [{:?}]", action); + + crate::extension::built_in::window_management::perform_action_on_main_thread( + &tauri_app_handle, + action, + )?; + } OnOpened::Extension(ext_on_opened) => { // Apply the settings that would affect open behavior if let Some(settings) = ext_on_opened.settings { diff --git a/src-tauri/src/extension/built_in/mod.rs b/src-tauri/src/extension/built_in/mod.rs index a07e0536..c03d1be9 100644 --- a/src-tauri/src/extension/built_in/mod.rs +++ b/src-tauri/src/extension/built_in/mod.rs @@ -6,6 +6,8 @@ pub mod calculator; pub mod file_search; pub mod pizza_engine_runtime; pub mod quick_ai_access; +#[cfg(target_os = "macos")] +pub mod window_management; use super::Extension; use crate::SearchSourceRegistry; @@ -181,6 +183,19 @@ pub(crate) async fn list_built_in_extensions( .await?, ); + cfg_if::cfg_if! { + if #[cfg(target_os = "macos")] { + built_in_extensions.push( + load_built_in_extension( + &dir, + window_management::EXTENSION_ID, + window_management::PLUGIN_JSON_FILE, + ) + .await?, + ); + } + } + Ok(built_in_extensions) } @@ -215,6 +230,20 @@ pub(super) async fn init_built_in_extension( log::debug!("built-in extension [{}] initialized", extension.id); } + cfg_if::cfg_if! { + if #[cfg(target_os = "macos")] { + if extension.id == window_management::EXTENSION_ID { + let file_system_search = window_management::search_source::WindowManagementSearchSource; + search_source_registry + .register_source(file_system_search) + .await; + + window_management::set_up_commands_hotkeys(tauri_app_handle, extension)?; + log::debug!("built-in extension [{}] initialized", extension.id); + } + } + } + Ok(()) } @@ -303,6 +332,40 @@ pub(crate) async fn enable_built_in_extension( return Ok(()); } + cfg_if::cfg_if! { + if #[cfg(target_os = "macos")] { + if bundle_id.extension_id == window_management::EXTENSION_ID + && bundle_id.sub_extension_id.is_none() + { + let built_in_extension_dir = get_built_in_extension_directory(tauri_app_handle); + + let file_system_search = window_management::search_source::WindowManagementSearchSource; + search_source_registry_tauri_state + .register_source(file_system_search) + .await; + + let extension = + load_extension_from_json_file(&built_in_extension_dir, bundle_id.extension_id)?; + window_management::set_up_commands_hotkeys(tauri_app_handle, &extension)?; + + alter_extension_json_file(&built_in_extension_dir, bundle_id, update_extension)?; + + return Ok(()); + } + + if bundle_id.extension_id == window_management::EXTENSION_ID { + if let Some(command_id) = bundle_id.sub_extension_id { + let built_in_extension_dir = get_built_in_extension_directory(tauri_app_handle); + alter_extension_json_file(&built_in_extension_dir, bundle_id, update_extension)?; + + let extension = + load_extension_from_json_file(&built_in_extension_dir, bundle_id.extension_id)?; + window_management::set_up_command_hotkey(tauri_app_handle, &extension, command_id)?; + } + } + } + } + Ok(()) } @@ -386,6 +449,36 @@ pub(crate) async fn disable_built_in_extension( return Ok(()); } + cfg_if::cfg_if! { + if #[cfg(target_os = "macos")] { + if bundle_id.extension_id == window_management::EXTENSION_ID + && bundle_id.sub_extension_id.is_none() + { + let built_in_extension_dir = get_built_in_extension_directory(tauri_app_handle); + + search_source_registry_tauri_state + .remove_source(bundle_id.extension_id) + .await; + alter_extension_json_file(&built_in_extension_dir, bundle_id, update_extension)?; + + let extension = + load_extension_from_json_file(&built_in_extension_dir, bundle_id.extension_id)?; + window_management::unset_commands_hotkeys(tauri_app_handle, &extension)?; + } + + if bundle_id.extension_id == window_management::EXTENSION_ID { + if let Some(command_id) = bundle_id.sub_extension_id { + let built_in_extension_dir = get_built_in_extension_directory(tauri_app_handle); + alter_extension_json_file(&built_in_extension_dir, bundle_id, update_extension)?; + + let extension = + load_extension_from_json_file(&built_in_extension_dir, bundle_id.extension_id)?; + window_management::unset_command_hotkey(tauri_app_handle, &extension, command_id)?; + } + } + } + } + Ok(()) } @@ -393,12 +486,32 @@ pub(crate) fn set_built_in_extension_alias( tauri_app_handle: &AppHandle, bundle_id: &ExtensionBundleIdBorrowed<'_>, alias: &str, -) { +) -> Result<(), String> { if bundle_id.extension_id == application::QUERYSOURCE_ID_DATASOURCE_ID_DATASOURCE_NAME { if let Some(app_path) = bundle_id.sub_extension_id { application::set_app_alias(tauri_app_handle, app_path, alias); } } + + cfg_if::cfg_if! { + if #[cfg(target_os = "macos")] { + if bundle_id.extension_id == window_management::EXTENSION_ID + && bundle_id.sub_extension_id.is_some() + { + let update_function = |ext: &mut Extension| { + ext.alias = Some(alias.to_string()); + Ok(()) + }; + alter_extension_json_file( + &get_built_in_extension_directory(tauri_app_handle), + bundle_id, + update_function, + )?; + } + } + } + + Ok(()) } pub(crate) fn register_built_in_extension_hotkey( @@ -411,6 +524,29 @@ pub(crate) fn register_built_in_extension_hotkey( application::register_app_hotkey(&tauri_app_handle, app_path, hotkey)?; } } + + cfg_if::cfg_if! { + if #[cfg(target_os = "macos")] { + let update_function = |ext: &mut Extension| { + ext.hotkey = Some(hotkey.into()); + + Ok(()) + }; + + if bundle_id.extension_id == window_management::EXTENSION_ID { + if let Some(command_id) = bundle_id.sub_extension_id { + alter_extension_json_file( + &get_built_in_extension_directory(tauri_app_handle), + bundle_id, + update_function, + )?; + + window_management::register_command_hotkey(tauri_app_handle, command_id, hotkey)?; + } + } + } + } + Ok(()) } @@ -423,6 +559,35 @@ pub(crate) fn unregister_built_in_extension_hotkey( application::unregister_app_hotkey(&tauri_app_handle, app_path)?; } } + + cfg_if::cfg_if! { + if #[cfg(target_os = "macos")] { + let update_function = |ext: &mut Extension| { + ext.hotkey = None; + + Ok(()) + }; + + if bundle_id.extension_id == window_management::EXTENSION_ID { + if let Some(command_id) = bundle_id.sub_extension_id { + + let extension = load_extension_from_json_file( + &get_built_in_extension_directory(tauri_app_handle), + bundle_id.extension_id, + ) + .unwrap(); + window_management::unregister_command_hotkey(tauri_app_handle, &extension, command_id)?; + alter_extension_json_file( + &get_built_in_extension_directory(tauri_app_handle), + bundle_id, + update_function, + ) + .unwrap(); + } + } + } + } + Ok(()) } @@ -462,6 +627,8 @@ fn load_extension_from_json_file( Ok(extension) } +#[allow(unused_macros)] // #[function_name::named] only used on macOS +#[function_name::named] pub(crate) async fn is_built_in_extension_enabled( tauri_app_handle: &AppHandle, bundle_id: &ExtensionBundleIdBorrowed<'_>, @@ -514,5 +681,38 @@ pub(crate) async fn is_built_in_extension_enabled( .is_some()); } + cfg_if::cfg_if! { + if #[cfg(target_os = "macos")] { + // Window Management + if bundle_id.extension_id == window_management::EXTENSION_ID + && bundle_id.sub_extension_id.is_none() + { + return Ok(search_source_registry_tauri_state + .get_source(bundle_id.extension_id) + .await + .is_some()); + } + + // Window Management commands + if bundle_id.extension_id == window_management::EXTENSION_ID + && let Some(command_id) = bundle_id.sub_extension_id + { + let extension = load_extension_from_json_file( + &get_built_in_extension_directory(tauri_app_handle), + bundle_id.extension_id, + )?; + let commands = extension + .commands + .expect("window management extension has commands"); + + let extension = commands.iter().find( |cmd| cmd.id == command_id).unwrap_or_else(|| { + panic!("function [{}()] invoked with a Window Management command that does not exist, extension ID [{}] ", function_name!(), command_id) + }); + + return Ok(extension.enabled); + } + } + } + unreachable!("extension [{:?}] is not a built-in extension", bundle_id) } diff --git a/src-tauri/src/extension/built_in/window_management/actions.rs b/src-tauri/src/extension/built_in/window_management/actions.rs new file mode 100644 index 00000000..5e67e01c --- /dev/null +++ b/src-tauri/src/extension/built_in/window_management/actions.rs @@ -0,0 +1,134 @@ +#[derive(Debug, Clone, PartialEq, Copy, Hash, serde::Serialize, serde::Deserialize)] +pub enum Action { + /// Move the window to fill left half of the screen. + TopHalf, + /// Move the window to fill bottom half of the screen. + BottomHalf, + /// Move the window to fill left half of the screen. + LeftHalf, + /// Move the window to fill right half of the screen. + RightHalf, + /// Move the window to fill center half of the screen. + CenterHalf, + + /// Resize window to the top left quarter of the screen. + TopLeftQuarter, + /// Resize window to the top right quarter of the screen. + TopRightQuarter, + /// Resize window to the bottom left quarter of the screen. + BottomLeftQuarter, + /// Resize window to the bottom right quarter of the screen. + BottomRightQuarter, + + /// Resize window to the top left sixth of the screen. + TopLeftSixth, + /// Resize window to the top center sixth of the screen. + TopCenterSixth, + /// Resize window to the top right sixth of the screen. + TopRightSixth, + /// Resize window to the bottom left sixth of the screen. + BottomLeftSixth, + /// Resize window to the bottom center sixth of the screen. + BottomCenterSixth, + /// Resize window to the bottom right sixth of the screen. + BottomRightSixth, + + /// Resize window to the top third of the screen. + TopThird, + /// Resize window to the middle third of the screen. + MiddleThird, + /// Resize window to the bottom third of the screen. + BottomThird, + + /// Center window in the screen. + Center, + + /// Resize window to the first fourth of the screen. + FirstFourth, + /// Resize window to the second fourth of the screen. + SecondFourth, + /// Resize window to the third fourth of the screen. + ThirdFourth, + /// Resize window to the last fourth of the screen. + LastFourth, + + /// Resize window to the first third of the screen. + FirstThird, + /// Resize window to the center third of the screen. + CenterThird, + /// Resize window to the last third of the screen. + LastThird, + + /// Resize window to the first two thirds of the screen. + FirstTwoThirds, + /// Resize window to the center two thirds of the screen. + CenterTwoThirds, + /// Resize window to the last two thirds of the screen. + LastTwoThirds, + + /// Resize window to the first three fourths of the screen. + FirstThreeFourths, + /// Resize window to the center three fourths of the screen. + CenterThreeFourths, + /// Resize window to the last three fourths of the screen. + LastThreeFourths, + + /// Resize window to the top three fourths of the screen. + TopThreeFourths, + /// Resize window to the bottom three fourths of the screen. + BottomThreeFourths, + + /// Resize window to the top two thirds of the screen. + TopTwoThirds, + /// Resize window to the bottom two thirds of the screen. + BottomTwoThirds, + /// Resize window to the top center two thirds of the screen. + TopCenterTwoThirds, + + /// Resize window to the top first fourth of the screen. + TopFirstFourth, + /// Resize window to the top second fourth of the screen. + TopSecondFourth, + /// Resize window to the top third fourth of the screen. + TopThirdFourth, + /// Resize window to the top last fourth of the screen. + TopLastFourth, + + /// Increase the window until it reaches the screen size. + MakeLarger, + /// Decrease the window until it reaches its minimal size. + MakeSmaller, + + /// Maximize window to almost fit the screen. + AlmostMaximize, + /// Maximize window to fit the screen. + Maximize, + /// Maximize width of window to fit the screen. + MaximizeWidth, + /// Maximize height of window to fit the screen. + MaximizeHeight, + + /// Move window to the top edge of the screen. + MoveUp, + /// Move window to the bottom of the screen. + MoveDown, + /// Move window to the left edge of the screen. + MoveLeft, + /// Move window to the right edge of the screen. + MoveRight, + + /// Move window to the next desktop. + NextDesktop, + /// Move window to the previous desktop. + PreviousDesktop, + /// Move window to the next display. + NextDisplay, + /// Move window to the previous display. + PreviousDisplay, + + /// Restore window to its last position. + Restore, + + /// Toggle fullscreen mode. + ToggleFullscreen, +} diff --git a/src-tauri/src/extension/built_in/window_management/backend/mod.rs b/src-tauri/src/extension/built_in/window_management/backend/mod.rs new file mode 100644 index 00000000..9f5593d6 --- /dev/null +++ b/src-tauri/src/extension/built_in/window_management/backend/mod.rs @@ -0,0 +1,638 @@ +//! This module calls macOS APIs to implement various helper functions needed by +//! to perform the defined actions. + +mod private; + +use std::ffi::c_uint; +use std::ffi::c_ushort; +use std::ffi::c_void; +use std::ops::Deref; +use std::ptr::NonNull; + +use objc2::MainThreadMarker; +use objc2_app_kit::NSEvent; +use objc2_app_kit::NSScreen; +use objc2_app_kit::NSWorkspace; +use objc2_application_services::AXError; +use objc2_application_services::AXUIElement; +use objc2_application_services::AXValue; +use objc2_application_services::AXValueType; +use objc2_core_foundation::CFBoolean; +use objc2_core_foundation::CFRetained; +use objc2_core_foundation::CFString; +use objc2_core_foundation::CFType; +use objc2_core_foundation::CGPoint; +use objc2_core_foundation::CGRect; +use objc2_core_foundation::CGSize; +use objc2_core_foundation::Type; +use objc2_core_foundation::{CFArray, CFDictionary, CFNumber}; +use objc2_core_graphics::CGError; +use objc2_core_graphics::CGEvent; +use objc2_core_graphics::CGEventFlags; +use objc2_core_graphics::CGEventTapLocation; +use objc2_core_graphics::CGEventType; +use objc2_core_graphics::CGMouseButton; +use objc2_core_graphics::CGRectGetMidX; +use objc2_core_graphics::CGRectGetMinY; +use objc2_core_graphics::CGWindowID; + +use super::error::Error; + +use private::CGSCopyManagedDisplaySpaces; +use private::CGSGetActiveSpace; +use private::CGSMainConnectionID; +use private::CGSSpaceID; +use std::collections::HashMap; +use std::sync::{LazyLock, Mutex}; + +fn intersects(r1: CGRect, r2: CGRect) -> bool { + let overlapping = !(r1.origin.x + r1.size.width < r2.origin.x + || r1.origin.y + r1.size.height < r2.origin.y + || r1.origin.x > r2.origin.x + r2.size.width + || r1.origin.y > r2.origin.y + r2.size.height); + + overlapping +} + +/// Core graphics APIs use flipped coordinate system, while AppKit uses the +/// unflippled version, they differ in the y-axis. We need to do the conversion +/// (to `CGPoint.y`) manually. +fn flip_frame_y(main_screen_height: f64, frame_height: f64, frame_unflipped_y: f64) -> f64 { + main_screen_height - (frame_unflipped_y + frame_height) +} + +/// Helper function to extract an UI element's origin. +fn get_ui_element_origin(ui_element: &CFRetained) -> Result { + let mut position_value: *const CFType = std::ptr::null(); + let ptr_to_position_value = NonNull::new(&mut position_value).unwrap(); + let position_attr = CFString::from_static_str("AXPosition"); + let error = unsafe { ui_element.copy_attribute_value(&position_attr, ptr_to_position_value) }; + + if error != AXError::Success { + return Err(Error::AXError(error)); + } + assert!(!position_value.is_null()); + + let position: CFRetained = + unsafe { CFRetained::from_raw(NonNull::new(position_value.cast_mut().cast()).unwrap()) }; + + let mut position_cg_point = CGPoint::ZERO; + let ptr_to_position_cg_point = + NonNull::new((&mut position_cg_point as *mut CGPoint).cast()).unwrap(); + + let result = unsafe { position.value(AXValueType::CGPoint, ptr_to_position_cg_point) }; + assert!(result, "type mismatched"); + + Ok(position_cg_point) +} + +/// Helper function to extract an UI element's size. +fn get_ui_element_size(ui_element: &CFRetained) -> Result { + let mut size_value: *const CFType = std::ptr::null(); + let ptr_to_size_value = NonNull::new(&mut size_value).unwrap(); + let size_attr = CFString::from_static_str("AXSize"); + let error = unsafe { ui_element.copy_attribute_value(&size_attr, ptr_to_size_value) }; + + if error != AXError::Success { + return Err(Error::AXError(error)); + } + assert!(!size_value.is_null()); + + let size: CFRetained = + unsafe { CFRetained::from_raw(NonNull::new(size_value.cast_mut().cast()).unwrap()) }; + + let mut size_cg_size = CGSize::ZERO; + let ptr_to_size_cg_size = NonNull::new((&mut size_cg_size as *mut CGSize).cast()).unwrap(); + + let result = unsafe { size.value(AXValueType::CGSize, ptr_to_size_cg_size) }; + assert!(result, "type mismatched"); + + Ok(size_cg_size) +} + +/// Get the frontmost/focused window (as an UI element). +fn get_frontmost_window() -> Result, Error> { + let workspace = unsafe { NSWorkspace::sharedWorkspace() }; + let frontmost_app = + unsafe { workspace.frontmostApplication() }.ok_or(Error::CannotFindFocusWindow)?; + + let pid = unsafe { frontmost_app.processIdentifier() }; + + let app_element = unsafe { AXUIElement::new_application(pid) }; + + let mut window_element: *const CFType = std::ptr::null(); + let ptr_to_window_element = NonNull::new(&mut window_element).unwrap(); + let focused_window_attr = CFString::from_static_str("AXFocusedWindow"); + + let error = + unsafe { app_element.copy_attribute_value(&focused_window_attr, ptr_to_window_element) }; + + if error != AXError::Success { + return Err(Error::AXError(error)); + } + assert!(!window_element.is_null()); + + let window_element: *mut AXUIElement = window_element.cast::().cast_mut(); + + let window = unsafe { CFRetained::from_raw(NonNull::new(window_element).unwrap()) }; + + Ok(window) +} + +/// Get the CGWindowID of the frontmost/focused window. +#[allow(unused)] // In case we need it in the future +pub(crate) fn get_frontmost_window_id() -> Result { + let element = get_frontmost_window()?; + let ptr: NonNull = CFRetained::as_ptr(&element); + + let mut window_id_buffer: CGWindowID = 0; + let error = + unsafe { private::_AXUIElementGetWindow(ptr.as_ptr(), &mut window_id_buffer as *mut _) }; + if error != AXError::Success { + return Err(Error::AXError(error)); + } + + Ok(window_id_buffer) +} + +/// Returns the workspace ID list grouped by display. For example, suppose you +/// have 2 displays and 10 workspaces (5 workspaces per display), then this +/// function might return something like: +/// +/// ```text +/// [ +/// [8, 11, 12, 13, 24], +/// [519, 77, 15, 249, 414] +/// ] +/// ``` +/// +/// Even though this function return macOS internal space IDs, they should correspond +/// to the logical workspace that users are familiar with. The display that contains +/// workspaces `[8, 11, 12, 13, 24]` should be your main display; workspace 8 represents +/// Desktop 1, and workspace 414 represents Desktop 10. +fn workspace_ids_grouped_by_display() -> Vec> { + unsafe { + let mut ret = Vec::new(); + let conn = CGSMainConnectionID(); + + let display_spaces_raw = CGSCopyManagedDisplaySpaces(conn); + let display_spaces: CFRetained = + CFRetained::from_raw(NonNull::new(display_spaces_raw).unwrap()); + + let key_spaces: CFRetained = CFString::from_static_str("Spaces"); + let key_spaces_ptr: NonNull = CFRetained::as_ptr(&key_spaces); + let key_id64: CFRetained = CFString::from_static_str("id64"); + let key_id64_ptr: NonNull = CFRetained::as_ptr(&key_id64); + + for i in 0..display_spaces.count() { + let mut workspaces_of_this_display = Vec::new(); + + let dict_ref = display_spaces.value_at_index(i); + let dict: &CFDictionary = &*(dict_ref as *const CFDictionary); + + let mut ptr_to_value_buffer: *const c_void = std::ptr::null(); + let key_exists = dict.value_if_present( + key_spaces_ptr.as_ptr().cast::().cast_const(), + &mut ptr_to_value_buffer as *mut _, + ); + assert!(key_exists); + assert!(!ptr_to_value_buffer.is_null()); + + let spaces_raw: *const CFArray = ptr_to_value_buffer.cast::(); + + let spaces = &*spaces_raw; + + for idx in 0..spaces.count() { + let workspace_dictionary: &CFDictionary = + &*spaces.value_at_index(idx).cast::(); + + let mut ptr_to_value_buffer: *const c_void = std::ptr::null(); + let key_exists = workspace_dictionary.value_if_present( + key_id64_ptr.as_ptr().cast::().cast_const(), + &mut ptr_to_value_buffer as *mut _, + ); + assert!(key_exists); + assert!(!ptr_to_value_buffer.is_null()); + + let ptr_workspace_id = ptr_to_value_buffer.cast::(); + let workspace_id = (&*ptr_workspace_id).as_i32().unwrap(); + + workspaces_of_this_display.push(workspace_id); + } + + ret.push(workspaces_of_this_display); + } + + ret + } +} + +/// Get the next workspace's logical ID. By logical ID, we mean the ID that +/// users are familiar with, workspace 1/2/3 and so on, rather than the internal +/// `CGSSpaceID`. +/// +/// NOTE that this function returns None when the current workspace is the last +/// workspace in the current display. +pub(crate) fn get_next_workspace_logical_id() -> Option { + let window_server_connection = unsafe { CGSMainConnectionID() }; + let current_workspace_id = unsafe { CGSGetActiveSpace(window_server_connection) }; + + // Logical ID starts from 1 + let mut logical_id = 1_usize; + + for workspaces_in_a_display in workspace_ids_grouped_by_display() { + for (idx, workspace_raw_id) in workspaces_in_a_display.iter().enumerate() { + if *workspace_raw_id == current_workspace_id { + // We found it, now check if it is the last workspace in this display + if idx == workspaces_in_a_display.len() - 1 { + return None; + } else { + return Some(logical_id + 1); + } + } else { + logical_id += 1; + continue; + } + } + } + + unreachable!( + "unless the private API CGSGetActiveSpace() is broken, it should return an ID that is in the workspace ID list" + ) +} + +/// Get the previous workspace's logical ID. +/// +/// See [`get_next_workspace_logical_id`] for the doc. +pub(crate) fn get_previous_workspace_logical_id() -> Option { + let window_server_connection = unsafe { CGSMainConnectionID() }; + let current_workspace_id = unsafe { CGSGetActiveSpace(window_server_connection) }; + + // Logical ID starts from 1 + let mut logical_id = 1_usize; + + for workspaces_in_a_display in workspace_ids_grouped_by_display() { + for (idx, workspace_raw_id) in workspaces_in_a_display.iter().enumerate() { + if *workspace_raw_id == current_workspace_id { + // We found it, now check if it is the first workspace in this display + if idx == 0 { + return None; + } else { + // this sub operation is safe, logical_id is at least 2 + return Some(logical_id - 1); + } + } else { + logical_id += 1; + continue; + } + } + } + + unreachable!( + "unless the private API CGSGetActiveSpace() is broken, it should return an ID that is in the workspace ID list" + ) +} + +/// Move the frontmost window to the specified workspace. +/// +/// Credits to the Silica library +/// +/// * https://github.com/ianyh/Silica/blob/b91a18dbb822e99ce6b487d1cb4841e863139b2a/Silica/Sources/SIWindow.m#L215-L260 +/// * https://github.com/ianyh/Silica/blob/b91a18dbb822e99ce6b487d1cb4841e863139b2a/Silica/Sources/SISystemWideElement.m#L29-L65 +pub(crate) fn move_frontmost_window_to_workspace(space: usize) -> Result<(), Error> { + assert!(space >= 1); + if space > 16 { + return Err(Error::TooManyWorkspace); + } + + let window_frame = get_frontmost_window_frame()?; + let close_button_frame = get_frontmost_window_close_button_frame()?; + + let mouse_cursor_point = CGPoint::new( + unsafe { CGRectGetMidX(close_button_frame) }, + window_frame.origin.y + + (window_frame.origin.y - unsafe { CGRectGetMinY(close_button_frame) }).abs() / 2.0, + ); + + let mouse_move_event = unsafe { + CGEvent::new_mouse_event( + None, + CGEventType::MouseMoved, + mouse_cursor_point, + CGMouseButton::Left, + ) + }; + let mouse_drag_event = unsafe { + CGEvent::new_mouse_event( + None, + CGEventType::LeftMouseDragged, + mouse_cursor_point, + CGMouseButton::Left, + ) + }; + let mouse_down_event = unsafe { + CGEvent::new_mouse_event( + None, + CGEventType::LeftMouseDown, + mouse_cursor_point, + CGMouseButton::Left, + ) + }; + let mouse_up_event = unsafe { + CGEvent::new_mouse_event( + None, + CGEventType::LeftMouseUp, + mouse_cursor_point, + CGMouseButton::Left, + ) + }; + + unsafe { + CGEvent::set_flags(mouse_move_event.as_deref(), CGEventFlags(0)); + CGEvent::set_flags(mouse_down_event.as_deref(), CGEventFlags(0)); + CGEvent::set_flags(mouse_up_event.as_deref(), CGEventFlags(0)); + + // Move the mouse into place at the window's toolbar + CGEvent::post(CGEventTapLocation::HIDEventTap, mouse_move_event.as_deref()); + // Mouse down to set up the drag + CGEvent::post(CGEventTapLocation::HIDEventTap, mouse_down_event.as_deref()); + // Drag event to grab hold of the window + CGEvent::post(CGEventTapLocation::HIDEventTap, mouse_drag_event.as_deref()); + } + + // cast is safe as space is in range [1, 16] + let hot_key: c_ushort = 118 + space as c_ushort - 1; + + let mut flags: c_uint = 0; + let mut key_code: c_ushort = 0; + let error = unsafe { + private::CGSGetSymbolicHotKeyValue(hot_key, std::ptr::null_mut(), &mut key_code, &mut flags) + }; + if error != CGError::Success { + return Err(Error::CGError(error)); + } + + unsafe { + // If the hotkey is disabled, enable it. + if !private::CGSIsSymbolicHotKeyEnabled(hot_key) { + if private::CGSSetSymbolicHotKeyEnabled(hot_key, true) != CGError::Success { + return Err(Error::CGError(error)); + } + } + } + + let opt_keyboard_event = unsafe { CGEvent::new_keyboard_event(None, key_code, true) }; + unsafe { + // cast is safe (uint -> u64) + CGEvent::set_flags(opt_keyboard_event.as_deref(), CGEventFlags(flags as u64)); + } + + let keyboard_event = opt_keyboard_event.unwrap(); + let event = unsafe { NSEvent::eventWithCGEvent(&keyboard_event) }.unwrap(); + + let keyboard_event_up = unsafe { CGEvent::new_keyboard_event(None, event.keyCode(), false) }; + unsafe { + CGEvent::set_flags(keyboard_event_up.as_deref(), CGEventFlags(0)); + + // Send the shortcut command to get Mission Control to switch spaces from under the window. + CGEvent::post(CGEventTapLocation::HIDEventTap, event.CGEvent().as_deref()); + CGEvent::post( + CGEventTapLocation::HIDEventTap, + keyboard_event_up.as_deref(), + ); + } + + unsafe { + // Let go of the window. + CGEvent::post(CGEventTapLocation::HIDEventTap, mouse_up_event.as_deref()); + } + + Ok(()) +} + +pub(crate) fn get_frontmost_window_origin() -> Result { + let frontmost_window = get_frontmost_window()?; + get_ui_element_origin(&frontmost_window) +} + +pub(crate) fn get_frontmost_window_size() -> Result { + let frontmost_window = get_frontmost_window()?; + get_ui_element_size(&frontmost_window) +} + +pub(crate) fn get_frontmost_window_frame() -> Result { + let origin = get_frontmost_window_origin()?; + let size = get_frontmost_window_size()?; + + Ok(CGRect { origin, size }) +} + +/// Get the frontmost window's close button, then extract its frame. +fn get_frontmost_window_close_button_frame() -> Result { + let window = get_frontmost_window()?; + + let mut ptr_to_close_button: *const CFType = std::ptr::null(); + let ptr_to_buffer = NonNull::new(&mut ptr_to_close_button).unwrap(); + + let close_button_attribute = CFString::from_static_str("AXCloseButton"); + let error = unsafe { window.copy_attribute_value(&close_button_attribute, ptr_to_buffer) }; + if error != AXError::Success { + return Err(Error::AXError(error)); + } + assert!(!ptr_to_close_button.is_null()); + + let close_button_element = ptr_to_close_button.cast::().cast_mut(); + let close_button = unsafe { CFRetained::from_raw(NonNull::new(close_button_element).unwrap()) }; + + let origin = get_ui_element_origin(&close_button)?; + let size = get_ui_element_size(&close_button)?; + + Ok(CGRect { origin, size }) +} + +/// This function returns the "visible frame" [^1] of all the screens. +/// +/// FIXME: This function relies on the [`visibleFrame()`][vf_doc] API, which +/// has 2 bugs we need to work around: +/// +/// 1. It assumes the Dock is on the main display, which in reality depends on +/// how users arrange their displays and the "Dock position on screen" setting +/// entry. +/// 2. For non-main displays, it assumes that they don't have a menu bar, but macOS +/// puts a menu bar on every display. +/// +/// +/// [^1]: Visible frame: a rectangle defines the portion of the screen in which it +/// is currently safe to draw your app’s content. +/// +/// [vf_doc]: https://developer.apple.com/documentation/AppKit/NSScreen/visibleFrame +pub(crate) fn list_visible_frame_of_all_screens() -> Result, Error> { + let main_thread_marker = MainThreadMarker::new().ok_or(Error::NotInMainThread)?; + let screens = NSScreen::screens(main_thread_marker).to_vec(); + + if screens.is_empty() { + return Ok(Vec::new()); + } + + let main_screen = screens.first().expect("screens is not empty"); + + let frames = screens + .iter() + .map(|ns_screen| { + // NSScreen is an AppKit API, which uses unflipped coordinate + // system, flip it + let mut unflipped_frame = ns_screen.visibleFrame(); + let flipped_frame_origin_y = flip_frame_y( + main_screen.frame().size.height, + unflipped_frame.size.height, + unflipped_frame.origin.y, + ); + unflipped_frame.origin.y = flipped_frame_origin_y; + + unflipped_frame + }) + .collect(); + + Ok(frames) +} + +/// Get the Visible frame of the "active screen"[^1]. +/// +/// +/// [^1]: the screen which the frontmost window is on. +pub(crate) fn get_active_screen_visible_frame() -> Result { + let main_thread_marker = MainThreadMarker::new().ok_or(Error::NotInMainThread)?; + + let frontmost_window_frame = get_frontmost_window_frame()?; + + let screens = NSScreen::screens(main_thread_marker) + .into_iter() + .collect::>(); + + if screens.is_empty() { + return Err(Error::NoDisplay); + } + + let main_screen_height = screens[0].frame().size.height; + + // AppKit uses Unflipped Coordinate System, but Accessibility APIs use + // Flipped Coordinate System, we need to flip the origin of these screens. + for screen in screens { + let mut screen_frame = screen.frame(); + let unflipped_y = screen_frame.origin.y; + let flipped_y = flip_frame_y(main_screen_height, screen_frame.size.height, unflipped_y); + screen_frame.origin.y = flipped_y; + + if intersects(screen_frame, frontmost_window_frame) { + let mut visible_frame = screen.visibleFrame(); + let flipped_y = flip_frame_y( + main_screen_height, + visible_frame.size.height, + visible_frame.origin.y, + ); + visible_frame.origin.y = flipped_y; + + return Ok(visible_frame); + } + } + + unreachable!() +} + +/// Move the frontmost window's origin to the point specified by `x` and `y`. +pub fn move_frontmost_window(x: f64, y: f64) -> Result<(), Error> { + let frontmost_window = get_frontmost_window()?; + + let mut point = CGPoint::new(x, y); + let ptr_to_point = NonNull::new((&mut point as *mut CGPoint).cast::()).unwrap(); + let pos_value = unsafe { AXValue::new(AXValueType::CGPoint, ptr_to_point) }.unwrap(); + let pos_attr = CFString::from_static_str("AXPosition"); + + let error = unsafe { frontmost_window.set_attribute_value(&pos_attr, pos_value.deref()) }; + if error != AXError::Success { + return Err(Error::AXError(error)); + } + + Ok(()) +} + +/// Set the frontmost window's frame to the specified frame - adjust size and +/// location at the same time. +pub fn set_frontmost_window_frame(frame: CGRect) -> Result<(), Error> { + let frontmost_window = get_frontmost_window()?; + + let mut point = frame.origin; + let ptr_to_point = NonNull::new((&mut point as *mut CGPoint).cast::()).unwrap(); + let pos_value = unsafe { AXValue::new(AXValueType::CGPoint, ptr_to_point) }.unwrap(); + let pos_attr = CFString::from_static_str("AXPosition"); + + let error = unsafe { frontmost_window.set_attribute_value(&pos_attr, pos_value.deref()) }; + if error != AXError::Success { + return Err(Error::AXError(error)); + } + + let mut size = frame.size; + let ptr_to_size = NonNull::new((&mut size as *mut CGSize).cast::()).unwrap(); + let size_value = unsafe { AXValue::new(AXValueType::CGSize, ptr_to_size) }.unwrap(); + let size_attr = CFString::from_static_str("AXSize"); + + let error = unsafe { frontmost_window.set_attribute_value(&size_attr, size_value.deref()) }; + if error != AXError::Success { + return Err(Error::AXError(error)); + } + + Ok(()) +} + +pub fn toggle_fullscreen() -> Result<(), Error> { + let frontmost_window = get_frontmost_window()?; + let fullscreen_attr = CFString::from_static_str("AXFullScreen"); + + let mut current_value_ref: *const CFType = std::ptr::null(); + let error = unsafe { + frontmost_window.copy_attribute_value( + &fullscreen_attr, + NonNull::new(&mut current_value_ref).unwrap(), + ) + }; + + // TODO: If the attribute doesn't exist, error won't be Success as well. + // Before we handle that, we need to know the error case that will be + // returned in that case. + if error != AXError::Success { + return Err(Error::AXError(error)); + } + assert!(!current_value_ref.is_null()); + + let current_value = unsafe { + let retained_boolean: CFRetained = CFRetained::from_raw( + NonNull::new(current_value_ref.cast::().cast_mut()).unwrap(), + ); + retained_boolean.as_bool() + }; + + let new_value = !current_value; + let new_value_ref: CFRetained = CFBoolean::new(new_value).retain(); + + let error = + unsafe { frontmost_window.set_attribute_value(&fullscreen_attr, new_value_ref.deref()) }; + + if error != AXError::Success { + return Err(Error::AXError(error)); + } + + Ok(()) +} + +static LAST_FRAME: LazyLock>> = + LazyLock::new(|| Mutex::new(HashMap::new())); + +pub(crate) fn set_frontmost_window_last_frame(window_id: CGWindowID, frame: CGRect) { + let mut map = LAST_FRAME.lock().unwrap(); + map.insert(window_id, frame); +} + +pub(crate) fn get_frontmost_window_last_frame(window_id: CGWindowID) -> Option { + let map = LAST_FRAME.lock().unwrap(); + map.get(&window_id).cloned() +} diff --git a/src-tauri/src/extension/built_in/window_management/backend/private.rs b/src-tauri/src/extension/built_in/window_management/backend/private.rs new file mode 100644 index 00000000..78054d7b --- /dev/null +++ b/src-tauri/src/extension/built_in/window_management/backend/private.rs @@ -0,0 +1,70 @@ +//! Private macOS APIs. + +use bitflags::bitflags; +use objc2_application_services::AXError; +use objc2_application_services::AXUIElement; +use objc2_core_foundation::CFArray; +use objc2_core_graphics::CGError; +use objc2_core_graphics::CGWindowID; +use std::ffi::c_int; +use std::ffi::c_uint; +use std::ffi::c_ushort; + +pub(crate) type CGSConnectionID = u32; +pub(crate) type CGSSpaceID = c_int; + +bitflags! { + #[derive(Debug, Copy, Clone, PartialEq, Eq)] + #[repr(transparent)] + pub struct CGSSpaceMask: c_int { + const INCLUDE_CURRENT = 1 << 0; + const INCLUDE_OTHERS = 1 << 1; + + const INCLUDE_USER = 1 << 2; + const INCLUDE_OS = 1 << 3; + + const VISIBLE = 1 << 16; + + const CURRENT_SPACES = Self::INCLUDE_USER.bits() | Self::INCLUDE_CURRENT.bits(); + const OTHER_SPACES = Self::INCLUDE_USER.bits() | Self::INCLUDE_OTHERS.bits(); + const ALL_SPACES = + Self::INCLUDE_USER.bits() | Self::INCLUDE_OTHERS.bits() | Self::INCLUDE_CURRENT.bits(); + + const ALL_VISIBLE_SPACES = Self::ALL_SPACES.bits() | Self::VISIBLE.bits(); + + const CURRENT_OS_SPACES = Self::INCLUDE_OS.bits() | Self::INCLUDE_CURRENT.bits(); + const OTHER_OS_SPACES = Self::INCLUDE_OS.bits() | Self::INCLUDE_OTHERS.bits(); + const ALL_OS_SPACES = + Self::INCLUDE_OS.bits() | Self::INCLUDE_OTHERS.bits() | Self::INCLUDE_CURRENT.bits(); + } +} + +unsafe extern "C" { + /// Extract `window_id` from an AXUIElement. + pub(crate) fn _AXUIElementGetWindow( + elem: *mut AXUIElement, + window_id: *mut CGWindowID, + ) -> AXError; + + /// Connect to the WindowServer and get a connection descriptor. + pub(crate) fn CGSMainConnectionID() -> CGSConnectionID; + + /// It returns a CFArray of dictionaries. Each dictionary contains information + /// about a display, including a list of all the spaces (CGSSpaceID) on that display. + pub(crate) fn CGSCopyManagedDisplaySpaces(cid: CGSConnectionID) -> *mut CFArray; + + /// Gets the ID of the space currently visible to the user. + pub(crate) fn CGSGetActiveSpace(cid: CGSConnectionID) -> CGSSpaceID; + + /// Returns the values the symbolic hot key represented by the given UID is configured with. + pub(crate) fn CGSGetSymbolicHotKeyValue( + hotKey: c_ushort, + outKeyEquivalent: *mut c_ushort, + outVirtualKeyCode: *mut c_ushort, + outModifiers: *mut c_uint, + ) -> CGError; + /// Returns whether the symbolic hot key represented by the given UID is enabled. + pub(crate) fn CGSIsSymbolicHotKeyEnabled(hotKey: c_ushort) -> bool; + /// Sets whether the symbolic hot key represented by the given UID is enabled. + pub(crate) fn CGSSetSymbolicHotKeyEnabled(hotKey: c_ushort, isEnabled: bool) -> CGError; +} diff --git a/src-tauri/src/extension/built_in/window_management/error.rs b/src-tauri/src/extension/built_in/window_management/error.rs new file mode 100644 index 00000000..dc5505db --- /dev/null +++ b/src-tauri/src/extension/built_in/window_management/error.rs @@ -0,0 +1,25 @@ +use objc2_application_services::AXError; +use objc2_core_graphics::CGError; +use thiserror::Error; + +#[derive(Debug, Error)] +pub enum Error { + /// Cannot find the focused window. + #[error("Cannot find the focused window.")] + CannotFindFocusWindow, + /// Error code from the macOS Accessibility APIs. + #[error("Error code from the macOS Accessibility APIs: {0:?}")] + AXError(AXError), + /// Function should be in called from the main thread, but it is not. + #[error("Function should be in called from the main thread, but it is not.")] + NotInMainThread, + /// No monitor detected. + #[error("No monitor detected.")] + NoDisplay, + /// Can only handle 16 Workspaces at most. + #[error("libwmgr can only handle 16 Workspaces at most.")] + TooManyWorkspace, + /// Error code from the macOS Core Graphics APIs. + #[error("Error code from the macOS Core Graphics APIs: {0:?}")] + CGError(CGError), +} diff --git a/src-tauri/src/extension/built_in/window_management/mod.rs b/src-tauri/src/extension/built_in/window_management/mod.rs new file mode 100644 index 00000000..bff19e05 --- /dev/null +++ b/src-tauri/src/extension/built_in/window_management/mod.rs @@ -0,0 +1,973 @@ +pub(crate) mod actions; +mod backend; +mod error; +pub(crate) mod on_opened; +pub(crate) mod search_source; + +use crate::common::document::open; +use crate::extension::Extension; +use actions::Action; +use backend::get_active_screen_visible_frame; +use backend::get_frontmost_window_frame; +use backend::get_frontmost_window_id; +use backend::get_frontmost_window_last_frame; +use backend::get_next_workspace_logical_id; +use backend::get_previous_workspace_logical_id; +use backend::list_visible_frame_of_all_screens; +use backend::move_frontmost_window; +use backend::move_frontmost_window_to_workspace; +use backend::set_frontmost_window_frame; +use backend::set_frontmost_window_last_frame; +use backend::toggle_fullscreen; +use error::Error; +use objc2_core_foundation::{CGPoint, CGRect, CGSize}; +use oneshot::channel as oneshot_channel; +use tauri::AppHandle; +use tauri::async_runtime; +use tauri_plugin_global_shortcut::GlobalShortcutExt; +use tauri_plugin_global_shortcut::ShortcutState; + +pub(crate) const EXTENSION_ID: &str = "Window Management"; + +/// JSON file for this extension. +pub(crate) const PLUGIN_JSON_FILE: &str = include_str!("./plugin.json"); + +pub(crate) fn perform_action_on_main_thread( + tauri_app_handle: &AppHandle, + action: Action, +) -> Result<(), String> { + let (tx, rx) = oneshot_channel(); + + tauri_app_handle + .run_on_main_thread(move || { + let res = perform_action(action).map_err(|e| e.to_string()); + tx.send(res) + .expect("oneshot channel receiver unexpectedly dropped"); + }) + .expect("tauri internal bug, channel receiver dropped"); + + rx.recv() + .expect("oneshot channel sender unexpectedly dropped before sending function return value") +} + +/// Perform this action to the focused window. +fn perform_action(action: Action) -> Result<(), Error> { + let visible_frame = get_active_screen_visible_frame()?; + let frontmost_window_id = get_frontmost_window_id()?; + let frontmost_window_frame = get_frontmost_window_frame()?; + + set_frontmost_window_last_frame(frontmost_window_id, frontmost_window_frame); + + match action { + Action::TopHalf => { + let origin = CGPoint { + x: visible_frame.origin.x, + y: visible_frame.origin.y, + }; + let size = CGSize { + width: visible_frame.size.width, + height: visible_frame.size.height / 2.0, + }; + let new_frame = CGRect { origin, size }; + set_frontmost_window_frame(new_frame) + } + Action::BottomHalf => { + let origin = CGPoint { + x: visible_frame.origin.x, + y: visible_frame.origin.y + visible_frame.size.height / 2.0, + }; + let size = CGSize { + width: visible_frame.size.width, + height: visible_frame.size.height / 2.0, + }; + let new_frame = CGRect { origin, size }; + set_frontmost_window_frame(new_frame) + } + Action::LeftHalf => { + let origin = CGPoint { + x: visible_frame.origin.x, + y: visible_frame.origin.y, + }; + let size = CGSize { + width: visible_frame.size.width / 2.0, + height: visible_frame.size.height, + }; + let new_frame = CGRect { origin, size }; + set_frontmost_window_frame(new_frame) + } + Action::RightHalf => { + let origin = CGPoint { + x: visible_frame.origin.x + visible_frame.size.width / 2.0, + y: visible_frame.origin.y, + }; + let size = CGSize { + width: visible_frame.size.width / 2.0, + height: visible_frame.size.height, + }; + let new_frame = CGRect { origin, size }; + set_frontmost_window_frame(new_frame) + } + Action::CenterHalf => { + let origin = CGPoint { + x: visible_frame.origin.x + visible_frame.size.width / 4.0, + y: visible_frame.origin.y, + }; + let size = CGSize { + width: visible_frame.size.width / 2.0, + height: visible_frame.size.height, + }; + let new_frame = CGRect { origin, size }; + set_frontmost_window_frame(new_frame) + } + Action::TopLeftQuarter => { + let origin = visible_frame.origin; + let size = CGSize { + width: visible_frame.size.width / 2.0, + height: visible_frame.size.height / 2.0, + }; + let new_frame = CGRect { origin, size }; + set_frontmost_window_frame(new_frame) + } + Action::TopRightQuarter => { + let origin = CGPoint { + x: visible_frame.origin.x + visible_frame.size.width / 2.0, + y: visible_frame.origin.y, + }; + let size = CGSize { + width: visible_frame.size.width / 2.0, + height: visible_frame.size.height / 2.0, + }; + let new_frame = CGRect { origin, size }; + set_frontmost_window_frame(new_frame) + } + Action::BottomLeftQuarter => { + let origin = CGPoint { + x: visible_frame.origin.x, + y: visible_frame.origin.y + visible_frame.size.height / 2.0, + }; + let size = CGSize { + width: visible_frame.size.width / 2.0, + height: visible_frame.size.height / 2.0, + }; + let new_frame = CGRect { origin, size }; + set_frontmost_window_frame(new_frame) + } + Action::BottomRightQuarter => { + let origin = CGPoint { + x: visible_frame.origin.x + visible_frame.size.width / 2.0, + y: visible_frame.origin.y + visible_frame.size.height / 2.0, + }; + let size = CGSize { + width: visible_frame.size.width / 2.0, + height: visible_frame.size.height / 2.0, + }; + let new_frame = CGRect { origin, size }; + set_frontmost_window_frame(new_frame) + } + Action::TopLeftSixth => { + let origin = visible_frame.origin; + let size = CGSize { + width: visible_frame.size.width / 3.0, + height: visible_frame.size.height / 2.0, + }; + let new_frame = CGRect { origin, size }; + set_frontmost_window_frame(new_frame) + } + Action::TopCenterSixth => { + let origin = CGPoint { + x: visible_frame.origin.x + visible_frame.size.width / 3.0, + y: visible_frame.origin.y, + }; + let size = CGSize { + width: visible_frame.size.width / 3.0, + height: visible_frame.size.height / 2.0, + }; + let new_frame = CGRect { origin, size }; + set_frontmost_window_frame(new_frame) + } + Action::TopRightSixth => { + let origin = CGPoint { + x: visible_frame.origin.x + visible_frame.size.width * 2.0 / 3.0, + y: visible_frame.origin.y, + }; + let size = CGSize { + width: visible_frame.size.width / 3.0, + height: visible_frame.size.height / 2.0, + }; + let new_frame = CGRect { origin, size }; + set_frontmost_window_frame(new_frame) + } + Action::BottomLeftSixth => { + let origin = CGPoint { + x: visible_frame.origin.x, + y: visible_frame.origin.y + visible_frame.size.height / 2.0, + }; + let size = CGSize { + width: visible_frame.size.width / 3.0, + height: visible_frame.size.height / 2.0, + }; + let new_frame = CGRect { origin, size }; + set_frontmost_window_frame(new_frame) + } + Action::BottomCenterSixth => { + let origin = CGPoint { + x: visible_frame.origin.x + visible_frame.size.width / 3.0, + y: visible_frame.origin.y + visible_frame.size.height / 2.0, + }; + let size = CGSize { + width: visible_frame.size.width / 3.0, + height: visible_frame.size.height / 2.0, + }; + let new_frame = CGRect { origin, size }; + set_frontmost_window_frame(new_frame) + } + Action::BottomRightSixth => { + let origin = CGPoint { + x: visible_frame.origin.x + visible_frame.size.width * 2.0 / 3.0, + y: visible_frame.origin.y + visible_frame.size.height / 2.0, + }; + let size = CGSize { + width: visible_frame.size.width / 3.0, + height: visible_frame.size.height / 2.0, + }; + let new_frame = CGRect { origin, size }; + set_frontmost_window_frame(new_frame) + } + Action::TopThird => { + let origin = visible_frame.origin; + let size = CGSize { + width: visible_frame.size.width, + height: visible_frame.size.height / 3.0, + }; + let new_frame = CGRect { origin, size }; + set_frontmost_window_frame(new_frame) + } + Action::MiddleThird => { + let origin = CGPoint { + x: visible_frame.origin.x, + y: visible_frame.origin.y + visible_frame.size.height / 3.0, + }; + let size = CGSize { + width: visible_frame.size.width, + height: visible_frame.size.height / 3.0, + }; + let new_frame = CGRect { origin, size }; + set_frontmost_window_frame(new_frame) + } + Action::BottomThird => { + let origin = CGPoint { + x: visible_frame.origin.x, + y: visible_frame.origin.y + visible_frame.size.height * 2.0 / 3.0, + }; + let size = CGSize { + width: visible_frame.size.width, + height: visible_frame.size.height / 3.0, + }; + let new_frame = CGRect { origin, size }; + set_frontmost_window_frame(new_frame) + } + Action::Center => { + let window_size = frontmost_window_frame.size; + let origin = CGPoint { + x: visible_frame.origin.x + (visible_frame.size.width - window_size.width) / 2.0, + y: visible_frame.origin.y + (visible_frame.size.height - window_size.height) / 2.0, + }; + move_frontmost_window(origin.x, origin.y) + } + Action::FirstFourth => { + let origin = visible_frame.origin; + let size = CGSize { + width: visible_frame.size.width / 4.0, + height: visible_frame.size.height, + }; + let new_frame = CGRect { origin, size }; + set_frontmost_window_frame(new_frame) + } + Action::SecondFourth => { + let origin = CGPoint { + x: visible_frame.origin.x + visible_frame.size.width / 4.0, + y: visible_frame.origin.y, + }; + let size = CGSize { + width: visible_frame.size.width / 4.0, + height: visible_frame.size.height, + }; + let new_frame = CGRect { origin, size }; + set_frontmost_window_frame(new_frame) + } + Action::ThirdFourth => { + let origin = CGPoint { + x: visible_frame.origin.x + visible_frame.size.width * 2.0 / 4.0, + y: visible_frame.origin.y, + }; + let size = CGSize { + width: visible_frame.size.width / 4.0, + height: visible_frame.size.height, + }; + let new_frame = CGRect { origin, size }; + set_frontmost_window_frame(new_frame) + } + Action::LastFourth => { + let origin = CGPoint { + x: visible_frame.origin.x + visible_frame.size.width * 3.0 / 4.0, + y: visible_frame.origin.y, + }; + let size = CGSize { + width: visible_frame.size.width / 4.0, + height: visible_frame.size.height, + }; + let new_frame = CGRect { origin, size }; + set_frontmost_window_frame(new_frame) + } + Action::FirstThird => { + let origin = CGPoint { + x: visible_frame.origin.x, + y: visible_frame.origin.y, + }; + let size = CGSize { + width: visible_frame.size.width / 3.0, + height: visible_frame.size.height, + }; + let new_frame = CGRect { origin, size }; + set_frontmost_window_frame(new_frame) + } + Action::CenterThird => { + let origin = CGPoint { + x: visible_frame.origin.x + visible_frame.size.width / 3.0, + y: visible_frame.origin.y, + }; + let size = CGSize { + width: visible_frame.size.width / 3.0, + height: visible_frame.size.height, + }; + let new_frame = CGRect { origin, size }; + set_frontmost_window_frame(new_frame) + } + Action::LastThird => { + let origin = CGPoint { + x: visible_frame.origin.x + visible_frame.size.width * 2.0 / 3.0, + y: visible_frame.origin.y, + }; + let size = CGSize { + width: visible_frame.size.width / 3.0, + height: visible_frame.size.height, + }; + let new_frame = CGRect { origin, size }; + set_frontmost_window_frame(new_frame) + } + Action::FirstTwoThirds => { + let origin = CGPoint { + x: visible_frame.origin.x, + y: visible_frame.origin.y, + }; + let size = CGSize { + width: visible_frame.size.width * 2.0 / 3.0, + height: visible_frame.size.height, + }; + let new_frame = CGRect { origin, size }; + set_frontmost_window_frame(new_frame) + } + Action::CenterTwoThirds => { + let origin = CGPoint { + x: visible_frame.origin.x + visible_frame.size.width / 6.0, + y: visible_frame.origin.y, + }; + let size = CGSize { + width: visible_frame.size.width * 2.0 / 3.0, + height: visible_frame.size.height, + }; + let new_frame = CGRect { origin, size }; + set_frontmost_window_frame(new_frame) + } + Action::LastTwoThirds => { + let origin = CGPoint { + x: visible_frame.origin.x + visible_frame.size.width / 3.0, + y: visible_frame.origin.y, + }; + let size = CGSize { + width: visible_frame.size.width * 2.0 / 3.0, + height: visible_frame.size.height, + }; + let new_frame = CGRect { origin, size }; + set_frontmost_window_frame(new_frame) + } + Action::FirstThreeFourths => { + let origin = CGPoint { + x: visible_frame.origin.x, + y: visible_frame.origin.y, + }; + let size = CGSize { + width: visible_frame.size.width * 3.0 / 4.0, + height: visible_frame.size.height, + }; + let new_frame = CGRect { origin, size }; + set_frontmost_window_frame(new_frame) + } + Action::CenterThreeFourths => { + let origin = CGPoint { + x: visible_frame.origin.x + visible_frame.size.width / 8.0, + y: visible_frame.origin.y, + }; + let size = CGSize { + width: visible_frame.size.width * 3.0 / 4.0, + height: visible_frame.size.height, + }; + let new_frame = CGRect { origin, size }; + set_frontmost_window_frame(new_frame) + } + Action::LastThreeFourths => { + let origin = CGPoint { + x: visible_frame.origin.x + visible_frame.size.width / 4.0, + y: visible_frame.origin.y, + }; + let size = CGSize { + width: visible_frame.size.width * 3.0 / 4.0, + height: visible_frame.size.height, + }; + let new_frame = CGRect { origin, size }; + set_frontmost_window_frame(new_frame) + } + Action::TopThreeFourths => { + let origin = CGPoint { + x: visible_frame.origin.x, + y: visible_frame.origin.y, + }; + let size = CGSize { + width: visible_frame.size.width, + height: visible_frame.size.height * 3.0 / 4.0, + }; + let new_frame = CGRect { origin, size }; + set_frontmost_window_frame(new_frame) + } + Action::BottomThreeFourths => { + let origin = CGPoint { + x: visible_frame.origin.x, + y: visible_frame.origin.y + visible_frame.size.height / 4.0, + }; + let size = CGSize { + width: visible_frame.size.width, + height: visible_frame.size.height * 3.0 / 4.0, + }; + let new_frame = CGRect { origin, size }; + set_frontmost_window_frame(new_frame) + } + Action::TopTwoThirds => { + let origin = CGPoint { + x: visible_frame.origin.x, + y: visible_frame.origin.y, + }; + let size = CGSize { + width: visible_frame.size.width, + height: visible_frame.size.height * 2.0 / 3.0, + }; + let new_frame = CGRect { origin, size }; + set_frontmost_window_frame(new_frame) + } + Action::BottomTwoThirds => { + let origin = CGPoint { + x: visible_frame.origin.x, + y: visible_frame.origin.y + visible_frame.size.height / 3.0, + }; + let size = CGSize { + width: visible_frame.size.width, + height: visible_frame.size.height * 2.0 / 3.0, + }; + let new_frame = CGRect { origin, size }; + set_frontmost_window_frame(new_frame) + } + + Action::TopCenterTwoThirds => { + let origin = CGPoint { + x: visible_frame.origin.x + visible_frame.size.width / 6.0, + y: visible_frame.origin.y, + }; + let size = CGSize { + width: visible_frame.size.width * 2.0 / 3.0, + height: visible_frame.size.height * 2.0 / 3.0, + }; + let new_frame = CGRect { origin, size }; + set_frontmost_window_frame(new_frame) + } + Action::TopFirstFourth => { + let origin = CGPoint { + x: visible_frame.origin.x, + y: visible_frame.origin.y, + }; + let size = CGSize { + width: visible_frame.size.width, + height: visible_frame.size.height / 4.0, + }; + let new_frame = CGRect { origin, size }; + set_frontmost_window_frame(new_frame) + } + Action::TopSecondFourth => { + let origin = CGPoint { + x: visible_frame.origin.x, + y: visible_frame.origin.y + visible_frame.size.height / 4.0, + }; + let size = CGSize { + width: visible_frame.size.width, + height: visible_frame.size.height / 4.0, + }; + let new_frame = CGRect { origin, size }; + set_frontmost_window_frame(new_frame) + } + Action::TopThirdFourth => { + let origin = CGPoint { + x: visible_frame.origin.x, + y: visible_frame.origin.y + visible_frame.size.height * 2.0 / 4.0, + }; + let size = CGSize { + width: visible_frame.size.width, + height: visible_frame.size.height / 4.0, + }; + let new_frame = CGRect { origin, size }; + set_frontmost_window_frame(new_frame) + } + Action::TopLastFourth => { + let origin = CGPoint { + x: visible_frame.origin.x, + y: visible_frame.origin.y + visible_frame.size.height * 3.0 / 4.0, + }; + let size = CGSize { + width: visible_frame.size.width, + height: visible_frame.size.height / 4.0, + }; + let new_frame = CGRect { origin, size }; + set_frontmost_window_frame(new_frame) + } + Action::MakeLarger => { + let window_origin = frontmost_window_frame.origin; + let window_size = frontmost_window_frame.size; + let delta_width = 20_f64; + let delta_height = window_size.height / window_size.width * delta_width; + let delta_origin_x = delta_width / 2.0; + let delta_origin_y = delta_height / 2.0; + + let new_width = { + let possible_value = window_size.width + delta_width; + if possible_value > visible_frame.size.width { + visible_frame.size.width + } else { + possible_value + } + }; + let new_height = { + let possible_value = window_size.height + delta_height; + if possible_value > visible_frame.size.height { + visible_frame.size.height + } else { + possible_value + } + }; + + let new_origin_x = { + let possible_value = window_origin.x - delta_origin_x; + if possible_value < visible_frame.origin.x { + visible_frame.origin.x + } else { + possible_value + } + }; + let new_origin_y = { + let possible_value = window_origin.y - delta_origin_y; + if possible_value < visible_frame.origin.y { + visible_frame.origin.y + } else { + possible_value + } + }; + + let origin = CGPoint { + x: new_origin_x, + y: new_origin_y, + }; + let size = CGSize { + width: new_width, + height: new_height, + }; + let new_frame = CGRect { origin, size }; + set_frontmost_window_frame(new_frame) + } + Action::MakeSmaller => { + let window_origin = frontmost_window_frame.origin; + let window_size = frontmost_window_frame.size; + + let delta_width = 20_f64; + let delta_height = window_size.height / window_size.width * delta_width; + + let delta_origin_x = delta_width / 2.0; + let delta_origin_y = delta_height / 2.0; + + let origin = CGPoint { + x: window_origin.x + delta_origin_x, + y: window_origin.y + delta_origin_y, + }; + let size = CGSize { + width: window_size.width - delta_width, + height: window_size.height - delta_height, + }; + let new_frame = CGRect { origin, size }; + set_frontmost_window_frame(new_frame) + } + Action::AlmostMaximize => { + let new_size = CGSize { + width: visible_frame.size.width * 0.9, + height: visible_frame.size.height * 0.9, + }; + let new_origin = CGPoint { + x: visible_frame.origin.x + (visible_frame.size.width * 0.1), + y: visible_frame.origin.y + (visible_frame.size.height * 0.1), + }; + let new_frame = CGRect { + origin: new_origin, + size: new_size, + }; + set_frontmost_window_frame(new_frame) + } + Action::Maximize => { + let new_frame = CGRect { + origin: visible_frame.origin, + size: visible_frame.size, + }; + set_frontmost_window_frame(new_frame) + } + Action::MaximizeWidth => { + let window_origin = frontmost_window_frame.origin; + let window_size = frontmost_window_frame.size; + let origin = CGPoint { + x: visible_frame.origin.x, + y: window_origin.y, + }; + let size = CGSize { + width: visible_frame.size.width, + height: window_size.height, + }; + + let new_frame = CGRect { origin, size }; + set_frontmost_window_frame(new_frame) + } + Action::MaximizeHeight => { + let window_origin = frontmost_window_frame.origin; + let window_size = frontmost_window_frame.size; + let origin = CGPoint { + x: window_origin.x, + y: visible_frame.origin.y, + }; + let size = CGSize { + width: window_size.width, + height: visible_frame.size.height, + }; + + let new_frame = CGRect { origin, size }; + set_frontmost_window_frame(new_frame) + } + Action::MoveUp => { + let window_origin = frontmost_window_frame.origin; + let new_y = (window_origin.y - 10.0).max(visible_frame.origin.y); + move_frontmost_window(window_origin.x, new_y) + } + Action::MoveDown => { + let window_origin = frontmost_window_frame.origin; + let window_size = frontmost_window_frame.size; + let new_y = (window_origin.y + 10.0) + .min(visible_frame.origin.y + visible_frame.size.height - window_size.height); + move_frontmost_window(window_origin.x, new_y) + } + Action::MoveLeft => { + let window_origin = frontmost_window_frame.origin; + let new_x = (window_origin.x - 10.0).max(visible_frame.origin.x); + move_frontmost_window(new_x, window_origin.y) + } + Action::MoveRight => { + let window_origin = frontmost_window_frame.origin; + let window_size = frontmost_window_frame.size; + let new_x = (window_origin.x + 10.0) + .min(visible_frame.origin.x + visible_frame.size.width - window_size.width); + move_frontmost_window(new_x, window_origin.y) + } + Action::NextDesktop => { + let Some(next_workspace_logical_id) = get_next_workspace_logical_id() else { + // nothing to do + return Ok(()); + }; + + move_frontmost_window_to_workspace(next_workspace_logical_id) + } + Action::PreviousDesktop => { + let Some(previous_workspace_logical_id) = get_previous_workspace_logical_id() else { + // nothing to do + return Ok(()); + }; + + // Now let's switch the workspace + move_frontmost_window_to_workspace(previous_workspace_logical_id) + } + Action::NextDisplay => { + const TOO_MANY_MONITORS: &str = "I don't think you can have so many monitors"; + + let frames = list_visible_frame_of_all_screens()?; + let n_frames = frames.len(); + if n_frames == 0 { + return Err(Error::NoDisplay); + } + if n_frames == 1 { + return Ok(()); + } + + let index = frames + .iter() + .position(|fr| fr == &visible_frame) + .expect("active screen should be in the list"); + let new_index: usize = { + let index_i32: i32 = index.try_into().expect(TOO_MANY_MONITORS); + let index_i32_plus_one = index_i32.checked_add(1).expect(TOO_MANY_MONITORS); + let final_value = index_i32_plus_one % n_frames as i32; + + final_value + .try_into() + .expect("final value should be positive") + }; + + let new_frame = frames[new_index]; + + set_frontmost_window_frame(new_frame) + } + Action::PreviousDisplay => { + const TOO_MANY_MONITORS: &str = "I don't think you can have so many monitors"; + + let frames = list_visible_frame_of_all_screens()?; + let n_frames = frames.len(); + if n_frames == 0 { + return Err(Error::NoDisplay); + } + if n_frames == 1 { + return Ok(()); + } + let index = frames + .iter() + .position(|fr| fr == &visible_frame) + .expect("active screen should be in the list"); + let new_index: usize = { + let index_i32: i32 = index.try_into().expect(TOO_MANY_MONITORS); + let index_i32_minus_one = index_i32 - 1; + let n_frames_i32: i32 = n_frames.try_into().expect(TOO_MANY_MONITORS); + let final_value = (index_i32_minus_one + n_frames_i32) % n_frames_i32; + + final_value + .try_into() + .expect("final value should be positive") + }; + + let new_frame = frames[new_index]; + + set_frontmost_window_frame(new_frame) + } + Action::Restore => { + let Some(previous_frame) = get_frontmost_window_last_frame(frontmost_window_id) else { + // Previous frame found, Nothing to do + return Ok(()); + }; + + set_frontmost_window_frame(previous_frame) + } + Action::ToggleFullscreen => toggle_fullscreen(), + } +} + +pub(crate) fn set_up_commands_hotkeys( + tauri_app_handle: &AppHandle, + wm_extension: &Extension, +) -> Result<(), String> { + for command in wm_extension + .commands + .as_ref() + .expect("Window Management extension has commands") + .iter() + .filter(|cmd| cmd.enabled) + { + if let Some(ref hotkey) = command.hotkey { + let on_opened = on_opened::on_opened(&command.id); + + let extension_id_clone = command.id.clone(); + + tauri_app_handle + .global_shortcut() + .on_shortcut(hotkey.as_str(), move |tauri_app_handle, _hotkey, event| { + let on_opened_clone = on_opened.clone(); + let extension_id_clone = extension_id_clone.clone(); + let app_handle_clone = tauri_app_handle.clone(); + + if event.state() == ShortcutState::Pressed { + async_runtime::spawn(async move { + let result = open(app_handle_clone, on_opened_clone, None).await; + if let Err(msg) = result { + log::warn!( + "failed to open extension [{}], error [{}]", + extension_id_clone, + msg + ); + } + }); + } + }) + .map_err(|e| e.to_string())?; + } + } + + Ok(()) +} + +pub(crate) fn unset_commands_hotkeys( + tauri_app_handle: &AppHandle, + wm_extension: &Extension, +) -> Result<(), String> { + for command in wm_extension + .commands + .as_ref() + .expect("Window Management extension has commands") + .iter() + .filter(|cmd| cmd.enabled) + { + if let Some(ref hotkey) = command.hotkey { + tauri_app_handle + .global_shortcut() + .unregister(hotkey.as_str()) + .map_err(|e| e.to_string())?; + } + } + + Ok(()) +} + +pub(crate) fn set_up_command_hotkey( + tauri_app_handle: &AppHandle, + wm_extension: &Extension, + command_id: &str, +) -> Result<(), String> { + let commands = wm_extension + .commands + .as_ref() + .expect("Window Management has commands"); + let opt_command = commands.iter().find(|ext| ext.id == command_id); + + let Some(command) = opt_command else { + panic!("Window Management command does not exist {}", command_id); + }; + + if let Some(ref hotkey) = command.hotkey { + let on_opened = on_opened::on_opened(&command.id); + + let extension_id_clone = command.id.clone(); + + tauri_app_handle + .global_shortcut() + .on_shortcut(hotkey.as_str(), move |tauri_app_handle, _hotkey, event| { + let on_opened_clone = on_opened.clone(); + let extension_id_clone = extension_id_clone.clone(); + let app_handle_clone = tauri_app_handle.clone(); + + if event.state() == ShortcutState::Pressed { + async_runtime::spawn(async move { + let result = open(app_handle_clone, on_opened_clone, None).await; + if let Err(msg) = result { + log::warn!( + "failed to open extension [{}], error [{}]", + extension_id_clone, + msg + ); + } + }); + } + }) + .map_err(|e| e.to_string())?; + } + + Ok(()) +} + +pub(crate) fn unset_command_hotkey( + tauri_app_handle: &AppHandle, + wm_extension: &Extension, + command_id: &str, +) -> Result<(), String> { + let commands = wm_extension + .commands + .as_ref() + .expect("Window Management has commands"); + let opt_command = commands.iter().find(|ext| ext.id == command_id); + + let Some(command) = opt_command else { + panic!("Window Management command does not exist {}", command_id); + }; + + if let Some(ref hotkey) = command.hotkey { + tauri_app_handle + .global_shortcut() + .unregister(hotkey.as_str()) + .map_err(|e| e.to_string())?; + } + + Ok(()) +} + +pub(crate) fn register_command_hotkey( + tauri_app_handle: &AppHandle, + command_id: &str, + hotkey: &str, +) -> Result<(), String> { + let on_opened = on_opened::on_opened(&command_id); + + let extension_id_clone = command_id.to_string(); + + tauri_app_handle + .global_shortcut() + .on_shortcut(hotkey, move |tauri_app_handle, _hotkey, event| { + let on_opened_clone = on_opened.clone(); + let extension_id_clone = extension_id_clone.clone(); + let app_handle_clone = tauri_app_handle.clone(); + + if event.state() == ShortcutState::Pressed { + async_runtime::spawn(async move { + let result = open(app_handle_clone, on_opened_clone, None).await; + if let Err(msg) = result { + log::warn!( + "failed to open extension [{}], error [{}]", + extension_id_clone, + msg + ); + } + }); + } + }) + .map_err(|e| e.to_string())?; + + Ok(()) +} + +pub(crate) fn unregister_command_hotkey( + tauri_app_handle: &AppHandle, + wm_extension: &Extension, + command_id: &str, +) -> Result<(), String> { + let commands = wm_extension + .commands + .as_ref() + .expect("Window Management has commands"); + let opt_command = commands.iter().find(|ext| ext.id == command_id); + + let Some(command) = opt_command else { + panic!("Window Management command does not exist {}", command_id); + }; + + let Some(ref hotkey) = command.hotkey else { + return Ok(()); + }; + + tauri_app_handle + .global_shortcut() + .unregister(hotkey.as_str()) + .map_err(|e| e.to_string())?; + + Ok(()) +} diff --git a/src-tauri/src/extension/built_in/window_management/on_opened.rs b/src-tauri/src/extension/built_in/window_management/on_opened.rs new file mode 100644 index 00000000..73d4f62c --- /dev/null +++ b/src-tauri/src/extension/built_in/window_management/on_opened.rs @@ -0,0 +1,10 @@ +use super::actions::Action; +use crate::common::document::OnOpened; +use serde_plain; + +pub(crate) fn on_opened(command_id: &str) -> OnOpened { + let action: Action = serde_plain::from_str(command_id).unwrap_or_else(|_| { + panic!("Window Management commands IDs should be valid for `enum Action`, someone corrupts the JSON file"); + }); + OnOpened::WindowManagementAction { action } +} diff --git a/src-tauri/src/extension/built_in/window_management/plugin.json b/src-tauri/src/extension/built_in/window_management/plugin.json new file mode 100644 index 00000000..d153343b --- /dev/null +++ b/src-tauri/src/extension/built_in/window_management/plugin.json @@ -0,0 +1,415 @@ +{ + "id": "Window Management", + "name": "Window Management", + "platforms": [ + "macos" + ], + "description": "Resize, reorganize and move your focused window effortlessly", + "icon": "font_WindowManagement", + "type": "extension", + "category": "Utilities", + "tags": [ + "Productivity" + ], + "commands": [ + { + "id": "TopHalf", + "name": "Top Half", + "description": "Move the focused window to fill left half of the screen.", + "icon": "font_TopHalf", + "type": "command" + }, + { + "id": "BottomHalf", + "name": "Bottom Half", + "description": "Move the focused window to fill bottom half of the screen.", + "icon": "font_BottomHalf", + "type": "command" + }, + { + "id": "LeftHalf", + "name": "Left Half", + "description": "Move the focused window to fill left half of the screen.", + "icon": "font_LeftHalf", + "type": "command" + }, + { + "id": "RightHalf", + "name": "Right Half", + "description": "Move the focused window to fill right half of the screen.", + "icon": "font_RightHalf", + "type": "command" + }, + { + "id": "CenterHalf", + "name": "Center Half", + "description": "Move the focused window to fill center half of the screen.", + "icon": "font_CenterHalf", + "type": "command" + }, + { + "id": "Maximize", + "name": "Maximize", + "description": "Maximize the focused window to fit the screen.", + "icon": "font_Maximize", + "type": "command" + }, + { + "id": "TopLeftQuarter", + "name": "Top Left Quarter", + "description": "Resize the focused window to the top left quarter of the screen.", + "icon": "font_TopLeftQuarter", + "type": "command" + }, + { + "id": "TopRightQuarter", + "name": "Top Right Quarter", + "description": "Resize the focused window to the top right quarter of the screen.", + "icon": "font_TopRightQuarter", + "type": "command" + }, + { + "id": "BottomLeftQuarter", + "name": "Bottom Left Quarter", + "description": "Resize the focused window to the bottom left quarter of the screen.", + "icon": "font_BottomLeftQuarter", + "type": "command" + }, + { + "id": "BottomRightQuarter", + "name": "Bottom Right Quarter", + "description": "Resize the focused window to the bottom right quarter of the screen.", + "icon": "font_BottomRightQuarter", + "type": "command" + }, + { + "id": "TopLeftSixth", + "name": "Top Left Sixth", + "description": "Resize the focused window to the top left sixth of the screen.", + "icon": "font_TopLeftSixth", + "type": "command" + }, + { + "id": "TopCenterSixth", + "name": "Top Center Sixth", + "description": "Resize the focused window to the top center sixth of the screen.", + "icon": "font_TopCenterSixth", + "type": "command" + }, + { + "id": "TopRightSixth", + "name": "Top Right Sixth", + "description": "Resize the focused window to the top right sixth of the screen.", + "icon": "font_TopRightSixth", + "type": "command" + }, + { + "id": "BottomLeftSixth", + "name": "Bottom Left Sixth", + "description": "Resize the focused window to the bottom left sixth of the screen.", + "icon": "font_BottomLeftSixth", + "type": "command" + }, + { + "id": "BottomCenterSixth", + "name": "Bottom Center Sixth", + "description": "Resize the focused window to the bottom center sixth of the screen.", + "icon": "font_BottomCenterSixth", + "type": "command" + }, + { + "id": "BottomRightSixth", + "name": "Bottom Right Sixth", + "description": "Resize the focused window to the bottom right sixth of the screen.", + "icon": "font_BottomRightSixth", + "type": "command" + }, + { + "id": "TopThird", + "name": "Top Third", + "description": "Resize the focused window to the top third of the screen.", + "icon": "font_TopThird", + "type": "command" + }, + { + "id": "MiddleThird", + "name": "Middle Third", + "description": "Resize the focused window to the middle third of the screen.", + "icon": "font_MiddleThird", + "type": "command" + }, + { + "id": "BottomThird", + "name": "Bottom Third", + "description": "Resize the focused window to the bottom third of the screen.", + "icon": "font_BottomThird", + "type": "command" + }, + { + "id": "Center", + "name": "Center", + "description": "Center the focused window in the screen.", + "icon": "font_Center", + "type": "command" + }, + { + "id": "FirstFourth", + "name": "First Fourth", + "description": "Resize the focused window to the first fourth of the screen.", + "icon": "font_FirstFourth", + "type": "command" + }, + { + "id": "SecondFourth", + "name": "Second Fourth", + "description": "Resize the focused window to the second fourth of the screen.", + "icon": "font_SecondFourth", + "type": "command" + }, + { + "id": "ThirdFourth", + "name": "Third Fourth", + "description": "Resize the focused window to the third fourth of the screen.", + "icon": "font_ThirdFourth", + "type": "command" + }, + { + "id": "LastFourth", + "name": "Last Fourth", + "description": "Resize the focused window to the last fourth of the screen.", + "icon": "font_LastFourth", + "type": "command" + }, + { + "id": "FirstThird", + "name": "First Third", + "description": "Resize the focused window to the first third of the screen.", + "icon": "font_FirstThird", + "type": "command" + }, + { + "id": "CenterThird", + "name": "Center Third", + "description": "Resize the focused window to the center third of the screen.", + "icon": "font_CenterThird", + "type": "command" + }, + { + "id": "LastThird", + "name": "Last Third", + "description": "Resize the focused window to the last third of the screen.", + "icon": "font_LastThird", + "type": "command" + }, + { + "id": "FirstTwoThirds", + "name": "First Two Thirds", + "description": "Resize the focused window to the first two thirds of the screen.", + "icon": "font_FirstTwoThirds", + "type": "command" + }, + { + "id": "CenterTwoThirds", + "name": "Center Two Thirds", + "description": "Resize the focused window to the center two thirds of the screen.", + "icon": "font_CenterTwoThirds", + "type": "command" + }, + { + "id": "LastTwoThirds", + "name": "Last Two Thirds", + "description": "Resize the focused window to the last two thirds of the screen.", + "icon": "font_LastTwoThirds", + "type": "command" + }, + { + "id": "FirstThreeFourths", + "name": "First Three Fourths", + "description": "Resize the focused window to the first three fourths of the screen.", + "icon": "font_FirstThreeFourths", + "type": "command" + }, + { + "id": "CenterThreeFourths", + "name": "Center Three Fourths", + "description": "Resize the focused window to the center three fourths of the screen.", + "icon": "font_CenterThreeFourths", + "type": "command" + }, + { + "id": "LastThreeFourths", + "name": "Last Three Fourths", + "description": "Resize the focused window to the last three fourths of the screen.", + "icon": "font_LastThreeFourths", + "type": "command" + }, + { + "id": "TopThreeFourths", + "name": "Top Three Fourths", + "description": "Resize the focused window to the top three fourths of the screen.", + "icon": "font_TopThreeFourths", + "type": "command" + }, + { + "id": "BottomThreeFourths", + "name": "Bottom Three Fourths", + "description": "Resize the focused window to the bottom three fourths of the screen.", + "icon": "font_BottomThreeFourths", + "type": "command" + }, + { + "id": "TopTwoThirds", + "name": "Top Two Thirds", + "description": "Resize the focused window to the top two thirds of the screen.", + "icon": "font_TopTwoThirds", + "type": "command" + }, + { + "id": "BottomTwoThirds", + "name": "Bottom Two Thirds", + "description": "Resize the focused window to the bottom two thirds of the screen.", + "icon": "font_BottomTwoThirds", + "type": "command" + }, + { + "id": "TopCenterTwoThirds", + "name": "Top Center Two Thirds", + "description": "Resize the focused window to the top center two thirds of the screen.", + "icon": "font_TopCenterTwoThirds", + "type": "command" + }, + { + "id": "TopFirstFourth", + "name": "Top First Fourth", + "description": "Resize the focused window to the top first fourth of the screen.", + "icon": "font_TopFirstFourth", + "type": "command" + }, + { + "id": "TopSecondFourth", + "name": "Top Second Fourth", + "description": "Resize the focused window to the top second fourth of the screen.", + "icon": "font_TopSecondFourth", + "type": "command" + }, + { + "id": "TopThirdFourth", + "name": "Top Third Fourth", + "description": "Resize the focused window to the top third fourth of the screen.", + "icon": "font_TopThirdFourth", + "type": "command" + }, + { + "id": "TopLastFourth", + "name": "Top Last Fourth", + "description": "Resize the focused window to the top last fourth of the screen.", + "icon": "font_TopLastFourth", + "type": "command" + }, + { + "id": "MakeLarger", + "name": "Make Larger", + "description": "Increase the focused window until it reaches the screen size.", + "icon": "font_MakeLarger", + "type": "command" + }, + { + "id": "MakeSmaller", + "name": "Make Smaller", + "description": "Decrease the focused window until it reaches its minimal size.", + "icon": "font_MakeSmaller", + "type": "command" + }, + { + "id": "AlmostMaximize", + "name": "Almost Maximize", + "description": "Maximize the focused window to almost fit the screen.", + "icon": "font_AlmostMaximize", + "type": "command" + }, + { + "id": "MaximizeWidth", + "name": "Maximize Width", + "description": "Maximize width of the focused window to fit the screen.", + "icon": "font_MaximizeWidth", + "type": "command" + }, + { + "id": "MaximizeHeight", + "name": "Maximize Height", + "description": "Maximize height of the focused window to fit the screen.", + "icon": "font_MaximizeHeight", + "type": "command" + }, + { + "id": "MoveUp", + "name": "Move Up", + "description": "Move the focused window to the top edge of the screen.", + "icon": "font_MoveUp", + "type": "command" + }, + { + "id": "MoveDown", + "name": "Move Down", + "description": "Move the focused window to the bottom of the screen.", + "icon": "font_MoveDown", + "type": "command" + }, + { + "id": "MoveLeft", + "name": "Move Left", + "description": "Move the focused window to the left edge of the screen.", + "icon": "font_MoveLeft", + "type": "command" + }, + { + "id": "MoveRight", + "name": "Move Right", + "description": "Move the focused window to the right edge of the screen.", + "icon": "font_MoveRight", + "type": "command" + }, + { + "id": "NextDesktop", + "name": "Next Desktop", + "description": "Move the focused window to the next desktop.", + "icon": "font_NextDesktop", + "type": "command" + }, + { + "id": "PreviousDesktop", + "name": "Previous Desktop", + "description": "Move the focused window to the previous desktop.", + "icon": "font_PreviousDesktop", + "type": "command" + }, + { + "id": "NextDisplay", + "name": "Next Display", + "description": "Move the focused window to the next display.", + "icon": "font_NextDisplay", + "type": "command" + }, + { + "id": "PreviousDisplay", + "name": "Previous Display", + "description": "Move the focused window to the previous display.", + "icon": "font_PreviousDisplay", + "type": "command" + }, + { + "id": "Restore", + "name": "Restore", + "description": "Restore the focused window to its last position.", + "icon": "font_Restore", + "type": "command" + }, + { + "id": "ToggleFullscreen", + "name": "Toggle Fullscreen", + "description": "Toggle fullscreen mode.", + "icon": "font_ToggleFullscreen", + "type": "command" + } + ] +} diff --git a/src-tauri/src/extension/built_in/window_management/search_source.rs b/src-tauri/src/extension/built_in/window_management/search_source.rs new file mode 100644 index 00000000..5d7ab5f7 --- /dev/null +++ b/src-tauri/src/extension/built_in/window_management/search_source.rs @@ -0,0 +1,127 @@ +use super::EXTENSION_ID; +use crate::common::document::{DataSourceReference, Document}; +use crate::common::{ + error::SearchError, + search::{QueryResponse, QuerySource, SearchQuery}, + traits::SearchSource, +}; +use crate::extension::built_in::{get_built_in_extension_directory, load_extension_from_json_file}; +use crate::extension::{ExtensionType, LOCAL_QUERY_SOURCE_TYPE, calculate_text_similarity}; +use async_trait::async_trait; +use hostname; +use tauri::AppHandle; + +/// A search source to allow users to search WM actions. +pub(crate) struct WindowManagementSearchSource; + +#[async_trait] +impl SearchSource for WindowManagementSearchSource { + fn get_type(&self) -> QuerySource { + QuerySource { + r#type: LOCAL_QUERY_SOURCE_TYPE.into(), + name: hostname::get() + .unwrap_or(EXTENSION_ID.into()) + .to_string_lossy() + .into(), + id: EXTENSION_ID.into(), + } + } + + async fn search( + &self, + tauri_app_handle: AppHandle, + query: SearchQuery, + ) -> Result { + let Some(query_string) = query.query_strings.get("query") else { + return Ok(QueryResponse { + source: self.get_type(), + hits: Vec::new(), + total_hits: 0, + }); + }; + let from = usize::try_from(query.from).expect("from too big"); + let size = usize::try_from(query.size).expect("size too big"); + + let query_string = query_string.trim(); + if query_string.is_empty() { + return Ok(QueryResponse { + source: self.get_type(), + hits: Vec::new(), + total_hits: 0, + }); + } + let query_string_lowercase = query_string.to_lowercase(); + + let extension = load_extension_from_json_file( + &get_built_in_extension_directory(&tauri_app_handle), + super::EXTENSION_ID, + ) + .map_err(SearchError::InternalError)?; + let commands = extension.commands.expect("this extension has commands"); + + let mut hits: Vec<(Document, f64)> = Vec::new(); + + // We know they are all commands + let command_type_string = ExtensionType::Command.to_string(); + for command in commands.iter().filter(|ext| ext.enabled) { + let score = { + let mut score = 0_f64; + + if let Some(name_score) = + calculate_text_similarity(&query_string_lowercase, &command.name.to_lowercase()) + { + score += name_score; + } + + if let Some(ref alias) = command.alias { + if let Some(alias_score) = + calculate_text_similarity(&query_string_lowercase, &alias.to_lowercase()) + { + score += alias_score; + } + } + + score + }; + + if score > 0.0 { + let on_opened = super::on_opened::on_opened(&command.id); + let url = on_opened.url(); + + let document = Document { + id: command.id.clone(), + title: Some(command.name.clone()), + icon: Some(command.icon.clone()), + on_opened: Some(on_opened), + url: Some(url), + category: Some(command_type_string.clone()), + source: Some(DataSourceReference { + id: Some(command_type_string.clone()), + name: Some(command_type_string.clone()), + icon: None, + r#type: Some(command_type_string.clone()), + }), + + ..Default::default() + }; + + hits.push((document, score)); + } + } + + hits.sort_by(|(_, score_a), (_, score_b)| { + score_a + .partial_cmp(&score_b) + .expect("expect no NAN/INFINITY/...") + }); + + let total_hits = hits.len(); + let from_size_applied = hits.into_iter().skip(from).take(size).collect(); + + Ok(QueryResponse { + source: self.get_type(), + hits: from_size_applied, + total_hits, + }) + } +} diff --git a/src-tauri/src/extension/mod.rs b/src-tauri/src/extension/mod.rs index b73e840a..8bba0377 100644 --- a/src-tauri/src/extension/mod.rs +++ b/src-tauri/src/extension/mod.rs @@ -773,7 +773,7 @@ pub(crate) async fn set_extension_alias( let bundle_id_borrowed = bundle_id.borrow(); if built_in::is_extension_built_in(&bundle_id_borrowed) { - built_in::set_built_in_extension_alias(&tauri_app_handle, &bundle_id_borrowed, &alias); + built_in::set_built_in_extension_alias(&tauri_app_handle, &bundle_id_borrowed, &alias)?; return Ok(()); } third_party::THIRD_PARTY_EXTENSIONS_SEARCH_SOURCE.get().expect("global third party search source not set, looks like init_extensions() has not been executed").set_extension_alias(&tauri_app_handle, &bundle_id_borrowed, &alias).await @@ -1111,6 +1111,52 @@ pub(crate) struct ExtensionSettings { pub(crate) hide_before_open: Option, } +/// Calculates a similarity score between a query and a text, aiming for a [0, 1] range. +/// Assumes query and text are already lowercased. +/// +/// Used in extension_to_hit(). +fn calculate_text_similarity(query: &str, text: &str) -> Option { + if query.is_empty() || text.is_empty() { + return None; + } + + if text == query { + return Some(1.0); // Perfect match + } + + let query_len = query.len() as f64; + let text_len = text.len() as f64; + let ratio = query_len / text_len; + let mut score: f64 = 0.0; + + // Case 1: Text starts with the query (prefix match) + // Score: base 0.5, bonus up to 0.4 for how much of `text` is covered by `query`. Max 0.9. + if text.starts_with(query) { + score = score.max(0.5 + 0.4 * ratio); + } + + // Case 2: Text contains the query (substring match, not necessarily prefix) + // Score: base 0.3, bonus up to 0.3. Max 0.6. + // `score.max` ensures that if it's both a prefix and contains, the higher score (prefix) is taken. + if text.contains(query) { + score = score.max(0.3 + 0.3 * ratio); + } + + // Case 3: Fallback for "all query characters exist in text" (order-independent) + if score < 0.2 { + if query.chars().all(|c_q| text.contains(c_q)) { + score = score.max(0.15); // Fixed low score for this weaker match type + } + } + + if score > 0.0 { + // Cap non-perfect matches slightly below 1.0 to make perfect (1.0) distinct. + Some(score.min(0.95)) + } else { + None + } +} + #[cfg(test)] mod tests { use super::*; @@ -1581,4 +1627,96 @@ mod tests { let result = link.concatenate_url(&None); assert_eq!(result, ""); } + + // Helper function for approximate floating point comparison + fn approx_eq(a: f64, b: f64) -> bool { + (a - b).abs() < 1e-10 + } + + #[test] + fn test_empty_strings() { + assert_eq!(calculate_text_similarity("", "text"), None); + assert_eq!(calculate_text_similarity("query", ""), None); + assert_eq!(calculate_text_similarity("", ""), None); + } + + #[test] + fn test_perfect_match() { + assert_eq!(calculate_text_similarity("text", "text"), Some(1.0)); + assert_eq!(calculate_text_similarity("a", "a"), Some(1.0)); + } + + #[test] + fn test_prefix_match() { + // For "te" and "text": + // score = 0.5 + 0.4 * (2/4) = 0.5 + 0.2 = 0.7 + let score = calculate_text_similarity("te", "text").unwrap(); + assert!(approx_eq(score, 0.7)); + + // For "tex" and "text": + // score = 0.5 + 0.4 * (3/4) = 0.5 + 0.3 = 0.8 + let score = calculate_text_similarity("tex", "text").unwrap(); + assert!(approx_eq(score, 0.8)); + } + + #[test] + fn test_substring_match() { + // For "ex" and "text": + // score = 0.3 + 0.3 * (2/4) = 0.3 + 0.15 = 0.45 + let score = calculate_text_similarity("ex", "text").unwrap(); + assert!(approx_eq(score, 0.45)); + + // Prefix should score higher than substring + assert!( + calculate_text_similarity("te", "text").unwrap() + > calculate_text_similarity("ex", "text").unwrap() + ); + } + + #[test] + fn test_character_presence() { + // Characters present but not in sequence + // "tac" in "contact" - not a substring, but all chars exist + let score = calculate_text_similarity("tac", "contact").unwrap(); + assert!(approx_eq(0.3 + 0.3 * (3.0 / 7.0), score)); + + assert!(calculate_text_similarity("ac", "contact").is_some()); + + // Should not apply if some characters are missing + assert_eq!(calculate_text_similarity("xyz", "contact"), None); + } + + #[test] + fn test_combined_scenarios() { + // Test that character presence fallback doesn't override higher scores + // "tex" is a prefix of "text" with score 0.8 + let score = calculate_text_similarity("tex", "text").unwrap(); + assert!(approx_eq(score, 0.8)); + + // Test a case where the characters exist but it's already a substring + // "act" is a substring of "contact" with score > 0.2, so fallback won't apply + let expected_score = 0.3 + 0.3 * (3.0 / 7.0); + let actual_score = calculate_text_similarity("act", "contact").unwrap(); + assert!(approx_eq(actual_score, expected_score)); + } + + #[test] + fn test_no_similarity() { + assert_eq!(calculate_text_similarity("xyz", "test"), None); + } + + #[test] + fn test_score_capping() { + // Use a long query that's a prefix of a slightly longer text + let long_text = "abcdefghijklmnopqrstuvwxyz"; + let long_prefix = "abcdefghijklmnopqrstuvwxy"; // All but last letter + + // Expected score would be 0.5 + 0.4 * (25/26) = 0.5 + 0.385 = 0.885 + let expected_score = 0.5 + 0.4 * (25.0 / 26.0); + let actual_score = calculate_text_similarity(long_prefix, long_text).unwrap(); + assert!(approx_eq(actual_score, expected_score)); + + // Verify that non-perfect matches are capped at 0.95 + assert!(calculate_text_similarity("almost", "almost perfect").unwrap() <= 0.95); + } } diff --git a/src-tauri/src/extension/third_party/mod.rs b/src-tauri/src/extension/third_party/mod.rs index b925ef4e..3366506e 100644 --- a/src-tauri/src/extension/third_party/mod.rs +++ b/src-tauri/src/extension/third_party/mod.rs @@ -15,6 +15,7 @@ use crate::common::search::QuerySource; use crate::common::search::SearchQuery; use crate::common::traits::SearchSource; use crate::extension::ExtensionBundleIdBorrowed; +use crate::extension::calculate_text_similarity; use crate::util::platform::Platform; use async_trait::async_trait; use borrowme::ToOwned; @@ -803,7 +804,20 @@ impl SearchSource for ThirdPartyExtensionsSearchSource { } } -fn extension_to_hit( +#[tauri::command] +pub(crate) async fn uninstall_extension( + tauri_app_handle: AppHandle, + developer: String, + extension_id: String, +) -> Result<(), String> { + THIRD_PARTY_EXTENSIONS_SEARCH_SOURCE + .get() + .expect("global third party search source not set") + .uninstall_extension(&tauri_app_handle, &developer, &extension_id) + .await +} + +pub(crate) fn extension_to_hit( extension: &Extension, query_lower: &str, opt_data_source: Option<&str>, @@ -872,157 +886,3 @@ fn extension_to_hit( None } } - -// Calculates a similarity score between a query and a text, aiming for a [0, 1] range. -// Assumes query and text are already lowercased. -fn calculate_text_similarity(query: &str, text: &str) -> Option { - if query.is_empty() || text.is_empty() { - return None; - } - - if text == query { - return Some(1.0); // Perfect match - } - - let query_len = query.len() as f64; - let text_len = text.len() as f64; - let ratio = query_len / text_len; - let mut score: f64 = 0.0; - - // Case 1: Text starts with the query (prefix match) - // Score: base 0.5, bonus up to 0.4 for how much of `text` is covered by `query`. Max 0.9. - if text.starts_with(query) { - score = score.max(0.5 + 0.4 * ratio); - } - - // Case 2: Text contains the query (substring match, not necessarily prefix) - // Score: base 0.3, bonus up to 0.3. Max 0.6. - // `score.max` ensures that if it's both a prefix and contains, the higher score (prefix) is taken. - if text.contains(query) { - score = score.max(0.3 + 0.3 * ratio); - } - - // Case 3: Fallback for "all query characters exist in text" (order-independent) - if score < 0.2 { - if query.chars().all(|c_q| text.contains(c_q)) { - score = score.max(0.15); // Fixed low score for this weaker match type - } - } - - if score > 0.0 { - // Cap non-perfect matches slightly below 1.0 to make perfect (1.0) distinct. - Some(score.min(0.95)) - } else { - None - } -} - -#[tauri::command] -pub(crate) async fn uninstall_extension( - tauri_app_handle: AppHandle, - developer: String, - extension_id: String, -) -> Result<(), String> { - THIRD_PARTY_EXTENSIONS_SEARCH_SOURCE - .get() - .expect("global third party search source not set") - .uninstall_extension(&tauri_app_handle, &developer, &extension_id) - .await -} - -#[cfg(test)] -mod tests { - use super::*; - - // Helper function for approximate floating point comparison - fn approx_eq(a: f64, b: f64) -> bool { - (a - b).abs() < 1e-10 - } - - #[test] - fn test_empty_strings() { - assert_eq!(calculate_text_similarity("", "text"), None); - assert_eq!(calculate_text_similarity("query", ""), None); - assert_eq!(calculate_text_similarity("", ""), None); - } - - #[test] - fn test_perfect_match() { - assert_eq!(calculate_text_similarity("text", "text"), Some(1.0)); - assert_eq!(calculate_text_similarity("a", "a"), Some(1.0)); - } - - #[test] - fn test_prefix_match() { - // For "te" and "text": - // score = 0.5 + 0.4 * (2/4) = 0.5 + 0.2 = 0.7 - let score = calculate_text_similarity("te", "text").unwrap(); - assert!(approx_eq(score, 0.7)); - - // For "tex" and "text": - // score = 0.5 + 0.4 * (3/4) = 0.5 + 0.3 = 0.8 - let score = calculate_text_similarity("tex", "text").unwrap(); - assert!(approx_eq(score, 0.8)); - } - - #[test] - fn test_substring_match() { - // For "ex" and "text": - // score = 0.3 + 0.3 * (2/4) = 0.3 + 0.15 = 0.45 - let score = calculate_text_similarity("ex", "text").unwrap(); - assert!(approx_eq(score, 0.45)); - - // Prefix should score higher than substring - assert!( - calculate_text_similarity("te", "text").unwrap() - > calculate_text_similarity("ex", "text").unwrap() - ); - } - - #[test] - fn test_character_presence() { - // Characters present but not in sequence - // "tac" in "contact" - not a substring, but all chars exist - let score = calculate_text_similarity("tac", "contact").unwrap(); - assert!(approx_eq(0.3 + 0.3 * (3.0 / 7.0), score)); - - assert!(calculate_text_similarity("ac", "contact").is_some()); - - // Should not apply if some characters are missing - assert_eq!(calculate_text_similarity("xyz", "contact"), None); - } - - #[test] - fn test_combined_scenarios() { - // Test that character presence fallback doesn't override higher scores - // "tex" is a prefix of "text" with score 0.8 - let score = calculate_text_similarity("tex", "text").unwrap(); - assert!(approx_eq(score, 0.8)); - - // Test a case where the characters exist but it's already a substring - // "act" is a substring of "contact" with score > 0.2, so fallback won't apply - let expected_score = 0.3 + 0.3 * (3.0 / 7.0); - let actual_score = calculate_text_similarity("act", "contact").unwrap(); - assert!(approx_eq(actual_score, expected_score)); - } - - #[test] - fn test_no_similarity() { - assert_eq!(calculate_text_similarity("xyz", "test"), None); - } - - #[test] - fn test_score_capping() { - // Use a long query that's a prefix of a slightly longer text - let long_text = "abcdefghijklmnopqrstuvwxyz"; - let long_prefix = "abcdefghijklmnopqrstuvwxy"; // All but last letter - - // Expected score would be 0.5 + 0.4 * (25/26) = 0.5 + 0.385 = 0.885 - let expected_score = 0.5 + 0.4 * (25.0 / 26.0); - let actual_score = calculate_text_similarity(long_prefix, long_text).unwrap(); - assert!(approx_eq(actual_score, expected_score)); - - // Verify that non-perfect matches are capped at 0.95 - assert!(calculate_text_similarity("almost", "almost perfect").unwrap() <= 0.95); - } -}