@@ -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");