From 5dea1bded60d4c89a177b67e8c01da7552961015 Mon Sep 17 00:00:00 2001 From: jshin-tacticalid Date: Tue, 31 Mar 2026 14:34:49 -0400 Subject: [PATCH 1/3] feat(macos): add Send + Sync for SubclassingAdapter iced's Proxy requires Send + Sync for its Notifier trait because it wraps the adapter in a channel. The SubclassingAdapter uses RefCell internally, which is not Send/Sync. This is safe because the SubclassingAdapter is always created and accessed on the main thread. The Send + Sync bounds come from iced's channel infrastructure, not actual cross-thread usage. Accessibility callbacks (NSAccessibility) only fire on the window's thread. --- platforms/macos/src/subclass.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/platforms/macos/src/subclass.rs b/platforms/macos/src/subclass.rs index 9d5b194fb..d07507441 100644 --- a/platforms/macos/src/subclass.rs +++ b/platforms/macos/src/subclass.rs @@ -255,6 +255,13 @@ impl SubclassingAdapter { } } +// SAFETY: SubclassingAdapter is always created and accessed on the main thread. +// The Send + Sync bounds are required by iced's Proxy / Notifier trait, +// which wraps the adapter in a channel — but actual accessibility callbacks +// only ever fire on the main thread. +unsafe impl Send for SubclassingAdapter {} +unsafe impl Sync for SubclassingAdapter {} + impl Drop for SubclassingAdapter { fn drop(&mut self) { let prev_class = self.associated.ivars().prev_class; From 117379a31b9f98d68ecde546958e03607b80bb9f Mon Sep 17 00:00:00 2001 From: jshin-tacticalid Date: Tue, 31 Mar 2026 14:34:56 -0400 Subject: [PATCH 2/3] feat(windows): add Send + Sync for SubclassingAdapter, remove visibility panic MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two changes: 1. Add unsafe Send + Sync implementations for SubclassingAdapter, matching the macOS change. The adapter is always accessed on the UI thread; WM_GETOBJECT and focus callbacks only fire on the window's thread. 2. Remove the IsWindowVisible panic in SubclassingAdapter::new(). Some frameworks (notably iced) process adapter initialization after the window is already shown — this is normal lifecycle behavior, not an error. Window subclassing works fine on visible windows. --- platforms/windows/src/subclass.rs | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/platforms/windows/src/subclass.rs b/platforms/windows/src/subclass.rs index 0f93418ba..d06445941 100644 --- a/platforms/windows/src/subclass.rs +++ b/platforms/windows/src/subclass.rs @@ -156,18 +156,15 @@ impl SubclassingAdapter { /// handler will always be called on that thread. The action handler /// may or may not be called on that thread. /// - /// # Panics + /// # Note /// - /// Panics if the window is already visible. + /// Ideally, this should be called before the window is shown for the first + /// time, but it will still work if the window is already visible. pub fn new( hwnd: HWND, activation_handler: impl 'static + ActivationHandler, action_handler: impl 'static + ActionHandler + Send, ) -> Self { - if unsafe { IsWindowVisible(hwnd) }.into() { - panic!("The AccessKit Windows subclassing adapter must be created before the window is shown (made visible) for the first time."); - } - let mut r#impl = SubclassImpl::new(hwnd, activation_handler, action_handler); r#impl.install(); Self(r#impl) @@ -195,6 +192,13 @@ impl SubclassingAdapter { } } +// SAFETY: SubclassingAdapter is always created and accessed on the UI thread. +// The Send + Sync bounds are required by iced's Proxy / Notifier trait, +// which wraps the adapter in a channel — but actual accessibility callbacks +// (WM_GETOBJECT, focus changes) only ever fire on the window's thread. +unsafe impl Send for SubclassingAdapter {} +unsafe impl Sync for SubclassingAdapter {} + impl Drop for SubclassingAdapter { fn drop(&mut self) { self.0.uninstall(); From 292a7dd5ac862803b176a216858ba078c6b0a2f2 Mon Sep 17 00:00:00 2001 From: jshin-tacticalid Date: Tue, 31 Mar 2026 14:35:02 -0400 Subject: [PATCH 3/3] fix(winit): remove visibility panic, use dyn Window in Windows adapter 1. Remove the panic when the window is already visible at adapter creation time. Update doc comment from "# Panics" to "# Note" explaining that pre-visibility creation is preferred but not required. 2. Change Windows platform adapter to accept &dyn Window instead of &Window for consistency with the trait-based API. --- platforms/winit/src/lib.rs | 10 ++++------ platforms/winit/src/platform_impl/windows.rs | 2 +- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/platforms/winit/src/lib.rs b/platforms/winit/src/lib.rs index a67605c9d..fadc3b474 100644 --- a/platforms/winit/src/lib.rs +++ b/platforms/winit/src/lib.rs @@ -97,9 +97,11 @@ impl Adapter { /// the first update. However, remember that each of these handlers may be /// called on any thread, depending on the underlying platform adapter. /// - /// # Panics + /// # Note /// - /// Panics if the window is already visible. + /// Ideally, this should be called before the window is shown for the first + /// time, but it will still work if the window is already visible (the + /// platform adapter will attach to the existing window). pub fn with_direct_handlers( event_loop: &dyn ActiveEventLoop, window: &dyn Window, @@ -107,10 +109,6 @@ impl Adapter { action_handler: impl 'static + ActionHandler + Send, deactivation_handler: impl 'static + DeactivationHandler + Send, ) -> Self { - if window.is_visible() == Some(true) { - panic!("The AccessKit winit adapter must be created before the window is shown (made visible) for the first time."); - } - let inner = platform_impl::Adapter::new( event_loop, window, diff --git a/platforms/winit/src/platform_impl/windows.rs b/platforms/winit/src/platform_impl/windows.rs index 84c7c1420..135af7836 100644 --- a/platforms/winit/src/platform_impl/windows.rs +++ b/platforms/winit/src/platform_impl/windows.rs @@ -17,7 +17,7 @@ pub struct Adapter { impl Adapter { pub fn new( _event_loop: &dyn ActiveEventLoop, - window: &Window, + window: &dyn Window, activation_handler: impl 'static + ActivationHandler, action_handler: impl 'static + ActionHandler + Send, _deactivation_handler: impl 'static + DeactivationHandler,