Skip to content

Commit 00f4a91

Browse files
fix minimize animation on win
1 parent 14b8cdf commit 00f4a91

File tree

4 files changed

+53
-3
lines changed

4 files changed

+53
-3
lines changed

desktop/src/app.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -495,6 +495,10 @@ impl ApplicationHandler for App {
495495

496496
let Some(render_state) = &mut self.render_state else { return };
497497
if let Some(window) = &self.window {
498+
if !window.can_render() {
499+
return;
500+
}
501+
498502
match render_state.render(window) {
499503
Ok(_) => {}
500504
Err(RenderError::OutdatedUITextureError) => {

desktop/src/window.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@ pub(crate) trait NativeWindow {
1212
fn init() {}
1313
fn configure(attributes: WindowAttributes, event_loop: &dyn ActiveEventLoop) -> WindowAttributes;
1414
fn new(window: &dyn WinitWindow, app_event_scheduler: AppEventScheduler) -> Self;
15+
fn can_render(&self) -> bool {
16+
true
17+
}
1518
fn update_menu(&self, _entries: Vec<MenuItem>) {}
1619
fn hide(&self) {}
1720
fn hide_others(&self) {}
@@ -85,6 +88,10 @@ impl Window {
8588
self.winit_window.pre_present_notify();
8689
}
8790

91+
pub(crate) fn can_render(&self) -> bool {
92+
self.native_handle.can_render()
93+
}
94+
8895
pub(crate) fn surface_size(&self) -> winit::dpi::PhysicalSize<u32> {
8996
self.winit_window.surface_size()
9097
}

desktop/src/window/win.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,10 @@ impl super::NativeWindow for NativeWindowImpl {
2828
let native_handle = native_handle::NativeWindowHandle::new(window);
2929
NativeWindowImpl { native_handle }
3030
}
31+
32+
fn can_render(&self) -> bool {
33+
self.native_handle.can_render()
34+
}
3135
}
3236

3337
impl Drop for NativeWindowImpl {

desktop/src/window/win/native_handle.rs

Lines changed: 38 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@
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;
1314
use wgpu::rwh::{HasWindowHandle, RawWindowHandle};
1415
use windows::Win32::Foundation::*;
1516
use windows::Win32::Graphics::Dwm::*;
@@ -21,11 +22,18 @@ use windows::Win32::UI::WindowsAndMessaging::*;
2122
use windows::core::PCWSTR;
2223
use 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)]
2532
pub(super) struct NativeWindowHandle {
2633
main: HWND,
2734
helper: HWND,
2835
prev_window_message_handler: isize,
36+
state: Arc<Mutex<NativeWindowState>>,
2937
}
3038
impl 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() > 100 => {
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

128163
mod 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

296331
unsafe fn calculate_hit(helper: HWND, lparam: LPARAM) -> u32 {

0 commit comments

Comments
 (0)