diff --git a/src/platform/macos/context.rs b/src/platform/macos/context.rs index 2961a4df..a8cfe27a 100644 --- a/src/platform/macos/context.rs +++ b/src/platform/macos/context.rs @@ -29,7 +29,8 @@ impl WindowContext { pub fn request_close(&self) { let Some(view) = self.view.load() else { return }; - BaseviewView::close(view.inner_ref()); + let Some(view) = view.inner_ref() else { return }; + BaseviewView::close(view); } pub fn has_focus(&self) -> bool { @@ -58,7 +59,7 @@ impl WindowContext { pub fn resize(&self, size: Size) { let Some(view) = self.view.load() else { return }; - let view = view.inner_ref(); + let Some(view) = view.inner_ref() else { return }; if view.inner.state.closed.get() { return; } @@ -82,7 +83,7 @@ impl WindowContext { #[cfg(feature = "opengl")] pub fn gl_context(&self) -> Option { - Some(crate::gl::GlContext::new(self.view.load()?.inner().gl_context.get()?.clone())) + Some(crate::gl::GlContext::new(self.view.load()?.inner()?.gl_context.get()?.clone())) } pub fn window_handle(&self) -> Option> { diff --git a/src/platform/macos/view.rs b/src/platform/macos/view.rs index e5cd28d6..f14587f3 100644 --- a/src/platform/macos/view.rs +++ b/src/platform/macos/view.rs @@ -106,14 +106,18 @@ impl BaseviewView { let timer_view = Weak::new(view.view); view.frame_timer.set(TimerHandle::new(0.015, move || { if let Some(view) = timer_view.load() { - Self::trigger_frame(view.inner_ref()); + if let Some(view) = view.inner_ref() { + Self::trigger_frame(view); + } } })); let notifier_view = Weak::new(view.view); let observer = NotificationCenterObserver::register_window_key_change(move |n| { if let Some(view) = notifier_view.load() { - BaseviewView::handle_notification(view.inner_ref(), n); + if let Some(view) = view.inner_ref() { + BaseviewView::handle_notification(view, n); + } } }); view.notification_center_observer.set(Some(observer)); diff --git a/src/platform/macos/window.rs b/src/platform/macos/window.rs index 51cf91b1..6d343005 100644 --- a/src/platform/macos/window.rs +++ b/src/platform/macos/window.rs @@ -18,6 +18,15 @@ pub struct WindowHandle { state: Rc, } +impl Drop for WindowHandle { + fn drop(&mut self) { + let Some(view) = self.view.load() else { return }; + let Some(view) = view.inner_ref() else { return }; + + BaseviewView::close(view); + } +} + impl WindowHandle { pub fn create_window(mut options: WindowOpenOptions, handler: WindowHandlerBuilder) -> Self { autoreleasepool(|_| { @@ -75,14 +84,6 @@ impl WindowHandle { NSApplication::sharedApplication(self.mtm).run(); } - pub fn close(&self) { - let Some(view) = self.view.load() else { - return; - }; - - BaseviewView::close(view.inner_ref()); - } - pub fn is_open(&self) -> bool { self.state.closed.get() } diff --git a/src/platform/win/window.rs b/src/platform/win/window.rs index dbfc32e3..83749fbe 100644 --- a/src/platform/win/window.rs +++ b/src/platform/win/window.rs @@ -1,14 +1,14 @@ use windows_core::{ComObject, Result, HSTRING}; use windows_sys::Win32::{ - Foundation::{HWND, LPARAM, LRESULT, RECT, WPARAM}, + Foundation::{LPARAM, LRESULT, RECT, WPARAM}, UI::{ Controls::WM_MOUSELEAVE, WindowsAndMessaging::{ - PostMessageW, HTCLIENT, WHEEL_DELTA, WM_CHAR, WM_CLOSE, WM_DPICHANGED, - WM_INPUTLANGCHANGE, WM_KEYDOWN, WM_KEYUP, WM_KILLFOCUS, WM_LBUTTONDOWN, WM_LBUTTONUP, - WM_MBUTTONDOWN, WM_MBUTTONUP, WM_MOUSEHWHEEL, WM_MOUSEMOVE, WM_MOUSEWHEEL, - WM_RBUTTONDOWN, WM_RBUTTONUP, WM_SETCURSOR, WM_SETFOCUS, WM_SIZE, WM_SYSCHAR, - WM_SYSKEYDOWN, WM_SYSKEYUP, WM_TIMER, WM_USER, WM_XBUTTONDOWN, WM_XBUTTONUP, + HTCLIENT, WHEEL_DELTA, WM_CHAR, WM_CLOSE, WM_DPICHANGED, WM_INPUTLANGCHANGE, + WM_KEYDOWN, WM_KEYUP, WM_KILLFOCUS, WM_LBUTTONDOWN, WM_LBUTTONUP, WM_MBUTTONDOWN, + WM_MBUTTONUP, WM_MOUSEHWHEEL, WM_MOUSEMOVE, WM_MOUSEWHEEL, WM_RBUTTONDOWN, + WM_RBUTTONUP, WM_SETCURSOR, WM_SETFOCUS, WM_SIZE, WM_SYSCHAR, WM_SYSKEYDOWN, + WM_SYSKEYUP, WM_TIMER, WM_USER, WM_XBUTTONDOWN, WM_XBUTTONUP, }, }, }; @@ -50,7 +50,7 @@ const WIN_FRAME_TIMER: NonZeroUsize = match NonZeroUsize::new(4242) { }; pub struct WindowHandle { - hwnd: Cell>, + hwnd: Cell>, is_open: Rc>, } @@ -59,19 +59,19 @@ impl WindowHandle { run_thread_message_loop_until(|| !self.is_open()).unwrap(); } - pub fn close(&self) { - if let Some(hwnd) = self.hwnd.take() { - unsafe { - PostMessageW(hwnd, BV_WINDOW_MUST_CLOSE, 0, 0); - } - } - } - pub fn is_open(&self) -> bool { self.is_open.get() } } +impl Drop for WindowHandle { + fn drop(&mut self) { + if let Some(hwnd) = self.hwnd.take() { + let _ = hwnd.destroy(); + } + } +} + struct ParentHandle { is_open: Rc>, } @@ -474,7 +474,7 @@ impl WindowHandle { window.show_and_activate(); - WindowHandle { hwnd: Some(hwnd).into(), is_open: Rc::clone(&is_open) } + WindowHandle { hwnd: Some(window).into(), is_open: Rc::clone(&is_open) } } } diff --git a/src/platform/x11/window.rs b/src/platform/x11/window.rs index 43245e2f..de97ef78 100644 --- a/src/platform/x11/window.rs +++ b/src/platform/x11/window.rs @@ -51,16 +51,18 @@ impl WindowHandle { }); } - pub fn close(&self) { + pub fn is_open(&self) -> bool { + self.is_open.load(Ordering::Relaxed) + } +} + +impl Drop for WindowHandle { + fn drop(&mut self) { self.close_requested.store(true, Ordering::Relaxed); if let Some(event_loop) = self.event_loop_handle.take() { let _ = event_loop.join(); } } - - pub fn is_open(&self) -> bool { - self.is_open.load(Ordering::Relaxed) - } } pub(crate) struct ParentHandle { diff --git a/src/window.rs b/src/window.rs index 240092d8..fc44bdc3 100644 --- a/src/window.rs +++ b/src/window.rs @@ -20,8 +20,8 @@ impl WindowHandle { } /// Close the window - pub fn close(&self) { - self.window_handle.close(); + pub fn close(self) { + drop(self) } /// Returns `true` if the window is still open, and returns `false` diff --git a/src/wrappers/appkit/view.rs b/src/wrappers/appkit/view.rs index c5a27e5b..4394b51e 100644 --- a/src/wrappers/appkit/view.rs +++ b/src/wrappers/appkit/view.rs @@ -51,7 +51,7 @@ impl View { let view: Retained> = unsafe { msg_send![view, initWithFrame: frame] }; - init(view.inner_ref()); + init(view.inner_ref().unwrap()); view } @@ -68,23 +68,28 @@ impl View { let ivar = class.instance_variable(BASEVIEW_STATE_IVAR).unwrap(); let ivar = unsafe { ivar.load_ptr::<*mut c_void>(this) }; let raw = unsafe { ivar.read() }; + + if raw.is_null() { + return; + } + let inner = unsafe { Box::>::from_raw(raw.cast()) }; unsafe { ivar.write(core::ptr::null_mut()) }; drop(inner); } - fn get_inner(&self) -> &ViewInner { + fn get_inner(&self) -> Option<&ViewInner> { let ivar = self.class().instance_variable(BASEVIEW_STATE_IVAR).unwrap(); let ivar = unsafe { ivar.load::<*mut c_void>(self) }; - unsafe { ivar.cast::>().as_ref() }.unwrap() + unsafe { ivar.cast::>().as_ref() } } - pub fn inner(&self) -> &V { - &self.get_inner().inner + pub fn inner(&self) -> Option<&V> { + Some(&self.get_inner()?.inner) } - pub fn inner_ref(&self) -> ViewRef<'_, V> { - ViewRef { view: self, inner: self.inner() } + pub fn inner_ref(&self) -> Option> { + Some(ViewRef { view: self, inner: self.inner()? }) } pub fn window_handle_from_weak(this: &Weak) -> Option> { diff --git a/src/wrappers/appkit/view/implementation.rs b/src/wrappers/appkit/view/implementation.rs index a3706768..96026124 100644 --- a/src/wrappers/appkit/view/implementation.rs +++ b/src/wrappers/appkit/view/implementation.rs @@ -162,125 +162,150 @@ extern "C-unwind" fn accepts_first_mouse(_this: &NSView, _sel: Sel, _event: &NSE } extern "C-unwind" fn become_first_responder(this: &View, _sel: Sel) -> Bool { - V::become_first_responder(this.inner_ref()).into() + let Some(inner) = this.inner_ref() else { return false.into() }; + V::become_first_responder(inner).into() } extern "C-unwind" fn resign_first_responder(this: &View, _sel: Sel) -> Bool { - V::resign_first_responder(this.inner_ref()).into() + let Some(inner) = this.inner_ref() else { return true.into() }; + V::resign_first_responder(inner).into() } extern "C-unwind" fn window_should_close( this: &View, _: Sel, _sender: &AnyObject, ) -> Bool { - V::window_should_close(this.inner_ref()).into() + let Some(inner) = this.inner_ref() else { return true.into() }; + V::window_should_close(inner).into() } extern "C-unwind" fn view_did_change_backing_properties( this: &View, _: Sel, _: &AnyObject, ) { - V::view_did_change_backing_properties(this.inner_ref()); + let Some(inner) = this.inner_ref() else { return }; + V::view_did_change_backing_properties(inner); } extern "C-unwind" fn hit_test( this: &View, _sel: Sel, point: NSPoint, ) -> Option<&NSView> { - V::hit_test(this.inner_ref(), point) + V::hit_test(this.inner_ref()?, point) } extern "C-unwind" fn view_will_move_to_window( this: &View, _self: Sel, new_window: Option<&NSWindow>, ) { - V::view_will_move_to_window(this.inner_ref(), new_window); + let Some(inner) = this.inner_ref() else { return }; + V::view_will_move_to_window(inner, new_window); } extern "C-unwind" fn update_tracking_areas(this: &View, _self: Sel, _: &AnyObject) { - V::update_tracking_areas(this.inner_ref()); + let Some(inner) = this.inner_ref() else { return }; + V::update_tracking_areas(inner); } extern "C-unwind" fn mouse_moved(this: &View, _sel: Sel, event: &NSEvent) { - V::mouse_moved(this.inner_ref(), event); + let Some(inner) = this.inner_ref() else { return }; + V::mouse_moved(inner, event); } extern "C-unwind" fn scroll_wheel(this: &View, _: Sel, event: &NSEvent) { - V::scroll_wheel(this.inner_ref(), event); + let Some(inner) = this.inner_ref() else { return }; + V::scroll_wheel(inner, event); } extern "C-unwind" fn dragging_entered( this: &View, _sel: Sel, sender: Option<&ProtocolObject>, ) -> NSDragOperation { - V::dragging_entered(this.inner_ref(), sender) + let Some(inner) = this.inner_ref() else { return NSDragOperation::None }; + V::dragging_entered(inner, sender) } extern "C-unwind" fn dragging_updated( this: &View, _sel: Sel, sender: Option<&ProtocolObject>, ) -> NSDragOperation { - V::dragging_updated(this.inner_ref(), sender) + let Some(inner) = this.inner_ref() else { return NSDragOperation::None }; + V::dragging_updated(inner, sender) } extern "C-unwind" fn prepare_for_drag_operation( this: &View, _sel: Sel, sender: Option<&ProtocolObject>, ) -> Bool { - V::prepare_for_drag_operation(this.inner_ref(), sender).into() + let Some(inner) = this.inner_ref() else { return false.into() }; + V::prepare_for_drag_operation(inner, sender).into() } extern "C-unwind" fn perform_drag_operation( this: &View, _sel: Sel, sender: Option<&ProtocolObject>, ) -> Bool { - V::perform_drag_operation(this.inner_ref(), sender).into() + let Some(inner) = this.inner_ref() else { return false.into() }; + V::perform_drag_operation(inner, sender).into() } extern "C-unwind" fn dragging_exited( this: &View, _sel: Sel, sender: Option<&ProtocolObject>, ) { - V::dragging_exited(this.inner_ref(), sender) + let Some(inner) = this.inner_ref() else { return }; + V::dragging_exited(inner, sender) } extern "C-unwind" fn handle_notification( this: &View, _cmd: Sel, notification: &NSNotification, ) { - V::handle_notification(this.inner_ref(), notification) + let Some(inner) = this.inner_ref() else { return }; + V::handle_notification(inner, notification) } extern "C-unwind" fn mouse_entered(this: &View, _: Sel, _: &AnyObject) { - V::mouse_entered(this.inner_ref()); + let Some(inner) = this.inner_ref() else { return }; + V::mouse_entered(inner); } extern "C-unwind" fn mouse_exited(this: &View, _: Sel, _: &AnyObject) { - V::mouse_exited(this.inner_ref()); + let Some(inner) = this.inner_ref() else { return }; + V::mouse_exited(inner); } extern "C-unwind" fn key_down(this: &View, _: Sel, event: &NSEvent) { - V::key_down(this.inner_ref(), event); + let Some(inner) = this.inner_ref() else { return }; + V::key_down(inner, event); } extern "C-unwind" fn key_up(this: &View, _: Sel, event: &NSEvent) { - V::key_up(this.inner_ref(), event); + let Some(inner) = this.inner_ref() else { return }; + V::key_up(inner, event); } extern "C-unwind" fn flags_changed(this: &View, _: Sel, event: &NSEvent) { - V::flags_changed(this.inner_ref(), event); + let Some(inner) = this.inner_ref() else { return }; + V::flags_changed(inner, event); } extern "C-unwind" fn mouse_down(this: &View, _sel: Sel, event: &NSEvent) { - V::mouse_down(this.inner_ref(), event); + let Some(inner) = this.inner_ref() else { return }; + V::mouse_down(inner, event); } extern "C-unwind" fn mouse_up(this: &View, _sel: Sel, event: &NSEvent) { - V::mouse_up(this.inner_ref(), event); + let Some(inner) = this.inner_ref() else { return }; + V::mouse_up(inner, event); } extern "C-unwind" fn right_mouse_down(this: &View, _sel: Sel, event: &NSEvent) { - V::right_mouse_down(this.inner_ref(), event); + let Some(inner) = this.inner_ref() else { return }; + V::right_mouse_down(inner, event); } extern "C-unwind" fn right_mouse_up(this: &View, _sel: Sel, event: &NSEvent) { - V::right_mouse_up(this.inner_ref(), event); + let Some(inner) = this.inner_ref() else { return }; + V::right_mouse_up(inner, event); } extern "C-unwind" fn other_mouse_down(this: &View, _sel: Sel, event: &NSEvent) { - V::other_mouse_down(this.inner_ref(), event); + let Some(inner) = this.inner_ref() else { return }; + V::other_mouse_down(inner, event); } extern "C-unwind" fn other_mouse_up(this: &View, _sel: Sel, event: &NSEvent) { - V::other_mouse_up(this.inner_ref(), event); + let Some(inner) = this.inner_ref() else { return }; + V::other_mouse_up(inner, event); }