diff --git a/Cargo.lock b/Cargo.lock index 2fb2dde..a55fbb9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,15 +4,15 @@ version = 4 [[package]] name = "accesskit" -version = "0.19.0" +version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e25ae84c0260bdf5df07796d7cc4882460de26a2b406ec0e6c42461a723b271b" +checksum = "553cd5f6b68b8c3dd07606447b91a12c044e8023d30decdc1554ecc313481d25" [[package]] name = "accesskit_atspi_common" -version = "0.12.0" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29bd41de2e54451a8ca0dd95ebf45b54d349d29ebceb7f20be264eee14e3d477" +checksum = "fe8f7e6cedea3731ad97d934cb85d89d930e34ade75a82aec3ec0adc9d834d0a" dependencies = [ "accesskit", "accesskit_consumer", @@ -24,9 +24,9 @@ dependencies = [ [[package]] name = "accesskit_consumer" -version = "0.28.0" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8bfae7c152994a31dc7d99b8eeac7784a919f71d1b306f4b83217e110fd3824c" +checksum = "5c964dad39d2e2d6977674abb9bf333a118a657dd5abb6d3b90ac44ab1f70951" dependencies = [ "accesskit", "hashbrown 0.15.4", @@ -34,9 +34,9 @@ dependencies = [ [[package]] name = "accesskit_macos" -version = "0.20.0" +version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "692dd318ff8a7a0ffda67271c4bd10cf32249656f4e49390db0b26ca92b095f2" +checksum = "dc1aada7b0eec94ac456568d123ea32a4155cc7670c7d28c37d19843a4f00ba6" dependencies = [ "accesskit", "accesskit_consumer", @@ -48,9 +48,9 @@ dependencies = [ [[package]] name = "accesskit_unix" -version = "0.15.0" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5f7474c36606d0fe4f438291d667bae7042ea2760f506650ad2366926358fc8" +checksum = "31a205f8ef4ae2d1e1ad93cc616e27f93c471628787612ecaed565773bdfeb3c" dependencies = [ "accesskit", "accesskit_atspi_common", @@ -66,23 +66,23 @@ dependencies = [ [[package]] name = "accesskit_windows" -version = "0.27.0" +version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70a042b62c9c05bf7b616f015515c17d2813f3ba89978d6f4fc369735d60700a" +checksum = "b415603285ccd9db7a4c97bc4e4e450132e4dc5df639acc5aaa3b59cf607de5f" dependencies = [ "accesskit", "accesskit_consumer", "hashbrown 0.15.4", "static_assertions", - "windows", - "windows-core", + "windows 0.61.3", + "windows-core 0.61.2", ] [[package]] name = "accesskit_winit" -version = "0.27.0" +version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c1f0d3d13113d8857542a4f8d1a1c24d1dc1527b77aee8426127f4901588708" +checksum = "ce4cc9d736f66d1b090a723a92e15336b06a095d6ad349b051ab04c3a2426432" dependencies = [ "accesskit", "accesskit_macos", @@ -479,26 +479,6 @@ dependencies = [ "unty", ] -[[package]] -name = "bindgen" -version = "0.71.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f58bf3d7db68cfbac37cfc485a8d711e87e064c3d0fe0435b92f7a407f9d6b3" -dependencies = [ - "bitflags 2.9.1", - "cexpr", - "clang-sys", - "itertools 0.13.0", - "log", - "prettyplease", - "proc-macro2", - "quote", - "regex", - "rustc-hash 2.1.1", - "shlex", - "syn", -] - [[package]] name = "bindgen" version = "0.72.0" @@ -1662,9 +1642,9 @@ checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" [[package]] name = "i-slint-backend-selector" -version = "1.12.1" +version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50166eb0f0f63ffa514069cdad5465d1d4c711c57dbd495f16f0a4ee14b82e46" +checksum = "1b5c1525cd7a659b609600a7df79bb7d90092730d5c4de4f378f39ab9a023993" dependencies = [ "cfg-if", "i-slint-backend-winit", @@ -1675,9 +1655,9 @@ dependencies = [ [[package]] name = "i-slint-backend-winit" -version = "1.12.1" +version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c3b5697d3fbbc7ae0fcba4592c76f39d13a25fad055064a31855f2234fd82ba" +checksum = "ba2a1f40bf70d4dfc5e7009673da72730ec32b4af680654975c6b39908bcd739" dependencies = [ "accesskit", "accesskit_winit", @@ -1697,18 +1677,20 @@ dependencies = [ "raw-window-handle", "scoped-tls-hkt", "scopeguard", + "strum", "vtable", "wasm-bindgen", "web-sys", + "windows 0.61.3", "winit", "zbus", ] [[package]] name = "i-slint-common" -version = "1.12.1" +version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c400c33bd6bc68397adefa1be2abaf77cdd90c216ad88b1be2ebdb0003ea996" +checksum = "40862447fc6e177ab924f43fa2bcab4de3a10fe41596a2a2cb279c911f0ad5e9" dependencies = [ "cfg-if", "derive_more", @@ -1719,9 +1701,9 @@ dependencies = [ [[package]] name = "i-slint-compiler" -version = "1.12.1" +version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1eafbcc08babe8bb24967193a7796c0e26170d0a6cdf09236cc2fdb63dded502" +checksum = "8e7e35548ed4f437f7fcb7c2bb11bbd0f45c8271d1900b47b688e4eed89482d0" dependencies = [ "by_address", "codemap", @@ -1749,9 +1731,9 @@ dependencies = [ [[package]] name = "i-slint-core" -version = "1.12.1" +version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc384a0a106e7bc1aaf6fbf06d5a4d0d8e51a4bc5ff5ce36dbe559620aef4533" +checksum = "68d10fc4c25a22e757784acf7da950223762477329f01d73e1c9cfa0749bf51a" dependencies = [ "auto_enums", "bitflags 2.9.1", @@ -1793,9 +1775,9 @@ dependencies = [ [[package]] name = "i-slint-core-macros" -version = "1.12.1" +version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81504739c60f11af98f80f287624379514923888ecdf37e0bc43c5dc1cadafa5" +checksum = "583ffd7589dc4e273cf25058b8f41fc8baeee40f28660b4539ee60f7ffc06c6b" dependencies = [ "quote", "serde_json", @@ -1804,9 +1786,9 @@ dependencies = [ [[package]] name = "i-slint-renderer-skia" -version = "1.12.1" +version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "687126d7e82d447e15bc2666053f7653fa562e11dc6a9799e6dd0186a7927142" +checksum = "0848e46481abf3155d3aca7e4a9b07be5a5d55716cd90d891293e8698a07b679" dependencies = [ "bytemuck", "cfg-if", @@ -1833,7 +1815,10 @@ dependencies = [ "softbuffer", "unicode-segmentation", "vtable", - "windows", + "windows 0.58.0", + "windows 0.61.3", + "windows-core 0.58.0", + "windows-core 0.61.2", ] [[package]] @@ -1848,7 +1833,7 @@ dependencies = [ "js-sys", "log", "wasm-bindgen", - "windows-core", + "windows-core 0.61.2", ] [[package]] @@ -3020,7 +3005,7 @@ version = "0.1.0" dependencies = [ "approx", "atomic_refcell", - "bindgen 0.72.0", + "bindgen", "clap-sys", "log", "num-derive", @@ -3052,8 +3037,8 @@ dependencies = [ "raw-window-handle", "sys-locale", "uuid", - "windows", - "windows-core", + "windows 0.61.3", + "windows-core 0.61.2", "x11rb", "xkbcommon", ] @@ -3720,15 +3705,16 @@ checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d" [[package]] name = "skia-bindings" -version = "0.86.1" +version = "0.87.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2bf215f640b53293844d441e93448b437ca4937595f60e3317fbb03d7ac6783" +checksum = "704242769235d2ffe66a2a0a3002661262fc4af08d32807c362d7b0160ee703c" dependencies = [ - "bindgen 0.71.1", + "bindgen", "cc", "flate2", "heck", "lazy_static", + "pkg-config", "regex", "serde_json", "tar", @@ -3737,14 +3723,14 @@ dependencies = [ [[package]] name = "skia-safe" -version = "0.86.1" +version = "0.87.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e372258f52414e04de007326fa497581617c9fa872a3225dca5e42212723c426" +checksum = "0f7d94f3e7537c71ad4cf132eb26e3be8c8a886ed3649c4525c089041fc312b2" dependencies = [ "bitflags 2.9.1", "lazy_static", "skia-bindings", - "windows", + "windows 0.61.3", ] [[package]] @@ -3755,9 +3741,9 @@ checksum = "04dc19736151f35336d325007ac991178d504a119863a2fcb3758cdb5e52c50d" [[package]] name = "slint" -version = "1.12.1" +version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c99512aff435eb85fc719bf73aff5c4a13f3d202843c326a2f50eb0377956f8" +checksum = "f467a64a49620e41807016dc1d519ba0ebb9d1322f734853059f93b8c3f3d2bd" dependencies = [ "const-field-offset", "i-slint-backend-selector", @@ -3773,21 +3759,21 @@ dependencies = [ [[package]] name = "slint-build" -version = "1.12.1" +version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0f58adfef3f956cc3c124cb19154cf29b510badf2a06b3a3521c6fdb97a47a4" +checksum = "11ea77b3786ae4e7549f924232a9d1ce427a320729334643a3ec1a76702d00d8" dependencies = [ "derive_more", "i-slint-compiler", "spin_on", - "toml_edit 0.22.27", + "toml_edit 0.23.4", ] [[package]] name = "slint-macros" -version = "1.12.1" +version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33e4f639260309e13e8f8dc40ec905d57a15dc512d8d50c52ad650088cc7e1e2" +checksum = "e11f55a603d8bb037f0831d4f4e91a560cfe93d93ddf2f992aa375b620f4bca3" dependencies = [ "i-slint-compiler", "proc-macro2", @@ -4155,7 +4141,7 @@ checksum = "dd79e69d3b627db300ff956027cc6c3798cef26d22526befdfcd12feeb6d2257" dependencies = [ "serde", "serde_spanned", - "toml_datetime", + "toml_datetime 0.6.11", "toml_edit 0.19.15", ] @@ -4167,7 +4153,7 @@ checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362" dependencies = [ "serde", "serde_spanned", - "toml_datetime", + "toml_datetime 0.6.11", "toml_edit 0.22.27", ] @@ -4180,6 +4166,15 @@ dependencies = [ "serde", ] +[[package]] +name = "toml_datetime" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bade1c3e902f58d73d3f294cd7f20391c1cb2fbcb643b73566bc773971df91e3" +dependencies = [ + "serde", +] + [[package]] name = "toml_edit" version = "0.19.15" @@ -4189,7 +4184,7 @@ dependencies = [ "indexmap", "serde", "serde_spanned", - "toml_datetime", + "toml_datetime 0.6.11", "winnow 0.5.40", ] @@ -4202,17 +4197,45 @@ dependencies = [ "indexmap", "serde", "serde_spanned", - "toml_datetime", + "toml_datetime 0.6.11", "toml_write", "winnow 0.7.11", ] +[[package]] +name = "toml_edit" +version = "0.23.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7211ff1b8f0d3adae1663b7da9ffe396eabe1ca25f0b0bee42b0da29a9ddce93" +dependencies = [ + "indexmap", + "toml_datetime 0.7.0", + "toml_parser", + "toml_writer", + "winnow 0.7.11", +] + +[[package]] +name = "toml_parser" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b551886f449aa90d4fe2bdaa9f4a2577ad2dde302c61ecf262d80b116db95c10" +dependencies = [ + "winnow 0.7.11", +] + [[package]] name = "toml_write" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801" +[[package]] +name = "toml_writer" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcc842091f2def52017664b53082ecbbeb5c7731092bad69d2c63050401dfd64" + [[package]] name = "tracing" version = "0.1.41" @@ -4734,6 +4757,16 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "windows" +version = "0.58.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd04d41d93c4992d421894c18c8b43496aa748dd4c081bac0dc93eb0489272b6" +dependencies = [ + "windows-core 0.58.0", + "windows-targets 0.52.6", +] + [[package]] name = "windows" version = "0.61.3" @@ -4741,7 +4774,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9babd3a767a4c1aef6900409f85f5d53ce2544ccdfaa86dad48c91782c6d6893" dependencies = [ "windows-collections", - "windows-core", + "windows-core 0.61.2", "windows-future", "windows-link", "windows-numerics", @@ -4753,7 +4786,20 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3beeceb5e5cfd9eb1d76b381630e82c4241ccd0d27f1a39ed41b2760b255c5e8" dependencies = [ - "windows-core", + "windows-core 0.61.2", +] + +[[package]] +name = "windows-core" +version = "0.58.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ba6d44ec8c2591c134257ce647b7ea6b20335bf6379a27dac5f1641fcf59f99" +dependencies = [ + "windows-implement 0.58.0", + "windows-interface 0.58.0", + "windows-result 0.2.0", + "windows-strings 0.1.0", + "windows-targets 0.52.6", ] [[package]] @@ -4762,11 +4808,11 @@ version = "0.61.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3" dependencies = [ - "windows-implement", - "windows-interface", + "windows-implement 0.60.0", + "windows-interface 0.59.1", "windows-link", - "windows-result", - "windows-strings", + "windows-result 0.3.4", + "windows-strings 0.4.2", ] [[package]] @@ -4775,11 +4821,22 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc6a41e98427b19fe4b73c550f060b59fa592d7d686537eebf9385621bfbad8e" dependencies = [ - "windows-core", + "windows-core 0.61.2", "windows-link", "windows-threading", ] +[[package]] +name = "windows-implement" +version = "0.58.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bbd5b46c938e506ecbce286b6628a02171d56153ba733b6c741fc627ec9579b" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "windows-implement" version = "0.60.0" @@ -4791,6 +4848,17 @@ dependencies = [ "syn", ] +[[package]] +name = "windows-interface" +version = "0.58.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "053c4c462dc91d3b1504c6fe5a726dd15e216ba718e84a0e46a88fbe5ded3515" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "windows-interface" version = "0.59.1" @@ -4814,10 +4882,19 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9150af68066c4c5c07ddc0ce30421554771e528bde427614c61038bc2c92c2b1" dependencies = [ - "windows-core", + "windows-core 0.61.2", "windows-link", ] +[[package]] +name = "windows-result" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d1043d8214f791817bab27572aaa8af63732e11bf84aa21a45a78d6c317ae0e" +dependencies = [ + "windows-targets 0.52.6", +] + [[package]] name = "windows-result" version = "0.3.4" @@ -4827,6 +4904,16 @@ dependencies = [ "windows-link", ] +[[package]] +name = "windows-strings" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10" +dependencies = [ + "windows-result 0.2.0", + "windows-targets 0.52.6", +] + [[package]] name = "windows-strings" version = "0.4.2" diff --git a/Cargo.toml b/Cargo.toml index 05d1003..ca0aee2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,13 +23,13 @@ log = "0.4" num-traits = "0.2" portable-atomic = { version = "1.10", features = ["float", "serde"] } raw-window-handle = "0.6" -slint = { version = "1.12.1", default-features = false, features = ["accessibility", "compat-1-2", "std"] } +slint = { version = "1.13.1", default-features = false, features = ["accessibility", "compat-1-2", "std"] } # Internal slint crate versions need to be pinned # since they don't maintain semver compatibility -i-slint-common = "1.12.1" -i-slint-core = "1.12.1" -i-slint-renderer-skia = { version = "1.12.1", features = ["x11"] } +i-slint-common = "1.13.1" +i-slint-core = "1.13.1" +i-slint-renderer-skia = { version = "1.13.1", features = ["x11"] } [patch.crates-io] # FIXME: Needed for loading cursors to work, remove once the fix has shipped diff --git a/examples/gain-plugin/Cargo.toml b/examples/gain-plugin/Cargo.toml index a1b5b0f..b29a47a 100644 --- a/examples/gain-plugin/Cargo.toml +++ b/examples/gain-plugin/Cargo.toml @@ -12,7 +12,7 @@ plinth-plugin.workspace = true plugin-canvas-slint.workspace = true serde = "1.0" serde_json = "1.0" -slint = { version = "1.10", default-features = false, features = ["accessibility", "compat-1-2", "std"] } +slint = { version = "1.13", default-features = false, features = ["accessibility", "compat-1-2", "std"] } [build-dependencies] -slint-build = "1.10" +slint-build = "1.13" diff --git a/plugin-canvas-slint/src/editor.rs b/plugin-canvas-slint/src/editor.rs index f9f5f7c..6b4dce9 100644 --- a/plugin-canvas-slint/src/editor.rs +++ b/plugin-canvas-slint/src/editor.rs @@ -53,8 +53,6 @@ impl SlintEditor { // It's ok if this fails as it just means it has already been set slint::platform::set_platform(Box::new(PluginCanvasPlatform)).ok(); - // This is Arc only to appease slint - #[expect(clippy::arc_with_non_send_sync)] let window = Arc::new(window); WINDOW_TO_SLINT.set(Some(window.clone())); diff --git a/plugin-canvas/src/lib.rs b/plugin-canvas/src/lib.rs index 6f6f500..a25dd2f 100644 --- a/plugin-canvas/src/lib.rs +++ b/plugin-canvas/src/lib.rs @@ -3,6 +3,7 @@ pub mod drag_drop; pub mod error; pub mod event; pub mod keyboard; +pub mod thread_bound; pub mod window; pub use dimensions::{LogicalPosition, LogicalSize, PhysicalPosition, PhysicalSize}; diff --git a/plugin-canvas/src/platform/mac/view.rs b/plugin-canvas/src/platform/mac/view.rs index cb1ccdb..16c02f7 100644 --- a/plugin-canvas/src/platform/mac/view.rs +++ b/plugin-canvas/src/platform/mac/view.rs @@ -1,4 +1,4 @@ -use std::{cell::RefCell, ffi::{c_void, CString}, ops::{Deref, DerefMut}, path::PathBuf, rc::Weak, str::FromStr, sync::atomic::{AtomicPtr, AtomicU8, AtomicUsize, Ordering}}; +use std::{cell::RefCell, ffi::{c_void, CString}, ops::{Deref, DerefMut}, path::PathBuf, str::FromStr, sync::{atomic::{AtomicPtr, AtomicU8, AtomicUsize, Ordering}, Weak}}; use objc2::{declare::ClassBuilder, msg_send, runtime::{AnyClass, Bool}, sel, ClassType, Encode, Encoding, Message, RefEncode}; use objc2::runtime::{Sel, ProtocolObject}; @@ -6,7 +6,7 @@ use objc2_app_kit::{NSDragOperation, NSDraggingInfo, NSEvent, NSEventModifierFla use objc2_foundation::{NSPoint, NSRect, NSURL}; use uuid::Uuid; -use crate::{drag_drop::{DropData, DropOperation}, event::EventResponse, keyboard::KeyboardModifiers, Event, LogicalPosition, MouseButton}; +use crate::{drag_drop::{DropData, DropOperation}, event::EventResponse, keyboard::KeyboardModifiers, thread_bound::ThreadBound, Event, LogicalPosition, MouseButton}; use super::{keyboard::key_event_to_keyboard_type_code, window::OsWindow}; @@ -15,7 +15,7 @@ pub struct OsWindowView { } struct Context { - os_window_ptr: AtomicPtr, + os_window_ptr: AtomicPtr>, input_focus: AtomicU8, keyboard_modifiers: RefCell, } @@ -81,7 +81,7 @@ impl OsWindowView { builder.register() } - pub(crate) fn set_os_window_ptr(&self, ptr: *mut OsWindow) { + pub(crate) fn set_os_window_ptr(&self, ptr: *mut ThreadBound) { self.with_context(|context| context.os_window_ptr.store(ptr, Ordering::Release)); } diff --git a/plugin-canvas/src/platform/mac/window.rs b/plugin-canvas/src/platform/mac/window.rs index b8901b0..6f433b2 100644 --- a/plugin-canvas/src/platform/mac/window.rs +++ b/plugin-canvas/src/platform/mac/window.rs @@ -1,4 +1,4 @@ -use std::{cell::RefCell, ptr::{null_mut, NonNull}, rc::Rc, sync::atomic::{AtomicBool, Ordering}}; +use std::{cell::RefCell, ptr::{null_mut, NonNull}, sync::{atomic::{AtomicBool, Ordering}, Arc}}; use cursor_icon::CursorIcon; use objc2::{msg_send, rc::{Allocated, Retained}, sel, AllocAnyThread}; @@ -9,7 +9,7 @@ use objc2_foundation::{MainThreadMarker, NSArray, NSDefaultRunLoopMode, NSPoint, use objc2_quartz_core::CADisplayLink; use raw_window_handle::{AppKitWindowHandle, HasDisplayHandle, HasWindowHandle, RawWindowHandle}; -use crate::{platform::os_window_handle::OsWindowHandle, Event, LogicalPosition}; +use crate::{platform::os_window_handle::OsWindowHandle, thread_bound::ThreadBound, Event, LogicalPosition}; use crate::error::Error; use crate::event::{EventCallback, EventResponse}; use crate::platform::interface::OsWindowInterface; @@ -88,7 +88,7 @@ impl OsWindowInterface for OsWindow { let main_thread_marker = MainThreadMarker::new().unwrap(); - let window = Rc::new(Self { + let window = Self { window_handle, display_link: Default::default(), event_callback, @@ -96,7 +96,9 @@ impl OsWindowInterface for OsWindow { cursor_hidden: Default::default(), main_thread_marker, - }); + }; + + let window = Arc::new(ThreadBound::new(window)); let display_link = unsafe { view.displayLinkWithTarget_selector(&view, sel!(drawRect:)) }; @@ -106,7 +108,7 @@ impl OsWindowInterface for OsWindow { *window.display_link.borrow_mut() = Some(display_link); - view.set_os_window_ptr(Rc::downgrade(&window).into_raw() as _); + view.set_os_window_ptr(Arc::downgrade(&window).into_raw() as _); Ok(OsWindowHandle::new(window)) } diff --git a/plugin-canvas/src/platform/os_window_handle.rs b/plugin-canvas/src/platform/os_window_handle.rs index 9176bb9..1a70fee 100644 --- a/plugin-canvas/src/platform/os_window_handle.rs +++ b/plugin-canvas/src/platform/os_window_handle.rs @@ -1,15 +1,18 @@ -use std::{ops::Deref, rc::Rc}; +use std::sync::Arc; +use std::ops::Deref; use raw_window_handle::{HasDisplayHandle, HasWindowHandle}; +use crate::thread_bound::ThreadBound; + use super::window::OsWindow; pub(crate) struct OsWindowHandle { - os_window: Rc, + os_window: Arc>, } impl OsWindowHandle { - pub(super) fn new(os_window: Rc) -> Self { + pub(super) fn new(os_window: Arc>) -> Self { Self { os_window, } diff --git a/plugin-canvas/src/platform/win32/drop_target.rs b/plugin-canvas/src/platform/win32/drop_target.rs index 8d398ae..1f9b396 100644 --- a/plugin-canvas/src/platform/win32/drop_target.rs +++ b/plugin-canvas/src/platform/win32/drop_target.rs @@ -3,7 +3,7 @@ use std::ffi::OsString; use std::ops::Deref; use std::os::windows::prelude::OsStringExt; use std::ptr::null_mut; -use std::rc::Weak; +use std::sync::Weak; use windows::Win32::Foundation::{POINTL, POINT}; use windows::Win32::Graphics::Gdi::MapWindowPoints; @@ -16,18 +16,19 @@ use windows::Win32::UI::WindowsAndMessaging::HWND_DESKTOP; use crate::event::EventResponse; use crate::platform::interface::OsWindowInterface; +use crate::thread_bound::ThreadBound; use crate::{LogicalPosition, PhysicalPosition}; use crate::drag_drop::{DropData, DropOperation}; use super::window::OsWindow; #[implement(IDropTarget)] pub(super) struct DropTarget { - window: Weak, + window: Weak>, drop_data: RefCell, } impl DropTarget { - pub fn new(window: Weak) -> Self { + pub fn new(window: Weak>) -> Self { Self { window, drop_data: Default::default(), diff --git a/plugin-canvas/src/platform/win32/window.rs b/plugin-canvas/src/platform/win32/window.rs index 128090a..164bc81 100644 --- a/plugin-canvas/src/platform/win32/window.rs +++ b/plugin-canvas/src/platform/win32/window.rs @@ -1,4 +1,5 @@ -use std::{cell::RefCell, ffi::OsString, mem::{size_of, transmute}, num::NonZeroIsize, os::windows::prelude::OsStringExt, ptr::{null, null_mut}, rc::{Rc, Weak}, sync::{atomic::{AtomicBool, AtomicUsize, Ordering}, Arc}, time::Duration}; +use std::sync::Weak; +use std::{cell::RefCell, ffi::OsString, mem::{size_of, transmute}, num::NonZeroIsize, os::windows::prelude::OsStringExt, ptr::{null, null_mut}, sync::{atomic::{AtomicBool, AtomicUsize, Ordering}, Arc}, time::Duration}; use cursor_icon::CursorIcon; use keyboard_types::Code; @@ -10,6 +11,7 @@ use windows::Win32::Graphics::{Dwm::{DwmFlush, DwmIsCompositionEnabled}, Dxgi::{ use windows::Win32::System::{Ole::{IDropTarget, OleInitialize, RegisterDragDrop, RevokeDragDrop}, Threading::GetCurrentThreadId}; use windows::Win32::UI::{Controls::WM_MOUSELEAVE, Input::KeyboardAndMouse::{GetAsyncKeyState, SetCapture, TrackMouseEvent, TME_LEAVE, TRACKMOUSEEVENT, VK_CONTROL, VK_MENU, VK_SHIFT}, WindowsAndMessaging::{CallNextHookEx, CreateWindowExW, DefWindowProcW, DestroyWindow, GetWindowLongPtrW, LoadCursorW, MoveWindow, PostMessageW, RegisterClassW, SendMessageW, SetCursor, SetCursorPos, SetWindowLongPtrW, SetWindowsHookExW, ShowCursor, UnhookWindowsHookEx, UnregisterClassW, CS_OWNDC, GWLP_USERDATA, HHOOK, HICON, IDC_ARROW, MOUSEHOOKSTRUCTEX, WH_MOUSE, WINDOW_EX_STYLE, WM_LBUTTONDOWN, WM_LBUTTONUP, WM_MBUTTONDOWN, WM_MBUTTONUP, WM_MOUSEMOVE, WM_MOUSEWHEEL, WM_MOVE, WM_RBUTTONDOWN, WM_RBUTTONUP, WNDCLASSW, WS_CHILD, WS_VISIBLE}}; +use crate::thread_bound::ThreadBound; use crate::{dimensions::Size, error::Error, event::{Event, EventCallback, EventResponse, MouseButton}, keyboard::KeyboardModifiers, platform::{interface::OsWindowInterface, os_window_handle::OsWindowHandle}, window::WindowAttributes, LogicalPosition, LogicalSize, PhysicalPosition}; use super::{cursors::Cursors, drop_target::DropTarget, message_window::MessageWindow, to_wstr, version::is_windows10_or_greater, PLUGIN_HINSTANCE, WM_USER_CHAR, WM_USER_FRAME_TIMER, WM_USER_KEY_DOWN, WM_USER_KEY_UP}; @@ -174,7 +176,7 @@ impl OsWindowInterface for OsWindow { move || message_window.run(running) }); - let window = Rc::new(Self { + let window = Self { window_class, window_handle, hook_handle, @@ -189,9 +191,11 @@ impl OsWindowInterface for OsWindow { moved, keyboard_modifiers: Default::default(), - }); + }; + + let window = Arc::new(ThreadBound::new(window)); - let drop_target: Box = Box::new(DropTarget::new(Rc::downgrade(&window)).into()); + let drop_target: Box = Box::new(DropTarget::new(Arc::downgrade(&window)).into()); unsafe { OleInitialize(None)?; @@ -200,7 +204,7 @@ impl OsWindowInterface for OsWindow { *window.drop_target.borrow_mut() = Some(drop_target); - unsafe { SetWindowLongPtrW(hwnd, GWLP_USERDATA, Rc::downgrade(&window).into_raw() as _) }; + unsafe { SetWindowLongPtrW(hwnd, GWLP_USERDATA, Arc::downgrade(&window).into_raw() as _) }; Ok(OsWindowHandle::new(window)) } @@ -316,7 +320,7 @@ impl HasDisplayHandle for OsWindow { } unsafe extern "system" fn wnd_proc(hwnd: HWND, msg: u32, wparam: WPARAM, lparam: LPARAM) -> LRESULT { - let window_ptr = unsafe { GetWindowLongPtrW(hwnd, GWLP_USERDATA) } as *mut OsWindow; + let window_ptr = unsafe { GetWindowLongPtrW(hwnd, GWLP_USERDATA) } as *mut ThreadBound; if window_ptr.is_null() { return unsafe { DefWindowProcW(hwnd, msg, wparam, lparam) }; } diff --git a/plugin-canvas/src/platform/win32/window_handle.rs b/plugin-canvas/src/platform/win32/window_handle.rs new file mode 100644 index 0000000..c14c6dd --- /dev/null +++ b/plugin-canvas/src/platform/win32/window_handle.rs @@ -0,0 +1,68 @@ +use std::cell::UnsafeCell; +use std::sync::{Arc, Weak}; +use std::thread::ThreadId; + +use crate::platform::window::OsWindow; + +pub(crate) struct OsWindowHandle { + os_window: Arc>, + thread: ThreadId, +} + +impl OsWindowHandle { + // OsWindow is not Send + Sync but we are + #[expect(clippy::arc_with_non_send_sync)] + pub(super) fn new(os_window: OsWindow) -> Self { + Self { + os_window: Arc::new(os_window.into()), + thread: std::thread::current().id(), + } + } + + pub fn as_window(&self) -> &OsWindow { + assert_eq!(std::thread::current().id(), self.thread); + + // SAFETY: It's checked above that we're not on another thread + unsafe { &*self.os_window.get() } + } + + pub(super) fn downgrade(&self) -> OsWindowWeak { + OsWindowWeak { + os_window: Arc::downgrade(&self.os_window), + thread: self.thread, + } + } +} + +unsafe impl Send for OsWindowHandle {} +unsafe impl Sync for OsWindowHandle {} + +#[derive(Clone)] +pub(super) struct OsWindowWeak { + os_window: Weak>, + thread: ThreadId, +} + +impl OsWindowWeak { + pub fn upgrade(&self) -> Option { + let os_window = self.os_window.upgrade()?; + + Some(OsWindowHandle { + os_window, + thread: self.thread, + }) + } + + pub fn into_raw(self) -> *const UnsafeCell { + Weak::into_raw(self.os_window) + } + + /// SAFETY: + /// Must be called from the same thread as into_raw() was called from + pub unsafe fn from_raw(ptr: *const UnsafeCell) -> Self { + Self { + os_window: unsafe { Weak::from_raw(ptr) }, + thread: std::thread::current().id(), + } + } +} diff --git a/plugin-canvas/src/platform/x11/window.rs b/plugin-canvas/src/platform/x11/window.rs index 3214629..5f70f7b 100644 --- a/plugin-canvas/src/platform/x11/window.rs +++ b/plugin-canvas/src/platform/x11/window.rs @@ -1,3 +1,4 @@ +use std::sync::Arc; use std::{cell::RefCell, ffi::OsStr, num::NonZeroU32, ptr::NonNull, sync::atomic::{AtomicBool, Ordering}}; use cursor_icon::CursorIcon; @@ -97,15 +98,13 @@ impl OsWindow { for keysym in xkb_state.key_get_syms(x11_keycode) { xkb_compose_state.feed(*keysym); - if xkb_compose_state.status() == xkb::Status::Composed { - if let Some(text) = xkb_compose_state.utf8() { - self.send_event(Event::KeyDown { - key_code: keycode, - text: Some(text), - }); - - sent_event_with_text = true; - } + if xkb_compose_state.status() == xkb::Status::Composed && let Some(text) = xkb_compose_state.utf8() { + self.send_event(Event::KeyDown { + key_code: keycode, + text: Some(text), + }); + + sent_event_with_text = true; } } @@ -302,7 +301,7 @@ impl OsWindowInterface for OsWindow { showing_cursor: true.into(), }; - Ok(OsWindowHandle::new(window.into())) + Ok(OsWindowHandle::new(Arc::new(window.into()))) } fn os_scale(&self) -> f64 { diff --git a/plugin-canvas/src/thread_bound.rs b/plugin-canvas/src/thread_bound.rs new file mode 100644 index 0000000..884a0f8 --- /dev/null +++ b/plugin-canvas/src/thread_bound.rs @@ -0,0 +1,46 @@ +use std::cell::UnsafeCell; +use std::ops::{Deref, DerefMut}; +use std::thread::ThreadId; + +pub struct ThreadBound { + inner: UnsafeCell, + thread: ThreadId, +} + +impl ThreadBound { + pub fn new(inner: T) -> Self { + Self { + inner: inner.into(), + thread: std::thread::current().id(), + } + } + + fn assert_thread(&self) { + assert_eq!(std::thread::current().id(), self.thread, "Tried to access inner ThreadBound value from an invalid thread"); + } +} + +impl Deref for ThreadBound { + type Target = T; + + fn deref(&self) -> &Self::Target { + self.assert_thread(); + unsafe { &*self.inner.get() } + } +} + +impl DerefMut for ThreadBound { + fn deref_mut(&mut self) -> &mut Self::Target { + self.assert_thread(); + self.inner.get_mut() + } +} + +impl From for ThreadBound { + fn from(value: T) -> Self { + Self::new(value) + } +} + +unsafe impl Send for ThreadBound {} +unsafe impl Sync for ThreadBound {}