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:
parent
879a2ea06f
commit
338bf3fd28
1 changed files with 109 additions and 65 deletions
|
@ -52,12 +52,13 @@ pub struct WindowsWindowState {
|
||||||
|
|
||||||
pub display: WindowsDisplay,
|
pub display: WindowsDisplay,
|
||||||
fullscreen: Option<StyleAndBounds>,
|
fullscreen: Option<StyleAndBounds>,
|
||||||
initial_placement: Option<WINDOWPLACEMENT>,
|
initial_placement: Option<WindowOpenStatus>,
|
||||||
hwnd: HWND,
|
hwnd: HWND,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) struct WindowsWindowStatePtr {
|
pub(crate) struct WindowsWindowStatePtr {
|
||||||
hwnd: HWND,
|
hwnd: HWND,
|
||||||
|
this: Weak<Self>,
|
||||||
pub(crate) state: RefCell<WindowsWindowState>,
|
pub(crate) state: RefCell<WindowsWindowState>,
|
||||||
pub(crate) handle: AnyWindowHandle,
|
pub(crate) handle: AnyWindowHandle,
|
||||||
pub(crate) hide_title_bar: bool,
|
pub(crate) hide_title_bar: bool,
|
||||||
|
@ -222,9 +223,10 @@ impl WindowsWindowStatePtr {
|
||||||
context.display,
|
context.display,
|
||||||
)?);
|
)?);
|
||||||
|
|
||||||
Ok(Rc::new(Self {
|
Ok(Rc::new_cyclic(|this| Self {
|
||||||
state,
|
|
||||||
hwnd,
|
hwnd,
|
||||||
|
this: this.clone(),
|
||||||
|
state,
|
||||||
handle: context.handle,
|
handle: context.handle,
|
||||||
hide_title_bar: context.hide_title_bar,
|
hide_title_bar: context.hide_title_bar,
|
||||||
is_movable: context.is_movable,
|
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<()> {
|
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(());
|
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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -361,7 +438,10 @@ impl WindowsWindow {
|
||||||
if params.show {
|
if params.show {
|
||||||
unsafe { SetWindowPlacement(hwnd, &placement)? };
|
unsafe { SetWindowPlacement(hwnd, &placement)? };
|
||||||
} else {
|
} 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))
|
Ok(Self(state_ptr))
|
||||||
|
@ -579,68 +659,21 @@ impl PlatformWindow for WindowsWindow {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn zoom(&self) {
|
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) {
|
fn toggle_fullscreen(&self) {
|
||||||
let state_ptr = self.0.clone();
|
if unsafe { IsWindowVisible(self.0.hwnd).as_bool() } {
|
||||||
self.0
|
self.0.toggle_fullscreen();
|
||||||
.executor
|
} else if let Some(status) = self.0.state.borrow_mut().initial_placement.as_mut() {
|
||||||
.spawn(async move {
|
status.state = WindowOpenState::Fullscreen;
|
||||||
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 is_fullscreen(&self) -> bool {
|
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 {
|
fn register_wnd_class(icon_handle: HICON) -> PCWSTR {
|
||||||
const CLASS_NAME: PCWSTR = w!("Zed::Window");
|
const CLASS_NAME: PCWSTR = w!("Zed::Window");
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue