From 338bf3fd282bf467dbd2f76c08b70fb4160cd1d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=A0=E5=B0=8F=E7=99=BD?= <364772080@qq.com> Date: Thu, 17 Oct 2024 01:29:42 +0800 Subject: [PATCH] windows: Fix window not displaying correctly on launch (#19124) Closes #18705 (comment) This PR fixes the issue where the Zed window was not displaying correctly on launch. Now, when Zed is closed in a maximized state, it will reopen in a maximized state. On macOS, when a window is created but not yet visible, calling `zoom` or `toggle_fullscreen` will still affect the hidden window. However, this behavior is different on Windows, so special handling is required. Also, since #18705 hasn't been reviewed yet, I'm not sure if this PR should be merged now or if it should wait until #18705 is reviewed first. Release Notes: - N/A --- crates/gpui/src/platform/windows/window.rs | 174 +++++++++++++-------- 1 file changed, 109 insertions(+), 65 deletions(-) diff --git a/crates/gpui/src/platform/windows/window.rs b/crates/gpui/src/platform/windows/window.rs index 3faaa6a8d2..a363745f9b 100644 --- a/crates/gpui/src/platform/windows/window.rs +++ b/crates/gpui/src/platform/windows/window.rs @@ -52,12 +52,13 @@ pub struct WindowsWindowState { pub display: WindowsDisplay, fullscreen: Option, - initial_placement: Option, + initial_placement: Option, hwnd: HWND, } pub(crate) struct WindowsWindowStatePtr { hwnd: HWND, + this: Weak, pub(crate) state: RefCell, pub(crate) handle: AnyWindowHandle, pub(crate) hide_title_bar: bool, @@ -222,9 +223,10 @@ impl WindowsWindowStatePtr { context.display, )?); - Ok(Rc::new(Self { - state, + Ok(Rc::new_cyclic(|this| Self { hwnd, + this: this.clone(), + state, handle: context.handle, hide_title_bar: context.hide_title_bar, is_movable: context.is_movable, @@ -235,11 +237,86 @@ impl WindowsWindowStatePtr { })) } + fn toggle_fullscreen(&self) { + let Some(state_ptr) = self.this.upgrade() else { + log::error!("Unable to toggle fullscreen: window has been dropped"); + return; + }; + self.executor + .spawn(async move { + let mut lock = state_ptr.state.borrow_mut(); + let StyleAndBounds { + style, + x, + y, + cx, + cy, + } = if let Some(state) = lock.fullscreen.take() { + state + } else { + let (window_bounds, _) = lock.calculate_window_bounds(); + lock.fullscreen_restore_bounds = window_bounds; + let style = + WINDOW_STYLE(unsafe { get_window_long(state_ptr.hwnd, GWL_STYLE) } as _); + let mut rc = RECT::default(); + unsafe { GetWindowRect(state_ptr.hwnd, &mut rc) }.log_err(); + let _ = lock.fullscreen.insert(StyleAndBounds { + style, + x: rc.left, + y: rc.top, + cx: rc.right - rc.left, + cy: rc.bottom - rc.top, + }); + let style = style + & !(WS_THICKFRAME + | WS_SYSMENU + | WS_MAXIMIZEBOX + | WS_MINIMIZEBOX + | WS_CAPTION); + let physical_bounds = lock.display.physical_bounds(); + StyleAndBounds { + style, + x: physical_bounds.left().0, + y: physical_bounds.top().0, + cx: physical_bounds.size.width.0, + cy: physical_bounds.size.height.0, + } + }; + drop(lock); + unsafe { set_window_long(state_ptr.hwnd, GWL_STYLE, style.0 as isize) }; + unsafe { + SetWindowPos( + state_ptr.hwnd, + HWND::default(), + x, + y, + cx, + cy, + SWP_FRAMECHANGED | SWP_NOACTIVATE | SWP_NOZORDER, + ) + } + .log_err(); + }) + .detach(); + } + fn set_window_placement(&self) -> Result<()> { - let Some(placement) = self.state.borrow_mut().initial_placement.take() else { + let Some(open_status) = self.state.borrow_mut().initial_placement.take() else { return Ok(()); }; - unsafe { SetWindowPlacement(self.hwnd, &placement)? }; + match open_status.state { + WindowOpenState::Maximized => unsafe { + SetWindowPlacement(self.hwnd, &open_status.placement)?; + ShowWindowAsync(self.hwnd, SW_MAXIMIZE).ok()?; + }, + WindowOpenState::Fullscreen => { + unsafe { SetWindowPlacement(self.hwnd, &open_status.placement)? }; + self.toggle_fullscreen(); + } + WindowOpenState::Windowed => unsafe { + SetWindowPlacement(self.hwnd, &open_status.placement)?; + }, + } Ok(()) } } @@ -361,7 +438,10 @@ impl WindowsWindow { if params.show { unsafe { SetWindowPlacement(hwnd, &placement)? }; } else { - state_ptr.state.borrow_mut().initial_placement = Some(placement); + state_ptr.state.borrow_mut().initial_placement = Some(WindowOpenStatus { + placement, + state: WindowOpenState::Windowed, + }); } Ok(Self(state_ptr)) @@ -579,68 +659,21 @@ impl PlatformWindow for WindowsWindow { } fn zoom(&self) { - unsafe { ShowWindowAsync(self.0.hwnd, SW_MAXIMIZE).ok().log_err() }; + unsafe { + if IsWindowVisible(self.0.hwnd).as_bool() { + ShowWindowAsync(self.0.hwnd, SW_MAXIMIZE).ok().log_err(); + } else if let Some(status) = self.0.state.borrow_mut().initial_placement.as_mut() { + status.state = WindowOpenState::Maximized; + } + } } fn toggle_fullscreen(&self) { - let state_ptr = self.0.clone(); - self.0 - .executor - .spawn(async move { - let mut lock = state_ptr.state.borrow_mut(); - let StyleAndBounds { - style, - x, - y, - cx, - cy, - } = if let Some(state) = lock.fullscreen.take() { - state - } else { - let (window_bounds, _) = lock.calculate_window_bounds(); - lock.fullscreen_restore_bounds = window_bounds; - let style = - WINDOW_STYLE(unsafe { get_window_long(state_ptr.hwnd, GWL_STYLE) } as _); - let mut rc = RECT::default(); - unsafe { GetWindowRect(state_ptr.hwnd, &mut rc) }.log_err(); - let _ = lock.fullscreen.insert(StyleAndBounds { - style, - x: rc.left, - y: rc.top, - cx: rc.right - rc.left, - cy: rc.bottom - rc.top, - }); - let style = style - & !(WS_THICKFRAME - | WS_SYSMENU - | WS_MAXIMIZEBOX - | WS_MINIMIZEBOX - | WS_CAPTION); - let physical_bounds = lock.display.physical_bounds(); - StyleAndBounds { - style, - x: physical_bounds.left().0, - y: physical_bounds.top().0, - cx: physical_bounds.size.width.0, - cy: physical_bounds.size.height.0, - } - }; - drop(lock); - unsafe { set_window_long(state_ptr.hwnd, GWL_STYLE, style.0 as isize) }; - unsafe { - SetWindowPos( - state_ptr.hwnd, - HWND::default(), - x, - y, - cx, - cy, - SWP_FRAMECHANGED | SWP_NOACTIVATE | SWP_NOZORDER, - ) - } - .log_err(); - }) - .detach(); + if unsafe { IsWindowVisible(self.0.hwnd).as_bool() } { + self.0.toggle_fullscreen(); + } else if let Some(status) = self.0.state.borrow_mut().initial_placement.as_mut() { + status.state = WindowOpenState::Fullscreen; + } } fn is_fullscreen(&self) -> bool { @@ -925,6 +958,17 @@ impl WindowBorderOffset { } } +struct WindowOpenStatus { + placement: WINDOWPLACEMENT, + state: WindowOpenState, +} + +enum WindowOpenState { + Maximized, + Fullscreen, + Windowed, +} + fn register_wnd_class(icon_handle: HICON) -> PCWSTR { const CLASS_NAME: PCWSTR = w!("Zed::Window");