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
This commit is contained in:
张小白 2024-10-17 01:29:42 +08:00 committed by GitHub
parent 879a2ea06f
commit 338bf3fd28
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -52,12 +52,13 @@ pub struct WindowsWindowState {
pub display: WindowsDisplay,
fullscreen: Option<StyleAndBounds>,
initial_placement: Option<WINDOWPLACEMENT>,
initial_placement: Option<WindowOpenStatus>,
hwnd: HWND,
}
pub(crate) struct WindowsWindowStatePtr {
hwnd: HWND,
this: Weak<Self>,
pub(crate) state: RefCell<WindowsWindowState>,
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");