Skip to content

Commit

Permalink
feat: smoother restore from maximize into tiling/floating position
Browse files Browse the repository at this point in the history
  • Loading branch information
lars-berger committed Nov 14, 2024
1 parent c4e92f9 commit 8bcd202
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 27 deletions.
29 changes: 13 additions & 16 deletions packages/wm/src/common/events/handle_window_location_changed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,6 @@ pub fn handle_window_location_changed(
let frame_position =
try_warn!(window.native().refresh_frame_position());

let is_minimized = try_warn!(window.native().refresh_is_minimized());

let old_is_maximized = window.native().is_maximized()?;
let is_maximized = try_warn!(window.native().refresh_is_maximized());

Expand All @@ -44,6 +42,14 @@ pub fn handle_window_location_changed(
return Ok(());
}

let is_minimized = try_warn!(window.native().refresh_is_minimized());

// Ignore events for minimized windows. Let them be handled by the
// handler for `PlatformEvent::WindowMinimized` instead.
if is_minimized {
return Ok(());
}

let nearest_monitor = state
.nearest_monitor(&window.native())
.context("Failed to get workspace of nearest monitor.")?;
Expand Down Expand Up @@ -71,7 +77,7 @@ pub fn handle_window_location_changed(
WindowState::Fullscreen(fullscreen_state) => {
// Restore the window if it's no longer fullscreen *or* for the
// edge case of fullscreen -> maximized -> restore from maximized.
if !is_minimized && !(is_fullscreen || is_maximized)
if !(is_fullscreen || is_maximized)
|| (is_fullscreen && !is_maximized && fullscreen_state.maximized)
{
info!("Window restored from fullscreen.");
Expand Down Expand Up @@ -101,13 +107,10 @@ pub fn handle_window_location_changed(
}
}
_ => {
// Update the window to be fullscreen if there's been a change in
// maximized state or if the window is now fullscreen.
if (is_maximized && old_is_maximized != is_maximized)
|| is_fullscreen
{
info!("Window fullscreened");
if is_maximized || is_fullscreen {
info!("Window fullscreened.");

// Update the window to be fullscreen.
update_window_state(
window,
WindowState::Fullscreen(FullscreenStateConfig {
Expand All @@ -117,13 +120,7 @@ pub fn handle_window_location_changed(
state,
config,
)?;

// A floating window that gets minimized can hit this arm, so
// ignore such events and let it be handled by the handler for
// `PlatformEvent::WindowMinimized` instead.
} else if !is_minimized
&& matches!(window.state(), WindowState::Floating(_))
{
} else if matches!(window.state(), WindowState::Floating(_)) {
// Update state with the new location of the floating window.
info!("Updating floating window position.");
window.set_floating_placement(frame_position);
Expand Down
38 changes: 27 additions & 11 deletions packages/wm/src/common/platform/native_window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,14 @@ use windows::{
EnumWindows, GetClassNameW, GetWindow, GetWindowLongPtrW,
GetWindowRect, GetWindowTextW, GetWindowThreadProcessId, IsIconic,
IsWindowVisible, IsZoomed, SendNotifyMessageW,
SetForegroundWindow, SetWindowLongPtrW, SetWindowPos,
ShowWindowAsync, GWL_EXSTYLE, GWL_STYLE, GW_OWNER, HWND_NOTOPMOST,
HWND_TOPMOST, SWP_ASYNCWINDOWPOS, SWP_FRAMECHANGED,
SWP_NOACTIVATE, SWP_NOCOPYBITS, SWP_NOMOVE, SWP_NOOWNERZORDER,
SWP_NOSENDCHANGING, SWP_NOSIZE, SWP_NOZORDER, SW_HIDE,
SW_MAXIMIZE, SW_MINIMIZE, SW_RESTORE, SW_SHOWNA, WINDOW_EX_STYLE,
WINDOW_STYLE, WM_CLOSE, WS_CAPTION, WS_CHILD, WS_DLGFRAME,
SetForegroundWindow, SetWindowLongPtrW, SetWindowPlacement,
SetWindowPos, ShowWindowAsync, GWL_EXSTYLE, GWL_STYLE, GW_OWNER,
HWND_NOTOPMOST, HWND_TOPMOST, SWP_ASYNCWINDOWPOS,
SWP_FRAMECHANGED, SWP_NOACTIVATE, SWP_NOCOPYBITS, SWP_NOMOVE,
SWP_NOOWNERZORDER, SWP_NOSENDCHANGING, SWP_NOSIZE, SWP_NOZORDER,
SW_HIDE, SW_MAXIMIZE, SW_MINIMIZE, SW_RESTORE, SW_SHOWNA,
WINDOWPLACEMENT, WINDOW_EX_STYLE, WINDOW_STYLE, WM_CLOSE,
WPF_ASYNCWINDOWPLACEMENT, WS_CAPTION, WS_CHILD, WS_DLGFRAME,
WS_EX_NOACTIVATE, WS_EX_TOOLWINDOW, WS_MAXIMIZEBOX, WS_THICKFRAME,
},
},
Expand Down Expand Up @@ -484,8 +485,21 @@ impl NativeWindow {
(current_style & style.0 as isize) != 0
}

pub fn restore(&self) -> anyhow::Result<()> {
unsafe { ShowWindowAsync(HWND(self.handle), SW_RESTORE).ok() }?;
pub fn restore_to_position(&self, rect: &Rect) -> anyhow::Result<()> {
let placement = WINDOWPLACEMENT {
length: std::mem::size_of::<WINDOWPLACEMENT>() as u32,
flags: WPF_ASYNCWINDOWPLACEMENT,
showCmd: SW_RESTORE.0 as u32,
rcNormalPosition: RECT {
left: rect.left,
top: rect.top,
right: rect.right,
bottom: rect.bottom,
},
..Default::default()
};

unsafe { SetWindowPlacement(HWND(self.handle), &placement) }?;
Ok(())
}

Expand Down Expand Up @@ -568,15 +582,17 @@ impl NativeWindow {
// to non-maximized fullscreen.
WindowState::Fullscreen(config) => {
if !config.maximized && self.is_maximized()? {
self.restore()?;
// Restoring to position has the same effect as `ShowWindow` with
// `SW_RESTORE`, but doesn't cause a flicker.
self.restore_to_position(rect)?;
}
}
// No need to restore window if it'll be minimized. Transitioning
// from maximized to minimized works without having to restore.
WindowState::Minimized => {}
_ => {
if self.is_minimized()? || self.is_maximized()? {
self.restore()?;
self.restore_to_position(rect)?;
}
}
}
Expand Down

0 comments on commit 8bcd202

Please sign in to comment.