Fix the hidden sidebar's hover reveal: full-width peek that retracts without the native overlay's broken titlebar - #229
Conversation
…es the real width Hiding the sidebar left two native NSSplitView mechanisms armed: the edge-hover reveal and the windowed 'proactive peek'. Both overlay a minimum-width sidebar that crams the traffic lights against the toolbar, never retracts on mouse-out, and desyncs AppState.sidebarVisible so the toggle shortcut needed two presses. The proactive peek also races any concurrent uncollapse and crashes in _cancelProactivePeek on freed state (EXC_BAD_ACCESS, seen in a real crash log). Disable both natives (flag clear + gate swizzle, each probed so an OS change degrades to the old quirk rather than crashing) and implement the peek in MainWindow instead: a 12px leading-edge strip slides the sidebar out through the same columnVisibility path the shortcut uses — so it reopens at its remembered width with correct titlebar layout — and it slides back in when the pointer leaves the sidebar or the window. columnVisibility now also mirrors back into AppState so toolbar-button and drag-out changes keep the shortcut single-press.
|
Here's a demo: Screen.Recording.2026-08-07.at.14.44.37.mov |
Window-state benchmark
Not labeled
Reported value is the median of 3×10s windows per state (splitting the window and taking the median keeps one co-scheduled spike from skewing a state); CPU % is the process CPU-time delta over a window. Runs land on different shared runners, so treat small deltas as noise — 🔺/🔻 marks changes ≥25% that also clear the metric's absolute noise floor (CPU % ≥0.5, Memory (RSS MB) ≥25, CPU ms/s ≥5, Wakeups/s ≥50); CPU deltas off a noise-dominated baseline aren't flagged (CPU % baseline ≥1.5, CPU ms/s baseline ≥15). The |
|
@jcuhnoio can you add a toggle to enable/disable this in the settings? |
What's here
With the sidebar hidden, hovering the pointer at the window's leading edge now peeks the sidebar out at the width it had before it was hidden, and it slides back in when the pointer leaves the sidebar (or the window). The toggle shortcut, the toolbar button, and dragging the collapsed column out all stay in sync — one press always does what the screen suggests it should.
Why
Hiding the sidebar left two native NSSplitView mechanisms armed, and both misbehave under Macterm's transparent titlebar:
revealsOnEdgeHoverInFullscreen, default-on for sidebar items and — despite the name — active in windowed mode on Tahoe), and_NSSplitViewCollapsedInteractionsViewtrackers installed over every collapsed pane).Hovering the left edge popped a minimum-width sidebar overlay that crammed the traffic lights against the toolbar, never retracted on mouse-out, and left
columnVisibilitydesynced fromAppState.sidebarVisible, so re-hiding took two shortcut presses. The proactive peek also races any concurrent uncollapse of the same column: its target state is freed mid-engage andmouseExited:→-[NSSplitView _cancelProactivePeek]crashes on it (EXC_BAD_ACCESS, from a real crash log).How
WindowAppearancedisables both native mechanisms: the reveal by clearing the item flag and re-running_updateHasItemToRevealOnEdgeHover(which derives "anything to reveal" solely from that flag andcanCollapse*— verified by disassembly), the proactive peek by replacing its single gate_canDoSidebarProactivePeekwith a constant NO (no per-item opt-out exists, and its trackers reinstall on every collapse, so anything less re-races). Every SPI touch is probed withresponds(to:); an OS that removes them degrades to the old quirk, never a crash.MainWindowimplements the peek itself with a smallonContinuousHoverstate machine: a 12px leading-edge strip slides the column out through the exactcolumnVisibilitypath the shortcut uses — so SwiftUI restores its remembered width and the titlebar lays out as for a pinned sidebar — and the pointer moving past the sidebar's width (+8px grace) or leaving the window slides it back. Peeking never flips the user's toggle state; pressing the shortcut while peeked pins the sidebar, and hiding it under the pointer won't instantly re-peek (the pointer must leave the strip once).columnVisibilitychanges that bypass AppState (toolbar button, drag-out of the collapsed column) now mirror back intoappState.sidebarVisible, ending the two-presses-to-hide desync.firstSplitView/owningSplitViewControllerview-walk helpers move fromSettingsViewtoWindowAppearanceso both windows share one copy.