window position restoration working

Kay Simmons created

Change summary

crates/gpui/src/platform/mac/geometry.rs | 38 +++++++++++-------------
crates/gpui/src/platform/mac/window.rs   | 21 +++++++-----
crates/workspace/src/workspace.rs        | 40 +++++++++++++++++++++++--
3 files changed, 66 insertions(+), 33 deletions(-)

Detailed changes

crates/gpui/src/platform/mac/geometry.rs 🔗

@@ -42,31 +42,16 @@ impl RectFExt for RectF {
     }
 
     fn to_ns_rect(&self) -> NSRect {
-        dbg!(&self);
         NSRect::new(
             NSPoint::new(
-                dbg!(self.origin_x() as f64),
-                dbg!(-(self.origin_y() - self.height()) as f64),
+                self.origin_x() as f64,
+                -(self.origin_y() + self.height()) as f64,
             ),
             NSSize::new(self.width() as f64, self.height() as f64),
         )
     }
 }
 
-pub trait NSPointExt {
-    /// Converts self to a Vector2F with y axis pointing down.
-    /// Also takes care of converting from window scaled coordinates to screen coordinates
-    fn to_window_vector2f(&self, native_window: id) -> Vector2F;
-}
-impl NSPointExt for NSPoint {
-    fn to_window_vector2f(&self, native_window: id) -> Vector2F {
-        unsafe {
-            let point: NSPoint = msg_send![native_window, convertPointFromScreen: self];
-            vec2f(point.x as f32, -point.y as f32)
-        }
-    }
-}
-
 pub trait NSRectExt {
     /// Converts self to a RectF with y axis pointing down.
     /// The resulting RectF will have an origin at the top left of the rectangle.
@@ -77,11 +62,13 @@ pub trait NSRectExt {
     /// The resulting RectF will have an origin at the top left of the rectangle.
     /// Unlike to_screen_ns_rect, coordinates are not converted and are assumed to already be in screen scale
     fn to_rectf(&self) -> RectF;
+
+    fn intersects(&self, other: Self) -> bool;
 }
 impl NSRectExt for NSRect {
     fn to_window_rectf(&self, native_window: id) -> RectF {
         unsafe {
-            dbg!(self.origin.x);
+            self.origin.x;
             let rect: NSRect = native_window.convertRectFromScreen_(*self);
             rect.to_rectf()
         }
@@ -90,10 +77,21 @@ impl NSRectExt for NSRect {
     fn to_rectf(&self) -> RectF {
         RectF::new(
             vec2f(
-                dbg!(self.origin.x as f32),
-                dbg!(-(self.origin.y - self.size.height) as f32),
+                self.origin.x as f32,
+                -(self.origin.y + self.size.height) as f32,
             ),
             vec2f(self.size.width as f32, self.size.height as f32),
         )
     }
+
+    fn intersects(&self, other: Self) -> bool {
+        self.size.width > 0.
+            && self.size.height > 0.
+            && other.size.width > 0.
+            && other.size.height > 0.
+            && self.origin.x <= other.origin.x + other.size.width
+            && self.origin.x + self.size.width >= other.origin.x
+            && self.origin.y <= other.origin.y + other.size.height
+            && self.origin.y + self.size.height >= other.origin.y
+    }
 }

crates/gpui/src/platform/mac/window.rs 🔗

@@ -371,14 +371,8 @@ impl WindowState {
                 return WindowBounds::Fullscreen;
             }
 
-            let screen_frame = self
-                .native_window
-                .screen()
-                .visibleFrame()
-                .to_window_rectf(self.native_window);
             let window_frame = self.frame();
-
-            if screen_frame == window_frame {
+            if window_frame == self.native_window.screen().visibleFrame().to_rectf() {
                 WindowBounds::Maximized
             } else {
                 WindowBounds::Fixed(window_frame)
@@ -388,7 +382,10 @@ impl WindowState {
 
     // Returns the window bounds in window coordinates
     fn frame(&self) -> RectF {
-        unsafe { NSWindow::frame(self.native_window).to_window_rectf(self.native_window) }
+        unsafe {
+            let ns_frame = NSWindow::frame(self.native_window);
+            ns_frame.to_rectf()
+        }
     }
 
     fn content_size(&self) -> Vector2F {
@@ -474,7 +471,13 @@ impl Window {
                     native_window.setFrame_display_(screen.visibleFrame(), YES);
                 }
                 WindowBounds::Fixed(rect) => {
-                    native_window.setFrame_display_(rect.to_screen_ns_rect(native_window), YES);
+                    let screen_frame = screen.visibleFrame();
+                    let ns_rect = rect.to_ns_rect();
+                    if ns_rect.intersects(screen_frame) {
+                        native_window.setFrame_display_(ns_rect, YES);
+                    } else {
+                        native_window.setFrame_display_(screen_frame, YES);
+                    }
                 }
             }
 

crates/workspace/src/workspace.rs 🔗

@@ -682,10 +682,28 @@ impl Workspace {
                 DB.next_id().await.unwrap_or(0)
             };
 
-            let (bounds, display) = dbg!(serialized_workspace
+            let (bounds, display) = serialized_workspace
                 .as_ref()
                 .and_then(|sw| sw.bounds.zip(sw.display))
-                .unzip());
+                .and_then(|(mut bounds, display)| {
+                    // Stored bounds are relative to the containing display. So convert back to global coordinates if that screen still exists
+                    if let WindowBounds::Fixed(mut window_bounds) = bounds {
+                        if let Some(screen) = cx.platform().screen_by_id(display) {
+                            let screen_bounds = screen.bounds();
+                            window_bounds
+                                .set_origin_x(window_bounds.origin_x() + screen_bounds.origin_x());
+                            window_bounds
+                                .set_origin_y(window_bounds.origin_y() + screen_bounds.origin_y());
+                            bounds = WindowBounds::Fixed(window_bounds);
+                        } else {
+                            // Screen no longer exists. Return none here.
+                            return None;
+                        }
+                    }
+
+                    Some((bounds, display))
+                })
+                .unzip();
 
             // Use the serialized workspace to construct the new window
             let (_, workspace) = cx.add_window(
@@ -699,9 +717,23 @@ impl Workspace {
                         cx,
                     );
                     (app_state.initialize_workspace)(&mut workspace, &app_state, cx);
-                    cx.observe_window_bounds(move |_, bounds, display, cx| {
+                    cx.observe_window_bounds(move |_, mut bounds, display, cx| {
+                        // Transform fixed bounds to be stored in terms of the containing display
+                        if let WindowBounds::Fixed(mut window_bounds) = bounds {
+                            if let Some(screen) = cx.platform().screen_by_id(display) {
+                                let screen_bounds = screen.bounds();
+                                window_bounds.set_origin_x(
+                                    window_bounds.origin_x() - screen_bounds.origin_x(),
+                                );
+                                window_bounds.set_origin_y(
+                                    window_bounds.origin_y() - screen_bounds.origin_y(),
+                                );
+                                bounds = WindowBounds::Fixed(window_bounds);
+                            }
+                        }
+
                         cx.background()
-                            .spawn(DB.set_window_bounds(workspace_id, dbg!(bounds), dbg!(display)))
+                            .spawn(DB.set_window_bounds(workspace_id, bounds, display))
                             .detach_and_log_err(cx);
                     })
                     .detach();