99//! - The helper window is a invisible window that never activates, so it doesn't steal focus from the main window.
1010//! - The main window needs to update the helper window's position and size whenever it moves or resizes.
1111
12- use std:: sync:: OnceLock ;
12+ use std:: sync:: { Arc , Mutex , OnceLock } ;
13+ use std:: time:: Instant ;
1314use wgpu:: rwh:: { HasWindowHandle , RawWindowHandle } ;
1415use windows:: Win32 :: Foundation :: * ;
1516use windows:: Win32 :: Graphics :: Dwm :: * ;
@@ -21,11 +22,18 @@ use windows::Win32::UI::WindowsAndMessaging::*;
2122use windows:: core:: PCWSTR ;
2223use winit:: window:: Window ;
2324
25+ #[ derive( Default ) ]
26+ struct NativeWindowState {
27+ can_render : bool ,
28+ can_render_since : Option < Instant > ,
29+ }
30+
2431#[ derive( Clone ) ]
2532pub ( super ) struct NativeWindowHandle {
2633 main : HWND ,
2734 helper : HWND ,
2835 prev_window_message_handler : isize ,
36+ state : Arc < Mutex < NativeWindowState > > ,
2937}
3038impl NativeWindowHandle {
3139 pub ( super ) fn new ( window : & dyn Window ) -> NativeWindowHandle {
@@ -74,6 +82,7 @@ impl NativeWindowHandle {
7482 main,
7583 helper,
7684 prev_window_message_handler,
85+ state : Arc :: new ( Mutex :: new ( NativeWindowState :: default ( ) ) ) ,
7786 } ;
7887 registry:: insert ( & native_handle) ;
7988
@@ -123,6 +132,32 @@ impl NativeWindowHandle {
123132 let _ = unsafe { DestroyWindow ( self . helper ) } ;
124133 }
125134 }
135+
136+ // Rendering should be disabled when window is minimized
137+ // Rendering also needs to be disabled during minimize and restore animations
138+ // Reenabling rendering is done after a small delay to account for restore animation
139+ // TODO: Find a cleaner solution that doesn't depend on a timeout
140+ pub ( super ) fn can_render ( & self ) -> bool {
141+ let can_render = !unsafe { IsIconic ( self . main ) . into ( ) } && unsafe { IsWindowVisible ( self . main ) . into ( ) } ;
142+ let Ok ( mut state) = self . state . lock ( ) else {
143+ tracing:: error!( "Failed to lock NativeWindowState" ) ;
144+ return true ;
145+ } ;
146+ match ( can_render, state. can_render , state. can_render_since ) {
147+ ( true , false , None ) => {
148+ state. can_render_since = Some ( Instant :: now ( ) ) ;
149+ }
150+ ( true , false , Some ( can_render_since) ) if can_render_since. elapsed ( ) . as_millis ( ) > 50 => {
151+ state. can_render = true ;
152+ state. can_render_since = None ;
153+ }
154+ ( false , true , _) => {
155+ state. can_render = false ;
156+ }
157+ _ => { }
158+ }
159+ state. can_render
160+ }
126161}
127162
128163mod registry {
@@ -226,7 +261,7 @@ unsafe extern "system" fn main_window_handle_message(hwnd: HWND, msg: u32, wpara
226261 // Call the previous window message handler, this is a standard subclassing pattern.
227262 let prev_window_message_handler_fn_ptr: * const ( ) = std:: ptr:: without_provenance ( handle. prev_window_message_handler as usize ) ;
228263 let prev_window_message_handler_fn = unsafe { std:: mem:: transmute :: < _ , _ > ( prev_window_message_handler_fn_ptr) } ;
229- return unsafe { CallWindowProcW ( Some ( prev_window_message_handler_fn) , hwnd, msg, wparam, lparam) } ;
264+ unsafe { CallWindowProcW ( Some ( prev_window_message_handler_fn) , hwnd, msg, wparam, lparam) }
230265}
231266
232267// Helper window message handler, called on the UI thread for every message the helper window receives.
@@ -290,7 +325,7 @@ unsafe fn position_helper(main: HWND, helper: HWND) {
290325 let w = ( r. right - r. left ) + RESIZE_BAND_THICKNESS * 2 ;
291326 let h = ( r. bottom - r. top ) + RESIZE_BAND_THICKNESS * 2 ;
292327
293- let _ = unsafe { SetWindowPos ( helper, main, x, y, w, h, SWP_NOACTIVATE ) } ;
328+ let _ = unsafe { SetWindowPos ( helper, main, x, y, w, h, SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOOWNERZORDER | SWP_NOSENDCHANGING ) } ;
294329}
295330
296331unsafe fn calculate_hit ( helper : HWND , lparam : LPARAM ) -> u32 {
0 commit comments