Skip to content

Fix the hidden sidebar's hover reveal: full-width peek that retracts without the native overlay's broken titlebar - #229

Open
jcuhnoio wants to merge 1 commit into
thdxg:mainfrom
jcuhnoio:fix/sidebar-hover-reveal
Open

Fix the hidden sidebar's hover reveal: full-width peek that retracts without the native overlay's broken titlebar#229
jcuhnoio wants to merge 1 commit into
thdxg:mainfrom
jcuhnoio:fix/sidebar-hover-reveal

Conversation

@jcuhnoio

@jcuhnoio jcuhnoio commented Aug 7, 2026

Copy link
Copy Markdown
Collaborator

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:

  • the edge-hover reveal (revealsOnEdgeHoverInFullscreen, default-on for sidebar items and — despite the name — active in windowed mode on Tahoe), and
  • the windowed "proactive peek" (_NSSplitViewCollapsedInteractionsView trackers 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 columnVisibility desynced from AppState.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 and mouseExited:-[NSSplitView _cancelProactivePeek] crashes on it (EXC_BAD_ACCESS, from a real crash log).

How

  • WindowAppearance disables both native mechanisms: the reveal by clearing the item flag and re-running _updateHasItemToRevealOnEdgeHover (which derives "anything to reveal" solely from that flag and canCollapse* — verified by disassembly), the proactive peek by replacing its single gate _canDoSidebarProactivePeek with 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 with responds(to:); an OS that removes them degrades to the old quirk, never a crash.
  • MainWindow implements the peek itself with a small onContinuousHover state machine: a 12px leading-edge strip slides the column out through the exact columnVisibility path 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).
  • columnVisibility changes that bypass AppState (toolbar button, drag-out of the collapsed column) now mirror back into appState.sidebarVisible, ending the two-presses-to-hide desync.
  • The firstSplitView/owningSplitViewController view-walk helpers move from SettingsView to WindowAppearance so both windows share one copy.

…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.
@github-actions github-actions Bot added the area:ui Views, Settings UI label Aug 7, 2026
@jcuhnoio

jcuhnoio commented Aug 7, 2026

Copy link
Copy Markdown
Collaborator Author

Here's a demo:

Screen.Recording.2026-08-07.at.14.44.37.mov

@jcuhnoio jcuhnoio changed the title Fix the hidden sidebar's hover reveal: full-width peek that retracts, without the native overlay's broken titlebar and crash Fix the hidden sidebar's hover reveal: full-width peek that retracts without the native overlay's broken titlebar Aug 7, 2026
@jcuhnoio
jcuhnoio requested a review from thdxg August 7, 2026 05:47
@jcuhnoio jcuhnoio self-assigned this Aug 7, 2026
@github-actions

github-actions Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Window-state benchmark

State Metric main@1a30a21e8 this branch Δ
focused CPU % 1.30 0.80 -38%
Memory (RSS MB) 109.3 109.7 +0%
CPU ms/s (powermetrics) 12.9 7.7 -40%
Wakeups/s (powermetrics) 142.2 160.7 +13%
workload-focused CPU % 2.80 2.30 -18%
Memory (RSS MB) 165.7 165.2 -0%
CPU ms/s (powermetrics) 26.9 20.8 -23%
Wakeups/s (powermetrics) 253.1 231.4 -9%
workload-unfocused CPU % 2.70 2.10 -22%
Memory (RSS MB) 169.1 148.5 -12%
CPU ms/s (powermetrics) 26.5 19.7 -26% 🔻
Wakeups/s (powermetrics) 262.2 207.2 -21%

Not labeled benchmark:improvement: only one metric moved. A label needs ≥2 metrics past threshold with at least one under workload. Flagged cells (improved):

  • workload-unfocused — CPU ms/s (powermetrics): 26.5 → 19.7 (-26%)

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 benchmark:regression / benchmark:improvement label needs corroboration — ≥2 flagged metrics in the same direction, at least one under workload — so a lone noisy cell shows its arrow here without tagging the PR.

@thdxg

thdxg commented Aug 7, 2026

Copy link
Copy Markdown
Owner

@jcuhnoio can you add a toggle to enable/disable this in the settings?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:ui Views, Settings UI

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants