@@ -28,31 +28,21 @@ const NS_FLOATING_WINDOW_LEVEL: isize = 3; |
| 28 | 28 | /// Top-left Y in CG global coordinates becomes bottom-left Y in Cocoa |
| 29 | 29 | /// global coordinates by subtracting from the primary screen height. |
| 30 | 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 { |
| 38 | | - let screens = NSScreen::screens(mtm); |
| 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 { |
| 48 | | - screens.objectAtIndex(0).frame().size.height |
| 49 | | - } else { |
| 50 | | - 0.0 |
| 31 | +/// We use the main CGDisplay's bounds rather than `NSScreen.screens` |
| 32 | +/// because NSScreen caches and only refreshes on certain notifications |
| 33 | +/// — when a monitor is plugged or unplugged, NSScreen.screens can |
| 34 | +/// return stale primary-height values, causing every cocoa Y on the |
| 35 | +/// new layout to be off by the difference. CGDisplayBounds reflects |
| 36 | +/// the current state immediately. |
| 37 | +fn primary_screen_height() -> f64 { |
| 38 | + unsafe { |
| 39 | + let main_id = objc2_core_graphics::CGMainDisplayID(); |
| 40 | + objc2_core_graphics::CGDisplayBounds(main_id).size.height |
| 51 | 41 | } |
| 52 | 42 | } |
| 53 | 43 | |
| 54 | | -fn cg_to_cocoa_frame(cg: CGRect, mtm: MainThreadMarker) -> CGRect { |
| 55 | | - let primary_height = primary_screen_height(mtm); |
| 44 | +fn cg_to_cocoa_frame(cg: CGRect, _mtm: MainThreadMarker) -> CGRect { |
| 45 | + let primary_height = primary_screen_height(); |
| 56 | 46 | let cocoa_y = primary_height - cg.origin.y - cg.size.height; |
| 57 | 47 | CGRect::new( |
| 58 | 48 | CGPoint::new(cg.origin.x, cocoa_y), |
@@ -64,11 +54,19 @@ fn cg_to_cocoa_frame(cg: CGRect, mtm: MainThreadMarker) -> CGRect { |
| 64 | 54 | /// multi-monitor coordinate issues. |
| 65 | 55 | pub fn log_screens(mtm: MainThreadMarker) { |
| 66 | 56 | let screens = NSScreen::screens(mtm); |
| 67 | | - let primary_h = primary_screen_height(mtm); |
| 57 | + let primary_h = primary_screen_height(); |
| 58 | + let cg_main_bounds = unsafe { |
| 59 | + let id = objc2_core_graphics::CGMainDisplayID(); |
| 60 | + objc2_core_graphics::CGDisplayBounds(id) |
| 61 | + }; |
| 68 | 62 | tracing::debug!( |
| 69 | | - primary_height = primary_h, |
| 70 | | - count = screens.count(), |
| 71 | | - "NSScreen layout" |
| 63 | + cg_primary_height = primary_h, |
| 64 | + cg_main_x = cg_main_bounds.origin.x, |
| 65 | + cg_main_y = cg_main_bounds.origin.y, |
| 66 | + cg_main_w = cg_main_bounds.size.width, |
| 67 | + cg_main_h = cg_main_bounds.size.height, |
| 68 | + nsscreen_count = screens.count(), |
| 69 | + "screen layout" |
| 72 | 70 | ); |
| 73 | 71 | for i in 0..screens.count() { |
| 74 | 72 | let s = screens.objectAtIndex(i); |
@@ -79,7 +77,7 @@ pub fn log_screens(mtm: MainThreadMarker) { |
| 79 | 77 | cocoa_y = f.origin.y, |
| 80 | 78 | w = f.size.width, |
| 81 | 79 | h = f.size.height, |
| 82 | | - "screen" |
| 80 | + "nsscreen" |
| 83 | 81 | ); |
| 84 | 82 | } |
| 85 | 83 | } |