From e87c7b088a557ffc5ac1c7e6e24227c530603ca4 Mon Sep 17 00:00:00 2001
From: Richie McIlroy <33632126+richiemcilroy@users.noreply.github.com>
Date: Wed, 18 Feb 2026 13:21:48 +0000
Subject: [PATCH 1/8] chore: vendor tao dependency
---
Cargo.lock | 3 +-
Cargo.toml | 1 +
vendor/tao/.cargo-ok | 1 +
vendor/tao/.cargo_vcs_info.json | 7 +
vendor/tao/Cargo.lock | 3267 +++++++++++++++++
vendor/tao/Cargo.toml | 390 ++
vendor/tao/Cargo.toml.orig | 158 +
vendor/tao/LICENSE | 201 +
vendor/tao/LICENSE.spdx | 18 +
vendor/tao/README.md | 80 +
vendor/tao/examples/control_flow.rs | 120 +
vendor/tao/examples/cursor.rs | 89 +
vendor/tao/examples/cursor_grab.rs | 66 +
vendor/tao/examples/custom_events.rs | 51 +
vendor/tao/examples/decorations.rs | 51 +
vendor/tao/examples/drag_window.rs | 78 +
vendor/tao/examples/fullscreen.rs | 129 +
vendor/tao/examples/handling_close.rs | 87 +
vendor/tao/examples/min_max_size.rs | 87 +
vendor/tao/examples/minimize.rs | 47 +
vendor/tao/examples/monitor_list.rs | 14 +
vendor/tao/examples/mouse_wheel.rs | 54 +
vendor/tao/examples/multithreaded.rs | 187 +
vendor/tao/examples/multiwindow.rs | 55 +
vendor/tao/examples/overlay.rs | 128 +
vendor/tao/examples/parentwindow.rs | 70 +
vendor/tao/examples/progress_bar.rs | 89 +
vendor/tao/examples/reopen_event.rs | 45 +
vendor/tao/examples/request_redraw.rs | 43 +
.../tao/examples/request_redraw_threaded.rs | 45 +
vendor/tao/examples/resizable.rs | 51 +
vendor/tao/examples/set_ime_position.rs | 56 +
vendor/tao/examples/theme.rs | 50 +
vendor/tao/examples/timer.rs | 43 +
vendor/tao/examples/transparent.rs | 66 +
vendor/tao/examples/video_modes.rs | 24 +
vendor/tao/examples/window.rs | 52 +
vendor/tao/examples/window_debug.rs | 176 +
vendor/tao/examples/window_icon.rs | 64 +
vendor/tao/examples/window_run_return.rs | 59 +
vendor/tao/src/error.rs | 88 +
vendor/tao/src/event.rs | 928 +++++
vendor/tao/src/event_loop.rs | 411 +++
vendor/tao/src/icon.rs | 169 +
vendor/tao/src/keyboard.rs | 1596 ++++++++
vendor/tao/src/lib.rs | 199 +
vendor/tao/src/monitor.rs | 163 +
vendor/tao/src/platform/android.rs | 48 +
vendor/tao/src/platform/ios.rs | 345 ++
vendor/tao/src/platform/linux.rs | 5 +
vendor/tao/src/platform/macos.rs | 458 +++
vendor/tao/src/platform/mod.rs | 28 +
vendor/tao/src/platform/run_return.rs | 50 +
vendor/tao/src/platform/unix.rs | 308 ++
vendor/tao/src/platform/windows.rs | 449 +++
vendor/tao/src/platform_impl/android/mod.rs | 1262 +++++++
.../tao/src/platform_impl/android/ndk_glue.rs | 378 ++
vendor/tao/src/platform_impl/ios/app_state.rs | 1033 ++++++
vendor/tao/src/platform_impl/ios/badge.rs | 15 +
.../tao/src/platform_impl/ios/event_loop.rs | 385 ++
vendor/tao/src/platform_impl/ios/ffi.rs | 433 +++
vendor/tao/src/platform_impl/ios/keycode.rs | 13 +
vendor/tao/src/platform_impl/ios/mod.rs | 123 +
vendor/tao/src/platform_impl/ios/monitor.rs | 300 ++
vendor/tao/src/platform_impl/ios/view.rs | 696 ++++
vendor/tao/src/platform_impl/ios/window.rs | 790 ++++
vendor/tao/src/platform_impl/linux/device.rs | 80 +
.../tao/src/platform_impl/linux/event_loop.rs | 1289 +++++++
vendor/tao/src/platform_impl/linux/icon.rs | 47 +
.../tao/src/platform_impl/linux/keyboard.rs | 288 ++
vendor/tao/src/platform_impl/linux/keycode.rs | 325 ++
vendor/tao/src/platform_impl/linux/mod.rs | 97 +
vendor/tao/src/platform_impl/linux/monitor.rs | 96 +
vendor/tao/src/platform_impl/linux/taskbar.rs | 161 +
vendor/tao/src/platform_impl/linux/util.rs | 111 +
.../src/platform_impl/linux/wayland/header.rs | 36 +
.../src/platform_impl/linux/wayland/mod.rs | 5 +
vendor/tao/src/platform_impl/linux/window.rs | 1103 ++++++
vendor/tao/src/platform_impl/linux/x11/ffi.rs | 8 +
vendor/tao/src/platform_impl/linux/x11/mod.rs | 8 +
.../src/platform_impl/linux/x11/xdisplay.rs | 169 +
vendor/tao/src/platform_impl/macos/app.rs | 126 +
.../src/platform_impl/macos/app_delegate.rs | 223 ++
.../tao/src/platform_impl/macos/app_state.rs | 470 +++
vendor/tao/src/platform_impl/macos/badge.rs | 13 +
vendor/tao/src/platform_impl/macos/dock.rs | 91 +
vendor/tao/src/platform_impl/macos/event.rs | 335 ++
.../tao/src/platform_impl/macos/event_loop.rs | 356 ++
vendor/tao/src/platform_impl/macos/ffi.rs | 273 ++
vendor/tao/src/platform_impl/macos/icon.rs | 14 +
vendor/tao/src/platform_impl/macos/keycode.rs | 264 ++
vendor/tao/src/platform_impl/macos/mod.rs | 97 +
vendor/tao/src/platform_impl/macos/monitor.rs | 338 ++
.../tao/src/platform_impl/macos/observer.rs | 305 ++
.../src/platform_impl/macos/progress_bar.rs | 161 +
.../tao/src/platform_impl/macos/util/async.rs | 257 ++
.../src/platform_impl/macos/util/cursor.rs | 177 +
.../tao/src/platform_impl/macos/util/mod.rs | 145 +
vendor/tao/src/platform_impl/macos/view.rs | 1184 ++++++
vendor/tao/src/platform_impl/macos/window.rs | 1788 +++++++++
.../platform_impl/macos/window_delegate.rs | 679 ++++
vendor/tao/src/platform_impl/mod.rs | 40 +
.../src/platform_impl/windows/dark_mode.rs | 240 ++
vendor/tao/src/platform_impl/windows/dpi.rs | 109 +
.../src/platform_impl/windows/drop_handler.rs | 181 +
vendor/tao/src/platform_impl/windows/event.rs | 421 +++
.../src/platform_impl/windows/event_loop.rs | 2669 ++++++++++++++
.../windows/event_loop/runner.rs | 447 +++
vendor/tao/src/platform_impl/windows/icon.rs | 170 +
.../tao/src/platform_impl/windows/keyboard.rs | 817 +++++
.../platform_impl/windows/keyboard_layout.rs | 983 +++++
.../tao/src/platform_impl/windows/keycode.rs | 338 ++
.../src/platform_impl/windows/minimal_ime.rs | 88 +
vendor/tao/src/platform_impl/windows/mod.rs | 157 +
.../tao/src/platform_impl/windows/monitor.rs | 270 ++
.../src/platform_impl/windows/raw_input.rs | 217 ++
vendor/tao/src/platform_impl/windows/util.rs | 511 +++
.../tao/src/platform_impl/windows/window.rs | 1554 ++++++++
.../src/platform_impl/windows/window_state.rs | 513 +++
vendor/tao/src/window.rs | 1698 +++++++++
120 files changed, 39515 insertions(+), 2 deletions(-)
create mode 100644 vendor/tao/.cargo-ok
create mode 100644 vendor/tao/.cargo_vcs_info.json
create mode 100644 vendor/tao/Cargo.lock
create mode 100644 vendor/tao/Cargo.toml
create mode 100644 vendor/tao/Cargo.toml.orig
create mode 100644 vendor/tao/LICENSE
create mode 100644 vendor/tao/LICENSE.spdx
create mode 100644 vendor/tao/README.md
create mode 100644 vendor/tao/examples/control_flow.rs
create mode 100644 vendor/tao/examples/cursor.rs
create mode 100644 vendor/tao/examples/cursor_grab.rs
create mode 100644 vendor/tao/examples/custom_events.rs
create mode 100644 vendor/tao/examples/decorations.rs
create mode 100644 vendor/tao/examples/drag_window.rs
create mode 100644 vendor/tao/examples/fullscreen.rs
create mode 100644 vendor/tao/examples/handling_close.rs
create mode 100644 vendor/tao/examples/min_max_size.rs
create mode 100644 vendor/tao/examples/minimize.rs
create mode 100644 vendor/tao/examples/monitor_list.rs
create mode 100644 vendor/tao/examples/mouse_wheel.rs
create mode 100644 vendor/tao/examples/multithreaded.rs
create mode 100644 vendor/tao/examples/multiwindow.rs
create mode 100644 vendor/tao/examples/overlay.rs
create mode 100644 vendor/tao/examples/parentwindow.rs
create mode 100644 vendor/tao/examples/progress_bar.rs
create mode 100644 vendor/tao/examples/reopen_event.rs
create mode 100644 vendor/tao/examples/request_redraw.rs
create mode 100644 vendor/tao/examples/request_redraw_threaded.rs
create mode 100644 vendor/tao/examples/resizable.rs
create mode 100644 vendor/tao/examples/set_ime_position.rs
create mode 100644 vendor/tao/examples/theme.rs
create mode 100644 vendor/tao/examples/timer.rs
create mode 100644 vendor/tao/examples/transparent.rs
create mode 100644 vendor/tao/examples/video_modes.rs
create mode 100644 vendor/tao/examples/window.rs
create mode 100644 vendor/tao/examples/window_debug.rs
create mode 100644 vendor/tao/examples/window_icon.rs
create mode 100644 vendor/tao/examples/window_run_return.rs
create mode 100644 vendor/tao/src/error.rs
create mode 100644 vendor/tao/src/event.rs
create mode 100644 vendor/tao/src/event_loop.rs
create mode 100644 vendor/tao/src/icon.rs
create mode 100644 vendor/tao/src/keyboard.rs
create mode 100644 vendor/tao/src/lib.rs
create mode 100644 vendor/tao/src/monitor.rs
create mode 100644 vendor/tao/src/platform/android.rs
create mode 100644 vendor/tao/src/platform/ios.rs
create mode 100644 vendor/tao/src/platform/linux.rs
create mode 100644 vendor/tao/src/platform/macos.rs
create mode 100644 vendor/tao/src/platform/mod.rs
create mode 100644 vendor/tao/src/platform/run_return.rs
create mode 100644 vendor/tao/src/platform/unix.rs
create mode 100644 vendor/tao/src/platform/windows.rs
create mode 100644 vendor/tao/src/platform_impl/android/mod.rs
create mode 100644 vendor/tao/src/platform_impl/android/ndk_glue.rs
create mode 100644 vendor/tao/src/platform_impl/ios/app_state.rs
create mode 100644 vendor/tao/src/platform_impl/ios/badge.rs
create mode 100644 vendor/tao/src/platform_impl/ios/event_loop.rs
create mode 100644 vendor/tao/src/platform_impl/ios/ffi.rs
create mode 100644 vendor/tao/src/platform_impl/ios/keycode.rs
create mode 100644 vendor/tao/src/platform_impl/ios/mod.rs
create mode 100644 vendor/tao/src/platform_impl/ios/monitor.rs
create mode 100644 vendor/tao/src/platform_impl/ios/view.rs
create mode 100644 vendor/tao/src/platform_impl/ios/window.rs
create mode 100644 vendor/tao/src/platform_impl/linux/device.rs
create mode 100644 vendor/tao/src/platform_impl/linux/event_loop.rs
create mode 100644 vendor/tao/src/platform_impl/linux/icon.rs
create mode 100644 vendor/tao/src/platform_impl/linux/keyboard.rs
create mode 100644 vendor/tao/src/platform_impl/linux/keycode.rs
create mode 100644 vendor/tao/src/platform_impl/linux/mod.rs
create mode 100644 vendor/tao/src/platform_impl/linux/monitor.rs
create mode 100644 vendor/tao/src/platform_impl/linux/taskbar.rs
create mode 100644 vendor/tao/src/platform_impl/linux/util.rs
create mode 100644 vendor/tao/src/platform_impl/linux/wayland/header.rs
create mode 100644 vendor/tao/src/platform_impl/linux/wayland/mod.rs
create mode 100644 vendor/tao/src/platform_impl/linux/window.rs
create mode 100644 vendor/tao/src/platform_impl/linux/x11/ffi.rs
create mode 100644 vendor/tao/src/platform_impl/linux/x11/mod.rs
create mode 100644 vendor/tao/src/platform_impl/linux/x11/xdisplay.rs
create mode 100644 vendor/tao/src/platform_impl/macos/app.rs
create mode 100644 vendor/tao/src/platform_impl/macos/app_delegate.rs
create mode 100644 vendor/tao/src/platform_impl/macos/app_state.rs
create mode 100644 vendor/tao/src/platform_impl/macos/badge.rs
create mode 100644 vendor/tao/src/platform_impl/macos/dock.rs
create mode 100644 vendor/tao/src/platform_impl/macos/event.rs
create mode 100644 vendor/tao/src/platform_impl/macos/event_loop.rs
create mode 100644 vendor/tao/src/platform_impl/macos/ffi.rs
create mode 100644 vendor/tao/src/platform_impl/macos/icon.rs
create mode 100644 vendor/tao/src/platform_impl/macos/keycode.rs
create mode 100644 vendor/tao/src/platform_impl/macos/mod.rs
create mode 100644 vendor/tao/src/platform_impl/macos/monitor.rs
create mode 100644 vendor/tao/src/platform_impl/macos/observer.rs
create mode 100644 vendor/tao/src/platform_impl/macos/progress_bar.rs
create mode 100644 vendor/tao/src/platform_impl/macos/util/async.rs
create mode 100644 vendor/tao/src/platform_impl/macos/util/cursor.rs
create mode 100644 vendor/tao/src/platform_impl/macos/util/mod.rs
create mode 100644 vendor/tao/src/platform_impl/macos/view.rs
create mode 100644 vendor/tao/src/platform_impl/macos/window.rs
create mode 100644 vendor/tao/src/platform_impl/macos/window_delegate.rs
create mode 100644 vendor/tao/src/platform_impl/mod.rs
create mode 100644 vendor/tao/src/platform_impl/windows/dark_mode.rs
create mode 100644 vendor/tao/src/platform_impl/windows/dpi.rs
create mode 100644 vendor/tao/src/platform_impl/windows/drop_handler.rs
create mode 100644 vendor/tao/src/platform_impl/windows/event.rs
create mode 100644 vendor/tao/src/platform_impl/windows/event_loop.rs
create mode 100644 vendor/tao/src/platform_impl/windows/event_loop/runner.rs
create mode 100644 vendor/tao/src/platform_impl/windows/icon.rs
create mode 100644 vendor/tao/src/platform_impl/windows/keyboard.rs
create mode 100644 vendor/tao/src/platform_impl/windows/keyboard_layout.rs
create mode 100644 vendor/tao/src/platform_impl/windows/keycode.rs
create mode 100644 vendor/tao/src/platform_impl/windows/minimal_ime.rs
create mode 100644 vendor/tao/src/platform_impl/windows/mod.rs
create mode 100644 vendor/tao/src/platform_impl/windows/monitor.rs
create mode 100644 vendor/tao/src/platform_impl/windows/raw_input.rs
create mode 100644 vendor/tao/src/platform_impl/windows/util.rs
create mode 100644 vendor/tao/src/platform_impl/windows/window.rs
create mode 100644 vendor/tao/src/platform_impl/windows/window_state.rs
create mode 100644 vendor/tao/src/window.rs
diff --git a/Cargo.lock b/Cargo.lock
index c78ac1f0cde..5c23ca443f0 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1316,6 +1316,7 @@ dependencies = [
"tokio-util",
"tracing",
"tracing-subscriber",
+ "windows 0.60.0",
"workspace-hack",
]
@@ -9103,8 +9104,6 @@ dependencies = [
[[package]]
name = "tao"
version = "0.34.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "959469667dbcea91e5485fc48ba7dd6023face91bb0f1a14681a70f99847c3f7"
dependencies = [
"bitflags 2.9.4",
"block2 0.6.1",
diff --git a/Cargo.toml b/Cargo.toml
index b67052237e4..44097ca7576 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -108,6 +108,7 @@ cidre = { git = "https://github.com/CapSoftware/cidre", rev = "bf84b67079a8" }
# https://github.com/gfx-rs/wgpu/pull/7550
# wgpu = { git = "https://github.com/gfx-rs/wgpu", rev = "cd41a6e32a6239b65d1cecbeccde6a43a100914a" }
wgpu-hal = { path = "vendor/wgpu-hal" }
+tao = { path = "vendor/tao" }
# https://github.com/CapSoftware/posthog-rs/commit/c7e9712be2f9a9122b1df685d5a067afa5415288
posthog-rs = { git = "https://github.com/CapSoftware/posthog-rs", rev = "c7e9712be2f9a9122b1df685d5a067afa5415288" }
diff --git a/vendor/tao/.cargo-ok b/vendor/tao/.cargo-ok
new file mode 100644
index 00000000000..5f8b795830a
--- /dev/null
+++ b/vendor/tao/.cargo-ok
@@ -0,0 +1 @@
+{"v":1}
\ No newline at end of file
diff --git a/vendor/tao/.cargo_vcs_info.json b/vendor/tao/.cargo_vcs_info.json
new file mode 100644
index 00000000000..d201940feca
--- /dev/null
+++ b/vendor/tao/.cargo_vcs_info.json
@@ -0,0 +1,7 @@
+{
+ "git": {
+ "sha1": "fda48e80ef0600079666c19146eb01bdfc4dd3c4",
+ "dirty": true
+ },
+ "path_in_vcs": ""
+}
diff --git a/vendor/tao/Cargo.lock b/vendor/tao/Cargo.lock
new file mode 100644
index 00000000000..e134e3112c1
--- /dev/null
+++ b/vendor/tao/Cargo.lock
@@ -0,0 +1,3267 @@
+# 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.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916"
+dependencies = [
+ "memchr",
+]
+
+[[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 = "0.6.20"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3ae563653d1938f79b1ab1b5e668c87c76a9930414574a6583a7b7e11a8e6192"
+dependencies = [
+ "anstyle",
+ "anstyle-parse",
+ "anstyle-query",
+ "anstyle-wincon",
+ "colorchoice",
+ "is_terminal_polyfill",
+ "utf8parse",
+]
+
+[[package]]
+name = "anstyle"
+version = "1.0.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "862ed96ca487e809f1c8e5a8447f6ee2cf102f846893800b20cebdf541fc6bbd"
+
+[[package]]
+name = "anstyle-parse"
+version = "0.2.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2"
+dependencies = [
+ "utf8parse",
+]
+
+[[package]]
+name = "anstyle-query"
+version = "1.1.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9e231f6134f61b71076a3eab506c379d4f36122f2af15a9ff04415ea4c3339e2"
+dependencies = [
+ "windows-sys 0.60.2",
+]
+
+[[package]]
+name = "anstyle-wincon"
+version = "3.0.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3e0633414522a32ffaac8ac6cc8f748e090c5717661fddeea04219e2344f5f2a"
+dependencies = [
+ "anstyle",
+ "once_cell_polyfill",
+ "windows-sys 0.60.2",
+]
+
+[[package]]
+name = "anyhow"
+version = "1.0.99"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b0674a1ddeecb70197781e945de4b3b8ffb61fa939a5597bcf48503737663100"
+
+[[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.106",
+]
+
+[[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 = "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 = "av1-grain"
+version = "0.2.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4f3efb2ca85bc610acfa917b5aaa36f3fcbebed5b3182d7f877b02531c4b80c8"
+dependencies = [
+ "anyhow",
+ "arrayvec",
+ "log",
+ "nom",
+ "num-rational",
+ "v_frame",
+]
+
+[[package]]
+name = "avif-serialize"
+version = "0.8.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "47c8fbc0f831f4519fe8b810b6a7a91410ec83031b8233f730a0480029f6a23f"
+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.9.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "34efbcccd345379ca2868b2b2c9d3782e9cc58ba87bc7d79d5b53d9c9ae6f25d"
+
+[[package]]
+name = "bitstream-io"
+version = "2.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6099cdc01846bc367c4e7dd630dc5966dccf36b652fae7a74e17b640411a91b2"
+
+[[package]]
+name = "block2"
+version = "0.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2c132eebf10f5cad5289222520a4a058514204aed6d791f1cf4fe8088b82d15f"
+dependencies = [
+ "objc2 0.5.2",
+]
+
+[[package]]
+name = "block2"
+version = "0.6.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "340d2f0bdb2a43c1d3cd40513185b2bd7def0aa1052f956455114bc98f82dcf2"
+dependencies = [
+ "objc2 0.6.2",
+]
+
+[[package]]
+name = "built"
+version = "0.7.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "56ed6191a7e78c36abdb16ab65341eefd73d64d303fffccdbb00d51e4205967b"
+
+[[package]]
+name = "bumpalo"
+version = "3.19.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43"
+
+[[package]]
+name = "bytemuck"
+version = "1.23.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3995eaeebcdf32f91f980d360f78732ddc061097ab4e39991ae7a6ace9194677"
+dependencies = [
+ "bytemuck_derive",
+]
+
+[[package]]
+name = "bytemuck_derive"
+version = "1.10.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4f154e572231cb6ba2bd1176980827e3d5dc04cc183a75dea38109fbdd672d29"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.106",
+]
+
+[[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.10.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a"
+
+[[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",
+]
+
+[[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.34"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "42bc4aea80032b7bf409b0bc7ccad88853858911b7713a8062fdc0623867bedc"
+dependencies = [
+ "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.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2fd1289c04a9ea8cb22300a459a72a385d7c73d3259e2ed7dcb2af674838cfa9"
+
+[[package]]
+name = "cfg_aliases"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724"
+
+[[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.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75"
+
+[[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.24.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fa95a34622365fa5bbf40b20b75dba8dfa8c94c734aea8ac9a5ca38af14316f1"
+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-lite"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1f791803201ab277ace03903de1594460708d2d54df6053f2d9e82f592b19e3b"
+
+[[package]]
+name = "cty"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b365fabc795046672053e29c954733ec3b05e4be654ab130fe8f1f94d7051f35"
+
+[[package]]
+name = "dispatch"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bd0c93bb4b0c6d9b77f4435b0ae98c24d17f1c45b2ff844c6151a07256ca923b"
+
+[[package]]
+name = "dispatch2"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "89a09f22a6c6069a18470eb92d2298acf25463f14256d24778e1230d789a2aec"
+dependencies = [
+ "bitflags",
+ "objc2 0.6.2",
+]
+
+[[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.106",
+]
+
+[[package]]
+name = "dlib"
+version = "0.5.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "330c60081dcc4c72131f8eb70510f1ac07223e5d4163db481a04a0befcffa412"
+dependencies = [
+ "libloading",
+]
+
+[[package]]
+name = "dlopen2"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b54f373ccf864bf587a89e880fb7610f8d73f3045f13580948ccbcaff26febff"
+dependencies = [
+ "dlopen2_derive",
+ "libc",
+ "once_cell",
+ "winapi",
+]
+
+[[package]]
+name = "dlopen2_derive"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "788160fb30de9cdd857af31c6a2675904b16ece8fc2737b2c7127ba368c9d0f4"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.106",
+]
+
+[[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.12.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "98888c4bbd601524c11a7ed63f814b8825f420514f78e96f752c437ae9cbb5d1"
+dependencies = [
+ "bitflags",
+ "bytemuck",
+ "drm-ffi",
+ "drm-fourcc",
+ "rustix 0.38.44",
+]
+
+[[package]]
+name = "drm-ffi"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "97c98727e48b7ccb4f4aea8cfe881e5b07f702d17b7875991881b41af7278d53"
+dependencies = [
+ "drm-sys",
+ "rustix 0.38.44",
+]
+
+[[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.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fd39dde40b6e196c2e8763f23d119ddb1a8714534bf7d77fa97a65b0feda3986"
+dependencies = [
+ "libc",
+ "linux-raw-sys 0.6.5",
+]
+
+[[package]]
+name = "either"
+version = "1.15.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719"
+
+[[package]]
+name = "env_filter"
+version = "0.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "186e05a59d4c50738528153b83b0b0194d3a29507dfec16eccd4b342903397d0"
+dependencies = [
+ "log",
+ "regex",
+]
+
+[[package]]
+name = "env_logger"
+version = "0.11.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "13c863f0904021b108aa8b2f55046443e6b1ebde8fd4a15c399893aae4fa069f"
+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.106",
+]
+
+[[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.13"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "778e2ac28f6c47af28e4907f13ffd1e1ddbd400980a9abd7c8df189bf578a5ad"
+dependencies = [
+ "libc",
+ "windows-sys 0.60.2",
+]
+
+[[package]]
+name = "exr"
+version = "1.73.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f83197f59927b46c04a183a619b7c29df34e63e63c7869320862268c0ef687e0"
+dependencies = [
+ "bit_field",
+ "half",
+ "lebe",
+ "miniz_oxide",
+ "rayon-core",
+ "smallvec",
+ "zune-inflate",
+]
+
+[[package]]
+name = "fastrand"
+version = "2.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be"
+
+[[package]]
+name = "fax"
+version = "0.2.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f05de7d48f37cd6730705cbca900770cab77a89f413d23e100ad7fad7795a0ab"
+dependencies = [
+ "fax_derive",
+]
+
+[[package]]
+name = "fax_derive"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a0aca10fb742cb43f9e7bb8467c91aa9bcb8e3ffbc6a6f7389bb93ffc920577d"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.106",
+]
+
+[[package]]
+name = "fdeflate"
+version = "0.3.7"
+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 = "flate2"
+version = "1.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4a3d7db9596fecd151c5f638c0ee5d5bd487b6e0ea232e5dc96d5250f6f94b1d"
+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.106",
+]
+
+[[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.31"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10"
+dependencies = [
+ "futures-core",
+]
+
+[[package]]
+name = "futures-core"
+version = "0.3.31"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e"
+
+[[package]]
+name = "futures-executor"
+version = "0.3.31"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f"
+dependencies = [
+ "futures-core",
+ "futures-task",
+ "futures-util",
+]
+
+[[package]]
+name = "futures-io"
+version = "0.3.31"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6"
+
+[[package]]
+name = "futures-macro"
+version = "0.3.31"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.106",
+]
+
+[[package]]
+name = "futures-task"
+version = "0.3.31"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988"
+
+[[package]]
+name = "futures-util"
+version = "0.3.31"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81"
+dependencies = [
+ "futures-core",
+ "futures-macro",
+ "futures-task",
+ "pin-project-lite",
+ "pin-utils",
+ "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.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fc257fdb4038301ce4b9cd1b3b51704509692bb3ff716a410cbd07925d9dae55"
+dependencies = [
+ "rustix 1.0.8",
+ "windows-targets 0.52.6",
+]
+
+[[package]]
+name = "getrandom"
+version = "0.2.16"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592"
+dependencies = [
+ "cfg-if",
+ "libc",
+ "wasi 0.11.1+wasi-snapshot-preview1",
+]
+
+[[package]]
+name = "getrandom"
+version = "0.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4"
+dependencies = [
+ "cfg-if",
+ "libc",
+ "r-efi",
+ "wasi 0.14.3+wasi-0.2.4",
+]
+
+[[package]]
+name = "gif"
+version = "0.13.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4ae047235e33e2829703574b54fdec96bfbad892062d97fed2f76022287de61b"
+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",
+]
+
+[[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",
+]
+
+[[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.106",
+]
+
+[[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.106",
+]
+
+[[package]]
+name = "half"
+version = "2.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "459196ed295495a68f7d7fe1d84f6c4b7ff0e21fe3017b2f283c6fac3ad803c9"
+dependencies = [
+ "cfg-if",
+ "crunchy",
+]
+
+[[package]]
+name = "hashbrown"
+version = "0.15.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1"
+
+[[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.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "200072f5d0e3614556f94a9930d5dc3e0662a652823904c3a75dc3b0af7fee47"
+dependencies = [
+ "displaydoc",
+ "potential_utf",
+ "yoke",
+ "zerofrom",
+ "zerovec",
+]
+
+[[package]]
+name = "icu_locale_core"
+version = "2.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0cde2700ccaed3872079a65fb1a78f6c0a36c91570f28755dda67bc8f7d9f00a"
+dependencies = [
+ "displaydoc",
+ "litemap",
+ "tinystr",
+ "writeable",
+ "zerovec",
+]
+
+[[package]]
+name = "icu_normalizer"
+version = "2.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "436880e8e18df4d7bbc06d58432329d6458cc84531f7ac5f024e93deadb37979"
+dependencies = [
+ "displaydoc",
+ "icu_collections",
+ "icu_normalizer_data",
+ "icu_properties",
+ "icu_provider",
+ "smallvec",
+ "zerovec",
+]
+
+[[package]]
+name = "icu_normalizer_data"
+version = "2.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "00210d6893afc98edb752b664b8890f0ef174c8adbb8d0be9710fa66fbbf72d3"
+
+[[package]]
+name = "icu_properties"
+version = "2.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "016c619c1eeb94efb86809b015c58f479963de65bdb6253345c1a1276f22e32b"
+dependencies = [
+ "displaydoc",
+ "icu_collections",
+ "icu_locale_core",
+ "icu_properties_data",
+ "icu_provider",
+ "potential_utf",
+ "zerotrie",
+ "zerovec",
+]
+
+[[package]]
+name = "icu_properties_data"
+version = "2.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "298459143998310acd25ffe6810ed544932242d3f07083eee1084d83a71bd632"
+
+[[package]]
+name = "icu_provider"
+version = "2.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "03c80da27b5f4187909049ee2d72f276f0d9f99a42c306bd0131ecfe04d8e5af"
+dependencies = [
+ "displaydoc",
+ "icu_locale_core",
+ "stable_deref_trait",
+ "tinystr",
+ "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.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344"
+dependencies = [
+ "icu_normalizer",
+ "icu_properties",
+]
+
+[[package]]
+name = "image"
+version = "0.25.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1c6a3ce16143778e24df6f95365f12ed105425b22abefd289dd88a64bab59605"
+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.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d0263a3d970d5c054ed9312c0057b4f3bde9c0b33836d3637361d4a9e6e7a408"
+
+[[package]]
+name = "indexmap"
+version = "2.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f2481980430f9f78649238835720ddccc57e52df14ffce1c6f37391d61b563e9"
+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.106",
+]
+
+[[package]]
+name = "is_terminal_polyfill"
+version = "1.70.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf"
+
+[[package]]
+name = "itertools"
+version = "0.12.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569"
+dependencies = [
+ "either",
+]
+
+[[package]]
+name = "jiff"
+version = "0.2.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "be1f93b8b1eb69c77f24bbb0afdf66f54b632ee39af40ca21c4365a1d7347e49"
+dependencies = [
+ "jiff-static",
+ "log",
+ "portable-atomic",
+ "portable-atomic-util",
+ "serde",
+]
+
+[[package]]
+name = "jiff-static"
+version = "0.2.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "03343451ff899767262ec32146f6d559dd759fdadf42ff0e227c7c48f72594b4"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.106",
+]
+
+[[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",
+ "log",
+ "thiserror",
+ "walkdir",
+ "windows-sys 0.45.0",
+]
+
+[[package]]
+name = "jni-sys"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130"
+
+[[package]]
+name = "jobserver"
+version = "0.1.34"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33"
+dependencies = [
+ "getrandom 0.3.3",
+ "libc",
+]
+
+[[package]]
+name = "js-sys"
+version = "0.3.77"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f"
+dependencies = [
+ "once_cell",
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "lazy_static"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
+
+[[package]]
+name = "lebe"
+version = "0.5.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "03087c2bad5e1034e8cace5926dec053fb3790248370865f5117a7d0213354c8"
+
+[[package]]
+name = "libc"
+version = "0.2.175"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6a82ae493e598baaea5209805c49bbf2ea7de956d50d7da0da1164f9c6d28543"
+
+[[package]]
+name = "libfuzzer-sys"
+version = "0.4.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5037190e1f70cbeef565bd267599242926f724d3b8a9f510fd7e0b540cfa4404"
+dependencies = [
+ "arbitrary",
+ "cc",
+]
+
+[[package]]
+name = "libloading"
+version = "0.8.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "07033963ba89ebaf1584d767badaa2e8fcec21aedea6b8c0346d487d49c28667"
+dependencies = [
+ "cfg-if",
+ "windows-targets 0.53.3",
+]
+
+[[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.6.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2a385b1be4e5c3e362ad2ffa73c392e53f031eaa5b7d648e64cd87f27f6063d7"
+
+[[package]]
+name = "linux-raw-sys"
+version = "0.9.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12"
+
+[[package]]
+name = "litemap"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956"
+
+[[package]]
+name = "lock_api"
+version = "0.4.13"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "96936507f153605bddfcda068dd804796c84324ed2510809e5b2a624c81da765"
+dependencies = [
+ "autocfg",
+ "scopeguard",
+]
+
+[[package]]
+name = "log"
+version = "0.4.27"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94"
+
+[[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.7.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0"
+
+[[package]]
+name = "memmap2"
+version = "0.9.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "843a98750cd611cc2965a8213b53b43e715f13c37a9e096c6408e69990961db7"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "memoffset"
+version = "0.9.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a"
+dependencies = [
+ "autocfg",
+]
+
+[[package]]
+name = "minimal-lexical"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
+
+[[package]]
+name = "miniz_oxide"
+version = "0.8.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316"
+dependencies = [
+ "adler2",
+ "simd-adler32",
+]
+
+[[package]]
+name = "moxcms"
+version = "0.7.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ddd32fa8935aeadb8a8a6b6b351e40225570a37c43de67690383d87ef170cd08"
+dependencies = [
+ "num-traits",
+ "pxfm",
+]
+
+[[package]]
+name = "ndk"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c3f42e7bbe13d351b6bead8286a43aac9534b82bd3cc43e47037f012ebfd62d4"
+dependencies = [
+ "bitflags",
+ "jni-sys",
+ "log",
+ "ndk-sys",
+ "num_enum",
+ "raw-window-handle 0.6.2",
+ "thiserror",
+]
+
+[[package]]
+name = "ndk-context"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "27b02d87554356db9e9a873add8782d4ea6e3e58ea071a9adb9a2e8ddb884a8b"
+
+[[package]]
+name = "ndk-sys"
+version = "0.6.0+11769913"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ee6cda3051665f1fb8d9e08fc35c96d5a244fb1be711a03b71118828afc9a873"
+dependencies = [
+ "jni-sys",
+]
+
+[[package]]
+name = "new_debug_unreachable"
+version = "1.0.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086"
+
+[[package]]
+name = "nom"
+version = "7.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a"
+dependencies = [
+ "memchr",
+ "minimal-lexical",
+]
+
+[[package]]
+name = "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.106",
+]
+
+[[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.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a973b4e44ce6cad84ce69d797acf9a044532e4184c4f267913d1b546a0727b7a"
+dependencies = [
+ "num_enum_derive",
+ "rustversion",
+]
+
+[[package]]
+name = "num_enum_derive"
+version = "0.7.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "77e878c846a8abae00dd069496dbe8751b16ac1c3d6bd2a7283a938e8228f90d"
+dependencies = [
+ "proc-macro-crate 2.0.2",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.106",
+]
+
+[[package]]
+name = "objc-sys"
+version = "0.3.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cdb91bdd390c7ce1a8607f35f3ca7151b65afc0ff5ff3b34fa350f7d7c7e4310"
+
+[[package]]
+name = "objc2"
+version = "0.5.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "46a785d4eeff09c14c487497c162e92766fbb3e4059a71840cecc03d9a50b804"
+dependencies = [
+ "objc-sys",
+ "objc2-encode",
+]
+
+[[package]]
+name = "objc2"
+version = "0.6.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "561f357ba7f3a2a61563a186a163d0a3a5247e1089524a3981d49adb775078bc"
+dependencies = [
+ "objc2-encode",
+]
+
+[[package]]
+name = "objc2-app-kit"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e6f29f568bec459b0ddff777cec4fe3fd8666d82d5a40ebd0ff7e66134f89bcc"
+dependencies = [
+ "bitflags",
+ "objc2 0.6.2",
+ "objc2-core-foundation",
+ "objc2-foundation 0.3.1",
+]
+
+[[package]]
+name = "objc2-core-foundation"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1c10c2894a6fed806ade6027bcd50662746363a9589d3ec9d9bef30a4e4bc166"
+dependencies = [
+ "bitflags",
+ "dispatch2",
+ "objc2 0.6.2",
+]
+
+[[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.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0ee638a5da3799329310ad4cfa62fbf045d5f56e3ef5ba4149e7452dcf89d5a8"
+dependencies = [
+ "bitflags",
+ "block2 0.5.1",
+ "libc",
+ "objc2 0.5.2",
+]
+
+[[package]]
+name = "objc2-foundation"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "900831247d2fe1a09a683278e5384cfb8c80c79fe6b166f9d14bfdde0ea1b03c"
+dependencies = [
+ "bitflags",
+ "objc2 0.6.2",
+ "objc2-core-foundation",
+]
+
+[[package]]
+name = "objc2-metal"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dd0cba1276f6023976a406a14ffa85e1fdd19df6b0f737b063b95f6c8c7aadd6"
+dependencies = [
+ "bitflags",
+ "block2 0.5.1",
+ "objc2 0.5.2",
+ "objc2-foundation 0.2.2",
+]
+
+[[package]]
+name = "objc2-quartz-core"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e42bee7bff906b14b167da2bac5efe6b6a07e6f7c0a21a7308d40c960242dc7a"
+dependencies = [
+ "bitflags",
+ "block2 0.5.1",
+ "objc2 0.5.2",
+ "objc2-foundation 0.2.2",
+ "objc2-metal",
+]
+
+[[package]]
+name = "once_cell"
+version = "1.21.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
+
+[[package]]
+name = "once_cell_polyfill"
+version = "1.70.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a4895175b425cb1f87721b59f0f286c2092bd4af812243672510e1ac53e2e0ad"
+
+[[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.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "70d58bf43669b5795d1576d0641cfb6fbb2057bf629506267a92807158584a13"
+dependencies = [
+ "lock_api",
+ "parking_lot_core",
+]
+
+[[package]]
+name = "parking_lot_core"
+version = "0.9.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bc838d2a56b5b1a6c25f55575dfc605fabb63bb2365f6c2353ef9159aa69e4a5"
+dependencies = [
+ "cfg-if",
+ "libc",
+ "redox_syscall",
+ "smallvec",
+ "windows-targets 0.52.6",
+]
+
+[[package]]
+name = "paste"
+version = "1.0.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a"
+
+[[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.16"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b"
+
+[[package]]
+name = "pin-utils"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
+
+[[package]]
+name = "pkg-config"
+version = "0.3.32"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c"
+
+[[package]]
+name = "png"
+version = "0.18.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "97baced388464909d42d89643fe4361939af9b7ce7a31ee32a168f832a70f2a0"
+dependencies = [
+ "bitflags",
+ "crc32fast",
+ "fdeflate",
+ "flate2",
+ "miniz_oxide",
+]
+
+[[package]]
+name = "portable-atomic"
+version = "1.11.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f84267b20a16ea918e43c6a88433c2d54fa145c92a811b5b047ccbe153674483"
+
+[[package]]
+name = "portable-atomic-util"
+version = "0.2.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d8a2f0d8d040d7848a709caf78912debcc3f33ee4b3cac47d73d1e1069e83507"
+dependencies = [
+ "portable-atomic",
+]
+
+[[package]]
+name = "potential_utf"
+version = "0.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "84df19adbe5b5a0782edcab45899906947ab039ccf4573713735ee7de1e6b08a"
+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",
+ "toml_edit 0.20.2",
+]
+
+[[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.101"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de"
+dependencies = [
+ "unicode-ident",
+]
+
+[[package]]
+name = "profiling"
+version = "1.0.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3eb8486b569e12e2c32ad3e204dbaba5e4b5b216e9367044f25f1dba42341773"
+dependencies = [
+ "profiling-procmacros",
+]
+
+[[package]]
+name = "profiling-procmacros"
+version = "1.0.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "52717f9a02b6965224f95ca2a81e2e0c5c43baacd28ca057577988930b6c3d5b"
+dependencies = [
+ "quote",
+ "syn 2.0.106",
+]
+
+[[package]]
+name = "pxfm"
+version = "0.1.20"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6e790881194f6f6e86945f0a42a6981977323669aeb6c40e9c7ec253133b96f8"
+dependencies = [
+ "num-traits",
+]
+
+[[package]]
+name = "qoi"
+version = "0.4.1"
+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.37.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "331e97a1af0bf59823e6eadffe373d7b27f485be8748f71471c662c1f269b7fb"
+dependencies = [
+ "memchr",
+]
+
+[[package]]
+name = "quote"
+version = "1.0.40"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d"
+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.8.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
+dependencies = [
+ "libc",
+ "rand_chacha",
+ "rand_core",
+]
+
+[[package]]
+name = "rand_chacha"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
+dependencies = [
+ "ppv-lite86",
+ "rand_core",
+]
+
+[[package]]
+name = "rand_core"
+version = "0.6.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
+dependencies = [
+ "getrandom 0.2.16",
+]
+
+[[package]]
+name = "rav1e"
+version = "0.7.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cd87ce80a7665b1cce111f8a16c1f3929f6547ce91ade6addf4ec86a8dda5ce9"
+dependencies = [
+ "arbitrary",
+ "arg_enum_proc_macro",
+ "arrayvec",
+ "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",
+ "once_cell",
+ "paste",
+ "profiling",
+ "rand",
+ "rand_chacha",
+ "simd_helpers",
+ "system-deps",
+ "thiserror",
+ "v_frame",
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "ravif"
+version = "0.11.20"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5825c26fddd16ab9f515930d49028a630efec172e903483c94796cfe31893e6b"
+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.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "368f01d005bf8fd9b1206fb6fa653e6c4a81ceb1466406b81792d87c5677a58f"
+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.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5407465600fb0548f1442edf71dd20683c6ed326200ace4b1ef0763521bb3b77"
+dependencies = [
+ "bitflags",
+]
+
+[[package]]
+name = "regex"
+version = "1.11.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "23d7fd106d8c02486a8d64e778353d1cffe08ce79ac2e82f540c86d0facf6912"
+dependencies = [
+ "aho-corasick",
+ "memchr",
+ "regex-automata",
+ "regex-syntax",
+]
+
+[[package]]
+name = "regex-automata"
+version = "0.4.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6b9458fa0bfeeac22b5ca447c63aaf45f28439a709ccd244698632f9aa6394d6"
+dependencies = [
+ "aho-corasick",
+ "memchr",
+ "regex-syntax",
+]
+
+[[package]]
+name = "regex-syntax"
+version = "0.8.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "caf4aa5b0f434c91fe5c7f1ecb6a5ece2130b02ad2a590589dda5146df959001"
+
+[[package]]
+name = "rgb"
+version = "0.8.52"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0c6a884d2998352bb4daf0183589aec883f16a6da1f4dde84d8e2e9a5409a1ce"
+
+[[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.0.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "11181fbabf243db407ef8df94a6ce0b2f9a733bd8be4ad02b4eda9602296cac8"
+dependencies = [
+ "bitflags",
+ "errno",
+ "libc",
+ "linux-raw-sys 0.9.4",
+ "windows-sys 0.60.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.26"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "56e6fa9c48d24d85fb3de5ad847117517440f6beceb7798af16b4a87d616b8d0"
+
+[[package]]
+name = "serde"
+version = "1.0.219"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6"
+dependencies = [
+ "serde_derive",
+]
+
+[[package]]
+name = "serde_derive"
+version = "1.0.219"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.106",
+]
+
+[[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.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe"
+
+[[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.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7a2ae44ef20feb57a68b23d846850f861394c2e02dc425a50098ae8c90267589"
+
+[[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.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "18051cdd562e792cad055119e0cdb2cfc137e44e3987532e0f9659a77931bb08"
+dependencies = [
+ "as-raw-xcb-connection",
+ "bytemuck",
+ "cfg_aliases",
+ "core-graphics",
+ "drm",
+ "fastrand",
+ "foreign-types",
+ "js-sys",
+ "log",
+ "memmap2",
+ "objc2 0.5.2",
+ "objc2-foundation 0.2.2",
+ "objc2-quartz-core",
+ "raw-window-handle 0.6.2",
+ "redox_syscall",
+ "rustix 0.38.44",
+ "tiny-xlib",
+ "wasm-bindgen",
+ "wayland-backend",
+ "wayland-client",
+ "wayland-sys",
+ "web-sys",
+ "windows-sys 0.59.0",
+ "x11rb",
+]
+
+[[package]]
+name = "stable_deref_trait"
+version = "1.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3"
+
+[[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.106"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6"
+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.106",
+]
+
+[[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.34.3"
+dependencies = [
+ "bitflags",
+ "block2 0.6.1",
+ "core-foundation",
+ "core-graphics",
+ "crossbeam-channel",
+ "dispatch",
+ "dlopen2",
+ "dpi",
+ "env_logger",
+ "gdkwayland-sys",
+ "gdkx11-sys",
+ "gtk",
+ "image",
+ "jni",
+ "lazy_static",
+ "libc",
+ "log",
+ "ndk",
+ "ndk-context",
+ "ndk-sys",
+ "objc2 0.6.2",
+ "objc2-app-kit",
+ "objc2-foundation 0.3.1",
+ "once_cell",
+ "parking_lot",
+ "raw-window-handle 0.4.3",
+ "raw-window-handle 0.5.2",
+ "raw-window-handle 0.6.2",
+ "scopeguard",
+ "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.106",
+]
+
+[[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",
+]
+
+[[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.106",
+]
+
+[[package]]
+name = "tiff"
+version = "0.10.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "af9605de7fee8d9551863fd692cce7637f548dbd9db9180fcc07ccc6d26c336f"
+dependencies = [
+ "fax",
+ "flate2",
+ "half",
+ "quick-error",
+ "weezl",
+ "zune-jpeg",
+]
+
+[[package]]
+name = "tiny-xlib"
+version = "0.2.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0324504befd01cab6e0c994f34b2ffa257849ee019d3fb3b64fb2c858887d89e"
+dependencies = [
+ "as-raw-xcb-connection",
+ "ctor-lite",
+ "libloading",
+ "pkg-config",
+ "tracing",
+]
+
+[[package]]
+name = "tinystr"
+version = "0.8.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5d4f6d1145dcb577acf783d4e601bc1d76a13337bb54e6233add580b07344c8b"
+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",
+ "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_edit"
+version = "0.19.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421"
+dependencies = [
+ "indexmap",
+ "toml_datetime",
+ "winnow",
+]
+
+[[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",
+ "winnow",
+]
+
+[[package]]
+name = "tracing"
+version = "0.1.41"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0"
+dependencies = [
+ "pin-project-lite",
+ "tracing-core",
+]
+
+[[package]]
+name = "tracing-core"
+version = "0.1.34"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b9d12581f227e93f094d3af2ae690a574abb8a2b9b7a96e7cfe9647b2b617678"
+
+[[package]]
+name = "unicode-ident"
+version = "1.0.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512"
+
+[[package]]
+name = "unicode-segmentation"
+version = "1.12.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493"
+
+[[package]]
+name = "url"
+version = "2.5.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "08bc136a29a3d1758e07a9cca267be308aeebf5cfd5a10f3f67ab2097683ef5b"
+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.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "852e951cb7832cb45cb1169900d19760cfa39b82bc0ea9c0e5a14ae88411c98b"
+
+[[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 = "wasi"
+version = "0.11.1+wasi-snapshot-preview1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b"
+
+[[package]]
+name = "wasi"
+version = "0.14.3+wasi-0.2.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6a51ae83037bdd272a9e28ce236db8c07016dd0d50c27038b3f407533c030c95"
+dependencies = [
+ "wit-bindgen",
+]
+
+[[package]]
+name = "wasm-bindgen"
+version = "0.2.100"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5"
+dependencies = [
+ "cfg-if",
+ "once_cell",
+ "rustversion",
+ "wasm-bindgen-macro",
+]
+
+[[package]]
+name = "wasm-bindgen-backend"
+version = "0.2.100"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6"
+dependencies = [
+ "bumpalo",
+ "log",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.106",
+ "wasm-bindgen-shared",
+]
+
+[[package]]
+name = "wasm-bindgen-macro"
+version = "0.2.100"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407"
+dependencies = [
+ "quote",
+ "wasm-bindgen-macro-support",
+]
+
+[[package]]
+name = "wasm-bindgen-macro-support"
+version = "0.2.100"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.106",
+ "wasm-bindgen-backend",
+ "wasm-bindgen-shared",
+]
+
+[[package]]
+name = "wasm-bindgen-shared"
+version = "0.2.100"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d"
+dependencies = [
+ "unicode-ident",
+]
+
+[[package]]
+name = "wayland-backend"
+version = "0.3.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "673a33c33048a5ade91a6b139580fa174e19fb0d23f396dca9fa15f2e1e49b35"
+dependencies = [
+ "cc",
+ "downcast-rs",
+ "rustix 1.0.8",
+ "scoped-tls",
+ "smallvec",
+ "wayland-sys",
+]
+
+[[package]]
+name = "wayland-client"
+version = "0.31.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c66a47e840dc20793f2264eb4b3e4ecb4b75d91c0dd4af04b456128e0bdd449d"
+dependencies = [
+ "bitflags",
+ "rustix 1.0.8",
+ "wayland-backend",
+ "wayland-scanner",
+]
+
+[[package]]
+name = "wayland-scanner"
+version = "0.31.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "54cb1e9dc49da91950bdfd8b848c49330536d9d1fb03d4bfec8cae50caa50ae3"
+dependencies = [
+ "proc-macro2",
+ "quick-xml",
+ "quote",
+]
+
+[[package]]
+name = "wayland-sys"
+version = "0.31.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "34949b42822155826b41db8e5d0c1be3a2bd296c747577a43a3e6daefc296142"
+dependencies = [
+ "dlib",
+ "log",
+ "once_cell",
+ "pkg-config",
+]
+
+[[package]]
+name = "web-sys"
+version = "0.3.77"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "33b6dd2ef9186f1f2072e409e99cd22a975331a6b3591b12c764e0e55c60d5d2"
+dependencies = [
+ "js-sys",
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "weezl"
+version = "0.1.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a751b3277700db47d3e574514de2eced5e54dc8a5436a3bf7a0b248b2cee16f3"
+
+[[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.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0978bf7171b3d90bac376700cb56d606feb40f251a475a5d6634613564460b22"
+dependencies = [
+ "windows-sys 0.60.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",
+ "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",
+ "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",
+ "windows-threading",
+]
+
+[[package]]
+name = "windows-implement"
+version = "0.60.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.106",
+]
+
+[[package]]
+name = "windows-interface"
+version = "0.59.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.106",
+]
+
+[[package]]
+name = "windows-link"
+version = "0.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a"
+
+[[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",
+]
+
+[[package]]
+name = "windows-result"
+version = "0.3.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6"
+dependencies = [
+ "windows-link",
+]
+
+[[package]]
+name = "windows-strings"
+version = "0.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57"
+dependencies = [
+ "windows-link",
+]
+
+[[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.60.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb"
+dependencies = [
+ "windows-targets 0.53.3",
+]
+
+[[package]]
+name = "windows-targets"
+version = "0.42.2"
+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 0.52.6",
+ "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-targets"
+version = "0.53.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d5fe6031c4041849d7c496a8ded650796e7b6ecc19df1a431c1a363342e5dc91"
+dependencies = [
+ "windows-link",
+ "windows_aarch64_gnullvm 0.53.0",
+ "windows_aarch64_msvc 0.53.0",
+ "windows_i686_gnu 0.53.0",
+ "windows_i686_gnullvm 0.53.0",
+ "windows_i686_msvc 0.53.0",
+ "windows_x86_64_gnu 0.53.0",
+ "windows_x86_64_gnullvm 0.53.0",
+ "windows_x86_64_msvc 0.53.0",
+]
+
+[[package]]
+name = "windows-threading"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b66463ad2e0ea3bbf808b7f1d371311c80e115c0b71d60efc142cafbcfb057a6"
+dependencies = [
+ "windows-link",
+]
+
+[[package]]
+name = "windows-version"
+version = "0.1.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e04a5c6627e310a23ad2358483286c7df260c964eb2d003d8efd6d0f4e79265c"
+dependencies = [
+ "windows-link",
+]
+
+[[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_gnullvm"
+version = "0.53.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764"
+
+[[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_aarch64_msvc"
+version = "0.53.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c"
+
+[[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_gnu"
+version = "0.53.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3"
+
+[[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_gnullvm"
+version = "0.53.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11"
+
+[[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_i686_msvc"
+version = "0.53.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d"
+
+[[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_gnu"
+version = "0.53.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba"
+
+[[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_gnullvm"
+version = "0.53.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57"
+
+[[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 = "windows_x86_64_msvc"
+version = "0.53.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486"
+
+[[package]]
+name = "winnow"
+version = "0.5.40"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876"
+dependencies = [
+ "memchr",
+]
+
+[[package]]
+name = "wit-bindgen"
+version = "0.45.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "052283831dbae3d879dc7f51f3d92703a316ca49f91540417d38591826127814"
+
+[[package]]
+name = "writeable"
+version = "0.6.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ea2f10b9bb0928dfb1b42b65e1f9e36f7f54dbdf08457afefb38afcdec4fa2bb"
+
+[[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.0.8",
+ "x11rb-protocol",
+]
+
+[[package]]
+name = "x11rb-protocol"
+version = "0.13.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ea6fc2961e4ef194dcbfe56bb845534d0dc8098940c7e5c012a258bfec6701bd"
+
+[[package]]
+name = "yoke"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5f41bb01b8226ef4bfd589436a297c53d118f65921786300e427be8d487695cc"
+dependencies = [
+ "serde",
+ "stable_deref_trait",
+ "yoke-derive",
+ "zerofrom",
+]
+
+[[package]]
+name = "yoke-derive"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.106",
+ "synstructure",
+]
+
+[[package]]
+name = "zerocopy"
+version = "0.8.26"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1039dd0d3c310cf05de012d8a39ff557cb0d23087fd44cad61df08fc31907a2f"
+dependencies = [
+ "zerocopy-derive",
+]
+
+[[package]]
+name = "zerocopy-derive"
+version = "0.8.26"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9ecf5b4cc5364572d7f4c329661bcc82724222973f2cab6f050a4e5c22f75181"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.106",
+]
+
+[[package]]
+name = "zerofrom"
+version = "0.1.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5"
+dependencies = [
+ "zerofrom-derive",
+]
+
+[[package]]
+name = "zerofrom-derive"
+version = "0.1.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.106",
+ "synstructure",
+]
+
+[[package]]
+name = "zerotrie"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "36f0bbd478583f79edad978b407914f61b2972f5af6fa089686016be8f9af595"
+dependencies = [
+ "displaydoc",
+ "yoke",
+ "zerofrom",
+]
+
+[[package]]
+name = "zerovec"
+version = "0.11.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e7aa2bd55086f1ab526693ecbe444205da57e25f4489879da80635a46d90e73b"
+dependencies = [
+ "yoke",
+ "zerofrom",
+ "zerovec-derive",
+]
+
+[[package]]
+name = "zerovec-derive"
+version = "0.11.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.106",
+]
+
+[[package]]
+name = "zune-core"
+version = "0.4.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3f423a2c17029964870cfaabb1f13dfab7d092a62a29a89264f4d36990ca414a"
+
+[[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.4.20"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fc1f7e205ce79eb2da3cd71c5f55f3589785cb7c79f6a03d1c8d1491bda5d089"
+dependencies = [
+ "zune-core",
+]
diff --git a/vendor/tao/Cargo.toml b/vendor/tao/Cargo.toml
new file mode 100644
index 00000000000..13c0c01c605
--- /dev/null
+++ b/vendor/tao/Cargo.toml
@@ -0,0 +1,390 @@
+# 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.34.3"
+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]
+default-target = "x86_64-unknown-linux-gnu"
+features = [
+ "rwh_04",
+ "rwh_05",
+ "rwh_06",
+ "serde",
+ "x11",
+]
+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",
+]
+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.lazy_static]
+version = "1"
+
+[dependencies.libc]
+version = "0.2"
+
+[dependencies.log]
+version = "0.4"
+
+[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 = "android", target_os = "windows"))'.dependencies.once_cell]
+version = "1"
+
+[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.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-context]
+version = "0.1"
+
+[target.'cfg(target_os = "android")'.dependencies.ndk-sys]
+version = "0.6"
+
+[target.'cfg(target_os = "android")'.dependencies.tao-macros]
+version = "0.1.0"
+
+[target.'cfg(target_os = "macos")'.dependencies.core-foundation]
+version = "0.10"
+
+[target.'cfg(target_os = "macos")'.dependencies.core-graphics]
+version = "0.24"
+
+[target.'cfg(target_os = "macos")'.dependencies.dispatch]
+version = "0.2"
+
+[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 = "macos")'.dependencies.scopeguard]
+version = "1.2"
+
+[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_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/vendor/tao/Cargo.toml.orig b/vendor/tao/Cargo.toml.orig
new file mode 100644
index 00000000000..5b0f5d2c44e
--- /dev/null
+++ b/vendor/tao/Cargo.toml.orig
@@ -0,0 +1,158 @@
+[package]
+name = "tao"
+version = "0.34.3"
+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" ]
+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" ]
+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" ]
+
+[workspace]
+members = [ "tao-macros" ]
+
+[dependencies]
+lazy_static = "1"
+libc = "0.2"
+log = "0.4"
+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_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(any(target_os = \"android\", target_os = \"windows\"))".dependencies]
+once_cell = "1"
+
+[target."cfg(target_os = \"android\")".dependencies]
+jni = "0.21"
+ndk = "0.9"
+ndk-sys = "0.6"
+ndk-context = "0.1"
+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.24"
+dispatch = "0.2"
+scopeguard = "1.2"
+
+[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"
diff --git a/vendor/tao/LICENSE b/vendor/tao/LICENSE
new file mode 100644
index 00000000000..ad410e11302
--- /dev/null
+++ b/vendor/tao/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/vendor/tao/LICENSE.spdx b/vendor/tao/LICENSE.spdx
new file mode 100644
index 00000000000..ac886c6d67b
--- /dev/null
+++ b/vendor/tao/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/vendor/tao/README.md b/vendor/tao/README.md
new file mode 100644
index 00000000000..a7d5046194a
--- /dev/null
+++ b/vendor/tao/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/vendor/tao/examples/control_flow.rs b/vendor/tao/examples/control_flow.rs
new file mode 100644
index 00000000000..45148bfd235
--- /dev/null
+++ b/vendor/tao/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/vendor/tao/examples/cursor.rs b/vendor/tao/examples/cursor.rs
new file mode 100644
index 00000000000..48a91d6a9e8
--- /dev/null
+++ b/vendor/tao/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/vendor/tao/examples/cursor_grab.rs b/vendor/tao/examples/cursor_grab.rs
new file mode 100644
index 00000000000..a939d820105
--- /dev/null
+++ b/vendor/tao/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/vendor/tao/examples/custom_events.rs b/vendor/tao/examples/custom_events.rs
new file mode 100644
index 00000000000..f94d001135e
--- /dev/null
+++ b/vendor/tao/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/vendor/tao/examples/decorations.rs b/vendor/tao/examples/decorations.rs
new file mode 100644
index 00000000000..d9025e2b46e
--- /dev/null
+++ b/vendor/tao/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/vendor/tao/examples/drag_window.rs b/vendor/tao/examples/drag_window.rs
new file mode 100644
index 00000000000..895c360d393
--- /dev/null
+++ b/vendor/tao/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/vendor/tao/examples/fullscreen.rs b/vendor/tao/examples/fullscreen.rs
new file mode 100644
index 00000000000..c5d8bfacd74
--- /dev/null
+++ b/vendor/tao/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/vendor/tao/examples/handling_close.rs b/vendor/tao/examples/handling_close.rs
new file mode 100644
index 00000000000..278a646fc77
--- /dev/null
+++ b/vendor/tao/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/vendor/tao/examples/min_max_size.rs b/vendor/tao/examples/min_max_size.rs
new file mode 100644
index 00000000000..6ad631faa84
--- /dev/null
+++ b/vendor/tao/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/vendor/tao/examples/minimize.rs b/vendor/tao/examples/minimize.rs
new file mode 100644
index 00000000000..76ceeb7b511
--- /dev/null
+++ b/vendor/tao/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/vendor/tao/examples/monitor_list.rs b/vendor/tao/examples/monitor_list.rs
new file mode 100644
index 00000000000..02ea917d652
--- /dev/null
+++ b/vendor/tao/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/vendor/tao/examples/mouse_wheel.rs b/vendor/tao/examples/mouse_wheel.rs
new file mode 100644
index 00000000000..8997a5e6f0e
--- /dev/null
+++ b/vendor/tao/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/vendor/tao/examples/multithreaded.rs b/vendor/tao/examples/multithreaded.rs
new file mode 100644
index 00000000000..7dfe9963256
--- /dev/null
+++ b/vendor/tao/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/vendor/tao/examples/multiwindow.rs b/vendor/tao/examples/multiwindow.rs
new file mode 100644
index 00000000000..32973057a57
--- /dev/null
+++ b/vendor/tao/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/vendor/tao/examples/overlay.rs b/vendor/tao/examples/overlay.rs
new file mode 100644
index 00000000000..03f290c61aa
--- /dev/null
+++ b/vendor/tao/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/vendor/tao/examples/parentwindow.rs b/vendor/tao/examples/parentwindow.rs
new file mode 100644
index 00000000000..54256510594
--- /dev/null
+++ b/vendor/tao/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/vendor/tao/examples/progress_bar.rs b/vendor/tao/examples/progress_bar.rs
new file mode 100644
index 00000000000..c526a74cc84
--- /dev/null
+++ b/vendor/tao/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/vendor/tao/examples/reopen_event.rs b/vendor/tao/examples/reopen_event.rs
new file mode 100644
index 00000000000..5b14ef4a2a7
--- /dev/null
+++ b/vendor/tao/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/vendor/tao/examples/request_redraw.rs b/vendor/tao/examples/request_redraw.rs
new file mode 100644
index 00000000000..f3f563c6fcb
--- /dev/null
+++ b/vendor/tao/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/vendor/tao/examples/request_redraw_threaded.rs b/vendor/tao/examples/request_redraw_threaded.rs
new file mode 100644
index 00000000000..069d65d52aa
--- /dev/null
+++ b/vendor/tao/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/vendor/tao/examples/resizable.rs b/vendor/tao/examples/resizable.rs
new file mode 100644
index 00000000000..e0d8c16f249
--- /dev/null
+++ b/vendor/tao/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/vendor/tao/examples/set_ime_position.rs b/vendor/tao/examples/set_ime_position.rs
new file mode 100644
index 00000000000..2310f5c5a05
--- /dev/null
+++ b/vendor/tao/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/vendor/tao/examples/theme.rs b/vendor/tao/examples/theme.rs
new file mode 100644
index 00000000000..c0e3284b9a2
--- /dev/null
+++ b/vendor/tao/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/vendor/tao/examples/timer.rs b/vendor/tao/examples/timer.rs
new file mode 100644
index 00000000000..eb3ce6f38d0
--- /dev/null
+++ b/vendor/tao/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/vendor/tao/examples/transparent.rs b/vendor/tao/examples/transparent.rs
new file mode 100644
index 00000000000..22c99c9a19d
--- /dev/null
+++ b/vendor/tao/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/vendor/tao/examples/video_modes.rs b/vendor/tao/examples/video_modes.rs
new file mode 100644
index 00000000000..d40b3f6e3b9
--- /dev/null
+++ b/vendor/tao/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/vendor/tao/examples/window.rs b/vendor/tao/examples/window.rs
new file mode 100644
index 00000000000..c4804fc4c02
--- /dev/null
+++ b/vendor/tao/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/vendor/tao/examples/window_debug.rs b/vendor/tao/examples/window_debug.rs
new file mode 100644
index 00000000000..1bb04c47820
--- /dev/null
+++ b/vendor/tao/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/vendor/tao/examples/window_icon.rs b/vendor/tao/examples/window_icon.rs
new file mode 100644
index 00000000000..bc5c4c61000
--- /dev/null
+++ b/vendor/tao/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/vendor/tao/examples/window_run_return.rs b/vendor/tao/examples/window_run_return.rs
new file mode 100644
index 00000000000..ebae8ac8b90
--- /dev/null
+++ b/vendor/tao/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/vendor/tao/src/error.rs b/vendor/tao/src/error.rs
new file mode 100644
index 00000000000..3bc21cedcc5
--- /dev/null
+++ b/vendor/tao/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/vendor/tao/src/event.rs b/vendor/tao/src/event.rs
new file mode 100644
index 00000000000..54b77ce7d3d
--- /dev/null
+++ b/vendor/tao/src/event.rs
@@ -0,0 +1,928 @@
+// 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.
+ Suspended,
+
+ /// Emitted when the application has been resumed.
+ 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 },
+}
+
+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,
+ },
+ }
+ }
+}
+
+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,
+ }),
+ }
+ }
+
+ /// 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,
+ }),
+ }
+ }
+}
+
+/// 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
+ ///
+ /// - **Linux / 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/vendor/tao/src/event_loop.rs b/vendor/tao/src/event_loop.rs
new file mode 100644
index 00000000000..8b01f3232d2
--- /dev/null
+++ b/vendor/tao/src/event_loop.rs
@@ -0,0 +1,411 @@
+// 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 {
+ 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)]
+pub enum DeviceEventFilter {
+ /// Always filter out device events.
+ Always,
+ /// Filter out device events while the window is not focused.
+ Unfocused,
+ /// Report all device events regardless of window focus.
+ Never,
+}
+
+impl Default for DeviceEventFilter {
+ fn default() -> Self {
+ Self::Unfocused
+ }
+}
diff --git a/vendor/tao/src/icon.rs b/vendor/tao/src/icon.rs
new file mode 100644
index 00000000000..8827e77bf00
--- /dev/null
+++ b/vendor/tao/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/vendor/tao/src/keyboard.rs b/vendor/tao/src/keyboard.rs
new file mode 100644
index 00000000000..ac50d42c530
--- /dev/null
+++ b/vendor/tao/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/vendor/tao/src/lib.rs b/vendor/tao/src/lib.rs
new file mode 100644
index 00000000000..072dbb6508d
--- /dev/null
+++ b/vendor/tao/src/lib.rs
@@ -0,0 +1,199 @@
+// 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 lazy_static;
+#[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/vendor/tao/src/monitor.rs b/vendor/tao/src/monitor.rs
new file mode 100644
index 00000000000..7e5404f578e
--- /dev/null
+++ b/vendor/tao/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/vendor/tao/src/platform/android.rs b/vendor/tao/src/platform/android.rs
new file mode 100644
index 00000000000..47b45c76e89
--- /dev/null
+++ b/vendor/tao/src/platform/android.rs
@@ -0,0 +1,48 @@
+// 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;
+}
+
+impl WindowExtAndroid for Window {
+ fn content_rect(&self) -> Rect {
+ self.window.content_rect()
+ }
+
+ fn config(&self) -> Configuration {
+ self.window.config()
+ }
+}
+
+impl EventLoopWindowTargetExtAndroid for EventLoopWindowTarget {}
+
+/// Additional methods on `WindowBuilder` that are specific to Android.
+pub trait WindowBuilderExtAndroid {}
+
+impl WindowBuilderExtAndroid for WindowBuilder {}
diff --git a/vendor/tao/src/platform/ios.rs b/vendor/tao/src/platform/ios.rs
new file mode 100644
index 00000000000..42b1f8a279d
--- /dev/null
+++ b/vendor/tao/src/platform/ios.rs
@@ -0,0 +1,345 @@
+// 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);
+}
+
+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)
+ }
+}
+
+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;
+}
+
+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
+ }
+}
+
+/// 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();
+ }
+}
diff --git a/vendor/tao/src/platform/linux.rs b/vendor/tao/src/platform/linux.rs
new file mode 100644
index 00000000000..2f0603c23a0
--- /dev/null
+++ b/vendor/tao/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/vendor/tao/src/platform/macos.rs b/vendor/tao/src/platform/macos.rs
new file mode 100644
index 00000000000..32b8cbbf3f5
--- /dev/null
+++ b/vendor/tao/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/vendor/tao/src/platform/mod.rs b/vendor/tao/src/platform/mod.rs
new file mode 100644
index 00000000000..2ca20b36d4e
--- /dev/null
+++ b/vendor/tao/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/vendor/tao/src/platform/run_return.rs b/vendor/tao/src/platform/run_return.rs
new file mode 100644
index 00000000000..e86ae1f6abb
--- /dev/null
+++ b/vendor/tao/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/vendor/tao/src/platform/unix.rs b/vendor/tao/src/platform/unix.rs
new file mode 100644
index 00000000000..88584869e41
--- /dev/null
+++ b/vendor/tao/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: 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/vendor/tao/src/platform/windows.rs b/vendor/tao/src/platform/windows.rs
new file mode 100644
index 00000000000..a248b04b3af
--- /dev/null
+++ b/vendor/tao/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/vendor/tao/src/platform_impl/android/mod.rs b/vendor/tao/src/platform_impl/android/mod.rs
new file mode 100644
index 00000000000..45d02f1c20c
--- /dev/null
+++ b/vendor/tao/src/platform_impl/android/mod.rs
@@ -0,0 +1,1262 @@
+// 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")]
+use crate::{
+ dpi::{PhysicalPosition, PhysicalSize, Position, Size},
+ error, event,
+ event_loop::{self, ControlFlow},
+ keyboard::{Key, KeyCode, KeyLocation, NativeKeyCode},
+ monitor,
+ window::{self, ResizeDirection, Theme, WindowSizeConstraints},
+};
+use crossbeam_channel::{Receiver, Sender};
+use ndk::{
+ configuration::Configuration,
+ event::{InputEvent, KeyAction, MotionAction},
+ looper::{ForeignLooper, Poll, ThreadLooper},
+};
+use std::{
+ collections::VecDeque,
+ sync::RwLock,
+ time::{Duration, Instant},
+};
+
+pub mod ndk_glue;
+use ndk_glue::{Event, Rect};
+
+lazy_static! {
+ static ref CONFIG: RwLock = RwLock::new(Configuration::new());
+}
+
+enum EventSource {
+ Callback,
+ InputQueue,
+ User,
+}
+
+fn poll(poll: Poll) -> Option {
+ match poll {
+ Poll::Event { ident, .. } => match ident {
+ ndk_glue::NDK_GLUE_LOOPER_EVENT_PIPE_IDENT => Some(EventSource::Callback),
+ ndk_glue::NDK_GLUE_LOOPER_INPUT_QUEUE_IDENT => Some(EventSource::InputQueue),
+ _ => unreachable!(),
+ },
+ Poll::Timeout => None,
+ Poll::Wake => Some(EventSource::User),
+ Poll::Callback => unreachable!(),
+ }
+}
+
+#[derive(Debug, Clone, Eq, PartialEq, Hash)]
+pub struct KeyEventExtra {}
+
+pub struct EventLoop {
+ window_target: event_loop::EventLoopWindowTarget,
+ receiver: Receiver,
+ sender_to_clone: Sender,
+ first_event: Option,
+ start_cause: event::StartCause,
+ looper: ThreadLooper,
+ running: bool,
+}
+
+#[derive(Default, Debug, Copy, Clone, PartialEq, Eq, Hash)]
+pub(crate) struct PlatformSpecificEventLoopAttributes {}
+
+macro_rules! call_event_handler {
+ ( $event_handler:expr, $window_target:expr, $cf:expr, $event:expr ) => {{
+ if let ControlFlow::ExitWithCode(code) = $cf {
+ $event_handler($event, $window_target, &mut ControlFlow::ExitWithCode(code));
+ } else {
+ $event_handler($event, $window_target, &mut $cf);
+ }
+ }};
+}
+
+impl EventLoop {
+ pub(crate) fn new(_: &PlatformSpecificEventLoopAttributes) -> Self {
+ let (sender, receiver) = crossbeam_channel::unbounded();
+
+ Self {
+ window_target: event_loop::EventLoopWindowTarget {
+ p: EventLoopWindowTarget {
+ _marker: std::marker::PhantomData,
+ },
+ _marker: std::marker::PhantomData,
+ },
+ sender_to_clone: sender,
+ receiver,
+ first_event: None,
+ start_cause: event::StartCause::Init,
+ looper: ThreadLooper::for_thread().unwrap(),
+ running: false,
+ }
+ }
+
+ pub fn run(mut self, event_handler: F) -> !
+ where
+ F:
+ 'static + FnMut(event::Event<'_, T>, &event_loop::EventLoopWindowTarget, &mut ControlFlow),
+ {
+ let exit_code = self.run_return(event_handler);
+ ::std::process::exit(exit_code);
+ }
+
+ pub fn run_return(&mut self, mut event_handler: F) -> i32
+ where
+ F: FnMut(event::Event<'_, T>, &event_loop::EventLoopWindowTarget, &mut ControlFlow),
+ {
+ let mut control_flow = ControlFlow::default();
+
+ 'event_loop: loop {
+ call_event_handler!(
+ event_handler,
+ self.window_target(),
+ control_flow,
+ event::Event::NewEvents(self.start_cause)
+ );
+
+ let mut redraw = false;
+ let mut resized = false;
+
+ match self.first_event.take() {
+ Some(EventSource::Callback) => match ndk_glue::poll_events().unwrap() {
+ Event::Resume => {
+ call_event_handler!(
+ event_handler,
+ self.window_target(),
+ control_flow,
+ event::Event::Resumed
+ );
+ }
+ Event::WindowResized => resized = true,
+ Event::WindowRedrawNeeded => redraw = true,
+ Event::Pause => {
+ call_event_handler!(
+ event_handler,
+ self.window_target(),
+ control_flow,
+ event::Event::Suspended
+ );
+ }
+ Event::Stop => self.running = false,
+ Event::Start => self.running = true,
+ Event::ConfigChanged => {
+ // #[allow(deprecated)] // TODO: use ndk-context instead
+ // let am = ndk_glue::native_activity().asset_manager();
+ // let config = Configuration::from_asset_manager(&am);
+ // let old_scale_factor = MonitorHandle.scale_factor();
+ // *CONFIG.write().unwrap() = config;
+ // let scale_factor = MonitorHandle.scale_factor();
+ // if (scale_factor - old_scale_factor).abs() < f64::EPSILON {
+ // let mut size = MonitorHandle.size();
+ // let event = event::Event::WindowEvent {
+ // window_id: window::WindowId(WindowId),
+ // event: event::WindowEvent::ScaleFactorChanged {
+ // new_inner_size: &mut size,
+ // scale_factor,
+ // },
+ // };
+ // call_event_handler!(event_handler, self.window_target(), control_flow, event);
+ // }
+ }
+ Event::WindowHasFocus => {
+ call_event_handler!(
+ event_handler,
+ self.window_target(),
+ control_flow,
+ event::Event::WindowEvent {
+ window_id: window::WindowId(WindowId),
+ event: event::WindowEvent::Focused(true),
+ }
+ );
+ }
+ Event::WindowLostFocus => {
+ call_event_handler!(
+ event_handler,
+ self.window_target(),
+ control_flow,
+ event::Event::WindowEvent {
+ window_id: window::WindowId(WindowId),
+ event: event::WindowEvent::Focused(false),
+ }
+ );
+ }
+ _ => {}
+ },
+ Some(EventSource::InputQueue) => {
+ if let Some(input_queue) = ndk_glue::input_queue().as_ref() {
+ while let Ok(Some(event)) = input_queue.event() {
+ if let Some(event) = input_queue.pre_dispatch(event) {
+ let mut handled = true;
+ let window_id = window::WindowId(WindowId);
+ let device_id = event::DeviceId(DeviceId);
+ match &event {
+ InputEvent::MotionEvent(motion_event) => {
+ let phase = match motion_event.action() {
+ MotionAction::Down | MotionAction::PointerDown => {
+ Some(event::TouchPhase::Started)
+ }
+ MotionAction::Up | MotionAction::PointerUp => Some(event::TouchPhase::Ended),
+ MotionAction::Move => Some(event::TouchPhase::Moved),
+ MotionAction::Cancel => Some(event::TouchPhase::Cancelled),
+ _ => {
+ handled = false;
+ None // TODO mouse events
+ }
+ };
+ if let Some(phase) = phase {
+ let pointers: Box>> = match phase
+ {
+ event::TouchPhase::Started | event::TouchPhase::Ended => {
+ Box::new(std::iter::once(
+ motion_event.pointer_at_index(motion_event.pointer_index()),
+ ))
+ }
+ event::TouchPhase::Moved | event::TouchPhase::Cancelled => {
+ Box::new(motion_event.pointers())
+ }
+ };
+
+ for pointer in pointers {
+ let location = PhysicalPosition {
+ x: pointer.x() as _,
+ y: pointer.y() as _,
+ };
+ let event = event::Event::WindowEvent {
+ window_id,
+ event: event::WindowEvent::Touch(event::Touch {
+ device_id,
+ phase,
+ location,
+ id: pointer.pointer_id() as u64,
+ force: None,
+ }),
+ };
+ call_event_handler!(
+ event_handler,
+ self.window_target(),
+ control_flow,
+ event
+ );
+ }
+ }
+ }
+ InputEvent::KeyEvent(key) => {
+ let state = match key.action() {
+ KeyAction::Down => event::ElementState::Pressed,
+ KeyAction::Up => event::ElementState::Released,
+ _ => event::ElementState::Released,
+ };
+
+ let keycode = key.key_code();
+ let native = NativeKeyCode::Android(keycode.into());
+ let physical_key = KeyCode::Unidentified(native);
+ let logical_key = keycode_to_logical(keycode, native);
+ // TODO: maybe use getUnicodeChar to get the logical key
+
+ let event = event::Event::WindowEvent {
+ window_id,
+ event: event::WindowEvent::KeyboardInput {
+ device_id,
+ event: event::KeyEvent {
+ state,
+ physical_key,
+ logical_key,
+ location: keycode_to_location(keycode),
+ repeat: key.repeat_count() > 0,
+ text: None,
+ platform_specific: KeyEventExtra {},
+ },
+ is_synthetic: false,
+ },
+ };
+ call_event_handler!(event_handler, self.window_target(), control_flow, event);
+ }
+ _ => {}
+ };
+ input_queue.finish_event(event, handled);
+ }
+ }
+ }
+ }
+ Some(EventSource::User) => {
+ while let Ok(event) = self.receiver.try_recv() {
+ call_event_handler!(
+ event_handler,
+ self.window_target(),
+ control_flow,
+ event::Event::UserEvent(event)
+ );
+ }
+ }
+ None => {}
+ }
+
+ call_event_handler!(
+ event_handler,
+ self.window_target(),
+ control_flow,
+ event::Event::MainEventsCleared
+ );
+
+ if resized && self.running {
+ let size = MonitorHandle.size();
+ let event = event::Event::WindowEvent {
+ window_id: window::WindowId(WindowId),
+ event: event::WindowEvent::Resized(size),
+ };
+ call_event_handler!(event_handler, self.window_target(), control_flow, event);
+ }
+
+ if redraw && self.running {
+ let event = event::Event::RedrawRequested(window::WindowId(WindowId));
+ call_event_handler!(event_handler, self.window_target(), control_flow, event);
+ }
+
+ call_event_handler!(
+ event_handler,
+ self.window_target(),
+ control_flow,
+ event::Event::RedrawEventsCleared
+ );
+
+ match control_flow {
+ ControlFlow::ExitWithCode(code) => {
+ self.first_event = poll(
+ self
+ .looper
+ .poll_once_timeout(Duration::from_millis(0))
+ .unwrap(),
+ );
+ self.start_cause = event::StartCause::WaitCancelled {
+ start: Instant::now(),
+ requested_resume: None,
+ };
+ break 'event_loop code;
+ }
+ ControlFlow::Poll => {
+ self.first_event = poll(
+ self
+ .looper
+ .poll_all_timeout(Duration::from_millis(0))
+ .unwrap(),
+ );
+ self.start_cause = event::StartCause::Poll;
+ }
+ ControlFlow::Wait => {
+ self.first_event = poll(self.looper.poll_all().unwrap());
+ self.start_cause = event::StartCause::WaitCancelled {
+ start: Instant::now(),
+ requested_resume: None,
+ }
+ }
+ ControlFlow::WaitUntil(instant) => {
+ let start = Instant::now();
+ let duration = if instant <= start {
+ Duration::default()
+ } else {
+ instant - start
+ };
+ self.first_event = poll(self.looper.poll_all_timeout(duration).unwrap());
+ self.start_cause = if self.first_event.is_some() {
+ event::StartCause::WaitCancelled {
+ start,
+ requested_resume: Some(instant),
+ }
+ } else {
+ event::StartCause::ResumeTimeReached {
+ start,
+ requested_resume: instant,
+ }
+ }
+ }
+ }
+ }
+ }
+
+ pub fn window_target(&self) -> &event_loop::EventLoopWindowTarget {
+ &self.window_target
+ }
+
+ pub fn create_proxy(&self) -> EventLoopProxy {
+ EventLoopProxy {
+ queue: self.sender_to_clone.clone(),
+ looper: ForeignLooper::for_thread().expect("called from event loop thread"),
+ }
+ }
+}
+
+pub struct EventLoopProxy {
+ queue: Sender,
+ looper: ForeignLooper,
+}
+
+impl EventLoopProxy {
+ pub fn send_event(&self, event: T) -> Result<(), event_loop::EventLoopClosed> {
+ _ = self.queue.try_send(event);
+ self.looper.wake();
+ Ok(())
+ }
+}
+
+impl Clone for EventLoopProxy {
+ fn clone(&self) -> Self {
+ EventLoopProxy {
+ queue: self.queue.clone(),
+ looper: self.looper.clone(),
+ }
+ }
+}
+
+#[derive(Clone)]
+pub struct EventLoopWindowTarget {
+ _marker: std::marker::PhantomData,
+}
+
+impl EventLoopWindowTarget {
+ pub fn primary_monitor(&self) -> Option {
+ Some(monitor::MonitorHandle {
+ inner: MonitorHandle,
+ })
+ }
+
+ #[inline]
+ pub fn monitor_from_point(&self, _x: f64, _y: f64) -> Option {
+ warn!("`Window::monitor_from_point` is ignored on Android");
+ return None;
+ }
+
+ pub fn available_monitors(&self) -> VecDeque {
+ let mut v = VecDeque::with_capacity(1);
+ v.push_back(MonitorHandle);
+ v
+ }
+
+ #[cfg(feature = "rwh_05")]
+ #[inline]
+ pub fn raw_display_handle_rwh_05(&self) -> rwh_05::RawDisplayHandle {
+ rwh_05::RawDisplayHandle::Android(rwh_05::AndroidDisplayHandle::empty())
+ }
+
+ #[cfg(feature = "rwh_06")]
+ #[inline]
+ pub fn raw_display_handle_rwh_06(&self) -> Result {
+ Ok(rwh_06::RawDisplayHandle::Android(
+ rwh_06::AndroidDisplayHandle::new(),
+ ))
+ }
+
+ pub fn cursor_position(&self) -> Result, error::ExternalError> {
+ debug!("`EventLoopWindowTarget::cursor_position` is ignored on Android");
+ Ok((0, 0).into())
+ }
+}
+
+#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
+pub struct WindowId;
+
+impl WindowId {
+ pub fn dummy() -> Self {
+ WindowId
+ }
+}
+
+#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
+pub struct DeviceId;
+
+impl DeviceId {
+ pub fn dummy() -> Self {
+ DeviceId
+ }
+}
+
+#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
+pub struct PlatformSpecificWindowBuilderAttributes;
+
+pub struct Window;
+
+impl Window {
+ pub fn new(
+ _el: &EventLoopWindowTarget,
+ _window_attrs: window::WindowAttributes,
+ _: PlatformSpecificWindowBuilderAttributes,
+ ) -> Result {
+ // FIXME this ignores requested window attributes
+ Ok(Self)
+ }
+
+ pub fn id(&self) -> WindowId {
+ WindowId
+ }
+
+ pub fn primary_monitor(&self) -> Option {
+ Some(monitor::MonitorHandle {
+ inner: MonitorHandle,
+ })
+ }
+
+ pub fn available_monitors(&self) -> VecDeque {
+ let mut v = VecDeque::with_capacity(1);
+ v.push_back(MonitorHandle);
+ v
+ }
+
+ #[inline]
+ pub fn monitor_from_point(&self, _x: f64, _y: f64) -> Option {
+ warn!("`Window::monitor_from_point` is ignored on Android");
+ None
+ }
+
+ pub fn current_monitor(&self) -> Option {
+ Some(monitor::MonitorHandle {
+ inner: MonitorHandle,
+ })
+ }
+
+ pub fn scale_factor(&self) -> f64 {
+ MonitorHandle.scale_factor()
+ }
+
+ pub fn request_redraw(&self) {
+ // TODO
+ }
+
+ pub fn inner_position(&self) -> Result, error::NotSupportedError> {
+ Err(error::NotSupportedError::new())
+ }
+
+ pub fn outer_position(&self) -> Result, error::NotSupportedError> {
+ Err(error::NotSupportedError::new())
+ }
+
+ pub fn set_outer_position(&self, _position: Position) {
+ // no effect
+ }
+
+ pub fn inner_size(&self) -> PhysicalSize {
+ self.outer_size()
+ }
+
+ pub fn set_inner_size(&self, _size: Size) {
+ warn!("Cannot set window size on Android");
+ }
+
+ pub fn outer_size(&self) -> PhysicalSize {
+ MonitorHandle.size()
+ }
+
+ pub fn set_min_inner_size(&self, _: Option) {}
+ pub fn set_max_inner_size(&self, _: Option) {}
+ pub fn set_inner_size_constraints(&self, _: WindowSizeConstraints) {}
+
+ pub fn set_title(&self, _title: &str) {}
+ pub fn title(&self) -> String {
+ String::new()
+ }
+
+ pub fn set_visible(&self, _visibility: bool) {}
+
+ pub fn set_focus(&self) {
+ //FIXME: implementation goes here
+ warn!("set_focus not yet implemented on Android");
+ }
+
+ pub fn set_focusable(&self, _focusable: bool) {
+ warn!("set_focusable not yet implemented on Android");
+ }
+
+ pub fn is_focused(&self) -> bool {
+ log::warn!("`Window::is_focused` is ignored on Android");
+ false
+ }
+
+ pub fn is_always_on_top(&self) -> bool {
+ log::warn!("`Window::is_always_on_top` is ignored on Android");
+ false
+ }
+
+ pub fn set_resizable(&self, _resizeable: bool) {
+ warn!("`Window::set_resizable` is ignored on Android")
+ }
+
+ pub fn set_minimizable(&self, _minimizable: bool) {
+ warn!("`Window::set_minimizable` is ignored on Android")
+ }
+
+ pub fn set_maximizable(&self, _maximizable: bool) {
+ warn!("`Window::set_maximizable` is ignored on Android")
+ }
+
+ pub fn set_closable(&self, _closable: bool) {
+ warn!("`Window::set_closable` is ignored on Android")
+ }
+
+ pub fn set_minimized(&self, _minimized: bool) {}
+
+ pub fn set_maximized(&self, _maximized: bool) {}
+
+ pub fn is_maximized(&self) -> bool {
+ false
+ }
+
+ pub fn is_minimized(&self) -> bool {
+ false
+ }
+
+ pub fn is_visible(&self) -> bool {
+ log::warn!("`Window::is_visible` is ignored on Android");
+ false
+ }
+
+ pub fn is_resizable(&self) -> bool {
+ warn!("`Window::is_resizable` is ignored on Android");
+ false
+ }
+
+ pub fn is_minimizable(&self) -> bool {
+ warn!("`Window::is_minimizable` is ignored on Android");
+ false
+ }
+
+ pub fn is_maximizable(&self) -> bool {
+ warn!("`Window::is_maximizable` is ignored on Android");
+ false
+ }
+
+ pub fn is_closable(&self) -> bool {
+ warn!("`Window::is_closable` is ignored on Android");
+ false
+ }
+
+ pub fn is_decorated(&self) -> bool {
+ warn!("`Window::is_decorated` is ignored on Android");
+ false
+ }
+
+ pub fn set_fullscreen(&self, _monitor: Option) {
+ warn!("Cannot set fullscreen on Android");
+ }
+
+ pub fn fullscreen(&self) -> Option {
+ None
+ }
+
+ pub fn set_decorations(&self, _decorations: bool) {}
+
+ pub fn set_always_on_bottom(&self, _always_on_bottom: bool) {}
+
+ pub fn set_always_on_top(&self, _always_on_top: bool) {}
+
+ pub fn set_window_icon(&self, _window_icon: Option) {}
+
+ pub fn set_ime_position(&self, _position: Position) {}
+
+ pub fn request_user_attention(&self, _request_type: Option) {}
+
+ pub fn set_cursor_icon(&self, _: window::CursorIcon) {}
+
+ pub fn set_cursor_position(&self, _: Position) -> Result<(), error::ExternalError> {
+ Err(error::ExternalError::NotSupported(
+ error::NotSupportedError::new(),
+ ))
+ }
+
+ pub fn set_cursor_grab(&self, _: bool) -> Result<(), error::ExternalError> {
+ Err(error::ExternalError::NotSupported(
+ error::NotSupportedError::new(),
+ ))
+ }
+
+ pub fn set_cursor_visible(&self, _: bool) {}
+
+ pub fn drag_window(&self) -> Result<(), error::ExternalError> {
+ Err(error::ExternalError::NotSupported(
+ error::NotSupportedError::new(),
+ ))
+ }
+
+ pub fn drag_resize_window(
+ &self,
+ _direction: ResizeDirection,
+ ) -> Result<(), error::ExternalError> {
+ Err(error::ExternalError::NotSupported(
+ error::NotSupportedError::new(),
+ ))
+ }
+
+ pub fn set_background_color(&self, _color: Option) {}
+
+ pub fn set_ignore_cursor_events(&self, _ignore: bool) -> Result<(), error::ExternalError> {
+ Err(error::ExternalError::NotSupported(
+ error::NotSupportedError::new(),
+ ))
+ }
+
+ pub fn cursor_position(&self) -> Result, error::ExternalError> {
+ debug!("`Window::cursor_position` is ignored on Android");
+ Ok((0, 0).into())
+ }
+
+ #[cfg(feature = "rwh_04")]
+ pub fn raw_window_handle_rwh_04(&self) -> rwh_04::RawWindowHandle {
+ // TODO: Use main activity instead?
+ let mut handle = rwh_04::AndroidNdkHandle::empty();
+ if let Some(w) = ndk_glue::window_manager().as_ref() {
+ handle.a_native_window = w.as_obj().as_raw() as *mut _;
+ } else {
+ panic!("Cannot get the native window, it's null and will always be null before Event::Resumed and after Event::Suspended. Make sure you only call this function between those events.");
+ };
+ rwh_04::RawWindowHandle::AndroidNdk(handle)
+ }
+
+ #[cfg(feature = "rwh_05")]
+ pub fn raw_window_handle_rwh_05(&self) -> rwh_05::RawWindowHandle {
+ // TODO: Use main activity instead?
+ let mut handle = rwh_05::AndroidNdkWindowHandle::empty();
+ if let Some(w) = ndk_glue::window_manager().as_ref() {
+ handle.a_native_window = w.as_obj().as_raw() as *mut _;
+ } else {
+ panic!("Cannot get the native window, it's null and will always be null before Event::Resumed and after Event::Suspended. Make sure you only call this function between those events.");
+ };
+ rwh_05::RawWindowHandle::AndroidNdk(handle)
+ }
+
+ #[cfg(feature = "rwh_05")]
+ pub fn raw_display_handle_rwh_05(&self) -> rwh_05::RawDisplayHandle {
+ rwh_05::RawDisplayHandle::Android(rwh_05::AndroidDisplayHandle::empty())
+ }
+
+ #[cfg(feature = "rwh_06")]
+ pub fn raw_window_handle_rwh_06(&self) -> Result {
+ // TODO: Use main activity instead?
+ if let Some(w) = ndk_glue::window_manager().as_ref() {
+ let native_window =
+ unsafe { std::ptr::NonNull::new_unchecked(w.as_obj().as_raw() as *mut _) };
+ // native_window shuldn't be null
+ let handle = rwh_06::AndroidNdkWindowHandle::new(native_window);
+ Ok(rwh_06::RawWindowHandle::AndroidNdk(handle))
+ } else {
+ Err(rwh_06::HandleError::Unavailable)
+ }
+ }
+
+ #[cfg(feature = "rwh_06")]
+ pub fn raw_display_handle_rwh_06(&self) -> Result {
+ Ok(rwh_06::RawDisplayHandle::Android(
+ rwh_06::AndroidDisplayHandle::new(),
+ ))
+ }
+ pub fn config(&self) -> Configuration {
+ CONFIG.read().unwrap().clone()
+ }
+
+ pub fn content_rect(&self) -> Rect {
+ ndk_glue::content_rect()
+ }
+
+ pub fn theme(&self) -> Theme {
+ Theme::Light
+ }
+}
+
+#[derive(Default, Clone, Debug)]
+pub struct OsError;
+
+use std::fmt::{self, Display, Formatter};
+impl Display for OsError {
+ fn fmt(&self, fmt: &mut Formatter<'_>) -> Result<(), fmt::Error> {
+ write!(fmt, "Android OS Error")
+ }
+}
+
+pub(crate) use crate::icon::NoIcon as PlatformIcon;
+
+#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
+pub struct MonitorHandle;
+
+impl MonitorHandle {
+ pub fn name(&self) -> Option {
+ Some("Android Device".to_owned())
+ }
+
+ pub fn size(&self) -> PhysicalSize {
+ // TODO decide how to get JNIENV
+ if let Some(w) = ndk_glue::window_manager().as_ref() {
+ let ctx = ndk_context::android_context();
+ let vm = unsafe { jni::JavaVM::from_raw(ctx.vm().cast()) }.unwrap();
+ let mut env = vm.attach_current_thread().unwrap();
+ let window_manager = w.as_obj();
+ let metrics = env
+ .call_method(
+ window_manager,
+ "getCurrentWindowMetrics",
+ "()Landroid/view/WindowMetrics;",
+ &[],
+ )
+ .unwrap()
+ .l()
+ .unwrap();
+ let rect = env
+ .call_method(&metrics, "getBounds", "()Landroid/graphics/Rect;", &[])
+ .unwrap()
+ .l()
+ .unwrap();
+ let width = env
+ .call_method(&rect, "width", "()I", &[])
+ .unwrap()
+ .i()
+ .unwrap();
+ let height = env
+ .call_method(&rect, "height", "()I", &[])
+ .unwrap()
+ .i()
+ .unwrap();
+ PhysicalSize::new(width as u32, height as u32)
+ } else {
+ PhysicalSize::new(0, 0)
+ }
+ }
+
+ pub fn position(&self) -> PhysicalPosition {
+ (0, 0).into()
+ }
+
+ pub fn scale_factor(&self) -> f64 {
+ let config = CONFIG.read().unwrap();
+ config
+ .density()
+ .map(|dpi| dpi as f64 / 160.0)
+ .unwrap_or(1.0)
+ }
+
+ pub fn video_modes(&self) -> impl Iterator
- {
+ let size = self.size().into();
+ let mut v = Vec::new();
+ // FIXME this is not the real refresh rate
+ // (it is guarunteed to support 32 bit color though)
+ v.push(monitor::VideoMode {
+ video_mode: VideoMode {
+ size,
+ bit_depth: 32,
+ refresh_rate: 60,
+ monitor: self.clone(),
+ },
+ });
+ v.into_iter()
+ }
+}
+
+#[derive(Clone, Debug, Eq, Hash, PartialEq)]
+pub struct VideoMode {
+ size: (u32, u32),
+ bit_depth: u16,
+ refresh_rate: u16,
+ monitor: MonitorHandle,
+}
+
+impl VideoMode {
+ pub fn size(&self) -> PhysicalSize {
+ self.size.into()
+ }
+
+ pub fn bit_depth(&self) -> u16 {
+ self.bit_depth
+ }
+
+ pub fn refresh_rate(&self) -> u16 {
+ self.refresh_rate
+ }
+
+ pub fn monitor(&self) -> monitor::MonitorHandle {
+ monitor::MonitorHandle {
+ inner: self.monitor.clone(),
+ }
+ }
+}
+
+fn keycode_to_logical(keycode: ndk::event::Keycode, native: NativeKeyCode) -> Key<'static> {
+ use ndk::event::Keycode::*;
+
+ // The android `Keycode` is sort-of layout dependent. More specifically
+ // if I press the Z key using a US layout, then I get KEYCODE_Z,
+ // but if I press the same key after switching to a HUN layout, I get
+ // KEYCODE_Y.
+ //
+ // To prevents us from using this value to determine the `physical_key`
+ // (also know as winit's `KeyCode`)
+ //
+ // Unfortunately the documentation says that the scancode values
+ // "are not reliable and vary from device to device". Which seems to mean
+ // that there's no way to reliably get the physical_key on android.
+
+ match keycode {
+ Unknown => Key::Unidentified(native),
+
+ // Can be added on demand
+ SoftLeft => Key::Unidentified(native),
+ SoftRight => Key::Unidentified(native),
+
+ // Using `BrowserHome` instead of `GoHome` according to
+ // https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key/Key_Values
+ Home => Key::BrowserHome,
+ Back => Key::BrowserBack,
+ Call => Key::Call,
+ Endcall => Key::EndCall,
+
+ //-------------------------------------------------------------------------------
+ // Reporting unidentified, because the specific character is layout dependent.
+ // (I'm not sure though)
+ Keycode0 => Key::Unidentified(native),
+ Keycode1 => Key::Unidentified(native),
+ Keycode2 => Key::Unidentified(native),
+ Keycode3 => Key::Unidentified(native),
+ Keycode4 => Key::Unidentified(native),
+ Keycode5 => Key::Unidentified(native),
+ Keycode6 => Key::Unidentified(native),
+ Keycode7 => Key::Unidentified(native),
+ Keycode8 => Key::Unidentified(native),
+ Keycode9 => Key::Unidentified(native),
+ Star => Key::Unidentified(native),
+ Pound => Key::Unidentified(native),
+ A => Key::Unidentified(native),
+ B => Key::Unidentified(native),
+ C => Key::Unidentified(native),
+ D => Key::Unidentified(native),
+ E => Key::Unidentified(native),
+ F => Key::Unidentified(native),
+ G => Key::Unidentified(native),
+ H => Key::Unidentified(native),
+ I => Key::Unidentified(native),
+ J => Key::Unidentified(native),
+ K => Key::Unidentified(native),
+ L => Key::Unidentified(native),
+ M => Key::Unidentified(native),
+ N => Key::Unidentified(native),
+ O => Key::Unidentified(native),
+ P => Key::Unidentified(native),
+ Q => Key::Unidentified(native),
+ R => Key::Unidentified(native),
+ S => Key::Unidentified(native),
+ T => Key::Unidentified(native),
+ U => Key::Unidentified(native),
+ V => Key::Unidentified(native),
+ W => Key::Unidentified(native),
+ X => Key::Unidentified(native),
+ Y => Key::Unidentified(native),
+ Z => Key::Unidentified(native),
+ Comma => Key::Unidentified(native),
+ Period => Key::Unidentified(native),
+ Grave => Key::Unidentified(native),
+ Minus => Key::Unidentified(native),
+ Equals => Key::Unidentified(native),
+ LeftBracket => Key::Unidentified(native),
+ RightBracket => Key::Unidentified(native),
+ Backslash => Key::Unidentified(native),
+ Semicolon => Key::Unidentified(native),
+ Apostrophe => Key::Unidentified(native),
+ Slash => Key::Unidentified(native),
+ At => Key::Unidentified(native),
+ Plus => Key::Unidentified(native),
+ //-------------------------------------------------------------------------------
+ DpadUp => Key::ArrowUp,
+ DpadDown => Key::ArrowDown,
+ DpadLeft => Key::ArrowLeft,
+ DpadRight => Key::ArrowRight,
+ DpadCenter => Key::Enter,
+
+ VolumeUp => Key::AudioVolumeUp,
+ VolumeDown => Key::AudioVolumeDown,
+ Power => Key::Power,
+ Camera => Key::Camera,
+ Clear => Key::Clear,
+
+ AltLeft => Key::Alt,
+ AltRight => Key::Alt,
+ ShiftLeft => Key::Shift,
+ ShiftRight => Key::Shift,
+ Tab => Key::Tab,
+ Space => Key::Space,
+ Sym => Key::Symbol,
+ Explorer => Key::LaunchWebBrowser,
+ Envelope => Key::LaunchMail,
+ Enter => Key::Enter,
+ Del => Key::Backspace,
+
+ // According to https://developer.android.com/reference/android/view/KeyEvent#KEYCODE_NUM
+ Num => Key::Alt,
+
+ Headsethook => Key::HeadsetHook,
+ Focus => Key::CameraFocus,
+
+ Menu => Key::Unidentified(native),
+
+ Notification => Key::Notification,
+ Search => Key::BrowserSearch,
+ MediaPlayPause => Key::MediaPlayPause,
+ MediaStop => Key::MediaStop,
+ MediaNext => Key::MediaTrackNext,
+ MediaPrevious => Key::MediaTrackPrevious,
+ MediaRewind => Key::MediaRewind,
+ MediaFastForward => Key::MediaFastForward,
+ Mute => Key::MicrophoneVolumeMute,
+ PageUp => Key::PageUp,
+ PageDown => Key::PageDown,
+ Pictsymbols => Key::Unidentified(native),
+ SwitchCharset => Key::Unidentified(native),
+
+ // -----------------------------------------------------------------
+ // Gamepad events should be exposed through a separate API, not
+ // keyboard events
+ ButtonA => Key::Unidentified(native),
+ ButtonB => Key::Unidentified(native),
+ ButtonC => Key::Unidentified(native),
+ ButtonX => Key::Unidentified(native),
+ ButtonY => Key::Unidentified(native),
+ ButtonZ => Key::Unidentified(native),
+ ButtonL1 => Key::Unidentified(native),
+ ButtonR1 => Key::Unidentified(native),
+ ButtonL2 => Key::Unidentified(native),
+ ButtonR2 => Key::Unidentified(native),
+ ButtonThumbl => Key::Unidentified(native),
+ ButtonThumbr => Key::Unidentified(native),
+ ButtonStart => Key::Unidentified(native),
+ ButtonSelect => Key::Unidentified(native),
+ ButtonMode => Key::Unidentified(native),
+ // -----------------------------------------------------------------
+ Escape => Key::Escape,
+ ForwardDel => Key::Delete,
+ CtrlLeft => Key::Control,
+ CtrlRight => Key::Control,
+ CapsLock => Key::CapsLock,
+ ScrollLock => Key::ScrollLock,
+ MetaLeft => Key::Super,
+ MetaRight => Key::Super,
+ Function => Key::Fn,
+ Sysrq => Key::PrintScreen,
+ Break => Key::Pause,
+ MoveHome => Key::Home,
+ MoveEnd => Key::End,
+ Insert => Key::Insert,
+ Forward => Key::BrowserForward,
+ MediaPlay => Key::MediaPlay,
+ MediaPause => Key::MediaPause,
+ MediaClose => Key::MediaClose,
+ MediaEject => Key::Eject,
+ MediaRecord => Key::MediaRecord,
+ F1 => Key::F1,
+ F2 => Key::F2,
+ F3 => Key::F3,
+ F4 => Key::F4,
+ F5 => Key::F5,
+ F6 => Key::F6,
+ F7 => Key::F7,
+ F8 => Key::F8,
+ F9 => Key::F9,
+ F10 => Key::F10,
+ F11 => Key::F11,
+ F12 => Key::F12,
+ NumLock => Key::NumLock,
+ Numpad0 => Key::Unidentified(native),
+ Numpad1 => Key::Unidentified(native),
+ Numpad2 => Key::Unidentified(native),
+ Numpad3 => Key::Unidentified(native),
+ Numpad4 => Key::Unidentified(native),
+ Numpad5 => Key::Unidentified(native),
+ Numpad6 => Key::Unidentified(native),
+ Numpad7 => Key::Unidentified(native),
+ Numpad8 => Key::Unidentified(native),
+ Numpad9 => Key::Unidentified(native),
+ NumpadDivide => Key::Unidentified(native),
+ NumpadMultiply => Key::Unidentified(native),
+ NumpadSubtract => Key::Unidentified(native),
+ NumpadAdd => Key::Unidentified(native),
+ NumpadDot => Key::Unidentified(native),
+ NumpadComma => Key::Unidentified(native),
+ NumpadEnter => Key::Unidentified(native),
+ NumpadEquals => Key::Unidentified(native),
+ NumpadLeftParen => Key::Unidentified(native),
+ NumpadRightParen => Key::Unidentified(native),
+
+ VolumeMute => Key::AudioVolumeMute,
+ Info => Key::Info,
+ ChannelUp => Key::ChannelUp,
+ ChannelDown => Key::ChannelDown,
+ ZoomIn => Key::ZoomIn,
+ ZoomOut => Key::ZoomOut,
+ Tv => Key::TV,
+ Window => Key::Unidentified(native),
+ Guide => Key::Guide,
+ Dvr => Key::DVR,
+ Bookmark => Key::BrowserFavorites,
+ Captions => Key::ClosedCaptionToggle,
+ Settings => Key::Settings,
+ TvPower => Key::TVPower,
+ TvInput => Key::TVInput,
+ StbPower => Key::STBPower,
+ StbInput => Key::STBInput,
+ AvrPower => Key::AVRPower,
+ AvrInput => Key::AVRInput,
+ ProgRed => Key::ColorF0Red,
+ ProgGreen => Key::ColorF1Green,
+ ProgYellow => Key::ColorF2Yellow,
+ ProgBlue => Key::ColorF3Blue,
+ AppSwitch => Key::AppSwitch,
+ Button1 => Key::Unidentified(native),
+ Button2 => Key::Unidentified(native),
+ Button3 => Key::Unidentified(native),
+ Button4 => Key::Unidentified(native),
+ Button5 => Key::Unidentified(native),
+ Button6 => Key::Unidentified(native),
+ Button7 => Key::Unidentified(native),
+ Button8 => Key::Unidentified(native),
+ Button9 => Key::Unidentified(native),
+ Button10 => Key::Unidentified(native),
+ Button11 => Key::Unidentified(native),
+ Button12 => Key::Unidentified(native),
+ Button13 => Key::Unidentified(native),
+ Button14 => Key::Unidentified(native),
+ Button15 => Key::Unidentified(native),
+ Button16 => Key::Unidentified(native),
+ LanguageSwitch => Key::GroupNext,
+ MannerMode => Key::MannerMode,
+ Keycode3dMode => Key::TV3DMode,
+ Contacts => Key::LaunchContacts,
+ Calendar => Key::LaunchCalendar,
+ Music => Key::LaunchMusicPlayer,
+ Calculator => Key::LaunchApplication2,
+ ZenkakuHankaku => Key::ZenkakuHankaku,
+ Eisu => Key::Eisu,
+ Muhenkan => Key::NonConvert,
+ Henkan => Key::Convert,
+ KatakanaHiragana => Key::HiraganaKatakana,
+ Yen => Key::Unidentified(native),
+ Ro => Key::Unidentified(native),
+ Kana => Key::KanjiMode,
+ Assist => Key::Unidentified(native),
+ BrightnessDown => Key::BrightnessDown,
+ BrightnessUp => Key::BrightnessUp,
+ MediaAudioTrack => Key::MediaAudioTrack,
+ Sleep => Key::Standby,
+ Wakeup => Key::WakeUp,
+ Pairing => Key::Pairing,
+ MediaTopMenu => Key::MediaTopMenu,
+ Keycode11 => Key::Unidentified(native),
+ Keycode12 => Key::Unidentified(native),
+ LastChannel => Key::MediaLast,
+ TvDataService => Key::TVDataService,
+ VoiceAssist => Key::VoiceDial,
+ TvRadioService => Key::TVRadioService,
+ TvTeletext => Key::Teletext,
+ TvNumberEntry => Key::TVNumberEntry,
+ TvTerrestrialAnalog => Key::TVTerrestrialAnalog,
+ TvTerrestrialDigital => Key::TVTerrestrialDigital,
+ TvSatellite => Key::TVSatellite,
+ TvSatelliteBs => Key::TVSatelliteBS,
+ TvSatelliteCs => Key::TVSatelliteCS,
+ TvSatelliteService => Key::TVSatelliteToggle,
+ TvNetwork => Key::TVNetwork,
+ TvAntennaCable => Key::TVAntennaCable,
+ TvInputHdmi1 => Key::TVInputHDMI1,
+ TvInputHdmi2 => Key::TVInputHDMI2,
+ TvInputHdmi3 => Key::TVInputHDMI3,
+ TvInputHdmi4 => Key::TVInputHDMI4,
+ TvInputComposite1 => Key::TVInputComposite1,
+ TvInputComposite2 => Key::TVInputComposite2,
+ TvInputComponent1 => Key::TVInputComponent1,
+ TvInputComponent2 => Key::TVInputComponent2,
+ TvInputVga1 => Key::TVInputVGA1,
+ TvAudioDescription => Key::TVAudioDescription,
+ TvAudioDescriptionMixUp => Key::TVAudioDescriptionMixUp,
+ TvAudioDescriptionMixDown => Key::TVAudioDescriptionMixDown,
+ TvZoomMode => Key::ZoomToggle,
+ TvContentsMenu => Key::TVContentsMenu,
+ TvMediaContextMenu => Key::TVMediaContext,
+ TvTimerProgramming => Key::TVTimer,
+ Help => Key::Help,
+ NavigatePrevious => Key::NavigatePrevious,
+ NavigateNext => Key::NavigateNext,
+ NavigateIn => Key::NavigateIn,
+ NavigateOut => Key::NavigateOut,
+ StemPrimary => Key::Unidentified(native),
+ Stem1 => Key::Unidentified(native),
+ Stem2 => Key::Unidentified(native),
+ Stem3 => Key::Unidentified(native),
+ DpadUpLeft => Key::Unidentified(native),
+ DpadDownLeft => Key::Unidentified(native),
+ DpadUpRight => Key::Unidentified(native),
+ DpadDownRight => Key::Unidentified(native),
+ MediaSkipForward => Key::MediaSkipForward,
+ MediaSkipBackward => Key::MediaSkipBackward,
+ MediaStepForward => Key::MediaStepForward,
+ MediaStepBackward => Key::MediaStepBackward,
+ SoftSleep => Key::Unidentified(native),
+ Cut => Key::Cut,
+ Copy => Key::Copy,
+ Paste => Key::Paste,
+ SystemNavigationUp => Key::Unidentified(native),
+ SystemNavigationDown => Key::Unidentified(native),
+ SystemNavigationLeft => Key::Unidentified(native),
+ SystemNavigationRight => Key::Unidentified(native),
+ AllApps => Key::Unidentified(native),
+ Refresh => Key::BrowserRefresh,
+ ThumbsUp => Key::Unidentified(native),
+ ThumbsDown => Key::Unidentified(native),
+ ProfileSwitch => Key::Unidentified(native),
+ _ => Key::Unidentified(native),
+ }
+}
+
+fn keycode_to_location(keycode: ndk::event::Keycode) -> KeyLocation {
+ use ndk::event::Keycode::*;
+
+ match keycode {
+ AltLeft => KeyLocation::Left,
+ AltRight => KeyLocation::Right,
+ ShiftLeft => KeyLocation::Left,
+ ShiftRight => KeyLocation::Right,
+
+ // According to https://developer.android.com/reference/android/view/KeyEvent#KEYCODE_NUM
+ Num => KeyLocation::Left,
+
+ CtrlLeft => KeyLocation::Left,
+ CtrlRight => KeyLocation::Right,
+ MetaLeft => KeyLocation::Left,
+ MetaRight => KeyLocation::Right,
+
+ NumLock => KeyLocation::Numpad,
+ Numpad0 => KeyLocation::Numpad,
+ Numpad1 => KeyLocation::Numpad,
+ Numpad2 => KeyLocation::Numpad,
+ Numpad3 => KeyLocation::Numpad,
+ Numpad4 => KeyLocation::Numpad,
+ Numpad5 => KeyLocation::Numpad,
+ Numpad6 => KeyLocation::Numpad,
+ Numpad7 => KeyLocation::Numpad,
+ Numpad8 => KeyLocation::Numpad,
+ Numpad9 => KeyLocation::Numpad,
+ NumpadDivide => KeyLocation::Numpad,
+ NumpadMultiply => KeyLocation::Numpad,
+ NumpadSubtract => KeyLocation::Numpad,
+ NumpadAdd => KeyLocation::Numpad,
+ NumpadDot => KeyLocation::Numpad,
+ NumpadComma => KeyLocation::Numpad,
+ NumpadEnter => KeyLocation::Numpad,
+ NumpadEquals => KeyLocation::Numpad,
+ NumpadLeftParen => KeyLocation::Numpad,
+ NumpadRightParen => KeyLocation::Numpad,
+
+ _ => KeyLocation::Standard,
+ }
+}
+
+// FIXME: Implement android
+pub fn keycode_to_scancode(_code: KeyCode) -> Option {
+ None
+}
+
+pub fn keycode_from_scancode(_scancode: u32) -> KeyCode {
+ KeyCode::Unidentified(NativeKeyCode::Unidentified)
+}
diff --git a/vendor/tao/src/platform_impl/android/ndk_glue.rs b/vendor/tao/src/platform_impl/android/ndk_glue.rs
new file mode 100644
index 00000000000..a09b4b2915d
--- /dev/null
+++ b/vendor/tao/src/platform_impl/android/ndk_glue.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
+
+pub use jni::{
+ self,
+ objects::{GlobalRef, JClass, JMap, JObject, JString},
+ sys::jobject,
+ JNIEnv,
+};
+use log::Level;
+pub use ndk;
+use ndk::{
+ input_queue::InputQueue,
+ looper::{FdEvent, ForeignLooper, ThreadLooper},
+};
+use once_cell::sync::{Lazy, OnceCell};
+use std::{
+ cell::RefCell,
+ ffi::{CStr, CString},
+ fs::File,
+ io::{BufRead, BufReader},
+ os::unix::prelude::*,
+ sync::{Arc, Condvar, Mutex, RwLock, RwLockReadGuard},
+ thread,
+};
+
+/// Android pacakge name that could be used to reference classes
+/// in the android project.
+pub static PACKAGE: OnceCell<&str> = OnceCell::new();
+
+/// Generate JNI compilant functions that are necessary for
+/// building android apps with tao.
+///
+/// Arguments in order:
+/// 1. android app domain name in reverse snake_case as an ident (for ex: com_example)
+/// 2. android package anme (for ex: wryapp)
+/// 3. the android activity that has external linking for the following functions and calls them:
+/// - `private external fun create(activity: WryActivity)``
+/// - `private external fun start()`
+/// - `private external fun resume()`
+/// - `private external fun pause()`
+/// - `private external fun stop()`
+/// - `private external fun save()`
+/// - `private external fun destroy()`
+/// - `private external fun memory()`
+/// - `private external fun focus(focus: Boolean)`
+/// 4. a one time setup function that will be ran once after tao has created its event loop in the `create` function above.
+/// 5. the main entry point of your android application.
+#[rustfmt::skip]
+#[macro_export]
+macro_rules! android_binding {
+ ($domain:ident, $package:ident, $activity:ident, $setup:path, $main:ident) => {
+ ::tao::android_binding!($domain, $package, $activity, $setup, $main, ::tao)
+ };
+ ($domain:ident, $package:ident, $activity:ident, $setup:path, $main:ident, $tao:path) => {{
+ // NOTE: be careful when changing how this use statement is written
+ use $tao::{platform::android::prelude::android_fn, platform::android::prelude::*};
+ fn _____tao_store_package_name__() {
+ PACKAGE.get_or_init(move || generate_package_name!($domain, $package));
+ }
+
+ android_fn!(
+ $domain,
+ $package,
+ $activity,
+ create,
+ [JObject],
+ __VOID__,
+ [$setup, $main],
+ _____tao_store_package_name__,
+ );
+ android_fn!($domain, $package, $activity, start, [JObject]);
+ android_fn!($domain, $package, $activity, stop, [JObject]);
+ android_fn!($domain, $package, $activity, resume, [JObject]);
+ android_fn!($domain, $package, $activity, pause, [JObject]);
+ android_fn!($domain, $package, $activity, save, [JObject]);
+ android_fn!($domain, $package, $activity, destroy, [JObject]);
+ android_fn!($domain, $package, $activity, memory, [JObject]);
+ android_fn!($domain, $package, $activity, focus, [i32]);
+ }};
+}
+
+/// `ndk-glue` macros register the reading end of an event pipe with the
+/// main [`ThreadLooper`] under this `ident`.
+/// When returned from [`ThreadLooper::poll_*`](ThreadLooper::poll_once)
+/// an event can be retrieved from [`poll_events()`].
+pub const NDK_GLUE_LOOPER_EVENT_PIPE_IDENT: i32 = 0;
+
+/// The [`InputQueue`] received from Android is registered with the main
+/// [`ThreadLooper`] under this `ident`.
+/// When returned from [`ThreadLooper::poll_*`](ThreadLooper::poll_once)
+/// an event can be retrieved from [`input_queue()`].
+pub const NDK_GLUE_LOOPER_INPUT_QUEUE_IDENT: i32 = 1;
+
+pub fn android_log(level: Level, tag: &CStr, msg: &CStr) {
+ let prio = match level {
+ Level::Error => ndk_sys::android_LogPriority::ANDROID_LOG_ERROR,
+ Level::Warn => ndk_sys::android_LogPriority::ANDROID_LOG_WARN,
+ Level::Info => ndk_sys::android_LogPriority::ANDROID_LOG_INFO,
+ Level::Debug => ndk_sys::android_LogPriority::ANDROID_LOG_DEBUG,
+ Level::Trace => ndk_sys::android_LogPriority::ANDROID_LOG_VERBOSE,
+ };
+ unsafe {
+ ndk_sys::__android_log_write(prio.0 as _, tag.as_ptr(), msg.as_ptr());
+ }
+}
+
+pub(crate) struct StaticCell(RefCell);
+
+unsafe impl Send for StaticCell {}
+unsafe impl Sync for StaticCell {}
+
+impl std::ops::Deref for StaticCell