diff --git a/frontend/bun.lock b/frontend/bun.lock
index 4902cb5cf..806f3e5d2 100644
--- a/frontend/bun.lock
+++ b/frontend/bun.lock
@@ -21,7 +21,7 @@
"@tanstack/react-query": "^5.100.1",
"@tanstack/react-router": "^1.168.24",
"@tauri-apps/api": "2.11.0",
- "@tauri-apps/plugin-deep-link": "^2.4.9",
+ "@tauri-apps/plugin-deep-link": "2.4.8",
"@tauri-apps/plugin-dialog": "^2.7.1",
"@tauri-apps/plugin-fs": "^2.5.1",
"@tauri-apps/plugin-opener": "^2.5.4",
@@ -472,7 +472,7 @@
"@tauri-apps/cli-win32-x64-msvc": ["@tauri-apps/cli-win32-x64-msvc@2.11.1", "", { "os": "win32", "cpu": "x64" }, "sha512-b3ORhIAKgp9ZYY+zBt7b7r0kLU2kjvyGF0+MS2SBym3emsweGPybEqocJcmtMuxyBhkOKHP4CiuEJEDuAlTx6A=="],
- "@tauri-apps/plugin-deep-link": ["@tauri-apps/plugin-deep-link@2.4.9", "", { "dependencies": { "@tauri-apps/api": "^2.11.0" } }, "sha512-u0SKOUHnJ1wqeqXsDFq2+kASCBj9xxbG0g9XZWPy9SOmU4wXtp6b/wiYpm6oH6/5fBTQsLqnLhIvqLBRpgHJlA=="],
+ "@tauri-apps/plugin-deep-link": ["@tauri-apps/plugin-deep-link@2.4.8", "", { "dependencies": { "@tauri-apps/api": "^2.10.1" } }, "sha512-Cd2Cs960MGuGONeIwxOPx9wqwedetAHOGlwK5boJ/SMTfAtAyfErpfVPEn+EJzgXsJun8EKzsEumHjr+64V4fw=="],
"@tauri-apps/plugin-dialog": ["@tauri-apps/plugin-dialog@2.7.1", "", { "dependencies": { "@tauri-apps/api": "^2.11.0" } }, "sha512-OK1UBXYt+ojcmxMktzzuyonYIFta8CmAASpX+CA+DTGK24KlHjhYI6x2iOJ/TjZF4N7/ACK1oFmEOjIY9IhzOQ=="],
diff --git a/frontend/package.json b/frontend/package.json
index 13d35a6af..db3a34032 100644
--- a/frontend/package.json
+++ b/frontend/package.json
@@ -47,7 +47,7 @@
"@tanstack/react-query": "^5.100.1",
"@tanstack/react-router": "^1.168.24",
"@tauri-apps/api": "2.11.0",
- "@tauri-apps/plugin-deep-link": "^2.4.9",
+ "@tauri-apps/plugin-deep-link": "2.4.8",
"@tauri-apps/plugin-dialog": "^2.7.1",
"@tauri-apps/plugin-fs": "^2.5.1",
"@tauri-apps/plugin-opener": "^2.5.4",
diff --git a/frontend/src-tauri/Cargo.lock b/frontend/src-tauri/Cargo.lock
index 6db93c420..3f5525739 100644
--- a/frontend/src-tauri/Cargo.lock
+++ b/frontend/src-tauri/Cargo.lock
@@ -5424,8 +5424,6 @@ dependencies = [
[[package]]
name = "tao"
version = "0.35.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a33f7f9e486ade65fcf1e45c440f9236c904f5c1002cdc7fc6ae582777345ce4"
dependencies = [
"bitflags 2.10.0",
"block2 0.6.2",
@@ -5626,9 +5624,9 @@ dependencies = [
[[package]]
name = "tauri-plugin-deep-link"
-version = "2.4.9"
+version = "2.4.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "70ee75bc5627f77bfdf40c913255ebc258117b10ebe2b2239a1a1cf40b0b58aa"
+checksum = "94deb2e2e4641514ac496db2cddcfc850d6fc9d51ea17b82292a0490bd20ba5b"
dependencies = [
"dunce",
"plist",
@@ -5745,9 +5743,9 @@ dependencies = [
[[package]]
name = "tauri-plugin-single-instance"
-version = "2.4.2"
+version = "2.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5c8f29386f5e9fdc699182388a33ee80a56de436d91b67459e86afef426282af"
+checksum = "dc61e4822b8f74d68278e09161d3e3fdd1b14b9eb781e24edccaabf10c420e8c"
dependencies = [
"serde",
"serde_json",
diff --git a/frontend/src-tauri/Cargo.toml b/frontend/src-tauri/Cargo.toml
index 688a789cd..be2b65c5c 100644
--- a/frontend/src-tauri/Cargo.toml
+++ b/frontend/src-tauri/Cargo.toml
@@ -26,8 +26,11 @@ tauri = { version = "2.11.2", features = [] }
tauri-plugin-log = "2.8.0"
tauri-plugin-updater = "2.10.1"
tauri-plugin = "2.6.2"
-tauri-plugin-deep-link = "2.4.9"
-tauri-plugin-single-instance = { version = "2.4.2", features = ["deep-link"] }
+# Keep Android deep links on the last known-working plugin behavior.
+# tauri-plugin-deep-link 2.4.9 added Android-side config filtering that drops
+# our existing cloud.opensecret.maple:// OAuth callback before Rust receives it.
+tauri-plugin-deep-link = "=2.4.7"
+tauri-plugin-single-instance = { version = "=2.4.0", features = ["deep-link"] }
tauri-plugin-opener = "2.5.4"
tauri-plugin-os = "2.3.2"
tauri-plugin-sign-in-with-apple = "1.0.2"
@@ -86,3 +89,13 @@ sha2 = "0.10"
[target.'cfg(target_os = "android")'.dependencies]
openssl = { version = "0.10.80", default-features = false, features = ["vendored"] }
+
+[patch.crates-io]
+# Local patch for tao 0.35.2 Android intent crashes:
+# https://github.com/tauri-apps/tao/issues/1217
+#
+# Tao's Android intent handler currently unwraps several JNI calls that can
+# receive null objects from real Android launch/deep-link flows, aborting the
+# process before tauri-plugin-deep-link sees OAuth/payment redirects. Remove
+# this once Tauri resolves to a Tao release containing the upstream fix.
+tao = { path = "patches/tao-0.35.2" }
diff --git a/frontend/src-tauri/patches/tao-0.35.2/Cargo.lock b/frontend/src-tauri/patches/tao-0.35.2/Cargo.lock
new file mode 100644
index 000000000..4bf7205cf
--- /dev/null
+++ b/frontend/src-tauri/patches/tao-0.35.2/Cargo.lock
@@ -0,0 +1,3378 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 3
+
+[[package]]
+name = "adler2"
+version = "2.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa"
+
+[[package]]
+name = "aho-corasick"
+version = "1.1.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301"
+dependencies = [
+ "memchr",
+]
+
+[[package]]
+name = "aligned"
+version = "0.4.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ee4508988c62edf04abd8d92897fca0c2995d907ce1dfeaf369dac3716a40685"
+dependencies = [
+ "as-slice",
+]
+
+[[package]]
+name = "aligned-vec"
+version = "0.6.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dc890384c8602f339876ded803c97ad529f3842aba97f6392b3dba0dd171769b"
+dependencies = [
+ "equator",
+]
+
+[[package]]
+name = "anstream"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "824a212faf96e9acacdbd09febd34438f8f711fb84e09a8916013cd7815ca28d"
+dependencies = [
+ "anstyle",
+ "anstyle-parse",
+ "anstyle-query",
+ "anstyle-wincon",
+ "colorchoice",
+ "is_terminal_polyfill",
+ "utf8parse",
+]
+
+[[package]]
+name = "anstyle"
+version = "1.0.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "940b3a0ca603d1eade50a4846a2afffd5ef57a9feac2c0e2ec2e14f9ead76000"
+
+[[package]]
+name = "anstyle-parse"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "52ce7f38b242319f7cabaa6813055467063ecdc9d355bbb4ce0c68908cd8130e"
+dependencies = [
+ "utf8parse",
+]
+
+[[package]]
+name = "anstyle-query"
+version = "1.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc"
+dependencies = [
+ "windows-sys 0.61.2",
+]
+
+[[package]]
+name = "anstyle-wincon"
+version = "3.0.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d"
+dependencies = [
+ "anstyle",
+ "once_cell_polyfill",
+ "windows-sys 0.61.2",
+]
+
+[[package]]
+name = "anyhow"
+version = "1.0.102"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c"
+
+[[package]]
+name = "arbitrary"
+version = "1.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c3d036a3c4ab069c7b410a2ce876bd74808d2d0888a82667669f8e783a898bf1"
+
+[[package]]
+name = "arg_enum_proc_macro"
+version = "0.3.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0ae92a5119aa49cdbcf6b9f893fe4e1d98b04ccbf82ee0584ad948a44a734dea"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.117",
+]
+
+[[package]]
+name = "arrayvec"
+version = "0.7.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50"
+
+[[package]]
+name = "as-raw-xcb-connection"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "175571dd1d178ced59193a6fc02dde1b972eb0bc56c892cde9beeceac5bf0f6b"
+
+[[package]]
+name = "as-slice"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "516b6b4f0e40d50dcda9365d53964ec74560ad4284da2e7fc97122cd83174516"
+dependencies = [
+ "stable_deref_trait",
+]
+
+[[package]]
+name = "atk"
+version = "0.18.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "241b621213072e993be4f6f3a9e4b45f65b7e6faad43001be957184b7bb1824b"
+dependencies = [
+ "atk-sys",
+ "glib",
+ "libc",
+]
+
+[[package]]
+name = "atk-sys"
+version = "0.18.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c5e48b684b0ca77d2bbadeef17424c2ea3c897d44d566a1617e7e8f30614d086"
+dependencies = [
+ "glib-sys",
+ "gobject-sys",
+ "libc",
+ "system-deps",
+]
+
+[[package]]
+name = "autocfg"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8"
+
+[[package]]
+name = "av-scenechange"
+version = "0.14.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0f321d77c20e19b92c39e7471cf986812cbb46659d2af674adc4331ef3f18394"
+dependencies = [
+ "aligned",
+ "anyhow",
+ "arg_enum_proc_macro",
+ "arrayvec",
+ "log",
+ "num-rational",
+ "num-traits",
+ "pastey",
+ "rayon",
+ "thiserror 2.0.18",
+ "v_frame",
+ "y4m",
+]
+
+[[package]]
+name = "av1-grain"
+version = "0.2.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8cfddb07216410377231960af4fcab838eaa12e013417781b78bd95ee22077f8"
+dependencies = [
+ "anyhow",
+ "arrayvec",
+ "log",
+ "nom",
+ "num-rational",
+ "v_frame",
+]
+
+[[package]]
+name = "avif-serialize"
+version = "0.8.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "375082f007bd67184fb9c0374614b29f9aaa604ec301635f72338bb65386a53d"
+dependencies = [
+ "arrayvec",
+]
+
+[[package]]
+name = "bit_field"
+version = "0.10.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1e4b40c7323adcfc0a41c4b88143ed58346ff65a288fc144329c5c45e05d70c6"
+
+[[package]]
+name = "bitflags"
+version = "2.11.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c4512299f36f043ab09a583e57bceb5a5aab7a73db1805848e8fef3c9e8c78b3"
+
+[[package]]
+name = "bitstream-io"
+version = "4.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7eff00be299a18769011411c9def0d827e8f2d7bf0c3dbf53633147a8867fd1f"
+dependencies = [
+ "no_std_io2",
+]
+
+[[package]]
+name = "block2"
+version = "0.6.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cdeb9d870516001442e364c5220d3574d2da8dc765554b4a617230d33fa58ef5"
+dependencies = [
+ "objc2",
+]
+
+[[package]]
+name = "built"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f4ad8f11f288f48ca24471bbd51ac257aaeaaa07adae295591266b792902ae64"
+
+[[package]]
+name = "bumpalo"
+version = "3.20.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb"
+
+[[package]]
+name = "bytemuck"
+version = "1.25.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c8efb64bd706a16a1bdde310ae86b351e4d21550d98d056f22f8a7f7a2183fec"
+dependencies = [
+ "bytemuck_derive",
+]
+
+[[package]]
+name = "bytemuck_derive"
+version = "1.10.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f9abbd1bc6865053c427f7198e6af43bfdedc55ab791faed4fbd361d789575ff"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.117",
+]
+
+[[package]]
+name = "byteorder-lite"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8f1fe948ff07f4bd06c30984e69f5b4899c516a3ef74f34df92a2df2ab535495"
+
+[[package]]
+name = "bytes"
+version = "1.11.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33"
+
+[[package]]
+name = "cairo-rs"
+version = "0.18.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8ca26ef0159422fb77631dc9d17b102f253b876fe1586b03b803e63a309b4ee2"
+dependencies = [
+ "bitflags",
+ "cairo-sys-rs",
+ "glib",
+ "libc",
+ "once_cell",
+ "thiserror 1.0.69",
+]
+
+[[package]]
+name = "cairo-sys-rs"
+version = "0.18.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "685c9fa8e590b8b3d678873528d83411db17242a73fccaed827770ea0fedda51"
+dependencies = [
+ "glib-sys",
+ "libc",
+ "system-deps",
+]
+
+[[package]]
+name = "cc"
+version = "1.2.61"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d16d90359e986641506914ba71350897565610e87ce0ad9e6f28569db3dd5c6d"
+dependencies = [
+ "find-msvc-tools",
+ "jobserver",
+ "libc",
+ "shlex",
+]
+
+[[package]]
+name = "cesu8"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c"
+
+[[package]]
+name = "cfg-expr"
+version = "0.15.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d067ad48b8650848b989a59a86c6c36a995d02d2bf778d45c3c5d57bc2718f02"
+dependencies = [
+ "smallvec",
+ "target-lexicon",
+]
+
+[[package]]
+name = "cfg-if"
+version = "1.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
+
+[[package]]
+name = "color_quant"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b"
+
+[[package]]
+name = "colorchoice"
+version = "1.0.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1d07550c9036bf2ae0c684c4297d503f838287c83c53686d05370d0e139ae570"
+
+[[package]]
+name = "combine"
+version = "4.6.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd"
+dependencies = [
+ "bytes",
+ "memchr",
+]
+
+[[package]]
+name = "core-foundation"
+version = "0.10.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b2a6cd9ae233e7f62ba4e9353e81a88df7fc8a5987b8d445b4d90c879bd156f6"
+dependencies = [
+ "core-foundation-sys",
+ "libc",
+]
+
+[[package]]
+name = "core-foundation-sys"
+version = "0.8.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
+
+[[package]]
+name = "core-graphics"
+version = "0.25.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "064badf302c3194842cf2c5d61f56cc88e54a759313879cdf03abdd27d0c3b97"
+dependencies = [
+ "bitflags",
+ "core-foundation",
+ "core-graphics-types",
+ "foreign-types",
+ "libc",
+]
+
+[[package]]
+name = "core-graphics-types"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3d44a101f213f6c4cdc1853d4b78aef6db6bdfa3468798cc1d9912f4735013eb"
+dependencies = [
+ "bitflags",
+ "core-foundation",
+ "libc",
+]
+
+[[package]]
+name = "crc32fast"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511"
+dependencies = [
+ "cfg-if",
+]
+
+[[package]]
+name = "crossbeam-channel"
+version = "0.5.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "82b8f8f868b36967f9606790d1903570de9ceaf870a7bf9fbbd3016d636a2cb2"
+dependencies = [
+ "crossbeam-utils",
+]
+
+[[package]]
+name = "crossbeam-deque"
+version = "0.8.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51"
+dependencies = [
+ "crossbeam-epoch",
+ "crossbeam-utils",
+]
+
+[[package]]
+name = "crossbeam-epoch"
+version = "0.9.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e"
+dependencies = [
+ "crossbeam-utils",
+]
+
+[[package]]
+name = "crossbeam-utils"
+version = "0.8.21"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28"
+
+[[package]]
+name = "crunchy"
+version = "0.2.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5"
+
+[[package]]
+name = "ctor"
+version = "0.10.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "83cf0d42651b16c6dfe68685716d18480d18a9c39c62d76e8cf3eb6ed5d8bcbf"
+dependencies = [
+ "dtor",
+]
+
+[[package]]
+name = "cty"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b365fabc795046672053e29c954733ec3b05e4be654ab130fe8f1f94d7051f35"
+
+[[package]]
+name = "dbus"
+version = "0.9.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b942602992bb7acfd1f51c49811c58a610ef9181b6e66f3e519d79b540a3bf73"
+dependencies = [
+ "libc",
+ "libdbus-sys",
+ "windows-sys 0.61.2",
+]
+
+[[package]]
+name = "dispatch2"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1e0e367e4e7da84520dedcac1901e4da967309406d1e51017ae1abfb97adbd38"
+dependencies = [
+ "bitflags",
+ "block2",
+ "libc",
+ "objc2",
+]
+
+[[package]]
+name = "displaydoc"
+version = "0.2.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.117",
+]
+
+[[package]]
+name = "dlib"
+version = "0.5.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ab8ecd87370524b461f8557c119c405552c396ed91fc0a8eec68679eab26f94a"
+dependencies = [
+ "libloading",
+]
+
+[[package]]
+name = "dlopen2"
+version = "0.8.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5e2c5bd4158e66d1e215c49b837e11d62f3267b30c92f1d171c4d3105e3dc4d4"
+dependencies = [
+ "dlopen2_derive",
+ "libc",
+ "once_cell",
+ "winapi",
+]
+
+[[package]]
+name = "dlopen2_derive"
+version = "0.4.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0fbbb781877580993a8707ec48672673ec7b81eeba04cfd2310bd28c08e47c8f"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.117",
+]
+
+[[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"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d8b14ccef22fc6f5a8f4d7d768562a182c04ce9a3b3157b91390b52ddfdf1a76"
+dependencies = [
+ "serde",
+]
+
+[[package]]
+name = "drm"
+version = "0.14.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "80bc8c5c6c2941f70a55c15f8d9f00f9710ebda3ffda98075f996a0e6c92756f"
+dependencies = [
+ "bitflags",
+ "bytemuck",
+ "drm-ffi",
+ "drm-fourcc",
+ "libc",
+ "rustix 0.38.44",
+]
+
+[[package]]
+name = "drm-ffi"
+version = "0.9.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "51a91c9b32ac4e8105dec255e849e0d66e27d7c34d184364fb93e469db08f690"
+dependencies = [
+ "drm-sys",
+ "rustix 1.1.4",
+]
+
+[[package]]
+name = "drm-fourcc"
+version = "2.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0aafbcdb8afc29c1a7ee5fbe53b5d62f4565b35a042a662ca9fecd0b54dae6f4"
+
+[[package]]
+name = "drm-sys"
+version = "0.8.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ecc8e1361066d91f5ffccff060a3c3be9c3ecde15be2959c1937595f7a82a9f8"
+dependencies = [
+ "libc",
+ "linux-raw-sys 0.9.4",
+]
+
+[[package]]
+name = "dtor"
+version = "0.8.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "edf234dd1594d6dd434a8fb8cada51ddbbc593e40e4a01556a0b31c62da2775b"
+
+[[package]]
+name = "either"
+version = "1.15.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719"
+
+[[package]]
+name = "env_filter"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "32e90c2accc4b07a8456ea0debdc2e7587bdd890680d71173a15d4ae604f6eef"
+dependencies = [
+ "log",
+ "regex",
+]
+
+[[package]]
+name = "env_logger"
+version = "0.11.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0621c04f2196ac3f488dd583365b9c09be011a4ab8b9f37248ffcc8f6198b56a"
+dependencies = [
+ "anstream",
+ "anstyle",
+ "env_filter",
+ "jiff",
+ "log",
+]
+
+[[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.117",
+]
+
+[[package]]
+name = "equivalent"
+version = "1.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
+
+[[package]]
+name = "errno"
+version = "0.3.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb"
+dependencies = [
+ "libc",
+ "windows-sys 0.61.2",
+]
+
+[[package]]
+name = "exr"
+version = "1.74.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4300e043a56aa2cb633c01af81ca8f699a321879a7854d3896a0ba89056363be"
+dependencies = [
+ "bit_field",
+ "half",
+ "lebe",
+ "miniz_oxide",
+ "rayon-core",
+ "smallvec",
+ "zune-inflate",
+]
+
+[[package]]
+name = "fastrand"
+version = "2.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9f1f227452a390804cdb637b74a86990f2a7d7ba4b7d5693aac9b4dd6defd8d6"
+
+[[package]]
+name = "fax"
+version = "0.2.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "caf1079563223d5d59d83c85886a56e586cfd5c1a26292e971a0fa266531ac5a"
+
+[[package]]
+name = "fdeflate"
+version = "0.3.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1e6853b52649d4ac5c0bd02320cddc5ba956bdb407c4b75a2c6b75bf51500f8c"
+dependencies = [
+ "simd-adler32",
+]
+
+[[package]]
+name = "field-offset"
+version = "0.3.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "38e2275cc4e4fc009b0669731a1e5ab7ebf11f469eaede2bab9309a5b4d6057f"
+dependencies = [
+ "memoffset",
+ "rustc_version",
+]
+
+[[package]]
+name = "find-msvc-tools"
+version = "0.1.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582"
+
+[[package]]
+name = "flate2"
+version = "1.1.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "843fba2746e448b37e26a819579957415c8cef339bf08564fe8b7ddbd959573c"
+dependencies = [
+ "crc32fast",
+ "miniz_oxide",
+]
+
+[[package]]
+name = "foreign-types"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d737d9aa519fb7b749cbc3b962edcf310a8dd1f4b67c91c4f83975dbdd17d965"
+dependencies = [
+ "foreign-types-macros",
+ "foreign-types-shared",
+]
+
+[[package]]
+name = "foreign-types-macros"
+version = "0.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.117",
+]
+
+[[package]]
+name = "foreign-types-shared"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "aa9a19cbb55df58761df49b23516a86d432839add4af60fc256da840f66ed35b"
+
+[[package]]
+name = "form_urlencoded"
+version = "1.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf"
+dependencies = [
+ "percent-encoding",
+]
+
+[[package]]
+name = "futures-channel"
+version = "0.3.32"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "07bbe89c50d7a535e539b8c17bc0b49bdb77747034daa8087407d655f3f7cc1d"
+dependencies = [
+ "futures-core",
+]
+
+[[package]]
+name = "futures-core"
+version = "0.3.32"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d"
+
+[[package]]
+name = "futures-executor"
+version = "0.3.32"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "baf29c38818342a3b26b5b923639e7b1f4a61fc5e76102d4b1981c6dc7a7579d"
+dependencies = [
+ "futures-core",
+ "futures-task",
+ "futures-util",
+]
+
+[[package]]
+name = "futures-io"
+version = "0.3.32"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cecba35d7ad927e23624b22ad55235f2239cfa44fd10428eecbeba6d6a717718"
+
+[[package]]
+name = "futures-macro"
+version = "0.3.32"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e835b70203e41293343137df5c0664546da5745f82ec9b84d40be8336958447b"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.117",
+]
+
+[[package]]
+name = "futures-task"
+version = "0.3.32"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393"
+
+[[package]]
+name = "futures-util"
+version = "0.3.32"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6"
+dependencies = [
+ "futures-core",
+ "futures-macro",
+ "futures-task",
+ "pin-project-lite",
+ "slab",
+]
+
+[[package]]
+name = "gdk"
+version = "0.18.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d9f245958c627ac99d8e529166f9823fb3b838d1d41fd2b297af3075093c2691"
+dependencies = [
+ "cairo-rs",
+ "gdk-pixbuf",
+ "gdk-sys",
+ "gio",
+ "glib",
+ "libc",
+ "pango",
+]
+
+[[package]]
+name = "gdk-pixbuf"
+version = "0.18.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "50e1f5f1b0bfb830d6ccc8066d18db35c487b1b2b1e8589b5dfe9f07e8defaec"
+dependencies = [
+ "gdk-pixbuf-sys",
+ "gio",
+ "glib",
+ "libc",
+ "once_cell",
+]
+
+[[package]]
+name = "gdk-pixbuf-sys"
+version = "0.18.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3f9839ea644ed9c97a34d129ad56d38a25e6756f99f3a88e15cd39c20629caf7"
+dependencies = [
+ "gio-sys",
+ "glib-sys",
+ "gobject-sys",
+ "libc",
+ "system-deps",
+]
+
+[[package]]
+name = "gdk-sys"
+version = "0.18.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5c2d13f38594ac1e66619e188c6d5a1adb98d11b2fcf7894fc416ad76aa2f3f7"
+dependencies = [
+ "cairo-sys-rs",
+ "gdk-pixbuf-sys",
+ "gio-sys",
+ "glib-sys",
+ "gobject-sys",
+ "libc",
+ "pango-sys",
+ "pkg-config",
+ "system-deps",
+]
+
+[[package]]
+name = "gdkwayland-sys"
+version = "0.18.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "140071d506d223f7572b9f09b5e155afbd77428cd5cc7af8f2694c41d98dfe69"
+dependencies = [
+ "gdk-sys",
+ "glib-sys",
+ "gobject-sys",
+ "libc",
+ "pkg-config",
+ "system-deps",
+]
+
+[[package]]
+name = "gdkx11-sys"
+version = "0.18.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6e2e7445fe01ac26f11601db260dd8608fe172514eb63b3b5e261ea6b0f4428d"
+dependencies = [
+ "gdk-sys",
+ "glib-sys",
+ "libc",
+ "system-deps",
+ "x11",
+]
+
+[[package]]
+name = "gethostname"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1bd49230192a3797a9a4d6abe9b3eed6f7fa4c8a8a4947977c6f80025f92cbd8"
+dependencies = [
+ "rustix 1.1.4",
+ "windows-link 0.2.1",
+]
+
+[[package]]
+name = "getrandom"
+version = "0.3.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd"
+dependencies = [
+ "cfg-if",
+ "libc",
+ "r-efi",
+ "wasip2",
+]
+
+[[package]]
+name = "gif"
+version = "0.14.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ee8cfcc411d9adbbaba82fb72661cc1bcca13e8bba98b364e62b2dba8f960159"
+dependencies = [
+ "color_quant",
+ "weezl",
+]
+
+[[package]]
+name = "gio"
+version = "0.18.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d4fc8f532f87b79cbc51a79748f16a6828fb784be93145a322fa14d06d354c73"
+dependencies = [
+ "futures-channel",
+ "futures-core",
+ "futures-io",
+ "futures-util",
+ "gio-sys",
+ "glib",
+ "libc",
+ "once_cell",
+ "pin-project-lite",
+ "smallvec",
+ "thiserror 1.0.69",
+]
+
+[[package]]
+name = "gio-sys"
+version = "0.18.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "37566df850baf5e4cb0dfb78af2e4b9898d817ed9263d1090a2df958c64737d2"
+dependencies = [
+ "glib-sys",
+ "gobject-sys",
+ "libc",
+ "system-deps",
+ "winapi",
+]
+
+[[package]]
+name = "glib"
+version = "0.18.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "233daaf6e83ae6a12a52055f568f9d7cf4671dabb78ff9560ab6da230ce00ee5"
+dependencies = [
+ "bitflags",
+ "futures-channel",
+ "futures-core",
+ "futures-executor",
+ "futures-task",
+ "futures-util",
+ "gio-sys",
+ "glib-macros",
+ "glib-sys",
+ "gobject-sys",
+ "libc",
+ "memchr",
+ "once_cell",
+ "smallvec",
+ "thiserror 1.0.69",
+]
+
+[[package]]
+name = "glib-macros"
+version = "0.18.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0bb0228f477c0900c880fd78c8759b95c7636dbd7842707f49e132378aa2acdc"
+dependencies = [
+ "heck 0.4.1",
+ "proc-macro-crate 2.0.2",
+ "proc-macro-error",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.117",
+]
+
+[[package]]
+name = "glib-sys"
+version = "0.18.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "063ce2eb6a8d0ea93d2bf8ba1957e78dbab6be1c2220dd3daca57d5a9d869898"
+dependencies = [
+ "libc",
+ "system-deps",
+]
+
+[[package]]
+name = "gobject-sys"
+version = "0.18.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0850127b514d1c4a4654ead6dedadb18198999985908e6ffe4436f53c785ce44"
+dependencies = [
+ "glib-sys",
+ "libc",
+ "system-deps",
+]
+
+[[package]]
+name = "gtk"
+version = "0.18.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fd56fb197bfc42bd5d2751f4f017d44ff59fbb58140c6b49f9b3b2bdab08506a"
+dependencies = [
+ "atk",
+ "cairo-rs",
+ "field-offset",
+ "futures-channel",
+ "gdk",
+ "gdk-pixbuf",
+ "gio",
+ "glib",
+ "gtk-sys",
+ "gtk3-macros",
+ "libc",
+ "pango",
+ "pkg-config",
+]
+
+[[package]]
+name = "gtk-sys"
+version = "0.18.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8f29a1c21c59553eb7dd40e918be54dccd60c52b049b75119d5d96ce6b624414"
+dependencies = [
+ "atk-sys",
+ "cairo-sys-rs",
+ "gdk-pixbuf-sys",
+ "gdk-sys",
+ "gio-sys",
+ "glib-sys",
+ "gobject-sys",
+ "libc",
+ "pango-sys",
+ "system-deps",
+]
+
+[[package]]
+name = "gtk3-macros"
+version = "0.18.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "52ff3c5b21f14f0736fed6dcfc0bfb4225ebf5725f3c0209edeec181e4d73e9d"
+dependencies = [
+ "proc-macro-crate 1.3.1",
+ "proc-macro-error",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.117",
+]
+
+[[package]]
+name = "half"
+version = "2.7.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6ea2d84b969582b4b1864a92dc5d27cd2b77b622a8d79306834f1be5ba20d84b"
+dependencies = [
+ "cfg-if",
+ "crunchy",
+ "zerocopy",
+]
+
+[[package]]
+name = "hashbrown"
+version = "0.17.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4f467dd6dccf739c208452f8014c75c18bb8301b050ad1cfb27153803edb0f51"
+
+[[package]]
+name = "heck"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
+
+[[package]]
+name = "heck"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
+
+[[package]]
+name = "icu_collections"
+version = "2.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2984d1cd16c883d7935b9e07e44071dca8d917fd52ecc02c04d5fa0b5a3f191c"
+dependencies = [
+ "displaydoc",
+ "potential_utf",
+ "utf8_iter",
+ "yoke",
+ "zerofrom",
+ "zerovec",
+]
+
+[[package]]
+name = "icu_locale_core"
+version = "2.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "92219b62b3e2b4d88ac5119f8904c10f8f61bf7e95b640d25ba3075e6cac2c29"
+dependencies = [
+ "displaydoc",
+ "litemap",
+ "tinystr",
+ "writeable",
+ "zerovec",
+]
+
+[[package]]
+name = "icu_normalizer"
+version = "2.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c56e5ee99d6e3d33bd91c5d85458b6005a22140021cc324cea84dd0e72cff3b4"
+dependencies = [
+ "icu_collections",
+ "icu_normalizer_data",
+ "icu_properties",
+ "icu_provider",
+ "smallvec",
+ "zerovec",
+]
+
+[[package]]
+name = "icu_normalizer_data"
+version = "2.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "da3be0ae77ea334f4da67c12f149704f19f81d1adf7c51cf482943e84a2bad38"
+
+[[package]]
+name = "icu_properties"
+version = "2.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bee3b67d0ea5c2cca5003417989af8996f8604e34fb9ddf96208a033901e70de"
+dependencies = [
+ "icu_collections",
+ "icu_locale_core",
+ "icu_properties_data",
+ "icu_provider",
+ "zerotrie",
+ "zerovec",
+]
+
+[[package]]
+name = "icu_properties_data"
+version = "2.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8e2bbb201e0c04f7b4b3e14382af113e17ba4f63e2c9d2ee626b720cbce54a14"
+
+[[package]]
+name = "icu_provider"
+version = "2.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "139c4cf31c8b5f33d7e199446eff9c1e02decfc2f0eec2c8d71f65befa45b421"
+dependencies = [
+ "displaydoc",
+ "icu_locale_core",
+ "writeable",
+ "yoke",
+ "zerofrom",
+ "zerotrie",
+ "zerovec",
+]
+
+[[package]]
+name = "idna"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de"
+dependencies = [
+ "idna_adapter",
+ "smallvec",
+ "utf8_iter",
+]
+
+[[package]]
+name = "idna_adapter"
+version = "1.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cb68373c0d6620ef8105e855e7745e18b0d00d3bdb07fb532e434244cdb9a714"
+dependencies = [
+ "icu_normalizer",
+ "icu_properties",
+]
+
+[[package]]
+name = "image"
+version = "0.25.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "85ab80394333c02fe689eaf900ab500fbd0c2213da414687ebf995a65d5a6104"
+dependencies = [
+ "bytemuck",
+ "byteorder-lite",
+ "color_quant",
+ "exr",
+ "gif",
+ "image-webp",
+ "moxcms",
+ "num-traits",
+ "png",
+ "qoi",
+ "ravif",
+ "rayon",
+ "rgb",
+ "tiff",
+ "zune-core",
+ "zune-jpeg",
+]
+
+[[package]]
+name = "image-webp"
+version = "0.2.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "525e9ff3e1a4be2fbea1fdf0e98686a6d98b4d8f937e1bf7402245af1909e8c3"
+dependencies = [
+ "byteorder-lite",
+ "quick-error",
+]
+
+[[package]]
+name = "imgref"
+version = "1.12.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "40fac9d56ed6437b198fddba683305e8e2d651aa42647f00f5ae542e7f5c94a2"
+
+[[package]]
+name = "indexmap"
+version = "2.14.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9"
+dependencies = [
+ "equivalent",
+ "hashbrown",
+]
+
+[[package]]
+name = "interpolate_name"
+version = "0.2.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c34819042dc3d3971c46c2190835914dfbe0c3c13f61449b2997f4e9722dfa60"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.117",
+]
+
+[[package]]
+name = "is_terminal_polyfill"
+version = "1.70.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695"
+
+[[package]]
+name = "itertools"
+version = "0.14.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285"
+dependencies = [
+ "either",
+]
+
+[[package]]
+name = "jiff"
+version = "0.2.24"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f00b5dbd620d61dfdcb6007c9c1f6054ebd75319f163d886a9055cec1155073d"
+dependencies = [
+ "jiff-static",
+ "log",
+ "portable-atomic",
+ "portable-atomic-util",
+ "serde_core",
+]
+
+[[package]]
+name = "jiff-static"
+version = "0.2.24"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e000de030ff8022ea1da3f466fbb0f3a809f5e51ed31f6dd931c35181ad8e6d7"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.117",
+]
+
+[[package]]
+name = "jni"
+version = "0.21.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1a87aa2bb7d2af34197c04845522473242e1aa17c12f4935d5856491a7fb8c97"
+dependencies = [
+ "cesu8",
+ "cfg-if",
+ "combine",
+ "jni-sys 0.3.1",
+ "log",
+ "thiserror 1.0.69",
+ "walkdir",
+ "windows-sys 0.45.0",
+]
+
+[[package]]
+name = "jni-sys"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "41a652e1f9b6e0275df1f15b32661cf0d4b78d4d87ddec5e0c3c20f097433258"
+dependencies = [
+ "jni-sys 0.4.1",
+]
+
+[[package]]
+name = "jni-sys"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c6377a88cb3910bee9b0fa88d4f42e1d2da8e79915598f65fb0c7ee14c878af2"
+dependencies = [
+ "jni-sys-macros",
+]
+
+[[package]]
+name = "jni-sys-macros"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "38c0b942f458fe50cdac086d2f946512305e5631e720728f2a61aabcd47a6264"
+dependencies = [
+ "quote",
+ "syn 2.0.117",
+]
+
+[[package]]
+name = "jobserver"
+version = "0.1.34"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33"
+dependencies = [
+ "getrandom",
+ "libc",
+]
+
+[[package]]
+name = "js-sys"
+version = "0.3.97"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a1840c94c045fbcf8ba2812c95db44499f7c64910a912551aaaa541decebcacf"
+dependencies = [
+ "cfg-if",
+ "futures-util",
+ "once_cell",
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "lebe"
+version = "0.5.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7a79a3332a6609480d7d0c9eab957bca6b455b91bb84e66d19f5ff66294b85b8"
+
+[[package]]
+name = "libc"
+version = "0.2.186"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66"
+
+[[package]]
+name = "libdbus-sys"
+version = "0.2.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "328c4789d42200f1eeec05bd86c9c13c7f091d2ba9a6ea35acdf51f31bc0f043"
+dependencies = [
+ "pkg-config",
+]
+
+[[package]]
+name = "libfuzzer-sys"
+version = "0.4.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f12a681b7dd8ce12bff52488013ba614b869148d54dd79836ab85aafdd53f08d"
+dependencies = [
+ "arbitrary",
+ "cc",
+]
+
+[[package]]
+name = "libloading"
+version = "0.8.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d7c4b02199fee7c5d21a5ae7d8cfa79a6ef5bb2fc834d6e9058e89c825efdc55"
+dependencies = [
+ "cfg-if",
+ "windows-link 0.2.1",
+]
+
+[[package]]
+name = "linux-raw-sys"
+version = "0.4.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab"
+
+[[package]]
+name = "linux-raw-sys"
+version = "0.9.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12"
+
+[[package]]
+name = "linux-raw-sys"
+version = "0.12.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53"
+
+[[package]]
+name = "litemap"
+version = "0.8.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "92daf443525c4cce67b150400bc2316076100ce0b3686209eb8cf3c31612e6f0"
+
+[[package]]
+name = "lock_api"
+version = "0.4.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965"
+dependencies = [
+ "scopeguard",
+]
+
+[[package]]
+name = "log"
+version = "0.4.29"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897"
+
+[[package]]
+name = "loop9"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0fae87c125b03c1d2c0150c90365d7d6bcc53fb73a9acaef207d2d065860f062"
+dependencies = [
+ "imgref",
+]
+
+[[package]]
+name = "maybe-rayon"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8ea1f30cedd69f0a2954655f7188c6a834246d2bcf1e315e2ac40c4b24dc9519"
+dependencies = [
+ "cfg-if",
+ "rayon",
+]
+
+[[package]]
+name = "memchr"
+version = "2.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79"
+
+[[package]]
+name = "memmap2"
+version = "0.9.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "714098028fe011992e1c3962653c96b2d578c4b4bce9036e15ff220319b1e0e3"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "memoffset"
+version = "0.9.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a"
+dependencies = [
+ "autocfg",
+]
+
+[[package]]
+name = "miniz_oxide"
+version = "0.8.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316"
+dependencies = [
+ "adler2",
+ "simd-adler32",
+]
+
+[[package]]
+name = "moxcms"
+version = "0.8.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bb85c154ba489f01b25c0d36ae69a87e4a1c73a72631fc6c0eb6dde34a73e44b"
+dependencies = [
+ "num-traits",
+ "pxfm",
+]
+
+[[package]]
+name = "ndk"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c3f42e7bbe13d351b6bead8286a43aac9534b82bd3cc43e47037f012ebfd62d4"
+dependencies = [
+ "bitflags",
+ "jni-sys 0.3.1",
+ "log",
+ "ndk-sys",
+ "num_enum",
+ "raw-window-handle 0.6.2",
+ "thiserror 1.0.69",
+]
+
+[[package]]
+name = "ndk-sys"
+version = "0.6.0+11769913"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ee6cda3051665f1fb8d9e08fc35c96d5a244fb1be711a03b71118828afc9a873"
+dependencies = [
+ "jni-sys 0.3.1",
+]
+
+[[package]]
+name = "new_debug_unreachable"
+version = "1.0.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086"
+
+[[package]]
+name = "no_std_io2"
+version = "0.9.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b51ed7824b6e07d354605f4abb3d9d300350701299da96642ee084f5ce631550"
+dependencies = [
+ "memchr",
+]
+
+[[package]]
+name = "nom"
+version = "8.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "df9761775871bdef83bee530e60050f7e54b1105350d6884eb0fb4f46c2f9405"
+dependencies = [
+ "memchr",
+]
+
+[[package]]
+name = "noop_proc_macro"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0676bb32a98c1a483ce53e500a81ad9c3d5b3f7c920c28c24e9cb0980d0b5bc8"
+
+[[package]]
+name = "num-bigint"
+version = "0.4.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9"
+dependencies = [
+ "num-integer",
+ "num-traits",
+]
+
+[[package]]
+name = "num-derive"
+version = "0.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.117",
+]
+
+[[package]]
+name = "num-integer"
+version = "0.1.46"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f"
+dependencies = [
+ "num-traits",
+]
+
+[[package]]
+name = "num-rational"
+version = "0.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824"
+dependencies = [
+ "num-bigint",
+ "num-integer",
+ "num-traits",
+]
+
+[[package]]
+name = "num-traits"
+version = "0.2.19"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
+dependencies = [
+ "autocfg",
+]
+
+[[package]]
+name = "num_enum"
+version = "0.7.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5d0bca838442ec211fa11de3a8b0e0e8f3a4522575b5c4c06ed722e005036f26"
+dependencies = [
+ "num_enum_derive",
+ "rustversion",
+]
+
+[[package]]
+name = "num_enum_derive"
+version = "0.7.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "680998035259dcfcafe653688bf2aa6d3e2dc05e98be6ab46afb089dc84f1df8"
+dependencies = [
+ "proc-macro-crate 3.5.0",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.117",
+]
+
+[[package]]
+name = "objc2"
+version = "0.6.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3a12a8ed07aefc768292f076dc3ac8c48f3781c8f2d5851dd3d98950e8c5a89f"
+dependencies = [
+ "objc2-encode",
+]
+
+[[package]]
+name = "objc2-app-kit"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d49e936b501e5c5bf01fda3a9452ff86dc3ea98ad5f283e1455153142d97518c"
+dependencies = [
+ "bitflags",
+ "objc2",
+ "objc2-core-foundation",
+ "objc2-foundation",
+]
+
+[[package]]
+name = "objc2-cloud-kit"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "73ad74d880bb43877038da939b7427bba67e9dd42004a18b809ba7d87cee241c"
+dependencies = [
+ "bitflags",
+ "objc2",
+ "objc2-foundation",
+]
+
+[[package]]
+name = "objc2-core-data"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0b402a653efbb5e82ce4df10683b6b28027616a2715e90009947d50b8dd298fa"
+dependencies = [
+ "objc2",
+ "objc2-foundation",
+]
+
+[[package]]
+name = "objc2-core-foundation"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2a180dd8642fa45cdb7dd721cd4c11b1cadd4929ce112ebd8b9f5803cc79d536"
+dependencies = [
+ "bitflags",
+ "dispatch2",
+ "objc2",
+]
+
+[[package]]
+name = "objc2-core-graphics"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e022c9d066895efa1345f8e33e584b9f958da2fd4cd116792e15e07e4720a807"
+dependencies = [
+ "bitflags",
+ "dispatch2",
+ "objc2",
+ "objc2-core-foundation",
+ "objc2-io-surface",
+]
+
+[[package]]
+name = "objc2-core-image"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e5d563b38d2b97209f8e861173de434bd0214cf020e3423a52624cd1d989f006"
+dependencies = [
+ "objc2",
+ "objc2-foundation",
+]
+
+[[package]]
+name = "objc2-core-location"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ca347214e24bc973fc025fd0d36ebb179ff30536ed1f80252706db19ee452009"
+dependencies = [
+ "objc2",
+ "objc2-foundation",
+]
+
+[[package]]
+name = "objc2-core-text"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0cde0dfb48d25d2b4862161a4d5fcc0e3c24367869ad306b0c9ec0073bfed92d"
+dependencies = [
+ "bitflags",
+ "objc2",
+ "objc2-core-foundation",
+ "objc2-core-graphics",
+]
+
+[[package]]
+name = "objc2-encode"
+version = "4.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ef25abbcd74fb2609453eb695bd2f860d389e457f67dc17cafc8b8cbc89d0c33"
+
+[[package]]
+name = "objc2-foundation"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e3e0adef53c21f888deb4fa59fc59f7eb17404926ee8a6f59f5df0fd7f9f3272"
+dependencies = [
+ "bitflags",
+ "objc2",
+ "objc2-core-foundation",
+]
+
+[[package]]
+name = "objc2-io-surface"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "180788110936d59bab6bd83b6060ffdfffb3b922ba1396b312ae795e1de9d81d"
+dependencies = [
+ "bitflags",
+ "objc2",
+ "objc2-core-foundation",
+]
+
+[[package]]
+name = "objc2-quartz-core"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "96c1358452b371bf9f104e21ec536d37a650eb10f7ee379fff67d2e08d537f1f"
+dependencies = [
+ "bitflags",
+ "objc2",
+ "objc2-core-foundation",
+ "objc2-foundation",
+]
+
+[[package]]
+name = "objc2-ui-kit"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d87d638e33c06f577498cbcc50491496a3ed4246998a7fbba7ccb98b1e7eab22"
+dependencies = [
+ "bitflags",
+ "block2",
+ "objc2",
+ "objc2-cloud-kit",
+ "objc2-core-data",
+ "objc2-core-foundation",
+ "objc2-core-graphics",
+ "objc2-core-image",
+ "objc2-core-location",
+ "objc2-core-text",
+ "objc2-foundation",
+ "objc2-quartz-core",
+ "objc2-user-notifications",
+]
+
+[[package]]
+name = "objc2-user-notifications"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9df9128cbbfef73cda168416ccf7f837b62737d748333bfe9ab71c245d76613e"
+dependencies = [
+ "objc2",
+ "objc2-foundation",
+]
+
+[[package]]
+name = "once_cell"
+version = "1.21.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50"
+
+[[package]]
+name = "once_cell_polyfill"
+version = "1.70.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe"
+
+[[package]]
+name = "pango"
+version = "0.18.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7ca27ec1eb0457ab26f3036ea52229edbdb74dee1edd29063f5b9b010e7ebee4"
+dependencies = [
+ "gio",
+ "glib",
+ "libc",
+ "once_cell",
+ "pango-sys",
+]
+
+[[package]]
+name = "pango-sys"
+version = "0.18.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "436737e391a843e5933d6d9aa102cb126d501e815b83601365a948a518555dc5"
+dependencies = [
+ "glib-sys",
+ "gobject-sys",
+ "libc",
+ "system-deps",
+]
+
+[[package]]
+name = "parking_lot"
+version = "0.12.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a"
+dependencies = [
+ "lock_api",
+ "parking_lot_core",
+]
+
+[[package]]
+name = "parking_lot_core"
+version = "0.9.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1"
+dependencies = [
+ "cfg-if",
+ "libc",
+ "redox_syscall",
+ "smallvec",
+ "windows-link 0.2.1",
+]
+
+[[package]]
+name = "paste"
+version = "1.0.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a"
+
+[[package]]
+name = "pastey"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "35fb2e5f958ec131621fdd531e9fc186ed768cbe395337403ae56c17a74c68ec"
+
+[[package]]
+name = "percent-encoding"
+version = "2.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220"
+
+[[package]]
+name = "pin-project-lite"
+version = "0.2.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd"
+
+[[package]]
+name = "pkg-config"
+version = "0.3.33"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "19f132c84eca552bf34cab8ec81f1c1dcc229b811638f9d283dceabe58c5569e"
+
+[[package]]
+name = "png"
+version = "0.18.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "60769b8b31b2a9f263dae2776c37b1b28ae246943cf719eb6946a1db05128a61"
+dependencies = [
+ "bitflags",
+ "crc32fast",
+ "fdeflate",
+ "flate2",
+ "miniz_oxide",
+]
+
+[[package]]
+name = "portable-atomic"
+version = "1.13.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c33a9471896f1c69cecef8d20cbe2f7accd12527ce60845ff44c153bb2a21b49"
+
+[[package]]
+name = "portable-atomic-util"
+version = "0.2.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c2a106d1259c23fac8e543272398ae0e3c0b8d33c88ed73d0cc71b0f1d902618"
+dependencies = [
+ "portable-atomic",
+]
+
+[[package]]
+name = "potential_utf"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0103b1cef7ec0cf76490e969665504990193874ea05c85ff9bab8b911d0a0564"
+dependencies = [
+ "zerovec",
+]
+
+[[package]]
+name = "ppv-lite86"
+version = "0.2.21"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9"
+dependencies = [
+ "zerocopy",
+]
+
+[[package]]
+name = "proc-macro-crate"
+version = "1.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919"
+dependencies = [
+ "once_cell",
+ "toml_edit 0.19.15",
+]
+
+[[package]]
+name = "proc-macro-crate"
+version = "2.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b00f26d3400549137f92511a46ac1cd8ce37cb5598a96d382381458b992a5d24"
+dependencies = [
+ "toml_datetime 0.6.3",
+ "toml_edit 0.20.2",
+]
+
+[[package]]
+name = "proc-macro-crate"
+version = "3.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e67ba7e9b2b56446f1d419b1d807906278ffa1a658a8a5d8a39dcb1f5a78614f"
+dependencies = [
+ "toml_edit 0.25.11+spec-1.1.0",
+]
+
+[[package]]
+name = "proc-macro-error"
+version = "1.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c"
+dependencies = [
+ "proc-macro-error-attr",
+ "proc-macro2",
+ "quote",
+ "syn 1.0.109",
+ "version_check",
+]
+
+[[package]]
+name = "proc-macro-error-attr"
+version = "1.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "version_check",
+]
+
+[[package]]
+name = "proc-macro2"
+version = "1.0.106"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934"
+dependencies = [
+ "unicode-ident",
+]
+
+[[package]]
+name = "profiling"
+version = "1.0.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3d595e54a326bc53c1c197b32d295e14b169e3cfeaa8dc82b529f947fba6bcf5"
+dependencies = [
+ "profiling-procmacros",
+]
+
+[[package]]
+name = "profiling-procmacros"
+version = "1.0.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4488a4a36b9a4ba6b9334a32a39971f77c1436ec82c38707bce707699cc3bbcb"
+dependencies = [
+ "quote",
+ "syn 2.0.117",
+]
+
+[[package]]
+name = "pxfm"
+version = "0.1.29"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e0c5ccf5294c6ccd63a74f1565028353830a9c2f5eb0c682c355c471726a6e3f"
+
+[[package]]
+name = "qoi"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7f6d64c71eb498fe9eae14ce4ec935c555749aef511cca85b5568910d6e48001"
+dependencies = [
+ "bytemuck",
+]
+
+[[package]]
+name = "quick-error"
+version = "2.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3"
+
+[[package]]
+name = "quick-xml"
+version = "0.39.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "958f21e8e7ceb5a1aa7fa87fab28e7c75976e0bfe7e23ff069e0a260f894067d"
+dependencies = [
+ "memchr",
+]
+
+[[package]]
+name = "quote"
+version = "1.0.45"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924"
+dependencies = [
+ "proc-macro2",
+]
+
+[[package]]
+name = "r-efi"
+version = "5.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f"
+
+[[package]]
+name = "rand"
+version = "0.9.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "44c5af06bb1b7d3216d91932aed5265164bf384dc89cd6ba05cf59a35f5f76ea"
+dependencies = [
+ "rand_chacha",
+ "rand_core",
+]
+
+[[package]]
+name = "rand_chacha"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb"
+dependencies = [
+ "ppv-lite86",
+ "rand_core",
+]
+
+[[package]]
+name = "rand_core"
+version = "0.9.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c"
+dependencies = [
+ "getrandom",
+]
+
+[[package]]
+name = "rav1e"
+version = "0.8.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "43b6dd56e85d9483277cde964fd1bdb0428de4fec5ebba7540995639a21cb32b"
+dependencies = [
+ "aligned-vec",
+ "arbitrary",
+ "arg_enum_proc_macro",
+ "arrayvec",
+ "av-scenechange",
+ "av1-grain",
+ "bitstream-io",
+ "built",
+ "cfg-if",
+ "interpolate_name",
+ "itertools",
+ "libc",
+ "libfuzzer-sys",
+ "log",
+ "maybe-rayon",
+ "new_debug_unreachable",
+ "noop_proc_macro",
+ "num-derive",
+ "num-traits",
+ "paste",
+ "profiling",
+ "rand",
+ "rand_chacha",
+ "simd_helpers",
+ "thiserror 2.0.18",
+ "v_frame",
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "ravif"
+version = "0.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e52310197d971b0f5be7fe6b57530dcd27beb35c1b013f29d66c1ad73fbbcc45"
+dependencies = [
+ "avif-serialize",
+ "imgref",
+ "loop9",
+ "quick-error",
+ "rav1e",
+ "rayon",
+ "rgb",
+]
+
+[[package]]
+name = "raw-window-handle"
+version = "0.4.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b800beb9b6e7d2df1fe337c9e3d04e3af22a124460fb4c30fcc22c9117cefb41"
+dependencies = [
+ "cty",
+]
+
+[[package]]
+name = "raw-window-handle"
+version = "0.5.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f2ff9a1f06a88b01621b7ae906ef0211290d1c8a168a15542486a8f61c0833b9"
+
+[[package]]
+name = "raw-window-handle"
+version = "0.6.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "20675572f6f24e9e76ef639bc5552774ed45f1c30e2951e1e99c59888861c539"
+
+[[package]]
+name = "rayon"
+version = "1.12.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fb39b166781f92d482534ef4b4b1b2568f42613b53e5b6c160e24cfbfa30926d"
+dependencies = [
+ "either",
+ "rayon-core",
+]
+
+[[package]]
+name = "rayon-core"
+version = "1.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "22e18b0f0062d30d4230b2e85ff77fdfe4326feb054b9783a3460d8435c8ab91"
+dependencies = [
+ "crossbeam-deque",
+ "crossbeam-utils",
+]
+
+[[package]]
+name = "redox_syscall"
+version = "0.5.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d"
+dependencies = [
+ "bitflags",
+]
+
+[[package]]
+name = "regex"
+version = "1.12.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276"
+dependencies = [
+ "aho-corasick",
+ "memchr",
+ "regex-automata",
+ "regex-syntax",
+]
+
+[[package]]
+name = "regex-automata"
+version = "0.4.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f"
+dependencies = [
+ "aho-corasick",
+ "memchr",
+ "regex-syntax",
+]
+
+[[package]]
+name = "regex-syntax"
+version = "0.8.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a"
+
+[[package]]
+name = "rgb"
+version = "0.8.53"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "47b34b781b31e5d73e9fbc8689c70551fd1ade9a19e3e28cfec8580a79290cc4"
+
+[[package]]
+name = "rustc_version"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92"
+dependencies = [
+ "semver",
+]
+
+[[package]]
+name = "rustix"
+version = "0.38.44"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154"
+dependencies = [
+ "bitflags",
+ "errno",
+ "libc",
+ "linux-raw-sys 0.4.15",
+ "windows-sys 0.59.0",
+]
+
+[[package]]
+name = "rustix"
+version = "1.1.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190"
+dependencies = [
+ "bitflags",
+ "errno",
+ "libc",
+ "linux-raw-sys 0.12.1",
+ "windows-sys 0.61.2",
+]
+
+[[package]]
+name = "rustversion"
+version = "1.0.22"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d"
+
+[[package]]
+name = "same-file"
+version = "1.0.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
+dependencies = [
+ "winapi-util",
+]
+
+[[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"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
+
+[[package]]
+name = "semver"
+version = "1.0.28"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd"
+
+[[package]]
+name = "serde"
+version = "1.0.228"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e"
+dependencies = [
+ "serde_core",
+ "serde_derive",
+]
+
+[[package]]
+name = "serde_core"
+version = "1.0.228"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad"
+dependencies = [
+ "serde_derive",
+]
+
+[[package]]
+name = "serde_derive"
+version = "1.0.228"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.117",
+]
+
+[[package]]
+name = "serde_spanned"
+version = "0.6.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bf41e0cfaf7226dca15e8197172c295a782857fcb97fad1808a166870dee75a3"
+dependencies = [
+ "serde",
+]
+
+[[package]]
+name = "shlex"
+version = "1.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
+
+[[package]]
+name = "simd-adler32"
+version = "0.3.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "703d5c7ef118737c72f1af64ad2f6f8c5e1921f818cdcb97b8fe6fc69bf66214"
+
+[[package]]
+name = "simd_helpers"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "95890f873bec569a0362c235787f3aca6e1e887302ba4840839bcc6459c42da6"
+dependencies = [
+ "quote",
+]
+
+[[package]]
+name = "slab"
+version = "0.4.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5"
+
+[[package]]
+name = "smallvec"
+version = "1.15.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03"
+
+[[package]]
+name = "softbuffer"
+version = "0.4.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "aac18da81ebbf05109ab275b157c22a653bb3c12cf884450179942f81bcbf6c3"
+dependencies = [
+ "as-raw-xcb-connection",
+ "bytemuck",
+ "drm",
+ "fastrand",
+ "js-sys",
+ "memmap2",
+ "ndk",
+ "objc2",
+ "objc2-core-foundation",
+ "objc2-core-graphics",
+ "objc2-foundation",
+ "objc2-quartz-core",
+ "raw-window-handle 0.6.2",
+ "redox_syscall",
+ "rustix 1.1.4",
+ "tiny-xlib",
+ "tracing",
+ "wasm-bindgen",
+ "wayland-backend",
+ "wayland-client",
+ "wayland-sys",
+ "web-sys",
+ "windows-sys 0.61.2",
+ "x11rb",
+]
+
+[[package]]
+name = "stable_deref_trait"
+version = "1.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596"
+
+[[package]]
+name = "syn"
+version = "1.0.109"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
+dependencies = [
+ "proc-macro2",
+ "unicode-ident",
+]
+
+[[package]]
+name = "syn"
+version = "2.0.117"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-ident",
+]
+
+[[package]]
+name = "synstructure"
+version = "0.13.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.117",
+]
+
+[[package]]
+name = "system-deps"
+version = "6.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a3e535eb8dded36d55ec13eddacd30dec501792ff23a0b1682c38601b8cf2349"
+dependencies = [
+ "cfg-expr",
+ "heck 0.5.0",
+ "pkg-config",
+ "toml",
+ "version-compare",
+]
+
+[[package]]
+name = "tao"
+version = "0.35.2"
+dependencies = [
+ "bitflags",
+ "block2",
+ "core-foundation",
+ "core-graphics",
+ "crossbeam-channel",
+ "dbus",
+ "dispatch2",
+ "dlopen2",
+ "dpi",
+ "env_logger",
+ "gdkwayland-sys",
+ "gdkx11-sys",
+ "gtk",
+ "image",
+ "jni",
+ "libc",
+ "log",
+ "ndk",
+ "ndk-sys",
+ "objc2",
+ "objc2-app-kit",
+ "objc2-foundation",
+ "objc2-ui-kit",
+ "once_cell",
+ "parking_lot",
+ "percent-encoding",
+ "raw-window-handle 0.4.3",
+ "raw-window-handle 0.5.2",
+ "raw-window-handle 0.6.2",
+ "serde",
+ "softbuffer",
+ "tao-macros",
+ "unicode-segmentation",
+ "url",
+ "windows",
+ "windows-core",
+ "windows-version",
+ "x11-dl",
+]
+
+[[package]]
+name = "tao-macros"
+version = "0.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f4e16beb8b2ac17db28eab8bca40e62dbfbb34c0fcdc6d9826b11b7b5d047dfd"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.117",
+]
+
+[[package]]
+name = "target-lexicon"
+version = "0.12.16"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1"
+
+[[package]]
+name = "thiserror"
+version = "1.0.69"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52"
+dependencies = [
+ "thiserror-impl 1.0.69",
+]
+
+[[package]]
+name = "thiserror"
+version = "2.0.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4"
+dependencies = [
+ "thiserror-impl 2.0.18",
+]
+
+[[package]]
+name = "thiserror-impl"
+version = "1.0.69"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.117",
+]
+
+[[package]]
+name = "thiserror-impl"
+version = "2.0.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.117",
+]
+
+[[package]]
+name = "tiff"
+version = "0.11.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b63feaf3343d35b6ca4d50483f94843803b0f51634937cc2ec519fc32232bc52"
+dependencies = [
+ "fax",
+ "flate2",
+ "half",
+ "quick-error",
+ "weezl",
+ "zune-jpeg",
+]
+
+[[package]]
+name = "tiny-xlib"
+version = "0.2.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a90a0ca3ee6a69f2ad28fd11621a4c3f03b371f366be500b64df260c4ffbafb4"
+dependencies = [
+ "as-raw-xcb-connection",
+ "ctor",
+ "libloading",
+ "pkg-config",
+ "tracing",
+]
+
+[[package]]
+name = "tinystr"
+version = "0.8.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c8323304221c2a851516f22236c5722a72eaa19749016521d6dff0824447d96d"
+dependencies = [
+ "displaydoc",
+ "zerovec",
+]
+
+[[package]]
+name = "toml"
+version = "0.8.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "185d8ab0dfbb35cf1399a6344d8484209c088f75f8f68230da55d48d95d43e3d"
+dependencies = [
+ "serde",
+ "serde_spanned",
+ "toml_datetime 0.6.3",
+ "toml_edit 0.20.2",
+]
+
+[[package]]
+name = "toml_datetime"
+version = "0.6.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b"
+dependencies = [
+ "serde",
+]
+
+[[package]]
+name = "toml_datetime"
+version = "1.1.1+spec-1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3165f65f62e28e0115a00b2ebdd37eb6f3b641855f9d636d3cd4103767159ad7"
+dependencies = [
+ "serde_core",
+]
+
+[[package]]
+name = "toml_edit"
+version = "0.19.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421"
+dependencies = [
+ "indexmap",
+ "toml_datetime 0.6.3",
+ "winnow 0.5.40",
+]
+
+[[package]]
+name = "toml_edit"
+version = "0.20.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "396e4d48bbb2b7554c944bde63101b5ae446cff6ec4a24227428f15eb72ef338"
+dependencies = [
+ "indexmap",
+ "serde",
+ "serde_spanned",
+ "toml_datetime 0.6.3",
+ "winnow 0.5.40",
+]
+
+[[package]]
+name = "toml_edit"
+version = "0.25.11+spec-1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0b59c4d22ed448339746c59b905d24568fcbb3ab65a500494f7b8c3e97739f2b"
+dependencies = [
+ "indexmap",
+ "toml_datetime 1.1.1+spec-1.1.0",
+ "toml_parser",
+ "winnow 1.0.2",
+]
+
+[[package]]
+name = "toml_parser"
+version = "1.1.2+spec-1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a2abe9b86193656635d2411dc43050282ca48aa31c2451210f4202550afb7526"
+dependencies = [
+ "winnow 1.0.2",
+]
+
+[[package]]
+name = "tracing"
+version = "0.1.44"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100"
+dependencies = [
+ "pin-project-lite",
+ "tracing-core",
+]
+
+[[package]]
+name = "tracing-core"
+version = "0.1.36"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a"
+
+[[package]]
+name = "unicode-ident"
+version = "1.0.24"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75"
+
+[[package]]
+name = "unicode-segmentation"
+version = "1.13.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9629274872b2bfaf8d66f5f15725007f635594914870f65218920345aa11aa8c"
+
+[[package]]
+name = "url"
+version = "2.5.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed"
+dependencies = [
+ "form_urlencoded",
+ "idna",
+ "percent-encoding",
+ "serde",
+]
+
+[[package]]
+name = "utf8_iter"
+version = "1.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be"
+
+[[package]]
+name = "utf8parse"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
+
+[[package]]
+name = "v_frame"
+version = "0.3.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "666b7727c8875d6ab5db9533418d7c764233ac9c0cff1d469aec8fa127597be2"
+dependencies = [
+ "aligned-vec",
+ "num-traits",
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "version-compare"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "03c2856837ef78f57382f06b2b8563a2f512f7185d732608fd9176cb3b8edf0e"
+
+[[package]]
+name = "version_check"
+version = "0.9.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
+
+[[package]]
+name = "walkdir"
+version = "2.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b"
+dependencies = [
+ "same-file",
+ "winapi-util",
+]
+
+[[package]]
+name = "wasip2"
+version = "1.0.3+wasi-0.2.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "20064672db26d7cdc89c7798c48a0fdfac8213434a1186e5ef29fd560ae223d6"
+dependencies = [
+ "wit-bindgen",
+]
+
+[[package]]
+name = "wasm-bindgen"
+version = "0.2.120"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "df52b6d9b87e0c74c9edfa1eb2d9bf85e5d63515474513aa50fa181b3c4f5db1"
+dependencies = [
+ "cfg-if",
+ "once_cell",
+ "rustversion",
+ "wasm-bindgen-macro",
+ "wasm-bindgen-shared",
+]
+
+[[package]]
+name = "wasm-bindgen-macro"
+version = "0.2.120"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "78b1041f495fb322e64aca85f5756b2172e35cd459376e67f2a6c9dffcedb103"
+dependencies = [
+ "quote",
+ "wasm-bindgen-macro-support",
+]
+
+[[package]]
+name = "wasm-bindgen-macro-support"
+version = "0.2.120"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9dcd0ff20416988a18ac686d4d4d0f6aae9ebf08a389ff5d29012b05af2a1b41"
+dependencies = [
+ "bumpalo",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.117",
+ "wasm-bindgen-shared",
+]
+
+[[package]]
+name = "wasm-bindgen-shared"
+version = "0.2.120"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "49757b3c82ebf16c57d69365a142940b384176c24df52a087fb748e2085359ea"
+dependencies = [
+ "unicode-ident",
+]
+
+[[package]]
+name = "wayland-backend"
+version = "0.3.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2857dd20b54e916ec7253b3d6b4d5c4d7d4ca2c33c2e11c6c76a99bd8744755d"
+dependencies = [
+ "cc",
+ "downcast-rs",
+ "rustix 1.1.4",
+ "scoped-tls",
+ "smallvec",
+ "wayland-sys",
+]
+
+[[package]]
+name = "wayland-client"
+version = "0.31.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "645c7c96bb74690c3189b5c9cb4ca1627062bb23693a4fad9d8c3de958260144"
+dependencies = [
+ "bitflags",
+ "rustix 1.1.4",
+ "wayland-backend",
+ "wayland-scanner",
+]
+
+[[package]]
+name = "wayland-scanner"
+version = "0.31.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9c324a910fd86ebdc364a3e61ec1f11737d3b1d6c273c0239ee8ff4bc0d24b4a"
+dependencies = [
+ "proc-macro2",
+ "quick-xml",
+ "quote",
+]
+
+[[package]]
+name = "wayland-sys"
+version = "0.31.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d8eab23fefc9e41f8e841df4a9c707e8a8c4ed26e944ef69297184de2785e3be"
+dependencies = [
+ "dlib",
+ "log",
+ "once_cell",
+ "pkg-config",
+]
+
+[[package]]
+name = "web-sys"
+version = "0.3.97"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2eadbac71025cd7b0834f20d1fe8472e8495821b4e9801eb0a60bd1f19827602"
+dependencies = [
+ "js-sys",
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "weezl"
+version = "0.1.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a28ac98ddc8b9274cb41bb4d9d4d5c425b6020c50c46f25559911905610b4a88"
+
+[[package]]
+name = "winapi"
+version = "0.3.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
+dependencies = [
+ "winapi-i686-pc-windows-gnu",
+ "winapi-x86_64-pc-windows-gnu",
+]
+
+[[package]]
+name = "winapi-i686-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
+
+[[package]]
+name = "winapi-util"
+version = "0.1.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22"
+dependencies = [
+ "windows-sys 0.61.2",
+]
+
+[[package]]
+name = "winapi-x86_64-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
+
+[[package]]
+name = "windows"
+version = "0.61.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9babd3a767a4c1aef6900409f85f5d53ce2544ccdfaa86dad48c91782c6d6893"
+dependencies = [
+ "windows-collections",
+ "windows-core",
+ "windows-future",
+ "windows-link 0.1.3",
+ "windows-numerics",
+]
+
+[[package]]
+name = "windows-collections"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3beeceb5e5cfd9eb1d76b381630e82c4241ccd0d27f1a39ed41b2760b255c5e8"
+dependencies = [
+ "windows-core",
+]
+
+[[package]]
+name = "windows-core"
+version = "0.61.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3"
+dependencies = [
+ "windows-implement",
+ "windows-interface",
+ "windows-link 0.1.3",
+ "windows-result",
+ "windows-strings",
+]
+
+[[package]]
+name = "windows-future"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fc6a41e98427b19fe4b73c550f060b59fa592d7d686537eebf9385621bfbad8e"
+dependencies = [
+ "windows-core",
+ "windows-link 0.1.3",
+ "windows-threading",
+]
+
+[[package]]
+name = "windows-implement"
+version = "0.60.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.117",
+]
+
+[[package]]
+name = "windows-interface"
+version = "0.59.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.117",
+]
+
+[[package]]
+name = "windows-link"
+version = "0.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a"
+
+[[package]]
+name = "windows-link"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
+
+[[package]]
+name = "windows-numerics"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9150af68066c4c5c07ddc0ce30421554771e528bde427614c61038bc2c92c2b1"
+dependencies = [
+ "windows-core",
+ "windows-link 0.1.3",
+]
+
+[[package]]
+name = "windows-result"
+version = "0.3.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6"
+dependencies = [
+ "windows-link 0.1.3",
+]
+
+[[package]]
+name = "windows-strings"
+version = "0.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57"
+dependencies = [
+ "windows-link 0.1.3",
+]
+
+[[package]]
+name = "windows-sys"
+version = "0.45.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0"
+dependencies = [
+ "windows-targets 0.42.2",
+]
+
+[[package]]
+name = "windows-sys"
+version = "0.59.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
+dependencies = [
+ "windows-targets 0.52.6",
+]
+
+[[package]]
+name = "windows-sys"
+version = "0.61.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc"
+dependencies = [
+ "windows-link 0.2.1",
+]
+
+[[package]]
+name = "windows-targets"
+version = "0.42.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071"
+dependencies = [
+ "windows_aarch64_gnullvm 0.42.2",
+ "windows_aarch64_msvc 0.42.2",
+ "windows_i686_gnu 0.42.2",
+ "windows_i686_msvc 0.42.2",
+ "windows_x86_64_gnu 0.42.2",
+ "windows_x86_64_gnullvm 0.42.2",
+ "windows_x86_64_msvc 0.42.2",
+]
+
+[[package]]
+name = "windows-targets"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
+dependencies = [
+ "windows_aarch64_gnullvm 0.52.6",
+ "windows_aarch64_msvc 0.52.6",
+ "windows_i686_gnu 0.52.6",
+ "windows_i686_gnullvm",
+ "windows_i686_msvc 0.52.6",
+ "windows_x86_64_gnu 0.52.6",
+ "windows_x86_64_gnullvm 0.52.6",
+ "windows_x86_64_msvc 0.52.6",
+]
+
+[[package]]
+name = "windows-threading"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b66463ad2e0ea3bbf808b7f1d371311c80e115c0b71d60efc142cafbcfb057a6"
+dependencies = [
+ "windows-link 0.1.3",
+]
+
+[[package]]
+name = "windows-version"
+version = "0.1.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e4060a1da109b9d0326b7262c8e12c84df67cc0dbc9e33cf49e01ccc2eb63631"
+dependencies = [
+ "windows-link 0.2.1",
+]
+
+[[package]]
+name = "windows_aarch64_gnullvm"
+version = "0.42.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8"
+
+[[package]]
+name = "windows_aarch64_gnullvm"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
+
+[[package]]
+name = "windows_aarch64_msvc"
+version = "0.42.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43"
+
+[[package]]
+name = "windows_aarch64_msvc"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
+
+[[package]]
+name = "windows_i686_gnu"
+version = "0.42.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f"
+
+[[package]]
+name = "windows_i686_gnu"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
+
+[[package]]
+name = "windows_i686_gnullvm"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
+
+[[package]]
+name = "windows_i686_msvc"
+version = "0.42.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060"
+
+[[package]]
+name = "windows_i686_msvc"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
+
+[[package]]
+name = "windows_x86_64_gnu"
+version = "0.42.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36"
+
+[[package]]
+name = "windows_x86_64_gnu"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
+
+[[package]]
+name = "windows_x86_64_gnullvm"
+version = "0.42.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3"
+
+[[package]]
+name = "windows_x86_64_gnullvm"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
+
+[[package]]
+name = "windows_x86_64_msvc"
+version = "0.42.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0"
+
+[[package]]
+name = "windows_x86_64_msvc"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
+
+[[package]]
+name = "winnow"
+version = "0.5.40"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876"
+dependencies = [
+ "memchr",
+]
+
+[[package]]
+name = "winnow"
+version = "1.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2ee1708bef14716a11bae175f579062d4554d95be2c6829f518df847b7b3fdd0"
+dependencies = [
+ "memchr",
+]
+
+[[package]]
+name = "wit-bindgen"
+version = "0.57.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e"
+
+[[package]]
+name = "writeable"
+version = "0.6.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1ffae5123b2d3fc086436f8834ae3ab053a283cfac8fe0a0b8eaae044768a4c4"
+
+[[package]]
+name = "x11"
+version = "2.21.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "502da5464ccd04011667b11c435cb992822c2c0dbde1770c988480d312a0db2e"
+dependencies = [
+ "libc",
+ "pkg-config",
+]
+
+[[package]]
+name = "x11-dl"
+version = "2.21.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "38735924fedd5314a6e548792904ed8c6de6636285cb9fec04d5b1db85c1516f"
+dependencies = [
+ "libc",
+ "once_cell",
+ "pkg-config",
+]
+
+[[package]]
+name = "x11rb"
+version = "0.13.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9993aa5be5a26815fe2c3eacfc1fde061fc1a1f094bf1ad2a18bf9c495dd7414"
+dependencies = [
+ "as-raw-xcb-connection",
+ "gethostname",
+ "libc",
+ "libloading",
+ "once_cell",
+ "rustix 1.1.4",
+ "x11rb-protocol",
+]
+
+[[package]]
+name = "x11rb-protocol"
+version = "0.13.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ea6fc2961e4ef194dcbfe56bb845534d0dc8098940c7e5c012a258bfec6701bd"
+
+[[package]]
+name = "y4m"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7a5a4b21e1a62b67a2970e6831bc091d7b87e119e7f9791aef9702e3bef04448"
+
+[[package]]
+name = "yoke"
+version = "0.8.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "abe8c5fda708d9ca3df187cae8bfb9ceda00dd96231bed36e445a1a48e66f9ca"
+dependencies = [
+ "stable_deref_trait",
+ "yoke-derive",
+ "zerofrom",
+]
+
+[[package]]
+name = "yoke-derive"
+version = "0.8.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "de844c262c8848816172cef550288e7dc6c7b7814b4ee56b3e1553f275f1858e"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.117",
+ "synstructure",
+]
+
+[[package]]
+name = "zerocopy"
+version = "0.8.48"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "eed437bf9d6692032087e337407a86f04cd8d6a16a37199ed57949d415bd68e9"
+dependencies = [
+ "zerocopy-derive",
+]
+
+[[package]]
+name = "zerocopy-derive"
+version = "0.8.48"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "70e3cd084b1788766f53af483dd21f93881ff30d7320490ec3ef7526d203bad4"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.117",
+]
+
+[[package]]
+name = "zerofrom"
+version = "0.1.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "69faa1f2a1ea75661980b013019ed6687ed0e83d069bc1114e2cc74c6c04c4df"
+dependencies = [
+ "zerofrom-derive",
+]
+
+[[package]]
+name = "zerofrom-derive"
+version = "0.1.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "11532158c46691caf0f2593ea8358fed6bbf68a0315e80aae9bd41fbade684a1"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.117",
+ "synstructure",
+]
+
+[[package]]
+name = "zerotrie"
+version = "0.2.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0f9152d31db0792fa83f70fb2f83148effb5c1f5b8c7686c3459e361d9bc20bf"
+dependencies = [
+ "displaydoc",
+ "yoke",
+ "zerofrom",
+]
+
+[[package]]
+name = "zerovec"
+version = "0.11.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "90f911cbc359ab6af17377d242225f4d75119aec87ea711a880987b18cd7b239"
+dependencies = [
+ "yoke",
+ "zerofrom",
+ "zerovec-derive",
+]
+
+[[package]]
+name = "zerovec-derive"
+version = "0.11.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "625dc425cab0dca6dc3c3319506e6593dcb08a9f387ea3b284dbd52a92c40555"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.117",
+]
+
+[[package]]
+name = "zune-core"
+version = "0.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cb8a0807f7c01457d0379ba880ba6322660448ddebc890ce29bb64da71fb40f9"
+
+[[package]]
+name = "zune-inflate"
+version = "0.2.54"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "73ab332fe2f6680068f3582b16a24f90ad7096d5d39b974d1c0aff0125116f02"
+dependencies = [
+ "simd-adler32",
+]
+
+[[package]]
+name = "zune-jpeg"
+version = "0.5.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "27bc9d5b815bc103f142aa054f561d9187d191692ec7c2d1e2b4737f8dbd7296"
+dependencies = [
+ "zune-core",
+]
diff --git a/frontend/src-tauri/patches/tao-0.35.2/Cargo.toml b/frontend/src-tauri/patches/tao-0.35.2/Cargo.toml
new file mode 100644
index 000000000..3f0674d4e
--- /dev/null
+++ b/frontend/src-tauri/patches/tao-0.35.2/Cargo.toml
@@ -0,0 +1,406 @@
+# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
+#
+# When uploading crates to the registry Cargo will automatically
+# "normalize" Cargo.toml files for maximal compatibility
+# with all versions of Cargo and also rewrite `path` dependencies
+# to registry (e.g., crates.io) dependencies.
+#
+# If you are reading this file be aware that the original Cargo.toml
+# will likely look very different (and much more reasonable).
+# See Cargo.toml.orig for the original contents.
+
+[package]
+edition = "2021"
+rust-version = "1.74"
+name = "tao"
+version = "0.35.2"
+authors = [
+ "Tauri Programme within The Commons Conservancy",
+ "The winit contributors",
+]
+build = false
+include = [
+ "/README.md",
+ "src/**/*.rs",
+ "examples/**/*.rs",
+ "LICENSE*",
+]
+autolib = false
+autobins = false
+autoexamples = false
+autotests = false
+autobenches = false
+description = "Cross-platform window manager library."
+documentation = "https://docs.rs/tao"
+readme = "README.md"
+keywords = ["windowing"]
+categories = ["gui"]
+license = "Apache-2.0"
+repository = "https://github.com/tauri-apps/tao"
+
+[package.metadata.docs.rs]
+features = [
+ "rwh_04",
+ "rwh_05",
+ "rwh_06",
+ "serde",
+ "x11",
+ "dbus",
+]
+default-target = "x86_64-unknown-linux-gnu"
+targets = [
+ "i686-pc-windows-msvc",
+ "x86_64-pc-windows-msvc",
+ "i686-unknown-linux-gnu",
+ "x86_64-unknown-linux-gnu",
+ "x86_64-apple-darwin",
+]
+
+[features]
+dbus = ["dep:dbus"]
+default = [
+ "rwh_06",
+ "x11",
+ "dbus",
+]
+rwh_04 = ["dep:rwh_04"]
+rwh_05 = ["dep:rwh_05"]
+rwh_06 = ["dep:rwh_06"]
+serde = [
+ "dep:serde",
+ "dpi/serde",
+]
+x11 = [
+ "dep:gdkx11-sys",
+ "dep:x11-dl",
+]
+
+[lib]
+name = "tao"
+path = "src/lib.rs"
+
+[[example]]
+name = "control_flow"
+path = "examples/control_flow.rs"
+
+[[example]]
+name = "cursor"
+path = "examples/cursor.rs"
+
+[[example]]
+name = "cursor_grab"
+path = "examples/cursor_grab.rs"
+
+[[example]]
+name = "custom_events"
+path = "examples/custom_events.rs"
+
+[[example]]
+name = "decorations"
+path = "examples/decorations.rs"
+
+[[example]]
+name = "drag_window"
+path = "examples/drag_window.rs"
+
+[[example]]
+name = "fullscreen"
+path = "examples/fullscreen.rs"
+
+[[example]]
+name = "handling_close"
+path = "examples/handling_close.rs"
+
+[[example]]
+name = "min_max_size"
+path = "examples/min_max_size.rs"
+
+[[example]]
+name = "minimize"
+path = "examples/minimize.rs"
+
+[[example]]
+name = "monitor_list"
+path = "examples/monitor_list.rs"
+
+[[example]]
+name = "mouse_wheel"
+path = "examples/mouse_wheel.rs"
+
+[[example]]
+name = "multithreaded"
+path = "examples/multithreaded.rs"
+
+[[example]]
+name = "multiwindow"
+path = "examples/multiwindow.rs"
+
+[[example]]
+name = "overlay"
+path = "examples/overlay.rs"
+
+[[example]]
+name = "parentwindow"
+path = "examples/parentwindow.rs"
+
+[[example]]
+name = "progress_bar"
+path = "examples/progress_bar.rs"
+
+[[example]]
+name = "reopen_event"
+path = "examples/reopen_event.rs"
+
+[[example]]
+name = "request_redraw"
+path = "examples/request_redraw.rs"
+
+[[example]]
+name = "request_redraw_threaded"
+path = "examples/request_redraw_threaded.rs"
+
+[[example]]
+name = "resizable"
+path = "examples/resizable.rs"
+
+[[example]]
+name = "set_ime_position"
+path = "examples/set_ime_position.rs"
+
+[[example]]
+name = "theme"
+path = "examples/theme.rs"
+
+[[example]]
+name = "timer"
+path = "examples/timer.rs"
+
+[[example]]
+name = "transparent"
+path = "examples/transparent.rs"
+
+[[example]]
+name = "video_modes"
+path = "examples/video_modes.rs"
+
+[[example]]
+name = "window"
+path = "examples/window.rs"
+
+[[example]]
+name = "window_debug"
+path = "examples/window_debug.rs"
+
+[[example]]
+name = "window_icon"
+path = "examples/window_icon.rs"
+
+[[example]]
+name = "window_run_return"
+path = "examples/window_run_return.rs"
+
+[dependencies.bitflags]
+version = "2"
+
+[dependencies.crossbeam-channel]
+version = "0.5"
+
+[dependencies.dpi]
+version = "0.1"
+
+[dependencies.libc]
+version = "0.2"
+
+[dependencies.log]
+version = "0.4"
+
+[dependencies.once_cell]
+version = "1"
+
+[dependencies.rwh_04]
+version = "0.4"
+optional = true
+package = "raw-window-handle"
+
+[dependencies.rwh_05]
+version = "0.5"
+features = ["std"]
+optional = true
+package = "raw-window-handle"
+
+[dependencies.rwh_06]
+version = "0.6"
+features = ["std"]
+optional = true
+package = "raw-window-handle"
+
+[dependencies.serde]
+version = "1"
+features = ["serde_derive"]
+optional = true
+
+[dependencies.url]
+version = "2"
+
+[dev-dependencies.env_logger]
+version = "0.11"
+
+[dev-dependencies.image]
+version = "0.25"
+
+[target.'cfg(any(target_os = "ios", target_os = "macos"))'.dependencies.block2]
+version = "0.6"
+
+[target.'cfg(any(target_os = "ios", target_os = "macos"))'.dependencies.objc2]
+version = "0.6"
+
+[target.'cfg(any(target_os = "linux", target_os = "dragonfly", target_os = "freebsd", target_os = "openbsd", target_os = "netbsd"))'.dependencies.dbus]
+version = "0.9"
+optional = true
+
+[target.'cfg(any(target_os = "linux", target_os = "dragonfly", target_os = "freebsd", target_os = "openbsd", target_os = "netbsd"))'.dependencies.dlopen2]
+version = "0.8.0"
+
+[target.'cfg(any(target_os = "linux", target_os = "dragonfly", target_os = "freebsd", target_os = "openbsd", target_os = "netbsd"))'.dependencies.gdkwayland-sys]
+version = "0.18.0"
+
+[target.'cfg(any(target_os = "linux", target_os = "dragonfly", target_os = "freebsd", target_os = "openbsd", target_os = "netbsd"))'.dependencies.gdkx11-sys]
+version = "0.18"
+optional = true
+
+[target.'cfg(any(target_os = "linux", target_os = "dragonfly", target_os = "freebsd", target_os = "openbsd", target_os = "netbsd"))'.dependencies.gtk]
+version = "0.18"
+
+[target.'cfg(any(target_os = "linux", target_os = "dragonfly", target_os = "freebsd", target_os = "openbsd", target_os = "netbsd"))'.dependencies.parking_lot]
+version = "0.12"
+
+[target.'cfg(any(target_os = "linux", target_os = "dragonfly", target_os = "freebsd", target_os = "openbsd", target_os = "netbsd"))'.dependencies.x11-dl]
+version = "2.21"
+optional = true
+
+[target.'cfg(target_os = "android")'.dependencies.jni]
+version = "0.21"
+
+[target.'cfg(target_os = "android")'.dependencies.ndk]
+version = "0.9"
+
+[target.'cfg(target_os = "android")'.dependencies.ndk-sys]
+version = "0.6"
+
+[target.'cfg(target_os = "android")'.dependencies.percent-encoding]
+version = "2.3"
+
+[target.'cfg(target_os = "android")'.dependencies.tao-macros]
+version = "0.1.0"
+
+[target.'cfg(target_os = "ios")'.dependencies.objc2-foundation]
+version = "0.3"
+features = ["NSProcessInfo"]
+default-features = false
+
+[target.'cfg(target_os = "ios")'.dependencies.objc2-ui-kit]
+version = "0.3"
+features = [
+ "UIResponder",
+ "UIScene",
+ "UISceneOptions",
+ "UIOpenURLContext",
+]
+
+[target.'cfg(target_os = "macos")'.dependencies.core-foundation]
+version = "0.10"
+
+[target.'cfg(target_os = "macos")'.dependencies.core-graphics]
+version = "0.25"
+
+[target.'cfg(target_os = "macos")'.dependencies.dispatch2]
+version = "0.3"
+
+[target.'cfg(target_os = "macos")'.dependencies.objc2-app-kit]
+version = "0.3"
+features = [
+ "std",
+ "objc2-core-foundation",
+ "NSApplication",
+ "NSButton",
+ "NSColor",
+ "NSControl",
+ "NSEvent",
+ "NSGraphics",
+ "NSImage",
+ "NSOpenGLView",
+ "NSPasteboard",
+ "NSResponder",
+ "NSRunningApplication",
+ "NSScreen",
+ "NSView",
+ "NSWindow",
+ "NSUserActivity",
+]
+default-features = false
+
+[target.'cfg(target_os = "macos")'.dependencies.objc2-foundation]
+version = "0.3"
+features = [
+ "std",
+ "NSArray",
+ "NSAttributedString",
+ "NSAutoreleasePool",
+ "NSDate",
+ "NSDictionary",
+ "NSEnumerator",
+ "NSGeometry",
+ "NSObjCRuntime",
+ "NSRange",
+ "NSString",
+ "NSThread",
+ "NSURL",
+]
+default-features = false
+
+[target.'cfg(target_os = "windows")'.dependencies.parking_lot]
+version = "0.12"
+
+[target.'cfg(target_os = "windows")'.dependencies.unicode-segmentation]
+version = "1.11"
+
+[target.'cfg(target_os = "windows")'.dependencies.windows]
+version = "0.61"
+features = [
+ "Win32_Devices_HumanInterfaceDevice",
+ "Win32_Foundation",
+ "Win32_Globalization",
+ "Win32_Graphics_Dwm",
+ "Win32_Graphics_Gdi",
+ "Win32_System_Com",
+ "Win32_System_Com_StructuredStorage",
+ "Win32_System_DataExchange",
+ "Win32_System_Diagnostics_Debug",
+ "Win32_System_LibraryLoader",
+ "Win32_System_Memory",
+ "Win32_System_Ole",
+ "Win32_System_Registry",
+ "Win32_System_SystemServices",
+ "Win32_System_Threading",
+ "Win32_System_WindowsProgramming",
+ "Win32_System_SystemInformation",
+ "Win32_UI_Accessibility",
+ "Win32_UI_Controls",
+ "Win32_UI_HiDpi",
+ "Win32_UI_Input_Ime",
+ "Win32_UI_Input_KeyboardAndMouse",
+ "Win32_UI_Input_Pointer",
+ "Win32_UI_Input_Touch",
+ "Win32_UI_Shell",
+ "Win32_UI_TextServices",
+ "Win32_UI_WindowsAndMessaging",
+]
+
+[target.'cfg(target_os = "windows")'.dependencies.windows-core]
+version = "0.61"
+
+[target.'cfg(target_os = "windows")'.dependencies.windows-version]
+version = "0.1"
+
+[target.'cfg(target_os = "windows")'.dev-dependencies.softbuffer]
+version = "0.4"
diff --git a/frontend/src-tauri/patches/tao-0.35.2/Cargo.toml.orig b/frontend/src-tauri/patches/tao-0.35.2/Cargo.toml.orig
new file mode 100644
index 000000000..75c8c138b
--- /dev/null
+++ b/frontend/src-tauri/patches/tao-0.35.2/Cargo.toml.orig
@@ -0,0 +1,172 @@
+[package]
+name = "tao"
+version = "0.35.2"
+description = "Cross-platform window manager library."
+authors = [
+ "Tauri Programme within The Commons Conservancy",
+ "The winit contributors",
+]
+edition = "2021"
+rust-version = "1.74"
+keywords = ["windowing"]
+license = "Apache-2.0"
+readme = "README.md"
+repository = "https://github.com/tauri-apps/tao"
+documentation = "https://docs.rs/tao"
+categories = ["gui"]
+include = ["/README.md", "src/**/*.rs", "examples/**/*.rs", "LICENSE*"]
+
+[package.metadata.docs.rs]
+features = ["rwh_04", "rwh_05", "rwh_06", "serde", "x11", "dbus"]
+default-target = "x86_64-unknown-linux-gnu"
+targets = [
+ "i686-pc-windows-msvc",
+ "x86_64-pc-windows-msvc",
+ "i686-unknown-linux-gnu",
+ "x86_64-unknown-linux-gnu",
+ "x86_64-apple-darwin",
+]
+
+[features]
+default = ["rwh_06", "x11", "dbus"]
+serde = ["dep:serde", "dpi/serde"]
+rwh_04 = ["dep:rwh_04"]
+rwh_05 = ["dep:rwh_05"]
+rwh_06 = ["dep:rwh_06"]
+x11 = ["dep:gdkx11-sys", "dep:x11-dl"]
+dbus = ["dep:dbus"]
+
+[workspace]
+members = ["tao-macros"]
+
+[dependencies]
+libc = "0.2"
+log = "0.4"
+once_cell = "1"
+serde = { version = "1", optional = true, features = ["serde_derive"] }
+rwh_04 = { package = "raw-window-handle", version = "0.4", optional = true }
+rwh_05 = { package = "raw-window-handle", version = "0.5", features = [
+ "std",
+], optional = true }
+rwh_06 = { package = "raw-window-handle", version = "0.6", features = [
+ "std",
+], optional = true }
+bitflags = "2"
+crossbeam-channel = "0.5"
+url = "2"
+dpi = "0.1"
+
+[dev-dependencies]
+image = "0.25"
+env_logger = "0.11"
+
+[target."cfg(target_os = \"windows\")".dev-dependencies]
+softbuffer = "0.4"
+
+[target."cfg(target_os = \"windows\")".dependencies]
+parking_lot = "0.12"
+unicode-segmentation = "1.11"
+windows-version = "0.1"
+windows-core = "0.61"
+
+[target."cfg(target_os = \"windows\")".dependencies.windows]
+version = "0.61"
+features = [
+ "Win32_Devices_HumanInterfaceDevice",
+ "Win32_Foundation",
+ "Win32_Globalization",
+ "Win32_Graphics_Dwm",
+ "Win32_Graphics_Gdi",
+ "Win32_System_Com",
+ "Win32_System_Com_StructuredStorage",
+ "Win32_System_DataExchange",
+ "Win32_System_Diagnostics_Debug",
+ "Win32_System_LibraryLoader",
+ "Win32_System_Memory",
+ "Win32_System_Ole",
+ "Win32_System_Registry",
+ "Win32_System_SystemServices",
+ "Win32_System_Threading",
+ "Win32_System_WindowsProgramming",
+ "Win32_System_SystemInformation",
+ "Win32_UI_Accessibility",
+ "Win32_UI_Controls",
+ "Win32_UI_HiDpi",
+ "Win32_UI_Input_Ime",
+ "Win32_UI_Input_KeyboardAndMouse",
+ "Win32_UI_Input_Pointer",
+ "Win32_UI_Input_Touch",
+ "Win32_UI_Shell",
+ "Win32_UI_TextServices",
+ "Win32_UI_WindowsAndMessaging",
+]
+
+[target."cfg(target_os = \"android\")".dependencies]
+jni = "0.21"
+ndk = "0.9"
+ndk-sys = "0.6"
+percent-encoding = "2.3"
+tao-macros = { version = "0.1.0", path = "./tao-macros" }
+
+[target."cfg(any(target_os = \"ios\", target_os = \"macos\"))".dependencies]
+objc2 = "0.6"
+block2 = "0.6"
+
+[target."cfg(target_os = \"macos\")".dependencies]
+objc2-foundation = { version = "0.3", default-features = false, features = [
+ "std",
+ "NSArray",
+ "NSAttributedString",
+ "NSAutoreleasePool",
+ "NSDate",
+ "NSDictionary",
+ "NSEnumerator",
+ "NSGeometry",
+ "NSObjCRuntime",
+ "NSRange",
+ "NSString",
+ "NSThread",
+ "NSURL",
+] }
+objc2-app-kit = { version = "0.3", default-features = false, features = [
+ "std",
+ "objc2-core-foundation",
+ "NSApplication",
+ "NSButton",
+ "NSColor",
+ "NSControl",
+ "NSEvent",
+ "NSGraphics",
+ "NSImage",
+ "NSOpenGLView",
+ "NSPasteboard",
+ "NSResponder",
+ "NSRunningApplication",
+ "NSScreen",
+ "NSView",
+ "NSWindow",
+ "NSUserActivity",
+] }
+core-foundation = "0.10"
+core-graphics = "0.25"
+dispatch2 = "0.3"
+
+[target."cfg(target_os = \"ios\")".dependencies]
+objc2-ui-kit = { version = "0.3", features = [
+ "UIResponder",
+ "UIScene",
+ "UISceneOptions",
+ "UIOpenURLContext",
+] }
+objc2-foundation = { version = "0.3", default-features = false, features = [
+ "NSProcessInfo",
+] }
+
+[target."cfg(any(target_os = \"linux\", target_os = \"dragonfly\", target_os = \"freebsd\", target_os = \"openbsd\", target_os = \"netbsd\"))".dependencies]
+gtk = "0.18"
+gdkx11-sys = { version = "0.18", optional = true }
+gdkwayland-sys = "0.18.0"
+x11-dl = { version = "2.21", optional = true }
+parking_lot = "0.12"
+dlopen2 = "0.8.0"
+dbus = { version = "0.9", optional = true }
diff --git a/frontend/src-tauri/patches/tao-0.35.2/LICENSE b/frontend/src-tauri/patches/tao-0.35.2/LICENSE
new file mode 100644
index 000000000..ad410e113
--- /dev/null
+++ b/frontend/src-tauri/patches/tao-0.35.2/LICENSE
@@ -0,0 +1,201 @@
+Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "{}"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright {yyyy} {name of copyright owner}
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
\ No newline at end of file
diff --git a/frontend/src-tauri/patches/tao-0.35.2/LICENSE.spdx b/frontend/src-tauri/patches/tao-0.35.2/LICENSE.spdx
new file mode 100644
index 000000000..ac886c6d6
--- /dev/null
+++ b/frontend/src-tauri/patches/tao-0.35.2/LICENSE.spdx
@@ -0,0 +1,18 @@
+SPDXVersion: SPDX-2.1
+DataLicense: CC0-1.0
+PackageName: tao
+DataFormat: SPDXRef-1
+PackageSupplier: Organization: The Tauri Programme in the Commons Conservancy
+PackageHomePage: https://tauri.app
+PackageLicenseDeclared: Apache-2.0
+PackageCopyrightText: 2021-2023, The Tauri Programme in the Commons Conservancy
+PackageSummary: Tao is the official, rust-based window manager for Wry.
+
+PackageComment: The package includes the following libraries; see
+Relationship information.
+
+Created: 2020-05-20T09:00:00Z
+PackageDownloadLocation: git://github.com/tauri-apps/tao
+PackageDownloadLocation: git+https://github.com/tauri-apps/tao.git
+PackageDownloadLocation: git+ssh://github.com/tauri-apps/tao.git
+Creator: Person: Daniel Thompson-Yvetot
diff --git a/frontend/src-tauri/patches/tao-0.35.2/README.md b/frontend/src-tauri/patches/tao-0.35.2/README.md
new file mode 100644
index 000000000..a7d504619
--- /dev/null
+++ b/frontend/src-tauri/patches/tao-0.35.2/README.md
@@ -0,0 +1,80 @@
+
+
+[](https://crates.io/crates/tao)
+[](https://docs.rs/tao/)
+[](https://opencollective.com/tauri)
+[](https://discord.gg/SpmNs4S)
+[](https://tauri.app)
+[](https://good-labs.github.io/greater-good-affirmation)
+[](https://opencollective.com/tauri)
+
+Cross-platform application window creation library in Rust that supports all major platforms like
+Windows, macOS, Linux, iOS and Android. Built for you, maintained for Tauri.
+
+### Cargo Features
+
+TAO provides the following features, which can be enabled in your `Cargo.toml` file:
+
+- `serde`: Enables serialization/deserialization of certain types with [Serde](https://crates.io/crates/serde).
+
+## Platform-specific notes
+
+### Android
+
+This library makes use of the [ndk-rs](https://github.com/rust-windowing/android-ndk-rs) crates, refer to that repo for more documentation.
+
+Running on an Android device needs a dynamic system library, add this to Cargo.toml:
+
+```toml
+[[example]]
+name = "request_redraw_threaded"
+crate-type = ["cdylib"]
+```
+
+And add this to the example file to add the native activity glue:
+
+```rust
+#[cfg_attr(target_os = "android", ndk_glue::main(backtrace = "on"))]
+fn main() {
+ ...
+}
+```
+
+And run the application with `cargo apk run --example request_redraw_threaded`
+
+### Linux
+
+Gtk and its related libraries are used to build the support of Linux. Be sure to install following packages before building:
+
+#### Arch Linux / Manjaro:
+
+```bash
+sudo pacman -S gtk3
+```
+
+#### Debian / Ubuntu:
+
+```bash
+sudo apt install libgtk-3-dev
+```
+
+### Acknowledgement
+
+This is a fork of [winit](https://crates.io/crates/winit) which replaces Linux's port to Gtk.
+In the future, we want to make these features more modular as separate crates. So we can switch back to winit and also benefit the whole community.
+
+## Partners
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+For the complete list of sponsors please visit our [website](https://tauri.app#sponsors) and [Open Collective](https://opencollective.com/tauri).
diff --git a/frontend/src-tauri/patches/tao-0.35.2/examples/control_flow.rs b/frontend/src-tauri/patches/tao-0.35.2/examples/control_flow.rs
new file mode 100644
index 000000000..45148bfd2
--- /dev/null
+++ b/frontend/src-tauri/patches/tao-0.35.2/examples/control_flow.rs
@@ -0,0 +1,120 @@
+// Copyright 2014-2021 The winit contributors
+// Copyright 2021-2023 Tauri Programme within The Commons Conservancy
+// SPDX-License-Identifier: Apache-2.0
+
+use std::{thread, time};
+
+use tao::{
+ event::{ElementState, Event, KeyEvent, WindowEvent},
+ event_loop::{ControlFlow, EventLoop},
+ keyboard::Key,
+ window::WindowBuilder,
+};
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+enum Mode {
+ Wait,
+ WaitUntil,
+ Poll,
+}
+
+const WAIT_TIME: time::Duration = time::Duration::from_millis(100);
+const POLL_SLEEP_TIME: time::Duration = time::Duration::from_millis(100);
+
+#[allow(clippy::single_match)]
+fn main() {
+ env_logger::init();
+
+ println!("Press '1' to switch to Wait mode.");
+ println!("Press '2' to switch to WaitUntil mode.");
+ println!("Press '3' to switch to Poll mode.");
+ println!("Press 'R' to toggle request_redraw() calls.");
+ println!("Press 'Esc' to close the window.");
+
+ let event_loop = EventLoop::new();
+ let window = WindowBuilder::new()
+ .with_title("Press 1, 2, 3 to change control flow mode. Press R to toggle redraw requests.")
+ .build(&event_loop)
+ .unwrap();
+
+ let mut mode = Mode::Wait;
+ let mut request_redraw = false;
+ let mut wait_cancelled = false;
+ let mut close_requested = false;
+
+ event_loop.run(move |event, _, control_flow| {
+ use tao::event::StartCause;
+ println!("{event:?}");
+ match event {
+ Event::NewEvents(start_cause) => {
+ wait_cancelled = match start_cause {
+ StartCause::WaitCancelled { .. } => mode == Mode::WaitUntil,
+ _ => false,
+ }
+ }
+ Event::WindowEvent { event, .. } => match event {
+ WindowEvent::CloseRequested => {
+ close_requested = true;
+ }
+ WindowEvent::KeyboardInput {
+ event:
+ KeyEvent {
+ logical_key,
+ state: ElementState::Pressed,
+ ..
+ },
+ ..
+ } => {
+ // WARNING: Consider using `key_without_modifers()` if available on your platform.
+ // See the `key_binding` example
+ if Key::Character("1") == logical_key {
+ mode = Mode::Wait;
+ println!("\nmode: {mode:?}\n");
+ }
+ if Key::Character("2") == logical_key {
+ mode = Mode::WaitUntil;
+ println!("\nmode: {mode:?}\n");
+ }
+ if Key::Character("3") == logical_key {
+ mode = Mode::Poll;
+ println!("\nmode: {mode:?}\n");
+ }
+ if Key::Character("r") == logical_key {
+ request_redraw = !request_redraw;
+ println!("\nrequest_redraw: {request_redraw}\n");
+ }
+ if Key::Escape == logical_key {
+ close_requested = true;
+ }
+ }
+ _ => {}
+ },
+ Event::MainEventsCleared => {
+ if request_redraw && !wait_cancelled && !close_requested {
+ window.request_redraw();
+ }
+ if close_requested {
+ *control_flow = ControlFlow::Exit;
+ }
+ }
+ Event::RedrawRequested(_window_id) => {}
+ Event::RedrawEventsCleared => {
+ *control_flow = match mode {
+ Mode::Wait => ControlFlow::Wait,
+ Mode::WaitUntil => {
+ if wait_cancelled {
+ *control_flow
+ } else {
+ ControlFlow::WaitUntil(time::Instant::now() + WAIT_TIME)
+ }
+ }
+ Mode::Poll => {
+ thread::sleep(POLL_SLEEP_TIME);
+ ControlFlow::Poll
+ }
+ };
+ }
+ _ => (),
+ }
+ });
+}
diff --git a/frontend/src-tauri/patches/tao-0.35.2/examples/cursor.rs b/frontend/src-tauri/patches/tao-0.35.2/examples/cursor.rs
new file mode 100644
index 000000000..48a91d6a9
--- /dev/null
+++ b/frontend/src-tauri/patches/tao-0.35.2/examples/cursor.rs
@@ -0,0 +1,89 @@
+// Copyright 2014-2021 The winit contributors
+// Copyright 2021-2023 Tauri Programme within The Commons Conservancy
+// SPDX-License-Identifier: Apache-2.0
+
+use tao::{
+ event::{ElementState, Event, KeyEvent, WindowEvent},
+ event_loop::{ControlFlow, EventLoop},
+ window::{CursorIcon, WindowBuilder},
+};
+
+fn main() {
+ env_logger::init();
+ let event_loop = EventLoop::new();
+
+ let window = WindowBuilder::new().build(&event_loop).unwrap();
+ window.set_title("A fantastic window!");
+
+ let mut cursor_idx = 0;
+
+ event_loop.run(move |event, _, control_flow| {
+ *control_flow = ControlFlow::Wait;
+
+ match event {
+ Event::WindowEvent {
+ event:
+ WindowEvent::KeyboardInput {
+ event:
+ KeyEvent {
+ state: ElementState::Pressed,
+ ..
+ },
+ ..
+ },
+ ..
+ } => {
+ println!("Setting cursor to \"{:?}\"", CURSORS[cursor_idx]);
+ window.set_cursor_icon(CURSORS[cursor_idx]);
+ if cursor_idx < CURSORS.len() - 1 {
+ cursor_idx += 1;
+ } else {
+ cursor_idx = 0;
+ }
+ }
+ Event::WindowEvent {
+ event: WindowEvent::CloseRequested,
+ ..
+ } => *control_flow = ControlFlow::Exit,
+ _ => (),
+ }
+ });
+}
+
+const CURSORS: &[CursorIcon] = &[
+ CursorIcon::Default,
+ CursorIcon::Crosshair,
+ CursorIcon::Hand,
+ CursorIcon::Arrow,
+ CursorIcon::Move,
+ CursorIcon::Text,
+ CursorIcon::Wait,
+ CursorIcon::Help,
+ CursorIcon::Progress,
+ CursorIcon::NotAllowed,
+ CursorIcon::ContextMenu,
+ CursorIcon::Cell,
+ CursorIcon::VerticalText,
+ CursorIcon::Alias,
+ CursorIcon::Copy,
+ CursorIcon::NoDrop,
+ CursorIcon::Grab,
+ CursorIcon::Grabbing,
+ CursorIcon::AllScroll,
+ CursorIcon::ZoomIn,
+ CursorIcon::ZoomOut,
+ CursorIcon::EResize,
+ CursorIcon::NResize,
+ CursorIcon::NeResize,
+ CursorIcon::NwResize,
+ CursorIcon::SResize,
+ CursorIcon::SeResize,
+ CursorIcon::SwResize,
+ CursorIcon::WResize,
+ CursorIcon::EwResize,
+ CursorIcon::NsResize,
+ CursorIcon::NeswResize,
+ CursorIcon::NwseResize,
+ CursorIcon::ColResize,
+ CursorIcon::RowResize,
+];
diff --git a/frontend/src-tauri/patches/tao-0.35.2/examples/cursor_grab.rs b/frontend/src-tauri/patches/tao-0.35.2/examples/cursor_grab.rs
new file mode 100644
index 000000000..a939d8201
--- /dev/null
+++ b/frontend/src-tauri/patches/tao-0.35.2/examples/cursor_grab.rs
@@ -0,0 +1,66 @@
+// Copyright 2014-2021 The winit contributors
+// Copyright 2021-2023 Tauri Programme within The Commons Conservancy
+// SPDX-License-Identifier: Apache-2.0
+
+use tao::{
+ event::{DeviceEvent, ElementState, Event, KeyEvent, WindowEvent},
+ event_loop::{ControlFlow, EventLoop},
+ keyboard::{Key, ModifiersState},
+ window::WindowBuilder,
+};
+
+#[allow(clippy::single_match)]
+fn main() {
+ env_logger::init();
+ let event_loop = EventLoop::new();
+
+ let window = WindowBuilder::new()
+ .with_title("Super Cursor Grab'n'Hide Simulator 9000")
+ .build(&event_loop)
+ .unwrap();
+
+ let mut modifiers = ModifiersState::default();
+
+ event_loop.run(move |event, _, control_flow| {
+ *control_flow = ControlFlow::Wait;
+
+ match event {
+ Event::WindowEvent { event, .. } => match event {
+ WindowEvent::CloseRequested => *control_flow = ControlFlow::Exit,
+ WindowEvent::KeyboardInput {
+ event:
+ KeyEvent {
+ logical_key: key,
+ state: ElementState::Released,
+ ..
+ },
+ ..
+ } => {
+ // WARNING: Consider using `key_without_modifers()` if available on your platform.
+ // See the `key_binding` example
+ match key {
+ Key::Escape => *control_flow = ControlFlow::Exit,
+ Key::Character(ch) => match ch.to_lowercase().as_str() {
+ "g" => window.set_cursor_grab(!modifiers.shift_key()).unwrap(),
+ "h" => window.set_cursor_visible(modifiers.shift_key()),
+ _ => (),
+ },
+ _ => (),
+ }
+ }
+ WindowEvent::ModifiersChanged(m) => modifiers = m,
+ _ => (),
+ },
+ Event::DeviceEvent { event, .. } => match event {
+ DeviceEvent::MouseMotion { delta, .. } => println!("mouse moved: {delta:?}"),
+ DeviceEvent::Button { button, state, .. } => match state {
+ ElementState::Pressed => println!("mouse button {button} pressed"),
+ ElementState::Released => println!("mouse button {button} released"),
+ _ => (),
+ },
+ _ => (),
+ },
+ _ => (),
+ }
+ });
+}
diff --git a/frontend/src-tauri/patches/tao-0.35.2/examples/custom_events.rs b/frontend/src-tauri/patches/tao-0.35.2/examples/custom_events.rs
new file mode 100644
index 000000000..f94d00113
--- /dev/null
+++ b/frontend/src-tauri/patches/tao-0.35.2/examples/custom_events.rs
@@ -0,0 +1,51 @@
+// Copyright 2014-2021 The winit contributors
+// Copyright 2021-2023 Tauri Programme within The Commons Conservancy
+// SPDX-License-Identifier: Apache-2.0
+
+#[allow(clippy::single_match)]
+fn main() {
+ env_logger::init();
+ use tao::{
+ event::{Event, WindowEvent},
+ event_loop::{ControlFlow, EventLoopBuilder},
+ window::WindowBuilder,
+ };
+
+ #[derive(Debug, Clone, Copy)]
+ enum CustomEvent {
+ Timer,
+ }
+
+ let event_loop = EventLoopBuilder::::with_user_event().build();
+
+ let _window = WindowBuilder::new()
+ .with_title("A fantastic window!")
+ .build(&event_loop)
+ .unwrap();
+
+ // `EventLoopProxy` allows you to dispatch custom events to the main Tao event
+ // loop from any thread.
+ let event_loop_proxy = event_loop.create_proxy();
+
+ std::thread::spawn(move || {
+ // Wake up the `event_loop` once every second and dispatch a custom event
+ // from a different thread.
+ loop {
+ std::thread::sleep(std::time::Duration::from_secs(1));
+ event_loop_proxy.send_event(CustomEvent::Timer).ok();
+ }
+ });
+
+ event_loop.run(move |event, _, control_flow| {
+ *control_flow = ControlFlow::Wait;
+
+ match event {
+ Event::UserEvent(event) => println!("user event: {event:?}"),
+ Event::WindowEvent {
+ event: WindowEvent::CloseRequested,
+ ..
+ } => *control_flow = ControlFlow::Exit,
+ _ => (),
+ }
+ });
+}
diff --git a/frontend/src-tauri/patches/tao-0.35.2/examples/decorations.rs b/frontend/src-tauri/patches/tao-0.35.2/examples/decorations.rs
new file mode 100644
index 000000000..d9025e2b4
--- /dev/null
+++ b/frontend/src-tauri/patches/tao-0.35.2/examples/decorations.rs
@@ -0,0 +1,51 @@
+// Copyright 2014-2021 The winit contributors
+// Copyright 2021-2023 Tauri Programme within The Commons Conservancy
+// SPDX-License-Identifier: Apache-2.0
+
+use tao::{
+ dpi::LogicalSize,
+ event::{ElementState, Event, KeyEvent, WindowEvent},
+ event_loop::{ControlFlow, EventLoop},
+ keyboard::KeyCode,
+ window::WindowBuilder,
+};
+
+#[allow(clippy::single_match)]
+fn main() {
+ env_logger::init();
+ let event_loop = EventLoop::new();
+
+ let mut decorations = true;
+
+ let window = WindowBuilder::new()
+ .with_title("Hit space to toggle decorations.")
+ .with_inner_size(LogicalSize::new(400.0, 200.0))
+ .with_decorations(decorations)
+ .build(&event_loop)
+ .unwrap();
+
+ event_loop.run(move |event, _, control_flow| {
+ *control_flow = ControlFlow::Wait;
+
+ match event {
+ Event::WindowEvent { event, .. } => match event {
+ WindowEvent::CloseRequested => *control_flow = ControlFlow::Exit,
+ WindowEvent::KeyboardInput {
+ event:
+ KeyEvent {
+ physical_key: KeyCode::Space,
+ state: ElementState::Released,
+ ..
+ },
+ ..
+ } => {
+ decorations = !decorations;
+ println!("Decorations: {decorations}");
+ window.set_decorations(decorations);
+ }
+ _ => (),
+ },
+ _ => (),
+ };
+ });
+}
diff --git a/frontend/src-tauri/patches/tao-0.35.2/examples/drag_window.rs b/frontend/src-tauri/patches/tao-0.35.2/examples/drag_window.rs
new file mode 100644
index 000000000..895c360d3
--- /dev/null
+++ b/frontend/src-tauri/patches/tao-0.35.2/examples/drag_window.rs
@@ -0,0 +1,78 @@
+// Copyright 2014-2021 The winit contributors
+// Copyright 2021-2023 Tauri Programme within The Commons Conservancy
+// SPDX-License-Identifier: Apache-2.0
+
+use tao::{
+ event::{ElementState, Event, KeyEvent, MouseButton, StartCause, WindowEvent},
+ event_loop::{ControlFlow, EventLoop},
+ keyboard::Key,
+ window::{Window, WindowBuilder, WindowId},
+};
+
+#[allow(clippy::single_match)]
+fn main() {
+ env_logger::init();
+ let event_loop = EventLoop::new();
+
+ let window_1 = WindowBuilder::new().build(&event_loop).unwrap();
+ let window_2 = WindowBuilder::new().build(&event_loop).unwrap();
+
+ let mut switched = false;
+ let mut entered_id = window_2.id();
+
+ event_loop.run(move |event, _, control_flow| match event {
+ Event::NewEvents(StartCause::Init) => {
+ eprintln!("Switch which window is to be dragged by pressing \"x\".")
+ }
+ Event::WindowEvent {
+ event, window_id, ..
+ } => match event {
+ WindowEvent::CloseRequested => *control_flow = ControlFlow::Exit,
+ WindowEvent::MouseInput {
+ state: ElementState::Pressed,
+ button: MouseButton::Left,
+ ..
+ } => {
+ let window = if (window_id == window_1.id() && switched)
+ || (window_id == window_2.id() && !switched)
+ {
+ &window_2
+ } else {
+ &window_1
+ };
+
+ window.drag_window().unwrap()
+ }
+ WindowEvent::CursorEntered { .. } => {
+ entered_id = window_id;
+ name_windows(entered_id, switched, &window_1, &window_2)
+ }
+ WindowEvent::KeyboardInput {
+ event:
+ KeyEvent {
+ state: ElementState::Released,
+ logical_key: Key::Character("x"),
+ ..
+ },
+ ..
+ } => {
+ switched = !switched;
+ name_windows(entered_id, switched, &window_1, &window_2);
+ println!("Switched!")
+ }
+ _ => (),
+ },
+ _ => (),
+ });
+}
+
+fn name_windows(window_id: WindowId, switched: bool, window_1: &Window, window_2: &Window) {
+ let (drag_target, other) =
+ if (window_id == window_1.id() && switched) || (window_id == window_2.id() && !switched) {
+ (&window_2, &window_1)
+ } else {
+ (&window_1, &window_2)
+ };
+ drag_target.set_title("drag target");
+ other.set_title("tao window");
+}
diff --git a/frontend/src-tauri/patches/tao-0.35.2/examples/fullscreen.rs b/frontend/src-tauri/patches/tao-0.35.2/examples/fullscreen.rs
new file mode 100644
index 000000000..c5d8bfacd
--- /dev/null
+++ b/frontend/src-tauri/patches/tao-0.35.2/examples/fullscreen.rs
@@ -0,0 +1,129 @@
+// Copyright 2014-2021 The winit contributors
+// Copyright 2021-2023 Tauri Programme within The Commons Conservancy
+// SPDX-License-Identifier: Apache-2.0
+
+use std::io::{stdin, stdout, Write};
+
+use tao::{
+ event::{ElementState, Event, KeyEvent, WindowEvent},
+ event_loop::{ControlFlow, EventLoop},
+ keyboard::Key,
+ monitor::{MonitorHandle, VideoMode},
+ window::{Fullscreen, WindowBuilder},
+};
+#[allow(clippy::single_match)]
+#[allow(clippy::ok_expect)]
+fn main() {
+ env_logger::init();
+ let event_loop = EventLoop::new();
+
+ print!("Please choose the fullscreen mode: (1) exclusive, (2) borderless, (3) borderless on current monitor: ");
+ stdout().flush().unwrap();
+
+ let mut num = String::new();
+ stdin().read_line(&mut num).unwrap();
+ let num = num.trim().parse().ok().expect("Please enter a number");
+
+ let fullscreen = Some(match num {
+ 1 => Fullscreen::Exclusive(prompt_for_video_mode(&prompt_for_monitor(&event_loop))),
+ 2 => Fullscreen::Borderless(Some(prompt_for_monitor(&event_loop))),
+ 3 => Fullscreen::Borderless(None),
+ _ => panic!("Please enter a valid number"),
+ });
+
+ let mut decorations = true;
+
+ let window = WindowBuilder::new()
+ .with_title("Hello world!")
+ .with_fullscreen(fullscreen.clone())
+ .build(&event_loop)
+ .unwrap();
+
+ event_loop.run(move |event, _, control_flow| {
+ *control_flow = ControlFlow::Wait;
+
+ match event {
+ Event::WindowEvent { event, .. } => match event {
+ WindowEvent::CloseRequested => *control_flow = ControlFlow::Exit,
+ WindowEvent::KeyboardInput {
+ event:
+ KeyEvent {
+ logical_key,
+ state: ElementState::Pressed,
+ ..
+ },
+ ..
+ } => {
+ if Key::Escape == logical_key {
+ *control_flow = ControlFlow::Exit
+ }
+
+ if Key::Character("f") == logical_key {
+ if window.fullscreen().is_some() {
+ window.set_fullscreen(None);
+ } else {
+ window.set_fullscreen(fullscreen.clone());
+ }
+ }
+
+ if Key::Character("s") == logical_key {
+ println!("window.fullscreen {:?}", window.fullscreen());
+ }
+ if Key::Character("m") == logical_key {
+ let is_maximized = window.is_maximized();
+ window.set_maximized(!is_maximized);
+ }
+ if Key::Character("d") == logical_key {
+ decorations = !decorations;
+ window.set_decorations(decorations);
+ }
+ }
+ _ => (),
+ },
+ _ => {}
+ }
+ });
+}
+
+// Enumerate monitors and prompt user to choose one
+fn prompt_for_monitor(event_loop: &EventLoop<()>) -> MonitorHandle {
+ for (num, monitor) in event_loop.available_monitors().enumerate() {
+ println!("Monitor #{}: {:?}", num, monitor.name());
+ }
+
+ print!("Please write the number of the monitor to use: ");
+ stdout().flush().unwrap();
+
+ let mut num = String::new();
+ stdin().read_line(&mut num).unwrap();
+ let num = num.trim().parse().expect("Please enter a number");
+ let monitor = event_loop
+ .available_monitors()
+ .nth(num)
+ .expect("Please enter a valid ID");
+
+ println!("Using {:?}", monitor.name());
+
+ monitor
+}
+
+fn prompt_for_video_mode(monitor: &MonitorHandle) -> VideoMode {
+ for (i, video_mode) in monitor.video_modes().enumerate() {
+ println!("Video mode #{i}: {video_mode}");
+ }
+
+ print!("Please write the number of the video mode to use: ");
+ stdout().flush().unwrap();
+
+ let mut num = String::new();
+ stdin().read_line(&mut num).unwrap();
+ let num = num.trim().parse().expect("Please enter a number");
+ let video_mode = monitor
+ .video_modes()
+ .nth(num)
+ .expect("Please enter a valid ID");
+
+ println!("Using {video_mode}");
+
+ video_mode
+}
diff --git a/frontend/src-tauri/patches/tao-0.35.2/examples/handling_close.rs b/frontend/src-tauri/patches/tao-0.35.2/examples/handling_close.rs
new file mode 100644
index 000000000..278a646fc
--- /dev/null
+++ b/frontend/src-tauri/patches/tao-0.35.2/examples/handling_close.rs
@@ -0,0 +1,87 @@
+// Copyright 2014-2021 The winit contributors
+// Copyright 2021-2023 Tauri Programme within The Commons Conservancy
+// SPDX-License-Identifier: Apache-2.0
+
+use tao::{
+ event::{ElementState, Event, KeyEvent, WindowEvent},
+ event_loop::{ControlFlow, EventLoop},
+ keyboard::Key,
+ window::WindowBuilder,
+};
+
+#[allow(clippy::single_match)]
+fn main() {
+ env_logger::init();
+ let event_loop = EventLoop::new();
+
+ let _window = WindowBuilder::new()
+ .with_title("Your faithful window")
+ .build(&event_loop)
+ .unwrap();
+
+ let mut close_requested = false;
+
+ event_loop.run(move |event, _, control_flow| {
+ *control_flow = ControlFlow::Wait;
+
+ match event {
+ Event::WindowEvent { event, .. } => {
+ match event {
+ WindowEvent::CloseRequested => {
+ // `CloseRequested` is sent when the close button on the window is pressed (or
+ // through whatever other mechanisms the window manager provides for closing a
+ // window). If you don't handle this event, the close button won't actually do
+ // anything.
+
+ // A common thing to do here is prompt the user if they have unsaved work.
+ // Creating a proper dialog box for that is far beyond the scope of this
+ // example, so here we'll just respond to the Y and N keys.
+ println!("Are you ready to bid your window farewell? [Y/N]");
+ close_requested = true;
+
+ // In applications where you can safely close the window without further
+ // action from the user, this is generally where you'd handle cleanup before
+ // closing the window. How to close the window is detailed in the handler for
+ // the Y key.
+ }
+ WindowEvent::KeyboardInput {
+ event:
+ KeyEvent {
+ logical_key: Key::Character(char),
+ state: ElementState::Released,
+ ..
+ },
+ ..
+ } => {
+ // WARNING: Consider using `key_without_modifers()` if available on your platform.
+ // See the `key_binding` example
+ match char {
+ "y" => {
+ if close_requested {
+ // This is where you'll want to do any cleanup you need.
+ println!("Buh-bye!");
+
+ // For a single-window application like this, you'd normally just
+ // break out of the event loop here. If you wanted to keep running the
+ // event loop (i.e. if it's a multi-window application), you need to
+ // drop the window. That closes it, and results in `Destroyed` being
+ // sent.
+ *control_flow = ControlFlow::Exit;
+ }
+ }
+ "n" => {
+ if close_requested {
+ println!("Your window will continue to stay by your side.");
+ close_requested = false;
+ }
+ }
+ _ => (),
+ }
+ }
+ _ => (),
+ }
+ }
+ _ => (),
+ }
+ });
+}
diff --git a/frontend/src-tauri/patches/tao-0.35.2/examples/min_max_size.rs b/frontend/src-tauri/patches/tao-0.35.2/examples/min_max_size.rs
new file mode 100644
index 000000000..6ad631faa
--- /dev/null
+++ b/frontend/src-tauri/patches/tao-0.35.2/examples/min_max_size.rs
@@ -0,0 +1,87 @@
+// Copyright 2014-2021 The winit contributors
+// Copyright 2021-2023 Tauri Programme within The Commons Conservancy
+// SPDX-License-Identifier: Apache-2.0
+
+use tao::{
+ dpi::LogicalUnit,
+ event::{ElementState, Event, KeyEvent, WindowEvent},
+ event_loop::{ControlFlow, EventLoop},
+ keyboard::Key,
+ window::{WindowBuilder, WindowSizeConstraints},
+};
+
+#[allow(clippy::single_match)]
+fn main() {
+ env_logger::init();
+ let event_loop = EventLoop::new();
+
+ let min_width = 400.0;
+ let max_width = 800.0;
+ let min_height = 200.0;
+ let max_height = 400.0;
+ let mut size_constraints = WindowSizeConstraints::default();
+
+ let window = WindowBuilder::new().build(&event_loop).unwrap();
+
+ eprintln!("constraint keys:");
+ eprintln!(" (E) Toggle the min width");
+ eprintln!(" (F) Toggle the max width");
+ eprintln!(" (P) Toggle the min height");
+ eprintln!(" (V) Toggle the max height");
+
+ event_loop.run(move |event, _, control_flow| {
+ *control_flow = ControlFlow::Wait;
+
+ match event {
+ Event::WindowEvent {
+ event: WindowEvent::CloseRequested,
+ ..
+ } => *control_flow = ControlFlow::Exit,
+
+ Event::WindowEvent {
+ event:
+ WindowEvent::KeyboardInput {
+ event:
+ KeyEvent {
+ logical_key: Key::Character(key_str),
+ state: ElementState::Released,
+ ..
+ },
+ ..
+ },
+ ..
+ } => match key_str {
+ "e" => {
+ size_constraints.min_width = size_constraints
+ .min_width
+ .is_none()
+ .then_some(LogicalUnit::new(min_width).into());
+ window.set_inner_size_constraints(size_constraints);
+ }
+ "f" => {
+ size_constraints.max_width = size_constraints
+ .max_width
+ .is_none()
+ .then_some(LogicalUnit::new(max_width).into());
+ window.set_inner_size_constraints(size_constraints);
+ }
+ "p" => {
+ size_constraints.min_height = size_constraints
+ .min_height
+ .is_none()
+ .then_some(LogicalUnit::new(min_height).into());
+ window.set_inner_size_constraints(size_constraints);
+ }
+ "v" => {
+ size_constraints.max_height = size_constraints
+ .max_height
+ .is_none()
+ .then_some(LogicalUnit::new(max_height).into());
+ window.set_inner_size_constraints(size_constraints);
+ }
+ _ => {}
+ },
+ _ => (),
+ }
+ });
+}
diff --git a/frontend/src-tauri/patches/tao-0.35.2/examples/minimize.rs b/frontend/src-tauri/patches/tao-0.35.2/examples/minimize.rs
new file mode 100644
index 000000000..76ceeb7b5
--- /dev/null
+++ b/frontend/src-tauri/patches/tao-0.35.2/examples/minimize.rs
@@ -0,0 +1,47 @@
+// Copyright 2014-2021 The winit contributors
+// Copyright 2021-2023 Tauri Programme within The Commons Conservancy
+// SPDX-License-Identifier: Apache-2.0
+
+extern crate tao;
+
+use tao::{
+ event::{Event, WindowEvent},
+ event_loop::{ControlFlow, EventLoop},
+ keyboard::Key,
+ window::WindowBuilder,
+};
+
+#[allow(clippy::single_match)]
+fn main() {
+ env_logger::init();
+ let event_loop = EventLoop::new();
+
+ let window = WindowBuilder::new()
+ .with_title("A fantastic window!")
+ .build(&event_loop)
+ .unwrap();
+
+ event_loop.run(move |event, _, control_flow| {
+ *control_flow = ControlFlow::Wait;
+
+ match event {
+ Event::WindowEvent {
+ event: WindowEvent::CloseRequested,
+ ..
+ } => *control_flow = ControlFlow::Exit,
+
+ // Keyboard input event to handle minimize via a hotkey
+ Event::WindowEvent {
+ event: WindowEvent::KeyboardInput { event, .. },
+ window_id,
+ ..
+ } if window_id == window.id() && Key::Character("m") == event.logical_key => {
+ // Pressing the 'm' key will minimize the window
+ // WARNING: Consider using `key_without_modifers()` if available on your platform.
+ // See the `key_binding` example
+ window.set_minimized(true);
+ }
+ _ => (),
+ }
+ });
+}
diff --git a/frontend/src-tauri/patches/tao-0.35.2/examples/monitor_list.rs b/frontend/src-tauri/patches/tao-0.35.2/examples/monitor_list.rs
new file mode 100644
index 000000000..02ea917d6
--- /dev/null
+++ b/frontend/src-tauri/patches/tao-0.35.2/examples/monitor_list.rs
@@ -0,0 +1,14 @@
+// Copyright 2014-2021 The winit contributors
+// Copyright 2021-2023 Tauri Programme within The Commons Conservancy
+// SPDX-License-Identifier: Apache-2.0
+
+use tao::{event_loop::EventLoop, window::WindowBuilder};
+
+fn main() {
+ env_logger::init();
+ let event_loop = EventLoop::new();
+ let window = WindowBuilder::new().build(&event_loop).unwrap();
+
+ dbg!(window.available_monitors().collect::>());
+ dbg!(window.primary_monitor());
+}
diff --git a/frontend/src-tauri/patches/tao-0.35.2/examples/mouse_wheel.rs b/frontend/src-tauri/patches/tao-0.35.2/examples/mouse_wheel.rs
new file mode 100644
index 000000000..8997a5e6f
--- /dev/null
+++ b/frontend/src-tauri/patches/tao-0.35.2/examples/mouse_wheel.rs
@@ -0,0 +1,54 @@
+// Copyright 2014-2021 The winit contributors
+// Copyright 2021-2023 Tauri Programme within The Commons Conservancy
+// SPDX-License-Identifier: Apache-2.0
+
+use tao::{
+ event::{DeviceEvent, Event, WindowEvent},
+ event_loop::{ControlFlow, EventLoop},
+ window::WindowBuilder,
+};
+
+#[allow(clippy::collapsible_match)]
+#[allow(clippy::single_match)]
+fn main() {
+ env_logger::init();
+ let event_loop = EventLoop::new();
+
+ let window = WindowBuilder::new()
+ .with_title("Mouse Wheel events")
+ .build(&event_loop)
+ .unwrap();
+
+ event_loop.run(move |event, _, control_flow| {
+ *control_flow = ControlFlow::Wait;
+
+ match event {
+ Event::WindowEvent { event, .. } => match event {
+ WindowEvent::CloseRequested => *control_flow = ControlFlow::Exit,
+ _ => (),
+ },
+ Event::DeviceEvent { event, .. } => match event {
+ DeviceEvent::MouseWheel { delta, .. } => match delta {
+ tao::event::MouseScrollDelta::LineDelta(x, y) => {
+ println!("mouse wheel Line Delta: ({x},{y})");
+ let pixels_per_line = 120.0;
+ let mut pos = window.outer_position().unwrap();
+ pos.x -= (x * pixels_per_line) as i32;
+ pos.y -= (y * pixels_per_line) as i32;
+ window.set_outer_position(pos)
+ }
+ tao::event::MouseScrollDelta::PixelDelta(p) => {
+ println!("mouse wheel Pixel Delta: ({},{})", p.x, p.y);
+ let mut pos = window.outer_position().unwrap();
+ pos.x -= p.x as i32;
+ pos.y -= p.y as i32;
+ window.set_outer_position(pos)
+ }
+ _ => (),
+ },
+ _ => (),
+ },
+ _ => (),
+ }
+ });
+}
diff --git a/frontend/src-tauri/patches/tao-0.35.2/examples/multithreaded.rs b/frontend/src-tauri/patches/tao-0.35.2/examples/multithreaded.rs
new file mode 100644
index 000000000..7dfe99632
--- /dev/null
+++ b/frontend/src-tauri/patches/tao-0.35.2/examples/multithreaded.rs
@@ -0,0 +1,187 @@
+// Copyright 2014-2021 The winit contributors
+// Copyright 2021-2023 Tauri Programme within The Commons Conservancy
+// SPDX-License-Identifier: Apache-2.0
+
+#[allow(clippy::single_match)]
+#[allow(clippy::iter_nth)]
+fn main() {
+ use std::{collections::HashMap, sync::mpsc, thread, time::Duration};
+
+ use tao::{
+ dpi::{PhysicalPosition, PhysicalSize, Position, Size},
+ event::{ElementState, Event, KeyEvent, WindowEvent},
+ event_loop::{ControlFlow, EventLoop},
+ keyboard::{Key, ModifiersState},
+ window::{CursorIcon, Fullscreen, WindowBuilder},
+ };
+
+ const WINDOW_COUNT: usize = 3;
+ const WINDOW_SIZE: PhysicalSize = PhysicalSize::new(600, 400);
+
+ env_logger::init();
+ let event_loop = EventLoop::new();
+ let mut window_senders = HashMap::with_capacity(WINDOW_COUNT);
+ for _ in 0..WINDOW_COUNT {
+ let window = WindowBuilder::new()
+ .with_inner_size(WINDOW_SIZE)
+ .build(&event_loop)
+ .unwrap();
+
+ let mut video_modes: Vec<_> = window.current_monitor().unwrap().video_modes().collect();
+ let mut video_mode_id = 0usize;
+
+ let (tx, rx) = mpsc::channel();
+ window_senders.insert(window.id(), tx);
+ let mut modifiers = ModifiersState::default();
+ thread::spawn(move || {
+ while let Ok(event) = rx.recv() {
+ match event {
+ WindowEvent::Moved { .. } => {
+ // We need to update our chosen video mode if the window
+ // was moved to an another monitor, so that the window
+ // appears on this monitor instead when we go fullscreen
+ let previous_video_mode = video_modes.iter().nth(video_mode_id).cloned();
+ video_modes = window.current_monitor().unwrap().video_modes().collect();
+ video_mode_id = video_mode_id.min(video_modes.len());
+ let video_mode = video_modes.iter().nth(video_mode_id);
+
+ // Different monitors may support different video modes,
+ // and the index we chose previously may now point to a
+ // completely different video mode, so notify the user
+ if video_mode != previous_video_mode.as_ref() {
+ println!(
+ "Window moved to another monitor, picked video mode: {}",
+ video_modes.iter().nth(video_mode_id).unwrap()
+ );
+ }
+ }
+ WindowEvent::ModifiersChanged(mod_state) => {
+ modifiers = mod_state;
+ }
+ WindowEvent::KeyboardInput {
+ event:
+ KeyEvent {
+ state: ElementState::Released,
+ logical_key: key,
+ ..
+ },
+ ..
+ } => {
+ use Key::{ArrowLeft, ArrowRight, Character};
+ window.set_title(&format!("{key:?}"));
+ let state = !modifiers.shift_key();
+ match &key {
+ // WARNING: Consider using `key_without_modifers()` if available on your platform.
+ // See the `key_binding` example
+ Character(string) => match string.to_lowercase().as_str() {
+ "a" => window.set_always_on_top(state),
+ "c" => window.set_cursor_icon(match state {
+ true => CursorIcon::Progress,
+ false => CursorIcon::Default,
+ }),
+ "d" => window.set_decorations(!state),
+ "f" => window.set_fullscreen(match (state, modifiers.alt_key()) {
+ (true, false) => Some(Fullscreen::Borderless(None)),
+ (true, true) => Some(Fullscreen::Exclusive(
+ video_modes.iter().nth(video_mode_id).unwrap().clone(),
+ )),
+ (false, _) => None,
+ }),
+ "g" => window.set_cursor_grab(state).unwrap(),
+ "h" => window.set_cursor_visible(!state),
+ "i" => {
+ println!("Info:");
+ println!("-> outer_position : {:?}", window.outer_position());
+ println!("-> inner_position : {:?}", window.inner_position());
+ println!("-> outer_size : {:?}", window.outer_size());
+ println!("-> inner_size : {:?}", window.inner_size());
+ println!("-> fullscreen : {:?}", window.fullscreen());
+ }
+ "l" => window.set_min_inner_size(match state {
+ true => Some(WINDOW_SIZE),
+ false => None,
+ }),
+ "m" => window.set_maximized(state),
+ "p" => window.set_outer_position({
+ let mut position = window.outer_position().unwrap();
+ let sign = if state { 1 } else { -1 };
+ position.x += 10 * sign;
+ position.y += 10 * sign;
+ position
+ }),
+ "q" => window.request_redraw(),
+ "r" => window.set_resizable(state),
+ "s" => window.set_inner_size(match state {
+ true => PhysicalSize::new(WINDOW_SIZE.width + 100, WINDOW_SIZE.height + 100),
+ false => WINDOW_SIZE,
+ }),
+ "w" => {
+ if let Size::Physical(size) = WINDOW_SIZE.into() {
+ window
+ .set_cursor_position(Position::Physical(PhysicalPosition::new(
+ size.width as i32 / 2,
+ size.height as i32 / 2,
+ )))
+ .unwrap()
+ }
+ }
+ "z" => {
+ window.set_visible(false);
+ thread::sleep(Duration::from_secs(1));
+ window.set_visible(true);
+ }
+ _ => (),
+ },
+ ArrowRight | ArrowLeft => {
+ video_mode_id = match &key {
+ ArrowLeft => video_mode_id.saturating_sub(1),
+ ArrowRight => (video_modes.len() - 1).min(video_mode_id + 1),
+ _ => unreachable!(),
+ };
+ println!(
+ "Picking video mode: {}",
+ video_modes.iter().nth(video_mode_id).unwrap()
+ );
+ }
+ _ => (),
+ }
+ }
+ _ => (),
+ }
+ }
+ });
+ }
+ event_loop.run(move |event, _event_loop, control_flow| {
+ *control_flow = match !window_senders.is_empty() {
+ true => ControlFlow::Wait,
+ false => ControlFlow::Exit,
+ };
+ match event {
+ Event::WindowEvent {
+ event, window_id, ..
+ } => match event {
+ WindowEvent::CloseRequested
+ | WindowEvent::Destroyed
+ | WindowEvent::KeyboardInput {
+ event:
+ KeyEvent {
+ state: ElementState::Released,
+ logical_key: Key::Escape,
+ ..
+ },
+ ..
+ } => {
+ window_senders.remove(&window_id);
+ }
+ _ => {
+ if let Some(tx) = window_senders.get(&window_id) {
+ if let Some(event) = event.to_static() {
+ tx.send(event).unwrap();
+ }
+ }
+ }
+ },
+ _ => (),
+ }
+ })
+}
diff --git a/frontend/src-tauri/patches/tao-0.35.2/examples/multiwindow.rs b/frontend/src-tauri/patches/tao-0.35.2/examples/multiwindow.rs
new file mode 100644
index 000000000..32973057a
--- /dev/null
+++ b/frontend/src-tauri/patches/tao-0.35.2/examples/multiwindow.rs
@@ -0,0 +1,55 @@
+// Copyright 2014-2021 The winit contributors
+// Copyright 2021-2023 Tauri Programme within The Commons Conservancy
+// SPDX-License-Identifier: Apache-2.0
+
+use std::collections::HashMap;
+
+use tao::{
+ event::{ElementState, Event, KeyEvent, WindowEvent},
+ event_loop::{ControlFlow, EventLoop},
+ window::Window,
+};
+
+fn main() {
+ env_logger::init();
+ let event_loop = EventLoop::new();
+
+ let mut windows = HashMap::new();
+ for _ in 0..3 {
+ let window = Window::new(&event_loop).unwrap();
+ windows.insert(window.id(), window);
+ }
+
+ event_loop.run(move |event, event_loop, control_flow| {
+ *control_flow = ControlFlow::Wait;
+
+ if let Event::WindowEvent {
+ event, window_id, ..
+ } = event
+ {
+ match event {
+ WindowEvent::CloseRequested => {
+ println!("Window {window_id:?} has received the signal to close");
+
+ // This drops the window, causing it to close.
+ windows.remove(&window_id);
+
+ if windows.is_empty() {
+ *control_flow = ControlFlow::Exit;
+ }
+ }
+ WindowEvent::KeyboardInput {
+ event: KeyEvent {
+ state: ElementState::Pressed,
+ ..
+ },
+ ..
+ } => {
+ let window = Window::new(event_loop).unwrap();
+ windows.insert(window.id(), window);
+ }
+ _ => (),
+ }
+ }
+ })
+}
diff --git a/frontend/src-tauri/patches/tao-0.35.2/examples/overlay.rs b/frontend/src-tauri/patches/tao-0.35.2/examples/overlay.rs
new file mode 100644
index 000000000..03f290c61
--- /dev/null
+++ b/frontend/src-tauri/patches/tao-0.35.2/examples/overlay.rs
@@ -0,0 +1,128 @@
+// Copyright 2014-2021 The winit contributors
+// Copyright 2021-2023 Tauri Programme within The Commons Conservancy
+// SPDX-License-Identifier: Apache-2.0
+
+use tao::{
+ event::{ElementState, Event, KeyEvent, WindowEvent},
+ event_loop::{ControlFlow, EventLoop},
+ keyboard::{Key, ModifiersState},
+ window::WindowBuilder,
+};
+
+#[cfg(any(
+ target_os = "linux",
+ target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "netbsd",
+ target_os = "openbsd"
+))]
+use tao::platform::unix::WindowExtUnix;
+
+#[cfg(target_os = "macos")]
+use tao::platform::macos::WindowExtMacOS;
+
+#[cfg(target_os = "ios")]
+use tao::platform::ios::WindowExtIOS;
+
+#[cfg(windows)]
+use tao::{
+ dpi::PhysicalSize, platform::windows::IconExtWindows, platform::windows::WindowExtWindows,
+ window::Icon,
+};
+
+#[allow(clippy::single_match)]
+fn main() {
+ env_logger::init();
+ let event_loop = EventLoop::new();
+
+ let window = WindowBuilder::new().build(&event_loop).unwrap();
+
+ let mut modifiers = ModifiersState::default();
+
+ eprintln!("Key mappings:");
+ #[cfg(windows)]
+ eprintln!(" [any key]: Show the Overlay Icon");
+ #[cfg(not(windows))]
+ eprintln!(" [1-5]: Show a Badge count");
+ eprintln!(" Ctrl+1: Clear");
+
+ event_loop.run(move |event, _, control_flow| {
+ *control_flow = ControlFlow::Wait;
+
+ match event {
+ Event::WindowEvent {
+ event: WindowEvent::CloseRequested,
+ ..
+ } => *control_flow = ControlFlow::Exit,
+ Event::WindowEvent { event, .. } => match event {
+ WindowEvent::ModifiersChanged(new_state) => {
+ modifiers = new_state;
+ }
+ WindowEvent::KeyboardInput {
+ event:
+ KeyEvent {
+ logical_key: Key::Character(key_str),
+ state: ElementState::Released,
+ ..
+ },
+ ..
+ } => {
+ let _count = match key_str {
+ "1" => 1,
+ "2" => 2,
+ "3" => 3,
+ "4" => 4,
+ "5" => 5,
+ _ => 20,
+ };
+
+ if modifiers.is_empty() {
+ #[cfg(windows)]
+ {
+ let mut path = std::env::current_dir().unwrap();
+ path.push("./examples/icon.ico");
+ let icon = Icon::from_path(path, Some(PhysicalSize::new(32, 32))).unwrap();
+
+ window.set_overlay_icon(Some(&icon));
+ }
+
+ #[cfg(any(
+ target_os = "linux",
+ target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "netbsd",
+ target_os = "openbsd"
+ ))]
+ window.set_badge_count(Some(_count), None);
+
+ #[cfg(target_os = "macos")]
+ window.set_badge_label(_count.to_string().into());
+
+ #[cfg(target_os = "ios")]
+ window.set_badge_count(_count);
+ } else if modifiers.control_key() && key_str == "1" {
+ #[cfg(windows)]
+ window.set_overlay_icon(None);
+
+ #[cfg(any(
+ target_os = "linux",
+ target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "netbsd",
+ target_os = "openbsd"
+ ))]
+ window.set_badge_count(None, None);
+
+ #[cfg(target_os = "macos")]
+ window.set_badge_label(None);
+
+ #[cfg(target_os = "ios")]
+ window.set_badge_count(0);
+ }
+ }
+ _ => {}
+ },
+ _ => {}
+ }
+ });
+}
diff --git a/frontend/src-tauri/patches/tao-0.35.2/examples/parentwindow.rs b/frontend/src-tauri/patches/tao-0.35.2/examples/parentwindow.rs
new file mode 100644
index 000000000..542565105
--- /dev/null
+++ b/frontend/src-tauri/patches/tao-0.35.2/examples/parentwindow.rs
@@ -0,0 +1,70 @@
+// Copyright 2014-2021 The winit contributors
+// Copyright 2021-2023 Tauri Programme within The Commons Conservancy
+// SPDX-License-Identifier: Apache-2.0
+
+#[cfg(any(target_os = "windows", target_os = "macos", target_os = "linux"))]
+fn main() {
+ use std::collections::HashMap;
+ #[cfg(target_os = "macos")]
+ use tao::platform::macos::{WindowBuilderExtMacOS, WindowExtMacOS};
+ #[cfg(target_os = "linux")]
+ use tao::platform::unix::{WindowBuilderExtUnix, WindowExtUnix};
+ #[cfg(target_os = "windows")]
+ use tao::platform::windows::{WindowBuilderExtWindows, WindowExtWindows};
+ use tao::{
+ dpi::LogicalSize,
+ event::{Event, StartCause, WindowEvent},
+ event_loop::{ControlFlow, EventLoop},
+ window::WindowBuilder,
+ };
+ env_logger::init();
+ let event_loop = EventLoop::new();
+ let mut windows = HashMap::new();
+ let main_window = WindowBuilder::new().build(&event_loop).unwrap();
+
+ #[cfg(target_os = "macos")]
+ let parent_window = main_window.ns_window();
+ #[cfg(target_os = "windows")]
+ let parent_window = main_window.hwnd();
+ #[cfg(target_os = "linux")]
+ let parent_window = main_window.gtk_window();
+
+ let child_window_builder = WindowBuilder::new().with_inner_size(LogicalSize::new(200, 200));
+
+ #[cfg(any(target_os = "windows", target_os = "macos"))]
+ let child_window_builder = child_window_builder.with_parent_window(parent_window);
+
+ #[cfg(target_os = "linux")]
+ let child_window_builder = child_window_builder.with_transient_for(parent_window);
+
+ let child_window = child_window_builder.build(&event_loop).unwrap();
+
+ windows.insert(child_window.id(), child_window);
+ windows.insert(main_window.id(), main_window);
+
+ event_loop.run(move |event, _, control_flow| {
+ *control_flow = ControlFlow::Wait;
+
+ match event {
+ Event::NewEvents(StartCause::Init) => println!("TAO application started!"),
+ Event::WindowEvent {
+ event: WindowEvent::CloseRequested,
+ window_id,
+ ..
+ } => {
+ println!("Window {window_id:?} has received the signal to close");
+ // This drop the window, causing it to close.
+ windows.remove(&window_id);
+ if windows.is_empty() {
+ *control_flow = ControlFlow::Exit;
+ }
+ }
+ _ => (),
+ };
+ })
+}
+
+#[cfg(not(any(target_os = "windows", target_os = "macos", target_os = "linux")))]
+fn main() {
+ println!("This platform doesn't have the parent window support.");
+}
diff --git a/frontend/src-tauri/patches/tao-0.35.2/examples/progress_bar.rs b/frontend/src-tauri/patches/tao-0.35.2/examples/progress_bar.rs
new file mode 100644
index 000000000..c526a74cc
--- /dev/null
+++ b/frontend/src-tauri/patches/tao-0.35.2/examples/progress_bar.rs
@@ -0,0 +1,89 @@
+// Copyright 2014-2021 The winit contributors
+// Copyright 2021-2023 Tauri Programme within The Commons Conservancy
+// SPDX-License-Identifier: Apache-2.0
+
+use tao::{
+ event::{ElementState, Event, KeyEvent, WindowEvent},
+ event_loop::{ControlFlow, EventLoop},
+ keyboard::{Key, ModifiersState},
+ window::{ProgressBarState, ProgressState, WindowBuilder},
+};
+
+#[allow(clippy::single_match)]
+fn main() {
+ env_logger::init();
+ let event_loop = EventLoop::new();
+
+ let window = WindowBuilder::new().build(&event_loop).unwrap();
+
+ let mut modifiers = ModifiersState::default();
+
+ eprintln!("Key mappings:");
+ eprintln!(" [1-5]: Set progress to [0%, 25%, 50%, 75%, 100%]");
+ eprintln!(" Ctrl+1: Set state to None");
+ eprintln!(" Ctrl+2: Set state to Normal");
+ eprintln!(" Ctrl+3: Set state to Indeterminate");
+ eprintln!(" Ctrl+4: Set state to Paused");
+ eprintln!(" Ctrl+5: Set state to Error");
+
+ event_loop.run(move |event, _, control_flow| {
+ *control_flow = ControlFlow::Wait;
+
+ match event {
+ Event::WindowEvent {
+ event: WindowEvent::CloseRequested,
+ ..
+ } => *control_flow = ControlFlow::Exit,
+ Event::WindowEvent { event, .. } => match event {
+ WindowEvent::ModifiersChanged(new_state) => {
+ modifiers = new_state;
+ }
+ WindowEvent::KeyboardInput {
+ event:
+ KeyEvent {
+ logical_key: Key::Character(key_str),
+ state: ElementState::Released,
+ ..
+ },
+ ..
+ } => {
+ if modifiers.is_empty() {
+ let mut progress: u64 = 0;
+ match key_str {
+ "1" => progress = 0,
+ "2" => progress = 25,
+ "3" => progress = 50,
+ "4" => progress = 75,
+ "5" => progress = 100,
+ _ => {}
+ }
+
+ window.set_progress_bar(ProgressBarState {
+ progress: Some(progress),
+ state: Some(ProgressState::Normal),
+ desktop_filename: None,
+ });
+ } else if modifiers.control_key() {
+ let mut state = ProgressState::None;
+ match key_str {
+ "1" => state = ProgressState::None,
+ "2" => state = ProgressState::Normal,
+ "3" => state = ProgressState::Indeterminate,
+ "4" => state = ProgressState::Paused,
+ "5" => state = ProgressState::Error,
+ _ => {}
+ }
+
+ window.set_progress_bar(ProgressBarState {
+ progress: None,
+ state: Some(state),
+ desktop_filename: None,
+ });
+ }
+ }
+ _ => {}
+ },
+ _ => {}
+ }
+ });
+}
diff --git a/frontend/src-tauri/patches/tao-0.35.2/examples/reopen_event.rs b/frontend/src-tauri/patches/tao-0.35.2/examples/reopen_event.rs
new file mode 100644
index 000000000..5b14ef4a2
--- /dev/null
+++ b/frontend/src-tauri/patches/tao-0.35.2/examples/reopen_event.rs
@@ -0,0 +1,45 @@
+// Copyright 2014-2021 The winit contributors
+// Copyright 2021-2023 Tauri Programme within The Commons Conservancy
+// SPDX-License-Identifier: Apache-2.0
+
+use tao::{
+ event::{Event, WindowEvent},
+ event_loop::{ControlFlow, EventLoop},
+ window::Window,
+};
+
+#[allow(clippy::single_match)]
+fn main() {
+ let event_loop = EventLoop::new();
+
+ let mut window = Some(Window::new(&event_loop).unwrap());
+
+ event_loop.run(move |event, event_loop, control_flow| {
+ *control_flow = ControlFlow::Wait;
+
+ match event {
+ Event::WindowEvent {
+ event: WindowEvent::CloseRequested,
+ ..
+ } => {
+ // drop the window
+ window = None;
+ }
+ Event::Reopen {
+ has_visible_windows,
+ ..
+ } => {
+ println!("on reopen, has visible windows: {has_visible_windows}");
+ if !has_visible_windows {
+ window = Some(Window::new(event_loop).unwrap())
+ }
+ }
+ Event::MainEventsCleared => {
+ if let Some(w) = &window {
+ w.request_redraw();
+ }
+ }
+ _ => (),
+ }
+ });
+}
diff --git a/frontend/src-tauri/patches/tao-0.35.2/examples/request_redraw.rs b/frontend/src-tauri/patches/tao-0.35.2/examples/request_redraw.rs
new file mode 100644
index 000000000..f3f563c6f
--- /dev/null
+++ b/frontend/src-tauri/patches/tao-0.35.2/examples/request_redraw.rs
@@ -0,0 +1,43 @@
+// Copyright 2014-2021 The winit contributors
+// Copyright 2021-2023 Tauri Programme within The Commons Conservancy
+// SPDX-License-Identifier: Apache-2.0
+
+use tao::{
+ event::{ElementState, Event, WindowEvent},
+ event_loop::{ControlFlow, EventLoop},
+ window::WindowBuilder,
+};
+
+#[allow(clippy::single_match)]
+fn main() {
+ env_logger::init();
+ let event_loop = EventLoop::new();
+
+ let window = WindowBuilder::new()
+ .with_title("A fantastic window!")
+ .build(&event_loop)
+ .unwrap();
+
+ event_loop.run(move |event, _, control_flow| {
+ println!("{event:?}");
+
+ *control_flow = ControlFlow::Wait;
+
+ match event {
+ Event::WindowEvent { event, .. } => match event {
+ WindowEvent::CloseRequested => *control_flow = ControlFlow::Exit,
+ WindowEvent::MouseInput {
+ state: ElementState::Released,
+ ..
+ } => {
+ window.request_redraw();
+ }
+ _ => (),
+ },
+ Event::RedrawRequested(_) => {
+ println!("\nredrawing!\n");
+ }
+ _ => (),
+ }
+ });
+}
diff --git a/frontend/src-tauri/patches/tao-0.35.2/examples/request_redraw_threaded.rs b/frontend/src-tauri/patches/tao-0.35.2/examples/request_redraw_threaded.rs
new file mode 100644
index 000000000..069d65d52
--- /dev/null
+++ b/frontend/src-tauri/patches/tao-0.35.2/examples/request_redraw_threaded.rs
@@ -0,0 +1,45 @@
+// Copyright 2014-2021 The winit contributors
+// Copyright 2021-2023 Tauri Programme within The Commons Conservancy
+// SPDX-License-Identifier: Apache-2.0
+
+use std::{thread, time};
+
+use tao::{
+ event::{Event, WindowEvent},
+ event_loop::{ControlFlow, EventLoop},
+ window::WindowBuilder,
+};
+
+#[allow(clippy::single_match)]
+#[allow(clippy::collapsible_match)]
+fn main() {
+ env_logger::init();
+ let event_loop = EventLoop::new();
+
+ let window = WindowBuilder::new()
+ .with_title("A fantastic window!")
+ .build(&event_loop)
+ .unwrap();
+
+ thread::spawn(move || loop {
+ thread::sleep(time::Duration::from_secs(1));
+ window.request_redraw();
+ });
+
+ event_loop.run(move |event, _, control_flow| {
+ println!("{event:?}");
+
+ *control_flow = ControlFlow::Wait;
+
+ match event {
+ Event::WindowEvent { event, .. } => match event {
+ WindowEvent::CloseRequested => *control_flow = ControlFlow::Exit,
+ _ => (),
+ },
+ Event::RedrawRequested(_) => {
+ println!("\nredrawing!\n");
+ }
+ _ => (),
+ }
+ });
+}
diff --git a/frontend/src-tauri/patches/tao-0.35.2/examples/resizable.rs b/frontend/src-tauri/patches/tao-0.35.2/examples/resizable.rs
new file mode 100644
index 000000000..e0d8c16f2
--- /dev/null
+++ b/frontend/src-tauri/patches/tao-0.35.2/examples/resizable.rs
@@ -0,0 +1,51 @@
+// Copyright 2014-2021 The winit contributors
+// Copyright 2021-2023 Tauri Programme within The Commons Conservancy
+// SPDX-License-Identifier: Apache-2.0
+
+use tao::{
+ dpi::LogicalSize,
+ event::{ElementState, Event, KeyEvent, WindowEvent},
+ event_loop::{ControlFlow, EventLoop},
+ keyboard::KeyCode,
+ window::WindowBuilder,
+};
+
+#[allow(clippy::single_match)]
+fn main() {
+ env_logger::init();
+ let event_loop = EventLoop::new();
+
+ let mut resizable = false;
+
+ let window = WindowBuilder::new()
+ .with_title("Hit space to toggle resizability.")
+ .with_inner_size(LogicalSize::new(400.0, 200.0))
+ .with_resizable(resizable)
+ .build(&event_loop)
+ .unwrap();
+
+ event_loop.run(move |event, _, control_flow| {
+ *control_flow = ControlFlow::Wait;
+
+ match event {
+ Event::WindowEvent { event, .. } => match event {
+ WindowEvent::CloseRequested => *control_flow = ControlFlow::Exit,
+ WindowEvent::KeyboardInput {
+ event:
+ KeyEvent {
+ physical_key: KeyCode::Space,
+ state: ElementState::Released,
+ ..
+ },
+ ..
+ } => {
+ resizable = !resizable;
+ println!("Resizable: {resizable}");
+ window.set_resizable(resizable);
+ }
+ _ => (),
+ },
+ _ => (),
+ };
+ });
+}
diff --git a/frontend/src-tauri/patches/tao-0.35.2/examples/set_ime_position.rs b/frontend/src-tauri/patches/tao-0.35.2/examples/set_ime_position.rs
new file mode 100644
index 000000000..2310f5c5a
--- /dev/null
+++ b/frontend/src-tauri/patches/tao-0.35.2/examples/set_ime_position.rs
@@ -0,0 +1,56 @@
+// Copyright 2014-2021 The winit contributors
+// Copyright 2021-2023 Tauri Programme within The Commons Conservancy
+// SPDX-License-Identifier: Apache-2.0
+
+use tao::{
+ dpi::PhysicalPosition,
+ event::{ElementState, Event, WindowEvent},
+ event_loop::{ControlFlow, EventLoop},
+ window::WindowBuilder,
+};
+
+fn main() {
+ env_logger::init();
+ let event_loop = EventLoop::new();
+
+ let window = WindowBuilder::new().build(&event_loop).unwrap();
+ window.set_title("A fantastic window!");
+
+ println!("Ime position will system default");
+ println!("Click to set ime position to cursor's");
+
+ let mut cursor_position = PhysicalPosition::new(0.0, 0.0);
+ event_loop.run(move |event, _, control_flow| {
+ *control_flow = ControlFlow::Wait;
+
+ match event {
+ Event::WindowEvent {
+ event: WindowEvent::CursorMoved { position, .. },
+ ..
+ } => {
+ cursor_position = position;
+ }
+ Event::WindowEvent {
+ event:
+ WindowEvent::MouseInput {
+ state: ElementState::Released,
+ ..
+ },
+ ..
+ } => {
+ println!(
+ "Setting ime position to {}, {}",
+ cursor_position.x, cursor_position.y
+ );
+ window.set_ime_position(cursor_position);
+ }
+ Event::WindowEvent {
+ event: WindowEvent::CloseRequested,
+ ..
+ } => {
+ *control_flow = ControlFlow::Exit;
+ }
+ _ => (),
+ }
+ });
+}
diff --git a/frontend/src-tauri/patches/tao-0.35.2/examples/theme.rs b/frontend/src-tauri/patches/tao-0.35.2/examples/theme.rs
new file mode 100644
index 000000000..c0e3284b9
--- /dev/null
+++ b/frontend/src-tauri/patches/tao-0.35.2/examples/theme.rs
@@ -0,0 +1,50 @@
+// Copyright 2014-2021 The winit contributors
+// Copyright 2021-2023 Tauri Programme within The Commons Conservancy
+// SPDX-License-Identifier: Apache-2.0
+
+use tao::{event::KeyEvent, keyboard::KeyCode};
+
+fn main() {
+ use tao::{
+ event::{Event, WindowEvent},
+ event_loop::{ControlFlow, EventLoop},
+ window::{Theme, WindowBuilder},
+ };
+
+ env_logger::init();
+ let event_loop = EventLoop::new();
+
+ let window = WindowBuilder::new()
+ .with_title("A fantastic window!")
+ // .with_theme(Some(tao::window::Theme::Light))
+ .build(&event_loop)
+ .unwrap();
+
+ println!("Initial theme: {:?}", window.theme());
+ println!("Press D for Dark Mode");
+ println!("Press L for Light Mode");
+ println!("Press A for Auto Mode");
+
+ event_loop.run(move |event, _, control_flow| {
+ *control_flow = ControlFlow::Wait;
+
+ if let Event::WindowEvent { event, .. } = event {
+ match event {
+ WindowEvent::CloseRequested => *control_flow = ControlFlow::Exit,
+ WindowEvent::KeyboardInput {
+ event: KeyEvent { physical_key, .. },
+ ..
+ } => match physical_key {
+ KeyCode::KeyD => window.set_theme(Some(Theme::Dark)),
+ KeyCode::KeyL => window.set_theme(Some(Theme::Light)),
+ KeyCode::KeyA => window.set_theme(None),
+ _ => {}
+ },
+ WindowEvent::ThemeChanged(theme) => {
+ println!("Theme is changed: {theme:?}")
+ }
+ _ => (),
+ }
+ }
+ });
+}
diff --git a/frontend/src-tauri/patches/tao-0.35.2/examples/timer.rs b/frontend/src-tauri/patches/tao-0.35.2/examples/timer.rs
new file mode 100644
index 000000000..eb3ce6f38
--- /dev/null
+++ b/frontend/src-tauri/patches/tao-0.35.2/examples/timer.rs
@@ -0,0 +1,43 @@
+// Copyright 2014-2021 The winit contributors
+// Copyright 2021-2023 Tauri Programme within The Commons Conservancy
+// SPDX-License-Identifier: Apache-2.0
+
+use std::time::{Duration, Instant};
+
+use tao::{
+ event::{Event, StartCause, WindowEvent},
+ event_loop::{ControlFlow, EventLoop},
+ window::WindowBuilder,
+};
+
+#[allow(clippy::single_match)]
+fn main() {
+ env_logger::init();
+ let event_loop = EventLoop::new();
+
+ let _window = WindowBuilder::new()
+ .with_title("A fantastic window!")
+ .build(&event_loop)
+ .unwrap();
+
+ let timer_length = Duration::new(1, 0);
+
+ event_loop.run(move |event, _, control_flow| {
+ println!("{event:?}");
+
+ match event {
+ Event::NewEvents(StartCause::Init) => {
+ *control_flow = ControlFlow::WaitUntil(Instant::now() + timer_length)
+ }
+ Event::NewEvents(StartCause::ResumeTimeReached { .. }) => {
+ *control_flow = ControlFlow::WaitUntil(Instant::now() + timer_length);
+ println!("\nTimer\n");
+ }
+ Event::WindowEvent {
+ event: WindowEvent::CloseRequested,
+ ..
+ } => *control_flow = ControlFlow::Exit,
+ _ => (),
+ }
+ });
+}
diff --git a/frontend/src-tauri/patches/tao-0.35.2/examples/transparent.rs b/frontend/src-tauri/patches/tao-0.35.2/examples/transparent.rs
new file mode 100644
index 000000000..22c99c9a1
--- /dev/null
+++ b/frontend/src-tauri/patches/tao-0.35.2/examples/transparent.rs
@@ -0,0 +1,66 @@
+// Copyright 2014-2021 The winit contributors
+// Copyright 2021-2023 Tauri Programme within The Commons Conservancy
+// SPDX-License-Identifier: Apache-2.0
+
+#[cfg(windows)]
+use std::{num::NonZeroU32, rc::Rc};
+
+use tao::{
+ event::{Event, WindowEvent},
+ event_loop::{ControlFlow, EventLoop},
+ window::WindowBuilder,
+};
+
+#[allow(clippy::single_match)]
+fn main() {
+ env_logger::init();
+ let event_loop = EventLoop::new();
+
+ let window = WindowBuilder::new()
+ .with_decorations(false)
+ .with_transparent(true)
+ .build(&event_loop)
+ .unwrap();
+
+ #[cfg(windows)]
+ let (window, _context, mut surface) = {
+ let window = Rc::new(window);
+ let context = softbuffer::Context::new(window.clone()).unwrap();
+ let surface = softbuffer::Surface::new(&context, window.clone()).unwrap();
+ (window, context, surface)
+ };
+
+ window.set_title("A fantastic window!");
+
+ event_loop.run(move |event, _, control_flow| {
+ *control_flow = ControlFlow::Wait;
+ println!("{event:?}");
+
+ match event {
+ Event::WindowEvent {
+ event: WindowEvent::CloseRequested,
+ ..
+ } => *control_flow = ControlFlow::Exit,
+
+ #[cfg(windows)]
+ Event::RedrawRequested(_) => {
+ let (width, height) = {
+ let size = window.inner_size();
+ (size.width, size.height)
+ };
+ surface
+ .resize(
+ NonZeroU32::new(width).unwrap(),
+ NonZeroU32::new(height).unwrap(),
+ )
+ .unwrap();
+
+ let mut buffer = surface.buffer_mut().unwrap();
+ buffer.fill(0);
+ buffer.present().unwrap();
+ }
+
+ _ => (),
+ }
+ });
+}
diff --git a/frontend/src-tauri/patches/tao-0.35.2/examples/video_modes.rs b/frontend/src-tauri/patches/tao-0.35.2/examples/video_modes.rs
new file mode 100644
index 000000000..d40b3f6e3
--- /dev/null
+++ b/frontend/src-tauri/patches/tao-0.35.2/examples/video_modes.rs
@@ -0,0 +1,24 @@
+// Copyright 2014-2021 The winit contributors
+// Copyright 2021-2023 Tauri Programme within The Commons Conservancy
+// SPDX-License-Identifier: Apache-2.0
+
+use tao::event_loop::EventLoop;
+
+#[allow(clippy::single_match)]
+fn main() {
+ env_logger::init();
+ let event_loop = EventLoop::new();
+ let monitor = match event_loop.primary_monitor() {
+ Some(monitor) => monitor,
+ None => {
+ println!("No primary monitor detected.");
+ return;
+ }
+ };
+
+ println!("Listing available video modes:");
+
+ for mode in monitor.video_modes() {
+ println!("{mode}");
+ }
+}
diff --git a/frontend/src-tauri/patches/tao-0.35.2/examples/window.rs b/frontend/src-tauri/patches/tao-0.35.2/examples/window.rs
new file mode 100644
index 000000000..c4804fc4c
--- /dev/null
+++ b/frontend/src-tauri/patches/tao-0.35.2/examples/window.rs
@@ -0,0 +1,52 @@
+// Copyright 2014-2021 The winit contributors
+// Copyright 2021-2023 Tauri Programme within The Commons Conservancy
+// SPDX-License-Identifier: Apache-2.0
+
+use tao::{
+ event::{Event, WindowEvent},
+ event_loop::{ControlFlow, EventLoop},
+ window::WindowBuilder,
+};
+
+#[allow(clippy::single_match)]
+fn main() {
+ let event_loop = EventLoop::new();
+
+ let mut window = Some(
+ WindowBuilder::new()
+ .with_title("A fantastic window!")
+ .with_inner_size(tao::dpi::LogicalSize::new(300.0, 300.0))
+ .with_min_inner_size(tao::dpi::LogicalSize::new(200.0, 200.0))
+ .build(&event_loop)
+ .unwrap(),
+ );
+
+ event_loop.run(move |event, _, control_flow| {
+ *control_flow = ControlFlow::Wait;
+ println!("{event:?}");
+
+ match event {
+ Event::WindowEvent {
+ event: WindowEvent::CloseRequested,
+ window_id: _,
+ ..
+ } => {
+ // drop the window to fire the `Destroyed` event
+ window = None;
+ }
+ Event::WindowEvent {
+ event: WindowEvent::Destroyed,
+ window_id: _,
+ ..
+ } => {
+ *control_flow = ControlFlow::Exit;
+ }
+ Event::MainEventsCleared => {
+ if let Some(w) = &window {
+ w.request_redraw();
+ }
+ }
+ _ => (),
+ }
+ });
+}
diff --git a/frontend/src-tauri/patches/tao-0.35.2/examples/window_debug.rs b/frontend/src-tauri/patches/tao-0.35.2/examples/window_debug.rs
new file mode 100644
index 000000000..1bb04c478
--- /dev/null
+++ b/frontend/src-tauri/patches/tao-0.35.2/examples/window_debug.rs
@@ -0,0 +1,176 @@
+// Copyright 2014-2021 The winit contributors
+// Copyright 2021-2023 Tauri Programme within The Commons Conservancy
+// SPDX-License-Identifier: Apache-2.0
+
+// This example is used by developers to test various window functions.
+
+use tao::{
+ dpi::{LogicalSize, PhysicalSize},
+ event::{DeviceEvent, ElementState, Event, KeyEvent, RawKeyEvent, WindowEvent},
+ event_loop::{ControlFlow, DeviceEventFilter, EventLoop},
+ keyboard::{Key, KeyCode},
+ window::{Fullscreen, WindowBuilder},
+};
+
+#[allow(clippy::single_match)]
+#[allow(clippy::collapsible_match)]
+fn main() {
+ env_logger::init();
+ let event_loop = EventLoop::new();
+ event_loop.set_device_event_filter(DeviceEventFilter::Never);
+
+ let window = WindowBuilder::new()
+ .with_title("A fantastic window!")
+ .with_inner_size(LogicalSize::new(100.0, 100.0))
+ .build(&event_loop)
+ .unwrap();
+
+ eprintln!("debugging keys:");
+ eprintln!(" (E) Enter exclusive fullscreen");
+ eprintln!(" (F) Toggle borderless fullscreen");
+ eprintln!(" (P) Toggle borderless fullscreen on system's preferred monitor");
+ eprintln!(" (V) Toggle visibility");
+ eprintln!(" (T) Toggle always on top");
+ eprintln!(" (B) Toggle always on bottom");
+ eprintln!(" (C) Toggle content protection");
+ eprintln!(" (R) Toggle resizable");
+ eprintln!(" (M) Toggle minimized");
+ eprintln!(" (X) Toggle maximized");
+ eprintln!(" (Q) Quit event loop");
+ eprintln!(" (Shift + M) Toggle minimizable");
+ eprintln!(" (Shift + X) Toggle maximizable");
+ eprintln!(" (Shift + Q) Toggle closable");
+
+ let mut always_on_bottom = false;
+ let mut always_on_top = false;
+ let mut visible = true;
+ let mut content_protection = false;
+ let mut resizable = false;
+
+ event_loop.run(move |event, _, control_flow| {
+ *control_flow = ControlFlow::Wait;
+
+ match event {
+ // This used to use the virtual key, but the new API
+ // only provides the `physical_key` (`Code`).
+ Event::DeviceEvent {
+ event:
+ DeviceEvent::Key(RawKeyEvent {
+ physical_key,
+ state: ElementState::Released,
+ ..
+ }),
+ ..
+ } => match physical_key {
+ KeyCode::KeyM => {
+ if window.is_minimized() {
+ window.set_minimized(false);
+ window.set_focus()
+ }
+ }
+ KeyCode::KeyV => {
+ if !visible {
+ visible = !visible;
+ window.set_visible(visible);
+ }
+ }
+ _ => (),
+ },
+ Event::WindowEvent {
+ event:
+ WindowEvent::KeyboardInput {
+ event:
+ KeyEvent {
+ logical_key: Key::Character(key_str),
+ state: ElementState::Released,
+ ..
+ },
+ ..
+ },
+ ..
+ } => match key_str {
+ // WARNING: Consider using `key_without_modifers()` if available on your platform.
+ // See the `key_binding` example
+ "e" => {
+ fn area(size: PhysicalSize) -> u32 {
+ size.width * size.height
+ }
+
+ let monitor = window.current_monitor().unwrap();
+ if let Some(mode) = monitor
+ .video_modes()
+ .max_by(|a, b| area(a.size()).cmp(&area(b.size())))
+ {
+ window.set_fullscreen(Some(Fullscreen::Exclusive(mode)));
+ } else {
+ eprintln!("no video modes available");
+ }
+ }
+ "f" => {
+ if window.fullscreen().is_some() {
+ window.set_fullscreen(None);
+ } else {
+ let monitor = window.current_monitor();
+ window.set_fullscreen(Some(Fullscreen::Borderless(monitor)));
+ }
+ }
+ "p" => {
+ if window.fullscreen().is_some() {
+ window.set_fullscreen(None);
+ } else {
+ window.set_fullscreen(Some(Fullscreen::Borderless(None)));
+ }
+ }
+ "r" => {
+ resizable = !resizable;
+ window.set_resizable(resizable);
+ println!("Resizable: {resizable}");
+ }
+ "m" => {
+ window.set_minimized(!window.is_minimized());
+ }
+ "q" => {
+ *control_flow = ControlFlow::Exit;
+ }
+ "v" => {
+ visible = !visible;
+ window.set_visible(visible);
+ }
+ "x" => {
+ window.set_maximized(!window.is_maximized());
+ }
+ "t" => {
+ always_on_top = !always_on_top;
+ window.set_always_on_top(always_on_top);
+ }
+ "b" => {
+ always_on_bottom = !always_on_bottom;
+ window.set_always_on_bottom(always_on_bottom);
+ }
+ "c" => {
+ content_protection = !content_protection;
+ window.set_content_protection(content_protection);
+ }
+ "M" => {
+ let minimizable = !window.is_minimizable();
+ window.set_minimizable(minimizable);
+ }
+ "X" => {
+ let maximizable = !window.is_maximizable();
+ window.set_maximizable(maximizable);
+ }
+ "Q" => {
+ let closable = !window.is_closable();
+ window.set_closable(closable);
+ }
+ _ => (),
+ },
+ Event::WindowEvent {
+ event: WindowEvent::CloseRequested,
+ window_id,
+ ..
+ } if window_id == window.id() => *control_flow = ControlFlow::Exit,
+ _ => (),
+ }
+ });
+}
diff --git a/frontend/src-tauri/patches/tao-0.35.2/examples/window_icon.rs b/frontend/src-tauri/patches/tao-0.35.2/examples/window_icon.rs
new file mode 100644
index 000000000..bc5c4c610
--- /dev/null
+++ b/frontend/src-tauri/patches/tao-0.35.2/examples/window_icon.rs
@@ -0,0 +1,64 @@
+// Copyright 2014-2021 The winit contributors
+// Copyright 2021-2023 Tauri Programme within The Commons Conservancy
+// SPDX-License-Identifier: Apache-2.0
+
+extern crate image;
+use std::path::Path;
+
+use tao::{
+ event::Event,
+ event_loop::{ControlFlow, EventLoop},
+ window::{Icon, WindowBuilder},
+};
+
+#[allow(clippy::single_match)]
+fn main() {
+ env_logger::init();
+
+ // You'll have to choose an icon size at your own discretion. On Linux, the icon should be
+ // provided in whatever size it was naturally drawn; that is, don’t scale the image before passing
+ // it to Tao. But on Windows, you will have to account for screen scaling. Here we use 32px,
+ // since it seems to work well enough in most cases. Be careful about going too high, or
+ // you'll be bitten by the low-quality downscaling built into the WM.
+ let path = concat!(env!("CARGO_MANIFEST_DIR"), "/examples/icon.png");
+
+ let icon = load_icon(Path::new(path));
+
+ let event_loop = EventLoop::new();
+
+ let window = WindowBuilder::new()
+ .with_title("An iconic window!")
+ // At present, this only does anything on Windows and Linux, so if you want to save load
+ // time, you can put icon loading behind a function that returns `None` on other platforms.
+ .with_window_icon(Some(icon))
+ .build(&event_loop)
+ .unwrap();
+
+ event_loop.run(move |event, _, control_flow| {
+ *control_flow = ControlFlow::Wait;
+
+ if let Event::WindowEvent { event, .. } = event {
+ use tao::event::WindowEvent::*;
+ match event {
+ CloseRequested => *control_flow = ControlFlow::Exit,
+ DroppedFile(path) => {
+ window.set_window_icon(Some(load_icon(&path)));
+ }
+ _ => (),
+ }
+ }
+ });
+}
+
+fn load_icon(path: &Path) -> Icon {
+ let (icon_rgba, icon_width, icon_height) = {
+ // alternatively, you can embed the icon in the binary through `include_bytes!` macro and use `image::load_from_memory`
+ let image = image::open(path)
+ .expect("Failed to open icon path")
+ .into_rgba8();
+ let (width, height) = image.dimensions();
+ let rgba = image.into_raw();
+ (rgba, width, height)
+ };
+ Icon::from_rgba(icon_rgba, icon_width, icon_height).expect("Failed to open icon")
+}
diff --git a/frontend/src-tauri/patches/tao-0.35.2/examples/window_run_return.rs b/frontend/src-tauri/patches/tao-0.35.2/examples/window_run_return.rs
new file mode 100644
index 000000000..c4754bb63
--- /dev/null
+++ b/frontend/src-tauri/patches/tao-0.35.2/examples/window_run_return.rs
@@ -0,0 +1,59 @@
+// Copyright 2014-2021 The winit contributors
+// Copyright 2021-2023 Tauri Programme within The Commons Conservancy
+// SPDX-License-Identifier: Apache-2.0
+
+// Limit this example to only compatible platforms.
+#[cfg(not(target_os = "ios"))]
+#[allow(clippy::single_match)]
+fn main() {
+ use std::{thread::sleep, time::Duration};
+
+ use tao::{
+ event::{Event, WindowEvent},
+ event_loop::{ControlFlow, EventLoop},
+ platform::run_return::EventLoopExtRunReturn,
+ window::WindowBuilder,
+ };
+ let mut event_loop = EventLoop::new();
+
+ env_logger::init();
+ let _window = WindowBuilder::new()
+ .with_title("A fantastic window!")
+ .build(&event_loop)
+ .unwrap();
+
+ let mut quit = false;
+
+ while !quit {
+ event_loop.run_return(|event, _, control_flow| {
+ *control_flow = ControlFlow::Wait;
+
+ if let Event::WindowEvent { event, .. } = &event {
+ // Print only Window events to reduce noise
+ println!("{event:?}");
+ }
+
+ match event {
+ Event::WindowEvent {
+ event: WindowEvent::CloseRequested,
+ ..
+ } => {
+ quit = true;
+ }
+ Event::MainEventsCleared => {
+ *control_flow = ControlFlow::Exit;
+ }
+ _ => (),
+ }
+ });
+
+ // Sleep for 1/60 second to simulate rendering
+ println!("rendering");
+ sleep(Duration::from_millis(16));
+ }
+}
+
+#[cfg(target_os = "ios")]
+fn main() {
+ println!("This platform doesn't support run_return.");
+}
diff --git a/frontend/src-tauri/patches/tao-0.35.2/src/error.rs b/frontend/src-tauri/patches/tao-0.35.2/src/error.rs
new file mode 100644
index 000000000..3bc21cedc
--- /dev/null
+++ b/frontend/src-tauri/patches/tao-0.35.2/src/error.rs
@@ -0,0 +1,88 @@
+// Copyright 2014-2021 The winit contributors
+// Copyright 2021-2023 Tauri Programme within The Commons Conservancy
+// SPDX-License-Identifier: Apache-2.0
+
+//! The `Error` struct and associated types.
+use std::{error, fmt};
+
+use crate::platform_impl;
+
+/// An error whose cause it outside Tao's control.
+#[non_exhaustive]
+#[derive(Debug)]
+pub enum ExternalError {
+ /// The operation is not supported by the backend.
+ NotSupported(NotSupportedError),
+ /// The OS cannot perform the operation.
+ Os(OsError),
+}
+
+/// The error type for when the requested operation is not supported by the backend.
+#[derive(Clone)]
+pub struct NotSupportedError {
+ _marker: (),
+}
+
+/// The error type for when the OS cannot perform the requested operation.
+#[derive(Debug)]
+pub struct OsError {
+ line: u32,
+ file: &'static str,
+ error: platform_impl::OsError,
+}
+
+impl NotSupportedError {
+ #[inline]
+ #[allow(dead_code)]
+ pub(crate) fn new() -> NotSupportedError {
+ NotSupportedError { _marker: () }
+ }
+}
+
+impl OsError {
+ #[allow(dead_code)]
+ pub(crate) fn new(line: u32, file: &'static str, error: platform_impl::OsError) -> OsError {
+ OsError { line, file, error }
+ }
+}
+
+#[allow(unused_macros)]
+macro_rules! os_error {
+ ($error:expr) => {{
+ crate::error::OsError::new(line!(), file!(), $error)
+ }};
+}
+
+impl fmt::Display for OsError {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
+ f.pad(&format!(
+ "os error at {}:{}: {}",
+ self.file, self.line, self.error
+ ))
+ }
+}
+
+impl fmt::Display for ExternalError {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
+ match self {
+ ExternalError::NotSupported(e) => e.fmt(f),
+ ExternalError::Os(e) => e.fmt(f),
+ }
+ }
+}
+
+impl fmt::Debug for NotSupportedError {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
+ f.debug_struct("NotSupportedError").finish()
+ }
+}
+
+impl fmt::Display for NotSupportedError {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
+ f.pad("the requested operation is not supported by Tao")
+ }
+}
+
+impl error::Error for OsError {}
+impl error::Error for ExternalError {}
+impl error::Error for NotSupportedError {}
diff --git a/frontend/src-tauri/patches/tao-0.35.2/src/event.rs b/frontend/src-tauri/patches/tao-0.35.2/src/event.rs
new file mode 100644
index 000000000..d72af30ba
--- /dev/null
+++ b/frontend/src-tauri/patches/tao-0.35.2/src/event.rs
@@ -0,0 +1,964 @@
+// Copyright 2014-2021 The winit contributors
+// Copyright 2021-2023 Tauri Programme within The Commons Conservancy
+// SPDX-License-Identifier: Apache-2.0
+
+//! The `Event` enum and assorted supporting types.
+//!
+//! These are sent to the closure given to [`EventLoop::run(...)`][event_loop_run], where they get
+//! processed and used to modify the program state. For more details, see the root-level documentation.
+//!
+//! Some of these events represent different "parts" of a traditional event-handling loop. You could
+//! approximate the basic ordering loop of [`EventLoop::run(...)`][event_loop_run] like this:
+//!
+//! ```rust,ignore
+//! let mut control_flow = ControlFlow::Poll;
+//! let mut start_cause = StartCause::Init;
+//!
+//! while control_flow != ControlFlow::Exit {
+//! event_handler(NewEvents(start_cause), ..., &mut control_flow);
+//!
+//! for e in (window events, user events, device events) {
+//! event_handler(e, ..., &mut control_flow);
+//! }
+//! event_handler(MainEventsCleared, ..., &mut control_flow);
+//!
+//! for w in (redraw windows) {
+//! event_handler(RedrawRequested(w), ..., &mut control_flow);
+//! }
+//! event_handler(RedrawEventsCleared, ..., &mut control_flow);
+//!
+//! start_cause = wait_if_necessary(control_flow);
+//! }
+//!
+//! event_handler(LoopDestroyed, ..., &mut control_flow);
+//! ```
+//!
+//! This leaves out timing details like `ControlFlow::WaitUntil` but hopefully
+//! describes what happens in what order.
+//!
+//! [event_loop_run]: crate::event_loop::EventLoop::run
+use std::{path::PathBuf, time::Instant};
+
+use crate::{
+ dpi::{PhysicalPosition, PhysicalSize},
+ keyboard::{self, ModifiersState},
+ platform_impl,
+ window::{Theme, WindowId},
+};
+
+/// Describes a generic event.
+///
+/// See the module-level docs for more information on the event loop manages each event.
+#[non_exhaustive]
+#[derive(Debug, PartialEq)]
+pub enum Event<'a, T: 'static> {
+ /// Emitted when new events arrive from the OS to be processed.
+ ///
+ /// This event type is useful as a place to put code that should be done before you start
+ /// processing events, such as updating frame timing information for benchmarking or checking
+ /// the [`StartCause`][crate::event::StartCause] to see if a timer set by
+ /// [`ControlFlow::WaitUntil`](crate::event_loop::ControlFlow::WaitUntil) has elapsed.
+ NewEvents(StartCause),
+
+ /// Emitted when the OS sends an event to a tao window.
+ #[non_exhaustive]
+ WindowEvent {
+ window_id: WindowId,
+ event: WindowEvent<'a>,
+ },
+
+ /// Emitted when the OS sends an event to a device.
+ #[non_exhaustive]
+ DeviceEvent {
+ device_id: DeviceId,
+ event: DeviceEvent,
+ },
+
+ /// Emitted when an event is sent from [`EventLoopProxy::send_event`](crate::event_loop::EventLoopProxy::send_event)
+ UserEvent(T),
+
+ /// Emitted when the application has been suspended.
+ ///
+ /// ## Platform-specific
+ ///
+ /// - **Android**: This is triggered by `onPause` method of the Activity.
+ /// - **iOS**: This is triggered by `applicationWillResignActive` method of the UIApplicationDelegate.
+ /// - **Linux / macOS / Windows**: Unsupported.
+ Suspended,
+
+ /// Emitted when the application has been resumed.
+ ///
+ /// ## Platform-specific
+ ///
+ /// - **Android**: This is triggered by `onResume` method of the Activity. The first onResume() is ignored to match the iOS implementation, since that is called on activity creation.
+ /// - **iOS**: This is triggered by `applicationWillEnterForeground` method of the UIApplicationDelegate.
+ /// - **Linux / macOS / Windows**: Unsupported.
+ Resumed,
+
+ /// Emitted when all of the event loop's input events have been processed and redraw processing
+ /// is about to begin.
+ ///
+ /// This event is useful as a place to put your code that should be run after all
+ /// state-changing events have been handled and you want to do stuff (updating state, performing
+ /// calculations, etc) that happens as the "main body" of your event loop. If your program only draws
+ /// graphics when something changes, it's usually better to do it in response to
+ /// [`Event::RedrawRequested`](crate::event::Event::RedrawRequested), which gets emitted
+ /// immediately after this event. Programs that draw graphics continuously, like most games,
+ /// can render here unconditionally for simplicity.
+ MainEventsCleared,
+
+ /// Emitted after `MainEventsCleared` when a window should be redrawn.
+ ///
+ /// This gets triggered in two scenarios:
+ /// - The OS has performed an operation that's invalidated the window's contents (such as
+ /// resizing the window).
+ /// - The application has explicitly requested a redraw via
+ /// [`Window::request_redraw`](crate::window::Window::request_redraw).
+ ///
+ /// During each iteration of the event loop, Tao will aggregate duplicate redraw requests
+ /// into a single event, to help avoid duplicating rendering work.
+ ///
+ /// Mainly of interest to applications with mostly-static graphics that avoid redrawing unless
+ /// something changes, like most non-game GUIs.
+ ///
+ /// ## Platform-specific
+ ///
+ /// - **Linux: This is triggered by `draw` signal of the gtk window. It can be used to detect if
+ /// the window is requested to redraw. But widgets it contains are usually not tied to its signal.
+ /// So if you really want to draw each component, please consider using `connect_draw` method
+ /// from [`WidgetExt`] directly.**
+ ///
+ /// [`WidgetExt`]: https://gtk-rs.org/gtk3-rs/stable/latest/docs/gtk/prelude/trait.WidgetExt.html
+ RedrawRequested(WindowId),
+
+ /// Emitted after all `RedrawRequested` events have been processed and control flow is about to
+ /// be taken away from the program. If there are no `RedrawRequested` events, it is emitted
+ /// immediately after `MainEventsCleared`.
+ ///
+ /// This event is useful for doing any cleanup or bookkeeping work after all the rendering
+ /// tasks have been completed.
+ RedrawEventsCleared,
+
+ /// Emitted when the event loop is being shut down.
+ ///
+ /// This is irreversable - if this event is emitted, it is guaranteed to be the last event that
+ /// gets emitted. You generally want to treat this as an "do on quit" event.
+ LoopDestroyed,
+
+ /// Emitted when the app is open by external resources, like opening a file or deeplink.
+ Opened { urls: Vec },
+
+ /// ## Platform-specific
+ ///
+ /// - **macOS**: https://developer.apple.com/documentation/appkit/nsapplicationdelegate/1428638-applicationshouldhandlereopen with return value same as hasVisibleWindows
+ /// - **Other**: Unsupported.
+ #[non_exhaustive]
+ Reopen { has_visible_windows: bool },
+
+ /// Emitted when a scene is requested by the system.
+ ///
+ /// This event is emitted when a scene is requested by the system.
+ /// Scenes created by `Window::new` are not emitted with this event.
+ /// It is also not emitted for the main scene.
+ #[cfg(target_os = "ios")]
+ SceneRequested {
+ /// Scene that was requested by the system.
+ scene: objc2::rc::Retained,
+ /// Options that were used to request the scene.
+ ///
+ /// This lets you determine why the scene was requested.
+ options: objc2::rc::Retained,
+ },
+}
+
+impl Clone for Event<'static, T> {
+ fn clone(&self) -> Self {
+ use self::Event::*;
+ match self {
+ WindowEvent { window_id, event } => WindowEvent {
+ window_id: *window_id,
+ event: event.clone(),
+ },
+ UserEvent(event) => UserEvent(event.clone()),
+ DeviceEvent { device_id, event } => DeviceEvent {
+ device_id: *device_id,
+ event: event.clone(),
+ },
+ NewEvents(cause) => NewEvents(*cause),
+ MainEventsCleared => MainEventsCleared,
+ RedrawRequested(wid) => RedrawRequested(*wid),
+ RedrawEventsCleared => RedrawEventsCleared,
+ LoopDestroyed => LoopDestroyed,
+ Suspended => Suspended,
+ Resumed => Resumed,
+ Opened { urls } => Opened { urls: urls.clone() },
+ Reopen {
+ has_visible_windows,
+ } => Reopen {
+ has_visible_windows: *has_visible_windows,
+ },
+ #[cfg(target_os = "ios")]
+ SceneRequested { scene, options } => SceneRequested {
+ scene: scene.clone(),
+ options: options.clone(),
+ },
+ }
+ }
+}
+
+impl<'a, T> Event<'a, T> {
+ pub fn map_nonuser_event(self) -> Result, Event<'a, T>> {
+ use self::Event::*;
+ match self {
+ UserEvent(_) => Err(self),
+ WindowEvent { window_id, event } => Ok(WindowEvent { window_id, event }),
+ DeviceEvent { device_id, event } => Ok(DeviceEvent { device_id, event }),
+ NewEvents(cause) => Ok(NewEvents(cause)),
+ MainEventsCleared => Ok(MainEventsCleared),
+ RedrawRequested(wid) => Ok(RedrawRequested(wid)),
+ RedrawEventsCleared => Ok(RedrawEventsCleared),
+ LoopDestroyed => Ok(LoopDestroyed),
+ Suspended => Ok(Suspended),
+ Resumed => Ok(Resumed),
+ Opened { urls } => Ok(Opened { urls }),
+ Reopen {
+ has_visible_windows,
+ } => Ok(Reopen {
+ has_visible_windows,
+ }),
+ #[cfg(target_os = "ios")]
+ SceneRequested { scene, options } => Ok(SceneRequested { scene, options }),
+ }
+ }
+
+ /// If the event doesn't contain a reference, turn it into an event with a `'static` lifetime.
+ /// Otherwise, return `None`.
+ pub fn to_static(self) -> Option> {
+ use self::Event::*;
+ match self {
+ WindowEvent { window_id, event } => event
+ .to_static()
+ .map(|event| WindowEvent { window_id, event }),
+ UserEvent(event) => Some(UserEvent(event)),
+ DeviceEvent { device_id, event } => Some(DeviceEvent { device_id, event }),
+ NewEvents(cause) => Some(NewEvents(cause)),
+ MainEventsCleared => Some(MainEventsCleared),
+ RedrawRequested(wid) => Some(RedrawRequested(wid)),
+ RedrawEventsCleared => Some(RedrawEventsCleared),
+ LoopDestroyed => Some(LoopDestroyed),
+ Suspended => Some(Suspended),
+ Resumed => Some(Resumed),
+ Opened { urls } => Some(Opened { urls }),
+ Reopen {
+ has_visible_windows,
+ } => Some(Reopen {
+ has_visible_windows,
+ }),
+ #[cfg(target_os = "ios")]
+ SceneRequested { scene, options } => Some(SceneRequested { scene, options }),
+ }
+ }
+}
+
+/// Describes the reason the event loop is resuming.
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+#[non_exhaustive]
+pub enum StartCause {
+ /// Sent if the time specified by `ControlFlow::WaitUntil` has been reached. Contains the
+ /// moment the timeout was requested and the requested resume time. The actual resume time is
+ /// guaranteed to be equal to or after the requested resume time.
+ #[non_exhaustive]
+ ResumeTimeReached {
+ start: Instant,
+ requested_resume: Instant,
+ },
+
+ /// Sent if the OS has new events to send to the window, after a wait was requested. Contains
+ /// the moment the wait was requested and the resume time, if requested.
+ #[non_exhaustive]
+ WaitCancelled {
+ start: Instant,
+ requested_resume: Option,
+ },
+
+ /// Sent if the event loop is being resumed after the loop's control flow was set to
+ /// `ControlFlow::Poll`.
+ Poll,
+
+ /// Sent once, immediately after `run` is called. Indicates that the loop was just initialized.
+ Init,
+}
+
+/// Describes an event from a `Window`.
+#[non_exhaustive]
+#[derive(Debug, PartialEq)]
+pub enum WindowEvent<'a> {
+ /// The size of the window has changed. Contains the client area's new dimensions.
+ Resized(PhysicalSize),
+
+ /// The position of the window has changed. Contains the window's new position.
+ ///
+ /// ## Platform-specific
+ ///
+ /// - **Linux(Wayland)**: will always be (0, 0) since Wayland doesn't support a global cordinate system.
+ Moved(PhysicalPosition),
+
+ /// The window has been requested to close.
+ CloseRequested,
+
+ /// The window has been destroyed.
+ ///
+ /// ## Platform-specific
+ ///
+ /// - **Windows / Linux:** Only fired if the [`crate::window::Window`] is dropped.
+ /// - **macOS:** Fired if the [`crate::window::Window`] is dropped or the dock `Quit` item is clicked.
+ Destroyed,
+
+ /// A file has been dropped into the window.
+ ///
+ /// When the user drops multiple files at once, this event will be emitted for each file
+ /// separately.
+ DroppedFile(PathBuf),
+
+ /// A file is being hovered over the window.
+ ///
+ /// When the user hovers multiple files at once, this event will be emitted for each file
+ /// separately.
+ HoveredFile(PathBuf),
+
+ /// A file was hovered, but has exited the window.
+ ///
+ /// There will be a single `HoveredFileCancelled` event triggered even if multiple files were
+ /// hovered.
+ HoveredFileCancelled,
+
+ /// The window received a unicode character.
+ ReceivedImeText(String),
+
+ /// The window gained or lost focus.
+ ///
+ /// The parameter is true if the window has gained focus, and false if it has lost focus.
+ Focused(bool),
+
+ /// An event from the keyboard has been received.
+ ///
+ /// ## Platform-specific
+ /// - **Windows:** The shift key overrides NumLock. In other words, while shift is held down,
+ /// numpad keys act as if NumLock wasn't active. When this is used, the OS sends fake key
+ /// events which are not marked as `is_synthetic`.
+ #[non_exhaustive]
+ KeyboardInput {
+ device_id: DeviceId,
+ event: KeyEvent,
+
+ /// If `true`, the event was generated synthetically by tao
+ /// in one of the following circumstances:
+ ///
+ /// * Synthetic key press events are generated for all keys pressed
+ /// when a window gains focus. Likewise, synthetic key release events
+ /// are generated for all keys pressed when a window goes out of focus.
+ /// ***Currently, this is only functional on Linux and Windows***
+ ///
+ /// Otherwise, this value is always `false`.
+ is_synthetic: bool,
+ },
+
+ /// The keyboard modifiers have changed.
+ ModifiersChanged(ModifiersState),
+
+ /// The cursor has moved on the window.
+ CursorMoved {
+ device_id: DeviceId,
+
+ /// (x,y) coords in pixels relative to the top-left corner of the window. Because the range of this data is
+ /// limited by the display area and it may have been transformed by the OS to implement effects such as cursor
+ /// acceleration, it should not be used to implement non-cursor-like interactions such as 3D camera control.
+ position: PhysicalPosition,
+ #[deprecated = "Deprecated in favor of WindowEvent::ModifiersChanged"]
+ modifiers: ModifiersState,
+ },
+
+ /// The cursor has entered the window.
+ CursorEntered { device_id: DeviceId },
+
+ /// The cursor has left the window.
+ CursorLeft { device_id: DeviceId },
+
+ /// A mouse wheel movement or touchpad scroll occurred.
+ MouseWheel {
+ device_id: DeviceId,
+ delta: MouseScrollDelta,
+ phase: TouchPhase,
+ #[deprecated = "Deprecated in favor of WindowEvent::ModifiersChanged"]
+ modifiers: ModifiersState,
+ },
+
+ /// An mouse button press has been received.
+ MouseInput {
+ device_id: DeviceId,
+ state: ElementState,
+ button: MouseButton,
+ #[deprecated = "Deprecated in favor of WindowEvent::ModifiersChanged"]
+ modifiers: ModifiersState,
+ },
+
+ /// Touchpad pressure event.
+ ///
+ /// At the moment, only supported on Apple forcetouch-capable macbooks.
+ /// The parameters are: pressure level (value between 0 and 1 representing how hard the touchpad
+ /// is being pressed) and stage (integer representing the click level).
+ TouchpadPressure {
+ device_id: DeviceId,
+ pressure: f32,
+ stage: i64,
+ },
+
+ /// Motion on some analog axis. May report data redundant to other, more specific events.
+ AxisMotion {
+ device_id: DeviceId,
+ axis: AxisId,
+ value: f64,
+ },
+
+ /// Touch event has been received
+ Touch(Touch),
+
+ /// The window's scale factor has changed.
+ ///
+ /// The following user actions can cause DPI changes:
+ ///
+ /// * Changing the display's resolution.
+ /// * Changing the display's scale factor (e.g. in Control Panel on Windows).
+ /// * Moving the window to a display with a different scale factor.
+ ///
+ /// After this event callback has been processed, the window will be resized to whatever value
+ /// is pointed to by the `new_inner_size` reference. By default, this will contain the size suggested
+ /// by the OS, but it can be changed to any value.
+ ///
+ /// For more information about DPI in general, see the [`dpi`](crate::dpi) module.
+ ScaleFactorChanged {
+ scale_factor: f64,
+ new_inner_size: &'a mut PhysicalSize,
+ },
+
+ /// The system window theme has changed.
+ ///
+ /// Applications might wish to react to this to change the theme of the content of the window
+ /// when the system changes the window theme.
+ ///
+ /// ## Platform-specific
+ ///
+ /// - **Android / iOS:** Unsupported
+ ThemeChanged(Theme),
+
+ /// The window decorations has been clicked.
+ ///
+ /// ## Platform-specific
+ ///
+ /// - **Linux / macOS / Android / iOS:** Unsupported
+ DecorationsClick,
+}
+
+impl Clone for WindowEvent<'static> {
+ fn clone(&self) -> Self {
+ use self::WindowEvent::*;
+ match self {
+ Resized(size) => Resized(*size),
+ Moved(pos) => Moved(*pos),
+ CloseRequested => CloseRequested,
+ Destroyed => Destroyed,
+ DroppedFile(file) => DroppedFile(file.clone()),
+ HoveredFile(file) => HoveredFile(file.clone()),
+ HoveredFileCancelled => HoveredFileCancelled,
+ ReceivedImeText(c) => ReceivedImeText(c.clone()),
+ Focused(f) => Focused(*f),
+ KeyboardInput {
+ device_id,
+ event,
+ is_synthetic,
+ } => KeyboardInput {
+ device_id: *device_id,
+ event: event.clone(),
+ is_synthetic: *is_synthetic,
+ },
+
+ ModifiersChanged(modifiers) => ModifiersChanged(*modifiers),
+ #[allow(deprecated)]
+ CursorMoved {
+ device_id,
+ position,
+ modifiers,
+ } => CursorMoved {
+ device_id: *device_id,
+ position: *position,
+ modifiers: *modifiers,
+ },
+ CursorEntered { device_id } => CursorEntered {
+ device_id: *device_id,
+ },
+ CursorLeft { device_id } => CursorLeft {
+ device_id: *device_id,
+ },
+ #[allow(deprecated)]
+ MouseWheel {
+ device_id,
+ delta,
+ phase,
+ modifiers,
+ } => MouseWheel {
+ device_id: *device_id,
+ delta: *delta,
+ phase: *phase,
+ modifiers: *modifiers,
+ },
+ #[allow(deprecated)]
+ MouseInput {
+ device_id,
+ state,
+ button,
+ modifiers,
+ } => MouseInput {
+ device_id: *device_id,
+ state: *state,
+ button: *button,
+ modifiers: *modifiers,
+ },
+ TouchpadPressure {
+ device_id,
+ pressure,
+ stage,
+ } => TouchpadPressure {
+ device_id: *device_id,
+ pressure: *pressure,
+ stage: *stage,
+ },
+ AxisMotion {
+ device_id,
+ axis,
+ value,
+ } => AxisMotion {
+ device_id: *device_id,
+ axis: *axis,
+ value: *value,
+ },
+ Touch(touch) => Touch(*touch),
+ ThemeChanged(theme) => ThemeChanged(*theme),
+ ScaleFactorChanged { .. } => {
+ unreachable!("Static event can't be about scale factor changing")
+ }
+ DecorationsClick => DecorationsClick,
+ }
+ }
+}
+
+impl<'a> WindowEvent<'a> {
+ pub fn to_static(self) -> Option> {
+ use self::WindowEvent::*;
+ match self {
+ Resized(size) => Some(Resized(size)),
+ Moved(position) => Some(Moved(position)),
+ CloseRequested => Some(CloseRequested),
+ Destroyed => Some(Destroyed),
+ DroppedFile(file) => Some(DroppedFile(file)),
+ HoveredFile(file) => Some(HoveredFile(file)),
+ HoveredFileCancelled => Some(HoveredFileCancelled),
+ ReceivedImeText(c) => Some(ReceivedImeText(c)),
+ Focused(focused) => Some(Focused(focused)),
+ KeyboardInput {
+ device_id,
+ event,
+ is_synthetic,
+ } => Some(KeyboardInput {
+ device_id,
+ event,
+ is_synthetic,
+ }),
+ ModifiersChanged(modifiers) => Some(ModifiersChanged(modifiers)),
+ #[allow(deprecated)]
+ CursorMoved {
+ device_id,
+ position,
+ modifiers,
+ } => Some(CursorMoved {
+ device_id,
+ position,
+ modifiers,
+ }),
+ CursorEntered { device_id } => Some(CursorEntered { device_id }),
+ CursorLeft { device_id } => Some(CursorLeft { device_id }),
+ #[allow(deprecated)]
+ MouseWheel {
+ device_id,
+ delta,
+ phase,
+ modifiers,
+ } => Some(MouseWheel {
+ device_id,
+ delta,
+ phase,
+ modifiers,
+ }),
+ #[allow(deprecated)]
+ MouseInput {
+ device_id,
+ state,
+ button,
+ modifiers,
+ } => Some(MouseInput {
+ device_id,
+ state,
+ button,
+ modifiers,
+ }),
+ TouchpadPressure {
+ device_id,
+ pressure,
+ stage,
+ } => Some(TouchpadPressure {
+ device_id,
+ pressure,
+ stage,
+ }),
+ AxisMotion {
+ device_id,
+ axis,
+ value,
+ } => Some(AxisMotion {
+ device_id,
+ axis,
+ value,
+ }),
+ Touch(touch) => Some(Touch(touch)),
+ ThemeChanged(theme) => Some(ThemeChanged(theme)),
+ ScaleFactorChanged { .. } => None,
+ DecorationsClick => Some(DecorationsClick),
+ }
+ }
+}
+
+/// Identifier of an input device.
+///
+/// Whenever you receive an event arising from a particular input device, this event contains a `DeviceId` which
+/// identifies its origin. Note that devices may be virtual (representing an on-screen cursor and keyboard focus) or
+/// physical. Virtual devices typically aggregate inputs from multiple physical devices.
+#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
+pub struct DeviceId(pub(crate) platform_impl::DeviceId);
+
+impl DeviceId {
+ /// # Safety
+ /// Returns a dummy `DeviceId`, useful for unit testing. The only guarantee made about the return
+ /// value of this function is that it will always be equal to itself and to future values returned
+ /// by this function. No other guarantees are made. This may be equal to a real `DeviceId`.
+ ///
+ /// **Passing this into a tao function will result in undefined behavior.**
+ pub unsafe fn dummy() -> Self {
+ DeviceId(platform_impl::DeviceId::dummy())
+ }
+}
+
+/// Represents raw hardware events that are not associated with any particular window.
+///
+/// Useful for interactions that diverge significantly from a conventional 2D GUI, such as 3D camera or first-person
+/// game controls. Many physical actions, such as mouse movement, can produce both device and window events. Because
+/// window events typically arise from virtual devices (corresponding to GUI cursors and keyboard focus) the device IDs
+/// may not match.
+///
+/// Note that these events are delivered regardless of input focus.
+#[non_exhaustive]
+#[derive(Clone, Debug, PartialEq)]
+pub enum DeviceEvent {
+ Added,
+ Removed,
+
+ /// Change in physical position of a pointing device.
+ ///
+ /// This represents raw, unfiltered physical motion. Not to be confused with `WindowEvent::CursorMoved`.
+ #[non_exhaustive]
+ MouseMotion {
+ /// (x, y) change in position in unspecified units.
+ ///
+ /// Different devices may use different units.
+ delta: (f64, f64),
+ },
+
+ /// Physical scroll event
+ #[non_exhaustive]
+ MouseWheel {
+ delta: MouseScrollDelta,
+ },
+
+ /// Motion on some analog axis. This event will be reported for all arbitrary input devices
+ /// that tao supports on this platform, including mouse devices. If the device is a mouse
+ /// device then this will be reported alongside the MouseMotion event.
+ #[non_exhaustive]
+ Motion {
+ axis: AxisId,
+ value: f64,
+ },
+
+ #[non_exhaustive]
+ Button {
+ button: ButtonId,
+ state: ElementState,
+ },
+
+ Key(RawKeyEvent),
+
+ #[non_exhaustive]
+ Text {
+ codepoint: char,
+ },
+}
+
+/// Describes a keyboard input as a raw device event.
+///
+/// Note that holding down a key may produce repeated `RawKeyEvent`s. The
+/// operating system doesn't provide information whether such an event is a
+/// repeat or the initial keypress. An application may emulate this by, for
+/// example keeping a Map/Set of pressed keys and determining whether a keypress
+/// corresponds to an already pressed key.
+#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+pub struct RawKeyEvent {
+ pub physical_key: keyboard::KeyCode,
+ pub state: ElementState,
+}
+
+/// Describes a keyboard input targeting a window.
+#[derive(Debug, Clone, Eq, PartialEq, Hash)]
+pub struct KeyEvent {
+ /// Represents the position of a key independent of the currently active layout.
+ ///
+ /// It also uniquely identifies the physical key (i.e. it's mostly synonymous with a scancode).
+ /// The most prevalent use case for this is games. For example the default keys for the player
+ /// to move around might be the W, A, S, and D keys on a US layout. The position of these keys
+ /// is more important than their label, so they should map to Z, Q, S, and D on an "AZERTY"
+ /// layout. (This value is `KeyCode::KeyW` for the Z key on an AZERTY layout.)
+ ///
+ /// Note that `Fn` and `FnLock` key events are not guaranteed to be emitted by `tao`. These
+ /// keys are usually handled at the hardware or OS level.
+ pub physical_key: keyboard::KeyCode,
+
+ /// This value is affected by all modifiers except Ctrl.
+ ///
+ /// This has two use cases:
+ /// - Allows querying whether the current input is a Dead key.
+ /// - Allows handling key-bindings on platforms which don't
+ /// support `key_without_modifiers`.
+ ///
+ /// ## Platform-specific
+ /// - **Web:** Dead keys might be reported as the real key instead
+ /// of `Dead` depending on the browser/OS.
+ pub logical_key: keyboard::Key<'static>,
+
+ /// Contains the text produced by this keypress.
+ ///
+ /// In most cases this is identical to the content
+ /// of the `Character` variant of `logical_key`.
+ /// However, on Windows when a dead key was pressed earlier
+ /// but cannot be combined with the character from this
+ /// keypress, the produced text will consist of two characters:
+ /// the dead-key-character followed by the character resulting
+ /// from this keypress.
+ ///
+ /// An additional difference from `logical_key` is that
+ /// this field stores the text representation of any key
+ /// that has such a representation. For example when
+ /// `logical_key` is `Key::Enter`, this field is `Some("\r")`.
+ ///
+ /// This is `None` if the current keypress cannot
+ /// be interpreted as text.
+ ///
+ /// See also: `text_with_all_modifiers()`
+ pub text: Option<&'static str>,
+
+ pub location: keyboard::KeyLocation,
+ pub state: ElementState,
+ pub repeat: bool,
+
+ pub(crate) platform_specific: platform_impl::KeyEventExtra,
+}
+
+#[cfg(not(any(target_os = "android", target_os = "ios")))]
+impl KeyEvent {
+ /// Identical to `KeyEvent::text` but this is affected by Ctrl.
+ ///
+ /// For example, pressing Ctrl+a produces `Some("\x01")`.
+ pub fn text_with_all_modifiers(&self) -> Option<&str> {
+ self.platform_specific.text_with_all_modifiers
+ }
+
+ /// This value ignores all modifiers including,
+ /// but not limited to Shift, Caps Lock,
+ /// and Ctrl. In most cases this means that the
+ /// unicode character in the resulting string is lowercase.
+ ///
+ /// This is useful for key-bindings / shortcut key combinations.
+ ///
+ /// In case `logical_key` reports `Dead`, this will still report the
+ /// key as `Character` according to the current keyboard layout. This value
+ /// cannot be `Dead`.
+ pub fn key_without_modifiers(&self) -> keyboard::Key<'static> {
+ self.platform_specific.key_without_modifiers.clone()
+ }
+}
+
+#[cfg(any(target_os = "android", target_os = "ios"))]
+impl KeyEvent {
+ /// Identical to `KeyEvent::text`.
+ pub fn text_with_all_modifiers(&self) -> Option<&str> {
+ self.text
+ }
+
+ /// Identical to `KeyEvent::logical_key`.
+ pub fn key_without_modifiers(&self) -> keyboard::Key<'static> {
+ self.logical_key.clone()
+ }
+}
+
+/// Describes touch-screen input state.
+#[non_exhaustive]
+#[derive(Debug, Hash, PartialEq, Eq, Clone, Copy)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+pub enum TouchPhase {
+ Started,
+ Moved,
+ Ended,
+ Cancelled,
+}
+
+/// Represents a touch event
+///
+/// Every time the user touches the screen, a new `Start` event with an unique
+/// identifier for the finger is generated. When the finger is lifted, an `End`
+/// event is generated with the same finger id.
+///
+/// After a `Start` event has been emitted, there may be zero or more `Move`
+/// events when the finger is moved or the touch pressure changes.
+///
+/// The finger id may be reused by the system after an `End` event. The user
+/// should assume that a new `Start` event received with the same id has nothing
+/// to do with the old finger and is a new finger.
+///
+/// A `Cancelled` event is emitted when the system has canceled tracking this
+/// touch, such as when the window loses focus, or on iOS if the user moves the
+/// device against their face.
+#[derive(Debug, Clone, Copy, PartialEq)]
+pub struct Touch {
+ pub device_id: DeviceId,
+ pub phase: TouchPhase,
+ pub location: PhysicalPosition,
+ /// Describes how hard the screen was pressed. May be `None` if the platform
+ /// does not support pressure sensitivity.
+ ///
+ /// ## Platform-specific
+ ///
+ /// - Only available on **iOS** 9.0+ and **Windows** 8+.
+ pub force: Option,
+ /// Unique identifier of a finger.
+ pub id: u64,
+}
+
+/// Describes the force of a touch event
+#[non_exhaustive]
+#[derive(Debug, Clone, Copy, PartialEq)]
+pub enum Force {
+ /// On iOS, the force is calibrated so that the same number corresponds to
+ /// roughly the same amount of pressure on the screen regardless of the
+ /// device.
+ #[non_exhaustive]
+ Calibrated {
+ /// The force of the touch, where a value of 1.0 represents the force of
+ /// an average touch (predetermined by the system, not user-specific).
+ ///
+ /// The force reported by Apple Pencil is measured along the axis of the
+ /// pencil. If you want a force perpendicular to the device, you need to
+ /// calculate this value using the `altitude_angle` value.
+ force: f64,
+ /// The maximum possible force for a touch.
+ ///
+ /// The value of this field is sufficiently high to provide a wide
+ /// dynamic range for values of the `force` field.
+ max_possible_force: f64,
+ /// The altitude (in radians) of the stylus.
+ ///
+ /// A value of 0 radians indicates that the stylus is parallel to the
+ /// surface. The value of this property is Pi/2 when the stylus is
+ /// perpendicular to the surface.
+ altitude_angle: Option,
+ },
+ /// If the platform reports the force as normalized, we have no way of
+ /// knowing how much pressure 1.0 corresponds to - we know it's the maximum
+ /// amount of force, but as to how much force, you might either have to
+ /// press really really hard, or not hard at all, depending on the device.
+ Normalized(f64),
+}
+
+impl Force {
+ /// Returns the force normalized to the range between 0.0 and 1.0 inclusive.
+ /// Instead of normalizing the force, you should prefer to handle
+ /// `Force::Calibrated` so that the amount of force the user has to apply is
+ /// consistent across devices.
+ pub fn normalized(&self) -> f64 {
+ match self {
+ Force::Calibrated {
+ force,
+ max_possible_force,
+ altitude_angle,
+ } => {
+ let force = match altitude_angle {
+ Some(altitude_angle) => force / altitude_angle.sin(),
+ None => *force,
+ };
+ force / max_possible_force
+ }
+ Force::Normalized(force) => *force,
+ }
+ }
+}
+
+/// Identifier for a specific analog axis on some device.
+pub type AxisId = u32;
+
+/// Identifier for a specific button on some device.
+pub type ButtonId = u32;
+
+/// Describes the input state of a key.
+#[non_exhaustive]
+#[derive(Debug, Hash, PartialEq, Eq, Clone, Copy)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+pub enum ElementState {
+ Pressed,
+ Released,
+}
+
+/// Describes a button of a mouse controller.
+#[non_exhaustive]
+#[derive(Debug, Hash, PartialEq, Eq, Clone, Copy)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+pub enum MouseButton {
+ Left,
+ Right,
+ Middle,
+ Other(u16),
+}
+
+/// Describes a difference in the mouse scroll wheel state.
+#[non_exhaustive]
+#[derive(Debug, Clone, Copy, PartialEq)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+pub enum MouseScrollDelta {
+ /// Amount in lines or rows to scroll in the horizontal
+ /// and vertical directions.
+ ///
+ /// Positive values indicate movement forward
+ /// (away from the user) or rightwards.
+ LineDelta(f32, f32),
+ /// Amount in pixels to scroll in the horizontal and
+ /// vertical direction.
+ ///
+ /// Scroll events are expressed as a PixelDelta if
+ /// supported by the device (eg. a touchpad) and
+ /// platform.
+ PixelDelta(PhysicalPosition),
+}
diff --git a/frontend/src-tauri/patches/tao-0.35.2/src/event_loop.rs b/frontend/src-tauri/patches/tao-0.35.2/src/event_loop.rs
new file mode 100644
index 000000000..6e3406d45
--- /dev/null
+++ b/frontend/src-tauri/patches/tao-0.35.2/src/event_loop.rs
@@ -0,0 +1,416 @@
+// Copyright 2014-2021 The winit contributors
+// Copyright 2021-2023 Tauri Programme within The Commons Conservancy
+// SPDX-License-Identifier: Apache-2.0
+
+//! The `EventLoop` struct and assorted supporting types, including `ControlFlow`.
+//!
+//! If you want to send custom events to the event loop, use [`EventLoop::create_proxy()`][create_proxy]
+//! to acquire an [`EventLoopProxy`][event_loop_proxy] and call its [`send_event`][send_event] method.
+//!
+//! See the root-level documentation for information on how to create and use an event loop to
+//! handle events.
+//!
+//! [create_proxy]: crate::event_loop::EventLoop::create_proxy
+//! [event_loop_proxy]: crate::event_loop::EventLoopProxy
+//! [send_event]: crate::event_loop::EventLoopProxy::send_event
+use std::{error, fmt, marker::PhantomData, ops::Deref, time::Instant};
+
+use crate::{
+ dpi::PhysicalPosition,
+ error::ExternalError,
+ event::Event,
+ monitor::MonitorHandle,
+ platform_impl,
+ window::{ProgressBarState, Theme},
+};
+
+/// Provides a way to retrieve events from the system and from the windows that were registered to
+/// the events loop.
+///
+/// An `EventLoop` can be seen more or less as a "context". Calling `EventLoop::new()`
+/// initializes everything that will be required to create windows.
+///
+/// To wake up an `EventLoop` from a another thread, see the `EventLoopProxy` docs.
+///
+/// Note that the `EventLoop` cannot be shared across threads (due to platform-dependant logic
+/// forbidding it), as such it is neither `Send` nor `Sync`. If you need cross-thread access, the
+/// `Window` created from this `EventLoop` _can_ be sent to an other thread, and the
+/// `EventLoopProxy` allows you to wake up an `EventLoop` from another thread.
+///
+pub struct EventLoop {
+ pub(crate) event_loop: platform_impl::EventLoop,
+ pub(crate) _marker: ::std::marker::PhantomData<*mut ()>, // Not Send nor Sync
+}
+
+/// Target that associates windows with an `EventLoop`.
+///
+/// This type exists to allow you to create new windows while Tao executes
+/// your callback. `EventLoop` will coerce into this type (`impl Deref for
+/// EventLoop`), so functions that take this as a parameter can also take
+/// `&EventLoop`.
+#[derive(Clone)]
+pub struct EventLoopWindowTarget {
+ pub(crate) p: platform_impl::EventLoopWindowTarget,
+ pub(crate) _marker: ::std::marker::PhantomData<*mut ()>, // Not Send nor Sync
+}
+
+impl fmt::Debug for EventLoop {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.pad("EventLoop { .. }")
+ }
+}
+
+impl fmt::Debug for EventLoopWindowTarget {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.pad("EventLoopWindowTarget { .. }")
+ }
+}
+
+/// Object that allows building the event loop.
+///
+/// This is used to make specifying options that affect the whole application
+/// easier. But note that constructing multiple event loops is not supported.
+#[derive(Default)]
+pub struct EventLoopBuilder {
+ pub(crate) platform_specific: platform_impl::PlatformSpecificEventLoopAttributes,
+ _p: PhantomData,
+}
+impl EventLoopBuilder<()> {
+ /// Start building a new event loop.
+ #[inline]
+ pub fn new() -> Self {
+ Self::with_user_event()
+ }
+}
+impl EventLoopBuilder {
+ /// Start building a new event loop, with the given type as the user event
+ /// type.
+ #[inline]
+ pub fn with_user_event() -> Self {
+ Self {
+ platform_specific: Default::default(),
+ _p: PhantomData,
+ }
+ }
+ /// Builds a new event loop.
+ ///
+ /// ***For cross-platform compatibility, the `EventLoop` must be created on the main thread.***
+ /// Attempting to create the event loop on a different thread will panic. This restriction isn't
+ /// strictly necessary on all platforms, but is imposed to eliminate any nasty surprises when
+ /// porting to platforms that require it. `EventLoopBuilderExt::any_thread` functions are exposed
+ /// in the relevant `platform` module if the target platform supports creating an event loop on
+ /// any thread.
+ ///
+ /// Usage will result in display backend initialisation, this can be controlled on linux
+ /// using an environment variable `WINIT_UNIX_BACKEND`. Legal values are `x11` and `wayland`.
+ /// If it is not set, winit will try to connect to a wayland connection, and if it fails will
+ /// fallback on x11. If this variable is set with any other value, winit will panic.
+ ///
+ /// ## Platform-specific
+ ///
+ /// - **iOS:** Can only be called on the main thread.
+ #[inline]
+ pub fn build(&mut self) -> EventLoop {
+ EventLoop {
+ #[cfg_attr(
+ any(
+ target_os = "linux",
+ target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "netbsd",
+ target_os = "openbsd"
+ ),
+ allow(clippy::unnecessary_mut_passed)
+ )]
+ event_loop: platform_impl::EventLoop::new(&mut self.platform_specific),
+ _marker: PhantomData,
+ }
+ }
+}
+
+/// Set by the user callback given to the `EventLoop::run` method.
+///
+/// Indicates the desired behavior of the event loop after [`Event::RedrawEventsCleared`][events_cleared]
+/// is emitted. Defaults to `Poll`.
+///
+/// ## Persistency
+/// Almost every change is persistent between multiple calls to the event loop closure within a
+/// given run loop. The only exception to this is `ExitWithCode` which, once set, cannot be unset.
+/// Changes are **not** persistent between multiple calls to `run_return` - issuing a new call will
+/// reset the control flow to `Poll`.
+///
+/// [events_cleared]: crate::event::Event::RedrawEventsCleared
+#[non_exhaustive]
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+pub enum ControlFlow {
+ /// When the current loop iteration finishes, immediately begin a new iteration regardless of
+ /// whether or not new events are available to process.
+ Poll,
+ /// When the current loop iteration finishes, suspend the thread until another event arrives.
+ Wait,
+ /// When the current loop iteration finishes, suspend the thread until either another event
+ /// arrives or the given time is reached.
+ WaitUntil(Instant),
+ /// Send a `LoopDestroyed` event and stop the event loop. This variant is *sticky* - once set,
+ /// `control_flow` cannot be changed from `ExitWithCode`, and any future attempts to do so will
+ /// result in the `control_flow` parameter being reset to `ExitWithCode`.
+ ///
+ /// The contained number will be used as exit code. The [`Exit`] constant is a shortcut for this
+ /// with exit code 0.
+ ///
+ /// ## Platform-specific
+ ///
+ /// - **Android / iOS / WASM**: The supplied exit code is unused.
+ /// - **Unix**: On most Unix-like platforms, only the 8 least significant bits will be used,
+ /// which can cause surprises with negative exit values (`-42` would end up as `214`). See
+ /// [`std::process::exit`].
+ ///
+ /// [`Exit`]: ControlFlow::Exit
+ ExitWithCode(i32),
+}
+
+impl ControlFlow {
+ /// Alias for [`ExitWithCode`]`(0)`.
+ ///
+ /// [`ExitWithCode`]: ControlFlow::ExitWithCode
+ #[allow(non_upper_case_globals)]
+ pub const Exit: Self = Self::ExitWithCode(0);
+}
+
+impl Default for ControlFlow {
+ #[inline(always)]
+ fn default() -> ControlFlow {
+ ControlFlow::Poll
+ }
+}
+
+impl EventLoop<()> {
+ /// Alias for [`EventLoopBuilder::new().build()`].
+ ///
+ /// [`EventLoopBuilder::new().build()`]: EventLoopBuilder::build
+ #[inline]
+ pub fn new() -> EventLoop<()> {
+ EventLoopBuilder::new().build()
+ }
+}
+
+impl Default for EventLoop<()> {
+ fn default() -> Self {
+ Self::new()
+ }
+}
+
+impl EventLoop {
+ /// Hijacks the calling thread and initializes the tao event loop with the provided
+ /// closure. Since the closure is `'static`, it must be a `move` closure if it needs to
+ /// access any data from the calling context.
+ ///
+ /// See the [`ControlFlow`] docs for information on how changes to `&mut ControlFlow` impact the
+ /// event loop's behavior.
+ ///
+ /// Any values not passed to this function will *not* be dropped.
+ ///
+ /// ## Platform-specific
+ ///
+ /// - **Unix**: The program terminates with exit code 1 if the display server
+ /// disconnects.
+ ///
+ /// [`ControlFlow`]: crate::event_loop::ControlFlow
+ #[inline]
+ pub fn run(self, event_handler: F) -> !
+ where
+ F: 'static + FnMut(Event<'_, T>, &EventLoopWindowTarget, &mut ControlFlow),
+ {
+ self.event_loop.run(event_handler)
+ }
+
+ /// Creates an `EventLoopProxy` that can be used to dispatch user events to the main event loop.
+ pub fn create_proxy(&self) -> EventLoopProxy {
+ EventLoopProxy {
+ event_loop_proxy: self.event_loop.create_proxy(),
+ }
+ }
+}
+
+impl Deref for EventLoop {
+ type Target = EventLoopWindowTarget;
+ fn deref(&self) -> &EventLoopWindowTarget {
+ self.event_loop.window_target()
+ }
+}
+
+impl EventLoopWindowTarget {
+ /// Returns the list of all the monitors available on the system.
+ #[inline]
+ pub fn available_monitors(&self) -> impl Iterator- {
+ self
+ .p
+ .available_monitors()
+ .into_iter()
+ .map(|inner| MonitorHandle { inner })
+ }
+
+ /// Returns the primary monitor of the system.
+ ///
+ /// Returns `None` if it can't identify any monitor as a primary one.
+ #[inline]
+ pub fn primary_monitor(&self) -> Option {
+ self.p.primary_monitor()
+ }
+
+ /// Returns the monitor that contains the given point.
+ ///
+ /// ## Platform-specific:
+ ///
+ /// - **Android / iOS:** Unsupported.
+ #[inline]
+ pub fn monitor_from_point(&self, x: f64, y: f64) -> Option {
+ self
+ .p
+ .monitor_from_point(x, y)
+ .map(|inner| MonitorHandle { inner })
+ }
+
+ /// Change [`DeviceEvent`] filter mode.
+ ///
+ /// Since the [`DeviceEvent`] capture can lead to high CPU usage for unfocused windows, tao
+ /// will ignore them by default for unfocused windows. This method allows changing
+ /// this filter at runtime to explicitly capture them again.
+ ///
+ /// ## Platform-specific
+ ///
+ /// - **Linux / macOS / iOS / Android:** Unsupported.
+ ///
+ /// [`DeviceEvent`]: crate::event::DeviceEvent
+ pub fn set_device_event_filter(&self, _filter: DeviceEventFilter) {
+ #[cfg(target_os = "windows")]
+ self.p.set_device_event_filter(_filter);
+ }
+
+ /// Returns the current cursor position
+ ///
+ /// ## Platform-specific
+ ///
+ /// - **iOS / Android / Linux(Wayland)**: Unsupported, returns `0,0`.
+ #[inline]
+ pub fn cursor_position(&self) -> Result, ExternalError> {
+ self.p.cursor_position()
+ }
+
+ /// Sets the progress bar state
+ ///
+ /// ## Platform-specific
+ ///
+ /// - **Windows:** Unsupported. Use the Progress Bar Function Available in Window (Windows can have different progress bars for different window)
+ /// - **Linux:** Only supported desktop environments with `libunity` (e.g. GNOME).
+ /// - **iOS / Android:** Unsupported.
+ #[inline]
+ pub fn set_progress_bar(&self, _progress: ProgressBarState) {
+ #[cfg(any(target_os = "linux", target_os = "macos"))]
+ self.p.set_progress_bar(_progress)
+ }
+
+ /// Sets the theme for the application.
+ ///
+ /// ## Platform-specific
+ ///
+ /// - **iOS / Android:** Unsupported.
+ #[inline]
+ pub fn set_theme(&self, _theme: Option) {
+ #[cfg(any(
+ windows,
+ target_os = "linux",
+ target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "netbsd",
+ target_os = "openbsd",
+ target_os = "macos",
+ ))]
+ self.p.set_theme(_theme)
+ }
+}
+
+#[cfg(feature = "rwh_05")]
+unsafe impl rwh_05::HasRawDisplayHandle for EventLoop {
+ fn raw_display_handle(&self) -> rwh_05::RawDisplayHandle {
+ rwh_05::HasRawDisplayHandle::raw_display_handle(&**self)
+ }
+}
+
+#[cfg(feature = "rwh_06")]
+impl rwh_06::HasDisplayHandle for EventLoop {
+ fn display_handle(&self) -> Result, rwh_06::HandleError> {
+ rwh_06::HasDisplayHandle::display_handle(&**self)
+ }
+}
+
+#[cfg(feature = "rwh_05")]
+unsafe impl rwh_05::HasRawDisplayHandle for EventLoopWindowTarget {
+ fn raw_display_handle(&self) -> rwh_05::RawDisplayHandle {
+ self.p.raw_display_handle_rwh_05()
+ }
+}
+
+#[cfg(feature = "rwh_06")]
+impl rwh_06::HasDisplayHandle for EventLoopWindowTarget {
+ fn display_handle(&self) -> Result, rwh_06::HandleError> {
+ let raw = self.p.raw_display_handle_rwh_06()?;
+ // SAFETY: The display will never be deallocated while the event loop is alive.
+ Ok(unsafe { rwh_06::DisplayHandle::borrow_raw(raw) })
+ }
+}
+
+/// Used to send custom events to `EventLoop`.
+pub struct EventLoopProxy {
+ event_loop_proxy: platform_impl::EventLoopProxy,
+}
+
+impl Clone for EventLoopProxy {
+ fn clone(&self) -> Self {
+ Self {
+ event_loop_proxy: self.event_loop_proxy.clone(),
+ }
+ }
+}
+
+impl EventLoopProxy {
+ /// Send an event to the `EventLoop` from which this proxy was created. This emits a
+ /// `UserEvent(event)` event in the event loop, where `event` is the value passed to this
+ /// function.
+ ///
+ /// Returns an `Err` if the associated `EventLoop` no longer exists.
+ pub fn send_event(&self, event: T) -> Result<(), EventLoopClosed> {
+ self.event_loop_proxy.send_event(event)
+ }
+}
+
+impl fmt::Debug for EventLoopProxy {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.pad("EventLoopProxy { .. }")
+ }
+}
+
+/// The error that is returned when an `EventLoopProxy` attempts to wake up an `EventLoop` that
+/// no longer exists. Contains the original event given to `send_event`.
+#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
+pub struct EventLoopClosed(pub T);
+
+impl fmt::Display for EventLoopClosed {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.write_str("Tried to wake up a closed `EventLoop`")
+ }
+}
+
+impl error::Error for EventLoopClosed {}
+
+/// Fiter controlling the propagation of device events.
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Default)]
+pub enum DeviceEventFilter {
+ /// Always filter out device events.
+ Always,
+ /// Filter out device events while the window is not focused.
+ #[default]
+ Unfocused,
+ /// Report all device events regardless of window focus.
+ Never,
+}
diff --git a/frontend/src-tauri/patches/tao-0.35.2/src/icon.rs b/frontend/src-tauri/patches/tao-0.35.2/src/icon.rs
new file mode 100644
index 000000000..8827e77bf
--- /dev/null
+++ b/frontend/src-tauri/patches/tao-0.35.2/src/icon.rs
@@ -0,0 +1,169 @@
+// Copyright 2014-2021 The winit contributors
+// Copyright 2021-2023 Tauri Programme within The Commons Conservancy
+// SPDX-License-Identifier: Apache-2.0
+
+use crate::platform_impl::PlatformIcon;
+use std::{error::Error, fmt, io, mem};
+
+#[repr(C)]
+#[derive(Debug)]
+pub(crate) struct Pixel {
+ pub(crate) r: u8,
+ pub(crate) g: u8,
+ pub(crate) b: u8,
+ pub(crate) a: u8,
+}
+
+pub(crate) const PIXEL_SIZE: usize = mem::size_of::();
+
+#[non_exhaustive]
+#[derive(Debug)]
+/// An error produced when using `Icon::from_rgba` with invalid arguments.
+pub enum BadIcon {
+ /// Produced when the length of the `rgba` argument isn't divisible by 4, thus `rgba` can't be
+ /// safely interpreted as 32bpp RGBA pixels.
+ #[non_exhaustive]
+ ByteCountNotDivisibleBy4 { byte_count: usize },
+ /// Produced when the number of pixels (`rgba.len() / 4`) isn't equal to `width * height`.
+ /// At least one of your arguments is incorrect.
+ #[non_exhaustive]
+ DimensionsVsPixelCount {
+ width: u32,
+ height: u32,
+ width_x_height: usize,
+ pixel_count: usize,
+ },
+ /// Produced when the provided icon width or height is equal to zero.
+ #[non_exhaustive]
+ DimensionsZero { width: u32, height: u32 },
+ /// Produced when the provided icon width or height is equal to zero.
+ #[non_exhaustive]
+ DimensionsMultiplyOverflow { width: u32, height: u32 },
+ /// Produced when underlying OS functionality failed to create the icon
+ OsError(io::Error),
+}
+
+impl fmt::Display for BadIcon {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ match self {
+ BadIcon::ByteCountNotDivisibleBy4 { byte_count } => write!(f,
+ "The length of the `rgba` argument ({byte_count:?}) isn't divisible by 4, making it impossible to interpret as 32bpp RGBA pixels.",
+ ),
+ BadIcon::DimensionsVsPixelCount {
+ width,
+ height,
+ width_x_height,
+ pixel_count,
+ } => write!(f,
+ "The specified dimensions ({width:?}x{height:?}) don't match the number of pixels supplied by the `rgba` argument ({pixel_count:?}). For those dimensions, the expected pixel count is {width_x_height:?}.",
+ ),
+ BadIcon::DimensionsZero {
+ width,
+ height,
+ } => write!(f,
+ "The specified dimensions ({width:?}x{height:?}) must be greater than zero."
+ ),
+ BadIcon::DimensionsMultiplyOverflow {
+ width,
+ height,
+ } => write!(f,
+ "The specified dimensions multiplication has overflowed ({width:?}x{height:?})."
+ ),
+ BadIcon::OsError(e) => write!(f, "OS error when instantiating the icon: {e:?}"),
+ }
+ }
+}
+
+impl Error for BadIcon {
+ fn source(&self) -> Option<&(dyn Error + 'static)> {
+ Some(self)
+ }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub(crate) struct RgbaIcon {
+ pub(crate) rgba: Vec,
+ pub(crate) width: u32,
+ pub(crate) height: u32,
+}
+
+/// For platforms which don't have window icons (e.g. web)
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub(crate) struct NoIcon;
+
+#[allow(dead_code)] // These are not used on every platform
+mod constructors {
+ use super::*;
+
+ impl RgbaIcon {
+ /// Creates an `Icon` from 32bpp RGBA data.
+ ///
+ /// The length of `rgba` must be divisible by 4, and `width * height` must equal
+ /// `rgba.len() / 4`. Otherwise, this will return a `BadIcon` error.
+ pub fn from_rgba(rgba: Vec, width: u32, height: u32) -> Result {
+ if width == 0 || height == 0 {
+ return Err(BadIcon::DimensionsZero { width, height });
+ }
+
+ if rgba.len() % PIXEL_SIZE != 0 {
+ return Err(BadIcon::ByteCountNotDivisibleBy4 {
+ byte_count: rgba.len(),
+ });
+ }
+ let width_usize = width as usize;
+ let height_usize = height as usize;
+ let width_x_height = match width_usize.checked_mul(height_usize) {
+ Some(v) => v,
+ None => return Err(BadIcon::DimensionsMultiplyOverflow { width, height }),
+ };
+
+ let pixel_count = rgba.len() / PIXEL_SIZE;
+ if pixel_count != width_x_height {
+ Err(BadIcon::DimensionsVsPixelCount {
+ width,
+ height,
+ width_x_height,
+ pixel_count,
+ })
+ } else {
+ Ok(RgbaIcon {
+ rgba,
+ width,
+ height,
+ })
+ }
+ }
+ }
+
+ impl NoIcon {
+ pub fn from_rgba(rgba: Vec, width: u32, height: u32) -> Result {
+ // Create the rgba icon anyway to validate the input
+ let _ = RgbaIcon::from_rgba(rgba, width, height)?;
+ Ok(NoIcon)
+ }
+ }
+}
+
+/// An icon used for the window titlebar, taskbar, etc.
+#[derive(Clone)]
+pub struct Icon {
+ pub(crate) inner: PlatformIcon,
+}
+
+impl fmt::Debug for Icon {
+ fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
+ fmt::Debug::fmt(&self.inner, formatter)
+ }
+}
+
+impl Icon {
+ /// Creates an `Icon` from 32bpp RGBA data.
+ ///
+ /// The length of `rgba` must be divisible by 4, and `width * height` must equal
+ /// `rgba.len() / 4`. Otherwise, this will return a `BadIcon` error.
+ pub fn from_rgba(rgba: Vec, width: u32, height: u32) -> Result {
+ Ok(Icon {
+ inner: PlatformIcon::from_rgba(rgba, width, height)?,
+ })
+ }
+}
diff --git a/frontend/src-tauri/patches/tao-0.35.2/src/keyboard.rs b/frontend/src-tauri/patches/tao-0.35.2/src/keyboard.rs
new file mode 100644
index 000000000..ac50d42c5
--- /dev/null
+++ b/frontend/src-tauri/patches/tao-0.35.2/src/keyboard.rs
@@ -0,0 +1,1596 @@
+// Copyright 2014-2021 The winit contributors
+// Copyright 2021-2023 Tauri Programme within The Commons Conservancy
+// SPDX-License-Identifier: Apache-2.0
+
+//! **UNSTABLE** -- Types related to the keyboard.
+
+// This file contains a substantial portion of the UI Events Specification by the W3C. In
+// particular, the variant names within `Key` and `KeyCode` and their documentation are modified
+// versions of contents of the aforementioned specification.
+//
+// The original documents are:
+//
+// ### For `Key`
+// UI Events KeyboardEvent key Values
+// https://www.w3.org/TR/2017/CR-uievents-key-20170601/
+// Copyright © 2017 W3C® (MIT, ERCIM, Keio, Beihang).
+//
+// ### For `KeyCode`
+// UI Events KeyboardEvent code Values
+// https://www.w3.org/TR/2017/CR-uievents-code-20170601/
+// Copyright © 2017 W3C® (MIT, ERCIM, Keio, Beihang).
+//
+// These documents were used under the terms of the following license. This W3C license as well as
+// the W3C short notice apply to the `Key` and `KeyCode` enums and their variants and the
+// documentation attached to their variants.
+
+// --------- BEGGINING OF W3C LICENSE --------------------------------------------------------------
+//
+// License
+//
+// By obtaining and/or copying this work, you (the licensee) agree that you have read, understood,
+// and will comply with the following terms and conditions.
+//
+// Permission to copy, modify, and distribute this work, with or without modification, for any
+// purpose and without fee or royalty is hereby granted, provided that you include the following on
+// ALL copies of the work or portions thereof, including modifications:
+//
+// - The full text of this NOTICE in a location viewable to users of the redistributed or derivative
+// work.
+// - Any pre-existing intellectual property disclaimers, notices, or terms and conditions. If none
+// exist, the W3C Software and Document Short Notice should be included.
+// - Notice of any changes or modifications, through a copyright statement on the new code or
+// document such as "This software or document includes material copied from or derived from
+// [title and URI of the W3C document]. Copyright © [YEAR] W3C® (MIT, ERCIM, Keio, Beihang)."
+//
+// Disclaimers
+//
+// THIS WORK IS PROVIDED "AS IS," AND COPYRIGHT HOLDERS MAKE NO REPRESENTATIONS OR WARRANTIES,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO, WARRANTIES OF MERCHANTABILITY OR FITNESS FOR
+// ANY PARTICULAR PURPOSE OR THAT THE USE OF THE SOFTWARE OR DOCUMENT WILL NOT INFRINGE ANY THIRD
+// PARTY PATENTS, COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS.
+//
+// COPYRIGHT HOLDERS WILL NOT BE LIABLE FOR ANY DIRECT, INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES
+// ARISING OUT OF ANY USE OF THE SOFTWARE OR DOCUMENT.
+//
+// The name and trademarks of copyright holders may NOT be used in advertising or publicity
+// pertaining to the work without specific, written prior permission. Title to copyright in this
+// work will at all times remain with copyright holders.
+//
+// --------- END OF W3C LICENSE --------------------------------------------------------------------
+
+// --------- BEGGINING OF W3C SHORT NOTICE ---------------------------------------------------------
+//
+// tao: https://github.com/tauri-apps/tao
+//
+// Copyright © 2021 World Wide Web Consortium, (Massachusetts Institute of Technology, European
+// Research Consortium for Informatics and Mathematics, Keio University, Beihang). All Rights
+// Reserved. This work is distributed under the W3C® Software License [1] in the hope that it will
+// be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE.
+//
+// [1] http://www.w3.org/Consortium/Legal/copyright-software
+//
+// --------- END OF W3C SHORT NOTICE ---------------------------------------------------------------
+
+use std::{fmt, str::FromStr};
+
+use crate::{
+ error::OsError,
+ platform_impl::{
+ keycode_from_scancode as platform_keycode_from_scancode,
+ keycode_to_scancode as platform_keycode_to_scancode,
+ },
+};
+
+impl ModifiersState {
+ /// Returns `true` if the shift key is pressed.
+ pub fn shift_key(&self) -> bool {
+ self.intersects(Self::SHIFT)
+ }
+ /// Returns `true` if the control key is pressed.
+ pub fn control_key(&self) -> bool {
+ self.intersects(Self::CONTROL)
+ }
+ /// Returns `true` if the alt key is pressed.
+ pub fn alt_key(&self) -> bool {
+ self.intersects(Self::ALT)
+ }
+ /// Returns `true` if the super key is pressed.
+ pub fn super_key(&self) -> bool {
+ self.intersects(Self::SUPER)
+ }
+}
+
+bitflags! {
+ /// Represents the current state of the keyboard modifiers
+ ///
+ /// Each flag represents a modifier and is set if this modifier is active.
+ #[derive(Clone, Copy, Default, Debug, PartialEq)]
+ pub struct ModifiersState: u32 {
+ // left and right modifiers are currently commented out, but we should be able to support
+ // them in a future release
+ /// The "shift" key.
+ const SHIFT = 0b100 << 0;
+ // const LSHIFT = 0b010 << 0;
+ // const RSHIFT = 0b001 << 0;
+ /// The "control" key.
+ const CONTROL = 0b100 << 3;
+ // const LCTRL = 0b010 << 3;
+ // const RCTRL = 0b001 << 3;
+ /// The "alt" key.
+ const ALT = 0b100 << 6;
+ // const LALT = 0b010 << 6;
+ // const RALT = 0b001 << 6;
+ /// This is the "windows" key on PC and "command" key on Mac.
+ const SUPER = 0b100 << 9;
+ // const LSUPER = 0b010 << 9;
+ // const RSUPER = 0b001 << 9;
+ }
+}
+
+#[cfg(feature = "serde")]
+mod modifiers_serde {
+ use super::ModifiersState;
+ use serde::{Deserialize, Deserializer, Serialize, Serializer};
+
+ #[derive(Default, Serialize, Deserialize)]
+ #[serde(default)]
+ #[serde(rename = "ModifiersState")]
+ pub struct ModifiersStateSerialize {
+ pub shift_key: bool,
+ pub control_key: bool,
+ pub alt_key: bool,
+ pub super_key: bool,
+ }
+
+ impl Serialize for ModifiersState {
+ fn serialize
(&self, serializer: S) -> Result
+ where
+ S: Serializer,
+ {
+ let s = ModifiersStateSerialize {
+ shift_key: self.shift_key(),
+ control_key: self.control_key(),
+ alt_key: self.alt_key(),
+ super_key: self.super_key(),
+ };
+ s.serialize(serializer)
+ }
+ }
+
+ impl<'de> Deserialize<'de> for ModifiersState {
+ fn deserialize(deserializer: D) -> Result
+ where
+ D: Deserializer<'de>,
+ {
+ let ModifiersStateSerialize {
+ shift_key,
+ control_key,
+ alt_key,
+ super_key,
+ } = ModifiersStateSerialize::deserialize(deserializer)?;
+ let mut m = ModifiersState::empty();
+ m.set(ModifiersState::SHIFT, shift_key);
+ m.set(ModifiersState::CONTROL, control_key);
+ m.set(ModifiersState::ALT, alt_key);
+ m.set(ModifiersState::SUPER, super_key);
+ Ok(m)
+ }
+ }
+}
+
+/// Contains the platform-native physical key identifier (aka scancode)
+#[non_exhaustive]
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+pub enum NativeKeyCode {
+ Unidentified,
+ Windows(u16),
+ MacOS(u16),
+ Gtk(u16),
+
+ /// This is the android "key code" of the event as returned by
+ /// `KeyEvent.getKeyCode()`
+ Android(i32),
+}
+
+/// Represents the code of a physical key.
+///
+/// This mostly conforms to the UI Events Specification's [`KeyboardEvent.code`] with a few
+/// exceptions:
+/// - The keys that the specification calls "MetaLeft" and "MetaRight" are named "SuperLeft" and
+/// "SuperRight" here.
+/// - The key that the specification calls "Super" is reported as `Unidentified` here.
+/// - The `Unidentified` variant here, can still identifiy a key through it's `NativeKeyCode`.
+///
+/// [`KeyboardEvent.code`]: https://w3c.github.io/uievents-code/#code-value-tables
+#[non_exhaustive]
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+pub enum KeyCode {
+ /// This variant is used when the key cannot be translated to any
+ /// other variant.
+ ///
+ /// The native scancode is provided (if available) in order
+ /// to allow the user to specify keybindings for keys which
+ /// are not defined by this API.
+ Unidentified(NativeKeyCode),
+ /// ` on a US keyboard. This is also called a backtick or grave.
+ /// This is the 半角/全角/漢字
+ /// (hankaku/zenkaku/kanji) key on Japanese keyboards
+ Backquote,
+ /// Used for both the US \\ (on the 101-key layout) and also for the key
+ /// located between the " and Enter keys on row C of the 102-,
+ /// 104- and 106-key layouts.
+ /// Labeled # on a UK (102) keyboard.
+ Backslash,
+ /// [ on a US keyboard.
+ BracketLeft,
+ /// ] on a US keyboard.
+ BracketRight,
+ /// , on a US keyboard.
+ Comma,
+ /// 0 on a US keyboard.
+ Digit0,
+ /// 1 on a US keyboard.
+ Digit1,
+ /// 2 on a US keyboard.
+ Digit2,
+ /// 3 on a US keyboard.
+ Digit3,
+ /// 4 on a US keyboard.
+ Digit4,
+ /// 5 on a US keyboard.
+ Digit5,
+ /// 6 on a US keyboard.
+ Digit6,
+ /// 7 on a US keyboard.
+ Digit7,
+ /// 8 on a US keyboard.
+ Digit8,
+ /// 9 on a US keyboard.
+ Digit9,
+ /// = on a US keyboard.
+ Equal,
+ /// Located between the left Shift and Z keys.
+ /// Labeled \\ on a UK keyboard.
+ IntlBackslash,
+ /// Located between the / and right Shift keys.
+ /// Labeled \\ (ro) on a Japanese keyboard.
+ IntlRo,
+ /// Located between the = and Backspace keys.
+ /// Labeled ¥ (yen) on a Japanese keyboard. \\ on a
+ /// Russian keyboard.
+ IntlYen,
+ /// a on a US keyboard.
+ /// Labeled q on an AZERTY (e.g., French) keyboard.
+ KeyA,
+ /// b on a US keyboard.
+ KeyB,
+ /// c on a US keyboard.
+ KeyC,
+ /// d on a US keyboard.
+ KeyD,
+ /// e on a US keyboard.
+ KeyE,
+ /// f on a US keyboard.
+ KeyF,
+ /// g on a US keyboard.
+ KeyG,
+ /// h on a US keyboard.
+ KeyH,
+ /// i on a US keyboard.
+ KeyI,
+ /// j on a US keyboard.
+ KeyJ,
+ /// k on a US keyboard.
+ KeyK,
+ /// l on a US keyboard.
+ KeyL,
+ /// m on a US keyboard.
+ KeyM,
+ /// n on a US keyboard.
+ KeyN,
+ /// o on a US keyboard.
+ KeyO,
+ /// p on a US keyboard.
+ KeyP,
+ /// q on a US keyboard.
+ /// Labeled a on an AZERTY (e.g., French) keyboard.
+ KeyQ,
+ /// r on a US keyboard.
+ KeyR,
+ /// s on a US keyboard.
+ KeyS,
+ /// t on a US keyboard.
+ KeyT,
+ /// u on a US keyboard.
+ KeyU,
+ /// v on a US keyboard.
+ KeyV,
+ /// w on a US keyboard.
+ /// Labeled z on an AZERTY (e.g., French) keyboard.
+ KeyW,
+ /// x on a US keyboard.
+ KeyX,
+ /// y on a US keyboard.
+ /// Labeled z on a QWERTZ (e.g., German) keyboard.
+ KeyY,
+ /// z on a US keyboard.
+ /// Labeled w on an AZERTY (e.g., French) keyboard, and y on a
+ /// QWERTZ (e.g., German) keyboard.
+ KeyZ,
+ /// - on a US keyboard.
+ Minus,
+ /// Shift+= on a US keyboard.
+ Plus,
+ /// . on a US keyboard.
+ Period,
+ /// ' on a US keyboard.
+ Quote,
+ /// ; on a US keyboard.
+ Semicolon,
+ /// / on a US keyboard.
+ Slash,
+ /// Alt, Option, or ⌥.
+ AltLeft,
+ /// Alt, Option, or ⌥.
+ /// This is labeled AltGr on many keyboard layouts.
+ AltRight,
+ /// Backspace or ⌫.
+ /// Labeled Delete on Apple keyboards.
+ Backspace,
+ /// CapsLock or ⇪
+ CapsLock,
+ /// The application context menu key, which is typically found between the right
+ /// Super key and the right Control key.
+ ContextMenu,
+ /// Control or ⌃
+ ControlLeft,
+ /// Control or ⌃
+ ControlRight,
+ /// Enter or ↵. Labeled Return on Apple keyboards.
+ Enter,
+ /// The Windows, ⌘, Command, or other OS symbol key.
+ SuperLeft,
+ /// The Windows, ⌘, Command, or other OS symbol key.
+ SuperRight,
+ /// Shift or ⇧
+ ShiftLeft,
+ /// Shift or ⇧
+ ShiftRight,
+ /// (space)
+ Space,
+ /// Tab or ⇥
+ Tab,
+ /// Japanese: 変 (henkan)
+ Convert,
+ /// Japanese: カタカナ/ひらがな/ローマ字 (katakana/hiragana/romaji)
+ KanaMode,
+ /// Korean: HangulMode 한/영 (han/yeong)
+ ///
+ /// Japanese (Mac keyboard): か (kana)
+ Lang1,
+ /// Korean: Hanja 한 (hanja)
+ ///
+ /// Japanese (Mac keyboard): 英 (eisu)
+ Lang2,
+ /// Japanese (word-processing keyboard): Katakana
+ Lang3,
+ /// Japanese (word-processing keyboard): Hiragana
+ Lang4,
+ /// Japanese (word-processing keyboard): Zenkaku/Hankaku
+ Lang5,
+ /// Japanese: 無変換 (muhenkan)
+ NonConvert,
+ /// ⌦. The forward delete key.
+ /// Note that on Apple keyboards, the key labelled Delete on the main part of
+ /// the keyboard is encoded as [`Backspace`].
+ ///
+ /// [`Backspace`]: Self::Backspace
+ Delete,
+ /// Page Down, End, or ↘
+ End,
+ /// Help. Not present on standard PC keyboards.
+ Help,
+ /// Home or ↖
+ Home,
+ /// Insert or Ins. Not present on Apple keyboards.
+ Insert,
+ /// Page Down, PgDn, or ⇟
+ PageDown,
+ /// Page Up, PgUp, or ⇞
+ PageUp,
+ /// ↓
+ ArrowDown,
+ /// ←
+ ArrowLeft,
+ /// →
+ ArrowRight,
+ /// ↑
+ ArrowUp,
+ /// On the Mac, this is used for the numpad Clear key.
+ NumLock,
+ /// 0 Ins on a keyboard. 0 on a phone or remote control
+ Numpad0,
+ /// 1 End on a keyboard. 1 or 1 QZ on a phone or remote control
+ Numpad1,
+ /// 2 ↓ on a keyboard. 2 ABC on a phone or remote control
+ Numpad2,
+ /// 3 PgDn on a keyboard. 3 DEF on a phone or remote control
+ Numpad3,
+ /// 4 ← on a keyboard. 4 GHI on a phone or remote control
+ Numpad4,
+ /// 5 on a keyboard. 5 JKL on a phone or remote control
+ Numpad5,
+ /// 6 → on a keyboard. 6 MNO on a phone or remote control
+ Numpad6,
+ /// 7 Home on a keyboard. 7 PQRS or 7 PRS on a phone
+ /// or remote control
+ Numpad7,
+ /// 8 ↑ on a keyboard. 8 TUV on a phone or remote control
+ Numpad8,
+ /// 9 PgUp on a keyboard. 9 WXYZ or 9 WXY on a phone
+ /// or remote control
+ Numpad9,
+ /// +
+ NumpadAdd,
+ /// Found on the Microsoft Natural Keyboard.
+ NumpadBackspace,
+ /// C or A (All Clear). Also for use with numpads that have a
+ /// Clear key that is separate from the NumLock key. On the Mac, the
+ /// numpad Clear key is encoded as [`NumLock`].
+ ///
+ /// [`NumLock`]: Self::NumLock
+ NumpadClear,
+ /// C (Clear Entry)
+ NumpadClearEntry,
+ /// , (thousands separator). For locales where the thousands separator
+ /// is a "." (e.g., Brazil), this key may generate a ..
+ NumpadComma,
+ /// . Del. For locales where the decimal separator is "," (e.g.,
+ /// Brazil), this key may generate a ,.
+ NumpadDecimal,
+ /// /
+ NumpadDivide,
+ NumpadEnter,
+ /// =
+ NumpadEqual,
+ /// # on a phone or remote control device. This key is typically found
+ /// below the 9 key and to the right of the 0 key.
+ NumpadHash,
+ /// M Add current entry to the value stored in memory.
+ NumpadMemoryAdd,
+ /// M Clear the value stored in memory.
+ NumpadMemoryClear,
+ /// M Replace the current entry with the value stored in memory.
+ NumpadMemoryRecall,
+ /// M Replace the value stored in memory with the current entry.
+ NumpadMemoryStore,
+ /// M Subtract current entry from the value stored in memory.
+ NumpadMemorySubtract,
+ /// * on a keyboard. For use with numpads that provide mathematical
+ /// operations (+, - * and /).
+ ///
+ /// Use `NumpadStar` for the * key on phones and remote controls.
+ NumpadMultiply,
+ /// ( Found on the Microsoft Natural Keyboard.
+ NumpadParenLeft,
+ /// ) Found on the Microsoft Natural Keyboard.
+ NumpadParenRight,
+ /// * on a phone or remote control device.
+ ///
+ /// This key is typically found below the 7 key and to the left of
+ /// the 0 key.
+ ///
+ /// Use "NumpadMultiply" for the * key on
+ /// numeric keypads.
+ NumpadStar,
+ /// -
+ NumpadSubtract,
+ /// Esc or ⎋
+ Escape,
+ /// Fn This is typically a hardware key that does not generate a separate code.
+ Fn,
+ /// FLock or FnLock. Function Lock key. Found on the Microsoft
+ /// Natural Keyboard.
+ FnLock,
+ /// PrtScr SysRq or Print Screen
+ PrintScreen,
+ /// Scroll Lock
+ ScrollLock,
+ /// Pause Break
+ Pause,
+ /// Some laptops place this key to the left of the ↑ key.
+ ///
+ /// This also the "back" button (triangle) on Android.
+ BrowserBack,
+ BrowserFavorites,
+ /// Some laptops place this key to the right of the ↑ key.
+ BrowserForward,
+ /// The "home" button on Android.
+ BrowserHome,
+ BrowserRefresh,
+ BrowserSearch,
+ BrowserStop,
+ /// Eject or ⏏. This key is placed in the function section on some Apple
+ /// keyboards.
+ Eject,
+ /// Sometimes labelled My Computer on the keyboard
+ LaunchApp1,
+ /// Sometimes labelled Calculator on the keyboard
+ LaunchApp2,
+ LaunchMail,
+ MediaPlayPause,
+ MediaSelect,
+ MediaStop,
+ MediaTrackNext,
+ MediaTrackPrevious,
+ /// This key is placed in the function section on some Apple keyboards, replacing the
+ /// Eject key.
+ Power,
+ Sleep,
+ AudioVolumeDown,
+ AudioVolumeMute,
+ AudioVolumeUp,
+ WakeUp,
+ Hyper,
+ Turbo,
+ Abort,
+ Resume,
+ Suspend,
+ /// Found on Sun’s USB keyboard.
+ Again,
+ /// Found on Sun’s USB keyboard.
+ Copy,
+ /// Found on Sun’s USB keyboard.
+ Cut,
+ /// Found on Sun’s USB keyboard.
+ Find,
+ /// Found on Sun’s USB keyboard.
+ Open,
+ /// Found on Sun’s USB keyboard.
+ Paste,
+ /// Found on Sun’s USB keyboard.
+ Props,
+ /// Found on Sun’s USB keyboard.
+ Select,
+ /// Found on Sun’s USB keyboard.
+ Undo,
+ /// Use for dedicated ひらがな key found on some Japanese word processing keyboards.
+ Hiragana,
+ /// Use for dedicated カタカナ key found on some Japanese word processing keyboards.
+ Katakana,
+ /// General-purpose function key.
+ /// Usually found at the top of the keyboard.
+ F1,
+ /// General-purpose function key.
+ /// Usually found at the top of the keyboard.
+ F2,
+ /// General-purpose function key.
+ /// Usually found at the top of the keyboard.
+ F3,
+ /// General-purpose function key.
+ /// Usually found at the top of the keyboard.
+ F4,
+ /// General-purpose function key.
+ /// Usually found at the top of the keyboard.
+ F5,
+ /// General-purpose function key.
+ /// Usually found at the top of the keyboard.
+ F6,
+ /// General-purpose function key.
+ /// Usually found at the top of the keyboard.
+ F7,
+ /// General-purpose function key.
+ /// Usually found at the top of the keyboard.
+ F8,
+ /// General-purpose function key.
+ /// Usually found at the top of the keyboard.
+ F9,
+ /// General-purpose function key.
+ /// Usually found at the top of the keyboard.
+ F10,
+ /// General-purpose function key.
+ /// Usually found at the top of the keyboard.
+ F11,
+ /// General-purpose function key.
+ /// Usually found at the top of the keyboard.
+ F12,
+ /// General-purpose function key.
+ /// Usually found at the top of the keyboard.
+ F13,
+ /// General-purpose function key.
+ /// Usually found at the top of the keyboard.
+ F14,
+ /// General-purpose function key.
+ /// Usually found at the top of the keyboard.
+ F15,
+ /// General-purpose function key.
+ /// Usually found at the top of the keyboard.
+ F16,
+ /// General-purpose function key.
+ /// Usually found at the top of the keyboard.
+ F17,
+ /// General-purpose function key.
+ /// Usually found at the top of the keyboard.
+ F18,
+ /// General-purpose function key.
+ /// Usually found at the top of the keyboard.
+ F19,
+ /// General-purpose function key.
+ /// Usually found at the top of the keyboard.
+ F20,
+ /// General-purpose function key.
+ /// Usually found at the top of the keyboard.
+ F21,
+ /// General-purpose function key.
+ /// Usually found at the top of the keyboard.
+ F22,
+ /// General-purpose function key.
+ /// Usually found at the top of the keyboard.
+ F23,
+ /// General-purpose function key.
+ /// Usually found at the top of the keyboard.
+ F24,
+ /// General-purpose function key.
+ F25,
+ /// General-purpose function key.
+ F26,
+ /// General-purpose function key.
+ F27,
+ /// General-purpose function key.
+ F28,
+ /// General-purpose function key.
+ F29,
+ /// General-purpose function key.
+ F30,
+ /// General-purpose function key.
+ F31,
+ /// General-purpose function key.
+ F32,
+ /// General-purpose function key.
+ F33,
+ /// General-purpose function key.
+ F34,
+ /// General-purpose function key.
+ F35,
+}
+
+impl KeyCode {
+ /// Return platform specific scancode.
+ pub fn to_scancode(self) -> Option {
+ platform_keycode_to_scancode(self)
+ }
+ /// Return `KeyCode` from platform scancode.
+ pub fn from_scancode(scancode: u32) -> KeyCode {
+ platform_keycode_from_scancode(scancode)
+ }
+}
+
+impl FromStr for KeyCode {
+ type Err = OsError;
+ fn from_str(accelerator_string: &str) -> Result {
+ let keycode = match accelerator_string.to_uppercase().as_str() {
+ "`" | "BACKQUOTE" => KeyCode::Backquote,
+ "BACKSLASH" => KeyCode::Backslash,
+ "[" | "BRACKETLEFT" => KeyCode::BracketLeft,
+ "]" | "BRACKETRIGHT" => KeyCode::BracketRight,
+ "," | "COMMA" => KeyCode::Comma,
+ "0" => KeyCode::Digit0,
+ "1" => KeyCode::Digit1,
+ "2" => KeyCode::Digit2,
+ "3" => KeyCode::Digit3,
+ "4" => KeyCode::Digit4,
+ "5" => KeyCode::Digit5,
+ "6" => KeyCode::Digit6,
+ "7" => KeyCode::Digit7,
+ "8" => KeyCode::Digit8,
+ "9" => KeyCode::Digit9,
+ "NUM0" | "NUMPAD0" => KeyCode::Numpad0,
+ "NUM1" | "NUMPAD1" => KeyCode::Numpad1,
+ "NUM2" | "NUMPAD2" => KeyCode::Numpad2,
+ "NUM3" | "NUMPAD3" => KeyCode::Numpad3,
+ "NUM4" | "NUMPAD4" => KeyCode::Numpad4,
+ "NUM5" | "NUMPAD5" => KeyCode::Numpad5,
+ "NUM6" | "NUMPAD6" => KeyCode::Numpad6,
+ "NUM7" | "NUMPAD7" => KeyCode::Numpad7,
+ "NUM8" | "NUMPAD8" => KeyCode::Numpad8,
+ "NUM9" | "NUMPAD9" => KeyCode::Numpad9,
+ "=" => KeyCode::Equal,
+ "-" => KeyCode::Minus,
+ "PLUS" => KeyCode::Plus,
+ "." | "PERIOD" => KeyCode::Period,
+ "'" | "QUOTE" => KeyCode::Quote,
+ "\\" => KeyCode::IntlBackslash,
+ "A" => KeyCode::KeyA,
+ "B" => KeyCode::KeyB,
+ "C" => KeyCode::KeyC,
+ "D" => KeyCode::KeyD,
+ "E" => KeyCode::KeyE,
+ "F" => KeyCode::KeyF,
+ "G" => KeyCode::KeyG,
+ "H" => KeyCode::KeyH,
+ "I" => KeyCode::KeyI,
+ "J" => KeyCode::KeyJ,
+ "K" => KeyCode::KeyK,
+ "L" => KeyCode::KeyL,
+ "M" => KeyCode::KeyM,
+ "N" => KeyCode::KeyN,
+ "O" => KeyCode::KeyO,
+ "P" => KeyCode::KeyP,
+ "Q" => KeyCode::KeyQ,
+ "R" => KeyCode::KeyR,
+ "S" => KeyCode::KeyS,
+ "T" => KeyCode::KeyT,
+ "U" => KeyCode::KeyU,
+ "V" => KeyCode::KeyV,
+ "W" => KeyCode::KeyW,
+ "X" => KeyCode::KeyX,
+ "Y" => KeyCode::KeyY,
+ "Z" => KeyCode::KeyZ,
+
+ ";" | "SEMICOLON" => KeyCode::Semicolon,
+ "/" | "SLASH" => KeyCode::Slash,
+ "BACKSPACE" => KeyCode::Backspace,
+ "CAPSLOCK" => KeyCode::CapsLock,
+ "CONTEXTMENU" => KeyCode::ContextMenu,
+ "ENTER" => KeyCode::Enter,
+ "SPACE" => KeyCode::Space,
+ "TAB" => KeyCode::Tab,
+ "CONVERT" => KeyCode::Convert,
+
+ "DELETE" => KeyCode::Delete,
+ "END" => KeyCode::End,
+ "HELP" => KeyCode::Help,
+ "HOME" => KeyCode::Home,
+ "PAGEDOWN" => KeyCode::PageDown,
+ "PAGEUP" => KeyCode::PageUp,
+
+ "DOWN" | "ARROWDOWN" => KeyCode::ArrowDown,
+ "UP" | "ARROWUP" => KeyCode::ArrowUp,
+ "LEFT" | "ARROWLEFT" => KeyCode::ArrowLeft,
+ "RIGHT" | "ARROWRIGHT" => KeyCode::ArrowRight,
+
+ "NUMLOCK" => KeyCode::NumLock,
+ "NUMADD" | "NUMPADADD" => KeyCode::NumpadAdd,
+ "NUMBACKSPACE" | "NUMPADBACKSPACE" => KeyCode::NumpadBackspace,
+ "NUMCLEAR" | "NUMPADCLEAR" => KeyCode::NumpadClear,
+ "NUMCOMMA" | "NUMPADCOMMA" => KeyCode::NumpadComma,
+ "NUMDIVIDE" | "NUMPADDIVIDE" => KeyCode::NumpadDivide,
+ "NUMSUBSTRACT" | "NUMPADSUBSTRACT" => KeyCode::NumpadSubtract,
+ "NUMENTER" | "NUMPADENTER" => KeyCode::NumpadEnter,
+
+ "ESC" | "ESCAPE" => KeyCode::Escape,
+ "FN" => KeyCode::Fn,
+ "FNLOCK" => KeyCode::FnLock,
+ "PRINTSCREEN" => KeyCode::PrintScreen,
+ "SCROLLLOCK" => KeyCode::ScrollLock,
+
+ "PAUSE" => KeyCode::Pause,
+
+ "VOLUMEMUTE" => KeyCode::AudioVolumeMute,
+ "VOLUMEDOWN" => KeyCode::AudioVolumeDown,
+ "VOLUMEUP" => KeyCode::AudioVolumeUp,
+ "MEDIANEXTTRACK" => KeyCode::MediaTrackNext,
+ "MEDIAPREVIOUSTRACK" => KeyCode::MediaTrackPrevious,
+ "MEDIAPLAYPAUSE" => KeyCode::MediaPlayPause,
+ "LAUNCHMAIL" => KeyCode::LaunchMail,
+
+ "SUSPEND" => KeyCode::Suspend,
+ "F1" => KeyCode::F1,
+ "F2" => KeyCode::F2,
+ "F3" => KeyCode::F3,
+ "F4" => KeyCode::F4,
+ "F5" => KeyCode::F5,
+ "F6" => KeyCode::F6,
+ "F7" => KeyCode::F7,
+ "F8" => KeyCode::F8,
+ "F9" => KeyCode::F9,
+ "F10" => KeyCode::F10,
+ "F11" => KeyCode::F11,
+ "F12" => KeyCode::F12,
+ "F13" => KeyCode::F13,
+ "F14" => KeyCode::F14,
+ "F15" => KeyCode::F15,
+ "F16" => KeyCode::F16,
+ "F17" => KeyCode::F17,
+ "F18" => KeyCode::F18,
+ "F19" => KeyCode::F19,
+ "F20" => KeyCode::F20,
+ "F21" => KeyCode::F21,
+ "F22" => KeyCode::F22,
+ "F23" => KeyCode::F23,
+ "F24" => KeyCode::F24,
+ "F25" => KeyCode::F25,
+ "F26" => KeyCode::F26,
+ "F27" => KeyCode::F27,
+ "F28" => KeyCode::F28,
+ "F29" => KeyCode::F29,
+ "F30" => KeyCode::F30,
+ "F31" => KeyCode::F31,
+ "F32" => KeyCode::F32,
+ "F33" => KeyCode::F33,
+ "F34" => KeyCode::F34,
+ "F35" => KeyCode::F35,
+ _ => KeyCode::Unidentified(NativeKeyCode::Unidentified),
+ };
+
+ Ok(keycode)
+ }
+}
+
+impl fmt::Display for KeyCode {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ match self {
+ &KeyCode::Unidentified(_) => write!(f, "{:?}", "Unidentified"),
+ val => write!(f, "{val:?}"),
+ }
+ }
+}
+
+/// Key represents the meaning of a keypress.
+///
+/// This mostly conforms to the UI Events Specification's [`KeyboardEvent.key`] with a few
+/// exceptions:
+/// - The `Super` variant here, is named `Meta` in the aforementioned specification. (There's
+/// another key which the specification calls `Super`. That does not exist here.)
+/// - The `Space` variant here, can be identified by the character it generates in the
+/// specificaiton.
+/// - The `Unidentified` variant here, can still identifiy a key through it's `NativeKeyCode`.
+/// - The `Dead` variant here, can specify the character which is inserted when pressing the
+/// dead-key twice.
+///
+/// [`KeyboardEvent.key`]: https://w3c.github.io/uievents-key/
+#[non_exhaustive]
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+pub enum Key<'a> {
+ /// A key string that corresponds to the character typed by the user, taking into account the
+ /// user’s current locale setting, and any system-level keyboard mapping overrides that are in
+ /// effect.
+ Character(&'a str),
+
+ /// This variant is used when the key cannot be translated to any other variant.
+ ///
+ /// The native scancode is provided (if available) in order to allow the user to specify
+ /// keybindings for keys which are not defined by this API.
+ Unidentified(NativeKeyCode),
+
+ /// Contains the text representation of the dead-key when available.
+ ///
+ /// ## Platform-specific
+ /// - **Web:** Always contains `None`
+ Dead(Option),
+
+ /// The `Alt` (Alternative) key.
+ ///
+ /// This key enables the alternate modifier function for interpreting concurrent or subsequent
+ /// keyboard input. This key value is also used for the Apple Option key.
+ Alt,
+ /// The Alternate Graphics (AltGr or AltGraph) key.
+ ///
+ /// This key is used enable the ISO Level 3 shift modifier (the standard `Shift` key is the
+ /// level 2 modifier).
+ AltGraph,
+ /// The `Caps Lock` (Capital) key.
+ ///
+ /// Toggle capital character lock function for interpreting subsequent keyboard input event.
+ CapsLock,
+ /// The `Control` or `Ctrl` key.
+ ///
+ /// Used to enable control modifier function for interpreting concurrent or subsequent keyboard
+ /// input.
+ Control,
+ /// The Function switch `Fn` key. Activating this key simultaneously with another key changes
+ /// that key’s value to an alternate character or function. This key is often handled directly
+ /// in the keyboard hardware and does not usually generate key events.
+ Fn,
+ /// The Function-Lock (`FnLock` or `F-Lock`) key. Activating this key switches the mode of the
+ /// keyboard to changes some keys' values to an alternate character or function. This key is
+ /// often handled directly in the keyboard hardware and does not usually generate key events.
+ FnLock,
+ /// The `NumLock` or Number Lock key. Used to toggle numpad mode function for interpreting
+ /// subsequent keyboard input.
+ NumLock,
+ /// Toggle between scrolling and cursor movement modes.
+ ScrollLock,
+ /// Used to enable shift modifier function for interpreting concurrent or subsequent keyboard
+ /// input.
+ Shift,
+ /// The Symbol modifier key (used on some virtual keyboards).
+ Symbol,
+ SymbolLock,
+ Hyper,
+ /// Used to enable "super" modifier function for interpreting concurrent or subsequent keyboard
+ /// input. This key value is used for the "Windows Logo" key and the Apple `Command` or `⌘` key.
+ ///
+ /// Note: In some contexts (e.g. the Web) this is referred to as the "Meta" key.
+ Super,
+ /// The `Enter` or `↵` key. Used to activate current selection or accept current input. This key
+ /// value is also used for the `Return` (Macintosh numpad) key. This key value is also used for
+ /// the Android `KEYCODE_DPAD_CENTER`.
+ Enter,
+ /// The Horizontal Tabulation `Tab` key.
+ Tab,
+ /// Used in text to insert a space between words. Usually located below the character keys.
+ Space,
+ /// Navigate or traverse downward. (`KEYCODE_DPAD_DOWN`)
+ ArrowDown,
+ /// Navigate or traverse leftward. (`KEYCODE_DPAD_LEFT`)
+ ArrowLeft,
+ /// Navigate or traverse rightward. (`KEYCODE_DPAD_RIGHT`)
+ ArrowRight,
+ /// Navigate or traverse upward. (`KEYCODE_DPAD_UP`)
+ ArrowUp,
+ /// The End key, used with keyboard entry to go to the end of content (`KEYCODE_MOVE_END`).
+ End,
+ /// The Home key, used with keyboard entry, to go to start of content (`KEYCODE_MOVE_HOME`).
+ /// For the mobile phone `Home` key (which goes to the phone’s main screen), use [`GoHome`].
+ ///
+ /// [`GoHome`]: Self::GoHome
+ Home,
+ /// Scroll down or display next page of content.
+ PageDown,
+ /// Scroll up or display previous page of content.
+ PageUp,
+ /// Used to remove the character to the left of the cursor. This key value is also used for
+ /// the key labeled `Delete` on MacOS keyboards.
+ Backspace,
+ /// Remove the currently selected input.
+ Clear,
+ /// Copy the current selection. (`APPCOMMAND_COPY`)
+ Copy,
+ /// The Cursor Select key.
+ CrSel,
+ /// Cut the current selection. (`APPCOMMAND_CUT`)
+ Cut,
+ /// Used to delete the character to the right of the cursor. This key value is also used for the
+ /// key labeled `Delete` on MacOS keyboards when `Fn` is active.
+ Delete,
+ /// The Erase to End of Field key. This key deletes all characters from the current cursor
+ /// position to the end of the current field.
+ EraseEof,
+ /// The Extend Selection (Exsel) key.
+ ExSel,
+ /// Toggle between text modes for insertion or overtyping.
+ /// (`KEYCODE_INSERT`)
+ Insert,
+ /// The Paste key. (`APPCOMMAND_PASTE`)
+ Paste,
+ /// Redo the last action. (`APPCOMMAND_REDO`)
+ Redo,
+ /// Undo the last action. (`APPCOMMAND_UNDO`)
+ Undo,
+ /// The Accept (Commit, OK) key. Accept current option or input method sequence conversion.
+ Accept,
+ /// Redo or repeat an action.
+ Again,
+ /// The Attention (Attn) key.
+ Attn,
+ Cancel,
+ /// Show the application’s context menu.
+ /// This key is commonly found between the right `Super` key and the right `Control` key.
+ ContextMenu,
+ /// The `Esc` key. This key was originally used to initiate an escape sequence, but is
+ /// now more generally used to exit or "escape" the current context, such as closing a dialog
+ /// or exiting full screen mode.
+ Escape,
+ Execute,
+ /// Open the Find dialog. (`APPCOMMAND_FIND`)
+ Find,
+ /// Open a help dialog or toggle display of help information. (`APPCOMMAND_HELP`,
+ /// `KEYCODE_HELP`)
+ Help,
+ /// Pause the current state or application (as appropriate).
+ ///
+ /// Note: Do not use this value for the `Pause` button on media controllers. Use `"MediaPause"`
+ /// instead.
+ Pause,
+ /// Play or resume the current state or application (as appropriate).
+ ///
+ /// Note: Do not use this value for the `Play` button on media controllers. Use `"MediaPlay"`
+ /// instead.
+ Play,
+ /// The properties (Props) key.
+ Props,
+ Select,
+ /// The ZoomIn key. (`KEYCODE_ZOOM_IN`)
+ ZoomIn,
+ /// The ZoomOut key. (`KEYCODE_ZOOM_OUT`)
+ ZoomOut,
+ /// The Brightness Down key. Typically controls the display brightness.
+ /// (`KEYCODE_BRIGHTNESS_DOWN`)
+ BrightnessDown,
+ /// The Brightness Up key. Typically controls the display brightness. (`KEYCODE_BRIGHTNESS_UP`)
+ BrightnessUp,
+ /// Toggle removable media to eject (open) and insert (close) state. (`KEYCODE_MEDIA_EJECT`)
+ Eject,
+ LogOff,
+ /// Toggle power state. (`KEYCODE_POWER`)
+ /// Note: Note: Some devices might not expose this key to the operating environment.
+ Power,
+ /// The `PowerOff` key. Sometime called `PowerDown`.
+ PowerOff,
+ /// Initiate print-screen function.
+ PrintScreen,
+ /// The Hibernate key. This key saves the current state of the computer to disk so that it can
+ /// be restored. The computer will then shutdown.
+ Hibernate,
+ /// The Standby key. This key turns off the display and places the computer into a low-power
+ /// mode without completely shutting down. It is sometimes labelled `Suspend` or `Sleep` key.
+ /// (`KEYCODE_SLEEP`)
+ Standby,
+ /// The WakeUp key. (`KEYCODE_WAKEUP`)
+ WakeUp,
+ /// Initate the multi-candidate mode.
+ AllCandidates,
+ Alphanumeric,
+ /// Initiate the Code Input mode to allow characters to be entered by
+ /// their code points.
+ CodeInput,
+ /// The Compose key, also known as "Multi_key" on the X Window System. This key acts in a
+ /// manner similar to a dead key, triggering a mode where subsequent key presses are combined to
+ /// produce a different character.
+ Compose,
+ /// Convert the current input method sequence.
+ Convert,
+ /// The Final Mode `Final` key used on some Asian keyboards, to enable the final mode for IMEs.
+ FinalMode,
+ /// Switch to the first character group. (ISO/IEC 9995)
+ GroupFirst,
+ /// Switch to the last character group. (ISO/IEC 9995)
+ GroupLast,
+ /// Switch to the next character group. (ISO/IEC 9995)
+ GroupNext,
+ /// Switch to the previous character group. (ISO/IEC 9995)
+ GroupPrevious,
+ /// Toggle between or cycle through input modes of IMEs.
+ ModeChange,
+ NextCandidate,
+ /// Accept current input method sequence without
+ /// conversion in IMEs.
+ NonConvert,
+ PreviousCandidate,
+ Process,
+ SingleCandidate,
+ /// Toggle between Hangul and English modes.
+ HangulMode,
+ HanjaMode,
+ JunjaMode,
+ /// The Eisu key. This key may close the IME, but its purpose is defined by the current IME.
+ /// (`KEYCODE_EISU`)
+ Eisu,
+ /// The (Half-Width) Characters key.
+ Hankaku,
+ /// The Hiragana (Japanese Kana characters) key.
+ Hiragana,
+ /// The Hiragana/Katakana toggle key. (`KEYCODE_KATAKANA_HIRAGANA`)
+ HiraganaKatakana,
+ /// The Kana Mode (Kana Lock) key. This key is used to enter hiragana mode (typically from
+ /// romaji mode).
+ KanaMode,
+ /// The Kanji (Japanese name for ideographic characters of Chinese origin) Mode key. This key is
+ /// typically used to switch to a hiragana keyboard for the purpose of converting input into
+ /// kanji. (`KEYCODE_KANA`)
+ KanjiMode,
+ /// The Katakana (Japanese Kana characters) key.
+ Katakana,
+ /// The Roman characters function key.
+ Romaji,
+ /// The Zenkaku (Full-Width) Characters key.
+ Zenkaku,
+ /// The Zenkaku/Hankaku (full-width/half-width) toggle key. (`KEYCODE_ZENKAKU_HANKAKU`)
+ ZenkakuHankaku,
+ /// General purpose virtual function key, as index 1.
+ Soft1,
+ /// General purpose virtual function key, as index 2.
+ Soft2,
+ /// General purpose virtual function key, as index 3.
+ Soft3,
+ /// General purpose virtual function key, as index 4.
+ Soft4,
+ /// Select next (numerically or logically) lower channel. (`APPCOMMAND_MEDIA_CHANNEL_DOWN`,
+ /// `KEYCODE_CHANNEL_DOWN`)
+ ChannelDown,
+ /// Select next (numerically or logically) higher channel. (`APPCOMMAND_MEDIA_CHANNEL_UP`,
+ /// `KEYCODE_CHANNEL_UP`)
+ ChannelUp,
+ /// Close the current document or message (Note: This doesn’t close the application).
+ /// (`APPCOMMAND_CLOSE`)
+ Close,
+ /// Open an editor to forward the current message. (`APPCOMMAND_FORWARD_MAIL`)
+ MailForward,
+ /// Open an editor to reply to the current message. (`APPCOMMAND_REPLY_TO_MAIL`)
+ MailReply,
+ /// Send the current message. (`APPCOMMAND_SEND_MAIL`)
+ MailSend,
+ /// Close the current media, for example to close a CD or DVD tray. (`KEYCODE_MEDIA_CLOSE`)
+ MediaClose,
+ /// Initiate or continue forward playback at faster than normal speed, or increase speed if
+ /// already fast forwarding. (`APPCOMMAND_MEDIA_FAST_FORWARD`, `KEYCODE_MEDIA_FAST_FORWARD`)
+ MediaFastForward,
+ /// Pause the currently playing media. (`APPCOMMAND_MEDIA_PAUSE`, `KEYCODE_MEDIA_PAUSE`)
+ ///
+ /// Note: Media controller devices should use this value rather than `"Pause"` for their pause
+ /// keys.
+ MediaPause,
+ /// Initiate or continue media playback at normal speed, if not currently playing at normal
+ /// speed. (`APPCOMMAND_MEDIA_PLAY`, `KEYCODE_MEDIA_PLAY`)
+ MediaPlay,
+ /// Toggle media between play and pause states. (`APPCOMMAND_MEDIA_PLAY_PAUSE`,
+ /// `KEYCODE_MEDIA_PLAY_PAUSE`)
+ MediaPlayPause,
+ /// Initiate or resume recording of currently selected media. (`APPCOMMAND_MEDIA_RECORD`,
+ /// `KEYCODE_MEDIA_RECORD`)
+ MediaRecord,
+ /// Initiate or continue reverse playback at faster than normal speed, or increase speed if
+ /// already rewinding. (`APPCOMMAND_MEDIA_REWIND`, `KEYCODE_MEDIA_REWIND`)
+ MediaRewind,
+ /// Stop media playing, pausing, forwarding, rewinding, or recording, if not already stopped.
+ /// (`APPCOMMAND_MEDIA_STOP`, `KEYCODE_MEDIA_STOP`)
+ MediaStop,
+ /// Seek to next media or program track. (`APPCOMMAND_MEDIA_NEXTTRACK`, `KEYCODE_MEDIA_NEXT`)
+ MediaTrackNext,
+ /// Seek to previous media or program track. (`APPCOMMAND_MEDIA_PREVIOUSTRACK`,
+ /// `KEYCODE_MEDIA_PREVIOUS`)
+ MediaTrackPrevious,
+ /// Open a new document or message. (`APPCOMMAND_NEW`)
+ New,
+ /// Open an existing document or message. (`APPCOMMAND_OPEN`)
+ Open,
+ /// Print the current document or message. (`APPCOMMAND_PRINT`)
+ Print,
+ /// Save the current document or message. (`APPCOMMAND_SAVE`)
+ Save,
+ /// Spellcheck the current document or selection. (`APPCOMMAND_SPELL_CHECK`)
+ SpellCheck,
+ /// The `11` key found on media numpads that
+ /// have buttons from `1` ... `12`.
+ Key11,
+ /// The `12` key found on media numpads that
+ /// have buttons from `1` ... `12`.
+ Key12,
+ /// Adjust audio balance leftward. (`VK_AUDIO_BALANCE_LEFT`)
+ AudioBalanceLeft,
+ /// Adjust audio balance rightward. (`VK_AUDIO_BALANCE_RIGHT`)
+ AudioBalanceRight,
+ /// Decrease audio bass boost or cycle down through bass boost states. (`APPCOMMAND_BASS_DOWN`,
+ /// `VK_BASS_BOOST_DOWN`)
+ AudioBassBoostDown,
+ /// Toggle bass boost on/off. (`APPCOMMAND_BASS_BOOST`)
+ AudioBassBoostToggle,
+ /// Increase audio bass boost or cycle up through bass boost states. (`APPCOMMAND_BASS_UP`,
+ /// `VK_BASS_BOOST_UP`)
+ AudioBassBoostUp,
+ /// Adjust audio fader towards front. (`VK_FADER_FRONT`)
+ AudioFaderFront,
+ /// Adjust audio fader towards rear. (`VK_FADER_REAR`)
+ AudioFaderRear,
+ /// Advance surround audio mode to next available mode. (`VK_SURROUND_MODE_NEXT`)
+ AudioSurroundModeNext,
+ /// Decrease treble. (`APPCOMMAND_TREBLE_DOWN`)
+ AudioTrebleDown,
+ /// Increase treble. (`APPCOMMAND_TREBLE_UP`)
+ AudioTrebleUp,
+ /// Decrease audio volume. (`APPCOMMAND_VOLUME_DOWN`, `KEYCODE_VOLUME_DOWN`)
+ AudioVolumeDown,
+ /// Increase audio volume. (`APPCOMMAND_VOLUME_UP`, `KEYCODE_VOLUME_UP`)
+ AudioVolumeUp,
+ /// Toggle between muted state and prior volume level. (`APPCOMMAND_VOLUME_MUTE`,
+ /// `KEYCODE_VOLUME_MUTE`)
+ AudioVolumeMute,
+ /// Toggle the microphone on/off. (`APPCOMMAND_MIC_ON_OFF_TOGGLE`)
+ MicrophoneToggle,
+ /// Decrease microphone volume. (`APPCOMMAND_MICROPHONE_VOLUME_DOWN`)
+ MicrophoneVolumeDown,
+ /// Increase microphone volume. (`APPCOMMAND_MICROPHONE_VOLUME_UP`)
+ MicrophoneVolumeUp,
+ /// Mute the microphone. (`APPCOMMAND_MICROPHONE_VOLUME_MUTE`, `KEYCODE_MUTE`)
+ MicrophoneVolumeMute,
+ /// Show correction list when a word is incorrectly identified. (`APPCOMMAND_CORRECTION_LIST`)
+ SpeechCorrectionList,
+ /// Toggle between dictation mode and command/control mode.
+ /// (`APPCOMMAND_DICTATE_OR_COMMAND_CONTROL_TOGGLE`)
+ SpeechInputToggle,
+ /// The first generic "LaunchApplication" key. This is commonly associated with launching "My
+ /// Computer", and may have a computer symbol on the key. (`APPCOMMAND_LAUNCH_APP1`)
+ LaunchApplication1,
+ /// The second generic "LaunchApplication" key. This is commonly associated with launching
+ /// "Calculator", and may have a calculator symbol on the key. (`APPCOMMAND_LAUNCH_APP2`,
+ /// `KEYCODE_CALCULATOR`)
+ LaunchApplication2,
+ /// The "Calendar" key. (`KEYCODE_CALENDAR`)
+ LaunchCalendar,
+ /// The "Contacts" key. (`KEYCODE_CONTACTS`)
+ LaunchContacts,
+ /// The "Mail" key. (`APPCOMMAND_LAUNCH_MAIL`)
+ LaunchMail,
+ /// The "Media Player" key. (`APPCOMMAND_LAUNCH_MEDIA_SELECT`)
+ LaunchMediaPlayer,
+ LaunchMusicPlayer,
+ LaunchPhone,
+ LaunchScreenSaver,
+ LaunchSpreadsheet,
+ LaunchWebBrowser,
+ LaunchWebCam,
+ LaunchWordProcessor,
+ /// Navigate to previous content or page in current history. (`APPCOMMAND_BROWSER_BACKWARD`)
+ BrowserBack,
+ /// Open the list of browser favorites. (`APPCOMMAND_BROWSER_FAVORITES`)
+ BrowserFavorites,
+ /// Navigate to next content or page in current history. (`APPCOMMAND_BROWSER_FORWARD`)
+ BrowserForward,
+ /// Go to the user’s preferred home page. (`APPCOMMAND_BROWSER_HOME`)
+ BrowserHome,
+ /// Refresh the current page or content. (`APPCOMMAND_BROWSER_REFRESH`)
+ BrowserRefresh,
+ /// Call up the user’s preferred search page. (`APPCOMMAND_BROWSER_SEARCH`)
+ BrowserSearch,
+ /// Stop loading the current page or content. (`APPCOMMAND_BROWSER_STOP`)
+ BrowserStop,
+ /// The Application switch key, which provides a list of recent apps to switch between.
+ /// (`KEYCODE_APP_SWITCH`)
+ AppSwitch,
+ /// The Call key. (`KEYCODE_CALL`)
+ Call,
+ /// The Camera key. (`KEYCODE_CAMERA`)
+ Camera,
+ /// The Camera focus key. (`KEYCODE_FOCUS`)
+ CameraFocus,
+ /// The End Call key. (`KEYCODE_ENDCALL`)
+ EndCall,
+ /// The Back key. (`KEYCODE_BACK`)
+ GoBack,
+ /// The Home key, which goes to the phone’s main screen. (`KEYCODE_HOME`)
+ GoHome,
+ /// The Headset Hook key. (`KEYCODE_HEADSETHOOK`)
+ HeadsetHook,
+ LastNumberRedial,
+ /// The Notification key. (`KEYCODE_NOTIFICATION`)
+ Notification,
+ /// Toggle between manner mode state: silent, vibrate, ring, ... (`KEYCODE_MANNER_MODE`)
+ MannerMode,
+ VoiceDial,
+ /// Switch to viewing TV. (`KEYCODE_TV`)
+ TV,
+ /// TV 3D Mode. (`KEYCODE_3D_MODE`)
+ TV3DMode,
+ /// Toggle between antenna and cable input. (`KEYCODE_TV_ANTENNA_CABLE`)
+ TVAntennaCable,
+ /// Audio description. (`KEYCODE_TV_AUDIO_DESCRIPTION`)
+ TVAudioDescription,
+ /// Audio description mixing volume down. (`KEYCODE_TV_AUDIO_DESCRIPTION_MIX_DOWN`)
+ TVAudioDescriptionMixDown,
+ /// Audio description mixing volume up. (`KEYCODE_TV_AUDIO_DESCRIPTION_MIX_UP`)
+ TVAudioDescriptionMixUp,
+ /// Contents menu. (`KEYCODE_TV_CONTENTS_MENU`)
+ TVContentsMenu,
+ /// Contents menu. (`KEYCODE_TV_DATA_SERVICE`)
+ TVDataService,
+ /// Switch the input mode on an external TV. (`KEYCODE_TV_INPUT`)
+ TVInput,
+ /// Switch to component input #1. (`KEYCODE_TV_INPUT_COMPONENT_1`)
+ TVInputComponent1,
+ /// Switch to component input #2. (`KEYCODE_TV_INPUT_COMPONENT_2`)
+ TVInputComponent2,
+ /// Switch to composite input #1. (`KEYCODE_TV_INPUT_COMPOSITE_1`)
+ TVInputComposite1,
+ /// Switch to composite input #2. (`KEYCODE_TV_INPUT_COMPOSITE_2`)
+ TVInputComposite2,
+ /// Switch to HDMI input #1. (`KEYCODE_TV_INPUT_HDMI_1`)
+ TVInputHDMI1,
+ /// Switch to HDMI input #2. (`KEYCODE_TV_INPUT_HDMI_2`)
+ TVInputHDMI2,
+ /// Switch to HDMI input #3. (`KEYCODE_TV_INPUT_HDMI_3`)
+ TVInputHDMI3,
+ /// Switch to HDMI input #4. (`KEYCODE_TV_INPUT_HDMI_4`)
+ TVInputHDMI4,
+ /// Switch to VGA input #1. (`KEYCODE_TV_INPUT_VGA_1`)
+ TVInputVGA1,
+ /// Media context menu. (`KEYCODE_TV_MEDIA_CONTEXT_MENU`)
+ TVMediaContext,
+ /// Toggle network. (`KEYCODE_TV_NETWORK`)
+ TVNetwork,
+ /// Number entry. (`KEYCODE_TV_NUMBER_ENTRY`)
+ TVNumberEntry,
+ /// Toggle the power on an external TV. (`KEYCODE_TV_POWER`)
+ TVPower,
+ /// Radio. (`KEYCODE_TV_RADIO_SERVICE`)
+ TVRadioService,
+ /// Satellite. (`KEYCODE_TV_SATELLITE`)
+ TVSatellite,
+ /// Broadcast Satellite. (`KEYCODE_TV_SATELLITE_BS`)
+ TVSatelliteBS,
+ /// Communication Satellite. (`KEYCODE_TV_SATELLITE_CS`)
+ TVSatelliteCS,
+ /// Toggle between available satellites. (`KEYCODE_TV_SATELLITE_SERVICE`)
+ TVSatelliteToggle,
+ /// Analog Terrestrial. (`KEYCODE_TV_TERRESTRIAL_ANALOG`)
+ TVTerrestrialAnalog,
+ /// Digital Terrestrial. (`KEYCODE_TV_TERRESTRIAL_DIGITAL`)
+ TVTerrestrialDigital,
+ /// Timer programming. (`KEYCODE_TV_TIMER_PROGRAMMING`)
+ TVTimer,
+ /// Switch the input mode on an external AVR (audio/video receiver). (`KEYCODE_AVR_INPUT`)
+ AVRInput,
+ /// Toggle the power on an external AVR (audio/video receiver). (`KEYCODE_AVR_POWER`)
+ AVRPower,
+ /// General purpose color-coded media function key, as index 0 (red). (`VK_COLORED_KEY_0`,
+ /// `KEYCODE_PROG_RED`)
+ ColorF0Red,
+ /// General purpose color-coded media function key, as index 1 (green). (`VK_COLORED_KEY_1`,
+ /// `KEYCODE_PROG_GREEN`)
+ ColorF1Green,
+ /// General purpose color-coded media function key, as index 2 (yellow). (`VK_COLORED_KEY_2`,
+ /// `KEYCODE_PROG_YELLOW`)
+ ColorF2Yellow,
+ /// General purpose color-coded media function key, as index 3 (blue). (`VK_COLORED_KEY_3`,
+ /// `KEYCODE_PROG_BLUE`)
+ ColorF3Blue,
+ /// General purpose color-coded media function key, as index 4 (grey). (`VK_COLORED_KEY_4`)
+ ColorF4Grey,
+ /// General purpose color-coded media function key, as index 5 (brown). (`VK_COLORED_KEY_5`)
+ ColorF5Brown,
+ /// Toggle the display of Closed Captions. (`VK_CC`, `KEYCODE_CAPTIONS`)
+ ClosedCaptionToggle,
+ /// Adjust brightness of device, by toggling between or cycling through states. (`VK_DIMMER`)
+ Dimmer,
+ /// Swap video sources. (`VK_DISPLAY_SWAP`)
+ DisplaySwap,
+ /// Select Digital Video Rrecorder. (`KEYCODE_DVR`)
+ DVR,
+ /// Exit the current application. (`VK_EXIT`)
+ Exit,
+ /// Clear program or content stored as favorite 0. (`VK_CLEAR_FAVORITE_0`)
+ FavoriteClear0,
+ /// Clear program or content stored as favorite 1. (`VK_CLEAR_FAVORITE_1`)
+ FavoriteClear1,
+ /// Clear program or content stored as favorite 2. (`VK_CLEAR_FAVORITE_2`)
+ FavoriteClear2,
+ /// Clear program or content stored as favorite 3. (`VK_CLEAR_FAVORITE_3`)
+ FavoriteClear3,
+ /// Select (recall) program or content stored as favorite 0. (`VK_RECALL_FAVORITE_0`)
+ FavoriteRecall0,
+ /// Select (recall) program or content stored as favorite 1. (`VK_RECALL_FAVORITE_1`)
+ FavoriteRecall1,
+ /// Select (recall) program or content stored as favorite 2. (`VK_RECALL_FAVORITE_2`)
+ FavoriteRecall2,
+ /// Select (recall) program or content stored as favorite 3. (`VK_RECALL_FAVORITE_3`)
+ FavoriteRecall3,
+ /// Store current program or content as favorite 0. (`VK_STORE_FAVORITE_0`)
+ FavoriteStore0,
+ /// Store current program or content as favorite 1. (`VK_STORE_FAVORITE_1`)
+ FavoriteStore1,
+ /// Store current program or content as favorite 2. (`VK_STORE_FAVORITE_2`)
+ FavoriteStore2,
+ /// Store current program or content as favorite 3. (`VK_STORE_FAVORITE_3`)
+ FavoriteStore3,
+ /// Toggle display of program or content guide. (`VK_GUIDE`, `KEYCODE_GUIDE`)
+ Guide,
+ /// If guide is active and displayed, then display next day’s content. (`VK_NEXT_DAY`)
+ GuideNextDay,
+ /// If guide is active and displayed, then display previous day’s content. (`VK_PREV_DAY`)
+ GuidePreviousDay,
+ /// Toggle display of information about currently selected context or media. (`VK_INFO`,
+ /// `KEYCODE_INFO`)
+ Info,
+ /// Toggle instant replay. (`VK_INSTANT_REPLAY`)
+ InstantReplay,
+ /// Launch linked content, if available and appropriate. (`VK_LINK`)
+ Link,
+ /// List the current program. (`VK_LIST`)
+ ListProgram,
+ /// Toggle display listing of currently available live content or programs. (`VK_LIVE`)
+ LiveContent,
+ /// Lock or unlock current content or program. (`VK_LOCK`)
+ Lock,
+ /// Show a list of media applications: audio/video players and image viewers. (`VK_APPS`)
+ ///
+ /// Note: Do not confuse this key value with the Windows' `VK_APPS` / `VK_CONTEXT_MENU` key,
+ /// which is encoded as `"ContextMenu"`.
+ MediaApps,
+ /// Audio track key. (`KEYCODE_MEDIA_AUDIO_TRACK`)
+ MediaAudioTrack,
+ /// Select previously selected channel or media. (`VK_LAST`, `KEYCODE_LAST_CHANNEL`)
+ MediaLast,
+ /// Skip backward to next content or program. (`KEYCODE_MEDIA_SKIP_BACKWARD`)
+ MediaSkipBackward,
+ /// Skip forward to next content or program. (`VK_SKIP`, `KEYCODE_MEDIA_SKIP_FORWARD`)
+ MediaSkipForward,
+ /// Step backward to next content or program. (`KEYCODE_MEDIA_STEP_BACKWARD`)
+ MediaStepBackward,
+ /// Step forward to next content or program. (`KEYCODE_MEDIA_STEP_FORWARD`)
+ MediaStepForward,
+ /// Media top menu. (`KEYCODE_MEDIA_TOP_MENU`)
+ MediaTopMenu,
+ /// Navigate in. (`KEYCODE_NAVIGATE_IN`)
+ NavigateIn,
+ /// Navigate to next key. (`KEYCODE_NAVIGATE_NEXT`)
+ NavigateNext,
+ /// Navigate out. (`KEYCODE_NAVIGATE_OUT`)
+ NavigateOut,
+ /// Navigate to previous key. (`KEYCODE_NAVIGATE_PREVIOUS`)
+ NavigatePrevious,
+ /// Cycle to next favorite channel (in favorites list). (`VK_NEXT_FAVORITE_CHANNEL`)
+ NextFavoriteChannel,
+ /// Cycle to next user profile (if there are multiple user profiles). (`VK_USER`)
+ NextUserProfile,
+ /// Access on-demand content or programs. (`VK_ON_DEMAND`)
+ OnDemand,
+ /// Pairing key to pair devices. (`KEYCODE_PAIRING`)
+ Pairing,
+ /// Move picture-in-picture window down. (`VK_PINP_DOWN`)
+ PinPDown,
+ /// Move picture-in-picture window. (`VK_PINP_MOVE`)
+ PinPMove,
+ /// Toggle display of picture-in-picture window. (`VK_PINP_TOGGLE`)
+ PinPToggle,
+ /// Move picture-in-picture window up. (`VK_PINP_UP`)
+ PinPUp,
+ /// Decrease media playback speed. (`VK_PLAY_SPEED_DOWN`)
+ PlaySpeedDown,
+ /// Reset playback to normal speed. (`VK_PLAY_SPEED_RESET`)
+ PlaySpeedReset,
+ /// Increase media playback speed. (`VK_PLAY_SPEED_UP`)
+ PlaySpeedUp,
+ /// Toggle random media or content shuffle mode. (`VK_RANDOM_TOGGLE`)
+ RandomToggle,
+ /// Not a physical key, but this key code is sent when the remote control battery is low.
+ /// (`VK_RC_LOW_BATTERY`)
+ RcLowBattery,
+ /// Toggle or cycle between media recording speeds. (`VK_RECORD_SPEED_NEXT`)
+ RecordSpeedNext,
+ /// Toggle RF (radio frequency) input bypass mode (pass RF input directly to the RF output).
+ /// (`VK_RF_BYPASS`)
+ RfBypass,
+ /// Toggle scan channels mode. (`VK_SCAN_CHANNELS_TOGGLE`)
+ ScanChannelsToggle,
+ /// Advance display screen mode to next available mode. (`VK_SCREEN_MODE_NEXT`)
+ ScreenModeNext,
+ /// Toggle display of device settings screen. (`VK_SETTINGS`, `KEYCODE_SETTINGS`)
+ Settings,
+ /// Toggle split screen mode. (`VK_SPLIT_SCREEN_TOGGLE`)
+ SplitScreenToggle,
+ /// Switch the input mode on an external STB (set top box). (`KEYCODE_STB_INPUT`)
+ STBInput,
+ /// Toggle the power on an external STB (set top box). (`KEYCODE_STB_POWER`)
+ STBPower,
+ /// Toggle display of subtitles, if available. (`VK_SUBTITLE`)
+ Subtitle,
+ /// Toggle display of teletext, if available (`VK_TELETEXT`, `KEYCODE_TV_TELETEXT`).
+ Teletext,
+ /// Advance video mode to next available mode. (`VK_VIDEO_MODE_NEXT`)
+ VideoModeNext,
+ /// Cause device to identify itself in some manner, e.g., audibly or visibly. (`VK_WINK`)
+ Wink,
+ /// Toggle between full-screen and scaled content, or alter magnification level. (`VK_ZOOM`,
+ /// `KEYCODE_TV_ZOOM_MODE`)
+ ZoomToggle,
+ /// General-purpose function key.
+ /// Usually found at the top of the keyboard.
+ F1,
+ /// General-purpose function key.
+ /// Usually found at the top of the keyboard.
+ F2,
+ /// General-purpose function key.
+ /// Usually found at the top of the keyboard.
+ F3,
+ /// General-purpose function key.
+ /// Usually found at the top of the keyboard.
+ F4,
+ /// General-purpose function key.
+ /// Usually found at the top of the keyboard.
+ F5,
+ /// General-purpose function key.
+ /// Usually found at the top of the keyboard.
+ F6,
+ /// General-purpose function key.
+ /// Usually found at the top of the keyboard.
+ F7,
+ /// General-purpose function key.
+ /// Usually found at the top of the keyboard.
+ F8,
+ /// General-purpose function key.
+ /// Usually found at the top of the keyboard.
+ F9,
+ /// General-purpose function key.
+ /// Usually found at the top of the keyboard.
+ F10,
+ /// General-purpose function key.
+ /// Usually found at the top of the keyboard.
+ F11,
+ /// General-purpose function key.
+ /// Usually found at the top of the keyboard.
+ F12,
+ /// General-purpose function key.
+ /// Usually found at the top of the keyboard.
+ F13,
+ /// General-purpose function key.
+ /// Usually found at the top of the keyboard.
+ F14,
+ /// General-purpose function key.
+ /// Usually found at the top of the keyboard.
+ F15,
+ /// General-purpose function key.
+ /// Usually found at the top of the keyboard.
+ F16,
+ /// General-purpose function key.
+ /// Usually found at the top of the keyboard.
+ F17,
+ /// General-purpose function key.
+ /// Usually found at the top of the keyboard.
+ F18,
+ /// General-purpose function key.
+ /// Usually found at the top of the keyboard.
+ F19,
+ /// General-purpose function key.
+ /// Usually found at the top of the keyboard.
+ F20,
+ /// General-purpose function key.
+ /// Usually found at the top of the keyboard.
+ F21,
+ /// General-purpose function key.
+ /// Usually found at the top of the keyboard.
+ F22,
+ /// General-purpose function key.
+ /// Usually found at the top of the keyboard.
+ F23,
+ /// General-purpose function key.
+ /// Usually found at the top of the keyboard.
+ F24,
+ /// General-purpose function key.
+ F25,
+ /// General-purpose function key.
+ F26,
+ /// General-purpose function key.
+ F27,
+ /// General-purpose function key.
+ F28,
+ /// General-purpose function key.
+ F29,
+ /// General-purpose function key.
+ F30,
+ /// General-purpose function key.
+ F31,
+ /// General-purpose function key.
+ F32,
+ /// General-purpose function key.
+ F33,
+ /// General-purpose function key.
+ F34,
+ /// General-purpose function key.
+ F35,
+}
+
+impl<'a> Key<'a> {
+ pub fn to_text(&self) -> Option<&'a str> {
+ match self {
+ Key::Character(ch) => Some(*ch),
+ Key::Enter => Some("\r"),
+ Key::Backspace => Some("\x08"),
+ Key::Tab => Some("\t"),
+ Key::Space => Some(" "),
+ Key::Escape => Some("\x1b"),
+ _ => None,
+ }
+ }
+}
+
+impl<'a> From<&'a str> for Key<'a> {
+ fn from(src: &'a str) -> Key<'a> {
+ Key::Character(src)
+ }
+}
+
+/// Represents the location of a physical key.
+#[non_exhaustive]
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+pub enum KeyLocation {
+ Standard,
+ Left,
+ Right,
+ Numpad,
+}
diff --git a/frontend/src-tauri/patches/tao-0.35.2/src/lib.rs b/frontend/src-tauri/patches/tao-0.35.2/src/lib.rs
new file mode 100644
index 000000000..e157637f5
--- /dev/null
+++ b/frontend/src-tauri/patches/tao-0.35.2/src/lib.rs
@@ -0,0 +1,196 @@
+// Copyright 2014-2021 The winit contributors
+// Copyright 2021-2023 Tauri Programme within The Commons Conservancy
+// SPDX-License-Identifier: Apache-2.0
+
+//! Tao is a cross-platform application window creation and event loop management library.
+//!
+//! # Building windows
+//!
+//! Before you can build a [`Window`], you first need to build an [`EventLoop`]. This is done with the
+//! [`EventLoop::new()`] function.
+//!
+//! ```no_run
+//! use tao::event_loop::EventLoop;
+//! let event_loop = EventLoop::new();
+//! ```
+//!
+//! Once this is done there are two ways to create a [`Window`]:
+//!
+//! - Calling [`Window::new(&event_loop)`][window_new].
+//! - Calling [`let builder = WindowBuilder::new()`][window_builder_new] then [`builder.build(&event_loop)`][window_builder_build].
+//!
+//! The first method is the simplest, and will give you default values for everything. The second
+//! method allows you to customize the way your [`Window`] will look and behave by modifying the
+//! fields of the [`WindowBuilder`] object before you create the [`Window`].
+//!
+//! # Event handling
+//!
+//! Once a [`Window`] has been created, it will generate different *events*. A [`Window`] object can
+//! generate [`WindowEvent`]s when certain input events occur, such as a cursor moving over the
+//! window or a key getting pressed while the window is focused. Devices can generate
+//! [`DeviceEvent`]s, which contain unfiltered event data that isn't specific to a certain window.
+//! Some user activity, like mouse movement, can generate both a [`WindowEvent`] *and* a
+//! [`DeviceEvent`]. You can also create and handle your own custom [`UserEvent`]s, if desired.
+//!
+//! You can retrieve events by calling [`EventLoop::run`][event_loop_run]. This function will
+//! dispatch events for every [`Window`] that was created with that particular [`EventLoop`], and
+//! will run until the `control_flow` argument given to the closure is set to
+//! [`ControlFlow`]`::`[`ExitWithCode`] (which [`ControlFlow`]`::`[`Exit`] aliases to), at which
+//! point [`Event`]`::`[`LoopDestroyed`] is emitted and the entire program terminates.
+//!
+//! Tao no longer uses a `EventLoop::poll_events() -> impl Iterator`-based event loop
+//! model, since that can't be implemented properly on some platforms (e.g web, iOS) and works poorly on
+//! most other platforms. However, this model can be re-implemented to an extent with
+//! [`EventLoopExtRunReturn::run_return`]. See that method's documentation for more reasons about why
+//! it's discouraged, beyond compatibility reasons.
+//!
+//!
+//! ```no_run
+//! use tao::{
+//! event::{Event, WindowEvent},
+//! event_loop::{ControlFlow, EventLoop},
+//! window::WindowBuilder,
+//! };
+//!
+//! let event_loop = EventLoop::new();
+//! let window = WindowBuilder::new().build(&event_loop).unwrap();
+//!
+//! event_loop.run(move |event, _, control_flow| {
+//! // ControlFlow::Poll continuously runs the event loop, even if the OS hasn't
+//! // dispatched any events. This is ideal for games and similar applications.
+//! *control_flow = ControlFlow::Poll;
+//!
+//! // ControlFlow::Wait pauses the event loop if no events are available to process.
+//! // This is ideal for non-game applications that only update in response to user
+//! // input, and uses significantly less power/CPU time than ControlFlow::Poll.
+//! *control_flow = ControlFlow::Wait;
+//!
+//! match event {
+//! Event::WindowEvent {
+//! event: WindowEvent::CloseRequested,
+//! ..
+//! } => {
+//! println!("The close button was pressed; stopping");
+//! *control_flow = ControlFlow::Exit
+//! },
+//! Event::MainEventsCleared => {
+//! // Application update code.
+//!
+//! // Queue a RedrawRequested event.
+//! //
+//! // You only need to call this if you've determined that you need to redraw, in
+//! // applications which do not always need to. Applications that redraw continuously
+//! // can just render here instead.
+//! window.request_redraw();
+//! },
+//! Event::RedrawRequested(_) => {
+//! // Redraw the application.
+//! //
+//! // It's preferable for applications that do not render continuously to render in
+//! // this event rather than in MainEventsCleared, since rendering in here allows
+//! // the program to gracefully handle redraws requested by the OS.
+//! },
+//! _ => ()
+//! }
+//! });
+//! ```
+//!
+//! [`Event`]`::`[`WindowEvent`] has a [`WindowId`] member. In multi-window environments, it should be
+//! compared to the value returned by [`Window::id()`][window_id_fn] to determine which [`Window`]
+//! dispatched the event.
+//!
+//! # Drawing on the window
+//!
+//! Tao doesn't directly provide any methods for drawing on a [`Window`]. However it allows you to
+//! retrieve the raw handle of the window and display (see the [`platform`] module and/or the
+//! [`raw_window_handle`] and [`raw_display_handle`] methods), which in turn allows you to create an
+//! OpenGL/Vulkan/DirectX/Metal/etc. context that can be used to render graphics.
+//!
+//! Note that many platforms will display garbage data in the window's client area if the
+//! application doesn't render anything to the window by the time the desktop compositor is ready to
+//! display the window to the user. If you notice this happening, you should create the window with
+//! [`visible` set to `false`](crate::window::WindowBuilder::with_visible) and explicitly make the
+//! window visible only once you're ready to render into it.
+//!
+//! [`EventLoop`]: event_loop::EventLoop
+//! [`EventLoopExtRunReturn::run_return`]: ./platform/run_return/trait.EventLoopExtRunReturn.html#tymethod.run_return
+//! [`EventLoop::new()`]: event_loop::EventLoop::new
+//! [event_loop_run]: event_loop::EventLoop::run
+//! [`ControlFlow`]: event_loop::ControlFlow
+//! [`Exit`]: event_loop::ControlFlow::Exit
+//! [`ExitWithCode`]: event_loop::ControlFlow::ExitWithCode
+//! [`Window`]: window::Window
+//! [`WindowId`]: window::WindowId
+//! [`WindowBuilder`]: window::WindowBuilder
+//! [window_new]: window::Window::new
+//! [window_builder_new]: window::WindowBuilder::new
+//! [window_builder_build]: window::WindowBuilder::build
+//! [window_id_fn]: window::Window::id
+//! [`Event`]: event::Event
+//! [`WindowEvent`]: event::WindowEvent
+//! [`DeviceEvent`]: event::DeviceEvent
+//! [`UserEvent`]: event::Event::UserEvent
+//! [`LoopDestroyed`]: event::Event::LoopDestroyed
+//! [`platform`]: platform
+//! [`raw_window_handle`]: ./window/struct.Window.html#method.raw_window_handle
+//! [`raw_display_handle`]: ./window/struct.Window.html#method.raw_display_handle
+#![allow(
+ clippy::match_str_case_mismatch,
+ clippy::upper_case_acronyms,
+ clippy::from_over_into,
+ clippy::option_map_unit_fn,
+ clippy::needless_lifetimes,
+ clippy::type_complexity,
+ clippy::identity_op,
+ clippy::wrong_self_convention,
+ clippy::non_send_fields_in_send_ty
+)]
+#![deny(rustdoc::broken_intra_doc_links)]
+
+use dpi::PixelUnit;
+#[cfg(feature = "rwh_04")]
+pub use rwh_04;
+#[cfg(feature = "rwh_05")]
+pub use rwh_05;
+#[cfg(feature = "rwh_06")]
+pub use rwh_06;
+
+#[allow(unused_imports)]
+#[macro_use]
+extern crate log;
+#[cfg(feature = "serde")]
+#[macro_use]
+extern crate serde;
+#[macro_use]
+extern crate bitflags;
+#[cfg(any(target_os = "macos", target_os = "ios"))]
+#[macro_use(class, msg_send, sel)]
+extern crate objc2;
+
+pub use dpi;
+
+#[macro_use]
+pub mod error;
+pub mod event;
+pub mod event_loop;
+mod icon;
+pub mod keyboard;
+pub mod monitor;
+mod platform_impl;
+
+pub mod window;
+
+pub mod platform;
+
+pub(crate) fn extract_width_height(size: dpi::Size) -> (PixelUnit, PixelUnit) {
+ match size {
+ dpi::Size::Physical(size) => (
+ PixelUnit::Physical(size.width.into()),
+ PixelUnit::Physical(size.height.into()),
+ ),
+ dpi::Size::Logical(size) => (
+ PixelUnit::Logical(size.width.into()),
+ PixelUnit::Logical(size.height.into()),
+ ),
+ }
+}
diff --git a/frontend/src-tauri/patches/tao-0.35.2/src/monitor.rs b/frontend/src-tauri/patches/tao-0.35.2/src/monitor.rs
new file mode 100644
index 000000000..7e5404f57
--- /dev/null
+++ b/frontend/src-tauri/patches/tao-0.35.2/src/monitor.rs
@@ -0,0 +1,163 @@
+// Copyright 2014-2021 The winit contributors
+// Copyright 2021-2023 Tauri Programme within The Commons Conservancy
+// SPDX-License-Identifier: Apache-2.0
+
+//! Types useful for interacting with a user's monitors.
+//!
+//! If you want to get basic information about a monitor, you can use the [`MonitorHandle`][monitor_handle]
+//! type. This is retrieved from one of the following methods, which return an iterator of
+//! [`MonitorHandle`][monitor_handle]:
+//! - [`EventLoopWindowTarget::available_monitors`][loop_get]
+//! - [`Window::available_monitors`][window_get].
+//!
+//! [monitor_handle]: crate::monitor::MonitorHandle
+//! [loop_get]: crate::event_loop::EventLoopWindowTarget::available_monitors
+//! [window_get]: crate::window::Window::available_monitors
+use crate::{
+ dpi::{PhysicalPosition, PhysicalSize},
+ platform_impl,
+};
+
+/// Describes a fullscreen video mode of a monitor.
+///
+/// Can be acquired with:
+/// - [`MonitorHandle::video_modes`][monitor_get].
+///
+/// [monitor_get]: crate::monitor::MonitorHandle::video_modes
+#[derive(Clone, PartialEq, Eq, Hash)]
+pub struct VideoMode {
+ pub(crate) video_mode: platform_impl::VideoMode,
+}
+
+impl std::fmt::Debug for VideoMode {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ self.video_mode.fmt(f)
+ }
+}
+
+impl PartialOrd for VideoMode {
+ fn partial_cmp(&self, other: &VideoMode) -> Option {
+ Some(self.cmp(other))
+ }
+}
+
+impl Ord for VideoMode {
+ fn cmp(&self, other: &VideoMode) -> std::cmp::Ordering {
+ // TODO: we can impl `Ord` for `PhysicalSize` once we switch from `f32`
+ // to `u32` there
+ let size: (u32, u32) = self.size().into();
+ let other_size: (u32, u32) = other.size().into();
+ self.monitor().cmp(&other.monitor()).then(
+ size
+ .cmp(&other_size)
+ .then(
+ self
+ .refresh_rate()
+ .cmp(&other.refresh_rate())
+ .then(self.bit_depth().cmp(&other.bit_depth())),
+ )
+ .reverse(),
+ )
+ }
+}
+
+impl VideoMode {
+ /// Returns the resolution of this video mode.
+ #[inline]
+ pub fn size(&self) -> PhysicalSize {
+ self.video_mode.size()
+ }
+
+ /// Returns the bit depth of this video mode, as in how many bits you have
+ /// available per color. This is generally 24 bits or 32 bits on modern
+ /// systems, depending on whether the alpha channel is counted or not.
+ ///
+ /// ## Platform-specific
+ /// - **iOS:** Always returns 32.
+ #[inline]
+ pub fn bit_depth(&self) -> u16 {
+ self.video_mode.bit_depth()
+ }
+
+ /// Returns the refresh rate of this video mode. **Note**: the returned
+ /// refresh rate is an integer approximation, and you shouldn't rely on this
+ /// value to be exact.
+ #[inline]
+ pub fn refresh_rate(&self) -> u16 {
+ self.video_mode.refresh_rate()
+ }
+
+ /// Returns the monitor that this video mode is valid for. Each monitor has
+ /// a separate set of valid video modes.
+ #[inline]
+ pub fn monitor(&self) -> MonitorHandle {
+ self.video_mode.monitor()
+ }
+}
+
+impl std::fmt::Display for VideoMode {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ write!(
+ f,
+ "{}x{} @ {} Hz ({} bpp)",
+ self.size().width,
+ self.size().height,
+ self.refresh_rate(),
+ self.bit_depth()
+ )
+ }
+}
+
+/// Handle to a monitor.
+///
+/// Allows you to retrieve information about a given monitor and can be used in [`Window`] creation.
+///
+/// [`Window`]: crate::window::Window
+#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
+pub struct MonitorHandle {
+ pub(crate) inner: platform_impl::MonitorHandle,
+}
+
+impl MonitorHandle {
+ /// Returns a human-readable name of the monitor.
+ ///
+ /// Returns `None` if the monitor doesn't exist anymore.
+ #[inline]
+ pub fn name(&self) -> Option {
+ self.inner.name()
+ }
+
+ /// Returns the monitor's resolution.
+ #[inline]
+ pub fn size(&self) -> PhysicalSize {
+ self.inner.size()
+ }
+
+ /// Returns the top-left corner position of the monitor relative to the larger full
+ /// screen area.
+ #[inline]
+ pub fn position(&self) -> PhysicalPosition {
+ self.inner.position()
+ }
+
+ /// Returns the scale factor that can be used to map logical pixels to physical pixels, and vice versa.
+ ///
+ /// See the [`dpi`](crate::dpi) module for more information.
+ ///
+ /// ## Platform-specific
+ ///
+ /// - **Android:** Always returns 1.0.
+ #[inline]
+ pub fn scale_factor(&self) -> f64 {
+ self.inner.scale_factor()
+ }
+
+ /// Returns all fullscreen video modes supported by this monitor.
+ ///
+ /// ## Platform-specific
+ /// - **Linux:** Unsupported. This will always return empty iterator.
+ #[inline]
+ pub fn video_modes(&self) -> impl Iterator- {
+ self.inner.video_modes()
+ }
+}
diff --git a/frontend/src-tauri/patches/tao-0.35.2/src/platform/android.rs b/frontend/src-tauri/patches/tao-0.35.2/src/platform/android.rs
new file mode 100644
index 000000000..7d4456cb8
--- /dev/null
+++ b/frontend/src-tauri/patches/tao-0.35.2/src/platform/android.rs
@@ -0,0 +1,72 @@
+// Copyright 2014-2021 The winit contributors
+// Copyright 2021-2023 Tauri Programme within The Commons Conservancy
+// SPDX-License-Identifier: Apache-2.0
+
+#![cfg(target_os = "android")]
+
+pub mod prelude {
+ pub use crate::platform_impl::ndk_glue::*;
+ pub use tao_macros::{android_fn, generate_package_name};
+}
+use crate::{
+ event_loop::{EventLoop, EventLoopWindowTarget},
+ platform_impl::ndk_glue::Rect,
+ window::{Window, WindowBuilder},
+};
+use ndk::configuration::Configuration;
+
+/// Additional methods on `EventLoop` that are specific to Android.
+pub trait EventLoopExtAndroid {}
+
+impl EventLoopExtAndroid for EventLoop {}
+
+/// Additional methods on `EventLoopWindowTarget` that are specific to Android.
+pub trait EventLoopWindowTargetExtAndroid {}
+
+/// Additional methods on `Window` that are specific to Android.
+pub trait WindowExtAndroid {
+ fn content_rect(&self) -> Rect;
+
+ fn config(&self) -> Configuration;
+
+ fn activity_name(&self) -> String;
+}
+
+impl WindowExtAndroid for Window {
+ fn content_rect(&self) -> Rect {
+ self.window.content_rect()
+ }
+
+ fn config(&self) -> Configuration {
+ self.window.config()
+ }
+
+ fn activity_name(&self) -> String {
+ self.window.activity_name().to_string()
+ }
+}
+
+impl EventLoopWindowTargetExtAndroid for EventLoopWindowTarget {}
+
+/// Additional methods on `WindowBuilder` that are specific to Android.
+pub trait WindowBuilderExtAndroid {
+ /// The name of the activity class to create.
+ fn with_activity_name(self, activity_name: String) -> Self;
+
+ /// The name of the activity class that created this window.
+ ///
+ /// This is important to define which stack the activity will be created on.
+ fn with_created_by_activity_name(self, created_by_activity_name: String) -> Self;
+}
+
+impl WindowBuilderExtAndroid for WindowBuilder {
+ fn with_activity_name(mut self, activity_name: String) -> Self {
+ self.platform_specific.activity_name = Some(activity_name);
+ self
+ }
+
+ fn with_created_by_activity_name(mut self, created_by_activity_name: String) -> Self {
+ self.platform_specific.created_by_activity_name = Some(created_by_activity_name);
+ self
+ }
+}
diff --git a/frontend/src-tauri/patches/tao-0.35.2/src/platform/ios.rs b/frontend/src-tauri/patches/tao-0.35.2/src/platform/ios.rs
new file mode 100644
index 000000000..536c3a98b
--- /dev/null
+++ b/frontend/src-tauri/patches/tao-0.35.2/src/platform/ios.rs
@@ -0,0 +1,378 @@
+// Copyright 2014-2021 The winit contributors
+// Copyright 2021-2023 Tauri Programme within The Commons Conservancy
+// SPDX-License-Identifier: Apache-2.0
+
+#![cfg(target_os = "ios")]
+
+use std::os::raw::c_void;
+
+use crate::{
+ event_loop::{EventLoop, EventLoopWindowTarget},
+ monitor::{MonitorHandle, VideoMode},
+ platform_impl::set_badge_count,
+ window::{Window, WindowBuilder},
+};
+
+/// Additional methods on [`EventLoop`] that are specific to iOS.
+pub trait EventLoopExtIOS {
+ /// Returns the [`Idiom`] (phone/tablet/tv/etc) for the current device.
+ fn idiom(&self) -> Idiom;
+}
+
+impl EventLoopExtIOS for EventLoop {
+ fn idiom(&self) -> Idiom {
+ self.event_loop.idiom()
+ }
+}
+
+/// Additional methods on [`Window`] that are specific to iOS.
+pub trait WindowExtIOS {
+ /// Returns a pointer to the [`UIWindow`] that is used by this window.
+ ///
+ /// The pointer will become invalid when the [`Window`] is destroyed.
+ ///
+ /// [`UIWindow`]: https://developer.apple.com/documentation/uikit/uiwindow?language=objc
+ fn ui_window(&self) -> *mut c_void;
+
+ /// Returns a pointer to the [`UIViewController`] that is used by this window.
+ ///
+ /// The pointer will become invalid when the [`Window`] is destroyed.
+ ///
+ /// [`UIViewController`]: https://developer.apple.com/documentation/uikit/uiviewcontroller?language=objc
+ fn ui_view_controller(&self) -> *mut c_void;
+
+ /// Returns a pointer to the [`UIView`] that is used by this window.
+ ///
+ /// The pointer will become invalid when the [`Window`] is destroyed.
+ ///
+ /// [`UIView`]: https://developer.apple.com/documentation/uikit/uiview?language=objc
+ fn ui_view(&self) -> *mut c_void;
+
+ /// Sets the [`contentScaleFactor`] of the underlying [`UIWindow`] to `scale_factor`.
+ ///
+ /// The default value is device dependent, and it's recommended GLES or Metal applications set
+ /// this to [`MonitorHandle::scale_factor()`].
+ ///
+ /// [`UIWindow`]: https://developer.apple.com/documentation/uikit/uiwindow?language=objc
+ /// [`contentScaleFactor`]: https://developer.apple.com/documentation/uikit/uiview/1622657-contentscalefactor?language=objc
+ fn set_scale_factor(&self, scale_factor: f64);
+
+ /// Sets the valid orientations for the [`Window`].
+ ///
+ /// The default value is [`ValidOrientations::LandscapeAndPortrait`].
+ ///
+ /// This changes the value returned by
+ /// [`-[UIViewController supportedInterfaceOrientations]`](https://developer.apple.com/documentation/uikit/uiviewcontroller/1621435-supportedinterfaceorientations?language=objc),
+ /// and then calls
+ /// [`-[UIViewController attemptRotationToDeviceOrientation]`](https://developer.apple.com/documentation/uikit/uiviewcontroller/1621400-attemptrotationtodeviceorientati?language=objc).
+ fn set_valid_orientations(&self, valid_orientations: ValidOrientations);
+
+ /// Sets whether the [`Window`] prefers the home indicator hidden.
+ ///
+ /// The default is to prefer showing the home indicator.
+ ///
+ /// This changes the value returned by
+ /// [`-[UIViewController prefersHomeIndicatorAutoHidden]`](https://developer.apple.com/documentation/uikit/uiviewcontroller/2887510-prefershomeindicatorautohidden?language=objc),
+ /// and then calls
+ /// [`-[UIViewController setNeedsUpdateOfHomeIndicatorAutoHidden]`](https://developer.apple.com/documentation/uikit/uiviewcontroller/2887509-setneedsupdateofhomeindicatoraut?language=objc).
+ ///
+ /// This only has an effect on iOS 11.0+.
+ fn set_prefers_home_indicator_hidden(&self, hidden: bool);
+
+ /// Sets the screen edges for which the system gestures will take a lower priority than the
+ /// application's touch handling.
+ ///
+ /// This changes the value returned by
+ /// [`-[UIViewController preferredScreenEdgesDeferringSystemGestures]`](https://developer.apple.com/documentation/uikit/uiviewcontroller/2887512-preferredscreenedgesdeferringsys?language=objc),
+ /// and then calls
+ /// [`-[UIViewController setNeedsUpdateOfScreenEdgesDeferringSystemGestures]`](https://developer.apple.com/documentation/uikit/uiviewcontroller/2887507-setneedsupdateofscreenedgesdefer?language=objc).
+ ///
+ /// This only has an effect on iOS 11.0+.
+ fn set_preferred_screen_edges_deferring_system_gestures(&self, edges: ScreenEdge);
+
+ /// Sets whether the [`Window`] prefers the status bar hidden.
+ ///
+ /// The default is to prefer showing the status bar.
+ ///
+ /// This changes the value returned by
+ /// [`-[UIViewController prefersStatusBarHidden]`](https://developer.apple.com/documentation/uikit/uiviewcontroller/1621440-prefersstatusbarhidden?language=objc),
+ /// and then calls
+ /// [`-[UIViewController setNeedsStatusBarAppearanceUpdate]`](https://developer.apple.com/documentation/uikit/uiviewcontroller/1621354-setneedsstatusbarappearanceupdat?language=objc).
+ fn set_prefers_status_bar_hidden(&self, hidden: bool);
+
+ /// Sets the badge count on iOS launcher. 0 hides the count
+ fn set_badge_count(&self, count: i32);
+
+ /// Returns the identifier of the UIScene tied to this UIWindow.
+ fn scene_identifier(&self) -> String;
+}
+
+impl WindowExtIOS for Window {
+ #[inline]
+ fn ui_window(&self) -> *mut c_void {
+ self.window.ui_window() as _
+ }
+
+ #[inline]
+ fn ui_view_controller(&self) -> *mut c_void {
+ self.window.ui_view_controller() as _
+ }
+
+ #[inline]
+ fn ui_view(&self) -> *mut c_void {
+ self.window.ui_view() as _
+ }
+
+ #[inline]
+ fn set_scale_factor(&self, scale_factor: f64) {
+ self.window.set_scale_factor(scale_factor)
+ }
+
+ #[inline]
+ fn set_valid_orientations(&self, valid_orientations: ValidOrientations) {
+ self.window.set_valid_orientations(valid_orientations)
+ }
+
+ #[inline]
+ fn set_prefers_home_indicator_hidden(&self, hidden: bool) {
+ self.window.set_prefers_home_indicator_hidden(hidden)
+ }
+
+ #[inline]
+ fn set_preferred_screen_edges_deferring_system_gestures(&self, edges: ScreenEdge) {
+ self
+ .window
+ .set_preferred_screen_edges_deferring_system_gestures(edges)
+ }
+
+ #[inline]
+ fn set_prefers_status_bar_hidden(&self, hidden: bool) {
+ self.window.set_prefers_status_bar_hidden(hidden)
+ }
+
+ #[inline]
+ fn set_badge_count(&self, count: i32) {
+ self.window.set_badge_count(count)
+ }
+
+ #[inline]
+ fn scene_identifier(&self) -> String {
+ self.window.scene_identifier()
+ }
+}
+
+pub trait EventLoopWindowTargetExtIOS {
+ /// Sets the badge count on iOS launcher. 0 hides the count
+ fn set_badge_count(&self, count: i32);
+}
+
+impl EventLoopWindowTargetExtIOS for EventLoopWindowTarget {
+ fn set_badge_count(&self, count: i32) {
+ set_badge_count(count)
+ }
+}
+
+/// Additional methods on [`WindowBuilder`] that are specific to iOS.
+pub trait WindowBuilderExtIOS {
+ /// Sets the root view class used by the [`Window`], otherwise a barebones [`UIView`] is provided.
+ ///
+ /// An instance of the class will be initialized by calling [`-[UIView initWithFrame:]`](https://developer.apple.com/documentation/uikit/uiview/1622488-initwithframe?language=objc).
+ ///
+ /// [`UIView`]: https://developer.apple.com/documentation/uikit/uiview?language=objc
+ fn with_root_view_class(self, root_view_class: *const c_void) -> WindowBuilder;
+
+ /// Sets the [`contentScaleFactor`] of the underlying [`UIWindow`] to `scale_factor`.
+ ///
+ /// The default value is device dependent, and it's recommended GLES or Metal applications set
+ /// this to [`MonitorHandle::scale_factor()`].
+ ///
+ /// [`UIWindow`]: https://developer.apple.com/documentation/uikit/uiwindow?language=objc
+ /// [`contentScaleFactor`]: https://developer.apple.com/documentation/uikit/uiview/1622657-contentscalefactor?language=objc
+ fn with_scale_factor(self, scale_factor: f64) -> WindowBuilder;
+
+ /// Sets the valid orientations for the [`Window`].
+ ///
+ /// The default value is [`ValidOrientations::LandscapeAndPortrait`].
+ ///
+ /// This sets the initial value returned by
+ /// [`-[UIViewController supportedInterfaceOrientations]`](https://developer.apple.com/documentation/uikit/uiviewcontroller/1621435-supportedinterfaceorientations?language=objc).
+ fn with_valid_orientations(self, valid_orientations: ValidOrientations) -> WindowBuilder;
+
+ /// Sets whether the [`Window`] prefers the home indicator hidden.
+ ///
+ /// The default is to prefer showing the home indicator.
+ ///
+ /// This sets the initial value returned by
+ /// [`-[UIViewController prefersHomeIndicatorAutoHidden]`](https://developer.apple.com/documentation/uikit/uiviewcontroller/2887510-prefershomeindicatorautohidden?language=objc).
+ ///
+ /// This only has an effect on iOS 11.0+.
+ fn with_prefers_home_indicator_hidden(self, hidden: bool) -> WindowBuilder;
+
+ /// Sets the screen edges for which the system gestures will take a lower priority than the
+ /// application's touch handling.
+ ///
+ /// This sets the initial value returned by
+ /// [`-[UIViewController preferredScreenEdgesDeferringSystemGestures]`](https://developer.apple.com/documentation/uikit/uiviewcontroller/2887512-preferredscreenedgesdeferringsys?language=objc).
+ ///
+ /// This only has an effect on iOS 11.0+.
+ fn with_preferred_screen_edges_deferring_system_gestures(
+ self,
+ edges: ScreenEdge,
+ ) -> WindowBuilder;
+
+ /// Sets whether the [`Window`] prefers the status bar hidden.
+ ///
+ /// The default is to prefer showing the status bar.
+ ///
+ /// This sets the initial value returned by
+ /// [`-[UIViewController prefersStatusBarHidden]`](https://developer.apple.com/documentation/uikit/uiviewcontroller/1621440-prefersstatusbarhidden?language=objc).
+ fn with_prefers_status_bar_hidden(self, hidden: bool) -> WindowBuilder;
+
+ /// Sets the identifier of the UIScene that is requesting the creation of this new scene,
+ /// establishing a relationship between the two scenes.
+ ///
+ /// By default the system uses the foreground scene.
+ fn with_requesting_scene_identifier(self, identifier: String) -> WindowBuilder;
+}
+
+impl WindowBuilderExtIOS for WindowBuilder {
+ #[inline]
+ fn with_root_view_class(mut self, root_view_class: *const c_void) -> WindowBuilder {
+ self.platform_specific.root_view_class = unsafe { &*(root_view_class as *const _) };
+ self
+ }
+
+ #[inline]
+ fn with_scale_factor(mut self, scale_factor: f64) -> WindowBuilder {
+ self.platform_specific.scale_factor = Some(scale_factor);
+ self
+ }
+
+ #[inline]
+ fn with_valid_orientations(mut self, valid_orientations: ValidOrientations) -> WindowBuilder {
+ self.platform_specific.valid_orientations = valid_orientations;
+ self
+ }
+
+ #[inline]
+ fn with_prefers_home_indicator_hidden(mut self, hidden: bool) -> WindowBuilder {
+ self.platform_specific.prefers_home_indicator_hidden = hidden;
+ self
+ }
+
+ #[inline]
+ fn with_preferred_screen_edges_deferring_system_gestures(
+ mut self,
+ edges: ScreenEdge,
+ ) -> WindowBuilder {
+ self
+ .platform_specific
+ .preferred_screen_edges_deferring_system_gestures = edges;
+ self
+ }
+
+ #[inline]
+ fn with_prefers_status_bar_hidden(mut self, hidden: bool) -> WindowBuilder {
+ self.platform_specific.prefers_status_bar_hidden = hidden;
+ self
+ }
+
+ #[inline]
+ fn with_requesting_scene_identifier(mut self, identifier: String) -> WindowBuilder {
+ self
+ .platform_specific
+ .requesting_scene_identifier
+ .replace(identifier);
+ self
+ }
+}
+
+/// Additional methods on [`MonitorHandle`] that are specific to iOS.
+pub trait MonitorHandleExtIOS {
+ /// Returns a pointer to the [`UIScreen`] that is used by this monitor.
+ ///
+ /// [`UIScreen`]: https://developer.apple.com/documentation/uikit/uiscreen?language=objc
+ fn ui_screen(&self) -> *mut c_void;
+
+ /// Returns the preferred [`VideoMode`] for this monitor.
+ ///
+ /// This translates to a call to [`-[UIScreen preferredMode]`](https://developer.apple.com/documentation/uikit/uiscreen/1617823-preferredmode?language=objc).
+ fn preferred_video_mode(&self) -> VideoMode;
+}
+
+impl MonitorHandleExtIOS for MonitorHandle {
+ #[inline]
+ fn ui_screen(&self) -> *mut c_void {
+ self.inner.ui_screen() as _
+ }
+
+ #[inline]
+ fn preferred_video_mode(&self) -> VideoMode {
+ self.inner.preferred_video_mode()
+ }
+}
+
+/// Valid orientations for a particular [`Window`].
+#[non_exhaustive]
+#[derive(Clone, Copy, Debug)]
+pub enum ValidOrientations {
+ /// Excludes `PortraitUpsideDown` on iphone
+ LandscapeAndPortrait,
+
+ Landscape,
+
+ /// Excludes `PortraitUpsideDown` on iphone
+ Portrait,
+}
+
+impl Default for ValidOrientations {
+ #[inline]
+ fn default() -> ValidOrientations {
+ ValidOrientations::LandscapeAndPortrait
+ }
+}
+
+/// The device [idiom].
+///
+/// [idiom]: https://developer.apple.com/documentation/uikit/uidevice/1620037-userinterfaceidiom?language=objc
+#[non_exhaustive]
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+pub enum Idiom {
+ Unspecified,
+
+ /// iPhone and iPod touch.
+ Phone,
+
+ /// iPad.
+ Pad,
+
+ /// tvOS and Apple TV.
+ TV,
+ CarPlay,
+}
+
+bitflags! {
+ /// The [edges] of a screen.
+ ///
+ /// [edges]: https://developer.apple.com/documentation/uikit/uirectedge?language=objc
+ #[derive(Clone, Copy ,Default)]
+ pub struct ScreenEdge: u8 {
+ const NONE = 0;
+ const TOP = 1 << 0;
+ const LEFT = 1 << 1;
+ const BOTTOM = 1 << 2;
+ const RIGHT = 1 << 3;
+ const ALL = ScreenEdge::TOP.bits() | ScreenEdge::LEFT.bits()
+ | ScreenEdge::BOTTOM.bits() | ScreenEdge::RIGHT.bits();
+ }
+}
+
+pub(crate) fn operating_system_version() -> (isize, isize, isize) {
+ let process_info = objc2_foundation::NSProcessInfo::processInfo();
+ let version = process_info.operatingSystemVersion();
+ (
+ version.majorVersion,
+ version.minorVersion,
+ version.patchVersion,
+ )
+}
diff --git a/frontend/src-tauri/patches/tao-0.35.2/src/platform/linux.rs b/frontend/src-tauri/patches/tao-0.35.2/src/platform/linux.rs
new file mode 100644
index 000000000..2f0603c23
--- /dev/null
+++ b/frontend/src-tauri/patches/tao-0.35.2/src/platform/linux.rs
@@ -0,0 +1,5 @@
+// Copyright 2014-2021 The winit contributors
+// Copyright 2021-2023 Tauri Programme within The Commons Conservancy
+// SPDX-License-Identifier: Apache-2.0
+
+#![cfg(target_os = "linux")]
diff --git a/frontend/src-tauri/patches/tao-0.35.2/src/platform/macos.rs b/frontend/src-tauri/patches/tao-0.35.2/src/platform/macos.rs
new file mode 100644
index 000000000..32b8cbbf3
--- /dev/null
+++ b/frontend/src-tauri/patches/tao-0.35.2/src/platform/macos.rs
@@ -0,0 +1,458 @@
+// Copyright 2014-2021 The winit contributors
+// Copyright 2021-2023 Tauri Programme within The Commons Conservancy
+// SPDX-License-Identifier: Apache-2.0
+
+#![cfg(target_os = "macos")]
+
+use std::os::raw::c_void;
+
+use objc2_foundation::NSObject;
+
+use crate::{
+ dpi::{LogicalSize, Position},
+ event_loop::{EventLoop, EventLoopWindowTarget},
+ monitor::MonitorHandle,
+ platform_impl::{get_aux_state_mut, set_badge_label, set_dock_visibility, Parent},
+ window::{Window, WindowBuilder},
+};
+
+/// Additional methods on `Window` that are specific to MacOS.
+pub trait WindowExtMacOS {
+ /// Returns a pointer to the cocoa `NSWindow` that is used by this window.
+ ///
+ /// The pointer will become invalid when the `Window` is destroyed.
+ fn ns_window(&self) -> *mut c_void;
+
+ /// Returns a pointer to the cocoa `NSView` that is used by this window.
+ ///
+ /// The pointer will become invalid when the `Window` is destroyed.
+ fn ns_view(&self) -> *mut c_void;
+
+ /// Returns whether or not the window is in simple fullscreen mode.
+ fn simple_fullscreen(&self) -> bool;
+
+ /// Toggles a fullscreen mode that doesn't require a new macOS space.
+ /// Returns a boolean indicating whether the transition was successful (this
+ /// won't work if the window was already in the native fullscreen).
+ ///
+ /// This is how fullscreen used to work on macOS in versions before Lion.
+ /// And allows the user to have a fullscreen window without using another
+ /// space or taking control over the entire monitor.
+ fn set_simple_fullscreen(&self, fullscreen: bool) -> bool;
+
+ /// Returns whether or not the window has shadow.
+ fn has_shadow(&self) -> bool;
+
+ /// Sets whether or not the window has shadow.
+ fn set_has_shadow(&self, has_shadow: bool);
+
+ /// Set the window traffic light position relative to the upper left corner
+ fn set_traffic_light_inset>(&self, position: P);
+ /// Put the window in a state which indicates a file save is required.
+ ///
+ ///
+ fn set_is_document_edited(&self, edited: bool);
+
+ /// Get the window's edit state
+ fn is_document_edited(&self) -> bool;
+
+ /// Sets whether the system can automatically organize windows into tabs.
+ ///
+ ///
+ fn set_allows_automatic_window_tabbing(&self, enabled: bool);
+
+ /// Returns whether the system can automatically organize windows into tabs.
+ fn allows_automatic_window_tabbing(&self) -> bool;
+
+ /// Group windows together by using the same tabbing identifier.
+ ///
+ ///
+ fn set_tabbing_identifier(&self, identifier: &str);
+
+ /// Returns the window's tabbing identifier.
+ fn tabbing_identifier(&self) -> String;
+
+ /// The content view consumes the full size of the window.
+ ///
+ ///
+ fn set_fullsize_content_view(&self, fullsize: bool);
+
+ /// A Boolean value that indicates whether the title bar draws its background.
+ ///
+ ///
+ fn set_titlebar_transparent(&self, transparent: bool);
+
+ /// Sets the badge label on the taskbar
+ fn set_badge_label(&self, label: Option);
+}
+
+impl WindowExtMacOS for Window {
+ #[inline]
+ fn ns_window(&self) -> *mut c_void {
+ self.window.ns_window()
+ }
+
+ #[inline]
+ fn ns_view(&self) -> *mut c_void {
+ self.window.ns_view()
+ }
+
+ #[inline]
+ fn simple_fullscreen(&self) -> bool {
+ self.window.simple_fullscreen()
+ }
+
+ #[inline]
+ fn set_simple_fullscreen(&self, fullscreen: bool) -> bool {
+ self.window.set_simple_fullscreen(fullscreen)
+ }
+
+ #[inline]
+ fn has_shadow(&self) -> bool {
+ self.window.has_shadow()
+ }
+
+ #[inline]
+ fn set_has_shadow(&self, has_shadow: bool) {
+ self.window.set_has_shadow(has_shadow)
+ }
+
+ #[inline]
+ fn set_traffic_light_inset>(&self, position: P) {
+ self.window.set_traffic_light_inset(position)
+ }
+
+ #[inline]
+ fn set_is_document_edited(&self, edited: bool) {
+ self.window.set_is_document_edited(edited)
+ }
+
+ #[inline]
+ fn is_document_edited(&self) -> bool {
+ self.window.is_document_edited()
+ }
+
+ #[inline]
+ fn set_allows_automatic_window_tabbing(&self, enabled: bool) {
+ self.window.set_allows_automatic_window_tabbing(enabled)
+ }
+
+ #[inline]
+ fn allows_automatic_window_tabbing(&self) -> bool {
+ self.window.allows_automatic_window_tabbing()
+ }
+
+ #[inline]
+ fn set_tabbing_identifier(&self, identifier: &str) {
+ self.window.set_tabbing_identifier(identifier)
+ }
+
+ #[inline]
+ fn tabbing_identifier(&self) -> String {
+ self.window.tabbing_identifier()
+ }
+
+ #[inline]
+ fn set_fullsize_content_view(&self, fullsize: bool) {
+ self.window.set_fullsize_content_view(fullsize);
+ }
+
+ #[inline]
+ fn set_titlebar_transparent(&self, transparent: bool) {
+ self.window.set_titlebar_transparent(transparent);
+ }
+
+ #[inline]
+ fn set_badge_label(&self, label: Option) {
+ self.window.set_badge_label(label);
+ }
+}
+
+/// Corresponds to `NSApplicationActivationPolicy`.
+#[non_exhaustive]
+#[derive(Debug, Clone, Copy, PartialEq, Default)]
+pub enum ActivationPolicy {
+ /// Corresponds to `NSApplicationActivationPolicyRegular`.
+ #[default]
+ Regular,
+ /// Corresponds to `NSApplicationActivationPolicyAccessory`.
+ Accessory,
+ /// Corresponds to `NSApplicationActivationPolicyProhibited`.
+ Prohibited,
+}
+
+/// Additional methods on `WindowBuilder` that are specific to MacOS.
+///
+/// **Note:** Properties dealing with the titlebar will be overwritten by the `with_decorations` method
+/// on the base `WindowBuilder`:
+///
+/// - `with_titlebar_transparent`
+/// - `with_title_hidden`
+/// - `with_titlebar_hidden`
+/// - `with_titlebar_buttons_hidden`
+/// - `with_fullsize_content_view`
+pub trait WindowBuilderExtMacOS {
+ /// Sets a parent to the window to be created.
+ fn with_parent_window(self, parent: *mut c_void) -> WindowBuilder;
+ /// Enables click-and-drag behavior for the entire window, not just the titlebar.
+ fn with_movable_by_window_background(self, movable_by_window_background: bool) -> WindowBuilder;
+ /// Makes the titlebar transparent and allows the content to appear behind it.
+ fn with_titlebar_transparent(self, titlebar_transparent: bool) -> WindowBuilder;
+ /// Hides the window title.
+ fn with_title_hidden(self, title_hidden: bool) -> WindowBuilder;
+ /// Hides the window titlebar.
+ fn with_titlebar_hidden(self, titlebar_hidden: bool) -> WindowBuilder;
+ /// Hides the window titlebar buttons.
+ fn with_titlebar_buttons_hidden(self, titlebar_buttons_hidden: bool) -> WindowBuilder;
+ /// Makes the window content appear behind the titlebar.
+ fn with_fullsize_content_view(self, fullsize_content_view: bool) -> WindowBuilder;
+ /// Build window with `resizeIncrements` property. Values must not be 0.
+ fn with_resize_increments(self, increments: LogicalSize) -> WindowBuilder;
+ fn with_disallow_hidpi(self, disallow_hidpi: bool) -> WindowBuilder;
+ /// Sets whether or not the window has shadow.
+ fn with_has_shadow(self, has_shadow: bool) -> WindowBuilder;
+ /// Sets the traffic light position to (x, y) relative to the upper left corner
+ fn with_traffic_light_inset>(self, inset: P) -> WindowBuilder;
+ /// Sets whether the system can automatically organize windows into tabs.
+ fn with_automatic_window_tabbing(self, automatic_tabbing: bool) -> WindowBuilder;
+ /// Defines the window [tabbing identifier].
+ ///
+ /// [tabbing identifier]:
+ fn with_tabbing_identifier(self, identifier: &str) -> WindowBuilder;
+}
+
+impl WindowBuilderExtMacOS for WindowBuilder {
+ #[inline]
+ fn with_parent_window(mut self, parent: *mut c_void) -> WindowBuilder {
+ self.platform_specific.parent = Parent::ChildOf(parent);
+ self
+ }
+
+ #[inline]
+ fn with_movable_by_window_background(
+ mut self,
+ movable_by_window_background: bool,
+ ) -> WindowBuilder {
+ self.platform_specific.movable_by_window_background = movable_by_window_background;
+ self
+ }
+
+ #[inline]
+ fn with_titlebar_transparent(mut self, titlebar_transparent: bool) -> WindowBuilder {
+ self.platform_specific.titlebar_transparent = titlebar_transparent;
+ self
+ }
+
+ #[inline]
+ fn with_titlebar_hidden(mut self, titlebar_hidden: bool) -> WindowBuilder {
+ self.platform_specific.titlebar_hidden = titlebar_hidden;
+ self
+ }
+
+ #[inline]
+ fn with_titlebar_buttons_hidden(mut self, titlebar_buttons_hidden: bool) -> WindowBuilder {
+ self.platform_specific.titlebar_buttons_hidden = titlebar_buttons_hidden;
+ self
+ }
+
+ #[inline]
+ fn with_title_hidden(mut self, title_hidden: bool) -> WindowBuilder {
+ self.platform_specific.title_hidden = title_hidden;
+ self
+ }
+
+ #[inline]
+ fn with_fullsize_content_view(mut self, fullsize_content_view: bool) -> WindowBuilder {
+ self.platform_specific.fullsize_content_view = fullsize_content_view;
+ self
+ }
+
+ #[inline]
+ fn with_resize_increments(mut self, increments: LogicalSize) -> WindowBuilder {
+ self.platform_specific.resize_increments = Some(increments);
+ self
+ }
+
+ #[inline]
+ fn with_disallow_hidpi(mut self, disallow_hidpi: bool) -> WindowBuilder {
+ self.platform_specific.disallow_hidpi = disallow_hidpi;
+ self
+ }
+
+ #[inline]
+ fn with_has_shadow(mut self, has_shadow: bool) -> WindowBuilder {
+ self.platform_specific.has_shadow = has_shadow;
+ self
+ }
+
+ #[inline]
+ fn with_traffic_light_inset>(mut self, inset: P) -> WindowBuilder {
+ self.platform_specific.traffic_light_inset = Some(inset.into());
+ self
+ }
+
+ #[inline]
+ fn with_automatic_window_tabbing(mut self, automatic_tabbing: bool) -> WindowBuilder {
+ self.platform_specific.automatic_tabbing = automatic_tabbing;
+ self
+ }
+
+ #[inline]
+ fn with_tabbing_identifier(mut self, tabbing_identifier: &str) -> WindowBuilder {
+ self
+ .platform_specific
+ .tabbing_identifier
+ .replace(tabbing_identifier.into());
+ self
+ }
+}
+
+pub trait EventLoopExtMacOS {
+ /// Sets the activation policy for the application. It is set to
+ /// `NSApplicationActivationPolicyRegular` by default.
+ ///
+ /// This function only takes effect if it's called before calling
+ /// [`run`](crate::event_loop::EventLoop::run) or
+ /// [`run_return`](crate::platform::run_return::EventLoopExtRunReturn::run_return).
+ /// To set the activation policy after that, use
+ /// [`EventLoopWindowTargetExtMacOS::set_activation_policy_at_runtime`](crate::platform::macos::EventLoopWindowTargetExtMacOS::set_activation_policy_at_runtime).
+ fn set_activation_policy(&mut self, activation_policy: ActivationPolicy);
+
+ /// Sets the visibility of the application in the dock.
+ ///
+ /// This function only takes effect if it's called before calling
+ /// [`run`](crate::event_loop::EventLoop::run) or
+ /// [`run_return`](crate::platform::run_return::EventLoopExtRunReturn::run_return).
+ fn set_dock_visibility(&mut self, visible: bool);
+
+ /// Used to prevent the application from automatically activating when launched if
+ /// another application is already active
+ ///
+ /// The default behavior is to ignore other applications and activate when launched.
+ ///
+ /// This function only takes effect if it's called before calling
+ /// [`run`](crate::event_loop::EventLoop::run) or
+ /// [`run_return`](crate::platform::run_return::EventLoopExtRunReturn::run_return)
+ fn set_activate_ignoring_other_apps(&mut self, ignore: bool);
+}
+
+impl EventLoopExtMacOS for EventLoop {
+ #[inline]
+ fn set_activation_policy(&mut self, activation_policy: ActivationPolicy) {
+ unsafe {
+ get_aux_state_mut(&**self.event_loop.delegate).activation_policy = activation_policy;
+ }
+ }
+
+ #[inline]
+ fn set_dock_visibility(&mut self, visible: bool) {
+ unsafe {
+ get_aux_state_mut(&**self.event_loop.delegate).dock_visibility = visible;
+ }
+ }
+
+ #[inline]
+ fn set_activate_ignoring_other_apps(&mut self, ignore: bool) {
+ unsafe {
+ get_aux_state_mut(&**self.event_loop.delegate).activate_ignoring_other_apps = ignore;
+ }
+ }
+}
+
+/// Additional methods on `MonitorHandle` that are specific to MacOS.
+pub trait MonitorHandleExtMacOS {
+ /// Returns the identifier of the monitor for Cocoa.
+ fn native_id(&self) -> u32;
+ /// Returns a pointer to the NSScreen representing this monitor.
+ fn ns_screen(&self) -> Option<*mut c_void>;
+}
+
+impl MonitorHandleExtMacOS for MonitorHandle {
+ #[inline]
+ fn native_id(&self) -> u32 {
+ self.inner.native_identifier()
+ }
+
+ fn ns_screen(&self) -> Option<*mut c_void> {
+ self
+ .inner
+ .ns_screen()
+ .map(|s| objc2::rc::Retained::into_raw(s) as *mut c_void)
+ }
+}
+
+/// Additional methods on `EventLoopWindowTarget` that are specific to macOS.
+pub trait EventLoopWindowTargetExtMacOS {
+ /// Hide the entire application. In most applications this is typically triggered with Command-H.
+ fn hide_application(&self);
+ /// Show the entire application.
+ fn show_application(&self);
+ /// Hide the other applications. In most applications this is typically triggered with Command+Option-H.
+ fn hide_other_applications(&self);
+ /// Sets the activation policy for the application. It is set to
+ /// `NSApplicationActivationPolicyRegular` by default.
+ ///
+ /// To set the activation policy before the app starts running, see
+ /// [`EventLoopExtMacOS::set_activation_policy`](crate::platform::macos::EventLoopExtMacOS::set_activation_policy).
+ fn set_activation_policy_at_runtime(&self, activation_policy: ActivationPolicy);
+
+ /// Sets the visibility of the application in the dock.
+ ///
+ /// To set the dock visibility before the app starts running, see
+ /// [`EventLoopExtMacOS::set_dock_visibility`](crate::platform::macos::EventLoopExtMacOS::set_dock_visibility).
+ fn set_dock_visibility(&self, visible: bool);
+
+ /// Sets the badge label on macos dock
+ fn set_badge_label(&self, label: Option);
+}
+
+impl EventLoopWindowTargetExtMacOS for EventLoopWindowTarget {
+ fn hide_application(&self) {
+ // TODO: Safety.
+ let mtm = unsafe { objc2_foundation::MainThreadMarker::new_unchecked() };
+ objc2_app_kit::NSApplication::sharedApplication(mtm).hide(None)
+ }
+
+ fn show_application(&self) {
+ // TODO: Safety.
+ let mtm = unsafe { objc2_foundation::MainThreadMarker::new_unchecked() };
+ unsafe { objc2_app_kit::NSApplication::sharedApplication(mtm).unhide(None) }
+ }
+
+ fn hide_other_applications(&self) {
+ // TODO: Safety.
+ let mtm = unsafe { objc2_foundation::MainThreadMarker::new_unchecked() };
+ objc2_app_kit::NSApplication::sharedApplication(mtm).hideOtherApplications(None)
+ }
+
+ fn set_activation_policy_at_runtime(&self, activation_policy: ActivationPolicy) {
+ use objc2_app_kit::NSApplicationActivationPolicy;
+
+ let ns_activation_policy = match activation_policy {
+ ActivationPolicy::Regular => NSApplicationActivationPolicy::Regular,
+ ActivationPolicy::Accessory => NSApplicationActivationPolicy::Accessory,
+ ActivationPolicy::Prohibited => NSApplicationActivationPolicy::Prohibited,
+ };
+
+ // TODO: Safety.
+ let mtm = unsafe { objc2_foundation::MainThreadMarker::new_unchecked() };
+ objc2_app_kit::NSApplication::sharedApplication(mtm).setActivationPolicy(ns_activation_policy);
+ }
+
+ fn set_dock_visibility(&self, visible: bool) {
+ let Some(Ok(delegate)) = (unsafe {
+ // TODO: Safety.
+ let mtm = objc2_foundation::MainThreadMarker::new_unchecked();
+ objc2_app_kit::NSApplication::sharedApplication(mtm)
+ .delegate()
+ .map(|delegate| delegate.downcast::())
+ }) else {
+ return;
+ };
+ set_dock_visibility(&delegate, visible);
+ }
+
+ fn set_badge_label(&self, label: Option) {
+ set_badge_label(label);
+ }
+}
diff --git a/frontend/src-tauri/patches/tao-0.35.2/src/platform/mod.rs b/frontend/src-tauri/patches/tao-0.35.2/src/platform/mod.rs
new file mode 100644
index 000000000..2ca20b36d
--- /dev/null
+++ b/frontend/src-tauri/patches/tao-0.35.2/src/platform/mod.rs
@@ -0,0 +1,28 @@
+// Copyright 2014-2021 The winit contributors
+// Copyright 2021-2023 Tauri Programme within The Commons Conservancy
+// SPDX-License-Identifier: Apache-2.0
+
+//! Contains traits with platform-specific methods in them.
+//!
+//! Contains the follow OS-specific modules:
+//!
+//! - `android`
+//! - `ios`
+//! - `macos`
+//! - `unix`
+//! - `linux`
+//! - `windows`
+//!
+//! And the following platform-specific module:
+//!
+//! - `run_return` (available on `windows`, `unix`, `macos`, and `android`)
+//!
+//! However only the module corresponding to the platform you're compiling to will be available.
+
+pub mod android;
+pub mod ios;
+pub mod linux;
+pub mod macos;
+pub mod run_return;
+pub mod unix;
+pub mod windows;
diff --git a/frontend/src-tauri/patches/tao-0.35.2/src/platform/run_return.rs b/frontend/src-tauri/patches/tao-0.35.2/src/platform/run_return.rs
new file mode 100644
index 000000000..e86ae1f6a
--- /dev/null
+++ b/frontend/src-tauri/patches/tao-0.35.2/src/platform/run_return.rs
@@ -0,0 +1,50 @@
+// Copyright 2014-2021 The winit contributors
+// Copyright 2021-2023 Tauri Programme within The Commons Conservancy
+// SPDX-License-Identifier: Apache-2.0
+
+#![cfg(not(target_os = "ios"))]
+
+use crate::{
+ event::Event,
+ event_loop::{ControlFlow, EventLoop, EventLoopWindowTarget},
+};
+
+/// Additional methods on `EventLoop` to return control flow to the caller.
+pub trait EventLoopExtRunReturn {
+ /// A type provided by the user that can be passed through `Event::UserEvent`.
+ type UserEvent;
+
+ /// Initializes the `tao` event loop.
+ ///
+ /// Unlike `run`, this function accepts non-`'static` (i.e. non-`move`) closures and returns
+ /// control flow to the caller when `control_flow` is set to `ControlFlow::Exit`.
+ ///
+ /// # Caveats
+ /// Despite its appearance at first glance, this is *not* a perfect replacement for
+ /// `poll_events`. For example, this function will not return on Windows or macOS while a
+ /// window is getting resized, resulting in all application logic outside of the
+ /// `event_handler` closure not running until the resize operation ends. Other OS operations
+ /// may also result in such freezes. This behavior is caused by fundamental limitations in the
+ /// underlying OS APIs, which cannot be hidden by `tao` without severe stability repercussions.
+ ///
+ /// You are strongly encouraged to use `run`, unless the use of this is absolutely necessary.
+ ///
+ /// ## Platform-specific
+ ///
+ /// - **Unix-alikes** (**X11** or **Wayland**): This function returns `1` upon disconnection from
+ /// the display server.
+ fn run_return(&mut self, event_handler: F) -> i32
+ where
+ F: FnMut(Event<'_, Self::UserEvent>, &EventLoopWindowTarget, &mut ControlFlow);
+}
+
+impl EventLoopExtRunReturn for EventLoop {
+ type UserEvent = T;
+
+ fn run_return(&mut self, event_handler: F) -> i32
+ where
+ F: FnMut(Event<'_, Self::UserEvent>, &EventLoopWindowTarget, &mut ControlFlow),
+ {
+ self.event_loop.run_return(event_handler)
+ }
+}
diff --git a/frontend/src-tauri/patches/tao-0.35.2/src/platform/unix.rs b/frontend/src-tauri/patches/tao-0.35.2/src/platform/unix.rs
new file mode 100644
index 000000000..c96fb9361
--- /dev/null
+++ b/frontend/src-tauri/patches/tao-0.35.2/src/platform/unix.rs
@@ -0,0 +1,308 @@
+// Copyright 2014-2021 The winit contributors
+// Copyright 2021-2023 Tauri Programme within The Commons Conservancy
+// SPDX-License-Identifier: Apache-2.0
+
+#![cfg(any(
+ target_os = "linux",
+ target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "netbsd",
+ target_os = "openbsd"
+))]
+
+#[cfg(feature = "x11")]
+use std::{os::raw::c_int, sync::Arc};
+
+// XConnection utilities
+#[doc(hidden)]
+#[cfg(feature = "x11")]
+pub use crate::platform_impl::x11;
+
+#[cfg(feature = "x11")]
+use crate::platform_impl::x11::xdisplay::XError;
+pub use crate::platform_impl::EventLoop as UnixEventLoop;
+use crate::{
+ error::{ExternalError, OsError},
+ event_loop::{EventLoopBuilder, EventLoopWindowTarget},
+ monitor::MonitorHandle,
+ platform_impl::{Parent, Window as UnixWindow},
+ window::{Window, WindowBuilder},
+};
+
+#[cfg(feature = "x11")]
+use self::x11::xdisplay::XConnection;
+
+/// Additional methods on `EventLoop` that are specific to Unix.
+pub trait EventLoopBuilderExtUnix {
+ /// Whether to allow the event loop to be created off of the main thread.
+ ///
+ /// By default, the window is only allowed to be created on the main
+ /// thread, to make platform compatibility easier.
+ ///
+ /// # `Window` caveats
+ ///
+ /// Note that any `Window` created on the new thread will be destroyed when the thread
+ /// terminates. Attempting to use a `Window` after its parent thread terminates has
+ /// unspecified, although explicitly not undefined, behavior.
+ fn with_any_thread(&mut self, any_thread: bool) -> &mut Self;
+
+ /// Set the gtk application id.
+ ///
+ /// If no application ID is given then some features (most notably application uniqueness) will be disabled.
+ fn with_app_id>(&mut self, id: S) -> &mut Self;
+}
+
+impl EventLoopBuilderExtUnix for EventLoopBuilder {
+ #[inline]
+ fn with_any_thread(&mut self, any_thread: bool) -> &mut Self {
+ self.platform_specific.any_thread = any_thread;
+ self
+ }
+
+ fn with_app_id>(&mut self, id: S) -> &mut Self {
+ self.platform_specific.app_id = Some(id.into());
+ self
+ }
+}
+
+/// Additional methods on `Window` that are specific to Unix.
+pub trait WindowExtUnix {
+ /// Create a new Tao window from an existing GTK window. Generally you should use
+ /// the non-Linux `WindowBuilder`, this is for those who need lower level window access
+ /// and know what they're doing.
+ fn new_from_gtk_window(
+ event_loop_window_target: &EventLoopWindowTarget,
+ window: gtk::ApplicationWindow,
+ ) -> Result;
+
+ /// Returns the `gtk::ApplicatonWindow` from gtk crate that is used by this window.
+ fn gtk_window(&self) -> >k::ApplicationWindow;
+
+ /// Returns the vertical `gtk::Box` that is added by default as the sole child of this window.
+ /// Returns `None` if the default vertical `gtk::Box` creation was disabled by [`WindowBuilderExtUnix::with_default_vbox`].
+ fn default_vbox(&self) -> Option<>k::Box>;
+
+ /// Whether to show the window icon in the taskbar or not.
+ fn set_skip_taskbar(&self, skip: bool) -> Result<(), ExternalError>;
+
+ fn set_badge_count(&self, count: Option, desktop_filename: Option);
+}
+
+impl WindowExtUnix for Window {
+ fn gtk_window(&self) -> >k::ApplicationWindow {
+ &self.window.window
+ }
+
+ fn default_vbox(&self) -> Option<>k::Box> {
+ self.window.default_vbox.as_ref()
+ }
+
+ fn set_skip_taskbar(&self, skip: bool) -> Result<(), ExternalError> {
+ self.window.set_skip_taskbar(skip)
+ }
+
+ fn new_from_gtk_window(
+ event_loop_window_target: &EventLoopWindowTarget,
+ window: gtk::ApplicationWindow,
+ ) -> Result {
+ let window = UnixWindow::new_from_gtk_window(&event_loop_window_target.p, window)?;
+ Ok(Window { window })
+ }
+
+ fn set_badge_count(&self, count: Option, desktop_filename: Option) {
+ self.window.set_badge_count(count, desktop_filename);
+ }
+}
+
+pub trait WindowBuilderExtUnix {
+ /// Whether to create the window icon with the taskbar icon or not.
+ fn with_skip_taskbar(self, skip: bool) -> WindowBuilder;
+ /// Set this window as a transient dialog for `parent`
+ ///
+ fn with_transient_for(self, parent: &impl gtk::glib::IsA) -> WindowBuilder;
+
+ /// Whether to enable or disable the internal draw for transparent window.
+ ///
+ /// When tranparent attribute is enabled, we will call `connect_draw` and draw a transparent background.
+ /// For anyone who wants to draw the background themselves, set this to `false`.
+ /// Default is `true`.
+ fn with_transparent_draw(self, draw: bool) -> WindowBuilder;
+
+ /// Whether to enable or disable the double buffered rendering of the window.
+ ///
+ /// Default is `true`.
+ fn with_double_buffered(self, double_buffered: bool) -> WindowBuilder;
+
+ /// Whether to enable the rgba visual for the window.
+ ///
+ /// Default is `false` but is always `true` if [`WindowAttributes::transparent`](crate::window::WindowAttributes::transparent) is `true`
+ fn with_rgba_visual(self, rgba_visual: bool) -> WindowBuilder;
+
+ /// Wether to set this window as app paintable
+ ///
+ ///
+ ///
+ /// Default is `false` but is always `true` if [`WindowAttributes::transparent`](crate::window::WindowAttributes::transparent) is `true`
+ fn with_app_paintable(self, app_paintable: bool) -> WindowBuilder;
+
+ /// Whether to set cursor moved event. Cursor event is suited for native GUI frameworks and
+ /// games. But it can block gtk's own pipeline occasionally. Turn this off can help Gtk looks
+ /// smoother.
+ ///
+ /// Default is `true`.
+ fn with_cursor_moved_event(self, cursor_moved: bool) -> WindowBuilder;
+
+ /// Whether to create a vertical `gtk::Box` and add it as the sole child of this window.
+ /// Created by default.
+ fn with_default_vbox(self, add: bool) -> WindowBuilder;
+}
+
+impl WindowBuilderExtUnix for WindowBuilder {
+ fn with_skip_taskbar(mut self, skip: bool) -> WindowBuilder {
+ self.platform_specific.skip_taskbar = skip;
+ self
+ }
+
+ fn with_transient_for(mut self, parent: &impl gtk::glib::IsA) -> WindowBuilder {
+ use gtk::glib::Cast;
+ self.platform_specific.parent = Parent::ChildOf(parent.clone().upcast());
+ self
+ }
+
+ fn with_transparent_draw(mut self, draw: bool) -> WindowBuilder {
+ self.platform_specific.auto_transparent = draw;
+ self
+ }
+
+ fn with_double_buffered(mut self, double_buffered: bool) -> WindowBuilder {
+ self.platform_specific.double_buffered = double_buffered;
+ self
+ }
+
+ fn with_rgba_visual(mut self, rgba_visual: bool) -> WindowBuilder {
+ self.platform_specific.rgba_visual = rgba_visual;
+ self
+ }
+
+ fn with_app_paintable(mut self, app_paintable: bool) -> WindowBuilder {
+ self.platform_specific.app_paintable = app_paintable;
+ self
+ }
+
+ fn with_cursor_moved_event(mut self, cursor_moved: bool) -> WindowBuilder {
+ self.platform_specific.cursor_moved = cursor_moved;
+ self
+ }
+
+ fn with_default_vbox(mut self, add: bool) -> WindowBuilder {
+ self.platform_specific.default_vbox = add;
+ self
+ }
+}
+
+/// Additional methods on `EventLoopWindowTarget` that are specific to Unix.
+pub trait EventLoopWindowTargetExtUnix {
+ /// True if the `EventLoopWindowTarget` uses Wayland.
+ fn is_wayland(&self) -> bool;
+
+ /// True if the `EventLoopWindowTarget` uses X11.
+ #[cfg(feature = "x11")]
+ fn is_x11(&self) -> bool;
+
+ #[cfg(feature = "x11")]
+ fn xlib_xconnection(&self) -> Option>;
+
+ // /// Returns a pointer to the `wl_display` object of wayland that is used by this
+ // /// `EventLoopWindowTarget`.
+ // ///
+ // /// Returns `None` if the `EventLoop` doesn't use wayland (if it uses xlib for example).
+ // ///
+ // /// The pointer will become invalid when the winit `EventLoop` is destroyed.
+ // fn wayland_display(&self) -> Option<*mut raw::c_void>;
+
+ /// Returns the gtk application for this event loop.
+ fn gtk_app(&self) -> >k::Application;
+
+ /// Sets the badge count on the taskbar
+ fn set_badge_count(&self, count: Option, desktop_filename: Option);
+}
+
+impl EventLoopWindowTargetExtUnix for EventLoopWindowTarget {
+ #[inline]
+ fn is_wayland(&self) -> bool {
+ self.p.is_wayland()
+ }
+
+ #[cfg(feature = "x11")]
+ #[inline]
+ fn is_x11(&self) -> bool {
+ !self.p.is_wayland()
+ }
+
+ #[cfg(feature = "x11")]
+ #[inline]
+ fn xlib_xconnection(&self) -> Option> {
+ if self.is_x11() {
+ if let Ok(xconn) = XConnection::new(Some(x_error_callback)) {
+ Some(Arc::new(xconn))
+ } else {
+ None
+ }
+ } else {
+ None
+ }
+ }
+
+ // #[inline]
+ // fn wayland_display(&self) -> Option<*mut raw::c_void> {
+ // match self.p {
+ // LinuxEventLoopWindowTarget::Wayland(ref p) => {
+ // Some(p.display().get_display_ptr() as *mut _)
+ // }
+ // #[cfg(feature = "x11")]
+ // _ => None,
+ // }
+ // }
+
+ #[inline]
+ fn gtk_app(&self) -> >k::Application {
+ &self.p.app
+ }
+
+ #[inline]
+ fn set_badge_count(&self, count: Option, desktop_filename: Option) {
+ self.p.set_badge_count(count, desktop_filename);
+ }
+}
+
+#[cfg(feature = "x11")]
+unsafe extern "C" fn x_error_callback(
+ _display: *mut x11::ffi::Display,
+ event: *mut x11::ffi::XErrorEvent,
+) -> c_int {
+ let error = XError {
+ // TODO get the error text as description
+ description: String::new(),
+ error_code: (*event).error_code,
+ request_code: (*event).request_code,
+ minor_code: (*event).minor_code,
+ };
+
+ error!("X11 error: {:#?}", error);
+
+ // Fun fact: this return value is completely ignored.
+ 0
+}
+
+/// Additional methods on `MonitorHandle` that are specific to Unix.
+pub trait MonitorHandleExtUnix {
+ /// Returns the gdk handle of the monitor.
+ fn gdk_monitor(&self) -> >k::gdk::Monitor;
+}
+
+impl MonitorHandleExtUnix for MonitorHandle {
+ #[inline]
+ fn gdk_monitor(&self) -> >k::gdk::Monitor {
+ &self.inner.monitor
+ }
+}
diff --git a/frontend/src-tauri/patches/tao-0.35.2/src/platform/windows.rs b/frontend/src-tauri/patches/tao-0.35.2/src/platform/windows.rs
new file mode 100644
index 000000000..a248b04b3
--- /dev/null
+++ b/frontend/src-tauri/patches/tao-0.35.2/src/platform/windows.rs
@@ -0,0 +1,449 @@
+// Copyright 2014-2021 The tao contributors
+// Copyright 2021-2023 Tauri Programme within The Commons Conservancy
+// SPDX-License-Identifier: Apache-2.0
+
+#![cfg(target_os = "windows")]
+
+use std::path::Path;
+
+use crate::{
+ dpi::PhysicalSize,
+ error::ExternalError,
+ event::DeviceId,
+ event_loop::EventLoopBuilder,
+ monitor::MonitorHandle,
+ platform_impl::{Parent, WinIcon},
+ window::{BadIcon, Icon, Theme, Window, WindowBuilder},
+};
+use windows::Win32::UI::Input::KeyboardAndMouse::*;
+
+pub type HWND = isize;
+pub type HMENU = isize;
+
+/// Additional methods on `EventLoop` that are specific to Windows.
+pub trait EventLoopBuilderExtWindows {
+ /// Whether to allow the event loop to be created off of the main thread.
+ ///
+ /// By default, the window is only allowed to be created on the main
+ /// thread, to make platform compatibility easier.
+ ///
+ /// # `Window` caveats
+ ///
+ /// Note that any `Window` created on the new thread will be destroyed when the thread
+ /// terminates. Attempting to use a `Window` after its parent thread terminates has
+ /// unspecified, although explicitly not undefined, behavior.
+ fn with_any_thread(&mut self, any_thread: bool) -> &mut Self;
+
+ /// Whether to enable process-wide DPI awareness.
+ ///
+ /// By default, `tao` will attempt to enable process-wide DPI awareness. If
+ /// that's undesirable, you can disable it with this function.
+ ///
+ /// # Example
+ ///
+ /// Disable process-wide DPI awareness.
+ ///
+ /// ```
+ /// use tao::event_loop::EventLoopBuilder;
+ /// #[cfg(target_os = "windows")]
+ /// use tao::platform::windows::EventLoopBuilderExtWindows;
+ ///
+ /// let mut builder = EventLoopBuilder::new();
+ /// #[cfg(target_os = "windows")]
+ /// builder.with_dpi_aware(false);
+ /// # if false { // We can't test this part
+ /// let event_loop = builder.build();
+ /// # }
+ /// ```
+ fn with_dpi_aware(&mut self, dpi_aware: bool) -> &mut Self;
+
+ /// A callback to be executed before dispatching a win32 message to the window procedure.
+ /// Return true to disable tao's internal message dispatching.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// # use windows::Win32::UI::WindowsAndMessaging::{ACCEL, CreateAcceleratorTableW, TranslateAcceleratorW, DispatchMessageW, TranslateMessage, MSG};
+ /// use tao::event_loop::EventLoopBuilder;
+ /// #[cfg(target_os = "windows")]
+ /// use tao::platform::windows::EventLoopBuilderExtWindows;
+ ///
+ /// let mut builder = EventLoopBuilder::new();
+ /// #[cfg(target_os = "windows")]
+ /// builder.with_msg_hook(|msg|{
+ /// let msg = msg as *const MSG;
+ /// # let accels_: Vec = Vec::new();
+ /// # let accels = accels_.as_slice();
+ /// let translated = unsafe {
+ /// TranslateAcceleratorW(
+ /// (*msg).hwnd,
+ /// CreateAcceleratorTableW(accels).unwrap(),
+ /// msg,
+ /// ) == 1
+ /// };
+ /// translated
+ /// });
+ /// ```
+ fn with_msg_hook(&mut self, callback: F) -> &mut Self
+ where
+ F: FnMut(*const std::ffi::c_void) -> bool + 'static;
+
+ /// Forces a theme or uses the system settings if `None` was provided.
+ ///
+ /// This will only affect some controls like context menus.
+ ///
+ /// ## Note
+ ///
+ /// Since this setting is app-wide, using [`WindowBuilder::with_theme`]
+ /// will not change the affected controls for that specific window,
+ /// so it is recommended to always use the same theme used for this app-wide setting
+ /// or use `None` so it automatically uses the theme of this method
+ /// or falls back to the system preference.
+ fn with_theme(&mut self, theme: Option) -> &mut Self;
+}
+
+impl EventLoopBuilderExtWindows for EventLoopBuilder {
+ #[inline]
+ fn with_any_thread(&mut self, any_thread: bool) -> &mut Self {
+ self.platform_specific.any_thread = any_thread;
+ self
+ }
+
+ #[inline]
+ fn with_dpi_aware(&mut self, dpi_aware: bool) -> &mut Self {
+ self.platform_specific.dpi_aware = dpi_aware;
+ self
+ }
+
+ #[inline]
+ fn with_msg_hook(&mut self, callback: F) -> &mut Self
+ where
+ F: FnMut(*const std::ffi::c_void) -> bool + 'static,
+ {
+ self.platform_specific.msg_hook = Some(Box::new(callback));
+ self
+ }
+
+ #[inline]
+ fn with_theme(&mut self, theme: Option) -> &mut Self {
+ self.platform_specific.preferred_theme = theme;
+ self
+ }
+}
+
+/// Additional methods on `Window` that are specific to Windows.
+pub trait WindowExtWindows {
+ /// Returns the HINSTANCE of the window
+ fn hinstance(&self) -> isize;
+ /// Returns the native handle that is used by this window.
+ ///
+ /// The pointer will become invalid when the native window was destroyed.
+ fn hwnd(&self) -> isize;
+
+ /// Enables or disables mouse and keyboard input to the specified window.
+ ///
+ /// A window must be enabled before it can be activated.
+ /// If an application has create a modal dialog box by disabling its owner window
+ /// (as described in [`WindowBuilderExtWindows::with_owner_window`]), the application must enable
+ /// the owner window before destroying the dialog box.
+ /// Otherwise, another window will receive the keyboard focus and be activated.
+ ///
+ /// If a child window is disabled, it is ignored when the system tries to determine which
+ /// window should receive mouse messages.
+ ///
+ /// For more information, see
+ /// and
+ fn set_enable(&self, enabled: bool);
+
+ /// This sets `ICON_BIG`. A good ceiling here is 256x256.
+ fn set_taskbar_icon(&self, taskbar_icon: Option);
+
+ /// This sets the overlay icon
+ fn set_overlay_icon(&self, icon: Option<&Icon>);
+
+ /// Returns the current window theme.
+ fn theme(&self) -> Theme;
+
+ /// Reset the dead key state of the keyboard.
+ ///
+ /// This is useful when a dead key is bound to trigger an action. Then
+ /// this function can be called to reset the dead key state so that
+ /// follow-up text input won't be affected by the dead key.
+ fn reset_dead_keys(&self);
+
+ /// Starts the resizing drag from given edge
+ fn begin_resize_drag(&self, edge: isize, button: u32, x: i32, y: i32);
+
+ /// Whether to show the window icon in the taskbar or not.
+ fn set_skip_taskbar(&self, skip: bool) -> Result<(), ExternalError>;
+
+ /// Shows or hides the background drop shadow for undecorated windows.
+ ///
+ /// Enabling the shadow causes a thin 1px line to appear on the top of the window.
+ fn set_undecorated_shadow(&self, shadow: bool);
+
+ /// Returns whether this window has shadow for undecorated windows.
+ fn has_undecorated_shadow(&self) -> bool;
+
+ /// Sets right-to-left layout.
+ ///
+ /// Enabling this mainly flips the orientation of menus and title bar buttons
+ fn set_rtl(&self, rtl: bool);
+}
+
+impl WindowExtWindows for Window {
+ #[inline]
+ fn hinstance(&self) -> isize {
+ self.window.hinstance().0 as _
+ }
+
+ #[inline]
+ fn hwnd(&self) -> isize {
+ self.window.hwnd().0 as _
+ }
+
+ #[inline]
+ fn set_enable(&self, enabled: bool) {
+ unsafe {
+ let _ = EnableWindow(self.window.hwnd(), enabled);
+ }
+ }
+
+ #[inline]
+ fn set_taskbar_icon(&self, taskbar_icon: Option) {
+ self.window.set_taskbar_icon(taskbar_icon)
+ }
+
+ #[inline]
+ fn theme(&self) -> Theme {
+ self.window.theme()
+ }
+
+ #[inline]
+ fn reset_dead_keys(&self) {
+ self.window.reset_dead_keys();
+ }
+
+ #[inline]
+ fn begin_resize_drag(&self, edge: isize, button: u32, x: i32, y: i32) {
+ self.window.begin_resize_drag(edge, button, x, y)
+ }
+
+ #[inline]
+ fn set_skip_taskbar(&self, skip: bool) -> Result<(), ExternalError> {
+ self.window.set_skip_taskbar(skip)
+ }
+
+ #[inline]
+ fn set_undecorated_shadow(&self, shadow: bool) {
+ self.window.set_undecorated_shadow(shadow)
+ }
+
+ #[inline]
+ fn has_undecorated_shadow(&self) -> bool {
+ self.window.has_undecorated_shadow()
+ }
+
+ #[inline]
+ fn set_rtl(&self, rtl: bool) {
+ self.window.set_rtl(rtl)
+ }
+
+ #[inline]
+ fn set_overlay_icon(&self, icon: Option<&Icon>) {
+ self.window.set_overlay_icon(icon);
+ }
+}
+
+/// Additional methods on `WindowBuilder` that are specific to Windows.
+pub trait WindowBuilderExtWindows {
+ /// Sets a parent to the window to be created.
+ ///
+ /// A child window has the WS_CHILD style and is confined to the client area of its parent window.
+ ///
+ /// For more information, see
+ fn with_parent_window(self, parent: HWND) -> WindowBuilder;
+
+ /// Set an owner to the window to be created. Can be used to create a dialog box, for example.
+ /// Can be used in combination with [`WindowExtWindows::set_enable(false)`](WindowExtWindows::set_enable)
+ /// on the owner window to create a modal dialog box.
+ ///
+ /// From MSDN:
+ /// - An owned window is always above its owner in the z-order.
+ /// - The system automatically destroys an owned window when its owner is destroyed.
+ /// - An owned window is hidden when its owner is minimized.
+ ///
+ /// For more information, see
+ fn with_owner_window(self, parent: HWND) -> WindowBuilder;
+
+ /// Sets a menu on the window to be created.
+ ///
+ /// Parent and menu are mutually exclusive; a child window cannot have a menu!
+ ///
+ /// The menu must have been manually created beforehand with [`windows::Win32::UI::WindowsAndMessaging::CreateMenu`]
+ /// or similar.
+ ///
+ /// Note: Dark mode cannot be supported for win32 menus, it's simply not possible to change how the menus look.
+ /// If you use this, it is recommended that you combine it with `with_theme(Some(Theme::Light))` to avoid a jarring effect.
+ fn with_menu(self, menu: HMENU) -> WindowBuilder;
+
+ /// This sets `ICON_BIG`. A good ceiling here is 256x256.
+ fn with_taskbar_icon(self, taskbar_icon: Option) -> WindowBuilder;
+
+ /// This sets `WS_EX_NOREDIRECTIONBITMAP`.
+ fn with_no_redirection_bitmap(self, flag: bool) -> WindowBuilder;
+
+ /// Enables or disables drag and drop support (enabled by default). Will interfere with other crates
+ /// that use multi-threaded COM API (`CoInitializeEx` with `COINIT_MULTITHREADED` instead of
+ /// `COINIT_APARTMENTTHREADED`) on the same thread. Note that tao may still attempt to initialize
+ /// COM API regardless of this option. Currently only fullscreen mode does that, but there may be more in the future.
+ /// If you need COM API with `COINIT_MULTITHREADED` you must initialize it before calling any tao functions.
+ /// See for more information.
+ fn with_drag_and_drop(self, flag: bool) -> WindowBuilder;
+
+ /// Whether to create the window icon with the taskbar icon or not.
+ fn with_skip_taskbar(self, skip: bool) -> WindowBuilder;
+
+ /// Customize the window class name.
+ fn with_window_classname>(self, classname: S) -> WindowBuilder;
+
+ /// Shows or hides the background drop shadow for undecorated windows.
+ ///
+ /// The shadow is hidden by default.
+ /// Enabling the shadow causes a thin 1px line to appear on the top of the window.
+ fn with_undecorated_shadow(self, shadow: bool) -> WindowBuilder;
+
+ /// Sets right-to-left layout.
+ fn with_rtl(self, rtl: bool) -> WindowBuilder;
+}
+
+impl WindowBuilderExtWindows for WindowBuilder {
+ #[inline]
+ fn with_parent_window(mut self, parent: HWND) -> WindowBuilder {
+ self.platform_specific.parent = Parent::ChildOf(windows::Win32::Foundation::HWND(parent as _));
+ self
+ }
+
+ #[inline]
+ fn with_owner_window(mut self, parent: HWND) -> WindowBuilder {
+ self.platform_specific.parent = Parent::OwnedBy(windows::Win32::Foundation::HWND(parent as _));
+ self
+ }
+
+ #[inline]
+ fn with_menu(mut self, menu: HMENU) -> WindowBuilder {
+ self.platform_specific.menu = Some(windows::Win32::UI::WindowsAndMessaging::HMENU(menu as _));
+ self
+ }
+
+ #[inline]
+ fn with_taskbar_icon(mut self, taskbar_icon: Option) -> WindowBuilder {
+ self.platform_specific.taskbar_icon = taskbar_icon;
+ self
+ }
+
+ #[inline]
+ fn with_no_redirection_bitmap(mut self, flag: bool) -> WindowBuilder {
+ self.platform_specific.no_redirection_bitmap = flag;
+ self
+ }
+
+ #[inline]
+ fn with_drag_and_drop(mut self, flag: bool) -> WindowBuilder {
+ self.platform_specific.drag_and_drop = flag;
+ self
+ }
+
+ #[inline]
+ fn with_skip_taskbar(mut self, skip: bool) -> WindowBuilder {
+ self.platform_specific.skip_taskbar = skip;
+ self
+ }
+
+ #[inline]
+ fn with_window_classname>(mut self, classname: S) -> WindowBuilder {
+ self.platform_specific.window_classname = classname.into();
+ self
+ }
+
+ #[inline]
+ fn with_undecorated_shadow(mut self, shadow: bool) -> WindowBuilder {
+ self.platform_specific.decoration_shadow = shadow;
+ self
+ }
+
+ #[inline]
+ fn with_rtl(mut self, rtl: bool) -> WindowBuilder {
+ self.platform_specific.rtl = rtl;
+ self
+ }
+}
+
+/// Additional methods on `MonitorHandle` that are specific to Windows.
+pub trait MonitorHandleExtWindows {
+ /// Returns the name of the monitor adapter specific to the Win32 API.
+ fn native_id(&self) -> String;
+
+ /// Returns the handle of the monitor - `HMONITOR`.
+ fn hmonitor(&self) -> isize;
+}
+
+impl MonitorHandleExtWindows for MonitorHandle {
+ #[inline]
+ fn native_id(&self) -> String {
+ self.inner.native_identifier()
+ }
+
+ #[inline]
+ fn hmonitor(&self) -> isize {
+ self.inner.hmonitor().0 as _
+ }
+}
+
+/// Additional methods on `DeviceId` that are specific to Windows.
+pub trait DeviceIdExtWindows {
+ /// Returns an identifier that persistently refers to this specific device.
+ ///
+ /// Will return `None` if the device is no longer available.
+ fn persistent_identifier(&self) -> Option;
+}
+
+impl DeviceIdExtWindows for DeviceId {
+ #[inline]
+ fn persistent_identifier(&self) -> Option {
+ self.0.persistent_identifier()
+ }
+}
+
+/// Additional methods on `Icon` that are specific to Windows.
+pub trait IconExtWindows: Sized {
+ /// Create an icon from a file path.
+ ///
+ /// Specify `size` to load a specific icon size from the file, or `None` to load the default
+ /// icon size from the file.
+ ///
+ /// In cases where the specified size does not exist in the file, Windows may perform scaling
+ /// to get an icon of the desired size.
+ fn from_path>(path: P, size: Option>) -> Result;
+
+ /// Create an icon from a resource embedded in this executable or library.
+ ///
+ /// Specify `size` to load a specific icon size from the file, or `None` to load the default
+ /// icon size from the file.
+ ///
+ /// In cases where the specified size does not exist in the file, Windows may perform scaling
+ /// to get an icon of the desired size.
+ fn from_resource(ordinal: u16, size: Option>) -> Result;
+}
+
+impl IconExtWindows for Icon {
+ fn from_path>(path: P, size: Option>) -> Result {
+ let win_icon = WinIcon::from_path(path, size)?;
+ Ok(Icon { inner: win_icon })
+ }
+
+ fn from_resource(ordinal: u16, size: Option>) -> Result {
+ let win_icon = WinIcon::from_resource(ordinal, size)?;
+ Ok(Icon { inner: win_icon })
+ }
+}
diff --git a/frontend/src-tauri/patches/tao-0.35.2/src/platform_impl/android/mod.rs b/frontend/src-tauri/patches/tao-0.35.2/src/platform_impl/android/mod.rs
new file mode 100644
index 000000000..b78113853
--- /dev/null
+++ b/frontend/src-tauri/patches/tao-0.35.2/src/platform_impl/android/mod.rs
@@ -0,0 +1,1490 @@
+// Copyright 2014-2021 The winit contributors
+// Copyright 2021-2023 Tauri Programme within The Commons Conservancy
+// SPDX-License-Identifier: Apache-2.0
+
+use crate::{
+ dpi::{PhysicalPosition, PhysicalSize, Position, Size},
+ error, event,
+ event_loop::{self, ControlFlow},
+ keyboard::{KeyCode, NativeKeyCode},
+ monitor,
+ window::{self, ResizeDirection, Theme, WindowSizeConstraints},
+};
+use crossbeam_channel::{Receiver, Sender};
+use ndk::{
+ configuration::Configuration,
+ looper::{ForeignLooper, Poll, ThreadLooper},
+};
+use once_cell::sync::Lazy;
+use std::{
+ collections::VecDeque,
+ error::Error,
+ fmt,
+ sync::RwLock,
+ time::{Duration, Instant},
+};
+
+#[derive(Debug)]
+pub struct JniCallError {
+ source: jni::errors::Error,
+ java_exception: Option,
+}
+
+impl JniCallError {
+ fn new(source: jni::errors::Error, java_exception: Option) -> Self {
+ Self {
+ source,
+ java_exception,
+ }
+ }
+}
+
+impl From for JniCallError {
+ fn from(source: jni::errors::Error) -> Self {
+ Self::new(source, None)
+ }
+}
+
+impl fmt::Display for JniCallError {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ match &self.java_exception {
+ Some(java_exception) => write!(f, "{}: {java_exception}", self.source),
+ None => self.source.fmt(f),
+ }
+ }
+}
+
+impl Error for JniCallError {
+ fn source(&self) -> Option<&(dyn Error + 'static)> {
+ Some(&self.source)
+ }
+}
+
+/// Logs and clears a pending Java exception while preserving the original JNI error.
+macro_rules! jni_handle_error {
+ ($env:ident, $e:expr) => {{
+ let e = $e;
+ let message = (|| -> jni::errors::Result