Skip to content

Commit

Permalink
fix(window-state): restore window position if the one of the window c…
Browse files Browse the repository at this point in the history
…orners 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
  • Loading branch information
amrbashir committed Jan 24, 2024
1 parent 035a482 commit 70d9908
Show file tree
Hide file tree
Showing 2 changed files with 70 additions and 20 deletions.
8 changes: 8 additions & 0 deletions .changes/window-state-zero-positions.md
Original file line number Diff line number Diff line change
@@ -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.
82 changes: 62 additions & 20 deletions plugins/window-state/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,11 @@ struct WindowState {
height: f64,
x: 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,
visible: bool,
decorated: bool,
Expand All @@ -72,6 +77,8 @@ impl Default for WindowState {
height: Default::default(),
x: Default::default(),
y: Default::default(),
prev_x: Default::default(),
prev_y: Default::default(),
maximized: Default::default(),
visible: true,
decorated: true,
Expand Down Expand Up @@ -141,13 +148,23 @@ impl<R: Runtime> WindowExt for Window<R> {
}

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
// otherwise, let the OS decide where to place the window
for m in self.available_monitors()? {
if m.contains((state.x, state.y).into()) {
if m.intersects(position, size) {
self.set_position(PhysicalPosition {
x: state.x,
y: state.y,
x: if state.maximized {
state.prev_x
} else {
state.x
},
y: if state.maximized {
state.prev_y
} else {
state.y
},
})?;
}
}
Expand Down Expand Up @@ -243,22 +260,17 @@ impl<R: Runtime> WindowExtInternal for Window<R> {
.unwrap_or(1.);
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 {
state.width = size.width;
state.height = size.height;
}
}

if flags.contains(StateFlags::POSITION) {
if flags.contains(StateFlags::POSITION) && !is_maximized {
let position = self.outer_position()?;
if let Ok(Some(monitor)) = self.current_monitor() {
// save only window positions that are inside the current monitor
if monitor.contains(position) && !is_maximized {
state.x = position.x;
state.y = position.y;
}
}
state.x = position.x;
state.y = position.y;
}

Ok(())
Expand All @@ -273,6 +285,10 @@ pub struct Builder {
}

impl Builder {
pub fn new() -> Self {
Self::default()
}

/// Sets the state flags to control what state gets restored and saved.
pub fn with_state_flags(mut self, flags: StateFlags) -> Self {
self.state_flags = flags;
Expand Down Expand Up @@ -345,13 +361,25 @@ impl Builder {
.or_insert_with(WindowState::default);
}

window.on_window_event(move |e| {
if let WindowEvent::CloseRequested { .. } = e {
window.on_window_event(move |e| match e {
WindowEvent::CloseRequested { .. } => {
let mut c = cache.lock().unwrap();
if let Some(state) = c.get_mut(&label) {
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| {
Expand All @@ -364,17 +392,31 @@ impl Builder {
}

trait MonitorExt {
fn contains(&self, position: PhysicalPosition<i32>) -> bool;
fn intersects(&self, position: PhysicalPosition<i32>, size: LogicalSize<u32>) -> bool;
}

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 PhysicalSize { width, height } = *self.size();

x < position.x as _
&& position.x < (x + width as i32)
&& y < position.y as _
&& position.y < (y + height as i32)
let left = x;
let right = x + width as i32;
let top = y;
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)
}
}

0 comments on commit 70d9908

Please sign in to comment.