gardesk/ers / 61997d6

Browse files

Periodically re-apply CAShapeLayer geometry to recover from sleep/wake

NSWindow.frame survives display sleep/wake correctly (placed_correctly
logs always returned true), but the CAShapeLayer's frame/path can be
reset to a small rect at the layer origin during the wake transition.
Because SLS window bounds didn't change, sync_overlay never re-applied
state — leaving a tiny border in the bottom-left corner of an
otherwise-correctly-positioned window.

Add OverlayWindow::reapply_layer (cheap — only the layer, not the
NSWindow) and call it once a second from the periodic reconcile, plus
on every CGDisplayReconfiguration hotplug.
Authored by mfwolffe <wolffemf@dukes.jmu.edu>
SHA
61997d6a583663ebe92d34346bb206a233aa9e2e
Parents
55bd2f9
Tree
cf26f60

2 changed files

StatusFile+-
M src/main.rs 17 0
M src/nswindow_overlay.rs 26 0
src/main.rsmodified
@@ -476,6 +476,17 @@ impl BorderMap {
476476
         changed
477477
     }
478478
 
479
+    /// Re-apply each overlay's CAShapeLayer geometry. Called on a slow
480
+    /// periodic schedule (and on hotplug) to repair layer state that
481
+    /// macOS occasionally resets during display sleep/wake without
482
+    /// changing the NSWindow's frame — sync_overlay won't fix it on
483
+    /// its own because the SLS bounds match what we already stored.
484
+    fn refresh_all_layers(&self) {
485
+        for overlay in self.overlays.values() {
486
+            overlay.window.reapply_layer();
487
+        }
488
+    }
489
+
479490
     /// Re-apply set_bounds for every tracked overlay even when the
480491
     /// stored CG bounds match the current SLS bounds. After a display
481492
     /// reconfiguration the cocoa frame depends on the (possibly new)
@@ -1070,6 +1081,11 @@ extern "C" fn timer_callback(_timer: *mut std::ffi::c_void, _info: *mut std::ffi
10701081
                 if removed {
10711082
                     debug!("[timer] periodic reconcile removed stale overlays");
10721083
                 }
1084
+                // Cheap: re-applies just the CAShapeLayer frame/path
1085
+                // for every overlay. Recovers from layer state that
1086
+                // macOS resets during display sleep/wake without
1087
+                // touching the NSWindow frame.
1088
+                s.borders.refresh_all_layers();
10731089
             }
10741090
         }
10751091
     });
@@ -1231,6 +1247,7 @@ unsafe extern "C" fn display_reconfig_callback(
12311247
     MAIN_STATE.with(|cell| {
12321248
         if let Some(s) = cell.borrow_mut().as_mut() {
12331249
             s.borders.reconcile_all_force();
1250
+            s.borders.refresh_all_layers();
12341251
         }
12351252
     });
12361253
 }
src/nswindow_overlay.rsmodified
@@ -253,6 +253,32 @@ impl OverlayWindow {
253253
         self.bounds_cg_h = h;
254254
     }
255255
 
256
+    /// Re-apply just the CAShapeLayer's frame and path to match the
257
+    /// current stored bounds. Cheap — no NSWindow setFrame. Useful when
258
+    /// macOS resets layer state during display sleep/wake but the
259
+    /// NSWindow's frame survives (in which case sync_overlay won't see
260
+    /// any CG bounds change and won't re-apply state on its own).
261
+    pub fn reapply_layer(&self) {
262
+        let outer_w = self.bounds_cg_w + 2.0 * self.border_width;
263
+        let outer_h = self.bounds_cg_h + 2.0 * self.border_width;
264
+        let outer_size = CGSize::new(outer_w, outer_h);
265
+        unsafe {
266
+            let path = objc2_core_graphics::CGPath::with_rounded_rect(
267
+                inset_for_stroke(outer_size, self.border_width),
268
+                self.radius,
269
+                self.radius,
270
+                ptr::null(),
271
+            );
272
+            let path_ref: *mut AnyObject =
273
+                objc2_core_foundation::CFRetained::as_ptr(&path).as_ptr() as *mut AnyObject;
274
+            let _: () = msg_send![&*self.border_layer, setPath: path_ref];
275
+            self.border_layer.setFrame(CGRect::new(
276
+                CGPoint::new(0.0, 0.0),
277
+                CGSize::new(outer_w, outer_h),
278
+            ));
279
+        }
280
+    }
281
+
256282
     pub fn set_color(&self, color: (f64, f64, f64, f64)) {
257283
         unsafe {
258284
             let stroke = make_cgcolor(color, self.mtm);