From 92daf66fe636271f44daca3f39986fbf88bee320 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?joseLu=C3=ADs?= Date: Mon, 3 Feb 2025 19:19:45 +0100 Subject: [PATCH] replace `OnceLock` with `AtomicPtr` in `NATIVE_DISPLAY` - reduce locking overhead by replacing `OnceLock>` with `AtomicPtr>`. - add `drop_display` to allow safely resetting `NATIVE_DISPLAY` while ensuring proper deallocation. - implement `Drop` for `GlContext` and `MetalContext` to guarantee cleanup on context destruction. - ensure memory safety using `Release/Acquire` ordering and explicit deallocation. - add `native_display_blocking` and `native_display_nonblocking` for safer access. - update documentation and rustfmt. --- src/graphics/gl.rs | 8 ++- src/graphics/gl/cache.rs | 4 +- src/graphics/metal.rs | 5 ++ src/lib.rs | 119 ++++++++++++++++++++++++++---------- src/native/android.rs | 2 +- src/native/ios.rs | 12 ++-- src/native/linux_wayland.rs | 2 +- src/native/linux_x11.rs | 12 ++-- src/native/macos.rs | 24 ++++---- src/native/wasm.rs | 6 +- src/native/windows.rs | 22 +++---- 11 files changed, 138 insertions(+), 78 deletions(-) diff --git a/src/graphics/gl.rs b/src/graphics/gl.rs index 74be9fd9..4079fc00 100644 --- a/src/graphics/gl.rs +++ b/src/graphics/gl.rs @@ -520,6 +520,11 @@ pub struct GlContext { pub(crate) cache: GlCache, pub(crate) info: ContextInfo, } +impl Drop for GlContext { + fn drop(&mut self) { + crate::drop_display(); + } +} impl GlContext { pub fn new() -> GlContext { @@ -1455,8 +1460,7 @@ impl RenderingBackend for GlContext { TextureOrRenderbuffer::Renderbuffer(id) => id, }; unsafe { - self.cache - .bind_texture(n, texture.params.kind.into(), raw); + self.cache.bind_texture(n, texture.params.kind.into(), raw); glUniform1i(gl_loc, n as i32); } } diff --git a/src/graphics/gl/cache.rs b/src/graphics/gl/cache.rs index 11293161..de4e8f23 100644 --- a/src/graphics/gl/cache.rs +++ b/src/graphics/gl/cache.rs @@ -135,9 +135,7 @@ impl GlCache { let cached_attr = &mut self.attributes[attr_index]; if cached_attr.is_some() { - unsafe { - glDisableVertexAttribArray(attr_index as GLuint) - }; + unsafe { glDisableVertexAttribArray(attr_index as GLuint) }; } *cached_attr = None; } diff --git a/src/graphics/metal.rs b/src/graphics/metal.rs index 7ac8870f..a5ccb508 100644 --- a/src/graphics/metal.rs +++ b/src/graphics/metal.rs @@ -280,6 +280,11 @@ pub struct MetalContext { current_pipeline: Option, current_ub_offset: u64, } +impl Drop for MetalContext { + fn drop(&mut self) { + crate::drop_display(); + } +} impl MetalContext { pub fn new() -> MetalContext { diff --git a/src/lib.rs b/src/lib.rs index 7385cd86..986c6a2d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -80,19 +80,72 @@ pub mod date { pub type Context = dyn RenderingBackend; -use std::sync::{Mutex, OnceLock}; +use std::ptr::null_mut; +use std::sync::atomic::{AtomicBool, AtomicPtr, Ordering}; +use std::sync::{Mutex, MutexGuard}; -static NATIVE_DISPLAY: OnceLock> = OnceLock::new(); +/// Atomic pointer to the global display instance, enabling safe concurrent access and resetting. +static NATIVE_DISPLAY: AtomicPtr> = AtomicPtr::new(null_mut()); +/// Atomic flag indicating whether `NATIVE_DISPLAY` is initialized and safe to access. +static NATIVE_DISPLAY_READY: AtomicBool = AtomicBool::new(false); +/// Sets the global display, replacing any previous instance and ensuring visibility to all threads. fn set_display(display: native::NativeDisplayData) { - NATIVE_DISPLAY - .set(Mutex::new(display)) - .unwrap_or_else(|_| panic!("NATIVE_DISPLAY already set")); + let new_data = Box::new(Mutex::new(display)); + let ptr = Box::into_raw(new_data); + + let old = NATIVE_DISPLAY.swap(ptr, Ordering::AcqRel); + if !old.is_null() { + // SAFETY: `old` was originally created using `Box::into_raw()`, meaning it must be + // properly deallocated using `Box::from_raw()` to prevent memory leaks. + unsafe { drop(Box::from_raw(old)) }; + } + // Ensure all threads see the updated pointer before marking it as ready. + NATIVE_DISPLAY_READY.store(true, Ordering::Release); +} + +/// Returns a reference to the global display mutex, or `None` if uninitialized. +fn native_display() -> Option<&'static Mutex> { + // Ensure this thread sees the latest pointer update before dereferencing. + if !NATIVE_DISPLAY_READY.load(Ordering::Acquire) { + return None; + } + let ptr = NATIVE_DISPLAY.load(Ordering::Acquire); + if ptr.is_null() { + return None; + } + // SAFETY: The pointer was allocated using `Box::into_raw()` and is valid + // as long as `drop_display()` has not been called. Since `NATIVE_DISPLAY_READY` + // was checked, it is safe to assume `ptr` is not currently being deallocated. + unsafe { Some(&*ptr) } } -fn native_display() -> &'static Mutex { - NATIVE_DISPLAY - .get() - .expect("Backend has not initialized NATIVE_DISPLAY yet.") //|| Mutex::new(Default::default())) + +/// Returns a blocking lock on the global display, panicking if uninitialized. +fn native_display_blocking() -> MutexGuard<'static, native::NativeDisplayData> { + native_display() + .expect("Global display not initialized") + .lock() + .expect("Failed to acquire blocking lock on the global display") +} + +/// Returns a non-blocking lock on the global display, panicking if unavailable. +fn native_display_nonblocking() -> MutexGuard<'static, native::NativeDisplayData> { + native_display() + .expect("Global display not initialized") + .try_lock() + .expect("Failed to acquire non-blocking lock on the global display") +} + +/// Drops the global display, ensuring it is safely deallocated and preventing further access. +fn drop_display() { + // Prevent further access before deallocating. + NATIVE_DISPLAY_READY.store(false, Ordering::Release); + let old = NATIVE_DISPLAY.swap(null_mut(), Ordering::AcqRel); + if !old.is_null() { + // SAFETY: `swap(null_mut())` ensures that no other thread will access `old` + // after this point, so it is safe to drop it without causing a use-after-free. + unsafe { drop(Box::from_raw(old)) }; + } } /// Window and associated to window rendering context related functions. @@ -125,26 +178,26 @@ pub mod window { /// The current framebuffer size in pixels /// NOTE: [High DPI Rendering](../conf/index.html#high-dpi-rendering) pub fn screen_size() -> (f32, f32) { - let d = native_display().lock().unwrap(); + let d = native_display_blocking(); (d.screen_width as f32, d.screen_height as f32) } /// The dpi scaling factor (window pixels to framebuffer pixels) /// NOTE: [High DPI Rendering](../conf/index.html#high-dpi-rendering) pub fn dpi_scale() -> f32 { - let d = native_display().lock().unwrap(); + let d = native_display_blocking(); d.dpi_scale } /// True when high_dpi was requested and actually running in a high-dpi scenario /// NOTE: [High DPI Rendering](../conf/index.html#high-dpi-rendering) pub fn high_dpi() -> bool { - let d = native_display().lock().unwrap(); + let d = native_display_blocking(); d.high_dpi } pub fn blocking_event_loop() -> bool { - let d = native_display().lock().unwrap(); + let d = native_display_blocking(); d.blocking_event_loop } @@ -156,7 +209,7 @@ pub mod window { /// happen in the order_quit implmentation) and execution might continue for some time after /// But the window is going to be inevitably closed at some point. pub fn order_quit() { - let mut d = native_display().lock().unwrap(); + let mut d = native_display_blocking(); d.quit_ordered = true; } @@ -171,7 +224,7 @@ pub mod window { /// If the event handler callback does nothing, the application will be quit as usual. /// To prevent this, call the function "cancel_quit()"" from inside the event handler. pub fn request_quit() { - let mut d = native_display().lock().unwrap(); + let mut d = native_display_blocking(); d.quit_requested = true; } @@ -181,7 +234,7 @@ pub mod window { /// function makes sense is from inside the event handler callback when /// the "quit_requested_event" event has been received pub fn cancel_quit() { - let mut d = native_display().lock().unwrap(); + let mut d = native_display_blocking(); d.quit_requested = false; } /// Capture mouse cursor to the current window @@ -191,7 +244,7 @@ pub mod window { /// so set_cursor_grab(false) on window's focus lost is recommended. /// TODO: implement window focus events pub fn set_cursor_grab(grab: bool) { - let d = native_display().lock().unwrap(); + let d = native_display_blocking(); d.native_requests .send(native::Request::SetCursorGrab(grab)) .unwrap(); @@ -205,7 +258,7 @@ pub mod window { pub fn schedule_update() { #[cfg(not(target_arch = "wasm32"))] { - let d = native_display().lock().unwrap(); + let d = native_display_blocking(); d.native_requests .send(native::Request::ScheduleUpdate) .unwrap(); @@ -219,7 +272,7 @@ pub mod window { /// Show or hide the mouse cursor pub fn show_mouse(shown: bool) { - let d = native_display().lock().unwrap(); + let d = native_display_blocking(); d.native_requests .send(native::Request::ShowMouse(shown)) .unwrap(); @@ -227,7 +280,7 @@ pub mod window { /// Set the mouse cursor icon. pub fn set_mouse_cursor(cursor_icon: CursorIcon) { - let d = native_display().lock().unwrap(); + let d = native_display_blocking(); d.native_requests .send(native::Request::SetMouseCursor(cursor_icon)) .unwrap(); @@ -235,7 +288,7 @@ pub mod window { /// Set the application's window size. pub fn set_window_size(new_width: u32, new_height: u32) { - let d = native_display().lock().unwrap(); + let d = native_display_blocking(); d.native_requests .send(native::Request::SetWindowSize { new_width, @@ -245,7 +298,7 @@ pub mod window { } pub fn set_window_position(new_x: u32, new_y: u32) { - let d = native_display().lock().unwrap(); + let d = native_display_blocking(); d.native_requests .send(native::Request::SetWindowPosition { new_x, new_y }) .unwrap(); @@ -255,12 +308,12 @@ pub mod window { /// TODO: implement for other platforms #[cfg(any(target_os = "windows", target_os = "linux"))] pub fn get_window_position() -> (u32, u32) { - let d = native_display().lock().unwrap(); + let d = native_display_blocking(); d.screen_position } pub fn set_fullscreen(fullscreen: bool) { - let d = native_display().lock().unwrap(); + let d = native_display_blocking(); d.native_requests .send(native::Request::SetFullscreen(fullscreen)) .unwrap(); @@ -268,32 +321,32 @@ pub mod window { /// Get current OS clipboard value pub fn clipboard_get() -> Option { - let mut d = native_display().lock().unwrap(); + let mut d = native_display_blocking(); d.clipboard.get() } /// Save value to OS clipboard pub fn clipboard_set(data: &str) { - let mut d = native_display().lock().unwrap(); + let mut d = native_display_blocking(); d.clipboard.set(data) } pub fn dropped_file_count() -> usize { - let d = native_display().lock().unwrap(); + let d = native_display_blocking(); d.dropped_files.bytes.len() } pub fn dropped_file_bytes(index: usize) -> Option> { - let d = native_display().lock().unwrap(); + let d = native_display_blocking(); d.dropped_files.bytes.get(index).cloned() } pub fn dropped_file_path(index: usize) -> Option { - let d = native_display().lock().unwrap(); + let d = native_display_blocking(); d.dropped_files.paths.get(index).cloned() } /// Show/hide onscreen keyboard. /// Only works on Android right now. pub fn show_keyboard(show: bool) { - let d = native_display().lock().unwrap(); + let d = native_display_blocking(); d.native_requests .send(native::Request::ShowKeyboard(show)) .unwrap(); @@ -301,17 +354,17 @@ pub mod window { #[cfg(target_vendor = "apple")] pub fn apple_gfx_api() -> crate::conf::AppleGfxApi { - let d = native_display().lock().unwrap(); + let d = native_display_blocking(); d.gfx_api } #[cfg(target_vendor = "apple")] pub fn apple_view() -> crate::native::apple::frameworks::ObjcId { - let d = native_display().lock().unwrap(); + let d = native_display_blocking(); d.view } #[cfg(target_os = "ios")] pub fn apple_view_ctrl() -> crate::native::apple::frameworks::ObjcId { - let d = native_display().lock().unwrap(); + let d = native_display_blocking(); d.view_ctrl } } diff --git a/src/native/android.rs b/src/native/android.rs index 3148cc68..825fccdd 100644 --- a/src/native/android.rs +++ b/src/native/android.rs @@ -198,7 +198,7 @@ impl MainThreadState { } { - let mut d = crate::native_display().lock().unwrap(); + let mut d = crate::native_display_blocking(); d.screen_width = width as _; d.screen_height = height as _; } diff --git a/src/native/ios.rs b/src/native/ios.rs index f600430c..478a9f5b 100644 --- a/src/native/ios.rs +++ b/src/native/ios.rs @@ -14,7 +14,7 @@ use { }, NativeDisplayData, }, - native_display, + native_display_blocking, }, std::{ cell::RefCell, @@ -143,7 +143,7 @@ pub fn define_glk_or_mtk_view(superclass: &Class) -> *const Class { let ios_touch: ObjcId = msg_send![enumerator, nextObject]; let mut ios_pos: NSPoint = msg_send![ios_touch, locationInView: this]; - if native_display().lock().unwrap().high_dpi { + if native_display_blocking().high_dpi { ios_pos.x *= 2.; ios_pos.y *= 2.; } else { @@ -317,7 +317,7 @@ pub fn define_glk_or_mtk_view_dlg(superclass: &Class) -> *const Class { let main_screen: ObjcId = unsafe { msg_send![class!(UIScreen), mainScreen] }; let screen_rect: NSRect = unsafe { msg_send![main_screen, bounds] }; - let high_dpi = native_display().lock().unwrap().high_dpi; + let high_dpi = native_display_blocking().high_dpi; let (screen_width, screen_height) = if high_dpi { ( @@ -332,11 +332,11 @@ pub fn define_glk_or_mtk_view_dlg(superclass: &Class) -> *const Class { ) }; - if native_display().lock().unwrap().screen_width != screen_width - || native_display().lock().unwrap().screen_height != screen_height + if native_display_blocking().screen_width != screen_width + || native_display_blocking().screen_height != screen_height { { - let mut d = native_display().lock().unwrap(); + let mut d = native_display_blocking(); d.screen_width = screen_width; d.screen_height = screen_height; } diff --git a/src/native/linux_wayland.rs b/src/native/linux_wayland.rs index c82951e0..d6cc6b9e 100644 --- a/src/native/linux_wayland.rs +++ b/src/native/linux_wayland.rs @@ -483,7 +483,7 @@ unsafe extern "C" fn xdg_toplevel_handle_configure( ) -> () { assert!(!data.is_null()); let payload: &mut WaylandPayload = &mut *(data as *mut _); - let mut d = crate::native_display().lock().unwrap(); + let mut d = crate::native_display_blocking(); if width != 0 && height != 0 { let (egl_w, egl_h) = if payload.decorations.is_some() { diff --git a/src/native/linux_x11.rs b/src/native/linux_x11.rs index 5ddb9eef..3ffe66b4 100644 --- a/src/native/linux_x11.rs +++ b/src/native/linux_x11.rs @@ -135,7 +135,7 @@ impl X11Display { event_handler.window_minimized_event(); } 22 => { - let mut d = crate::native_display().try_lock().unwrap(); + let mut d = crate::native_display_nonblocking(); let left = (*event).xconfigure.x; let top = (*event).xconfigure.y; d.screen_position = (left as _, top as _); @@ -151,7 +151,7 @@ impl X11Display { } } 33 => { - let mut d = crate::native_display().try_lock().unwrap(); + let mut d = crate::native_display_nonblocking(); if (*event).xclient.message_type == self.libx11.extensions.wm_protocols { let protocol = (*event).xclient.data.l[0 as libc::c_int as usize] as Atom; if protocol == self.libx11.extensions.wm_delete_window { @@ -180,11 +180,11 @@ impl X11Display { _ => {} }; - let d = crate::native_display().try_lock().unwrap(); + let d = crate::native_display_nonblocking(); if d.quit_requested && !d.quit_ordered { drop(d); event_handler.quit_requested_event(); - let mut d = crate::native_display().try_lock().unwrap(); + let mut d = crate::native_display_nonblocking(); if d.quit_requested { d.quit_ordered = true } @@ -425,7 +425,7 @@ where let mut event_handler = (f.take().unwrap())(); - while !crate::native_display().try_lock().unwrap().quit_ordered { + while !crate::native_display_nonblocking().quit_ordered { while let Ok(request) = rx.try_recv() { display.process_request(request); } @@ -537,7 +537,7 @@ where let mut event_handler = (f.take().unwrap())(); - while !crate::native_display().try_lock().unwrap().quit_ordered { + while !crate::native_display_nonblocking().quit_ordered { while let Ok(request) = rx.try_recv() { display.process_request(request); } diff --git a/src/native/macos.rs b/src/native/macos.rs index c5aebef8..6cf40ff5 100644 --- a/src/native/macos.rs +++ b/src/native/macos.rs @@ -10,7 +10,7 @@ use { apple::{apple_util::*, frameworks::*}, gl, NativeDisplayData, Request, }, - native_display, CursorIcon, + native_display_blocking, CursorIcon, }, std::{ collections::HashMap, @@ -135,7 +135,7 @@ impl MacosDisplay { impl MacosDisplay { fn transform_mouse_point(&self, point: &NSPoint) -> (f32, f32) { - let d = native_display().lock().unwrap(); + let d = native_display_blocking(); let new_x = point.x as f32 * d.dpi_scale; let new_y = d.screen_height as f32 - (point.y as f32 * d.dpi_scale) - 1.; @@ -155,7 +155,7 @@ impl MacosDisplay { } unsafe fn update_dimensions(&mut self) -> Option<(i32, i32)> { - let mut d = native_display().lock().unwrap(); + let mut d = native_display_blocking(); unsafe { if self.gl_context != nil { msg_send_![self.gl_context, update]; @@ -270,20 +270,20 @@ pub fn define_cocoa_window_delegate() -> *const Class { } // only give user-code a chance to intervene when sapp_quit() wasn't already called - if !native_display().lock().unwrap().quit_ordered { + if !native_display_blocking().quit_ordered { // if window should be closed and event handling is enabled, give user code // a chance to intervene via sapp_cancel_quit() - native_display().lock().unwrap().quit_requested = true; + native_display_blocking().quit_requested = true; if let Some(event_handler) = payload.context() { event_handler.quit_requested_event(); } // user code hasn't intervened, quit the app - if native_display().lock().unwrap().quit_requested { - native_display().lock().unwrap().quit_ordered = true; + if native_display_blocking().quit_requested { + native_display_blocking().quit_ordered = true; } } - if native_display().lock().unwrap().quit_ordered { + if native_display_blocking().quit_ordered { return YES; } else { return NO; @@ -965,7 +965,7 @@ unsafe fn perform_redraw( } { - let d = native_display().lock().unwrap(); + let d = native_display_blocking(); if d.quit_requested || d.quit_ordered { drop(d); let () = msg_send![display.window, performClose: nil]; @@ -1092,7 +1092,7 @@ where AppleGfxApi::Metal => create_metal_view(&mut display, conf.sample_count, conf.high_dpi), }; { - let mut d = native_display().lock().unwrap(); + let mut d = native_display_blocking(); d.view = view; } (*view).set_ivar("display_ptr", &mut display as *mut _ as *mut c_void); @@ -1150,13 +1150,13 @@ where let distant_future: ObjcId = msg_send![class!(NSDate), distantFuture]; let distant_past: ObjcId = msg_send![class!(NSDate), distantPast]; let mut done = false; - while !(done || crate::native_display().lock().unwrap().quit_ordered) { + while !(done || native_display_blocking().quit_ordered) { while let Ok(request) = display.native_requests.try_recv() { display.process_request(request); } { - let d = native_display().lock().unwrap(); + let d = native_display_blocking(); if d.quit_requested || d.quit_ordered { done = true; } diff --git a/src/native/wasm.rs b/src/native/wasm.rs index 3ca4be42..94de803e 100644 --- a/src/native/wasm.rs +++ b/src/native/wasm.rs @@ -310,7 +310,7 @@ pub extern "C" fn key_up(key: u32, modifiers: u32) { #[no_mangle] pub extern "C" fn resize(width: i32, height: i32) { { - let mut d = crate::native_display().lock().unwrap(); + let mut d = crate::native_display_blocking(); d.screen_width = width as _; d.screen_height = height as _; } @@ -340,7 +340,7 @@ pub extern "C" fn focus(has_focus: bool) { #[no_mangle] pub extern "C" fn on_files_dropped_start() { - let mut d = crate::native_display().lock().unwrap(); + let mut d = crate::native_display_blocking(); d.dropped_files = Default::default(); } @@ -356,7 +356,7 @@ pub extern "C" fn on_file_dropped( bytes: *mut u8, bytes_len: usize, ) { - let mut d = crate::native_display().lock().unwrap(); + let mut d = crate::native_display_blocking(); let path = PathBuf::from(unsafe { String::from_raw_parts(path, path_len, path_len) }); let bytes = unsafe { Vec::from_raw_parts(bytes, bytes_len, bytes_len) }; diff --git a/src/native/windows.rs b/src/native/windows.rs index a200442d..9afcc9f4 100644 --- a/src/native/windows.rs +++ b/src/native/windows.rs @@ -4,7 +4,7 @@ use crate::{ conf::{Conf, Icon}, event::{KeyMods, MouseButton}, native::{NativeDisplayData, Request}, - CursorIcon, EventHandler, + native_display_blocking, CursorIcon, EventHandler, }; use winapi::{ @@ -178,7 +178,7 @@ impl WindowsDisplay { ); } else { let (w, h) = { - let d = crate::native_display().lock().unwrap(); + let d = native_display_blocking(); (d.screen_width, d.screen_height) }; @@ -287,7 +287,7 @@ unsafe extern "system" fn win32_wndproc( match umsg { WM_CLOSE => { - let mut d = crate::native_display().lock().unwrap(); + let mut d = native_display_blocking(); // only give user a chance to intervene when sapp_quit() wasn't already called if !d.quit_ordered { // if window should be closed and event handling is enabled, give user code @@ -297,7 +297,7 @@ unsafe extern "system" fn win32_wndproc( // the prevent event may require access to native_display event_handler.quit_requested_event(); // Re-acquire native_display - d = crate::native_display().lock().unwrap(); + d = native_display_blocking(); // if user code hasn't intervened, quit the app if d.quit_requested { d.quit_ordered = true; @@ -434,7 +434,7 @@ unsafe extern "system" fn win32_wndproc( // convert from normalised absolute coordinates if (data.data.mouse().usFlags & MOUSE_MOVE_ABSOLUTE) == MOUSE_MOVE_ABSOLUTE { let (width, height) = { - let d = crate::native_display().lock().unwrap(); + let d = native_display_blocking(); (d.screen_width as f32, d.screen_height as f32) }; @@ -499,7 +499,7 @@ unsafe extern "system" fn win32_wndproc( SwapBuffers(payload.dc); if payload.update_dimensions(hwnd) { - let d = crate::native_display().lock().unwrap(); + let d = native_display_blocking(); let width = d.screen_width as f32; let height = d.screen_height as f32; drop(d); @@ -519,7 +519,7 @@ unsafe extern "system" fn win32_wndproc( let mut path: [u16; MAX_PATH] = std::mem::uninitialized(); let num_drops = DragQueryFileW(hdrop, u32::MAX, std::ptr::null_mut(), 0); - let mut d = crate::native_display().lock().unwrap(); + let mut d = native_display_blocking(); for i in 0..num_drops { let path_len = DragQueryFileW(hdrop, i, path.as_mut_ptr(), MAX_PATH as u32) as usize; @@ -773,7 +773,7 @@ impl WindowsDisplay { /// and window position from the window's rect. /// returns true if size or position has changed unsafe fn update_dimensions(&mut self, hwnd: HWND) -> bool { - let mut d = crate::native_display().lock().unwrap(); + let mut d = native_display_blocking(); let mut rect: RECT = std::mem::zeroed(); // Get the outer rectangle of the window in screen coordinates @@ -942,7 +942,7 @@ where SetWindowLong(wnd, GWLP_USERDATA, &mut display as *mut _ as isize); let mut done = false; - while !(done || crate::native_display().lock().unwrap().quit_ordered) { + while !(done || native_display_blocking().quit_ordered) { while let Ok(request) = rx.try_recv() { display.process_request(request); } @@ -975,7 +975,7 @@ where } if display.update_dimensions(wnd) { - let d = crate::native_display().lock().unwrap(); + let d = native_display_blocking(); let width = d.screen_width as f32; let height = d.screen_height as f32; drop(d); @@ -985,7 +985,7 @@ where .unwrap() .resize_event(width, height); } - if crate::native_display().lock().unwrap().quit_requested { + if native_display_blocking().quit_requested { PostMessageW(display.wnd, WM_CLOSE, 0, 0); } }