From 689db5180e4d2a30293a17ba9fe93cefd34edc51 Mon Sep 17 00:00:00 2001 From: Adrien Prokopowicz <6529475+prokopyl@users.noreply.github.com> Date: Sun, 25 Oct 2026 07:11:43 +0100 Subject: [PATCH 1/4] wip --- src/platform/win/window.rs | 8 +-- src/platform/win/window_state.rs | 28 ++++----- src/wrappers/win32/timer.rs | 89 ++++++++++++++++++++--------- src/wrappers/win32/window/handle.rs | 9 --- 4 files changed, 77 insertions(+), 57 deletions(-) diff --git a/src/platform/win/window.rs b/src/platform/win/window.rs index 99353128..30d8b032 100644 --- a/src/platform/win/window.rs +++ b/src/platform/win/window.rs @@ -14,7 +14,7 @@ use super::drop_target::DropTarget; use super::*; use crate::handler::WindowHandlerBuilder; use crate::host::Host; -use crate::platform::win::window_state::{WindowSharedState, WindowState}; +use crate::platform::win::window_state::{RedrawTimer, WindowSharedState, WindowState}; use crate::platform::PlatformError; use crate::utils::SizingStrategy; use crate::window::WindowInitializer; @@ -22,7 +22,7 @@ use crate::wrappers::win32::cursor::SystemCursor; use crate::wrappers::win32::window::*; use crate::wrappers::win32::{ ole_initialize, run_thread_message_loop_until, Dpi, DpiAwarenessGuard, LibraryModule, Rect, - TimerId, WindowStyle, + TimerId, TimerType, WindowStyle, }; use crate::{Event, MouseButton, MouseEvent, ScrollDelta, WindowEvent, WindowSize}; @@ -626,7 +626,7 @@ unsafe fn wnd_proc_inner( WM_TIMER => { let timer_id = TimerId::from_raw(wparam)?; - if window_state.redraw_timer.matches_id(timer_id) { + if timer_id == RedrawTimer::ID { if !window_state.redraw_timer.is_running() { return None; }; @@ -634,7 +634,7 @@ unsafe fn wnd_proc_inner( return Some(0); } - match window_state.shared.delayed_redraw_timers.remove_if_exists(window, timer_id) { + match window_state.shared.delayed_redraw_timers.remove_if_exists(timer_id) { Ok(false) => {} Err(e) => { warn!("Could not remove timer: {}", e); diff --git a/src/platform/win/window_state.rs b/src/platform/win/window_state.rs index 4e2c6e78..3748d998 100644 --- a/src/platform/win/window_state.rs +++ b/src/platform/win/window_state.rs @@ -9,7 +9,7 @@ use crate::wrappers::win32::cursor::SystemCursor; use crate::wrappers::win32::h_instance::HInstance; use crate::wrappers::win32::window::{HWnd, PostMessageExt}; use crate::wrappers::win32::{ - Dpi, DpiAwarenessGuard, ExtendedUser32, LibraryModule, TimerList, TimerSlot, + Dpi, DpiAwarenessGuard, ExtendedUser32, LibraryModule, TimerId, TimerList, TimerSlot, TimerType, }; use crate::{MouseCursor, WindowSize}; use raw_window_handle::{DisplayHandle, Win32WindowHandle}; @@ -18,7 +18,12 @@ use std::num::NonZeroIsize; use std::rc::Rc; use std::time::Duration; -const REDRAW_TIMER_DELAY_MSEC: u32 = 15; +pub(crate) struct RedrawTimer; + +impl TimerType for RedrawTimer { + const ID: TimerId = TimerId::from_const(0x42691); + const TIMEOUT_MSEC: u32 = 15; +} /// All data associated with the window. pub(crate) struct WindowState { @@ -31,7 +36,7 @@ pub(crate) struct WindowState { pub user32: LibraryModule, pub shared: Rc, - pub(crate) redraw_timer: TimerSlot, + pub(crate) redraw_timer: TimerSlot, pub redraw_requested: Cell, #[cfg(feature = "opengl")] @@ -131,17 +136,17 @@ impl WindowState { pub fn request_redraw(&self) { self.redraw_requested.set(true); - self.redraw_timer.start_if_not_running(REDRAW_TIMER_DELAY_MSEC); + self.redraw_timer.start_if_not_running(); } pub fn setup_redraw_request_for_next_frame(&self) { let should_redraw_next_frame = self.redraw_requested.take(); - self.redraw_timer.set_running(should_redraw_next_frame, REDRAW_TIMER_DELAY_MSEC); + self.redraw_timer.set_running(should_redraw_next_frame); } pub fn request_redraw_after(&self, duration: Duration) { - if let Err(e) = self.shared.delayed_redraw_timers.add_new_timer(self.hwnd, duration) { + if let Err(e) = self.shared.delayed_redraw_timers.add_new_timer(duration) { crate::warn!("Request Redraw failed: Could not add timer: {}", e) } } @@ -153,7 +158,7 @@ impl WindowState { #[inline] pub fn create_timer(&self, duration: Duration) -> Result { - Ok(self.shared.user_timers.add_new_timer(self.hwnd, duration)?) + Ok(self.shared.user_timers.add_new_timer(duration)?) } } @@ -265,15 +270,6 @@ impl WindowSharedState { } } -impl Drop for WindowSharedState { - fn drop(&mut self) { - if let Some(hwnd) = self.hwnd.get() { - self.user_timers.stop_and_destroy_all(hwnd); - self.delayed_redraw_timers.stop_and_destroy_all(hwnd); - } - } -} - struct Guard<'a>(&'a Cell); impl<'a> Drop for Guard<'a> { fn drop(&mut self) { diff --git a/src/wrappers/win32/timer.rs b/src/wrappers/win32/timer.rs index 44d1456b..8dcc7398 100644 --- a/src/wrappers/win32/timer.rs +++ b/src/wrappers/win32/timer.rs @@ -1,9 +1,12 @@ use crate::wrappers::win32::window::HWnd; use std::cell::{Cell, RefCell}; +use std::marker::PhantomData; use std::num::NonZeroUsize; +use std::ptr::null_mut; use std::time::Duration; use windows_core::Error; -use windows_sys::Win32::Foundation::WPARAM; +use windows_sys::Win32::Foundation::{FALSE, WPARAM}; +use windows_sys::Win32::UI::WindowsAndMessaging::{KillTimer, SetTimer}; #[derive(Copy, Clone, Eq, PartialEq, Debug)] pub struct TimerId(NonZeroUsize); @@ -16,58 +19,62 @@ impl TimerId { pub fn as_raw(&self) -> usize { self.0.get() } + + pub const fn from_const(value: usize) -> Self { + let Some(value) = NonZeroUsize::new(value) else { unreachable!() }; + Self(value) + } +} + +pub trait TimerType { + const ID: TimerId; + const TIMEOUT_MSEC: u32; } #[derive(PartialEq, Eq)] -pub struct TimerSlot { - id: Cell>, +pub struct TimerSlot { + running: Cell, hwnd: HWnd, + _timer: PhantomData, } -impl TimerSlot { +impl TimerSlot { pub fn empty(hwnd: HWnd) -> Self { - Self { hwnd, id: None.into() } + Self { hwnd, running: false.into(), _timer: PhantomData } } pub fn is_running(&self) -> bool { - self.id.get().is_some() + self.running.get() } - pub fn start_if_not_running(&self, timeout_msec: u32) { + pub fn start_if_not_running(&self) { if !self.is_running() { - self.start(timeout_msec); + self.start() } } - fn start(&self, timeout_msec: u32) { - match self.hwnd.create_timer(timeout_msec) { - Ok(timer_id) => self.id.set(Some(timer_id)), + fn start(&self) { + match self.hwnd.reset_timer(T::ID, T::TIMEOUT_MSEC) { + Ok(()) => self.running.set(true), Err(e) => crate::warn!("Failed to start timer: {}", e), } } - pub fn set_running(&self, running: bool, timeout_msec: u32) { + pub fn set_running(&self, running: bool) { match (running, self.is_running()) { (true, true) | (false, false) => (), // Nothing to do (false, true) => self.kill(), - (true, false) => self.start(timeout_msec), + (true, false) => self.start(), } } pub fn kill(&self) { - if let Some(timer_id) = self.id.take() { - if let Err(e) = self.hwnd.kill_timer(timer_id) { + if self.running.take() { + if let Err(e) = self.hwnd.kill_timer(T::ID) { crate::warn!("Failed to kill timer: {}", e); } } } - - pub fn matches_id(&self, other: TimerId) -> bool { - match self.id.get() { - None => false, - Some(id) => id == other, - } - } } pub struct TimerList { @@ -79,9 +86,9 @@ impl TimerList { Self { timers: Vec::new().into() } } - pub fn add_new_timer(&self, window: HWnd, timeout: Duration) -> Result { + pub fn add_new_timer(&self, timeout: Duration) -> Result { let timeout_msec = timeout.as_millis().try_into().unwrap_or(u32::MAX); - let new_timer_id = window.create_timer(timeout_msec)?; + let new_timer_id = create_thread_timer(timeout_msec)?; self.timers.borrow_mut().push(new_timer_id); Ok(new_timer_id) } @@ -90,12 +97,12 @@ impl TimerList { self.timers.borrow().contains(&timer_id) } - pub fn remove_if_exists(&self, window: HWnd, id: TimerId) -> Result { + pub fn remove_if_exists(&self, id: TimerId) -> Result { if !self.pop_if_exists(id) { return Ok(false); }; - window.kill_timer(id)?; + kill_thread_timer(id)?; Ok(true) } @@ -111,11 +118,37 @@ impl TimerList { self.timers.borrow_mut().pop() } - pub fn stop_and_destroy_all(&self, window: HWnd) { + fn stop_and_destroy_all(&self) { while let Some(timer) = self.pop() { - if let Err(e) = window.kill_timer(timer) { + if let Err(e) = kill_thread_timer(timer) { crate::warn!("Failed to kill timer: {}", e); } } } } + +impl Drop for TimerList { + fn drop(&mut self) { + self.stop_and_destroy_all() + } +} + +fn create_thread_timer(elapse: u32) -> windows_core::Result { + let result = unsafe { SetTimer(null_mut(), 0, elapse, None) }; + + let Some(id) = TimerId::from_raw(result) else { + return Err(Error::from_thread()); + }; + + Ok(id) +} + +fn kill_thread_timer(timer_id: TimerId) -> windows_core::Result<()> { + let result = unsafe { KillTimer(null_mut(), timer_id.as_raw()) }; + + if result == FALSE { + return Err(Error::from_thread()); + } + + Ok(()) +} diff --git a/src/wrappers/win32/window/handle.rs b/src/wrappers/win32/window/handle.rs index 303446c9..72d855b7 100644 --- a/src/wrappers/win32/window/handle.rs +++ b/src/wrappers/win32/window/handle.rs @@ -222,15 +222,6 @@ impl HWnd { Ok(()) } - pub fn create_timer(&self, elapse: u32) -> Result { - let result = unsafe { SetTimer(null_mut(), 0, elapse, None) }; - let timer_id = TimerId::from_raw(result).ok_or_else(Error::from_thread)?; - - self.reset_timer(timer_id, elapse)?; - - Ok(timer_id) - } - pub fn reset_timer(&self, timer_id: TimerId, elapse: u32) -> Result<()> { let result = unsafe { SetTimer(self.as_raw(), timer_id.as_raw(), elapse, None) }; From bce9f741b235c4cc5b35093b033cc09256387299 Mon Sep 17 00:00:00 2001 From: Adrien Prokopowicz <6529475+prokopyl@users.noreply.github.com> Date: Sun, 25 Oct 2026 15:24:14 +0100 Subject: [PATCH 2/4] wip2 --- src/platform/win/window.rs | 45 ++++++------- src/platform/win/window_state.rs | 14 ++-- src/wrappers/win32/dpi.rs | 4 ++ src/wrappers/win32/style.rs | 4 ++ src/wrappers/win32/timer.rs | 111 +++++++++++++++++++++++++------ 5 files changed, 126 insertions(+), 52 deletions(-) diff --git a/src/platform/win/window.rs b/src/platform/win/window.rs index 30d8b032..4a47047d 100644 --- a/src/platform/win/window.rs +++ b/src/platform/win/window.rs @@ -359,12 +359,6 @@ impl BaseviewWindow { handler.poll(); } - pub(crate) fn handle_timer(&self, timer: &TimerHandle) { - let Some(handler) = self.handler.get() else { return }; - - handler.on_timer(timer.into()); - } - pub(crate) fn handle_event(&self, event: Event) -> EventStatus { let Some(handler) = self.handler.get() else { return EventStatus::Ignored; @@ -372,6 +366,26 @@ impl BaseviewWindow { handler.on_event(event) } + + pub(crate) fn handle_delayed_redraw_wm_timer(&self, id: TimerId) { + match self.shared_state.delayed_redraw_timers.remove_if_exists(id) { + Ok(false) => {} + Err(e) => { + warn!("Could not remove timer: {}", e); + } + Ok(true) => { + self.window_state.request_redraw(); + } + } + } + + pub(crate) fn handle_user_wm_timer(&self, id: TimerId) { + if self.shared_state.user_timers.exists(id) { + let Some(handler) = self.handler.get() else { return }; + + handler.on_timer((&id).into()); + } + } } impl Drop for BaseviewWindow { @@ -634,24 +648,7 @@ unsafe fn wnd_proc_inner( return Some(0); } - match window_state.shared.delayed_redraw_timers.remove_if_exists(timer_id) { - Ok(false) => {} - Err(e) => { - warn!("Could not remove timer: {}", e); - return None; - } - Ok(true) => { - window_state.request_redraw(); - return Some(0); - } - } - - if window_state.shared.user_timers.exists(timer_id) { - window_bv.handle_timer(&timer_id); - Some(0) - } else { - None - } + None } WM_CLOSE => { window_bv.handle_event(Event::Window(WindowEvent::WillClose)); diff --git a/src/platform/win/window_state.rs b/src/platform/win/window_state.rs index 3748d998..395e6917 100644 --- a/src/platform/win/window_state.rs +++ b/src/platform/win/window_state.rs @@ -2,7 +2,7 @@ use crate::dpi::{PhysicalSize, Size}; use crate::platform::win::dpi::DpiScalingStrategy; use crate::platform::win::keyboard::KeyboardState; use crate::platform::win::waker::WindowWakerSource; -use crate::platform::{PlatformHandle, TimerHandle, WindowWaker}; +use crate::platform::{BaseviewWindow, PlatformHandle, TimerHandle, WindowWaker}; use crate::utils::SizingStrategy; use crate::window::WindowInitializer; use crate::wrappers::win32::cursor::SystemCursor; @@ -146,7 +146,7 @@ impl WindowState { } pub fn request_redraw_after(&self, duration: Duration) { - if let Err(e) = self.shared.delayed_redraw_timers.add_new_timer(duration) { + if let Err(e) = self.shared.delayed_redraw_timers.add_new_timer(self.hwnd, duration) { crate::warn!("Request Redraw failed: Could not add timer: {}", e) } } @@ -158,7 +158,7 @@ impl WindowState { #[inline] pub fn create_timer(&self, duration: Duration) -> Result { - Ok(self.shared.user_timers.add_new_timer(duration)?) + Ok(self.shared.user_timers.add_new_timer(self.hwnd, duration)?) } } @@ -185,11 +185,15 @@ impl WindowSharedState { let state = Self { sizing_strategy: SizingStrategy::from_settings(&init.settings), user32, + hwnd: None.into(), // Internal state is_alive: true.into(), resize_host_originated: false.into(), destroy_host_originated: false.into(), + delayed_redraw_timers: TimerList::new(BaseviewWindow::handle_delayed_redraw_wm_timer), + user_timers: TimerList::new(BaseviewWindow::handle_user_wm_timer), + window_waker_source: WindowWakerSource::new(), // Overriden by init() below parented: false.into(), @@ -197,10 +201,6 @@ impl WindowSharedState { current_size: init.settings.size.to_physical(1.0).into(), fallback_scale_factor: init.settings.fallback_scale_factor.into(), dpi_scaling_strategy: DpiScalingStrategy::default().into(), - delayed_redraw_timers: TimerList::new(), - user_timers: TimerList::new(), - window_waker_source: WindowWakerSource::new(), - hwnd: None.into(), }; state.init(init); diff --git a/src/wrappers/win32/dpi.rs b/src/wrappers/win32/dpi.rs index 079974d3..aadb950e 100644 --- a/src/wrappers/win32/dpi.rs +++ b/src/wrappers/win32/dpi.rs @@ -265,6 +265,10 @@ impl<'a> DpiAwarenessGuard<'a> { } } + pub fn dummy() -> Self { + Self { inner: None } + } + pub fn with_guard_optional( user32: &'a ExtendedUser32, strategy: DpiScalingStrategy, handler: impl FnOnce() -> T, ) -> T { diff --git a/src/wrappers/win32/style.rs b/src/wrappers/win32/style.rs index 9abf4bb0..18cee6c3 100644 --- a/src/wrappers/win32/style.rs +++ b/src/wrappers/win32/style.rs @@ -24,4 +24,8 @@ impl WindowStyle { style } + + pub const fn dummy() -> Self { + Self { style: 0, style_ex: 0 } + } } diff --git a/src/wrappers/win32/timer.rs b/src/wrappers/win32/timer.rs index 8dcc7398..b51c209d 100644 --- a/src/wrappers/win32/timer.rs +++ b/src/wrappers/win32/timer.rs @@ -1,11 +1,16 @@ -use crate::wrappers::win32::window::HWnd; +use crate::platform::{BaseviewWindow, PlatformError}; +use crate::wrappers::win32::window::{create_window, HWnd, WindowImpl}; +use crate::wrappers::win32::{DpiAwarenessGuard, WindowStyle}; +use dpi::PhysicalSize; use std::cell::{Cell, RefCell}; use std::marker::PhantomData; use std::num::NonZeroUsize; use std::ptr::null_mut; +use std::rc::Rc; use std::time::Duration; -use windows_core::Error; -use windows_sys::Win32::Foundation::{FALSE, WPARAM}; +use windows::Win32::UI::WindowsAndMessaging::WM_TIMER; +use windows_core::{Error, HSTRING}; +use windows_sys::Win32::Foundation::{FALSE, LPARAM, LRESULT, WPARAM}; use windows_sys::Win32::UI::WindowsAndMessaging::{KillTimer, SetTimer}; #[derive(Copy, Clone, Eq, PartialEq, Debug)] @@ -79,16 +84,56 @@ impl TimerSlot { pub struct TimerList { timers: RefCell>, + timer_window: Cell>, + timer_fn: fn(&BaseviewWindow, TimerId), } impl TimerList { - pub fn new() -> Self { - Self { timers: Vec::new().into() } + pub fn new(timer_fn: fn(&BaseviewWindow, TimerId)) -> Self { + Self { timers: Vec::new().into(), timer_window: None.into(), timer_fn } } - pub fn add_new_timer(&self, timeout: Duration) -> Result { + fn get_or_create_timer_window(&self, baseview_window: HWnd) -> Result { + if let Some(timer_window) = self.timer_window.get() { + return Ok(timer_window); + } + + let timer_fn = self.timer_fn; + let timer_window = create_window( + &HSTRING::new(), + WindowStyle::dummy(), + PhysicalSize::new(1, 1), + None, + &DpiAwarenessGuard::dummy(), + move |_| TimerWindow { baseview_window, timer_fn }, + )?; + self.timer_window.set(Some(timer_window)); + + Ok(timer_window) + } + + pub fn get_new_timer_id(&self) -> TimerId { + let Some(mut id) = NonZeroUsize::new(1) else { unreachable!() }; + + let timers = self.timers.borrow(); + + while timers.contains(&TimerId(id)) { + let Some(new_id) = id.checked_add(1) else { panic!("Too many timers") }; + id = new_id; + } + + TimerId(id) + } + + pub fn add_new_timer( + &self, baseview_window: HWnd, timeout: Duration, + ) -> Result { let timeout_msec = timeout.as_millis().try_into().unwrap_or(u32::MAX); - let new_timer_id = create_thread_timer(timeout_msec)?; + let timer_window = self.get_or_create_timer_window(baseview_window)?; + let new_timer_id = self.get_new_timer_id(); + + timer_window.reset_timer(new_timer_id, timeout_msec)?; + self.timers.borrow_mut().push(new_timer_id); Ok(new_timer_id) } @@ -102,7 +147,8 @@ impl TimerList { return Ok(false); }; - kill_thread_timer(id)?; + let Some(window) = self.timer_window.get() else { unreachable!() }; + window.kill_timer(id)?; Ok(true) } @@ -119,11 +165,16 @@ impl TimerList { } fn stop_and_destroy_all(&self) { + let Some(window) = self.timer_window.get() else { return }; + while let Some(timer) = self.pop() { - if let Err(e) = kill_thread_timer(timer) { + if let Err(e) = window.kill_timer(timer) { crate::warn!("Failed to kill timer: {}", e); } } + + let _ = window.destroy(); + self.timer_window.set(None); } } @@ -133,22 +184,40 @@ impl Drop for TimerList { } } -fn create_thread_timer(elapse: u32) -> windows_core::Result { - let result = unsafe { SetTimer(null_mut(), 0, elapse, None) }; - - let Some(id) = TimerId::from_raw(result) else { - return Err(Error::from_thread()); - }; +struct TimerWindow { + baseview_window: HWnd, + timer_fn: fn(&BaseviewWindow, TimerId), +} - Ok(id) +impl TimerWindow { + fn get_baseview_window_state(&self) -> Rc { + todo!() + } } -fn kill_thread_timer(timer_id: TimerId) -> windows_core::Result<()> { - let result = unsafe { KillTimer(null_mut(), timer_id.as_raw()) }; +impl WindowImpl for TimerWindow { + fn non_client_create(&self, _: HWnd) -> Result<(), PlatformError> { + Ok(()) + } + + fn after_create(&self, _: HWnd) -> Result<(), PlatformError> { + Ok(()) + } + + unsafe fn handle_message( + &self, _: HWnd, message_code: u32, wparam: WPARAM, _: LPARAM, + ) -> Option { + if message_code != WM_TIMER { + return None; + } + + let timer_id = TimerId::from_raw(wparam)?; + let window_state = self.get_baseview_window_state(); + + (self.timer_fn)(&window_state, timer_id); - if result == FALSE { - return Err(Error::from_thread()); + Some(0) } - Ok(()) + fn before_destroy(&self, _: HWnd) {} } From 2197094edd3337f7d8faccc606f56425e138db4a Mon Sep 17 00:00:00 2001 From: Adrien Prokopowicz <6529475+prokopyl@users.noreply.github.com> Date: Sun, 25 Oct 2026 18:21:11 +0100 Subject: [PATCH 3/4] wip --- src/wrappers/win32/timer.rs | 16 +++++++--------- src/wrappers/win32/window.rs | 17 +++++++++++++++++ 2 files changed, 24 insertions(+), 9 deletions(-) diff --git a/src/wrappers/win32/timer.rs b/src/wrappers/win32/timer.rs index b51c209d..5a9c4d32 100644 --- a/src/wrappers/win32/timer.rs +++ b/src/wrappers/win32/timer.rs @@ -1,5 +1,5 @@ use crate::platform::{BaseviewWindow, PlatformError}; -use crate::wrappers::win32::window::{create_window, HWnd, WindowImpl}; +use crate::wrappers::win32::window::{create_window, use_window, HWnd, WindowImpl}; use crate::wrappers::win32::{DpiAwarenessGuard, WindowStyle}; use dpi::PhysicalSize; use std::cell::{Cell, RefCell}; @@ -189,12 +189,6 @@ struct TimerWindow { timer_fn: fn(&BaseviewWindow, TimerId), } -impl TimerWindow { - fn get_baseview_window_state(&self) -> Rc { - todo!() - } -} - impl WindowImpl for TimerWindow { fn non_client_create(&self, _: HWnd) -> Result<(), PlatformError> { Ok(()) @@ -212,9 +206,13 @@ impl WindowImpl for TimerWindow { } let timer_id = TimerId::from_raw(wparam)?; - let window_state = self.get_baseview_window_state(); - (self.timer_fn)(&window_state, timer_id); + // SAFETY: baseview_window is of type BaseviewWindow + unsafe { + use_window::(self.baseview_window, |hwnd| { + (self.timer_fn)(hwnd, timer_id) + }) + }; Some(0) } diff --git a/src/wrappers/win32/window.rs b/src/wrappers/win32/window.rs index 53e3bb6e..aca88e20 100644 --- a/src/wrappers/win32/window.rs +++ b/src/wrappers/win32/window.rs @@ -5,8 +5,10 @@ mod window_class; #[cfg(feature = "opengl")] mod dc; + #[cfg(feature = "opengl")] pub use dc::*; +use std::mem::ManuallyDrop; #[cfg(feature = "opengl")] mod wgl; #[cfg(feature = "opengl")] @@ -55,6 +57,21 @@ pub trait WindowImpl: 'static { fn before_destroy(&self, window: HWnd); } +/// # Safety +/// +/// Must only be called on a window created with create_window, and W must match the inner window type +pub unsafe fn use_window(hwnd: HWnd, handler: impl FnOnce(&W)) { + let Some(raw_data) = hwnd.get_userdata_ptr::>() else { return }; + // This is actually borrowed from the window itself + let raw = ManuallyDrop::new(Rc::from_raw(raw_data.as_ptr())); + + // We keep this alive for as long as inner() runs, to guard against possible re-entrancy + let window_data = Rc::clone(&raw); + if let Some(inner) = window_data.inner() { + handler(inner); + } +} + /// Creates a window from the given settings, with a given [`WindowImpl`] type to handle the message, /// and an initializer function for that type. /// From 9ba0a71b3822fab5bdf2320a6fe5de838ea618f9 Mon Sep 17 00:00:00 2001 From: Adrien Prokopowicz <6529475+prokopyl@users.noreply.github.com> Date: Sun, 25 Oct 2026 18:27:40 +0100 Subject: [PATCH 4/4] wip --- src/wrappers/win32/timer.rs | 5 +---- src/wrappers/win32/window.rs | 2 +- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/src/wrappers/win32/timer.rs b/src/wrappers/win32/timer.rs index 5a9c4d32..5e8406dc 100644 --- a/src/wrappers/win32/timer.rs +++ b/src/wrappers/win32/timer.rs @@ -5,13 +5,10 @@ use dpi::PhysicalSize; use std::cell::{Cell, RefCell}; use std::marker::PhantomData; use std::num::NonZeroUsize; -use std::ptr::null_mut; -use std::rc::Rc; use std::time::Duration; use windows::Win32::UI::WindowsAndMessaging::WM_TIMER; use windows_core::{Error, HSTRING}; -use windows_sys::Win32::Foundation::{FALSE, LPARAM, LRESULT, WPARAM}; -use windows_sys::Win32::UI::WindowsAndMessaging::{KillTimer, SetTimer}; +use windows_sys::Win32::Foundation::{LPARAM, LRESULT, WPARAM}; #[derive(Copy, Clone, Eq, PartialEq, Debug)] pub struct TimerId(NonZeroUsize); diff --git a/src/wrappers/win32/window.rs b/src/wrappers/win32/window.rs index aca88e20..da2cb8a2 100644 --- a/src/wrappers/win32/window.rs +++ b/src/wrappers/win32/window.rs @@ -59,7 +59,7 @@ pub trait WindowImpl: 'static { /// # Safety /// -/// Must only be called on a window created with create_window, and W must match the inner window type +/// Must only be called on a window created with create_window, and W must match the inner window type. pub unsafe fn use_window(hwnd: HWnd, handler: impl FnOnce(&W)) { let Some(raw_data) = hwnd.get_userdata_ptr::>() else { return }; // This is actually borrowed from the window itself