diff --git a/Cargo.lock b/Cargo.lock index 34cdf3a2cd8..d47e187e9ec 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -20,76 +20,94 @@ checksum = "c71b1793ee61086797f5c80b6efa2b8ffa6d5dd703f118545808a7f2e27f7046" [[package]] name = "accesskit" -version = "0.12.1" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca8410747ed85a17c4a1e9ed3f5a74d3e7bdcc876cf9a18ff40ae21d645997b2" +checksum = "e4700bdc115b306d6c43381c344dc307f03b7f0460c304e4892c309930322bd7" dependencies = [ "enumn", "serde", ] +[[package]] +name = "accesskit_atspi_common" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1de72dc7093910a1284cef784b6b143bab0a34d67f6178e4fc3aaaf29a09f8b" +dependencies = [ + "accesskit", + "accesskit_consumer", + "atspi-common", + "serde", + "thiserror", + "zvariant", +] + [[package]] name = "accesskit_consumer" -version = "0.16.1" +version = "0.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c17cca53c09fbd7288667b22a201274b9becaa27f0b91bf52a526db95de45e6" +checksum = "fe3a07a32ab5837ad83db3230ac490c8504c2cd5b90ac8c00db6535f6ed65d0b" dependencies = [ "accesskit", + "immutable-chunkmap", ] [[package]] name = "accesskit_macos" -version = "0.10.1" +version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd3b6ae1eabbfbced10e840fd3fce8a93ae84f174b3e4ba892ab7bcb42e477a7" +checksum = "a189d159c153ae0fce5f9eefdcfec4a27885f453ce5ef0ccf078f72a73c39d34" dependencies = [ "accesskit", "accesskit_consumer", - "objc2 0.3.0-beta.3.patch-leaks.3", + "objc2", + "objc2-app-kit", + "objc2-foundation", "once_cell", ] [[package]] name = "accesskit_unix" -version = "0.6.1" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c8c9b4467d77cacfbc93cee9aa8e7822f6d527c774efdca5f8b3a5280c34847" +checksum = "b76c448cfd96d16131a9ad3ab786d06951eb341cdac1db908978ab010245a19d" dependencies = [ "accesskit", - "accesskit_consumer", + "accesskit_atspi_common", "async-channel", - "async-once-cell", + "async-executor", + "async-task", "atspi", - "futures-lite", - "once_cell", + "futures-lite 1.13.0", + "futures-util", "serde", "zbus", ] [[package]] name = "accesskit_windows" -version = "0.15.1" +version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afcae27ec0974fc7c3b0b318783be89fd1b2e66dd702179fe600166a38ff4a0b" +checksum = "682d8c4fb425606f97408e7577793f32e96310b646fa77662eb4216293eddc7f" dependencies = [ "accesskit", "accesskit_consumer", - "once_cell", "paste", "static_assertions", - "windows 0.48.0", + "windows 0.54.0", ] [[package]] name = "accesskit_winit" -version = "0.16.1" +version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5284218aca17d9e150164428a0ebc7b955f70e3a9a78b4c20894513aabf98a67" +checksum = "9afbd6d598b7c035639ad2b664aa0edc94c93dc1fc3ebb4b40d8a95fcd43ffac" dependencies = [ "accesskit", "accesskit_macos", "accesskit_unix", "accesskit_windows", + "raw-window-handle 0.6.2", "winit", ] @@ -139,9 +157,9 @@ checksum = "0942ffc6dcaadf03badf6e6a2d0228460359d5e34b57ccdc720b7382dfbd5ec5" [[package]] name = "android-activity" -version = "0.5.0" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "052ad56e336bcc615a214bffbeca6c181ee9550acec193f0327e0b103b033a4d" +checksum = "ef6978589202a00cd7e118380c448a08b6ed394c3a8df3a430d0898e3a42d046" dependencies = [ "android-properties", "bitflags 2.6.0", @@ -153,7 +171,7 @@ dependencies = [ "log", "ndk", "ndk-context", - "ndk-sys", + "ndk-sys 0.6.0+11769913", "num_enum", "thiserror", ] @@ -205,7 +223,7 @@ checksum = "9fb4009533e8ff8f1450a5bcbc30f4242a1d34442221f72314bea1f5dc9c7f89" dependencies = [ "clipboard-win", "log", - "objc2 0.5.1", + "objc2", "objc2-app-kit", "objc2-foundation", "parking_lot", @@ -251,13 +269,14 @@ dependencies = [ [[package]] name = "async-channel" -version = "1.9.0" +version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81953c529336010edd6d8e358f886d9581267795c61b19475b71314bffa46d35" +checksum = "89b47800b0be77592da0afd425cc03468052844aff33b84e33cc696f64e77b6a" dependencies = [ "concurrent-queue", - "event-listener 2.5.3", + "event-listener-strategy", "futures-core", + "pin-project-lite", ] [[package]] @@ -270,7 +289,7 @@ dependencies = [ "async-task", "concurrent-queue", "fastrand 2.0.1", - "futures-lite", + "futures-lite 1.13.0", "slab", ] @@ -283,7 +302,7 @@ dependencies = [ "async-lock", "autocfg", "blocking", - "futures-lite", + "futures-lite 1.13.0", ] [[package]] @@ -296,7 +315,7 @@ dependencies = [ "autocfg", "cfg-if", "concurrent-queue", - "futures-lite", + "futures-lite 1.13.0", "log", "parking", "polling 2.8.0", @@ -315,12 +334,6 @@ dependencies = [ "event-listener 2.5.3", ] -[[package]] -name = "async-once-cell" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9338790e78aa95a416786ec8389546c4b6a1dfc3dc36071ed9518a9413a542eb" - [[package]] name = "async-process" version = "1.8.0" @@ -333,7 +346,7 @@ dependencies = [ "blocking", "cfg-if", "event-listener 3.0.0", - "futures-lite", + "futures-lite 1.13.0", "rustix 0.38.21", "windows-sys 0.48.0", ] @@ -436,7 +449,7 @@ checksum = "a0c65e7d70f86d4c0e3b2d585d9bf3f979f0b19d635a336725a88d279f76b939" dependencies = [ "atspi-common", "atspi-proxies", - "futures-lite", + "futures-lite 1.13.0", "zbus", ] @@ -547,67 +560,26 @@ dependencies = [ "generic-array", ] -[[package]] -name = "block-sys" -version = "0.1.0-beta.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fa55741ee90902547802152aaf3f8e5248aab7e21468089560d4c8840561146" -dependencies = [ - "objc-sys 0.2.0-beta.2", -] - -[[package]] -name = "block-sys" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dd7cf50912cddc06dc5ea7c08c5e81c1b2c842a70d19def1848d54c586fed92" -dependencies = [ - "objc-sys 0.3.3", -] - [[package]] name = "block2" -version = "0.2.0-alpha.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8dd9e63c1744f755c2f60332b88de39d341e5e86239014ad839bd71c106dec42" -dependencies = [ - "block-sys 0.1.0-beta.1", - "objc2-encode 2.0.0-pre.2", -] - -[[package]] -name = "block2" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15b55663a85f33501257357e6421bb33e769d5c9ffb5ba0921c975a123e35e68" -dependencies = [ - "block-sys 0.2.0", - "objc2 0.4.1", -] - -[[package]] -name = "block2" -version = "0.5.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43ff7d91d3c1d568065b06c899777d1e48dcf76103a672a0adbc238a7f247f1e" +checksum = "2c132eebf10f5cad5289222520a4a058514204aed6d791f1cf4fe8088b82d15f" dependencies = [ - "objc2 0.5.1", + "objc2", ] [[package]] name = "blocking" -version = "1.4.0" +version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94c4ef1f913d78636d78d538eec1f18de81e481f44b1be0a81060090530846e1" +checksum = "703f41c54fc768e63e091340b424302bb1c29ef4aa0c7f10fe849dfb114d29ea" dependencies = [ "async-channel", - "async-lock", "async-task", - "fastrand 2.0.1", "futures-io", - "futures-lite", + "futures-lite 2.3.0", "piper", - "tracing", ] [[package]] @@ -660,9 +632,9 @@ dependencies = [ [[package]] name = "calloop" -version = "0.12.3" +version = "0.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b50b5a44d59a98c55a9eeb518f39bf7499ba19fd98ee7d22618687f3f10adbf" +checksum = "fba7adb4dd5aa98e5553510223000e7148f621165ec5f9acd7113f6ca4995298" dependencies = [ "bitflags 2.6.0", "log", @@ -728,6 +700,12 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e" +[[package]] +name = "cfg_aliases" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" + [[package]] name = "cgl" version = "0.3.2" @@ -883,9 +861,9 @@ dependencies = [ [[package]] name = "concurrent-queue" -version = "2.3.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f057a694a54f12365049b0958a1685bb52d567f5593b355fbf685838e873d400" +checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" dependencies = [ "crossbeam-utils", ] @@ -1169,6 +1147,12 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ea835d29036a4087793836fa931b08837ad5e957da9e23886b29586fb9b6650" +[[package]] +name = "dpi" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f25c0e292a7ca6d6498557ff1df68f32c99850012b6ea401cf8daf771f22ff53" + [[package]] name = "ecolor" version = "0.28.1" @@ -1199,15 +1183,14 @@ dependencies = [ "image", "js-sys", "log", - "objc2 0.5.1", + "objc2", "objc2-app-kit", "objc2-foundation", "parking_lot", "percent-encoding", "pollster", "puffin", - "raw-window-handle 0.5.2", - "raw-window-handle 0.6.0", + "raw-window-handle 0.6.2", "ron", "serde", "static_assertions", @@ -1265,10 +1248,12 @@ dependencies = [ "document-features", "egui", "log", + "nix", "puffin", - "raw-window-handle 0.6.0", + "raw-window-handle 0.6.2", "serde", "smithay-clipboard", + "wayland-cursor", "web-time", "webbrowser", "winit", @@ -1347,7 +1332,6 @@ dependencies = [ "log", "memoffset 0.9.0", "puffin", - "raw-window-handle 0.5.2", "wasm-bindgen", "web-sys", "winit", @@ -1518,6 +1502,27 @@ dependencies = [ "pin-project-lite", ] +[[package]] +name = "event-listener" +version = "5.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6032be9bd27023a771701cc49f9f053c751055f71efb2e0ae5c15809093675ba" +dependencies = [ + "concurrent-queue", + "parking", + "pin-project-lite", +] + +[[package]] +name = "event-listener-strategy" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f214dc438f977e6d4e3500aaa277f5ad94ca83fbbd9b1a15713ce2344ccc5a1" +dependencies = [ + "event-listener 5.3.1", + "pin-project-lite", +] + [[package]] name = "fancy-regex" version = "0.11.0" @@ -1646,6 +1651,27 @@ dependencies = [ "waker-fn", ] +[[package]] +name = "futures-lite" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52527eb5074e35e9339c6b4e8d12600c7128b68fb25dcb9fa9dec18f7c25f3a5" +dependencies = [ + "futures-core", + "pin-project-lite", +] + +[[package]] +name = "futures-macro" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.48", +] + [[package]] name = "futures-sink" version = "0.3.28" @@ -1666,6 +1692,7 @@ checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533" dependencies = [ "futures-core", "futures-io", + "futures-macro", "futures-sink", "futures-task", "memchr", @@ -1799,69 +1826,61 @@ dependencies = [ [[package]] name = "glutin" -version = "0.31.3" +version = "0.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18fcd4ae4e86d991ad1300b8f57166e5be0c95ef1f63f3f5b827f8a164548746" +checksum = "2491aa3090f682ddd920b184491844440fdd14379c7eef8f5bc10ef7fb3242fd" dependencies = [ "bitflags 2.6.0", - "cfg_aliases", + "cfg_aliases 0.2.1", "cgl", "core-foundation", "dispatch", "glutin_egl_sys", "glutin_glx_sys", - "glutin_wgl_sys 0.5.0", - "icrate", + "glutin_wgl_sys", "libloading", - "objc2 0.4.1", + "objc2", + "objc2-app-kit", + "objc2-foundation", "once_cell", - "raw-window-handle 0.5.2", + "raw-window-handle 0.6.2", "wayland-sys", - "windows-sys 0.48.0", + "windows-sys 0.52.0", "x11-dl", ] [[package]] name = "glutin-winit" -version = "0.4.2" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ebcdfba24f73b8412c5181e56f092b5eff16671c514ce896b258a0a64bd7735" +checksum = "85edca7075f8fc728f28cb8fbb111a96c3b89e930574369e3e9c27eb75d3788f" dependencies = [ - "cfg_aliases", + "cfg_aliases 0.2.1", "glutin", - "raw-window-handle 0.5.2", + "raw-window-handle 0.6.2", "winit", ] [[package]] name = "glutin_egl_sys" -version = "0.6.0" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77cc5623f5309ef433c3dd4ca1223195347fe62c413da8e2fdd0eb76db2d9bcd" +checksum = "cae99fff4d2850dbe6fb8c1fa8e4fead5525bab715beaacfccf3fb994e01c827" dependencies = [ "gl_generator", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] name = "glutin_glx_sys" -version = "0.5.0" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a165fd686c10dcc2d45380b35796e577eacfd43d4660ee741ec8ebe2201b3b4f" +checksum = "9c2b2d3918e76e18e08796b55eb64e8fe6ec67d5a6b2e2a7e2edce224ad24c63" dependencies = [ "gl_generator", "x11-dl", ] -[[package]] -name = "glutin_wgl_sys" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c8098adac955faa2d31079b65dc48841251f69efd3ac25477903fc424362ead" -dependencies = [ - "gl_generator", -] - [[package]] name = "glutin_wgl_sys" version = "0.6.0" @@ -2059,7 +2078,7 @@ dependencies = [ "iana-time-zone-haiku", "js-sys", "wasm-bindgen", - "windows-core", + "windows-core 0.51.1", ] [[package]] @@ -2071,17 +2090,6 @@ dependencies = [ "cc", ] -[[package]] -name = "icrate" -version = "0.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99d3aaff8a54577104bafdf686ff18565c3b6903ca5782a2026ef06e2c7aa319" -dependencies = [ - "block2 0.3.0", - "dispatch", - "objc2 0.4.1", -] - [[package]] name = "idna" version = "0.4.0" @@ -2124,6 +2132,15 @@ version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "029d73f573d8e8d63e6d5020011d3255b28c3ba85d6cf870a07184ed23de9284" +[[package]] +name = "immutable-chunkmap" +version = "2.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4419f022e55cc63d5bbd6b44b71e1d226b9c9480a47824c706e9d54e5c40c5eb" +dependencies = [ + "arrayvec", +] + [[package]] name = "indexmap" version = "2.1.0" @@ -2256,9 +2273,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.150" +version = "0.2.155" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c" +checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" [[package]] name = "libloading" @@ -2445,7 +2462,7 @@ dependencies = [ "arrayvec", "bit-set 0.6.0", "bitflags 2.6.0", - "cfg_aliases", + "cfg_aliases 0.1.1", "codespan-reporting", "hexf-parse", "indexmap", @@ -2459,17 +2476,16 @@ dependencies = [ [[package]] name = "ndk" -version = "0.8.0" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2076a31b7010b17a38c01907c45b945e8f11495ee4dd588309718901b1f7a5b7" +checksum = "c3f42e7bbe13d351b6bead8286a43aac9534b82bd3cc43e47037f012ebfd62d4" dependencies = [ "bitflags 2.6.0", "jni-sys", "log", - "ndk-sys", + "ndk-sys 0.6.0+11769913", "num_enum", - "raw-window-handle 0.5.2", - "raw-window-handle 0.6.0", + "raw-window-handle 0.6.2", "thiserror", ] @@ -2488,6 +2504,15 @@ dependencies = [ "jni-sys", ] +[[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 = "nix" version = "0.26.4" @@ -2568,99 +2593,205 @@ dependencies = [ [[package]] name = "objc-sys" -version = "0.2.0-beta.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df3b9834c1e95694a05a828b59f55fa2afec6288359cda67146126b3f90a55d7" - -[[package]] -name = "objc-sys" -version = "0.3.3" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da284c198fb9b7b0603f8635185e85fbd5b64ee154b1ed406d489077de2d6d60" +checksum = "cdb91bdd390c7ce1a8607f35f3ca7151b65afc0ff5ff3b34fa350f7d7c7e4310" [[package]] name = "objc2" -version = "0.3.0-beta.3.patch-leaks.3" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e01640f9f2cb1220bbe80325e179e532cb3379ebcd1bf2279d703c19fe3a468" +checksum = "46a785d4eeff09c14c487497c162e92766fbb3e4059a71840cecc03d9a50b804" dependencies = [ - "block2 0.2.0-alpha.6", - "objc-sys 0.2.0-beta.2", - "objc2-encode 2.0.0-pre.2", + "objc-sys", + "objc2-encode", ] [[package]] -name = "objc2" -version = "0.4.1" +name = "objc2-app-kit" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "559c5a40fdd30eb5e344fbceacf7595a81e242529fb4e21cf5f43fb4f11ff98d" +checksum = "e4e89ad9e3d7d297152b17d39ed92cd50ca8063a89a9fa569046d41568891eff" dependencies = [ - "objc-sys 0.3.3", - "objc2-encode 3.0.0", + "bitflags 2.6.0", + "block2", + "libc", + "objc2", + "objc2-core-data", + "objc2-core-image", + "objc2-foundation", + "objc2-quartz-core", ] [[package]] -name = "objc2" -version = "0.5.1" +name = "objc2-cloud-kit" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4b25e1034d0e636cd84707ccdaa9f81243d399196b8a773946dcffec0401659" +checksum = "74dd3b56391c7a0596a295029734d3c1c5e7e510a4cb30245f8221ccea96b009" dependencies = [ - "objc-sys 0.3.3", - "objc2-encode 4.0.1", + "bitflags 2.6.0", + "block2", + "objc2", + "objc2-core-location", + "objc2-foundation", ] [[package]] -name = "objc2-app-kit" -version = "0.2.0" +name = "objc2-contacts" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb79768a710a9a1798848179edb186d1af7e8a8679f369e4b8d201dd2a034047" +checksum = "a5ff520e9c33812fd374d8deecef01d4a840e7b41862d849513de77e44aa4889" dependencies = [ - "block2 0.5.0", - "objc2 0.5.1", - "objc2-core-data", + "block2", + "objc2", "objc2-foundation", ] [[package]] name = "objc2-core-data" -version = "0.2.0" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e092bc42eaf30a08844e6a076938c60751225ec81431ab89f5d1ccd9f958d6c" +checksum = "617fbf49e071c178c0b24c080767db52958f716d9eabdf0890523aeae54773ef" dependencies = [ - "block2 0.5.0", - "objc2 0.5.1", + "bitflags 2.6.0", + "block2", + "objc2", "objc2-foundation", ] [[package]] -name = "objc2-encode" -version = "2.0.0-pre.2" +name = "objc2-core-image" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abfcac41015b00a120608fdaa6938c44cb983fee294351cc4bac7638b4e50512" +checksum = "55260963a527c99f1819c4f8e3b47fe04f9650694ef348ffd2227e8196d34c80" dependencies = [ - "objc-sys 0.2.0-beta.2", + "block2", + "objc2", + "objc2-foundation", + "objc2-metal", ] [[package]] -name = "objc2-encode" -version = "3.0.0" +name = "objc2-core-location" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d079845b37af429bfe5dfa76e6d087d788031045b25cfc6fd898486fd9847666" +checksum = "000cfee34e683244f284252ee206a27953279d370e309649dc3ee317b37e5781" +dependencies = [ + "block2", + "objc2", + "objc2-contacts", + "objc2-foundation", +] [[package]] name = "objc2-encode" -version = "4.0.1" +version = "4.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88658da63e4cc2c8adb1262902cd6af51094df0488b760d6fd27194269c0950a" +checksum = "7891e71393cd1f227313c9379a26a584ff3d7e6e7159e988851f0934c993f0f8" [[package]] name = "objc2-foundation" -version = "0.2.0" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ee638a5da3799329310ad4cfa62fbf045d5f56e3ef5ba4149e7452dcf89d5a8" +dependencies = [ + "bitflags 2.6.0", + "block2", + "dispatch", + "libc", + "objc2", +] + +[[package]] +name = "objc2-link-presentation" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1a1ae721c5e35be65f01a03b6d2ac13a54cb4fa70d8a5da293d7b0020261398" +dependencies = [ + "block2", + "objc2", + "objc2-app-kit", + "objc2-foundation", +] + +[[package]] +name = "objc2-metal" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd0cba1276f6023976a406a14ffa85e1fdd19df6b0f737b063b95f6c8c7aadd6" +dependencies = [ + "bitflags 2.6.0", + "block2", + "objc2", + "objc2-foundation", +] + +[[package]] +name = "objc2-quartz-core" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e42bee7bff906b14b167da2bac5efe6b6a07e6f7c0a21a7308d40c960242dc7a" +dependencies = [ + "bitflags 2.6.0", + "block2", + "objc2", + "objc2-foundation", + "objc2-metal", +] + +[[package]] +name = "objc2-symbols" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a684efe3dec1b305badae1a28f6555f6ddd3bb2c2267896782858d5a78404dc" +dependencies = [ + "objc2", + "objc2-foundation", +] + +[[package]] +name = "objc2-ui-kit" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8bb46798b20cd6b91cbd113524c490f1686f4c4e8f49502431415f3512e2b6f" +dependencies = [ + "bitflags 2.6.0", + "block2", + "objc2", + "objc2-cloud-kit", + "objc2-core-data", + "objc2-core-image", + "objc2-core-location", + "objc2-foundation", + "objc2-link-presentation", + "objc2-quartz-core", + "objc2-symbols", + "objc2-uniform-type-identifiers", + "objc2-user-notifications", +] + +[[package]] +name = "objc2-uniform-type-identifiers" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44fa5f9748dbfe1ca6c0b79ad20725a11eca7c2218bceb4b005cb1be26273bfe" +dependencies = [ + "block2", + "objc2", + "objc2-foundation", +] + +[[package]] +name = "objc2-user-notifications" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfaefe14254871ea16c7d88968c0ff14ba554712a20d76421eec52f0a7fb8904" +checksum = "76cfcbf642358e8689af64cee815d139339f3ed8ad05103ed5eaf73db8d84cb3" dependencies = [ - "block2 0.5.0", - "objc2 0.5.1", + "bitflags 2.6.0", + "block2", + "objc2", + "objc2-core-location", + "objc2-foundation", ] [[package]] @@ -2786,6 +2917,26 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5be167a7af36ee22fe3115051bc51f6e6c7054c9348e28deb4f49bd6f705a315" +[[package]] +name = "pin-project" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6bf43b791c5b9e34c3d182969b4abb522f9343702850a2e57f460d00d09b4b3" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.48", +] + [[package]] name = "pin-project-lite" version = "0.2.13" @@ -2980,18 +3131,18 @@ dependencies = [ [[package]] name = "quick-xml" -version = "0.30.0" +version = "0.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eff6510e86862b57b210fd8cbe8ed3f0d7d600b9c2863cd4549a2e033c66e956" +checksum = "1004a344b30a54e2ee58d66a71b32d2db2feb0a31f9a2d302bf0536f15de2a33" dependencies = [ "memchr", ] [[package]] name = "quick-xml" -version = "0.31.0" +version = "0.34.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1004a344b30a54e2ee58d66a71b32d2db2feb0a31f9a2d302bf0536f15de2a33" +checksum = "6f24d770aeca0eacb81ac29dfbc55ebcc09312fdd1f8bbecdc7e4a84e000e3b4" dependencies = [ "memchr", ] @@ -3043,9 +3194,9 @@ checksum = "f2ff9a1f06a88b01621b7ae906ef0211290d1c8a168a15542486a8f61c0833b9" [[package]] name = "raw-window-handle" -version = "0.6.0" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42a9830a0e1b9fb145ebb365b8bc4ccd75f290f98c0247deafbbe2c75cefb544" +checksum = "20675572f6f24e9e76ef639bc5552774ed45f1c30e2951e1e99c59888861c539" [[package]] name = "rayon" @@ -3334,9 +3485,9 @@ dependencies = [ [[package]] name = "sctk-adwaita" -version = "0.8.1" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82b2eaf3a5b264a521b988b2e73042e742df700c4f962cde845d1541adb46550" +checksum = "7555fcb4f753d095d734fdefebb0ad8c98478a21db500492d87c55913d3b0086" dependencies = [ "ab_glyph", "log", @@ -3471,9 +3622,9 @@ checksum = "942b4a808e05215192e39f4ab80813e599068285906cc91aa64f923db842bd5a" [[package]] name = "smithay-client-toolkit" -version = "0.18.0" +version = "0.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60e3d9941fa3bacf7c2bf4b065304faa14164151254cd16ce1b1bc8fc381600f" +checksum = "922fd3eeab3bd820d76537ce8f582b1cf951eceb5475c28500c7457d9d17f53a" dependencies = [ "bitflags 2.6.0", "calloop", @@ -4118,13 +4269,13 @@ checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" [[package]] name = "wayland-backend" -version = "0.3.2" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19152ddd73f45f024ed4534d9ca2594e0ef252c1847695255dae47f34df9fbe4" +checksum = "f90e11ce2ca99c97b940ee83edbae9da2d56a08f9ea8158550fd77fa31722993" dependencies = [ "cc", "downcast-rs", - "nix", + "rustix 0.38.21", "scoped-tls", "smallvec", "wayland-sys", @@ -4132,12 +4283,12 @@ dependencies = [ [[package]] name = "wayland-client" -version = "0.31.1" +version = "0.31.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ca7d52347346f5473bf2f56705f360e8440873052e575e55890c4fa57843ed3" +checksum = "7e321577a0a165911bdcfb39cf029302479d7527b517ee58ab0f6ad09edf0943" dependencies = [ "bitflags 2.6.0", - "nix", + "rustix 0.38.21", "wayland-backend", "wayland-scanner", ] @@ -4155,20 +4306,20 @@ dependencies = [ [[package]] name = "wayland-cursor" -version = "0.31.0" +version = "0.31.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a44aa20ae986659d6c77d64d808a046996a932aa763913864dc40c359ef7ad5b" +checksum = "6ef9489a8df197ebf3a8ce8a7a7f0a2320035c3743f3c1bd0bdbccf07ce64f95" dependencies = [ - "nix", + "rustix 0.38.21", "wayland-client", "xcursor", ] [[package]] name = "wayland-protocols" -version = "0.31.0" +version = "0.31.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e253d7107ba913923dc253967f35e8561a3c65f914543e46843c88ddd729e21c" +checksum = "8f81f365b8b4a97f422ac0e8737c438024b5951734506b0e1d775c73030561f4" dependencies = [ "bitflags 2.6.0", "wayland-backend", @@ -4204,20 +4355,20 @@ dependencies = [ [[package]] name = "wayland-scanner" -version = "0.31.0" +version = "0.31.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb8e28403665c9f9513202b7e1ed71ec56fde5c107816843fb14057910b2c09c" +checksum = "d7b56f89937f1cf2ee1f1259cf2936a17a1f45d8f0aa1019fae6d470d304cfa6" dependencies = [ "proc-macro2", - "quick-xml 0.30.0", + "quick-xml 0.34.0", "quote", ] [[package]] name = "wayland-sys" -version = "0.31.1" +version = "0.31.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15a0c8eaff5216d07f226cb7a549159267f3467b289d9a2e52fd3ef5aae2b7af" +checksum = "43676fe2daf68754ecf1d72026e4e6c15483198b5d24e888b74d3f22f887a148" dependencies = [ "dlib", "log", @@ -4237,12 +4388,11 @@ dependencies = [ [[package]] name = "web-time" -version = "0.2.0" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19353897b48e2c4d849a2d73cb0aeb16dc2be4e00c565abfc11eb65a806e47de" +checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" dependencies = [ "js-sys", - "once_cell", "wasm-bindgen", ] @@ -4282,14 +4432,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c87e07e87a179614940ad845397e03201847453a37b43a31a3b54eee2e6e32ce" dependencies = [ "arrayvec", - "cfg_aliases", + "cfg_aliases 0.1.1", "document-features", "js-sys", "log", "naga", "parking_lot", "profiling", - "raw-window-handle 0.6.0", + "raw-window-handle 0.6.2", "smallvec", "static_assertions", "wasm-bindgen", @@ -4309,7 +4459,7 @@ dependencies = [ "arrayvec", "bit-vec 0.7.0", "bitflags 2.6.0", - "cfg_aliases", + "cfg_aliases 0.1.1", "document-features", "indexmap", "log", @@ -4317,7 +4467,7 @@ dependencies = [ "once_cell", "parking_lot", "profiling", - "raw-window-handle 0.6.0", + "raw-window-handle 0.6.2", "rustc-hash", "smallvec", "thiserror", @@ -4336,10 +4486,10 @@ dependencies = [ "ash", "bitflags 2.6.0", "block", - "cfg_aliases", + "cfg_aliases 0.1.1", "core-graphics-types", "glow", - "glutin_wgl_sys 0.6.0", + "glutin_wgl_sys", "gpu-alloc", "gpu-allocator", "gpu-descriptor", @@ -4351,12 +4501,12 @@ dependencies = [ "log", "metal", "naga", - "ndk-sys", + "ndk-sys 0.5.0+25.2.9519653", "objc", "once_cell", "parking_lot", "profiling", - "raw-window-handle 0.6.0", + "raw-window-handle 0.6.2", "renderdoc-sys", "rustc-hash", "smallvec", @@ -4417,23 +4567,24 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "windows" -version = "0.48.0" +version = "0.51.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f" +checksum = "ca229916c5ee38c2f2bc1e9d8f04df975b4bd93f9955dc69fabb5d91270045c9" dependencies = [ - "windows-implement", - "windows-interface", + "windows-core 0.51.1", "windows-targets 0.48.5", ] [[package]] name = "windows" -version = "0.51.1" +version = "0.54.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca229916c5ee38c2f2bc1e9d8f04df975b4bd93f9955dc69fabb5d91270045c9" +checksum = "9252e5725dbed82865af151df558e754e4a3c2c30818359eb17465f1346a1b49" dependencies = [ - "windows-core", - "windows-targets 0.48.5", + "windows-core 0.54.0", + "windows-implement", + "windows-interface", + "windows-targets 0.52.5", ] [[package]] @@ -4445,26 +4596,45 @@ dependencies = [ "windows-targets 0.48.5", ] +[[package]] +name = "windows-core" +version = "0.54.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12661b9c89351d684a50a8a643ce5f608e20243b9fb84687800163429f161d65" +dependencies = [ + "windows-result", + "windows-targets 0.52.5", +] + [[package]] name = "windows-implement" -version = "0.48.0" +version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e2ee588991b9e7e6c8338edf3333fbe4da35dc72092643958ebb43f0ab2c49c" +checksum = "942ac266be9249c84ca862f0a164a39533dc2f6f33dc98ec89c8da99b82ea0bd" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.48", ] [[package]] name = "windows-interface" -version = "0.48.0" +version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6fb8df20c9bcaa8ad6ab513f7b40104840c8867d5751126e4df3b08388d0cc7" +checksum = "da33557140a288fae4e1d5f8873aaf9eb6613a9cf82c3e070223ff177f598b60" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.48", +] + +[[package]] +name = "windows-result" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e383302e8ec8515204254685643de10811af0ed97ea37210dc26fb0032647f8" +dependencies = [ + "windows-targets 0.52.5", ] [[package]] @@ -4674,38 +4844,41 @@ checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" [[package]] name = "winit" -version = "0.29.10" +version = "0.30.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c824f11941eeae66ec71111cc2674373c772f482b58939bb4066b642aa2ffcf" +checksum = "1dc930d6cfbf53c4fe0b95689cdc2e17b8658c3f4214b9953298ccb5a1a15c90" dependencies = [ "ahash", "android-activity", "atomic-waker", "bitflags 2.6.0", + "block2", "bytemuck", "calloop", - "cfg_aliases", + "cfg_aliases 0.2.1", + "concurrent-queue", "core-foundation", "core-graphics", "cursor-icon", - "icrate", + "dpi", "js-sys", "libc", - "log", "memmap2", "ndk", - "ndk-sys", - "objc2 0.4.1", - "once_cell", + "objc2", + "objc2-app-kit", + "objc2-foundation", + "objc2-ui-kit", "orbclient", "percent-encoding", - "raw-window-handle 0.5.2", - "raw-window-handle 0.6.0", - "redox_syscall 0.3.5", + "pin-project", + "raw-window-handle 0.6.2", + "redox_syscall 0.4.1", "rustix 0.38.21", "sctk-adwaita", "smithay-client-toolkit", "smol_str", + "tracing", "unicode-segmentation", "wasm-bindgen", "wasm-bindgen-futures", @@ -4715,7 +4888,7 @@ dependencies = [ "wayland-protocols-plasma", "web-sys", "web-time", - "windows-sys 0.48.0", + "windows-sys 0.52.0", "x11-dl", "x11rb", "xkbcommon-dl", diff --git a/Cargo.toml b/Cargo.toml index 03d6f7c3652..f6b45737cd3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -73,8 +73,8 @@ bytemuck = "1.7.2" criterion = { version = "0.5.1", default-features = false } document-features = " 0.2.8" glow = "0.13" -glutin = "0.31" -glutin-winit = "0.4" +glutin = "0.32.0" +glutin-winit = "0.5.0" image = { version = "0.25", default-features = false } log = { version = "0.4", features = ["std"] } nohash-hasher = "0.2" @@ -85,7 +85,7 @@ ron = "0.8" raw-window-handle = "0.6.0" serde = { version = "1", features = ["derive"] } thiserror = "1.0.37" -web-time = "0.2" # Timekeeping for native and web +web-time = "1.1.0" # Timekeeping for native and web wasm-bindgen = "0.2" wasm-bindgen-futures = "0.4" web-sys = "0.3.58" @@ -93,8 +93,9 @@ wgpu = { version = "22.0.0", default-features = false, features = [ # Make the renderer `Sync` even on wasm32, because it makes the code simpler: "fragile-send-sync-non-atomic-wasm", ] } -winit = { version = "0.29.4", default-features = false } +# Currently can't upgrade above 0.30.2 due to https://github.com/rust-windowing/winit/issues/3837 +winit = { version = "=0.30.2", default-features = false } [workspace.lints.rust] unsafe_code = "deny" diff --git a/crates/eframe/Cargo.toml b/crates/eframe/Cargo.toml index 22907c0979a..0b18845c34a 100644 --- a/crates/eframe/Cargo.toml +++ b/crates/eframe/Cargo.toml @@ -59,14 +59,7 @@ android-native-activity = ["egui-winit/android-native-activity"] default_fonts = ["egui/default_fonts"] ## Use [`glow`](https://github.com/grovesNL/glow) for painting, via [`egui_glow`](https://github.com/emilk/egui/tree/master/crates/egui_glow). -glow = [ - "dep:egui_glow", - "dep:glow", - "dep:glutin-winit", - "dep:glutin", - "dep:rwh_05", - "winit/rwh_05", -] +glow = ["dep:egui_glow", "dep:glow", "dep:glutin-winit", "dep:glutin"] ## Enable saving app state to disk. persistence = [ @@ -141,10 +134,6 @@ web-time.workspace = true egui_glow = { workspace = true, optional = true, default-features = false } glow = { workspace = true, optional = true } -# glutin stuck on old version of raw-window-handle: -rwh_05 = { package = "raw-window-handle", version = "0.5.2", optional = true, features = [ - "std", -] } ron = { workspace = true, optional = true, features = ["integer128"] } serde = { workspace = true, optional = true } diff --git a/crates/eframe/src/epi.rs b/crates/eframe/src/epi.rs index c8c9069a0bf..ac6d0f45a24 100644 --- a/crates/eframe/src/epi.rs +++ b/crates/eframe/src/epi.rs @@ -23,7 +23,7 @@ use static_assertions::assert_not_impl_any; #[cfg(not(target_arch = "wasm32"))] #[cfg(any(feature = "glow", feature = "wgpu"))] -pub use winit::{event_loop::EventLoopBuilder, window::WindowBuilder}; +pub use winit::{event_loop::EventLoopBuilder, window::WindowAttributes}; /// Hook into the building of an event loop before it is run /// diff --git a/crates/eframe/src/native/epi_integration.rs b/crates/eframe/src/native/epi_integration.rs index c033eeef6ab..5d02e2386e9 100644 --- a/crates/eframe/src/native/epi_integration.rs +++ b/crates/eframe/src/native/epi_integration.rs @@ -3,7 +3,7 @@ use web_time::Instant; use std::path::PathBuf; -use winit::event_loop::EventLoopWindowTarget; +use winit::event_loop::ActiveEventLoop; use raw_window_handle::{HasDisplayHandle as _, HasWindowHandle as _}; @@ -12,9 +12,9 @@ use egui_winit::{EventResponse, WindowSettings}; use crate::{epi, Theme}; -pub fn viewport_builder( +pub fn viewport_builder( egui_zoom_factor: f32, - event_loop: &EventLoopWindowTarget, + event_loop: &ActiveEventLoop, native_options: &mut epi::NativeOptions, window_settings: Option, ) -> ViewportBuilder { @@ -95,10 +95,7 @@ pub fn apply_window_settings( } } -fn largest_monitor_point_size( - egui_zoom_factor: f32, - event_loop: &EventLoopWindowTarget, -) -> egui::Vec2 { +fn largest_monitor_point_size(egui_zoom_factor: f32, event_loop: &ActiveEventLoop) -> egui::Vec2 { crate::profile_function!(); let mut max_size = egui::Vec2::ZERO; @@ -229,27 +226,6 @@ impl EpiIntegration { } } - #[cfg(feature = "accesskit")] - pub fn init_accesskit + Send>( - &self, - egui_winit: &mut egui_winit::State, - window: &winit::window::Window, - event_loop_proxy: winit::event_loop::EventLoopProxy, - ) { - crate::profile_function!(); - - let egui_ctx = self.egui_ctx.clone(); - egui_winit.init_accesskit(window, event_loop_proxy, move || { - // This function is called when an accessibility client - // (e.g. screen reader) makes its first request. If we got here, - // we know that an accessibility tree is actually wanted. - egui_ctx.enable_accesskit(); - // Enqueue a repaint so we'll receive a full tree update soon. - egui_ctx.request_repaint(); - egui_ctx.accesskit_placeholder_tree_update() - }); - } - /// If `true`, it is time to close the native window. pub fn should_close(&self) -> bool { self.close diff --git a/crates/eframe/src/native/event_loop_context.rs b/crates/eframe/src/native/event_loop_context.rs new file mode 100644 index 00000000000..2bb9e42555a --- /dev/null +++ b/crates/eframe/src/native/event_loop_context.rs @@ -0,0 +1,54 @@ +use std::cell::Cell; +use winit::event_loop::ActiveEventLoop; + +thread_local! { + static CURRENT_EVENT_LOOP: Cell> = Cell::new(None); +} + +struct EventLoopGuard; + +impl EventLoopGuard { + fn new(event_loop: &ActiveEventLoop) -> Self { + CURRENT_EVENT_LOOP.with(|cell| { + assert!( + cell.get().is_none(), + "Attempted to set a new event loop while one is already set" + ); + cell.set(Some(event_loop as *const ActiveEventLoop)); + }); + Self + } +} + +impl Drop for EventLoopGuard { + fn drop(&mut self) { + CURRENT_EVENT_LOOP.with(|cell| cell.set(None)); + } +} + +// Helper function to safely use the current event loop +#[allow(unsafe_code)] +pub fn with_current_event_loop(f: F) -> Option +where + F: FnOnce(&ActiveEventLoop) -> R, +{ + CURRENT_EVENT_LOOP.with(|cell| { + cell.get().map(|ptr| { + // SAFETY: + // 1. The pointer is guaranteed to be valid when it's Some, as the EventLoopGuard that created it + // lives at least as long as the reference, and clears it when it's dropped. Only run_with_event_loop creates + // a new EventLoopGuard, and does not leak it. + // 2. Since the pointer was created from a borrow which lives at least as long as this pointer there are + // no mutable references to the ActiveEventLoop. + let event_loop = unsafe { &*ptr }; + f(event_loop) + }) + }) +} + +// The only public interface to use the event loop +pub fn with_event_loop_context(event_loop: &ActiveEventLoop, f: impl FnOnce()) { + // NOTE: For safety, this guard must NOT be leaked. + let _guard = EventLoopGuard::new(event_loop); + f(); +} diff --git a/crates/eframe/src/native/glow_integration.rs b/crates/eframe/src/native/glow_integration.rs index fd19f633fde..366b71cfd7a 100644 --- a/crates/eframe/src/native/glow_integration.rs +++ b/crates/eframe/src/native/glow_integration.rs @@ -21,8 +21,9 @@ use glutin::{ prelude::{GlDisplay, PossiblyCurrentGlContext}, surface::GlSurface, }; +use raw_window_handle::HasWindowHandle; use winit::{ - event_loop::{EventLoop, EventLoopProxy, EventLoopWindowTarget}, + event_loop::{ActiveEventLoop, EventLoop, EventLoopProxy}, window::{Window, WindowId}, }; @@ -145,7 +146,7 @@ impl GlowWinitApp { #[allow(unsafe_code)] fn create_glutin_windowed_context( egui_ctx: &egui::Context, - event_loop: &EventLoopWindowTarget, + event_loop: &ActiveEventLoop, storage: Option<&dyn Storage>, native_options: &mut NativeOptions, ) -> Result<(GlutinWindowContext, egui_glow::Painter)> { @@ -194,10 +195,7 @@ impl GlowWinitApp { Ok((glutin_window_context, painter)) } - fn init_run_state( - &mut self, - event_loop: &EventLoopWindowTarget, - ) -> Result<&mut GlowWinitRunning> { + fn init_run_state(&mut self, event_loop: &ActiveEventLoop) -> Result<&mut GlowWinitRunning> { crate::profile_function!(); let storage = if let Some(file) = &self.native_options.persistence_path { @@ -279,7 +277,7 @@ impl GlowWinitApp { .. } = viewport { - integration.init_accesskit(egui_winit, window, event_loop_proxy); + egui_winit.init_accesskit(window, event_loop_proxy); } } @@ -330,17 +328,9 @@ impl GlowWinitApp { let painter = Rc::downgrade(&painter); let beginning = integration.beginning; - let event_loop: *const EventLoopWindowTarget = event_loop; - egui::Context::set_immediate_viewport_renderer(move |egui_ctx, immediate_viewport| { if let (Some(glutin), Some(painter)) = (glutin.upgrade(), painter.upgrade()) { - // SAFETY: the event loop lives longer than - // the Rc:s we just upgraded above. - #[allow(unsafe_code)] - let event_loop = unsafe { event_loop.as_ref().unwrap() }; - render_immediate_viewport( - event_loop, egui_ctx, &glutin, &painter, @@ -401,116 +391,108 @@ impl WinitApp for GlowWinitApp { fn run_ui_and_paint( &mut self, - event_loop: &EventLoopWindowTarget, + event_loop: &ActiveEventLoop, window_id: WindowId, - ) -> EventResult { + ) -> Result { if let Some(running) = &mut self.running { running.run_ui_and_paint(event_loop, window_id) } else { - EventResult::Wait + Ok(EventResult::Wait) } } - fn on_event( - &mut self, - event_loop: &EventLoopWindowTarget, - event: &winit::event::Event, - ) -> Result { - crate::profile_function!(winit_integration::short_event_description(event)); - - Ok(match event { - winit::event::Event::Resumed => { - log::debug!("Event::Resumed"); - - let running = if let Some(running) = &mut self.running { - // Not the first resume event. Create all outstanding windows. - running - .glutin - .borrow_mut() - .initialize_all_windows(event_loop); - running - } else { - // First resume event. Created our root window etc. - self.init_run_state(event_loop)? - }; - let window_id = running.glutin.borrow().window_from_viewport[&ViewportId::ROOT]; - EventResult::RepaintNow(window_id) - } + fn resumed(&mut self, event_loop: &ActiveEventLoop) -> crate::Result { + log::debug!("Event::Resumed"); - winit::event::Event::Suspended => { - if let Some(running) = &mut self.running { - running.glutin.borrow_mut().on_suspend()?; - } - EventResult::Wait - } + let running = if let Some(running) = &mut self.running { + // Not the first resume event. Create all outstanding windows. + running + .glutin + .borrow_mut() + .initialize_all_windows(event_loop); + running + } else { + // First resume event. Create our root window etc. + self.init_run_state(event_loop)? + }; + let window_id = running.glutin.borrow().window_from_viewport[&ViewportId::ROOT]; + Ok(EventResult::RepaintNow(window_id)) + } - winit::event::Event::WindowEvent { event, window_id } => { - if let Some(running) = &mut self.running { - running.on_window_event(*window_id, event) - } else { - EventResult::Wait - } - } + fn suspended(&mut self, _: &ActiveEventLoop) -> crate::Result { + if let Some(running) = &mut self.running { + running.glutin.borrow_mut().on_suspend()?; + } + Ok(EventResult::Wait) + } - winit::event::Event::DeviceEvent { - device_id: _, - event: winit::event::DeviceEvent::MouseMotion { delta }, - } => { - if let Some(running) = &mut self.running { - let mut glutin = running.glutin.borrow_mut(); - if let Some(viewport) = glutin - .focused_viewport - .and_then(|viewport| glutin.viewports.get_mut(&viewport)) - { - if let Some(egui_winit) = viewport.egui_winit.as_mut() { - egui_winit.on_mouse_motion(*delta); - } + fn device_event( + &mut self, + _: &ActiveEventLoop, + _: winit::event::DeviceId, + event: winit::event::DeviceEvent, + ) -> crate::Result { + if let winit::event::DeviceEvent::MouseMotion { delta } = event { + if let Some(running) = &mut self.running { + let mut glutin = running.glutin.borrow_mut(); + if let Some(viewport) = glutin + .focused_viewport + .and_then(|viewport| glutin.viewports.get_mut(&viewport)) + { + if let Some(egui_winit) = viewport.egui_winit.as_mut() { + egui_winit.on_mouse_motion(delta); + } - if let Some(window) = viewport.window.as_ref() { - EventResult::RepaintNext(window.id()) - } else { - EventResult::Wait - } - } else { - EventResult::Wait + if let Some(window) = viewport.window.as_ref() { + return Ok(EventResult::RepaintNext(window.id())); } - } else { - EventResult::Wait } } + } - #[cfg(feature = "accesskit")] - winit::event::Event::UserEvent(UserEvent::AccessKitActionRequest( - accesskit_winit::ActionRequestEvent { request, window_id }, - )) => { - if let Some(running) = &self.running { - let mut glutin = running.glutin.borrow_mut(); - if let Some(viewport_id) = glutin.viewport_from_window.get(window_id).copied() { - if let Some(viewport) = glutin.viewports.get_mut(&viewport_id) { - if let Some(egui_winit) = &mut viewport.egui_winit { - crate::profile_scope!("on_accesskit_action_request"); - egui_winit.on_accesskit_action_request(request.clone()); - } - } + Ok(EventResult::Wait) + } + + fn window_event( + &mut self, + _: &ActiveEventLoop, + window_id: WindowId, + event: winit::event::WindowEvent, + ) -> Result { + if let Some(running) = &mut self.running { + Ok(running.on_window_event(window_id, &event)) + } else { + Ok(EventResult::Wait) + } + } + + #[cfg(feature = "accesskit")] + fn on_accesskit_event(&mut self, event: accesskit_winit::Event) -> crate::Result { + if let Some(running) = &self.running { + let mut glutin = running.glutin.borrow_mut(); + if let Some(viewport_id) = glutin.viewport_from_window.get(&event.window_id).copied() { + if let Some(viewport) = glutin.viewports.get_mut(&viewport_id) { + if let Some(egui_winit) = &mut viewport.egui_winit { + return Ok(winit_integration::on_accesskit_window_event( + egui_winit, + event.window_id, + &event.window_event, + )); } - // As a form of user input, accessibility actions should - // lead to a repaint. - EventResult::RepaintNext(*window_id) - } else { - EventResult::Wait } } - _ => EventResult::Wait, - }) + } + + Ok(EventResult::Wait) } } impl GlowWinitRunning { fn run_ui_and_paint( &mut self, - event_loop: &EventLoopWindowTarget, + event_loop: &ActiveEventLoop, window_id: WindowId, - ) -> EventResult { + ) -> Result { crate::profile_function!(); let Some(viewport_id) = self @@ -520,7 +502,7 @@ impl GlowWinitRunning { .get(&window_id) .copied() else { - return EventResult::Wait; + return Ok(EventResult::Wait); }; #[cfg(feature = "puffin")] @@ -538,10 +520,10 @@ impl GlowWinitRunning { // That means that the viewport cannot be rendered by itself and needs his parent to be rendered. if let Some(parent_viewport) = glutin.viewports.get(&viewport.ids.parent) { if let Some(window) = parent_viewport.window.as_ref() { - return EventResult::RepaintNext(window.id()); + return Ok(EventResult::RepaintNext(window.id())); } } - return EventResult::Wait; + return Ok(EventResult::Wait); } } @@ -549,15 +531,15 @@ impl GlowWinitRunning { let mut glutin = self.glutin.borrow_mut(); let egui_ctx = glutin.egui_ctx.clone(); let Some(viewport) = glutin.viewports.get_mut(&viewport_id) else { - return EventResult::Wait; + return Ok(EventResult::Wait); }; let Some(window) = viewport.window.as_ref() else { - return EventResult::Wait; + return Ok(EventResult::Wait); }; egui_winit::update_viewport_info(&mut viewport.info, &egui_ctx, window, false); let Some(egui_winit) = viewport.egui_winit.as_mut() else { - return EventResult::Wait; + return Ok(EventResult::Wait); }; let mut raw_input = egui_winit.take_egui_input(window); let viewport_ui_cb = viewport.viewport_ui_cb.clone(); @@ -593,10 +575,10 @@ impl GlowWinitRunning { } = &mut *glutin; let viewport = &viewports[&viewport_id]; let Some(window) = viewport.window.as_ref() else { - return EventResult::Wait; + return Ok(EventResult::Wait); }; let Some(gl_surface) = viewport.gl_surface.as_ref() else { - return EventResult::Wait; + return Ok(EventResult::Wait); }; let screen_size_in_pixels: [u32; 2] = window.inner_size().into(); @@ -651,7 +633,7 @@ impl GlowWinitRunning { } = &mut *glutin; let Some(viewport) = viewports.get_mut(&viewport_id) else { - return EventResult::Wait; + return Ok(EventResult::Wait); }; viewport.info.events.clear(); // they should have been processed @@ -723,13 +705,13 @@ impl GlowWinitRunning { // vsync - don't count as frame-time: frame_timer.pause(); crate::profile_scope!("swap_buffers"); - if let Err(err) = gl_surface.swap_buffers( - current_gl_context - .as_ref() - .expect("failed to get current context to swap buffers"), - ) { - log::error!("swap_buffers failed: {err}"); - } + let context = current_gl_context + .as_ref() + .ok_or(egui_glow::PainterError::from( + "failed to get current context to swap buffers".to_owned(), + ))?; + + gl_surface.swap_buffers(context)?; frame_timer.resume(); } @@ -755,9 +737,9 @@ impl GlowWinitRunning { } if integration.should_close() { - EventResult::Exit + Ok(EventResult::Exit) } else { - EventResult::Wait + Ok(EventResult::Wait) } } @@ -766,8 +748,6 @@ impl GlowWinitRunning { window_id: WindowId, event: &winit::event::WindowEvent, ) -> EventResult { - crate::profile_function!(egui_winit::short_window_event_description(event)); - let mut glutin = self.glutin.borrow_mut(); let viewport_id = glutin.viewport_from_window.get(&window_id).copied(); @@ -908,7 +888,7 @@ impl GlutinWindowContext { egui_ctx: &egui::Context, viewport_builder: ViewportBuilder, native_options: &NativeOptions, - event_loop: &EventLoopWindowTarget, + event_loop: &ActiveEventLoop, ) -> Result { crate::profile_function!(); @@ -957,7 +937,7 @@ impl GlutinWindowContext { let display_builder = glutin_winit::DisplayBuilder::new() // we might want to expose this option to users in the future. maybe using an env var or using native_options. .with_preference(glutin_winit::ApiPreference::FallbackEgl) // https://github.com/emilk/egui/issues/2520#issuecomment-1367841150 - .with_window_builder(Some(egui_winit::create_winit_window_builder( + .with_window_attributes(Some(egui_winit::create_winit_window_attributes( egui_ctx, event_loop, viewport_builder.clone(), @@ -993,8 +973,9 @@ impl GlutinWindowContext { gl_display.supported_features() ); let glutin_raw_window_handle = window.as_ref().map(|w| { - use rwh_05::HasRawWindowHandle as _; // glutin stuck on old version of raw-window-handle - w.raw_window_handle() + w.window_handle() + .expect("Failed to get window handle") + .as_raw() }); log::debug!("creating gl context using raw window handle: {glutin_raw_window_handle:?}"); @@ -1080,7 +1061,7 @@ impl GlutinWindowContext { /// Create a surface, window, and winit integration for all viewports lacking any of that. /// /// Errors will be logged. - fn initialize_all_windows(&mut self, event_loop: &EventLoopWindowTarget) { + fn initialize_all_windows(&mut self, event_loop: &ActiveEventLoop) { crate::profile_function!(); let viewports: Vec = self.viewports.keys().copied().collect(); @@ -1097,7 +1078,7 @@ impl GlutinWindowContext { pub(crate) fn initialize_window( &mut self, viewport_id: ViewportId, - event_loop: &EventLoopWindowTarget, + event_loop: &ActiveEventLoop, ) -> Result { crate::profile_function!(); @@ -1110,17 +1091,18 @@ impl GlutinWindowContext { window } else { log::debug!("Creating a window for viewport {viewport_id:?}"); - let window_builder = egui_winit::create_winit_window_builder( + let window_attributes = egui_winit::create_winit_window_attributes( &self.egui_ctx, event_loop, viewport.builder.clone(), ); - if window_builder.transparent() && self.gl_config.supports_transparency() == Some(false) + if window_attributes.transparent() + && self.gl_config.supports_transparency() == Some(false) { log::error!("Cannot create transparent window: the GL config does not support it"); } let window = - glutin_winit::finalize_window(event_loop, window_builder, &self.gl_config)?; + glutin_winit::finalize_window(event_loop, window_attributes, &self.gl_config)?; egui_winit::apply_viewport_builder_to_window( &self.egui_ctx, &window, @@ -1150,9 +1132,15 @@ impl GlutinWindowContext { let width_px = NonZeroU32::new(width_px).unwrap_or(NonZeroU32::MIN); let height_px = NonZeroU32::new(height_px).unwrap_or(NonZeroU32::MIN); let surface_attributes = { - use rwh_05::HasRawWindowHandle as _; // glutin stuck on old version of raw-window-handle glutin::surface::SurfaceAttributesBuilder::::new() - .build(window.raw_window_handle(), width_px, height_px) + .build( + window + .window_handle() + .expect("Failed to get display handle") + .as_raw(), + width_px, + height_px, + ) }; log::trace!("creating surface with attributes: {surface_attributes:?}"); @@ -1267,7 +1255,7 @@ impl GlutinWindowContext { fn handle_viewport_output( &mut self, - event_loop: &EventLoopWindowTarget, + event_loop: &ActiveEventLoop, egui_ctx: &egui::Context, viewport_output: &ViewportIdMap, ) { @@ -1389,7 +1377,6 @@ fn initialize_or_update_viewport( /// This is called (via a callback) by user code to render immediate viewports, /// i.e. viewport that are directly nested inside a parent viewport. fn render_immediate_viewport( - event_loop: &EventLoopWindowTarget, egui_ctx: &egui::Context, glutin: &RefCell, painter: &RefCell, @@ -1417,7 +1404,11 @@ fn render_immediate_viewport( None, ); - if let Err(err) = glutin.initialize_window(viewport_id, event_loop) { + let ret = event_loop_context::with_current_event_loop(|event_loop| { + glutin.initialize_window(viewport_id, event_loop) + }); + + if let Some(Err(err)) = ret { log::error!( "Failed to initialize a window for immediate viewport {viewport_id:?}: {err}" ); @@ -1523,7 +1514,9 @@ fn render_immediate_viewport( egui_winit.handle_platform_output(window, platform_output); - glutin.handle_viewport_output(event_loop, egui_ctx, &viewport_output); + event_loop_context::with_current_event_loop(|event_loop| { + glutin.handle_viewport_output(event_loop, egui_ctx, &viewport_output); + }); } #[cfg(feature = "__screenshot")] diff --git a/crates/eframe/src/native/mod.rs b/crates/eframe/src/native/mod.rs index 5fadd561014..cc0bfd7fc56 100644 --- a/crates/eframe/src/native/mod.rs +++ b/crates/eframe/src/native/mod.rs @@ -1,5 +1,6 @@ mod app_icon; mod epi_integration; +mod event_loop_context; pub mod run; /// File storage which can be used by native backends. diff --git a/crates/eframe/src/native/run.rs b/crates/eframe/src/native/run.rs index 6ba5486b678..2d3a9dbe2b0 100644 --- a/crates/eframe/src/native/run.rs +++ b/crates/eframe/src/native/run.rs @@ -1,36 +1,29 @@ use std::{cell::RefCell, time::Instant}; -use winit::event_loop::{EventLoop, EventLoopBuilder}; +use winit::{ + application::ApplicationHandler, + event_loop::{ActiveEventLoop, ControlFlow, EventLoop}, + window::WindowId, +}; use ahash::HashMap; +use super::winit_integration::{UserEvent, WinitApp}; use crate::{ epi, - native::winit_integration::{short_event_description, EventResult}, + native::{event_loop_context, winit_integration::EventResult}, Result, }; -use super::winit_integration::{UserEvent, WinitApp}; - // ---------------------------------------------------------------------------- - -fn create_event_loop_builder( - native_options: &mut epi::NativeOptions, -) -> EventLoopBuilder { +fn create_event_loop(native_options: &mut epi::NativeOptions) -> Result> { crate::profile_function!(); - let mut event_loop_builder = winit::event_loop::EventLoopBuilder::with_user_event(); + let mut builder = winit::event_loop::EventLoop::with_user_event(); if let Some(hook) = std::mem::take(&mut native_options.event_loop_builder) { - hook(&mut event_loop_builder); + hook(&mut builder); } - event_loop_builder -} - -fn create_event_loop(native_options: &mut epi::NativeOptions) -> Result> { - crate::profile_function!(); - let mut builder = create_event_loop_builder(native_options); - crate::profile_scope!("EventLoopBuilder::build"); Ok(builder.build()?) } @@ -59,324 +52,276 @@ fn with_event_loop( }) } -#[cfg(not(target_os = "ios"))] -fn run_and_return(event_loop: &mut EventLoop, mut winit_app: impl WinitApp) -> Result { - use winit::{event_loop::ControlFlow, platform::run_on_demand::EventLoopExtRunOnDemand}; - - log::trace!("Entering the winit event loop (run_on_demand)…"); - - // When to repaint what window - let mut windows_next_repaint_times = HashMap::default(); - - let mut returned_result = Ok(()); - - event_loop.run_on_demand(|event, event_loop_window_target| { - crate::profile_scope!("winit_event", short_event_description(&event)); - - log::trace!("winit event: {event:?}"); +/// Wraps a [`WinitApp`] to implement [`ApplicationHandler`]. This handles redrawing, exit states, and +/// some events, but otherwise forwards events to the [`WinitApp`]. +struct WinitAppWrapper { + windows_next_repaint_times: HashMap, + winit_app: T, + return_result: Result<(), crate::Error>, + run_and_return: bool, +} - if matches!(event, winit::event::Event::AboutToWait) { - return; // early-out: don't trigger another wait +impl WinitAppWrapper { + fn new(winit_app: T, run_and_return: bool) -> Self { + Self { + windows_next_repaint_times: HashMap::default(), + winit_app, + return_result: Ok(()), + run_and_return, } + } - let event_result = match &event { - winit::event::Event::LoopExiting => { - // On Mac, Cmd-Q we get here and then `run_on_demand` doesn't return (despite its name), - // so we need to save state now: - log::debug!("Received Event::LoopExiting - saving app state…"); - winit_app.save_and_destroy(); - return; - } + fn handle_event_result( + &mut self, + event_loop: &ActiveEventLoop, + event_result: Result, + ) { + let mut exit = false; - winit::event::Event::WindowEvent { - event: winit::event::WindowEvent::RedrawRequested, - window_id, - } => { - windows_next_repaint_times.remove(window_id); - winit_app.run_ui_and_paint(event_loop_window_target, *window_id) - } + log::trace!("event_result: {event_result:?}"); - winit::event::Event::UserEvent(UserEvent::RequestRepaint { - when, - frame_nr, - viewport_id, - }) => { - let current_frame_nr = winit_app.frame_nr(*viewport_id); - if current_frame_nr == *frame_nr || current_frame_nr == *frame_nr + 1 { - log::trace!("UserEvent::RequestRepaint scheduling repaint at {when:?}"); - if let Some(window_id) = winit_app.window_id_from_viewport_id(*viewport_id) { - EventResult::RepaintAt(window_id, *when) + let combined_result = event_result.and_then(|event_result| { + match event_result { + EventResult::Wait => { + event_loop.set_control_flow(ControlFlow::Wait); + Ok(event_result) + } + EventResult::RepaintNow(window_id) => { + log::trace!("RepaintNow of {window_id:?}",); + + if cfg!(target_os = "windows") { + // Fix flickering on Windows, see https://github.com/emilk/egui/pull/2280 + self.windows_next_repaint_times.remove(&window_id); + self.winit_app.run_ui_and_paint(event_loop, window_id) } else { - EventResult::Wait + // Fix for https://github.com/emilk/egui/issues/2425 + self.windows_next_repaint_times + .insert(window_id, Instant::now()); + Ok(event_result) } - } else { - log::trace!("Got outdated UserEvent::RequestRepaint"); - EventResult::Wait // old request - we've already repainted } - } - - winit::event::Event::NewEvents(winit::event::StartCause::ResumeTimeReached { - .. - }) => { - log::trace!("Woke up to check next_repaint_time"); - EventResult::Wait - } - - event => match winit_app.on_event(event_loop_window_target, event) { - Ok(event_result) => { - log::trace!("event_result: {event_result:?}"); - event_result + EventResult::RepaintNext(window_id) => { + log::trace!("RepaintNext of {window_id:?}",); + self.windows_next_repaint_times + .insert(window_id, Instant::now()); + Ok(event_result) } - Err(err) => { - log::error!("Exiting because of error: {err} during event {event:?}"); - returned_result = Err(err); - EventResult::Exit + EventResult::RepaintAt(window_id, repaint_time) => { + self.windows_next_repaint_times.insert( + window_id, + self.windows_next_repaint_times + .get(&window_id) + .map_or(repaint_time, |last| (*last).min(repaint_time)), + ); + Ok(event_result) } - }, - }; - - match event_result { - EventResult::Wait => { - event_loop_window_target.set_control_flow(ControlFlow::Wait); - } - EventResult::RepaintNow(window_id) => { - log::trace!( - "RepaintNow of {window_id:?} caused by {}", - short_event_description(&event) - ); - if cfg!(target_os = "windows") { - // Fix flickering on Windows, see https://github.com/emilk/egui/pull/2280 - windows_next_repaint_times.remove(&window_id); - - winit_app.run_ui_and_paint(event_loop_window_target, window_id); - } else { - // Fix for https://github.com/emilk/egui/issues/2425 - windows_next_repaint_times.insert(window_id, Instant::now()); + EventResult::Exit => { + exit = true; + Ok(event_result) } } - EventResult::RepaintNext(window_id) => { - log::trace!( - "RepaintNext of {window_id:?} caused by {}", - short_event_description(&event) - ); - windows_next_repaint_times.insert(window_id, Instant::now()); - } - EventResult::RepaintAt(window_id, repaint_time) => { - windows_next_repaint_times.insert( - window_id, - windows_next_repaint_times - .get(&window_id) - .map_or(repaint_time, |last| (*last).min(repaint_time)), - ); - } - EventResult::Exit => { + }); + + if let Err(err) = combined_result { + log::error!("Exiting because of error: {err}"); + exit = true; + self.return_result = Err(err); + }; + + if exit { + if self.run_and_return { log::debug!("Asking to exit event loop…"); - winit_app.save_and_destroy(); - event_loop_window_target.exit(); - return; + event_loop.exit(); + } else { + log::debug!("Quitting - saving app state…"); + self.winit_app.save_and_destroy(); + + log::debug!("Exiting with return code 0"); + + #[allow(clippy::exit)] + std::process::exit(0); } } - let mut next_repaint_time = windows_next_repaint_times.values().min().copied(); + self.check_redraw_requests(event_loop); + } + + fn check_redraw_requests(&mut self, event_loop: &ActiveEventLoop) { + let mut next_repaint_time = self.windows_next_repaint_times.values().min().copied(); - windows_next_repaint_times.retain(|window_id, repaint_time| { - if Instant::now() < *repaint_time { - return true; // not yet ready - }; + self.windows_next_repaint_times + .retain(|window_id, repaint_time| { + if Instant::now() < *repaint_time { + return true; // not yet ready + }; - next_repaint_time = None; - event_loop_window_target.set_control_flow(ControlFlow::Poll); + next_repaint_time = None; + event_loop.set_control_flow(ControlFlow::Poll); - if let Some(window) = winit_app.window(*window_id) { - log::trace!("request_redraw for {window_id:?}"); - let is_minimized = window.is_minimized().unwrap_or(false); - if is_minimized { - false + if let Some(window) = self.winit_app.window(*window_id) { + log::trace!("request_redraw for {window_id:?}"); + let is_minimized = window.is_minimized().unwrap_or(false); + if is_minimized { + false + } else { + window.request_redraw(); + true + } } else { - window.request_redraw(); - true + log::trace!("No window found for {window_id:?}"); + false } - } else { - log::trace!("No window found for {window_id:?}"); - false - } - }); + }); if let Some(next_repaint_time) = next_repaint_time { - event_loop_window_target.set_control_flow(ControlFlow::WaitUntil(next_repaint_time)); - }; - })?; - - log::debug!("eframe window closed"); + // WaitUntil seems to not work on iOS + #[cfg(target_os = "ios")] + winit_app + .get_window_winit_id(ViewportId::ROOT) + .map(|window_id| { + winit_app + .window(window_id) + .map(|window| window.request_redraw()) + }); - drop(winit_app); - - // On Windows this clears out events so that we can later create another window. - // See https://github.com/emilk/egui/pull/1889 for details. - // - // Note that this approach may cause issues on macOS (emilk/egui#2768); therefore, - // we only apply this approach on Windows to minimize the affect. - #[cfg(target_os = "windows")] - { - event_loop - .run_on_demand(|_, event_loop_window_target| { - event_loop_window_target.exit(); - }) - .ok(); + event_loop.set_control_flow(ControlFlow::WaitUntil(next_repaint_time)); + }; } - - returned_result } -fn run_and_exit( - event_loop: EventLoop, - mut winit_app: impl WinitApp + 'static, -) -> Result { - use winit::event_loop::ControlFlow; - log::trace!("Entering the winit event loop (run)…"); +impl ApplicationHandler for WinitAppWrapper { + fn suspended(&mut self, event_loop: &ActiveEventLoop) { + crate::profile_function!("Event::Suspended"); - // When to repaint what window - let mut windows_next_repaint_times = HashMap::default(); + event_loop_context::with_event_loop_context(event_loop, move || { + let event_result = self.winit_app.suspended(event_loop); + self.handle_event_result(event_loop, event_result); + }); + } - event_loop.run(move |event, event_loop_window_target| { - crate::profile_scope!("winit_event", short_event_description(&event)); + fn resumed(&mut self, event_loop: &ActiveEventLoop) { + crate::profile_function!("Event::Resumed"); - log::trace!("winit event: {event:?}"); + // Nb: Make sure this guard is dropped after this function returns. + event_loop_context::with_event_loop_context(event_loop, move || { + let event_result = self.winit_app.resumed(event_loop); + self.handle_event_result(event_loop, event_result); + }); + } - if matches!(event, winit::event::Event::AboutToWait) { - return; // early-out: don't trigger another wait - } + fn exiting(&mut self, event_loop: &ActiveEventLoop) { + // On Mac, Cmd-Q we get here and then `run_app_on_demand` doesn't return (despite its name), + // so we need to save state now: + log::debug!("Received Event::LoopExiting - saving app state…"); + event_loop_context::with_event_loop_context(event_loop, move || { + self.winit_app.save_and_destroy(); + }); + } - let event_result = match &event { - winit::event::Event::LoopExiting => { - log::debug!("Received Event::LoopExiting"); - EventResult::Exit - } + fn device_event( + &mut self, + event_loop: &ActiveEventLoop, + device_id: winit::event::DeviceId, + event: winit::event::DeviceEvent, + ) { + crate::profile_function!(egui_winit::short_device_event_description(&event)); + + // Nb: Make sure this guard is dropped after this function returns. + event_loop_context::with_event_loop_context(event_loop, move || { + let event_result = self.winit_app.device_event(event_loop, device_id, event); + self.handle_event_result(event_loop, event_result); + }); + } - winit::event::Event::WindowEvent { - event: winit::event::WindowEvent::RedrawRequested, - window_id, - } => { - windows_next_repaint_times.remove(window_id); - winit_app.run_ui_and_paint(event_loop_window_target, *window_id) - } + fn user_event(&mut self, event_loop: &ActiveEventLoop, event: UserEvent) { + crate::profile_function!(match &event { + UserEvent::RequestRepaint { .. } => "UserEvent::RequestRepaint", + #[cfg(feature = "accesskit")] + UserEvent::AccessKitActionRequest(_) => "UserEvent::AccessKitActionRequest", + }); - winit::event::Event::UserEvent(UserEvent::RequestRepaint { - when, - frame_nr, - viewport_id, - }) => { - let current_frame_nr = winit_app.frame_nr(*viewport_id); - if current_frame_nr == *frame_nr || current_frame_nr == *frame_nr + 1 { - if let Some(window_id) = winit_app.window_id_from_viewport_id(*viewport_id) { - EventResult::RepaintAt(window_id, *when) + event_loop_context::with_event_loop_context(event_loop, move || { + let event_result = match event { + UserEvent::RequestRepaint { + when, + frame_nr, + viewport_id, + } => { + let current_frame_nr = self.winit_app.frame_nr(viewport_id); + if current_frame_nr == frame_nr || current_frame_nr == frame_nr + 1 { + log::trace!("UserEvent::RequestRepaint scheduling repaint at {when:?}"); + if let Some(window_id) = + self.winit_app.window_id_from_viewport_id(viewport_id) + { + Ok(EventResult::RepaintAt(window_id, when)) + } else { + Ok(EventResult::Wait) + } } else { - EventResult::Wait + log::trace!("Got outdated UserEvent::RequestRepaint"); + Ok(EventResult::Wait) // old request - we've already repainted } - } else { - log::trace!("Got outdated UserEvent::RequestRepaint"); - EventResult::Wait // old request - we've already repainted } - } - - winit::event::Event::NewEvents(winit::event::StartCause::ResumeTimeReached { - .. - }) => { - log::trace!("Woke up to check next_repaint_time"); - EventResult::Wait - } - - event => match winit_app.on_event(event_loop_window_target, event) { - Ok(event_result) => { - log::trace!("event_result: {event_result:?}"); - event_result - } - Err(err) => { - panic!("eframe encountered a fatal error: {err} during event {event:?}"); + #[cfg(feature = "accesskit")] + UserEvent::AccessKitActionRequest(request) => { + self.winit_app.on_accesskit_event(request) } - }, - }; + }; + self.handle_event_result(event_loop, event_result); + }); + } - match event_result { - EventResult::Wait => { - event_loop_window_target.set_control_flow(ControlFlow::Wait); - } - EventResult::RepaintNow(window_id) => { - log::trace!("RepaintNow caused by {}", short_event_description(&event)); - if cfg!(target_os = "windows") { - // Fix flickering on Windows, see https://github.com/emilk/egui/pull/2280 - windows_next_repaint_times.remove(&window_id); + fn new_events(&mut self, event_loop: &ActiveEventLoop, cause: winit::event::StartCause) { + if let winit::event::StartCause::ResumeTimeReached { .. } = cause { + log::trace!("Woke up to check next_repaint_time"); + } - winit_app.run_ui_and_paint(event_loop_window_target, window_id); - } else { - // Fix for https://github.com/emilk/egui/issues/2425 - windows_next_repaint_times.insert(window_id, Instant::now()); - } - } - EventResult::RepaintNext(window_id) => { - log::trace!("RepaintNext caused by {}", short_event_description(&event)); - windows_next_repaint_times.insert(window_id, Instant::now()); - } - EventResult::RepaintAt(window_id, repaint_time) => { - windows_next_repaint_times.insert( - window_id, - windows_next_repaint_times - .get(&window_id) - .map_or(repaint_time, |last| (*last).min(repaint_time)), - ); - } - EventResult::Exit => { - log::debug!("Quitting - saving app state…"); - winit_app.save_and_destroy(); + self.check_redraw_requests(event_loop); + } - log::debug!("Exiting with return code 0"); - #[allow(clippy::exit)] - std::process::exit(0); - } - } + fn window_event( + &mut self, + event_loop: &ActiveEventLoop, + window_id: WindowId, + event: winit::event::WindowEvent, + ) { + crate::profile_function!(egui_winit::short_window_event_description(&event)); + + // Nb: Make sure this guard is dropped after this function returns. + event_loop_context::with_event_loop_context(event_loop, move || { + let event_result = match event { + winit::event::WindowEvent::RedrawRequested => { + self.windows_next_repaint_times.remove(&window_id); + self.winit_app.run_ui_and_paint(event_loop, window_id) + } + _ => self.winit_app.window_event(event_loop, window_id, event), + }; - let mut next_repaint_time = windows_next_repaint_times.values().min().copied(); + self.handle_event_result(event_loop, event_result); + }); + } +} - windows_next_repaint_times.retain(|window_id, repaint_time| { - if Instant::now() < *repaint_time { - return true; // not yet ready - } +#[cfg(not(target_os = "ios"))] +fn run_and_return(event_loop: &mut EventLoop, winit_app: impl WinitApp) -> Result { + use winit::platform::run_on_demand::EventLoopExtRunOnDemand; - next_repaint_time = None; - event_loop_window_target.set_control_flow(ControlFlow::Poll); + log::trace!("Entering the winit event loop (run_app_on_demand)…"); - if let Some(window) = winit_app.window(*window_id) { - log::trace!("request_redraw for {window_id:?}"); - let is_minimized = window.is_minimized().unwrap_or(false); - if is_minimized { - false - } else { - window.request_redraw(); - true - } - } else { - log::trace!("No window found for {window_id:?}"); - false - } - }); + let mut app = WinitAppWrapper::new(winit_app, true); + event_loop.run_app_on_demand(&mut app)?; + log::debug!("eframe window closed"); + app.return_result +} - if let Some(next_repaint_time) = next_repaint_time { - // WaitUntil seems to not work on iOS - #[cfg(target_os = "ios")] - winit_app - .get_window_winit_id(ViewportId::ROOT) - .map(|window_id| { - winit_app - .window(window_id) - .map(|window| window.request_redraw()) - }); +fn run_and_exit(event_loop: EventLoop, winit_app: impl WinitApp + 'static) -> Result { + log::trace!("Entering the winit event loop (run_app)…"); - event_loop_window_target.set_control_flow(ControlFlow::WaitUntil(next_repaint_time)); - }; - })?; + // When to repaint what window + let mut app = WinitAppWrapper::new(winit_app, false); + event_loop.run_app(&mut app)?; log::debug!("winit event loop unexpectedly returned"); - Ok(()) } diff --git a/crates/eframe/src/native/wgpu_integration.rs b/crates/eframe/src/native/wgpu_integration.rs index fc3f6e9e134..74f4e957c70 100644 --- a/crates/eframe/src/native/wgpu_integration.rs +++ b/crates/eframe/src/native/wgpu_integration.rs @@ -11,7 +11,7 @@ use egui_winit::ActionRequested; use parking_lot::Mutex; use raw_window_handle::{HasDisplayHandle as _, HasWindowHandle as _}; use winit::{ - event_loop::{EventLoop, EventLoopProxy, EventLoopWindowTarget}, + event_loop::{ActiveEventLoop, EventLoop, EventLoopProxy}, window::{Window, WindowId}, }; @@ -22,10 +22,11 @@ use egui::{ }; #[cfg(feature = "accesskit")] use egui_winit::accesskit_winit; +use winit_integration::UserEvent; use crate::{ native::{epi_integration::EpiIntegration, winit_integration::EventResult}, - App, AppCreator, CreationContext, NativeOptions, Result, Storage, UserEvent, + App, AppCreator, CreationContext, NativeOptions, Result, Storage, }; use super::{winit_integration::WinitApp, *}; @@ -119,7 +120,7 @@ impl WgpuWinitApp { } /// Create a window for all viewports lacking one. - fn initialized_all_windows(&mut self, event_loop: &EventLoopWindowTarget) { + fn initialized_all_windows(&mut self, event_loop: &ActiveEventLoop) { let Some(running) = &mut self.running else { return; }; @@ -142,11 +143,7 @@ impl WgpuWinitApp { } #[cfg(target_os = "android")] - fn recreate_window( - &self, - event_loop: &EventLoopWindowTarget, - running: &WgpuWinitRunning, - ) { + fn recreate_window(&self, event_loop: &ActiveEventLoop, running: &WgpuWinitRunning) { let SharedState { egui_ctx, viewports, @@ -178,7 +175,7 @@ impl WgpuWinitApp { fn init_run_state( &mut self, egui_ctx: egui::Context, - event_loop: &EventLoopWindowTarget, + event_loop: &ActiveEventLoop, storage: Option>, window: Window, builder: ViewportBuilder, @@ -252,7 +249,7 @@ impl WgpuWinitApp { #[cfg(feature = "accesskit")] { let event_loop_proxy = self.repaint_proxy.lock().clone(); - integration.init_accesskit(&mut egui_winit, &window, event_loop_proxy); + egui_winit.init_accesskit(&window, event_loop_proxy); } let theme = system_theme.unwrap_or(self.native_options.default_theme); egui_ctx.set_visuals(theme.egui_visuals()); @@ -311,16 +308,9 @@ impl WgpuWinitApp { let shared = Rc::downgrade(&shared); let beginning = integration.beginning; - let event_loop: *const EventLoopWindowTarget = event_loop; - egui::Context::set_immediate_viewport_renderer(move |_egui_ctx, immediate_viewport| { if let Some(shared) = shared.upgrade() { - // SAFETY: the event loop lives longer than - // the Rc:s we just upgraded above. - #[allow(unsafe_code)] - let event_loop = unsafe { event_loop.as_ref().unwrap() }; - - render_immediate_viewport(event_loop, beginning, &shared, immediate_viewport); + render_immediate_viewport(beginning, &shared, immediate_viewport); } else { log::warn!("render_sync_callback called after window closed"); } @@ -377,134 +367,127 @@ impl WinitApp for WgpuWinitApp { fn run_ui_and_paint( &mut self, - event_loop: &EventLoopWindowTarget, + event_loop: &ActiveEventLoop, window_id: WindowId, - ) -> EventResult { + ) -> Result { self.initialized_all_windows(event_loop); if let Some(running) = &mut self.running { running.run_ui_and_paint(window_id) } else { - EventResult::Wait + Ok(EventResult::Wait) } } - fn on_event( - &mut self, - event_loop: &EventLoopWindowTarget, - event: &winit::event::Event, - ) -> Result { - crate::profile_function!(winit_integration::short_event_description(event)); + fn resumed(&mut self, event_loop: &ActiveEventLoop) -> crate::Result { + log::debug!("Event::Resumed"); - self.initialized_all_windows(event_loop); + let running = if let Some(running) = &self.running { + #[cfg(target_os = "android")] + self.recreate_window(event_loop, running); + running + } else { + let storage = if let Some(file) = &self.native_options.persistence_path { + epi_integration::create_storage_with_file(file) + } else { + epi_integration::create_storage( + self.native_options + .viewport + .app_id + .as_ref() + .unwrap_or(&self.app_name), + ) + }; + let egui_ctx = winit_integration::create_egui_context(storage.as_deref()); + let (window, builder) = create_window( + &egui_ctx, + event_loop, + storage.as_deref(), + &mut self.native_options, + )?; + self.init_run_state(egui_ctx, event_loop, storage, window, builder)? + }; + + let viewport = &running.shared.borrow().viewports[&ViewportId::ROOT]; + if let Some(window) = &viewport.window { + Ok(EventResult::RepaintNow(window.id())) + } else { + Ok(EventResult::Wait) + } + } - Ok(match event { - winit::event::Event::Resumed => { - log::debug!("Event::Resumed"); + fn suspended(&mut self, _: &ActiveEventLoop) -> crate::Result { + #[cfg(target_os = "android")] + self.drop_window()?; + Ok(EventResult::Wait) + } - let running = if let Some(running) = &self.running { - #[cfg(target_os = "android")] - self.recreate_window(event_loop, running); - running - } else { - let storage = if let Some(file) = &self.native_options.persistence_path { - epi_integration::create_storage_with_file(file) - } else { - epi_integration::create_storage( - self.native_options - .viewport - .app_id - .as_ref() - .unwrap_or(&self.app_name), - ) - }; - let egui_ctx = winit_integration::create_egui_context(storage.as_deref()); - let (window, builder) = create_window( - &egui_ctx, - event_loop, - storage.as_deref(), - &mut self.native_options, - )?; - self.init_run_state(egui_ctx, event_loop, storage, window, builder)? - }; + fn device_event( + &mut self, + _: &ActiveEventLoop, + _: winit::event::DeviceId, + event: winit::event::DeviceEvent, + ) -> crate::Result { + if let winit::event::DeviceEvent::MouseMotion { delta } = event { + if let Some(running) = &mut self.running { + let mut shared = running.shared.borrow_mut(); + if let Some(viewport) = shared + .focused_viewport + .and_then(|viewport| shared.viewports.get_mut(&viewport)) + { + if let Some(egui_winit) = viewport.egui_winit.as_mut() { + egui_winit.on_mouse_motion(delta); + } - let viewport = &running.shared.borrow().viewports[&ViewportId::ROOT]; - if let Some(window) = &viewport.window { - EventResult::RepaintNow(window.id()) - } else { - EventResult::Wait + if let Some(window) = viewport.window.as_ref() { + return Ok(EventResult::RepaintNext(window.id())); + } } } + } - winit::event::Event::Suspended => { - #[cfg(target_os = "android")] - self.drop_window()?; - EventResult::Wait - } + Ok(EventResult::Wait) + } - winit::event::Event::WindowEvent { event, window_id } => { - if let Some(running) = &mut self.running { - running.on_window_event(*window_id, event) - } else { - EventResult::Wait - } - } + fn window_event( + &mut self, + event_loop: &ActiveEventLoop, + window_id: WindowId, + event: winit::event::WindowEvent, + ) -> crate::Result { + self.initialized_all_windows(event_loop); - winit::event::Event::DeviceEvent { - device_id: _, - event: winit::event::DeviceEvent::MouseMotion { delta }, - } => { - if let Some(running) = &mut self.running { - let mut shared = running.shared.borrow_mut(); - if let Some(viewport) = shared - .focused_viewport - .and_then(|viewport| shared.viewports.get_mut(&viewport)) - { - if let Some(egui_winit) = viewport.egui_winit.as_mut() { - egui_winit.on_mouse_motion(*delta); - } + if let Some(running) = &mut self.running { + Ok(running.on_window_event(window_id, &event)) + } else { + Ok(EventResult::Wait) + } + } - if let Some(window) = viewport.window.as_ref() { - EventResult::RepaintNext(window.id()) - } else { - EventResult::Wait - } - } else { - EventResult::Wait - } - } else { - EventResult::Wait + #[cfg(feature = "accesskit")] + fn on_accesskit_event(&mut self, event: accesskit_winit::Event) -> crate::Result { + if let Some(running) = &mut self.running { + let mut shared_lock = running.shared.borrow_mut(); + let SharedState { + viewport_from_window, + viewports, + .. + } = &mut *shared_lock; + if let Some(viewport) = viewport_from_window + .get(&event.window_id) + .and_then(|id| viewports.get_mut(id)) + { + if let Some(egui_winit) = &mut viewport.egui_winit { + return Ok(winit_integration::on_accesskit_window_event( + egui_winit, + event.window_id, + &event.window_event, + )); } } + } - #[cfg(feature = "accesskit")] - winit::event::Event::UserEvent(UserEvent::AccessKitActionRequest( - accesskit_winit::ActionRequestEvent { request, window_id }, - )) => { - if let Some(running) = &mut self.running { - let mut shared_lock = running.shared.borrow_mut(); - let SharedState { - viewport_from_window, - viewports, - .. - } = &mut *shared_lock; - if let Some(viewport) = viewport_from_window - .get(window_id) - .and_then(|id| viewports.get_mut(id)) - { - if let Some(egui_winit) = &mut viewport.egui_winit { - egui_winit.on_accesskit_action_request(request.clone()); - } - } - // As a form of user input, accessibility actions should - // lead to a repaint. - EventResult::RepaintNext(*window_id) - } else { - EventResult::Wait - } - } - _ => EventResult::Wait, - }) + Ok(EventResult::Wait) } } @@ -527,7 +510,7 @@ impl WgpuWinitRunning { } /// This is called both for the root viewport, and all deferred viewports - fn run_ui_and_paint(&mut self, window_id: WindowId) -> EventResult { + fn run_ui_and_paint(&mut self, window_id: WindowId) -> Result { crate::profile_function!(); let Some(viewport_id) = self @@ -537,7 +520,7 @@ impl WgpuWinitRunning { .get(&window_id) .copied() else { - return EventResult::Wait; + return Ok(EventResult::Wait); }; #[cfg(feature = "puffin")] @@ -562,7 +545,7 @@ impl WgpuWinitRunning { if viewport_id != ViewportId::ROOT { let Some(viewport) = viewports.get(&viewport_id) else { - return EventResult::Wait; + return Ok(EventResult::Wait); }; if viewport.viewport_ui_cb.is_none() { @@ -570,15 +553,15 @@ impl WgpuWinitRunning { // That means that the viewport cannot be rendered by itself and needs his parent to be rendered. if let Some(viewport) = viewports.get(&viewport.ids.parent) { if let Some(window) = viewport.window.as_ref() { - return EventResult::RepaintNext(window.id()); + return Ok(EventResult::RepaintNext(window.id())); } } - return EventResult::Wait; + return Ok(EventResult::Wait); } } let Some(viewport) = viewports.get_mut(&viewport_id) else { - return EventResult::Wait; + return Ok(EventResult::Wait); }; let Viewport { @@ -592,21 +575,17 @@ impl WgpuWinitRunning { let viewport_ui_cb = viewport_ui_cb.clone(); let Some(window) = window else { - return EventResult::Wait; + return Ok(EventResult::Wait); }; egui_winit::update_viewport_info(info, &integration.egui_ctx, window, false); { crate::profile_scope!("set_window"); - if let Err(err) = - pollster::block_on(painter.set_window(viewport_id, Some(window.clone()))) - { - log::warn!("Failed to set window: {err}"); - } + pollster::block_on(painter.set_window(viewport_id, Some(window.clone())))?; } let Some(egui_winit) = egui_winit.as_mut() else { - return EventResult::Wait; + return Ok(EventResult::Wait); }; let mut raw_input = egui_winit.take_egui_input(window); @@ -650,7 +629,7 @@ impl WgpuWinitRunning { remove_viewports_not_in(viewports, painter, viewport_from_window, &viewport_output); let Some(viewport) = viewports.get_mut(&viewport_id) else { - return EventResult::Wait; + return Ok(EventResult::Wait); }; viewport.info.events.clear(); // they should have been processed @@ -661,7 +640,7 @@ impl WgpuWinitRunning { .. } = viewport else { - return EventResult::Wait; + return Ok(EventResult::Wait); }; egui_winit.handle_platform_output(window, platform_output); @@ -751,9 +730,9 @@ impl WgpuWinitRunning { } if integration.should_close() { - EventResult::Exit + Ok(EventResult::Exit) } else { - EventResult::Wait + Ok(EventResult::Wait) } } @@ -762,8 +741,6 @@ impl WgpuWinitRunning { window_id: WindowId, event: &winit::event::WindowEvent, ) -> EventResult { - crate::profile_function!(egui_winit::short_window_event_description(event)); - let Self { integration, shared, @@ -865,7 +842,7 @@ impl Viewport { /// Create winit window, if needed. fn initialize_window( &mut self, - event_loop: &EventLoopWindowTarget, + event_loop: &ActiveEventLoop, egui_ctx: &egui::Context, windows_id: &mut HashMap, painter: &mut egui_wgpu::winit::Painter, @@ -910,7 +887,7 @@ impl Viewport { fn create_window( egui_ctx: &egui::Context, - event_loop: &EventLoopWindowTarget, + event_loop: &ActiveEventLoop, storage: Option<&dyn Storage>, native_options: &mut NativeOptions, ) -> Result<(Window, ViewportBuilder), winit::error::OsError> { @@ -931,7 +908,6 @@ fn create_window( } fn render_immediate_viewport( - event_loop: &EventLoopWindowTarget, beginning: Instant, shared: &RefCell, immediate_viewport: ImmediateViewport<'_>, @@ -956,7 +932,9 @@ fn render_immediate_viewport( let viewport = initialize_or_update_viewport(viewports, ids, ViewportClass::Immediate, builder, None); if viewport.window.is_none() { - viewport.initialize_window(event_loop, egui_ctx, viewport_from_window, painter); + event_loop_context::with_current_event_loop(|event_loop| { + viewport.initialize_window(event_loop, egui_ctx, viewport_from_window, painter); + }); } let (Some(window), Some(egui_winit)) = (&viewport.window, &mut viewport.egui_winit) else { diff --git a/crates/eframe/src/native/winit_integration.rs b/crates/eframe/src/native/winit_integration.rs index fbbd7910732..1489b0bf40d 100644 --- a/crates/eframe/src/native/winit_integration.rs +++ b/crates/eframe/src/native/winit_integration.rs @@ -1,7 +1,7 @@ use std::{sync::Arc, time::Instant}; use winit::{ - event_loop::EventLoopWindowTarget, + event_loop::ActiveEventLoop, window::{Window, WindowId}, }; @@ -48,12 +48,12 @@ pub enum UserEvent { /// A request related to [`accesskit`](https://accesskit.dev/). #[cfg(feature = "accesskit")] - AccessKitActionRequest(accesskit_winit::ActionRequestEvent), + AccessKitActionRequest(accesskit_winit::Event), } #[cfg(feature = "accesskit")] -impl From for UserEvent { - fn from(inner: accesskit_winit::ActionRequestEvent) -> Self { +impl From for UserEvent { + fn from(inner: accesskit_winit::Event) -> Self { Self::AccessKitActionRequest(inner) } } @@ -70,15 +70,30 @@ pub trait WinitApp { fn run_ui_and_paint( &mut self, - event_loop: &EventLoopWindowTarget, + event_loop: &ActiveEventLoop, window_id: WindowId, - ) -> EventResult; + ) -> crate::Result; + + fn suspended(&mut self, event_loop: &ActiveEventLoop) -> crate::Result; + + fn resumed(&mut self, event_loop: &ActiveEventLoop) -> crate::Result; + + fn device_event( + &mut self, + event_loop: &ActiveEventLoop, + device_id: winit::event::DeviceId, + event: winit::event::DeviceEvent, + ) -> crate::Result; - fn on_event( + fn window_event( &mut self, - event_loop: &EventLoopWindowTarget, - event: &winit::event::Event, + event_loop: &ActiveEventLoop, + window_id: WindowId, + event: winit::event::WindowEvent, ) -> crate::Result; + + #[cfg(feature = "accesskit")] + fn on_accesskit_event(&mut self, event: accesskit_winit::Event) -> crate::Result; } #[derive(Clone, Copy, Debug, PartialEq, Eq)] @@ -113,15 +128,35 @@ pub fn system_theme(window: &Window, options: &crate::NativeOptions) -> Option) -> &'static str { +#[cfg(feature = "accesskit")] +pub(crate) fn on_accesskit_window_event( + egui_winit: &mut egui_winit::State, + window_id: WindowId, + event: &accesskit_winit::WindowEvent, +) -> EventResult { match event { - winit::event::Event::UserEvent(user_event) => match user_event { - UserEvent::RequestRepaint { .. } => "UserEvent::RequestRepaint", - #[cfg(feature = "accesskit")] - UserEvent::AccessKitActionRequest(_) => "UserEvent::AccessKitActionRequest", - }, - _ => egui_winit::short_generic_event_description(event), + accesskit_winit::WindowEvent::InitialTreeRequested => { + egui_winit.egui_ctx().enable_accesskit(); + // Because we can't provide the initial tree synchronously + // (because that would require the activation handler to access + // the same mutable state as the winit event handler), some + // AccessKit platform adapters will use a placeholder tree + // until we send the first tree update. To minimize the possible + // bad effects of that workaround, repaint and send the tree + // immediately. + EventResult::RepaintNow(window_id) + } + accesskit_winit::WindowEvent::ActionRequested(request) => { + egui_winit.on_accesskit_action_request(request.clone()); + // As a form of user input, accessibility actions should cause + // a repaint, but not until the next regular frame. + EventResult::RepaintNext(window_id) + } + accesskit_winit::WindowEvent::AccessibilityDeactivated => { + egui_winit.egui_ctx().disable_accesskit(); + // Disabling AccessKit support should have no visible effect, + // so there's no need to repaint. + EventResult::Wait + } } } diff --git a/crates/egui-wgpu/Cargo.toml b/crates/egui-wgpu/Cargo.toml index 3eaac2e92f5..647016e302b 100644 --- a/crates/egui-wgpu/Cargo.toml +++ b/crates/egui-wgpu/Cargo.toml @@ -61,9 +61,7 @@ wgpu = { workspace = true, features = ["wgsl"] } # Optional dependencies: -winit = { workspace = true, optional = true, default-features = false, features = [ - "rwh_06", -] } +winit = { workspace = true, optional = true, default-features = false } # Native: [target.'cfg(not(target_arch = "wasm32"))'.dependencies] diff --git a/crates/egui-winit/Cargo.toml b/crates/egui-winit/Cargo.toml index 0cf9bf9403a..95e8215b7d9 100644 --- a/crates/egui-winit/Cargo.toml +++ b/crates/egui-winit/Cargo.toml @@ -62,14 +62,15 @@ egui = { workspace = true, default-features = false, features = ["log"] } ahash.workspace = true log.workspace = true +nix = { version = "0.26.4", default-features = false, optional = true } raw-window-handle.workspace = true web-time.workspace = true -winit = { workspace = true, default-features = false, features = ["rwh_06"] } +winit = { workspace = true, default-features = false } #! ### Optional dependencies # feature accesskit -accesskit_winit = { version = "0.16.0", optional = true } +accesskit_winit = { version = "0.22", optional = true } ## Enable this when generating docs. document-features = { workspace = true, optional = true } @@ -81,5 +82,10 @@ webbrowser = { version = "1.0.0", optional = true } [target.'cfg(any(target_os="linux", target_os="dragonfly", target_os="freebsd", target_os="netbsd", target_os="openbsd"))'.dependencies] smithay-clipboard = { version = "0.7.0", optional = true } +# The wayland-cursor normally selected doesn't properly enable all the features it uses +# and thus doesn't compile as it is used in egui-winit. This is fixed upstream, so force +# a slightly newer version. Remove this when winit upgrades past this version. +wayland-cursor = { version = "0.31.1", default-features = false, optional = true } + [target.'cfg(not(target_os = "android"))'.dependencies] arboard = { version = "3.3", optional = true, default-features = false } diff --git a/crates/egui-winit/src/lib.rs b/crates/egui-winit/src/lib.rs index 4854cd2fd68..e2565794ae3 100644 --- a/crates/egui-winit/src/lib.rs +++ b/crates/egui-winit/src/lib.rs @@ -31,7 +31,7 @@ pub(crate) use profiling_scopes::*; use winit::{ dpi::{PhysicalPosition, PhysicalSize}, event::ElementState, - event_loop::EventLoopWindowTarget, + event_loop::ActiveEventLoop, window::{CursorGrabMode, Window, WindowButtons, WindowLevel}, }; @@ -158,16 +158,15 @@ impl State { } #[cfg(feature = "accesskit")] - pub fn init_accesskit + Send>( + pub fn init_accesskit + Send>( &mut self, window: &Window, event_loop_proxy: winit::event_loop::EventLoopProxy, - initial_tree_update_factory: impl 'static + FnOnce() -> accesskit::TreeUpdate + Send, ) { crate::profile_function!(); - self.accesskit = Some(accesskit_winit::Adapter::new( + + self.accesskit = Some(accesskit_winit::Adapter::with_event_loop_proxy( window, - initial_tree_update_factory, event_loop_proxy, )); } @@ -263,7 +262,7 @@ impl State { crate::profile_function!(short_window_event_description(event)); #[cfg(feature = "accesskit")] - if let Some(accesskit) = &self.accesskit { + if let Some(accesskit) = self.accesskit.as_mut() { accesskit.process_event(window, event); } @@ -474,13 +473,14 @@ impl State { // Things we completely ignore: WindowEvent::ActivationTokenDone { .. } | WindowEvent::AxisMotion { .. } - | WindowEvent::SmartMagnify { .. } - | WindowEvent::TouchpadRotate { .. } => EventResponse { + | WindowEvent::DoubleTapGesture { .. } + | WindowEvent::RotationGesture { .. } + | WindowEvent::PanGesture { .. } => EventResponse { repaint: false, consumed: false, }, - WindowEvent::TouchpadMagnify { delta, .. } => { + WindowEvent::PinchGesture { delta, .. } => { // Positive delta values indicate magnification (zooming in). // Negative delta values indicate shrinking (zooming out). let zoom_factor = (*delta as f32).exp(); @@ -859,7 +859,7 @@ impl State { } #[cfg(feature = "accesskit")] - if let Some(accesskit) = self.accesskit.as_ref() { + if let Some(accesskit) = self.accesskit.as_mut() { if let Some(update) = accesskit_update { crate::profile_scope!("accesskit"); accesskit.update_if_active(|| update); @@ -880,7 +880,7 @@ impl State { if let Some(winit_cursor_icon) = translate_cursor(cursor_icon) { window.set_cursor_visible(true); - window.set_cursor_icon(winit_cursor_icon); + window.set_cursor(winit_cursor_icon); } else { window.set_cursor_visible(false); } @@ -1510,28 +1510,25 @@ fn process_viewport_command( /// /// # Errors /// Possible causes of error include denied permission, incompatible system, and lack of memory. -pub fn create_window( +pub fn create_window( egui_ctx: &egui::Context, - event_loop: &EventLoopWindowTarget, + event_loop: &ActiveEventLoop, viewport_builder: &ViewportBuilder, ) -> Result { crate::profile_function!(); - let window_builder = - create_winit_window_builder(egui_ctx, event_loop, viewport_builder.clone()); - let window = { - crate::profile_scope!("WindowBuilder::build"); - window_builder.build(event_loop)? - }; + let window_attributes = + create_winit_window_attributes(egui_ctx, event_loop, viewport_builder.clone()); + let window = event_loop.create_window(window_attributes)?; apply_viewport_builder_to_window(egui_ctx, &window, viewport_builder); Ok(window) } -pub fn create_winit_window_builder( +pub fn create_winit_window_attributes( egui_ctx: &egui::Context, - event_loop: &EventLoopWindowTarget, + event_loop: &ActiveEventLoop, viewport_builder: ViewportBuilder, -) -> winit::window::WindowBuilder { +) -> winit::window::WindowAttributes { crate::profile_function!(); // We set sizes and positions in egui:s own ui points, which depends on the egui @@ -1590,7 +1587,7 @@ pub fn create_winit_window_builder( clamp_size_to_monitor_size: _, // Handled in `viewport_builder` in `epi_integration.rs` } = viewport_builder; - let mut window_builder = winit::window::WindowBuilder::new() + let mut window_attributes = winit::window::WindowAttributes::default() .with_title(title.unwrap_or_else(|| "egui window".to_owned())) .with_transparent(transparent.unwrap_or(false)) .with_decorations(decorations.unwrap_or(true)) @@ -1621,28 +1618,28 @@ pub fn create_winit_window_builder( .with_active(active.unwrap_or(true)); if let Some(size) = inner_size { - window_builder = window_builder.with_inner_size(PhysicalSize::new( + window_attributes = window_attributes.with_inner_size(PhysicalSize::new( pixels_per_point * size.x, pixels_per_point * size.y, )); } if let Some(size) = min_inner_size { - window_builder = window_builder.with_min_inner_size(PhysicalSize::new( + window_attributes = window_attributes.with_min_inner_size(PhysicalSize::new( pixels_per_point * size.x, pixels_per_point * size.y, )); } if let Some(size) = max_inner_size { - window_builder = window_builder.with_max_inner_size(PhysicalSize::new( + window_attributes = window_attributes.with_max_inner_size(PhysicalSize::new( pixels_per_point * size.x, pixels_per_point * size.y, )); } if let Some(pos) = position { - window_builder = window_builder.with_position(PhysicalPosition::new( + window_attributes = window_attributes.with_position(PhysicalPosition::new( pixels_per_point * pos.x, pixels_per_point * pos.y, )); @@ -1650,61 +1647,61 @@ pub fn create_winit_window_builder( if let Some(icon) = icon { let winit_icon = to_winit_icon(&icon); - window_builder = window_builder.with_window_icon(winit_icon); + window_attributes = window_attributes.with_window_icon(winit_icon); } #[cfg(all(feature = "wayland", target_os = "linux"))] if let Some(app_id) = _app_id { - use winit::platform::wayland::WindowBuilderExtWayland as _; - window_builder = window_builder.with_name(app_id, ""); + use winit::platform::wayland::WindowAttributesExtWayland as _; + window_attributes = window_attributes.with_name(app_id, ""); } #[cfg(all(feature = "x11", target_os = "linux"))] { if let Some(window_type) = _window_type { - use winit::platform::x11::WindowBuilderExtX11 as _; - use winit::platform::x11::XWindowType; - window_builder = window_builder.with_x11_window_type(vec![match window_type { - egui::X11WindowType::Normal => XWindowType::Normal, - egui::X11WindowType::Utility => XWindowType::Utility, - egui::X11WindowType::Dock => XWindowType::Dock, - egui::X11WindowType::Desktop => XWindowType::Desktop, - egui::X11WindowType::Toolbar => XWindowType::Toolbar, - egui::X11WindowType::Menu => XWindowType::Menu, - egui::X11WindowType::Splash => XWindowType::Splash, - egui::X11WindowType::Dialog => XWindowType::Dialog, - egui::X11WindowType::DropdownMenu => XWindowType::DropdownMenu, - egui::X11WindowType::PopupMenu => XWindowType::PopupMenu, - egui::X11WindowType::Tooltip => XWindowType::Tooltip, - egui::X11WindowType::Notification => XWindowType::Notification, - egui::X11WindowType::Combo => XWindowType::Combo, - egui::X11WindowType::Dnd => XWindowType::Dnd, + use winit::platform::x11::WindowAttributesExtX11 as _; + use winit::platform::x11::WindowType; + window_attributes = window_attributes.with_x11_window_type(vec![match window_type { + egui::X11WindowType::Normal => WindowType::Normal, + egui::X11WindowType::Utility => WindowType::Utility, + egui::X11WindowType::Dock => WindowType::Dock, + egui::X11WindowType::Desktop => WindowType::Desktop, + egui::X11WindowType::Toolbar => WindowType::Toolbar, + egui::X11WindowType::Menu => WindowType::Menu, + egui::X11WindowType::Splash => WindowType::Splash, + egui::X11WindowType::Dialog => WindowType::Dialog, + egui::X11WindowType::DropdownMenu => WindowType::DropdownMenu, + egui::X11WindowType::PopupMenu => WindowType::PopupMenu, + egui::X11WindowType::Tooltip => WindowType::Tooltip, + egui::X11WindowType::Notification => WindowType::Notification, + egui::X11WindowType::Combo => WindowType::Combo, + egui::X11WindowType::Dnd => WindowType::Dnd, }]); } } #[cfg(target_os = "windows")] { - use winit::platform::windows::WindowBuilderExtWindows as _; + use winit::platform::windows::WindowAttributesExtWindows as _; if let Some(enable) = _drag_and_drop { - window_builder = window_builder.with_drag_and_drop(enable); + window_attributes = window_attributes.with_drag_and_drop(enable); } if let Some(show) = _taskbar { - window_builder = window_builder.with_skip_taskbar(!show); + window_attributes = window_attributes.with_skip_taskbar(!show); } } #[cfg(target_os = "macos")] { - use winit::platform::macos::WindowBuilderExtMacOS as _; - window_builder = window_builder + use winit::platform::macos::WindowAttributesExtMacOS as _; + window_attributes = window_attributes .with_title_hidden(!_title_shown.unwrap_or(true)) .with_titlebar_buttons_hidden(!_titlebar_buttons_shown.unwrap_or(true)) .with_titlebar_transparent(!_titlebar_shown.unwrap_or(true)) .with_fullsize_content_view(_fullsize_content_view.unwrap_or(false)); } - window_builder + window_attributes } fn to_winit_icon(icon: &egui::IconData) -> Option { @@ -1774,38 +1771,23 @@ pub fn apply_viewport_builder_to_window( // --------------------------------------------------------------------------- -/// Short and fast description of an event. +/// Short and fast description of a device event. /// Useful for logging and profiling. -pub fn short_generic_event_description(event: &winit::event::Event) -> &'static str { - use winit::event::{DeviceEvent, Event, StartCause}; +pub fn short_device_event_description(event: &winit::event::DeviceEvent) -> &'static str { + use winit::event::DeviceEvent; match event { - Event::AboutToWait => "Event::AboutToWait", - Event::LoopExiting => "Event::LoopExiting", - Event::Suspended => "Event::Suspended", - Event::Resumed => "Event::Resumed", - Event::MemoryWarning => "Event::MemoryWarning", - Event::UserEvent(_) => "UserEvent", - Event::DeviceEvent { event, .. } => match event { - DeviceEvent::Added { .. } => "DeviceEvent::Added", - DeviceEvent::Removed { .. } => "DeviceEvent::Removed", - DeviceEvent::MouseMotion { .. } => "DeviceEvent::MouseMotion", - DeviceEvent::MouseWheel { .. } => "DeviceEvent::MouseWheel", - DeviceEvent::Motion { .. } => "DeviceEvent::Motion", - DeviceEvent::Button { .. } => "DeviceEvent::Button", - DeviceEvent::Key { .. } => "DeviceEvent::Key", - }, - Event::NewEvents(start_cause) => match start_cause { - StartCause::ResumeTimeReached { .. } => "NewEvents::ResumeTimeReached", - StartCause::WaitCancelled { .. } => "NewEvents::WaitCancelled", - StartCause::Poll => "NewEvents::Poll", - StartCause::Init => "NewEvents::Init", - }, - Event::WindowEvent { event, .. } => short_window_event_description(event), + DeviceEvent::Added { .. } => "DeviceEvent::Added", + DeviceEvent::Removed { .. } => "DeviceEvent::Removed", + DeviceEvent::MouseMotion { .. } => "DeviceEvent::MouseMotion", + DeviceEvent::MouseWheel { .. } => "DeviceEvent::MouseWheel", + DeviceEvent::Motion { .. } => "DeviceEvent::Motion", + DeviceEvent::Button { .. } => "DeviceEvent::Button", + DeviceEvent::Key { .. } => "DeviceEvent::Key", } } -/// Short and fast description of an event. +/// Short and fast description of a window event. /// Useful for logging and profiling. pub fn short_window_event_description(event: &winit::event::WindowEvent) -> &'static str { use winit::event::WindowEvent; @@ -1828,16 +1810,17 @@ pub fn short_window_event_description(event: &winit::event::WindowEvent) -> &'st WindowEvent::CursorLeft { .. } => "WindowEvent::CursorLeft", WindowEvent::MouseWheel { .. } => "WindowEvent::MouseWheel", WindowEvent::MouseInput { .. } => "WindowEvent::MouseInput", - WindowEvent::TouchpadMagnify { .. } => "WindowEvent::TouchpadMagnify", + WindowEvent::PinchGesture { .. } => "WindowEvent::PinchGesture", WindowEvent::RedrawRequested { .. } => "WindowEvent::RedrawRequested", - WindowEvent::SmartMagnify { .. } => "WindowEvent::SmartMagnify", - WindowEvent::TouchpadRotate { .. } => "WindowEvent::TouchpadRotate", + WindowEvent::DoubleTapGesture { .. } => "WindowEvent::DoubleTapGesture", + WindowEvent::RotationGesture { .. } => "WindowEvent::RotationGesture", WindowEvent::TouchpadPressure { .. } => "WindowEvent::TouchpadPressure", WindowEvent::AxisMotion { .. } => "WindowEvent::AxisMotion", WindowEvent::Touch { .. } => "WindowEvent::Touch", WindowEvent::ScaleFactorChanged { .. } => "WindowEvent::ScaleFactorChanged", WindowEvent::ThemeChanged { .. } => "WindowEvent::ThemeChanged", WindowEvent::Occluded { .. } => "WindowEvent::Occluded", + WindowEvent::PanGesture { .. } => "WindowEvent::PanGesture", } } diff --git a/crates/egui-winit/src/window_settings.rs b/crates/egui-winit/src/window_settings.rs index ec633d3df0a..627d88158c0 100644 --- a/crates/egui-winit/src/window_settings.rs +++ b/crates/egui-winit/src/window_settings.rs @@ -50,10 +50,10 @@ impl WindowSettings { self.inner_size_points } - pub fn initialize_viewport_builder( + pub fn initialize_viewport_builder( &self, egui_zoom_factor: f32, - event_loop: &winit::event_loop::EventLoopWindowTarget, + event_loop: &winit::event_loop::ActiveEventLoop, mut viewport_builder: ViewportBuilder, ) -> ViewportBuilder { crate::profile_function!(); @@ -110,10 +110,10 @@ impl WindowSettings { } } - pub fn clamp_position_to_monitors( + pub fn clamp_position_to_monitors( &mut self, egui_zoom_factor: f32, - event_loop: &winit::event_loop::EventLoopWindowTarget, + event_loop: &winit::event_loop::ActiveEventLoop, ) { // If the app last ran on two monitors and only one is now connected, then // the given position is invalid. @@ -137,9 +137,9 @@ impl WindowSettings { } } -fn find_active_monitor( +fn find_active_monitor( egui_zoom_factor: f32, - event_loop: &winit::event_loop::EventLoopWindowTarget, + event_loop: &winit::event_loop::ActiveEventLoop, window_size_pts: egui::Vec2, position_px: &egui::Pos2, ) -> Option { @@ -172,9 +172,9 @@ fn find_active_monitor( Some(active_monitor) } -fn clamp_pos_to_monitors( +fn clamp_pos_to_monitors( egui_zoom_factor: f32, - event_loop: &winit::event_loop::EventLoopWindowTarget, + event_loop: &winit::event_loop::ActiveEventLoop, window_size_pts: egui::Vec2, position_px: &mut egui::Pos2, ) { diff --git a/crates/egui/Cargo.toml b/crates/egui/Cargo.toml index 2e8e1ddd557..a920df2bf46 100644 --- a/crates/egui/Cargo.toml +++ b/crates/egui/Cargo.toml @@ -86,7 +86,7 @@ ahash.workspace = true nohash-hasher.workspace = true #! ### Optional dependencies -accesskit = { version = "0.12", optional = true } +accesskit = { version = "0.16", optional = true } backtrace = { workspace = true, optional = true } diff --git a/crates/egui/src/context.rs b/crates/egui/src/context.rs index 5ddadf78321..cbb137df77f 100644 --- a/crates/egui/src/context.rs +++ b/crates/egui/src/context.rs @@ -396,8 +396,6 @@ struct ContextImpl { #[cfg(feature = "accesskit")] is_accesskit_enabled: bool, - #[cfg(feature = "accesskit")] - accesskit_node_classes: accesskit::NodeClassSet, loaders: Arc, } @@ -2016,12 +2014,7 @@ impl ContextImpl { state .node_builders .into_iter() - .map(|(id, builder)| { - ( - id.accesskit_id(), - builder.build(&mut self.accesskit_node_classes), - ) - }) + .map(|(id, builder)| (id.accesskit_id(), builder.build())) .collect() }; let focus_id = self @@ -2909,37 +2902,15 @@ impl Context { } /// Enable generation of AccessKit tree updates in all future frames. - /// - /// If it's practical for the egui integration to immediately run the egui - /// application when it is either initializing the AccessKit adapter or - /// being called by the AccessKit adapter to provide the initial tree update, - /// then it should do so, to provide a complete AccessKit tree to the adapter - /// immediately. Otherwise, it should enqueue a repaint and use the - /// placeholder tree update from [`Context::accesskit_placeholder_tree_update`] - /// in the meantime. #[cfg(feature = "accesskit")] pub fn enable_accesskit(&self) { self.write(|ctx| ctx.is_accesskit_enabled = true); } - /// Return a tree update that the egui integration should provide to the - /// AccessKit adapter if it cannot immediately run the egui application - /// to get a full tree update after running [`Context::enable_accesskit`]. + /// Disable generation of AccessKit tree updates in all future frames. #[cfg(feature = "accesskit")] - pub fn accesskit_placeholder_tree_update(&self) -> accesskit::TreeUpdate { - crate::profile_function!(); - - use accesskit::{NodeBuilder, Role, Tree, TreeUpdate}; - - let root_id = crate::accesskit_root_id().accesskit_id(); - self.write(|ctx| TreeUpdate { - nodes: vec![( - root_id, - NodeBuilder::new(Role::Window).build(&mut ctx.accesskit_node_classes), - )], - tree: Some(Tree::new(root_id)), - focus: root_id, - }) + pub fn disable_accesskit(&self) { + self.write(|ctx| ctx.is_accesskit_enabled = false); } } diff --git a/crates/egui/src/response.rs b/crates/egui/src/response.rs index 143175ba2ee..cb2ef5467f1 100644 --- a/crates/egui/src/response.rs +++ b/crates/egui/src/response.rs @@ -964,11 +964,11 @@ impl Response { info: crate::WidgetInfo, ) { use crate::WidgetType; - use accesskit::{Checked, Role}; + use accesskit::{Role, Toggled}; self.fill_accesskit_node_common(builder); builder.set_role(match info.typ { - WidgetType::Label => Role::StaticText, + WidgetType::Label => Role::Label, WidgetType::Link => Role::Link, WidgetType::TextEdit => Role::TextInput, WidgetType::Button | WidgetType::ImageButton | WidgetType::CollapsingHeader => { @@ -976,7 +976,7 @@ impl Response { } WidgetType::Checkbox => Role::CheckBox, WidgetType::RadioButton => Role::RadioButton, - WidgetType::SelectableLabel => Role::ToggleButton, + WidgetType::SelectableLabel => Role::Button, WidgetType::ComboBox => Role::ComboBox, WidgetType::Slider => Role::Slider, WidgetType::DragValue => Role::SpinButton, @@ -997,14 +997,14 @@ impl Response { builder.set_numeric_value(value); } if let Some(selected) = info.selected { - builder.set_checked(if selected { - Checked::True + builder.set_toggled(if selected { + Toggled::True } else { - Checked::False + Toggled::False }); } else if matches!(info.typ, WidgetType::Checkbox) { // Indeterminate state - builder.set_checked(Checked::Mixed); + builder.set_toggled(Toggled::Mixed); } } diff --git a/crates/egui/src/text_selection/label_text_selection.rs b/crates/egui/src/text_selection/label_text_selection.rs index 7988820d6af..f0660de0459 100644 --- a/crates/egui/src/text_selection/label_text_selection.rs +++ b/crates/egui/src/text_selection/label_text_selection.rs @@ -38,7 +38,7 @@ fn paint_selection( ui.ctx(), _response.id, cursor_range, - accesskit::Role::StaticText, + accesskit::Role::Label, galley_pos, galley, ); diff --git a/crates/egui/tests/accesskit.rs b/crates/egui/tests/accesskit.rs index e3d1c7b56ab..e5dc3d97a93 100644 --- a/crates/egui/tests/accesskit.rs +++ b/crates/egui/tests/accesskit.rs @@ -94,7 +94,7 @@ fn toggle_button_node() { let (_, toggle) = output .nodes .iter() - .find(|(_, node)| node.role() == Role::ToggleButton) + .find(|(_, node)| node.role() == Role::Button) .expect("Toggle button should exist in the accesskit output"); assert_eq!(toggle.name(), Some(button_text)); diff --git a/crates/egui_glow/Cargo.toml b/crates/egui_glow/Cargo.toml index 28de667e8c1..615247fb07e 100644 --- a/crates/egui_glow/Cargo.toml +++ b/crates/egui_glow/Cargo.toml @@ -69,9 +69,7 @@ document-features = { workspace = true, optional = true } # Native: [target.'cfg(not(target_arch = "wasm32"))'.dependencies] puffin = { workspace = true, optional = true } -winit = { workspace = true, optional = true, default-features = false, features = [ - "rwh_06", # for compatibility with egui-winit -] } +winit = { workspace = true, optional = true, default-features = false } # Web: [target.'cfg(target_arch = "wasm32")'.dependencies] @@ -82,15 +80,7 @@ wasm-bindgen.workspace = true [dev-dependencies] glutin.workspace = true # examples/pure_glow glutin-winit.workspace = true -# glutin stuck on old version of raw-window-handle: -rwh_05 = { package = "raw-window-handle", version = "0.5.2", features = [ - "std", -] } [[example]] name = "pure_glow" -required-features = [ - "winit", - "egui/default_fonts", - "winit/rwh_05", # glutin stuck on old version of raw-window-handle -] +required-features = ["winit", "egui/default_fonts"] diff --git a/crates/egui_glow/examples/pure_glow.rs b/crates/egui_glow/examples/pure_glow.rs index 0066b2ea815..4145e1d6310 100644 --- a/crates/egui_glow/examples/pure_glow.rs +++ b/crates/egui_glow/examples/pure_glow.rs @@ -8,8 +8,10 @@ #![allow(unsafe_code)] use std::num::NonZeroU32; +use std::sync::Arc; use egui_winit::winit; +use winit::raw_window_handle::HasWindowHandle; /// The majority of `GlutinWindowContext` is taken from `eframe` struct GlutinWindowContext { @@ -23,13 +25,12 @@ impl GlutinWindowContext { // refactor this function to use `glutin-winit` crate eventually. // preferably add android support at the same time. #[allow(unsafe_code)] - unsafe fn new(event_loop: &winit::event_loop::EventLoopWindowTarget) -> Self { + unsafe fn new(event_loop: &winit::event_loop::ActiveEventLoop) -> Self { use glutin::context::NotCurrentGlContext; use glutin::display::GetGlDisplay; use glutin::display::GlDisplay; use glutin::prelude::GlSurface; - use rwh_05::HasRawWindowHandle; - let winit_window_builder = winit::window::WindowBuilder::new() + let winit_window_builder = winit::window::WindowAttributes::default() .with_resizable(true) .with_inner_size(winit::dpi::LogicalSize { width: 800.0, @@ -48,7 +49,7 @@ impl GlutinWindowContext { let (mut window, gl_config) = glutin_winit::DisplayBuilder::new() // let glutin-winit helper crate handle the complex parts of opengl context creation .with_preference(glutin_winit::ApiPreference::FallbackEgl) // https://github.com/emilk/egui/issues/2520#issuecomment-1367841150 - .with_window_builder(Some(winit_window_builder.clone())) + .with_window_attributes(Some(winit_window_builder.clone())) .build( event_loop, config_template_builder, @@ -62,7 +63,11 @@ impl GlutinWindowContext { let gl_display = gl_config.display(); log::debug!("found gl_config: {:?}", &gl_config); - let raw_window_handle = window.as_ref().map(|w| w.raw_window_handle()); + let raw_window_handle = window.as_ref().map(|w| { + w.window_handle() + .expect("failed to get window handle") + .as_raw() + }); log::debug!("raw window handle: {:?}", raw_window_handle); let context_attributes = glutin::context::ContextAttributesBuilder::new().build(raw_window_handle); @@ -95,7 +100,14 @@ impl GlutinWindowContext { let height = NonZeroU32::new(height).unwrap_or(NonZeroU32::MIN); let surface_attributes = glutin::surface::SurfaceAttributesBuilder::::new() - .build(window.raw_window_handle(), width, height); + .build( + window + .window_handle() + .expect("failed to get window handle") + .as_raw(), + width, + height, + ); log::debug!( "creating surface with attributes: {:?}", &surface_attributes @@ -152,51 +164,81 @@ pub enum UserEvent { Redraw(std::time::Duration), } -fn main() { - let mut clear_color = [0.1, 0.1, 0.1]; +struct GlowApp { + proxy: winit::event_loop::EventLoopProxy, + gl_window: Option, + gl: Option>, + egui_glow: Option, + repaint_delay: std::time::Duration, + clear_color: [f32; 3], +} - let event_loop = winit::event_loop::EventLoopBuilder::::with_user_event() - .build() - .unwrap(); - let (gl_window, gl) = create_display(&event_loop); - let gl = std::sync::Arc::new(gl); - - let mut egui_glow = egui_glow::EguiGlow::new(&event_loop, gl.clone(), None, None, true); - - let event_loop_proxy = egui::mutex::Mutex::new(event_loop.create_proxy()); - egui_glow - .egui_ctx - .set_request_repaint_callback(move |info| { - event_loop_proxy - .lock() - .send_event(UserEvent::Redraw(info.delay)) - .expect("Cannot send event"); - }); +impl GlowApp { + fn new(proxy: winit::event_loop::EventLoopProxy) -> Self { + Self { + proxy, + gl_window: None, + gl: None, + egui_glow: None, + repaint_delay: std::time::Duration::MAX, + clear_color: [0.1, 0.1, 0.1], + } + } +} - let mut repaint_delay = std::time::Duration::MAX; +impl winit::application::ApplicationHandler for GlowApp { + fn resumed(&mut self, event_loop: &winit::event_loop::ActiveEventLoop) { + let (gl_window, gl) = create_display(event_loop); + let gl = std::sync::Arc::new(gl); + gl_window.window().set_visible(true); + + let egui_glow = egui_glow::EguiGlow::new(event_loop, gl.clone(), None, None, true); + + let event_loop_proxy = egui::mutex::Mutex::new(self.proxy.clone()); + egui_glow + .egui_ctx + .set_request_repaint_callback(move |info| { + event_loop_proxy + .lock() + .send_event(UserEvent::Redraw(info.delay)) + .expect("Cannot send event"); + }); + self.gl_window = Some(gl_window); + self.gl = Some(gl); + self.egui_glow = Some(egui_glow); + } - let _ = event_loop.run(move |event, event_loop_window_target| { + fn window_event( + &mut self, + event_loop: &winit::event_loop::ActiveEventLoop, + _window_id: winit::window::WindowId, + event: winit::event::WindowEvent, + ) { let mut redraw = || { let mut quit = false; - egui_glow.run(gl_window.window(), |egui_ctx| { - egui::SidePanel::left("my_side_panel").show(egui_ctx, |ui| { - ui.heading("Hello World!"); - if ui.button("Quit").clicked() { - quit = true; - } - ui.color_edit_button_rgb(&mut clear_color); - }); - }); + self.egui_glow.as_mut().unwrap().run( + self.gl_window.as_mut().unwrap().window(), + |egui_ctx| { + egui::SidePanel::left("my_side_panel").show(egui_ctx, |ui| { + ui.heading("Hello World!"); + if ui.button("Quit").clicked() { + quit = true; + } + + ui.color_edit_button_rgb(self.clear_color.as_mut().try_into().unwrap()); + }); + }, + ); if quit { - event_loop_window_target.exit(); + event_loop.exit(); } else { - event_loop_window_target.set_control_flow(if repaint_delay.is_zero() { - gl_window.window().request_redraw(); + event_loop.set_control_flow(if self.repaint_delay.is_zero() { + self.gl_window.as_mut().unwrap().window().request_redraw(); winit::event_loop::ControlFlow::Poll } else if let Some(repaint_after_instant) = - std::time::Instant::now().checked_add(repaint_delay) + std::time::Instant::now().checked_add(self.repaint_delay) { winit::event_loop::ControlFlow::WaitUntil(repaint_after_instant) } else { @@ -207,64 +249,88 @@ fn main() { { unsafe { use glow::HasContext as _; - gl.clear_color(clear_color[0], clear_color[1], clear_color[2], 1.0); - gl.clear(glow::COLOR_BUFFER_BIT); + self.gl.as_mut().unwrap().clear_color( + self.clear_color[0], + self.clear_color[1], + self.clear_color[2], + 1.0, + ); + self.gl.as_mut().unwrap().clear(glow::COLOR_BUFFER_BIT); } // draw things behind egui here - egui_glow.paint(gl_window.window()); + self.egui_glow + .as_mut() + .unwrap() + .paint(self.gl_window.as_mut().unwrap().window()); // draw things on top of egui here - gl_window.swap_buffers().unwrap(); - gl_window.window().set_visible(true); + self.gl_window.as_mut().unwrap().swap_buffers().unwrap(); + self.gl_window.as_mut().unwrap().window().set_visible(true); } }; - match event { - winit::event::Event::WindowEvent { event, .. } => { - use winit::event::WindowEvent; - if matches!(event, WindowEvent::CloseRequested | WindowEvent::Destroyed) { - event_loop_window_target.exit(); - return; - } + use winit::event::WindowEvent; + if matches!(event, WindowEvent::CloseRequested | WindowEvent::Destroyed) { + event_loop.exit(); + return; + } - if matches!(event, WindowEvent::RedrawRequested) { - redraw(); - return; - } + if matches!(event, WindowEvent::RedrawRequested) { + redraw(); + return; + } - if let winit::event::WindowEvent::Resized(physical_size) = &event { - gl_window.resize(*physical_size); - } + if let winit::event::WindowEvent::Resized(physical_size) = &event { + self.gl_window.as_mut().unwrap().resize(*physical_size); + } - let event_response = egui_glow.on_window_event(gl_window.window(), &event); + let event_response = self + .egui_glow + .as_mut() + .unwrap() + .on_window_event(self.gl_window.as_mut().unwrap().window(), &event); - if event_response.repaint { - gl_window.window().request_redraw(); - } - } + if event_response.repaint { + self.gl_window.as_mut().unwrap().window().request_redraw(); + } + } - winit::event::Event::UserEvent(UserEvent::Redraw(delay)) => { - repaint_delay = delay; - } - winit::event::Event::LoopExiting => { - egui_glow.destroy(); - } - winit::event::Event::NewEvents(winit::event::StartCause::ResumeTimeReached { - .. - }) => { - gl_window.window().request_redraw(); - } + fn user_event(&mut self, _event_loop: &winit::event_loop::ActiveEventLoop, event: UserEvent) { + match event { + UserEvent::Redraw(delay) => self.repaint_delay = delay, + } + } - _ => (), + fn new_events( + &mut self, + _event_loop: &winit::event_loop::ActiveEventLoop, + cause: winit::event::StartCause, + ) { + if let winit::event::StartCause::ResumeTimeReached { .. } = &cause { + self.gl_window.as_mut().unwrap().window().request_redraw(); } - }); + } + + fn exiting(&mut self, _event_loop: &winit::event_loop::ActiveEventLoop) { + self.egui_glow.as_mut().unwrap().destroy(); + } +} + +fn main() { + let event_loop = winit::event_loop::EventLoop::::with_user_event() + .build() + .unwrap(); + let proxy = event_loop.create_proxy(); + + let mut app = GlowApp::new(proxy); + event_loop.run_app(&mut app).expect("failed to run app"); } fn create_display( - event_loop: &winit::event_loop::EventLoopWindowTarget, + event_loop: &winit::event_loop::ActiveEventLoop, ) -> (GlutinWindowContext, glow::Context) { let glutin_window_context = unsafe { GlutinWindowContext::new(event_loop) }; let gl = unsafe { diff --git a/crates/egui_glow/src/winit.rs b/crates/egui_glow/src/winit.rs index c3bcfe386b5..0f1d96d08a4 100644 --- a/crates/egui_glow/src/winit.rs +++ b/crates/egui_glow/src/winit.rs @@ -22,8 +22,8 @@ pub struct EguiGlow { impl EguiGlow { /// For automatic shader version detection set `shader_version` to `None`. - pub fn new( - event_loop: &winit::event_loop::EventLoopWindowTarget, + pub fn new( + event_loop: &winit::event_loop::ActiveEventLoop, gl: std::sync::Arc, shader_version: Option, native_pixels_per_point: Option, diff --git a/deny.toml b/deny.toml index 9c8704bcd2d..5b3c546528d 100644 --- a/deny.toml +++ b/deny.toml @@ -49,16 +49,16 @@ skip = [ { name = "bit-set" }, # wgpu's naga depends on 0.6, syntect's (used by egui_extras) fancy-regex depends on 0.5 { name = "bit-vec" }, # dependency of bit-set in turn, different between 0.6 and 0.5 { name = "bitflags" }, # old 1.0 version via glutin, png, spirv, … - { name = "block2" }, # old version via glutin->icrate + { name = "cfg_aliases" }, # old version via wgpu { name = "event-listener" }, # TODO(emilk): rustls pulls in two versions of this 😭 - { name = "glutin_wgl_sys" }, # 0.6.0 used by wgpu-hal, 0.5.0 used by glutin which can't be updated until we update to winit 0.30 + { name = "futures-lite" }, # old version via accesskit_unix and zbus { name = "memoffset" }, # tiny dependency + { name = "ndk-sys" }, # old version via wgpu, winit uses newer version { name = "quick-xml" }, # old version via wayland-scanner { name = "redox_syscall" }, # old version via winit { name = "time" }, # old version pulled in by unmaintianed crate 'chrono' + { name = "windows-core" }, # old version via accesskit_windows { name = "windows" }, # old version via accesskit_windows - { name = "x11rb-protocol" }, # old version via arboard - { name = "x11rb" }, # old version via arboard ] skip-tree = [ { name = "criterion" }, # dev-dependency diff --git a/examples/serial_windows/src/main.rs b/examples/serial_windows/src/main.rs index 133155bd131..f82881e84fe 100644 --- a/examples/serial_windows/src/main.rs +++ b/examples/serial_windows/src/main.rs @@ -6,13 +6,6 @@ use eframe::egui; fn main() -> eframe::Result { env_logger::init(); // Log to stderr (if you run with `RUST_LOG=debug`). - if cfg!(target_os = "macos") { - eprintln!( - "This example does not work on Mac! See https://github.com/emilk/egui/issues/1918" - ); - return Ok(()); - } - let options = eframe::NativeOptions { run_and_return: true, viewport: egui::ViewportBuilder::default().with_inner_size([320.0, 240.0]), @@ -59,10 +52,6 @@ impl eframe::App for MyApp { }; ui.label(label_text); - if ctx.os() == egui::os::OperatingSystem::Mac { - ui.label("This example doesn't work on Mac!"); - } - if ui.button("Close").clicked() { eprintln!("Pressed Close button"); ui.ctx().send_viewport_cmd(egui::ViewportCommand::Close);