gardesk/ers / 03f53bc

Browse files

Add primary-screen detection and diagnostic logging

Find the primary screen by Cocoa origin (0,0) instead of relying on
NSScreen.screens[0], which Apple no longer guarantees to be the primary
on every macOS version. Log the screen layout at startup and the
CG-to-Cocoa transform on every set_bounds so we can diagnose offset
border reports.
Authored by mfwolffe <wolffemf@dukes.jmu.edu>
SHA
03f53bc03678cd7cb0d6aba9db9cae45516029d8
Parents
6cba17f
Tree
6e06b84

2 changed files

StatusFile+-
M src/main.rs 1 0
M src/nswindow_overlay.rs 57 3
src/main.rsmodified
@@ -837,6 +837,7 @@ fn main() {
837837
     // AppKit APIs. NSWindow operations (used by nswindow_overlay) all
838838
     // require a main-thread context.
839839
     let mtm = nswindow_overlay::init_application();
840
+    nswindow_overlay::log_screens(mtm);
840841
 
841842
     let cid = unsafe { SLSMainConnectionID() };
842843
     let own_pid = unsafe {
src/nswindow_overlay.rsmodified
@@ -27,13 +27,32 @@ const NS_FLOATING_WINDOW_LEVEL: isize = 3;
2727
 
2828
 /// Top-left Y in CG global coordinates becomes bottom-left Y in Cocoa
2929
 /// global coordinates by subtracting from the primary screen height.
30
-fn cg_to_cocoa_frame(cg: CGRect, mtm: MainThreadMarker) -> CGRect {
30
+///
31
+/// The "primary" screen is the one whose Cocoa frame origin is (0, 0) —
32
+/// by definition the bottom-left of the menu-bar screen, which is the
33
+/// shared anchor between CG (top-left) and Cocoa (bottom-left) global
34
+/// coordinates. `[NSScreen screens][0]` is documented as the primary
35
+/// but isn't reliable on every macOS version, so we look it up by
36
+/// origin instead.
37
+fn primary_screen_height(mtm: MainThreadMarker) -> f64 {
3138
     let screens = NSScreen::screens(mtm);
32
-    let primary_height = if screens.count() > 0 {
39
+    let count = screens.count();
40
+    for i in 0..count {
41
+        let s = screens.objectAtIndex(i);
42
+        let f = s.frame();
43
+        if f.origin.x.abs() < 0.5 && f.origin.y.abs() < 0.5 {
44
+            return f.size.height;
45
+        }
46
+    }
47
+    if count > 0 {
3348
         screens.objectAtIndex(0).frame().size.height
3449
     } else {
3550
         0.0
36
-    };
51
+    }
52
+}
53
+
54
+fn cg_to_cocoa_frame(cg: CGRect, mtm: MainThreadMarker) -> CGRect {
55
+    let primary_height = primary_screen_height(mtm);
3756
     let cocoa_y = primary_height - cg.origin.y - cg.size.height;
3857
     CGRect::new(
3958
         CGPoint::new(cg.origin.x, cocoa_y),
@@ -41,6 +60,30 @@ fn cg_to_cocoa_frame(cg: CGRect, mtm: MainThreadMarker) -> CGRect {
4160
     )
4261
 }
4362
 
63
+/// Log all NSScreens and which one we'll treat as primary. Helps diagnose
64
+/// multi-monitor coordinate issues.
65
+pub fn log_screens(mtm: MainThreadMarker) {
66
+    let screens = NSScreen::screens(mtm);
67
+    let primary_h = primary_screen_height(mtm);
68
+    tracing::debug!(
69
+        primary_height = primary_h,
70
+        count = screens.count(),
71
+        "NSScreen layout"
72
+    );
73
+    for i in 0..screens.count() {
74
+        let s = screens.objectAtIndex(i);
75
+        let f = s.frame();
76
+        tracing::debug!(
77
+            index = i,
78
+            cocoa_x = f.origin.x,
79
+            cocoa_y = f.origin.y,
80
+            w = f.size.width,
81
+            h = f.size.height,
82
+            "screen"
83
+        );
84
+    }
85
+}
86
+
4487
 /// Initialize NSApplication. Must be called once from the main thread.
4588
 pub fn init_application() -> MainThreadMarker {
4689
     let mtm = MainThreadMarker::new().expect("init_application must run on the main thread");
@@ -172,6 +215,17 @@ impl OverlayWindow {
172215
             CGSize::new(w + 2.0 * self.border_width, h + 2.0 * self.border_width),
173216
         );
174217
         let cocoa_frame = cg_to_cocoa_frame(outer_cg, self.mtm);
218
+        tracing::debug!(
219
+            cg_x = outer_cg.origin.x,
220
+            cg_y = outer_cg.origin.y,
221
+            cg_w = outer_cg.size.width,
222
+            cg_h = outer_cg.size.height,
223
+            cocoa_x = cocoa_frame.origin.x,
224
+            cocoa_y = cocoa_frame.origin.y,
225
+            cocoa_w = cocoa_frame.size.width,
226
+            cocoa_h = cocoa_frame.size.height,
227
+            "set_bounds"
228
+        );
175229
         self.window.setFrame_display(cocoa_frame, true);
176230
         // Update the border path to match new size.
177231
         unsafe {