Size the rail to the traffic lights instead of guessing
The collapsed rail was a fixed 72px, which left the cluster with more room on its left than its right. The width now comes from the buttons themselves - the close button's own inset plus the zoom button's right edge - so the margin matches on both sides. That inset is macOS's to choose and has changed between releases, so it is asked for rather than assumed. Measured at startup rather than on demand. The answer arrives on the main thread, and a command waiting for it there deadlocks until the timeout and silently returns the fallback - which is what the first attempt did.
This commit is contained in:
@@ -805,6 +805,61 @@ pub fn measure_chrome(_: &AppHandle) -> f64 {
|
||||
0.0
|
||||
}
|
||||
|
||||
/// Where the traffic lights actually sit, as (left inset, right edge) in
|
||||
/// logical pixels.
|
||||
///
|
||||
/// Asked rather than assumed. The collapsed rail has to be wide enough to give
|
||||
/// the cluster the same margin on its right as macOS gives it on its left, and
|
||||
/// those numbers are macOS's to choose — they differ by window style and have
|
||||
/// changed between releases.
|
||||
#[cfg(target_os = "macos")]
|
||||
pub fn traffic_lights(handle: &AppHandle) -> Option<(f64, f64)> {
|
||||
use objc2::runtime::AnyObject;
|
||||
use objc2_foundation::NSRect;
|
||||
|
||||
let wv = handle.get_webview_window("main")?;
|
||||
let (tx, rx) = std::sync::mpsc::channel::<Option<(f64, f64)>>();
|
||||
|
||||
let sent = wv.with_webview(move |platform| unsafe {
|
||||
let view = platform.inner() as *mut AnyObject;
|
||||
if view.is_null() {
|
||||
let _ = tx.send(None);
|
||||
return;
|
||||
}
|
||||
let window: *mut AnyObject = objc2::msg_send![view, window];
|
||||
if window.is_null() {
|
||||
let _ = tx.send(None);
|
||||
return;
|
||||
}
|
||||
|
||||
// NSWindowCloseButton = 0, NSWindowZoomButton = 2.
|
||||
let close: *mut AnyObject = objc2::msg_send![window, standardWindowButton: 0isize];
|
||||
let zoom: *mut AnyObject = objc2::msg_send![window, standardWindowButton: 2isize];
|
||||
if close.is_null() || zoom.is_null() {
|
||||
let _ = tx.send(None);
|
||||
return;
|
||||
}
|
||||
|
||||
let nil: *mut AnyObject = std::ptr::null_mut();
|
||||
let cb: NSRect = objc2::msg_send![close, bounds];
|
||||
let zb: NSRect = objc2::msg_send![zoom, bounds];
|
||||
let c: NSRect = objc2::msg_send![close, convertRect: cb, toView: nil];
|
||||
let z: NSRect = objc2::msg_send![zoom, convertRect: zb, toView: nil];
|
||||
|
||||
let _ = tx.send(Some((c.origin.x, z.origin.x + z.size.width)));
|
||||
});
|
||||
|
||||
if sent.is_err() {
|
||||
return None;
|
||||
}
|
||||
rx.recv_timeout(std::time::Duration::from_millis(400)).ok().flatten()
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "macos"))]
|
||||
pub fn traffic_lights(_: &AppHandle) -> Option<(f64, f64)> {
|
||||
None
|
||||
}
|
||||
|
||||
/// The title bar's height, for the shell to keep clear of.
|
||||
///
|
||||
/// Not an offset for positioning apps. The window's content view runs the full
|
||||
|
||||
Reference in New Issue
Block a user