fix: connect toolbar double clicks to native window zoom
Verify Tessera GUI / verify (push) Failing after 1m33s

This commit is contained in:
2026-10-25 15:22:24 +08:00
parent 050f777e33
commit 48fcb96f42
4 changed files with 78 additions and 4 deletions
+2 -2
View File
@@ -21,8 +21,8 @@ winit = "0.30.13"
[target.'cfg(target_os = "macos")'.dependencies]
objc2 = "0.5.2"
objc2-app-kit = { version = "0.2.2", default-features = false, features = ["NSButton", "NSView", "NSWindow"] }
objc2-foundation = { version = "0.2.2", default-features = false, features = ["NSGeometry"] }
objc2-app-kit = { version = "0.2.2", default-features = false, features = ["NSApplication", "NSButton", "NSEvent", "NSView", "NSWindow"] }
objc2-foundation = { version = "0.2.2", default-features = false, features = ["NSGeometry", "NSString", "NSUserDefaults"] }
[profile.release]
lto = "thin"
+29
View File
@@ -201,3 +201,32 @@ selection changes to the clicked tab and idle separators return after leaving.
The capture API does not establish frame-accurate 160 ms timing. Offline
all-target Clippy, formatting, release bundling and whitespace checks passed;
no cargo test, automated smoke script or Docker task was run.
### Native toolbar double-click — 2026-10-25
The custom row previously called only winit's native window-drag operation;
a manual double-click in its empty area did not resize the window. The same
empty-area hit test now consults AppKit's current NSEvent clickCount before
starting a drag. On the second press it calls NSWindow.performZoom, preserving
AppKit's standard/user frame toggle and avoiding a hand-built resize animation.
Tabs, close buttons and + remain excluded from this handler.
The adapter reads AppleActionOnDoubleClick without changing system preferences:
Minimize calls performMiniaturize; absent/Maximize calls performZoom; disabled
or unknown values do nothing. Fill also uses the public performZoom action,
whose standard frame fills this application's available screen in the checked
configuration. It does not invoke the private _zoomFill selector used by Chrome.
Consequently Fill is not claimed to reproduce every macOS tiling margin rule.
Native fullscreen uses a different window state and is left to AppKit.
References: Apple's [performZoom](https://developer.apple.com/documentation/appkit/nswindow/performzoom(_:))
and Chromium's [custom draggable-area handling](https://github.com/chromium/chromium/blob/main/components/remote_cocoa/app_shim/native_widget_mac_nswindow.mm).
Manual native verification: an empty-row double-click changed the Retina window
from 2560×1600 to 3024×1888; a second double-click restored 2560×1600. Clicking
+ and double-clicking a tab did not zoom the window. Dragging empty toolbar
space continued to move the window. The user's double-click preference was
absent (default zoom); other preference branches were not changed or manually
tested. Offline all-target Clippy, formatting, release bundling and whitespace
checks passed. No cargo test or automated smoke script was run.
+4
View File
@@ -1410,6 +1410,10 @@ impl ApplicationHandler<AppEvent> for TesseraApp {
&& self.pointer.x >= crate::tabs::LEADING
&& self.tab_hit().is_none()
{
#[cfg(target_os = "macos")]
if crate::native_chrome::titlebar_double_click(&window) {
return;
}
let _ = window.drag_window();
}
if self.pointer.y >= crate::tabs::height(&[]) {
+43 -2
View File
@@ -1,11 +1,52 @@
//! Keep AppKit's real window buttons aligned with the custom tab strip.
use objc2_app_kit::{NSView, NSWindowButton, NSWindowStyleMask};
use objc2_foundation::NSPoint;
use objc2_app_kit::{NSApplication, NSView, NSWindowButton, NSWindowStyleMask};
use objc2_foundation::{MainThreadMarker, NSPoint, NSString, NSUserDefaults};
use winit::{
raw_window_handle::{HasWindowHandle, RawWindowHandle},
window::Window,
};
/// The custom draggable row does not receive AppKit's titlebar double-click
/// action automatically. Use the native click count and native window actions.
pub fn titlebar_double_click(window: &Window) -> bool {
let Some(main_thread) = MainThreadMarker::new() else {
return false;
};
let Ok(handle) = window.window_handle() else {
return false;
};
let RawWindowHandle::AppKit(handle) = handle.as_raw() else {
return false;
};
// SAFETY: called on the event-loop thread during a left-button press, with
// a live winit-owned NSView. No native object outlives the Window borrow.
unsafe {
let Some(event) = NSApplication::sharedApplication(main_thread).currentEvent() else {
return false;
};
if event.clickCount() != 2 {
return false;
}
let view = &*handle.ns_view.as_ptr().cast::<NSView>();
let Some(native) = view.window() else {
return false;
};
if native.styleMask().contains(NSWindowStyleMask::FullScreen) {
return true;
}
let action = NSUserDefaults::standardUserDefaults()
.stringForKey(&NSString::from_str("AppleActionOnDoubleClick"))
.map(|value| value.to_string());
match action.as_deref() {
Some("Minimize") => native.performMiniaturize(None),
None | Some("Maximize" | "Fill") => native.performZoom(None),
// Respect disabled/unrecognized system actions without moving it.
_ => {}
}
}
true
}
/// Called only on winit's main thread, after native creation and before drawing.
/// AppKit can restore its default button positions when laying out the title bar.
pub fn align_controls(window: &Window) {