From 9f71253300ddcc55cee036c7663162bc65dbbc28 Mon Sep 17 00:00:00 2001 From: fredizzimo Date: Fri, 19 Jul 2024 13:04:13 +0300 Subject: [PATCH 1/2] chore: Update to winit 0.30.3 (#2698) * Update to Winit 0.30.3 Also Glutin 0.32, Glutin-winit 0.5.0 and raw-window-handle 0.6.0. * Working Linux build * Convert the main update loop to use Winit ApplicationHandler * Conver the error window to Winit ApplicationHandler * Fix macOS build * Fix Windows build * Update dependencies --- Cargo.lock | 367 ++++++++++++++++++----- Cargo.toml | 9 +- src/clipboard.rs | 44 +-- src/main.rs | 7 +- src/renderer/cursor_renderer/mod.rs | 15 +- src/renderer/mod.rs | 22 +- src/renderer/opengl.rs | 16 +- src/renderer/vsync/macos_display_link.rs | 12 +- src/window/error_window.rs | 58 ++-- src/window/macos.rs | 29 +- src/window/mod.rs | 111 ++----- src/window/update_loop.rs | 213 ++++++++----- src/window/window_wrapper.rs | 102 +++---- 13 files changed, 613 insertions(+), 392 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ab9d3a7f9b..660a920b07 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -63,9 +63,9 @@ checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f" [[package]] name = "android-activity" -version = "0.5.2" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee91c0c2905bae44f84bfa4e044536541df26b7703fd0888deeb9060fcc44289" +checksum = "ef6978589202a00cd7e118380c448a08b6ed394c3a8df3a430d0898e3a42d046" dependencies = [ "android-properties", "bitflags 2.6.0", @@ -283,7 +283,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "15b55663a85f33501257357e6421bb33e769d5c9ffb5ba0921c975a123e35e68" dependencies = [ "block-sys", - "objc2", + "objc2 0.4.1", +] + +[[package]] +name = "block2" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c132eebf10f5cad5289222520a4a058514204aed6d791f1cf4fe8088b82d15f" +dependencies = [ + "objc2 0.5.2", ] [[package]] @@ -362,13 +371,12 @@ dependencies = [ [[package]] name = "cc" -version = "1.1.3" +version = "1.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18e2d530f35b40a84124146478cd16f34225306a8441998836466a2e2961c950" +checksum = "324c74f2155653c90b04f25b2a47a8a631360cb908f92a772695f430c7e31052" dependencies = [ "jobserver", "libc", - "once_cell", ] [[package]] @@ -394,9 +402,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "cfg_aliases" -version = "0.1.1" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e" +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" [[package]] name = "cgl" @@ -672,6 +680,15 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2" +[[package]] +name = "dpi" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f25c0e292a7ca6d6498557ff1df68f32c99850012b6ea401cf8daf771f22ff53" +dependencies = [ + "serde", +] + [[package]] name = "either" version = "1.13.0" @@ -978,9 +995,9 @@ checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" [[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", @@ -990,43 +1007,44 @@ dependencies = [ "glutin_egl_sys", "glutin_glx_sys", "glutin_wgl_sys", - "icrate", "libloading", - "objc2", + "objc2 0.5.2", + "objc2-app-kit", + "objc2-foundation", "once_cell", - "raw-window-handle 0.5.2", + "raw-window-handle", "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", "glutin", - "raw-window-handle 0.5.2", + "raw-window-handle", "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", @@ -1034,9 +1052,9 @@ dependencies = [ [[package]] name = "glutin_wgl_sys" -version = "0.5.0" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c8098adac955faa2d31079b65dc48841251f69efd3ac25477903fc424362ead" +checksum = "0a4e1951bbd9434a81aa496fe59ccc2235af3820d27b85f9314e279609211e2c" dependencies = [ "gl_generator", ] @@ -1107,9 +1125,8 @@ version = "0.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "99d3aaff8a54577104bafdf686ff18565c3b6903ca5782a2026ef06e2c7aa319" dependencies = [ - "block2", - "dispatch", - "objc2", + "block2 0.3.0", + "objc2 0.4.1", ] [[package]] @@ -1405,17 +1422,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", "num_enum", - "raw-window-handle 0.5.2", - "raw-window-handle 0.6.2", + "raw-window-handle", "thiserror", ] @@ -1427,9 +1443,9 @@ checksum = "27b02d87554356db9e9a873add8782d4ea6e3e58ea071a9adb9a2e8ddb884a8b" [[package]] name = "ndk-sys" -version = "0.5.0+25.2.9519653" +version = "0.6.0+11769913" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c196769dd60fd4f363e11d948139556a344e79d451aeb2fa2fd040738ef7691" +checksum = "ee6cda3051665f1fb8d9e08fc35c96d5a244fb1be711a03b71118828afc9a873" dependencies = [ "jni-sys", ] @@ -1464,10 +1480,10 @@ dependencies = [ "notify-debouncer-full", "num", "nvim-rs", - "objc2", + "objc2 0.4.1", "parking_lot", "rand 0.8.5", - "raw-window-handle 0.5.2", + "raw-window-handle", "regex", "rmpv", "scoped-env", @@ -1706,7 +1722,93 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "559c5a40fdd30eb5e344fbceacf7595a81e242529fb4e21cf5f43fb4f11ff98d" dependencies = [ "objc-sys", - "objc2-encode", + "objc2-encode 3.0.0", +] + +[[package]] +name = "objc2" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46a785d4eeff09c14c487497c162e92766fbb3e4059a71840cecc03d9a50b804" +dependencies = [ + "objc-sys", + "objc2-encode 4.0.3", +] + +[[package]] +name = "objc2-app-kit" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4e89ad9e3d7d297152b17d39ed92cd50ca8063a89a9fa569046d41568891eff" +dependencies = [ + "bitflags 2.6.0", + "block2 0.5.1", + "libc", + "objc2 0.5.2", + "objc2-core-data", + "objc2-core-image", + "objc2-foundation", + "objc2-quartz-core", +] + +[[package]] +name = "objc2-cloud-kit" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74dd3b56391c7a0596a295029734d3c1c5e7e510a4cb30245f8221ccea96b009" +dependencies = [ + "bitflags 2.6.0", + "block2 0.5.1", + "objc2 0.5.2", + "objc2-core-location", + "objc2-foundation", +] + +[[package]] +name = "objc2-contacts" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5ff520e9c33812fd374d8deecef01d4a840e7b41862d849513de77e44aa4889" +dependencies = [ + "block2 0.5.1", + "objc2 0.5.2", + "objc2-foundation", +] + +[[package]] +name = "objc2-core-data" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "617fbf49e071c178c0b24c080767db52958f716d9eabdf0890523aeae54773ef" +dependencies = [ + "bitflags 2.6.0", + "block2 0.5.1", + "objc2 0.5.2", + "objc2-foundation", +] + +[[package]] +name = "objc2-core-image" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55260963a527c99f1819c4f8e3b47fe04f9650694ef348ffd2227e8196d34c80" +dependencies = [ + "block2 0.5.1", + "objc2 0.5.2", + "objc2-foundation", + "objc2-metal", +] + +[[package]] +name = "objc2-core-location" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "000cfee34e683244f284252ee206a27953279d370e309649dc3ee317b37e5781" +dependencies = [ + "block2 0.5.1", + "objc2 0.5.2", + "objc2-contacts", + "objc2-foundation", ] [[package]] @@ -1715,6 +1817,117 @@ version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d079845b37af429bfe5dfa76e6d087d788031045b25cfc6fd898486fd9847666" +[[package]] +name = "objc2-encode" +version = "4.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7891e71393cd1f227313c9379a26a584ff3d7e6e7159e988851f0934c993f0f8" + +[[package]] +name = "objc2-foundation" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ee638a5da3799329310ad4cfa62fbf045d5f56e3ef5ba4149e7452dcf89d5a8" +dependencies = [ + "bitflags 2.6.0", + "block2 0.5.1", + "dispatch", + "libc", + "objc2 0.5.2", +] + +[[package]] +name = "objc2-link-presentation" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1a1ae721c5e35be65f01a03b6d2ac13a54cb4fa70d8a5da293d7b0020261398" +dependencies = [ + "block2 0.5.1", + "objc2 0.5.2", + "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 0.5.1", + "objc2 0.5.2", + "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 0.5.1", + "objc2 0.5.2", + "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 0.5.2", + "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 0.5.1", + "objc2 0.5.2", + "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 0.5.1", + "objc2 0.5.2", + "objc2-foundation", +] + +[[package]] +name = "objc2-user-notifications" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76cfcbf642358e8689af64cee815d139339f3ed8ad05103ed5eaf73db8d84cb3" +dependencies = [ + "bitflags 2.6.0", + "block2 0.5.1", + "objc2 0.5.2", + "objc2-core-location", + "objc2-foundation", +] + [[package]] name = "objc_id" version = "0.1.1" @@ -1795,7 +2008,7 @@ checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" dependencies = [ "cfg-if", "libc", - "redox_syscall 0.5.2", + "redox_syscall 0.5.3", "smallvec", "windows-targets 0.52.6", ] @@ -1854,6 +2067,26 @@ dependencies = [ "siphasher", ] +[[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.71", +] + [[package]] name = "pin-project-lite" version = "0.2.14" @@ -2029,12 +2262,6 @@ dependencies = [ "rand_core 0.5.1", ] -[[package]] -name = "raw-window-handle" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2ff9a1f06a88b01621b7ae906ef0211290d1c8a168a15542486a8f61c0833b9" - [[package]] name = "raw-window-handle" version = "0.6.2" @@ -2051,15 +2278,6 @@ dependencies = [ "font-types", ] -[[package]] -name = "redox_syscall" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" -dependencies = [ - "bitflags 1.3.2", -] - [[package]] name = "redox_syscall" version = "0.4.1" @@ -2071,9 +2289,9 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.5.2" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c82cf8cff14456045f55ec4241383baeff27af886adb72ffb2162f99911de0fd" +checksum = "2a908a6e00f1fdd0dfd9c0eb08ce85126f6d8bbda50017e74bc4a4b7d4a926a4" dependencies = [ "bitflags 2.6.0", ] @@ -2187,9 +2405,9 @@ dependencies = [ [[package]] name = "scc" -version = "2.1.2" +version = "2.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af947d0ca10a2f3e00c7ec1b515b7c83e5cb3fa62d4c11a64301d9eec54440e9" +checksum = "a4465c22496331e20eb047ff46e7366455bc01c0c02015c4a376de0b2cd3a1af" dependencies = [ "sdd", ] @@ -2214,9 +2432,9 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "sctk-adwaita" -version = "0.8.3" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70b31447ca297092c5a9916fc3b955203157b37c19ca8edde4f52e9843e602c7" +checksum = "7555fcb4f753d095d734fdefebb0ad8c98478a21db500492d87c55913d3b0086" dependencies = [ "ab_glyph", "log", @@ -2227,9 +2445,9 @@ dependencies = [ [[package]] name = "sdd" -version = "0.2.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b84345e4c9bd703274a082fb80caaa99b7612be48dfaa1dd9266577ec412309d" +checksum = "1e806d6633ef141556fef75e345275e35652e9c045bbbc21e6ecfce3e9aa2638" [[package]] name = "serde" @@ -2972,9 +3190,9 @@ dependencies = [ [[package]] name = "web-time" -version = "0.2.4" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa30049b1c872b72c89866d458eae9f20380ab280ffd1b1e18df2d3e2d98cfe0" +checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" dependencies = [ "js-sys", "wasm-bindgen", @@ -3334,39 +3552,42 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "winit" -version = "0.29.15" +version = "0.30.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d59ad965a635657faf09c8f062badd885748428933dad8e8bdd64064d92e5ca" +checksum = "49f45a7b7e2de6af35448d7718dab6d95acec466eb3bb7a56f4d31d1af754004" dependencies = [ "ahash", "android-activity", "atomic-waker", "bitflags 2.6.0", + "block2 0.5.1", "bytemuck", "calloop", "cfg_aliases", + "concurrent-queue", "core-foundation", "core-graphics", "cursor-icon", - "icrate", + "dpi", "js-sys", "libc", - "log", "memmap2", "ndk", - "ndk-sys", - "objc2", - "once_cell", + "objc2 0.5.2", + "objc2-app-kit", + "objc2-foundation", + "objc2-ui-kit", "orbclient", "percent-encoding", - "raw-window-handle 0.5.2", - "raw-window-handle 0.6.2", - "redox_syscall 0.3.5", + "pin-project", + "raw-window-handle", + "redox_syscall 0.4.1", "rustix", "sctk-adwaita", "serde", "smithay-client-toolkit", "smol_str", + "tracing", "unicode-segmentation", "wasm-bindgen", "wasm-bindgen-futures", @@ -3376,7 +3597,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 4c27bf8a7d..90d87160a0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -40,8 +40,8 @@ glamour = { version = "0.11.1", features = ["serde"] } flexi_logger = { version = "0.28.0", default-features = false } futures = "0.3.21" gl = "0.14.0" -glutin = "0.31.1" -glutin-winit = "0.4.2" +glutin = "0.32.0" +glutin-winit = "0.5.0" image = { version = "0.25.0", default-features = false, features = ["ico"] } indoc = "2.0.5" itertools = "0.13.0" @@ -53,7 +53,7 @@ num = "0.4.1" nvim-rs = { version = "0.7.0", features = ["use_tokio"] } parking_lot = "0.12.0" rand = "0.8.5" -raw-window-handle = "0.5.0" +raw-window-handle = "0.6.0" rmpv = "1.0.0" serde = { version = "1.0.136", features = ["derive"] } serde_json = "1.0.79" @@ -74,7 +74,7 @@ tracy-client-sys = { version = "0.22.0", optional = true, default-features = fal ] } unicode-segmentation = "1.9.0" which = "6.0.1" -winit = { version = "=0.29.15", features = ["serde"] } +winit = { version = "=0.30.3", features = ["serde"] } xdg = "2.4.1" notify-debouncer-full = "0.3.1" regex = "1.10.3" @@ -110,6 +110,7 @@ icrate = { version = "0.0.4", features = [ "apple", "Foundation", "Foundation_NSThread", + "Foundation_NSProcessInfo", "AppKit", "AppKit_NSColor", "AppKit_NSEvent", diff --git a/src/clipboard.rs b/src/clipboard.rs index ce85b0cd1e..65f057b0da 100644 --- a/src/clipboard.rs +++ b/src/clipboard.rs @@ -8,7 +8,7 @@ use copypasta::{ }; use copypasta::{ClipboardContext, ClipboardProvider}; use parking_lot::Mutex; -use raw_window_handle::HasRawDisplayHandle; +use raw_window_handle::HasDisplayHandle; #[cfg(target_os = "linux")] use raw_window_handle::{RawDisplayHandle, WaylandDisplayHandle}; use winit::event_loop::EventLoop; @@ -27,26 +27,30 @@ static CLIPBOARD: OnceLock> = OnceLock::new(); pub fn init(event_loop: &EventLoop) { CLIPBOARD - .set(Mutex::new(match event_loop.raw_display_handle() { - #[cfg(target_os = "linux")] - RawDisplayHandle::Wayland(WaylandDisplayHandle { display, .. }) => unsafe { - let (selection, clipboard) = - wayland_clipboard::create_clipboards_from_external(display); - Clipboard { - clipboard: Box::new(clipboard), - selection: Box::new(selection), - } + .set(Mutex::new( + match event_loop.display_handle().unwrap().as_raw() { + #[cfg(target_os = "linux")] + RawDisplayHandle::Wayland(WaylandDisplayHandle { mut display, .. }) => unsafe { + let (selection, clipboard) = + wayland_clipboard::create_clipboards_from_external(display.as_mut()); + Clipboard { + clipboard: Box::new(clipboard), + selection: Box::new(selection), + } + }, + #[cfg(target_os = "linux")] + _ => Clipboard { + clipboard: Box::new(ClipboardContext::new().unwrap()), + selection: Box::new( + X11ClipboardContext::::new().unwrap(), + ), + }, + #[cfg(not(target_os = "linux"))] + _ => Clipboard { + clipboard: Box::new(ClipboardContext::new().unwrap()), + }, }, - #[cfg(target_os = "linux")] - _ => Clipboard { - clipboard: Box::new(ClipboardContext::new().unwrap()), - selection: Box::new(X11ClipboardContext::::new().unwrap()), - }, - #[cfg(not(target_os = "linux"))] - _ => Clipboard { - clipboard: Box::new(ClipboardContext::new().unwrap()), - }, - })) + )) .ok(); } diff --git a/src/main.rs b/src/main.rs index ffc02eb772..60a184c097 100644 --- a/src/main.rs +++ b/src/main.rs @@ -60,7 +60,7 @@ use renderer::{cursor_renderer::CursorSettings, RendererSettings}; #[cfg_attr(target_os = "windows", allow(unused_imports))] use settings::SETTINGS; use window::{ - create_event_loop, determine_window_size, main_loop, UserEvent, WindowSettings, WindowSize, + create_event_loop, determine_window_size, UpdateLoop, UserEvent, WindowSettings, WindowSize, }; pub use channel_utils::*; @@ -100,7 +100,10 @@ fn main() -> NeovideExitCode { match setup(event_loop.create_proxy()) { Err(err) => handle_startup_errors(err, event_loop).into(), Ok((window_size, font_settings, _runtime)) => { - main_loop(window_size, font_settings, event_loop).into() + let mut update_loop = + UpdateLoop::new(window_size, font_settings, event_loop.create_proxy()); + + event_loop.run_app(&mut update_loop).into() } } } diff --git a/src/renderer/cursor_renderer/mod.rs b/src/renderer/cursor_renderer/mod.rs index 30a89df21f..63fb67ef32 100644 --- a/src/renderer/cursor_renderer/mod.rs +++ b/src/renderer/cursor_renderer/mod.rs @@ -4,7 +4,7 @@ mod cursor_vfx; use std::collections::HashMap; use skia_safe::{op, Canvas, Paint, Path}; -use winit::event::{Event, WindowEvent}; +use winit::event::WindowEvent; use crate::{ bridge::EditorMode, @@ -13,7 +13,7 @@ use crate::{ renderer::{animation_utils::*, GridRenderer, RenderedWindow}, settings::{ParseFromValue, SETTINGS}, units::{to_skia_point, GridPos, GridScale, PixelPos, PixelSize, PixelVec}, - window::{ShouldRender, UserEvent}, + window::ShouldRender, }; use blink::*; @@ -192,16 +192,9 @@ impl CursorRenderer { renderer } - pub fn handle_event(&mut self, event: &Event) -> bool { - if let Event::WindowEvent { - event: WindowEvent::Focused(is_focused), - .. - } = event - { + pub fn handle_event(&mut self, event: &WindowEvent) { + if let WindowEvent::Focused(is_focused) = event { self.window_has_focus = *is_focused; - true - } else { - false } } diff --git a/src/renderer/mod.rs b/src/renderer/mod.rs index 99f04b9c1e..75874445b2 100644 --- a/src/renderer/mod.rs +++ b/src/renderer/mod.rs @@ -22,9 +22,9 @@ use log::{error, warn}; use skia_safe::Canvas; use winit::{ - event::Event, - event_loop::{EventLoopProxy, EventLoopWindowTarget}, - window::{Window, WindowBuilder}, + event::WindowEvent, + event_loop::{ActiveEventLoop, EventLoopProxy}, + window::{Window, WindowAttributes}, }; use crate::{ @@ -190,8 +190,8 @@ impl Renderer { } } - pub fn handle_event(&mut self, event: &Event) -> bool { - self.cursor_renderer.handle_event(event) + pub fn handle_event(&mut self, event: &WindowEvent) { + self.cursor_renderer.handle_event(event); } pub fn font_names(&self) -> Vec { @@ -503,17 +503,17 @@ pub struct WindowConfig { pub config: WindowConfigType, } -pub fn build_window_config( - winit_window_builder: WindowBuilder, - event_loop: &EventLoopWindowTarget, +pub fn build_window_config( + window_attributes: WindowAttributes, + event_loop: &ActiveEventLoop, ) -> WindowConfig { #[cfg(target_os = "windows")] { let cmd_line_settings = SETTINGS.get::(); if cmd_line_settings.opengl { - opengl::build_window(winit_window_builder, event_loop) + opengl::build_window(window_attributes, event_loop) } else { - let window = winit_window_builder.build(event_loop).unwrap(); + let window = event_loop.create_window(window_attributes).unwrap(); let config = WindowConfigType::Direct3D; WindowConfig { window, config } } @@ -521,7 +521,7 @@ pub fn build_window_config( #[cfg(not(target_os = "windows"))] { - opengl::build_window(winit_window_builder, event_loop) + opengl::build_window(window_attributes, event_loop) } } diff --git a/src/renderer/opengl.rs b/src/renderer/opengl.rs index 4ca4e3e15e..79057fcd81 100644 --- a/src/renderer/opengl.rs +++ b/src/renderer/opengl.rs @@ -16,7 +16,7 @@ use glutin::{ surface::{Surface, SurfaceAttributesBuilder, WindowSurface}, }; use glutin_winit::DisplayBuilder; -use raw_window_handle::HasRawWindowHandle; +use raw_window_handle::HasWindowHandle; use skia_safe::{ canvas::Canvas, gpu::{ @@ -27,8 +27,8 @@ use skia_safe::{ }; use winit::{ dpi::PhysicalSize, - event_loop::{EventLoopProxy, EventLoopWindowTarget}, - window::{Window, WindowBuilder}, + event_loop::{ActiveEventLoop, EventLoopProxy}, + window::{Window, WindowAttributes}, }; #[cfg(target_os = "windows")] @@ -77,7 +77,7 @@ impl OpenGLSkiaRenderer { }; let window = window.window; let gl_display = config.display(); - let raw_window_handle = window.raw_window_handle(); + let raw_window_handle = window.window_handle().unwrap().as_raw(); let size = clamp_render_buffer_size(&window.inner_size()); @@ -241,15 +241,15 @@ fn gen_config(mut config_iterator: Box + '_>) -> Con config_iterator.next().unwrap() } -pub fn build_window( - winit_window_builder: WindowBuilder, - event_loop: &EventLoopWindowTarget, +pub fn build_window( + window_attributes: WindowAttributes, + event_loop: &ActiveEventLoop, ) -> WindowConfig { let template_builder = ConfigTemplateBuilder::new() .with_stencil_size(8) .with_transparency(true); let (window, config) = DisplayBuilder::new() - .with_window_builder(Some(winit_window_builder)) + .with_window_attributes(Some(window_attributes)) .build(event_loop, template_builder, gen_config) .expect("Failed to create Window"); let window = window.expect("Could not create Window"); diff --git a/src/renderer/vsync/macos_display_link.rs b/src/renderer/vsync/macos_display_link.rs index f710512b6f..4911a204d3 100644 --- a/src/renderer/vsync/macos_display_link.rs +++ b/src/renderer/vsync/macos_display_link.rs @@ -4,11 +4,11 @@ use crate::profiling::tracy_zone; use self::core_video::CVReturn; -use icrate::{AppKit::NSWindow, Foundation::NSString}; +use icrate::{AppKit::NSView, Foundation::NSString}; use objc2::msg_send; use objc2::rc::Id; -use raw_window_handle::{HasRawWindowHandle, RawWindowHandle}; +use raw_window_handle::{HasWindowHandle, RawWindowHandle}; use winit::window::Window; // Display link api reference: https://developer.apple.com/documentation/corevideo/cvdisplaylink?language=objc @@ -206,8 +206,12 @@ impl Drop for MacosDisplayLink { pub fn get_display_id_of_window(window: &Window) -> core_video::CGDirectDisplayID { unsafe fn get_display_id(window: &Window) -> Option { let key: Id = NSString::from_str("NSScreenNumber"); - if let RawWindowHandle::AppKit(handle) = window.raw_window_handle() { - let ns_window = Id::retain(handle.ns_window as *mut NSWindow)?; + if let RawWindowHandle::AppKit(handle) = window.window_handle().unwrap().as_raw() { + let ns_view = handle.ns_view.as_ptr(); + let ns_view: Id = unsafe { Id::retain(ns_view.cast()) }.unwrap(); + let ns_window = ns_view + .window() + .expect("view was not installed in a window"); let screen = ns_window.screen()?; let descr = screen.deviceDescription(); let display_id_ns_number = descr.get(&key)?; diff --git a/src/window/error_window.rs b/src/window/error_window.rs index eb067656c0..21033f323e 100644 --- a/src/window/error_window.rs +++ b/src/window/error_window.rs @@ -10,11 +10,12 @@ use skia_safe::{ use strum::IntoEnumIterator; use strum::{EnumCount, EnumIter}; use winit::{ + application::ApplicationHandler, dpi::PhysicalSize, - event::{ElementState, Event, KeyEvent, Modifiers, MouseScrollDelta, WindowEvent}, - event_loop::{EventLoop, EventLoopWindowTarget}, + event::{ElementState, KeyEvent, Modifiers, MouseScrollDelta, WindowEvent}, + event_loop::{ActiveEventLoop, EventLoop}, keyboard::{Key, NamedKey}, - window::WindowBuilder, + window::Window, }; use crate::{ @@ -34,7 +35,7 @@ const DEFAULT_SIZE: PhysicalSize = PhysicalSize::new(800, 600); pub fn show_error_window(message: &str, event_loop: EventLoop) { let mut error_window = ErrorWindow::new(message); - error_window.run_event_loop(event_loop); + event_loop.run_app(&mut error_window).ok(); } #[derive(Debug)] @@ -83,25 +84,28 @@ impl<'a> ErrorWindow<'a> { message, } } +} - fn run_event_loop(&mut self, event_loop: EventLoop) { - let _ = event_loop.run(|e, window_target| match e { - Event::Resumed => { - if self.state.is_none() { - self.state = Some(State::new(self.message, window_target)); - } - } - Event::WindowEvent { event, .. } => { - let state = self.state.as_mut().unwrap(); - state.handle_window_event(event, window_target, self.message); - } - _ => {} - }); +impl<'a> ApplicationHandler for ErrorWindow<'a> { + fn window_event( + &mut self, + event_loop: &ActiveEventLoop, + _window_id: winit::window::WindowId, + event: WindowEvent, + ) { + let state = self.state.as_mut().unwrap(); + state.handle_window_event(event, event_loop, self.message); + } + + fn resumed(&mut self, event_loop: &ActiveEventLoop) { + if self.state.is_none() { + self.state = Some(State::new(self.message, event_loop)); + } } } impl State { - fn new(message: &str, event_loop: &EventLoopWindowTarget) -> Self { + fn new(message: &str, event_loop: &ActiveEventLoop) -> Self { let message = message.trim_end(); let font_manager = FontMgr::new(); @@ -137,12 +141,12 @@ impl State { fn handle_window_event( &mut self, event: WindowEvent, - window_target: &EventLoopWindowTarget, + event_loop: &ActiveEventLoop, message: &str, ) { match event { WindowEvent::CloseRequested => { - window_target.exit(); + event_loop.exit(); } WindowEvent::RedrawRequested => { self.render(); @@ -161,7 +165,7 @@ impl State { is_synthetic: false, .. } => { - if self.handle_keyboard_input(event, window_target, message) { + if self.handle_keyboard_input(event, event_loop, message) { self.skia_renderer.window().request_redraw(); } } @@ -212,7 +216,7 @@ impl State { fn handle_keyboard_input( &mut self, event: KeyEvent, - window_target: &EventLoopWindowTarget, + event_loop: &ActiveEventLoop, message: &str, ) -> bool { if event.state != ElementState::Pressed { @@ -244,7 +248,7 @@ impl State { true } "q" => { - window_target.exit(); + event_loop.exit(); true } "y" => { @@ -267,7 +271,7 @@ impl State { true } NamedKey::Escape => { - window_target.exit(); + event_loop.exit(); true } _ => false, @@ -480,10 +484,10 @@ fn create_paragraphs( } } -fn create_window(event_loop: &EventLoopWindowTarget) -> WindowConfig { +fn create_window(event_loop: &ActiveEventLoop) -> WindowConfig { let icon = load_icon(); - let winit_window_builder = WindowBuilder::new() + let window_attributes = Window::default_attributes() .with_title("Neovide") .with_window_icon(Some(icon)) .with_transparent(false) @@ -492,5 +496,5 @@ fn create_window(event_loop: &EventLoopWindowTarget) -> WindowConfig .with_inner_size(DEFAULT_SIZE) .with_min_inner_size(MIN_SIZE); - build_window_config(winit_window_builder, event_loop) + build_window_config(window_attributes, event_loop) } diff --git a/src/window/macos.rs b/src/window/macos.rs index 855a7132d3..9f2d9f1bec 100644 --- a/src/window/macos.rs +++ b/src/window/macos.rs @@ -16,14 +16,11 @@ use objc2::{ }; use csscolorparser::Color; -use raw_window_handle::{HasRawWindowHandle, RawWindowHandle}; -use winit::event::{Event, WindowEvent}; +use raw_window_handle::{HasWindowHandle, RawWindowHandle}; use winit::window::Window; use crate::bridge::{send_ui, ParallelCommand}; -use crate::{ - cmd_line::CmdLineSettings, error_msg, frame::Frame, settings::SETTINGS, window::UserEvent, -}; +use crate::{cmd_line::CmdLineSettings, error_msg, frame::Frame, settings::SETTINGS}; use super::{WindowSettings, WindowSettingsChanged}; @@ -70,9 +67,13 @@ pub struct MacosWindowFeature { impl MacosWindowFeature { pub fn from_winit_window(window: &Window, mtm: MainThreadMarker) -> MacosWindowFeature { - let ns_window = match window.raw_window_handle() { + let ns_window = match window.window_handle().unwrap().as_raw() { RawWindowHandle::AppKit(handle) => unsafe { - Id::retain(handle.ns_window as *mut NSWindow).unwrap() + let ns_view = handle.ns_view.as_ptr(); + let ns_view: Id = Id::retain(ns_view.cast()).unwrap(); + ns_view + .window() + .expect("view was not installed in a window") }, _ => panic!("Not an appkit window."), }; @@ -298,16 +299,10 @@ impl Menu { quit_handler: QuitHandler::new(mtm), } } - pub fn ensure_menu_added(&mut self, ev: &Event) { - if let Event::WindowEvent { - event: WindowEvent::Focused(_), - .. - } = ev - { - if !self.menu_added { - self.add_menus(); - self.menu_added = true; - } + pub fn ensure_menu_added(&mut self) { + if !self.menu_added { + self.add_menus(); + self.menu_added = true; } } diff --git a/src/window/mod.rs b/src/window/mod.rs index 663d5d343e..c0b68e9deb 100644 --- a/src/window/mod.rs +++ b/src/window/mod.rs @@ -11,25 +11,20 @@ mod macos; #[cfg(target_os = "linux")] use std::env; -#[cfg(target_os = "macos")] -use icrate::Foundation::MainThreadMarker; - use winit::{ dpi::{PhysicalSize, Size}, - error::EventLoopError, - event::Event, - event_loop::{EventLoop, EventLoopBuilder, EventLoopWindowTarget}, - window::{Icon, Theme, WindowBuilder}, + event_loop::{ActiveEventLoop, EventLoop}, + window::{Icon, Theme, Window}, }; #[cfg(target_os = "macos")] -use winit::platform::macos::WindowBuilderExtMacOS; +use winit::platform::macos::WindowAttributesExtMacOS; #[cfg(target_os = "linux")] -use winit::platform::{wayland::WindowBuilderExtWayland, x11::WindowBuilderExtX11}; +use winit::platform::{wayland::WindowAttributesExtWayland, x11::WindowAttributesExtX11}; #[cfg(target_os = "windows")] -use winit::platform::windows::WindowBuilderExtWindows; +use winit::platform::windows::WindowAttributesExtWindows; #[cfg(target_os = "macos")] use winit::platform::macos::EventLoopBuilderExtMacOS; @@ -37,21 +32,21 @@ use winit::platform::macos::EventLoopBuilderExtMacOS; use image::{load_from_memory, GenericImageView, Pixel}; use keyboard_manager::KeyboardManager; use mouse_manager::MouseManager; -use update_loop::UpdateLoop; use crate::{ cmd_line::{CmdLineSettings, GeometryArgs}, frame::Frame, renderer::{build_window_config, DrawCommand, WindowConfig}, settings::{ - clamped_grid_size, load_last_window_settings, save_window_size, FontSettings, - HotReloadConfigs, PersistentWindowSettings, SettingsChanged, SETTINGS, + clamped_grid_size, load_last_window_settings, save_window_size, HotReloadConfigs, + PersistentWindowSettings, SettingsChanged, SETTINGS, }, units::GridSize, }; pub use error_window::show_error_window; pub use settings::{WindowSettings, WindowSettingsChanged}; pub use update_loop::ShouldRender; +pub use update_loop::UpdateLoop; pub use window_wrapper::WinitWindowWrapper; static ICON: &[u8] = include_bytes!("../../assets/neovide.ico"); @@ -120,7 +115,7 @@ impl From for UserEvent { } pub fn create_event_loop() -> EventLoop { - let mut builder = EventLoopBuilder::::with_user_event(); + let mut builder = EventLoop::with_user_event(); #[cfg(target_os = "macos")] builder.with_default_menu(false); let event_loop = builder.build().expect("Failed to create winit event loop"); @@ -130,11 +125,7 @@ pub fn create_event_loop() -> EventLoop { event_loop } -pub fn create_window( - event_loop: &EventLoopWindowTarget, - maximized: bool, - title: &str, -) -> WindowConfig { +pub fn create_window(event_loop: &ActiveEventLoop, maximized: bool, title: &str) -> WindowConfig { let icon = load_icon(); let cmd_line_settings = SETTINGS.get::(); @@ -146,7 +137,7 @@ pub fn create_window( _ => None, }; - let winit_window_builder = WindowBuilder::new() + let window_attributes = Window::default_attributes() .with_title(title) .with_window_icon(Some(icon)) .with_maximized(maximized) @@ -154,10 +145,10 @@ pub fn create_window( .with_visible(false); #[cfg(target_os = "windows")] - let winit_window_builder = if !cmd_line_settings.opengl { - WindowBuilderExtWindows::with_no_redirection_bitmap(winit_window_builder, true) + let window_attributes = if !cmd_line_settings.opengl { + WindowAttributesExtWindows::with_no_redirection_bitmap(window_attributes, true) } else { - winit_window_builder + window_attributes }; let frame_decoration = cmd_line_settings.frame; @@ -167,45 +158,44 @@ pub fn create_window( // There is only two options for windows & linux, no need to match more options. #[cfg(not(target_os = "macos"))] - let mut winit_window_builder = - winit_window_builder.with_decorations(frame_decoration == Frame::Full); + let mut window_attributes = window_attributes.with_decorations(frame_decoration == Frame::Full); #[cfg(target_os = "macos")] - let mut winit_window_builder = match frame_decoration { - Frame::Full => winit_window_builder, - Frame::None => winit_window_builder.with_decorations(false), - Frame::Buttonless => winit_window_builder + let mut window_attributes = match frame_decoration { + Frame::Full => window_attributes, + Frame::None => window_attributes.with_decorations(false), + Frame::Buttonless => window_attributes .with_title_hidden(title_hidden) .with_titlebar_buttons_hidden(true) .with_titlebar_transparent(true) .with_fullsize_content_view(true), - Frame::Transparent => winit_window_builder + Frame::Transparent => window_attributes .with_title_hidden(title_hidden) .with_titlebar_transparent(true) .with_fullsize_content_view(true), }; if let Some(previous_position) = previous_position { - winit_window_builder = winit_window_builder.with_position(previous_position); + window_attributes = window_attributes.with_position(previous_position); } #[cfg(target_os = "linux")] - let winit_window_builder = { + let window_attributes = { if env::var("WAYLAND_DISPLAY").is_ok() { let app_id = &cmd_line_settings.wayland_app_id; - WindowBuilderExtWayland::with_name(winit_window_builder, "neovide", app_id.clone()) + WindowAttributesExtWayland::with_name(window_attributes, "neovide", app_id.clone()) } else { let class = &cmd_line_settings.x11_wm_class; let instance = &cmd_line_settings.x11_wm_class_instance; - WindowBuilderExtX11::with_name(winit_window_builder, class, instance) + WindowAttributesExtX11::with_name(window_attributes, class, instance) } }; #[cfg(target_os = "macos")] - let winit_window_builder = winit_window_builder.with_accepts_first_mouse(false); + let window_attributes = window_attributes.with_accepts_first_mouse(false); #[allow(clippy::let_and_return)] - let window_config = build_window_config(winit_window_builder, event_loop); + let window_config = build_window_config(window_attributes, event_loop); #[cfg(target_os = "macos")] if let Some(previous_position) = previous_position { @@ -267,55 +257,6 @@ pub fn determine_window_size(window_settings: Option<&PersistentWindowSettings>) } } -pub fn main_loop( - initial_window_size: WindowSize, - initial_font_settings: Option, - event_loop: EventLoop, -) -> Result<(), EventLoopError> { - let cmd_line_settings = SETTINGS.get::(); - let mut update_loop = UpdateLoop::new(cmd_line_settings.idle); - - let proxy = event_loop.create_proxy(); - let mut window_wrapper = Some(WinitWindowWrapper::new( - initial_window_size, - initial_font_settings, - )); - let mut create_window_allowed = false; - - #[cfg(target_os = "macos")] - let mut menu = { - let mtm = MainThreadMarker::new().expect("must be on the main thread"); - macos::Menu::new(mtm) - }; - let res = event_loop.run(move |e, window_target| { - #[cfg(target_os = "macos")] - menu.ensure_menu_added(&e); - - match e { - Event::Resumed => { - create_window_allowed = true; - if let Some(window_wrapper) = &mut window_wrapper { - window_wrapper.try_create_window(window_target, &proxy); - } - } - Event::LoopExiting => window_wrapper = None, - Event::UserEvent(UserEvent::NeovimExited) => { - save_window_size(window_wrapper.as_ref().unwrap()); - window_target.exit(); - } - _ => { - if let Some(window_wrapper) = &mut window_wrapper { - window_target.set_control_flow(update_loop.step(window_wrapper, e)); - if create_window_allowed { - window_wrapper.try_create_window(window_target, &proxy); - } - } - } - } - }); - res -} - pub fn load_icon() -> Icon { let icon = load_from_memory(ICON).expect("Failed to parse icon data"); let (width, height) = icon.dimensions(); diff --git a/src/window/update_loop.rs b/src/window/update_loop.rs index f6d8d78b54..1ef1262e09 100644 --- a/src/window/update_loop.rs +++ b/src/window/update_loop.rs @@ -1,16 +1,25 @@ use std::time::{Duration, Instant}; use winit::{ - event::{Event, WindowEvent}, - event_loop::ControlFlow, + application::ApplicationHandler, + event::WindowEvent, + event_loop::{ActiveEventLoop, ControlFlow, EventLoopProxy}, }; -use super::{UserEvent, WindowSettings, WinitWindowWrapper}; +#[cfg(target_os = "macos")] +use icrate::Foundation::MainThreadMarker; + +use super::{save_window_size, CmdLineSettings, UserEvent, WindowSettings, WinitWindowWrapper}; use crate::{ profiling::{tracy_plot, tracy_zone}, + renderer::DrawCommand, settings::SETTINGS, + FontSettings, WindowSize, }; +#[cfg(target_os = "macos")] +use super::macos::Menu; + enum FocusedState { Focused, UnfocusedNotDrawn, @@ -76,13 +85,24 @@ pub struct UpdateLoop { num_consecutive_rendered: u32, focused: FocusedState, pending_render: bool, // We should render as soon as the compositor/vsync allows - pending_draw_commands: Vec>, + pending_draw_commands: Vec>, animation_start: Instant, // When the last animation started (went from idle to animating) animation_time: Duration, // How long the current animation has been simulated, will usually be in the future + + window_wrapper: WinitWindowWrapper, + create_window_allowed: bool, + proxy: EventLoopProxy, + + #[cfg(target_os = "macos")] + menu: Menu, } impl UpdateLoop { - pub fn new(idle: bool) -> Self { + pub fn new( + initial_window_size: WindowSize, + initial_font_settings: Option, + proxy: EventLoopProxy, + ) -> Self { let previous_frame_start = Instant::now(); let last_dt = 0.0; let should_render = ShouldRender::Immediately; @@ -93,6 +113,17 @@ impl UpdateLoop { let animation_start = Instant::now(); let animation_time = Duration::from_millis(0); + #[cfg(target_os = "macos")] + let menu = { + let mtm = MainThreadMarker::new().expect("must be on the main thread"); + Menu::new(mtm) + }; + + let cmd_line_settings = SETTINGS.get::(); + let idle = cmd_line_settings.idle; + + let window_wrapper = WinitWindowWrapper::new(initial_window_size, initial_font_settings); + Self { idle, previous_frame_start, @@ -104,6 +135,13 @@ impl UpdateLoop { pending_draw_commands, animation_start, animation_time, + + window_wrapper, + create_window_allowed: false, + proxy, + + #[cfg(target_os = "macos")] + menu, } } @@ -138,12 +176,22 @@ impl UpdateLoop { } } - fn animate(&mut self, window_wrapper: &mut WinitWindowWrapper) { - if window_wrapper.skia_renderer.is_none() { + fn schedule_next_event(&mut self, event_loop: &ActiveEventLoop) { + #[cfg(feature = "profiling")] + self.should_render.plot_tracy(); + if self.create_window_allowed { + self.window_wrapper + .try_create_window(event_loop, &self.proxy); + } + event_loop.set_control_flow(ControlFlow::WaitUntil(self.get_event_deadline())); + } + + fn animate(&mut self) { + if self.window_wrapper.skia_renderer.is_none() { return; } - let skia_renderer = window_wrapper.skia_renderer.as_ref().unwrap(); - let vsync = window_wrapper.vsync.as_ref().unwrap(); + let skia_renderer = self.window_wrapper.skia_renderer.as_ref().unwrap(); + let vsync = self.window_wrapper.vsync.as_ref().unwrap(); let dt = Duration::from_secs_f32(vsync.get_refresh_rate(skia_renderer.window())); @@ -171,16 +219,16 @@ impl UpdateLoop { let num_steps = (dt.as_secs_f64() / MAX_ANIMATION_DT).ceil() as u32; let step = dt / num_steps; for _ in 0..num_steps { - if window_wrapper.animate_frame(step.as_secs_f32()) { + if self.window_wrapper.animate_frame(step.as_secs_f32()) { self.should_render = ShouldRender::Immediately; } } } - fn render(&mut self, window_wrapper: &mut WinitWindowWrapper) { + fn render(&mut self) { self.pending_render = false; tracy_plot!("pending_render", self.pending_render as u8 as f64); - window_wrapper.draw_frame(self.last_dt); + self.window_wrapper.draw_frame(self.last_dt); if let FocusedState::UnfocusedNotDrawn = self.focused { self.focused = FocusedState::Unfocused; @@ -195,11 +243,12 @@ impl UpdateLoop { self.previous_frame_start = Instant::now(); } - fn process_buffered_draw_commands(&mut self, window_wrapper: &mut WinitWindowWrapper) { - for e in self.pending_draw_commands.drain(..) { - if window_wrapper.handle_event(e) { - self.should_render = ShouldRender::Immediately; - } + fn process_buffered_draw_commands(&mut self) { + if !self.pending_draw_commands.is_empty() { + self.pending_draw_commands + .drain(..) + .for_each(|b| self.window_wrapper.handle_draw_commands(b)); + self.should_render = ShouldRender::Immediately; } } @@ -211,12 +260,12 @@ impl UpdateLoop { } } - fn schedule_render(&mut self, skipped_frame: bool, window_wrapper: &mut WinitWindowWrapper) { - if window_wrapper.skia_renderer.is_none() { + fn schedule_render(&mut self, skipped_frame: bool) { + if self.window_wrapper.skia_renderer.is_none() { return; } - let skia_renderer = window_wrapper.skia_renderer.as_ref().unwrap(); - let vsync = window_wrapper.vsync.as_mut().unwrap(); + let skia_renderer = self.window_wrapper.skia_renderer.as_ref().unwrap(); + let vsync = self.window_wrapper.vsync.as_mut().unwrap(); // There's really no point in trying to render if the frame is skipped // (most likely due to the compositor being busy). The animated frame will @@ -229,18 +278,18 @@ impl UpdateLoop { self.pending_render = true; tracy_plot!("pending_render", self.pending_render as u8 as f64); } else { - self.render(window_wrapper); + self.render(); } } } - fn prepare_and_animate(&mut self, window_wrapper: &mut WinitWindowWrapper) { + fn prepare_and_animate(&mut self) { // We will also animate, but not render when frames are skipped or a bit late, to reduce visual artifacts let skipped_frame = self.pending_render && Instant::now() > (self.animation_start + self.animation_time); let should_prepare = !self.pending_render || skipped_frame; if !should_prepare { - window_wrapper + self.window_wrapper .renderer .grid_renderer .shaper @@ -248,7 +297,7 @@ impl UpdateLoop { return; } - let res = window_wrapper.prepare_frame(); + let res = self.window_wrapper.prepare_frame(); self.should_render.update(res); let should_animate = @@ -256,8 +305,8 @@ impl UpdateLoop { if should_animate { self.reset_animation_period(); - self.animate(window_wrapper); - self.schedule_render(skipped_frame, window_wrapper); + self.animate(); + self.schedule_render(skipped_frame); } else { self.num_consecutive_rendered = 0; tracy_plot!( @@ -269,61 +318,89 @@ impl UpdateLoop { } } - pub fn step( + fn redraw_requested(&mut self) { + if self.pending_render { + tracy_zone!("render (redraw requested)"); + self.render(); + // We should process all buffered draw commands as soon as the rendering has finished + self.process_buffered_draw_commands(); + } else { + tracy_zone!("redraw requested"); + // The OS itself asks us to redraw, so we need to prepare first + self.should_render = ShouldRender::Immediately; + } + } +} + +impl ApplicationHandler for UpdateLoop { + fn window_event( &mut self, - window_wrapper: &mut WinitWindowWrapper, - event: Event, - ) -> ControlFlow { - tracy_zone!("render loop", 0); + event_loop: &ActiveEventLoop, + _window_id: winit::window::WindowId, + event: winit::event::WindowEvent, + ) { + tracy_zone!("window_event"); match event { - // Window focus changed - Event::WindowEvent { - event: WindowEvent::Focused(focused_event), - .. - } => { + WindowEvent::RedrawRequested => { + self.redraw_requested(); + } + WindowEvent::Focused(focused_event) => { self.focused = if focused_event { FocusedState::Focused } else { FocusedState::UnfocusedNotDrawn }; - } - Event::AboutToWait => { - self.prepare_and_animate(window_wrapper); - } - Event::WindowEvent { - event: WindowEvent::RedrawRequested, - .. - } - | Event::UserEvent(UserEvent::RedrawRequested) => { - if self.pending_render { - tracy_zone!("render (redraw requested)"); - self.render(window_wrapper); - // We should process all buffered draw commands as soon as the rendering has finished - self.process_buffered_draw_commands(window_wrapper); - } else { - tracy_zone!("redraw requested"); - // The OS itself asks us to redraw, so we need to prepare first - self.should_render = ShouldRender::Immediately; - } + #[cfg(target_os = "macos")] + self.menu.ensure_menu_added(); } _ => {} } - if self.pending_render && matches!(&event, Event::UserEvent(UserEvent::DrawCommandBatch(_))) - { - // Buffer the draw commands if we have a pending render, we have already decided what to - // draw, so it's not a good idea to process them now. - // They will be processed immediately after the rendering. - self.pending_draw_commands.push(event); - } else if window_wrapper.handle_event(event) { - // But we need to handle other events (in the if statement itself) - // Also schedule a render as soon as possible + if self.window_wrapper.handle_window_event(event) { self.should_render = ShouldRender::Immediately; } + self.schedule_next_event(event_loop); + } - #[cfg(feature = "profiling")] - self.should_render.plot_tracy(); + fn user_event(&mut self, event_loop: &ActiveEventLoop, event: UserEvent) { + tracy_zone!("user_event"); + match event { + UserEvent::NeovimExited => { + save_window_size(&self.window_wrapper); + event_loop.exit(); + } + UserEvent::RedrawRequested => { + self.redraw_requested(); + } + UserEvent::DrawCommandBatch(batch) if self.pending_render => { + // Buffer the draw commands if we have a pending render, we have already decided what to + // draw, so it's not a good idea to process them now. + // They will be processed immediately after the rendering. + self.pending_draw_commands.push(batch); + } + _ => { + self.window_wrapper.handle_user_event(event); + self.should_render = ShouldRender::Immediately; + } + } + self.schedule_next_event(event_loop); + } + + fn about_to_wait(&mut self, event_loop: &ActiveEventLoop) { + tracy_zone!("about_to_wait"); + self.prepare_and_animate(); + self.schedule_next_event(event_loop); + } + + fn resumed(&mut self, event_loop: &ActiveEventLoop) { + tracy_zone!("resumed"); + self.create_window_allowed = true; + self.schedule_next_event(event_loop); + } - ControlFlow::WaitUntil(self.get_event_deadline()) + fn exiting(&mut self, event_loop: &ActiveEventLoop) { + tracy_zone!("exiting"); + self.window_wrapper.exit(); + self.schedule_next_event(event_loop); } } diff --git a/src/window/window_wrapper.rs b/src/window/window_wrapper.rs index d7d1cabb18..c3d5faa280 100644 --- a/src/window/window_wrapper.rs +++ b/src/window/window_wrapper.rs @@ -32,11 +32,11 @@ use super::macos::MacosWindowFeature; use icrate::Foundation::MainThreadMarker; use log::trace; -use raw_window_handle::{HasRawWindowHandle, RawWindowHandle}; +use raw_window_handle::{HasWindowHandle, RawWindowHandle}; use winit::{ dpi, - event::{Event, Ime, WindowEvent}, - event_loop::{EventLoopProxy, EventLoopWindowTarget}, + event::{Ime, WindowEvent}, + event_loop::{ActiveEventLoop, EventLoopProxy}, window::{Fullscreen, Theme}, }; @@ -120,6 +120,11 @@ impl WinitWindowWrapper { } } + pub fn exit(&mut self) { + self.vsync = None; + self.skia_renderer = None; + } + pub fn set_fullscreen(&mut self, fullscreen: bool) { if let Some(skia_renderer) = &self.skia_renderer { let window = skia_renderer.window(); @@ -293,60 +298,7 @@ impl WinitWindowWrapper { } } - /// Handles an event from winit and returns an boolean indicating if - /// the window should be rendered. - pub fn handle_event(&mut self, event: Event) -> bool { - tracy_zone!("handle_event", 0); - - let renderer_asks_to_be_rendered = self.renderer.handle_event(&event); - let mut should_render = true; - match event { - Event::Resumed => { - tracy_zone!("Resumed"); - // No need to do anything, but handle the event so that should_render gets set - } - Event::WindowEvent { event, .. } => { - if !self.handle_window_event(event) { - should_render = renderer_asks_to_be_rendered; - } - } - Event::UserEvent(UserEvent::DrawCommandBatch(batch)) => { - self.handle_draw_commands(batch); - } - Event::UserEvent(UserEvent::WindowCommand(e)) => { - self.handle_window_command(e); - } - Event::UserEvent(UserEvent::SettingsChanged(SettingsChanged::Window(e))) => { - self.handle_window_settings_changed(e); - } - Event::UserEvent(UserEvent::SettingsChanged(SettingsChanged::Renderer(e))) => { - self.handle_render_settings_changed(e); - } - Event::UserEvent(UserEvent::ConfigsChanged(config)) => { - self.handle_config_changed(*config); - } - _ => { - match event { - Event::AboutToWait { .. } => { - tracy_zone!("AboutToWait"); - } - Event::DeviceEvent { .. } => { - tracy_zone!("DeviceEvent"); - } - Event::NewEvents(..) => { - tracy_zone!("NewEvents"); - } - _ => { - tracy_zone!("Unknown"); - } - } - should_render = renderer_asks_to_be_rendered; - } - } - self.ui_state >= UIState::FirstFrame && should_render - } - - fn handle_window_event(&mut self, event: WindowEvent) -> bool { + pub fn handle_window_event(&mut self, event: WindowEvent) -> bool { // The renderer and vsync should always be created when a window event is received let skia_renderer = self.skia_renderer.as_mut().unwrap(); let vsync = self.vsync.as_mut().unwrap(); @@ -358,6 +310,8 @@ impl WinitWindowWrapper { skia_renderer.window(), ); self.keyboard_manager.handle_event(&event); + self.renderer.handle_event(&event); + let mut should_render = true; match event { WindowEvent::CloseRequested => { @@ -412,10 +366,31 @@ impl WinitWindowWrapper { } _ => { tracy_zone!("Unknown WindowEvent"); - return false; + should_render = false; } } - true + self.ui_state >= UIState::FirstFrame && should_render + } + + pub fn handle_user_event(&mut self, event: UserEvent) { + match event { + UserEvent::DrawCommandBatch(batch) => { + self.handle_draw_commands(batch); + } + UserEvent::WindowCommand(e) => { + self.handle_window_command(e); + } + UserEvent::SettingsChanged(SettingsChanged::Window(e)) => { + self.handle_window_settings_changed(e); + } + UserEvent::SettingsChanged(SettingsChanged::Renderer(e)) => { + self.handle_render_settings_changed(e); + } + UserEvent::ConfigsChanged(config) => { + self.handle_config_changed(*config); + } + _ => {} + } } pub fn draw_frame(&mut self, dt: f32) { @@ -459,7 +434,7 @@ impl WinitWindowWrapper { pub fn try_create_window( &mut self, - event_loop: &EventLoopWindowTarget, + event_loop: &ActiveEventLoop, proxy: &EventLoopProxy, ) { if self.ui_state != UIState::WaitingForWindowCreate { @@ -542,7 +517,10 @@ impl WinitWindowWrapper { }; } log::info!("Showing window size: {:#?}, maximized: {}", size, maximized); - let is_wayland = matches!(window.raw_window_handle(), RawWindowHandle::Wayland(_)); + let is_wayland = matches!( + window.window_handle().unwrap().as_raw(), + RawWindowHandle::Wayland(_) + ); // On Wayland we can show the window now, since internally it's only shown after the first rendering // On the other platforms the window is shown after rendering to avoid flickering if is_wayland { @@ -597,7 +575,7 @@ impl WinitWindowWrapper { self.set_macos_option_as_meta(input_macos_option_key_is_meta); } - fn handle_draw_commands(&mut self, batch: Vec) { + pub fn handle_draw_commands(&mut self, batch: Vec) { tracy_zone!("handle_draw_commands"); let handle_draw_commands_result = self.renderer.handle_draw_commands(batch); From 3960baad20d19e10c0857e07f87ddd0c65e27177 Mon Sep 17 00:00:00 2001 From: Alexsander Falcucci Date: Fri, 19 Jul 2024 13:40:42 +0200 Subject: [PATCH 2/2] docs: consolidate macOS build instructions and scripts (#2716) * docs: consolidate macos build instructions and scripts - add a new file `macos-builder/readme.md` with instructions on building and packaging neovide for macos - update the `macos-builder/run` script to set the release directory based on the architecture target - modify the `dmg_name` variable in the `macos-builder/run` script to include the architecture target - update paths and filenames in the `notes` section for correctness and file presence - assume the script runs in a macos environment with the required tools installed * build: update macos build workflow configurations - update the target architecture variable assignments in the macos build workflow * ci: support multiple architectures in github actions - add support for building `x86_64-apple-darwin` in github action - add support for building `aarch64-apple-darwin` in github action - update the `run` script in the `macos-builder` directory to take an architecture parameter * chore: remove redundant code and improve efficiency - remove redundant echo statement from `macos-builder/run` --- macos-builder/readme.md | 77 +++++++++++++++++++++++++++++++++++++++++ macos-builder/run | 16 +++++++-- 2 files changed, 91 insertions(+), 2 deletions(-) create mode 100644 macos-builder/readme.md diff --git a/macos-builder/readme.md b/macos-builder/readme.md new file mode 100644 index 0000000000..9d25f7742e --- /dev/null +++ b/macos-builder/readme.md @@ -0,0 +1,77 @@ +# Neovide Packaging for macOS + +This script is designed to build (if needed) and package the Neovide application packaging it into a macOS `.app` bundle, and then creating a `.dmg` disk image for distribution. + +## Prerequisites + +Before running the script, ensure you have the following dependencies installed: + +- [cargo](https://doc.rust-lang.org/cargo/getting-started/installation.html) +- [create-dmg](https://github.com/create-dmg/create-dmg) +- [codesign](https://developer.apple.com/documentation/security/notarizing_macos_software_before_distribution) + +**Run the Script**: + +```bash +./macos-builder/run aarch64-apple-darwin +``` + +### Steps + +**Set Up Release Directory**: +The script sets the `RELEASE_DIR` based on the `TARGET_ARCHITECTURE` environment variable. If `TARGET_ARCHITECTURE` is not set, it defaults to `target/release`. + +```bash +RELEASE_DIR=${TARGET_ARCHITECTURE:+target/${TARGET_ARCHITECTURE}/release} +RELEASE_DIR=${RELEASE_DIR:-target/release} +``` + +**Build the Project**: +If the release directory does not exist, the script runs the `cargo build --release` command to build the project. + +_*This is for local development purposes since you would typically build the project beforehand.*_ + +```bash +if [ ! -d "${RELEASE_DIR}" ]; then + cargo build --release ${TARGET_ARCHITECTURE:+--target "${TARGET_ARCHITECTURE}"} +fi +``` + +**Prepare the Application Bundle**: + +- Sets up directories for the `.app` bundle. +- Copies the built binary and other necessary resources into the bundle. +- Signs the application using `codesign`. + +```bash +mkdir -p "${APP_BINARY_DIR}" +mkdir -p "${APP_EXTRAS_DIR}" +cp -fRp "${APP_TEMPLATE}" "${APP_DIR}" +cp -fp "${APP_BINARY}" "${APP_BINARY_DIR}" +touch -r "${APP_BINARY}" "${APP_DIR}/${APP_NAME}" +codesign --remove-signature "${APP_DIR}/${APP_NAME}" +codesign --force --deep --sign - "${APP_DIR}/${APP_NAME}" +``` + +**Create the Disk Image**: +Uses `create-dmg` to create a `.dmg` file for the application. + +```bash +create-dmg \ + --filesystem "${DMG_FILESYSTEM}" \ + --format "${DMG_FORMAT}" \ + --volname "${DMG_VOLNAME}" \ + --volicon "${DMG_ICNS}" \ + --background "${DMG_BACKGROUND}" \ + --window-size 650 470 \ + --icon-size 80 \ + --icon Neovide.app 240 320 \ + --app-drop-link 410 320 \ + "${APP_DIR}/${DMG_NAME}" \ + "${APP_DIR}/${APP_NAME}" +``` + +## Notes + +- Ensure all paths and filenames are correct and that the necessary files (like `Neovide.icns` and `neovide-dmg-background.tiff`) are present in their respective directories. +- The script assumes a macOS environment with the necessary tools installed. diff --git a/macos-builder/run b/macos-builder/run index d13e6e4dad..2d419adf79 100755 --- a/macos-builder/run +++ b/macos-builder/run @@ -2,10 +2,22 @@ set -e +if [ -n "$1" ]; then + TARGET_ARCHITECTURE=$1 +fi + +RELEASE_DIR=${TARGET_ARCHITECTURE:+target/${TARGET_ARCHITECTURE}/release} +RELEASE_DIR=${RELEASE_DIR:-target/release} + +if [ ! -d "${RELEASE_DIR}" ]; then + echo "Release directory '${RELEASE_DIR}' does not exist." + echo "Running 'cargo build --release${TARGET_ARCHITECTURE:+ --target ${TARGET_ARCHITECTURE}}' ..." + cargo build --release ${TARGET_ARCHITECTURE:+--target "${TARGET_ARCHITECTURE}"} +fi + TARGET="neovide" EXTRAS_DIR="extra" ASSETS_DIR="assets" -RELEASE_DIR="target/$1/release" BUNDLE_DIR="${RELEASE_DIR}/bundle" APP_NAME="Neovide.app" @@ -15,7 +27,7 @@ APP_BINARY="${RELEASE_DIR}/${TARGET}" APP_BINARY_DIR="${APP_DIR}/${APP_NAME}/Contents/MacOS" APP_EXTRAS_DIR="${APP_DIR}/${APP_NAME}/Contents/Resources" -DMG_NAME="Neovide-$1.dmg" +DMG_NAME="Neovide${TARGET_ARCHITECTURE:+-${TARGET_ARCHITECTURE}}.dmg" DMG_VOLNAME="Neovide" DMG_FILESYSTEM="HFS+" DMG_FORMAT="UDZO"