1
0
Fork 0

Replace Rcs by reference to entire WindowState

This removes the need to pass through individual Rcs at the cost of
adding more lifetime parameters to the internals of the shared `Window`
struct and requiring an `Option` for the handler.
This commit is contained in:
Robbert van der Helm 2023-01-01 23:38:51 +01:00
parent c10ca6b40f
commit be5238ec46
2 changed files with 67 additions and 72 deletions

View file

@ -169,7 +169,7 @@ unsafe fn wnd_proc_inner(
) -> Option<LRESULT> { ) -> Option<LRESULT> {
match msg { match msg {
WM_MOUSEMOVE => { WM_MOUSEMOVE => {
let mut window = window_state.create_window(hwnd); let mut window = window_state.create_window();
let mut window = crate::Window::new(&mut window); let mut window = crate::Window::new(&mut window);
let x = (lparam & 0xFFFF) as i16 as i32; let x = (lparam & 0xFFFF) as i16 as i32;
@ -185,12 +185,12 @@ unsafe fn wnd_proc_inner(
.get_modifiers_from_mouse_wparam(wparam), .get_modifiers_from_mouse_wparam(wparam),
}); });
window_state.handler.borrow_mut().on_event(&mut window, event); window_state.handler.borrow_mut().as_mut().unwrap().on_event(&mut window, event);
Some(0) Some(0)
} }
WM_MOUSEWHEEL | WM_MOUSEHWHEEL => { WM_MOUSEWHEEL | WM_MOUSEHWHEEL => {
let mut window = window_state.create_window(hwnd); let mut window = window_state.create_window();
let mut window = crate::Window::new(&mut window); let mut window = crate::Window::new(&mut window);
let value = (wparam >> 16) as i16; let value = (wparam >> 16) as i16;
@ -209,13 +209,13 @@ unsafe fn wnd_proc_inner(
.get_modifiers_from_mouse_wparam(wparam), .get_modifiers_from_mouse_wparam(wparam),
}); });
window_state.handler.borrow_mut().on_event(&mut window, event); window_state.handler.borrow_mut().as_mut().unwrap().on_event(&mut window, event);
Some(0) Some(0)
} }
WM_LBUTTONDOWN | WM_LBUTTONUP | WM_MBUTTONDOWN | WM_MBUTTONUP | WM_RBUTTONDOWN WM_LBUTTONDOWN | WM_LBUTTONUP | WM_MBUTTONDOWN | WM_MBUTTONUP | WM_RBUTTONDOWN
| WM_RBUTTONUP | WM_XBUTTONDOWN | WM_XBUTTONUP => { | WM_RBUTTONUP | WM_XBUTTONDOWN | WM_XBUTTONUP => {
let mut window = window_state.create_window(hwnd); let mut window = window_state.create_window();
let mut window = crate::Window::new(&mut window); let mut window = crate::Window::new(&mut window);
let mut mouse_button_counter = window_state.mouse_button_counter.get(); let mut mouse_button_counter = window_state.mouse_button_counter.get();
@ -268,17 +268,22 @@ unsafe fn wnd_proc_inner(
window_state.mouse_button_counter.set(mouse_button_counter); window_state.mouse_button_counter.set(mouse_button_counter);
window_state.handler.borrow_mut().on_event(&mut window, Event::Mouse(event)); window_state
.handler
.borrow_mut()
.as_mut()
.unwrap()
.on_event(&mut window, Event::Mouse(event));
} }
None None
} }
WM_TIMER => { WM_TIMER => {
let mut window = window_state.create_window(hwnd); let mut window = window_state.create_window();
let mut window = crate::Window::new(&mut window); let mut window = crate::Window::new(&mut window);
if wparam == WIN_FRAME_TIMER { if wparam == WIN_FRAME_TIMER {
window_state.handler.borrow_mut().on_frame(&mut window); window_state.handler.borrow_mut().as_mut().unwrap().on_frame(&mut window);
} }
Some(0) Some(0)
@ -286,12 +291,14 @@ unsafe fn wnd_proc_inner(
WM_CLOSE => { WM_CLOSE => {
// Make sure to release the borrow before the DefWindowProc call // Make sure to release the borrow before the DefWindowProc call
{ {
let mut window = window_state.create_window(hwnd); let mut window = window_state.create_window();
let mut window = crate::Window::new(&mut window); let mut window = crate::Window::new(&mut window);
window_state window_state
.handler .handler
.borrow_mut() .borrow_mut()
.as_mut()
.unwrap()
.on_event(&mut window, Event::Window(WindowEvent::WillClose)); .on_event(&mut window, Event::Window(WindowEvent::WillClose));
} }
@ -301,14 +308,19 @@ unsafe fn wnd_proc_inner(
} }
WM_CHAR | WM_SYSCHAR | WM_KEYDOWN | WM_SYSKEYDOWN | WM_KEYUP | WM_SYSKEYUP WM_CHAR | WM_SYSCHAR | WM_KEYDOWN | WM_SYSKEYDOWN | WM_KEYUP | WM_SYSKEYUP
| WM_INPUTLANGCHANGE => { | WM_INPUTLANGCHANGE => {
let mut window = window_state.create_window(hwnd); let mut window = window_state.create_window();
let mut window = crate::Window::new(&mut window); let mut window = crate::Window::new(&mut window);
let opt_event = let opt_event =
window_state.keyboard_state.borrow_mut().process_message(hwnd, msg, wparam, lparam); window_state.keyboard_state.borrow_mut().process_message(hwnd, msg, wparam, lparam);
if let Some(event) = opt_event { if let Some(event) = opt_event {
window_state.handler.borrow_mut().on_event(&mut window, Event::Keyboard(event)); window_state
.handler
.borrow_mut()
.as_mut()
.unwrap()
.on_event(&mut window, Event::Keyboard(event));
} }
if msg != WM_SYSKEYDOWN { if msg != WM_SYSKEYDOWN {
@ -318,7 +330,7 @@ unsafe fn wnd_proc_inner(
} }
} }
WM_SIZE => { WM_SIZE => {
let mut window = window_state.create_window(hwnd); let mut window = window_state.create_window();
let mut window = crate::Window::new(&mut window); let mut window = crate::Window::new(&mut window);
let width = (lparam & 0xFFFF) as u16 as u32; let width = (lparam & 0xFFFF) as u16 as u32;
@ -342,6 +354,8 @@ unsafe fn wnd_proc_inner(
window_state window_state
.handler .handler
.borrow_mut() .borrow_mut()
.as_mut()
.unwrap()
.on_event(&mut window, Event::Window(WindowEvent::Resized(new_window_info))); .on_event(&mut window, Event::Window(WindowEvent::Resized(new_window_info)));
None None
@ -433,13 +447,17 @@ unsafe fn unregister_wnd_class(wnd_class: ATOM) {
/// `handler` from indirectly triggering other events that would also need to be handled using /// `handler` from indirectly triggering other events that would also need to be handled using
/// `handler`. /// `handler`.
struct WindowState { struct WindowState {
hwnd: HWND, /// The HWND belonging to this window. The window's actual state is stored in the `WindowState`
/// struct associated with this HWND through `unsafe { GetWindowLongPtrW(self.hwnd,
/// GWLP_USERDATA) } as *const WindowState`.
pub hwnd: HWND,
window_class: ATOM, window_class: ATOM,
window_info: RefCell<WindowInfo>, window_info: RefCell<WindowInfo>,
_parent_handle: Option<ParentHandle>, _parent_handle: Option<ParentHandle>,
keyboard_state: RefCell<KeyboardState>, keyboard_state: RefCell<KeyboardState>,
mouse_button_counter: Cell<usize>, mouse_button_counter: Cell<usize>,
handler: RefCell<Box<dyn WindowHandler>>, // Initialized late so the `Window` can hold a reference to this `WindowState`
handler: RefCell<Option<Box<dyn WindowHandler>>>,
scale_policy: WindowScalePolicy, scale_policy: WindowScalePolicy,
dw_style: u32, dw_style: u32,
@ -448,25 +466,15 @@ struct WindowState {
/// handler requests a resize in response to a keyboard event, the window state will already be /// handler requests a resize in response to a keyboard event, the window state will already be
/// borrowed in `wnd_proc`. So the `resize()` function below cannot also mutably borrow that /// borrowed in `wnd_proc`. So the `resize()` function below cannot also mutably borrow that
/// window state at the same time. /// window state at the same time.
deferred_tasks: Rc<RefCell<VecDeque<WindowTask>>>, pub deferred_tasks: RefCell<VecDeque<WindowTask>>,
#[cfg(feature = "opengl")] #[cfg(feature = "opengl")]
gl_context: Rc<Option<GlContext>>, pub gl_context: Option<GlContext>,
} }
impl WindowState { impl WindowState {
#[cfg(not(feature = "opengl"))] fn create_window(&self) -> Window {
fn create_window(&self, hwnd: HWND) -> Window { Window { state: self }
Window { hwnd, deferred_tasks: self.deferred_tasks.clone() }
}
#[cfg(feature = "opengl")]
fn create_window(&self, hwnd: HWND) -> Window {
Window {
hwnd,
deferred_tasks: self.deferred_tasks.clone(),
gl_context: self.gl_context.clone(),
}
} }
/// Handle a deferred task as described in [`Self::deferred_tasks /// Handle a deferred task as described in [`Self::deferred_tasks
@ -506,20 +514,11 @@ enum WindowTask {
Resize(Size), Resize(Size),
} }
pub struct Window { pub struct Window<'a> {
/// The HWND belonging to this window. The window's actual state is stored in the `WindowState` state: &'a WindowState,
/// struct associated with this HWND through `unsafe { GetWindowLongPtrW(self.hwnd,
/// GWLP_USERDATA) } as *const WindowState`.
hwnd: HWND,
/// See [`WindowState::deferred_tasks`].
deferred_tasks: Rc<RefCell<VecDeque<WindowTask>>>,
#[cfg(feature = "opengl")]
gl_context: Rc<Option<GlContext>>,
} }
impl Window { impl Window<'_> {
pub fn open_parented<P, H, B>(parent: &P, options: WindowOpenOptions, build: B) -> WindowHandle pub fn open_parented<P, H, B>(parent: &P, options: WindowOpenOptions, build: B) -> WindowHandle
where where
P: HasRawWindowHandle, P: HasRawWindowHandle,
@ -635,31 +634,13 @@ impl Window {
// todo: manage error ^ // todo: manage error ^
#[cfg(feature = "opengl")] #[cfg(feature = "opengl")]
let gl_context: Rc<Option<GlContext>> = Rc::new(options.gl_config.map(|gl_config| { let gl_context: Option<GlContext> = options.gl_config.map(|gl_config| {
let mut handle = Win32Handle::empty(); let mut handle = Win32Handle::empty();
handle.hwnd = hwnd as *mut c_void; handle.hwnd = hwnd as *mut c_void;
let handle = RawWindowHandleWrapper { handle: RawWindowHandle::Win32(handle) }; let handle = RawWindowHandleWrapper { handle: RawWindowHandle::Win32(handle) };
GlContext::create(&handle, gl_config).expect("Could not create OpenGL context") GlContext::create(&handle, gl_config).expect("Could not create OpenGL context")
})); });
// The build closure shouldn't be enqueueing deferred tasks yet, but we'll try handling
// them just in case to avoid losing them
let deferred_tasks: Rc<RefCell<VecDeque<WindowTask>>> =
Rc::new(RefCell::new(VecDeque::new()));
#[cfg(not(feature = "opengl"))]
let handler = build(&mut crate::Window::new(&mut Window {
hwnd,
deferred_tasks: deferred_tasks.clone(),
}));
#[cfg(feature = "opengl")]
let handler = build(&mut crate::Window::new(&mut Window {
hwnd,
deferred_tasks: deferred_tasks.clone(),
gl_context: gl_context.clone(),
}));
let handler = RefCell::new(Box::new(handler));
let (parent_handle, window_handle) = ParentHandle::new(hwnd); let (parent_handle, window_handle) = ParentHandle::new(hwnd);
let parent_handle = if parented { Some(parent_handle) } else { None }; let parent_handle = if parented { Some(parent_handle) } else { None };
@ -671,21 +652,25 @@ impl Window {
_parent_handle: parent_handle, _parent_handle: parent_handle,
keyboard_state: RefCell::new(KeyboardState::new()), keyboard_state: RefCell::new(KeyboardState::new()),
mouse_button_counter: Cell::new(0), mouse_button_counter: Cell::new(0),
handler, // The Window refers to this `WindowState`, so this `handler` needs to be
// initialized later
handler: RefCell::new(None),
scale_policy: options.scale, scale_policy: options.scale,
dw_style: flags, dw_style: flags,
deferred_tasks: Rc::new(RefCell::new(VecDeque::with_capacity(4))), deferred_tasks: RefCell::new(VecDeque::with_capacity(4)),
#[cfg(feature = "opengl")] #[cfg(feature = "opengl")]
gl_context, gl_context,
}); });
// If the plugin did queue up tasks as part of the build handler, then we'll process let handler = {
// them now let mut window = window_state.create_window();
for task in deferred_tasks.borrow_mut().drain(..) { let mut window = crate::Window::new(&mut window);
window_state.handle_deferred_task(task);
} build(&mut window)
};
*window_state.handler.borrow_mut() = Some(Box::new(handler));
// Only works on Windows 10 unfortunately. // Only works on Windows 10 unfortunately.
SetProcessDpiAwarenessContext( SetProcessDpiAwarenessContext(
@ -744,7 +729,7 @@ impl Window {
pub fn close(&mut self) { pub fn close(&mut self) {
unsafe { unsafe {
PostMessageW(self.hwnd, BV_WINDOW_MUST_CLOSE, 0, 0); PostMessageW(self.state.hwnd, BV_WINDOW_MUST_CLOSE, 0, 0);
} }
} }
@ -752,19 +737,19 @@ impl Window {
// To avoid reentrant event handler calls we'll defer the actual resizing until after the // To avoid reentrant event handler calls we'll defer the actual resizing until after the
// event has been handled // event has been handled
let task = WindowTask::Resize(size); let task = WindowTask::Resize(size);
self.deferred_tasks.borrow_mut().push_back(task); self.state.deferred_tasks.borrow_mut().push_back(task);
} }
#[cfg(feature = "opengl")] #[cfg(feature = "opengl")]
pub fn gl_context(&self) -> Option<&GlContext> { pub fn gl_context(&self) -> Option<&GlContext> {
self.gl_context.as_ref().as_ref() self.state.gl_context.as_ref()
} }
} }
unsafe impl HasRawWindowHandle for Window { unsafe impl HasRawWindowHandle for Window<'_> {
fn raw_window_handle(&self) -> RawWindowHandle { fn raw_window_handle(&self) -> RawWindowHandle {
let mut handle = Win32Handle::empty(); let mut handle = Win32Handle::empty();
handle.hwnd = self.hwnd as *mut c_void; handle.hwnd = self.state.hwnd as *mut c_void;
RawWindowHandle::Win32(handle) RawWindowHandle::Win32(handle)
} }

View file

@ -54,12 +54,22 @@ pub trait WindowHandler {
} }
pub struct Window<'a> { pub struct Window<'a> {
#[cfg(target_os = "windows")]
window: &'a mut platform::Window<'a>,
#[cfg(not(target_os = "windows"))]
window: &'a mut platform::Window, window: &'a mut platform::Window,
// so that Window is !Send on all platforms // so that Window is !Send on all platforms
phantom: PhantomData<*mut ()>, phantom: PhantomData<*mut ()>,
} }
impl<'a> Window<'a> { impl<'a> Window<'a> {
#[cfg(target_os = "windows")]
pub(crate) fn new(window: &'a mut platform::Window<'a>) -> Window<'a> {
Window { window, phantom: PhantomData }
}
#[cfg(not(target_os = "windows"))]
pub(crate) fn new(window: &mut platform::Window) -> Window { pub(crate) fn new(window: &mut platform::Window) -> Window {
Window { window, phantom: PhantomData } Window { window, phantom: PhantomData }
} }