fix(window-state): restore window position if the one of the window corners intersects with monitor (#898)

* fix(window-state): restore window positions that matches monitor positions
closes #892

* check for intersections of any window corner instead of only top-left
pull/920/head
Amr Bashir 1 year ago committed by GitHub
parent 035a4824d6
commit 70d99086de
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -0,0 +1,8 @@
---
"window-state": "patch"
---
Address a couple of issues with restoring positions:
- Fix restoring window positions correctly when the top-left corner of the window was outside of the monitor.
- Fix restore maximization state only maximized on main monitor.

@ -59,6 +59,11 @@ struct WindowState {
height: f64, height: f64,
x: i32, x: i32,
y: i32, y: i32,
// prev_x and prev_y are used to store position
// before maximization happened, because maximization
// will set x and y to the top-left corner of the monitor
prev_x: i32,
prev_y: i32,
maximized: bool, maximized: bool,
visible: bool, visible: bool,
decorated: bool, decorated: bool,
@ -72,6 +77,8 @@ impl Default for WindowState {
height: Default::default(), height: Default::default(),
x: Default::default(), x: Default::default(),
y: Default::default(), y: Default::default(),
prev_x: Default::default(),
prev_y: Default::default(),
maximized: Default::default(), maximized: Default::default(),
visible: true, visible: true,
decorated: true, decorated: true,
@ -141,13 +148,23 @@ impl<R: Runtime> WindowExt for Window<R> {
} }
if flags.contains(StateFlags::POSITION) { if flags.contains(StateFlags::POSITION) {
let position = (state.x, state.y).into();
let size = (state.width, state.height).into();
// restore position to saved value if saved monitor exists // restore position to saved value if saved monitor exists
// otherwise, let the OS decide where to place the window // otherwise, let the OS decide where to place the window
for m in self.available_monitors()? { for m in self.available_monitors()? {
if m.contains((state.x, state.y).into()) { if m.intersects(position, size) {
self.set_position(PhysicalPosition { self.set_position(PhysicalPosition {
x: state.x, x: if state.maximized {
y: state.y, state.prev_x
} else {
state.x
},
y: if state.maximized {
state.prev_y
} else {
state.y
},
})?; })?;
} }
} }
@ -243,22 +260,17 @@ impl<R: Runtime> WindowExtInternal for Window<R> {
.unwrap_or(1.); .unwrap_or(1.);
let size = self.inner_size()?.to_logical(scale_factor); let size = self.inner_size()?.to_logical(scale_factor);
// It doesn't make sense to save a self with 0 height or width // It doesn't make sense to save a window with 0 height or width
if size.width > 0. && size.height > 0. && !is_maximized { if size.width > 0. && size.height > 0. && !is_maximized {
state.width = size.width; state.width = size.width;
state.height = size.height; state.height = size.height;
} }
} }
if flags.contains(StateFlags::POSITION) { if flags.contains(StateFlags::POSITION) && !is_maximized {
let position = self.outer_position()?; let position = self.outer_position()?;
if let Ok(Some(monitor)) = self.current_monitor() { state.x = position.x;
// save only window positions that are inside the current monitor state.y = position.y;
if monitor.contains(position) && !is_maximized {
state.x = position.x;
state.y = position.y;
}
}
} }
Ok(()) Ok(())
@ -273,6 +285,10 @@ pub struct Builder {
} }
impl Builder { impl Builder {
pub fn new() -> Self {
Self::default()
}
/// Sets the state flags to control what state gets restored and saved. /// Sets the state flags to control what state gets restored and saved.
pub fn with_state_flags(mut self, flags: StateFlags) -> Self { pub fn with_state_flags(mut self, flags: StateFlags) -> Self {
self.state_flags = flags; self.state_flags = flags;
@ -345,13 +361,25 @@ impl Builder {
.or_insert_with(WindowState::default); .or_insert_with(WindowState::default);
} }
window.on_window_event(move |e| { window.on_window_event(move |e| match e {
if let WindowEvent::CloseRequested { .. } = e { WindowEvent::CloseRequested { .. } => {
let mut c = cache.lock().unwrap(); let mut c = cache.lock().unwrap();
if let Some(state) = c.get_mut(&label) { if let Some(state) = c.get_mut(&label) {
let _ = window_clone.update_state(state, flags); let _ = window_clone.update_state(state, flags);
} }
} }
WindowEvent::Moved(position) if flags.contains(StateFlags::POSITION) => {
let mut c = cache.lock().unwrap();
if let Some(state) = c.get_mut(&label) {
state.prev_x = state.x;
state.prev_y = state.y;
state.x = position.x;
state.y = position.y;
}
}
_ => {}
}); });
}) })
.on_event(move |app, event| { .on_event(move |app, event| {
@ -364,17 +392,31 @@ impl Builder {
} }
trait MonitorExt { trait MonitorExt {
fn contains(&self, position: PhysicalPosition<i32>) -> bool; fn intersects(&self, position: PhysicalPosition<i32>, size: LogicalSize<u32>) -> bool;
} }
impl MonitorExt for Monitor { impl MonitorExt for Monitor {
fn contains(&self, position: PhysicalPosition<i32>) -> bool { fn intersects(&self, position: PhysicalPosition<i32>, size: LogicalSize<u32>) -> bool {
let size = size.to_physical::<u32>(self.scale_factor());
let PhysicalPosition { x, y } = *self.position(); let PhysicalPosition { x, y } = *self.position();
let PhysicalSize { width, height } = *self.size(); let PhysicalSize { width, height } = *self.size();
x < position.x as _ let left = x;
&& position.x < (x + width as i32) let right = x + width as i32;
&& y < position.y as _ let top = y;
&& position.y < (y + height as i32) let bottom = y + height as i32;
[
(position.x, position.y),
(position.x + size.width as i32, position.y),
(position.x, position.y + size.height as i32),
(
position.x + size.width as i32,
position.y + size.height as i32,
),
]
.into_iter()
.any(|(x, y)| x >= left && x < right && y >= top && y < bottom)
} }
} }

Loading…
Cancel
Save