Skip to content

Align titlebar accessory hints#5059

Merged
azooz2003-bit merged 1 commit into
mainfrom
feat-titlebar-accessory-alignment
May 31, 2026
Merged

Align titlebar accessory hints#5059
azooz2003-bit merged 1 commit into
mainfrom
feat-titlebar-accessory-alignment

Conversation

@azooz2003-bit
Copy link
Copy Markdown
Contributor

@azooz2003-bit azooz2003-bit commented May 31, 2026

Summary

Align the titlebar shortcut hint pills, titlebar icons, and accessory button hit targets to the same center X.

Root cause: the shortcut hint overlay positioned pills by right-edge spacer math, while the visible accessory buttons and hidden AppKit hit layer used separate leading offsets. The titlebar accessory host also reapplied traffic-light spacing that AppKit had already handled.

Validation

  • ./scripts/reload.sh --tag titlebarx --swift-frontend-workaround
  • Dogfooded tagged build titlebarx visually against the misaligned top-left titlebar accessory controls.

View with Codesmith Autofix with Codesmith
Need help on this PR? Tag @codesmith with what you need. Autofix is disabled.


Summary by cubic

Aligns titlebar shortcut hint pills, accessory icons, and hidden hit regions to the same center X for crisp visuals and correct click targets. Removes duplicate traffic‑light spacing and ad‑hoc offsets for a consistent layout.

  • Bug Fixes
    • Center each hint pill over its button using a shared centerX; remove right-edge planner and safety/base X shifts.
    • Use HeaderChromeControlMetrics.titlebarControlsLeadingPadding for both visible controls and hit regions.
    • Stop double-applying traffic-light spacing; rely on AppKit’s traffic-light position.
    • Set default titlebar hint X offset to 0; update content widths (classic 136, compact 126) and tests to match.

Written for commit 22c62a5. Summary will update on new commits.

Review in cubic

Summary by CodeRabbit

Release Notes

  • Bug Fixes

    • Improved titlebar shortcut hint positioning and alignment with toolbar controls for more consistent visual layout
  • Chores

    • Refactored internal layout metrics system for better consistency and maintainability

@vercel
Copy link
Copy Markdown

vercel Bot commented May 31, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
cmux Ready Ready Preview, Comment May 31, 2026 11:05pm
cmux-staging Building Building Preview, Comment May 31, 2026 11:05pm

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 31, 2026

Review Change Stack

📝 Walkthrough

Walkthrough

This PR refactors titlebar shortcut-hint layout from left-edge and right-edge positioning to center-based positioning. A new metric constant is introduced, TitlebarControlsLayoutMetrics is refactored with center-based helpers, the hint item data model changes to store centerX instead of leftEdge, rendering is rewritten to position pills by center, and test expectations are updated throughout.

Changes

Titlebar hint layout refactoring to center-based positioning

Layer / File(s) Summary
Layout metrics foundation and helpers
Sources/WindowChromeMetrics.swift, Sources/Update/UpdateTitlebarAccessory.swift
Added HeaderChromeControlMetrics.titlebarControlsLeadingPadding constant and refactored TitlebarControlsLayoutMetrics with new helper functions buttonCenterX(...) and hintInterval(...) that compute center-based positioning instead of right-edge ranges.
Data model and interval computation refactoring
Sources/Update/UpdateTitlebarAccessory.swift
Updated TitlebarHintLayoutItem to store centerX instead of leftEdge, refactored titlebarHintLayoutRightmostExtent to reserve width using interval bounds, simplified leadingOffset calculation, and rewrote titlebarHintIntervals to use the new center-based metrics helpers.
Hint item construction and rendering
Sources/Update/UpdateTitlebarAccessory.swift
Updated titlebarHintLayoutItems to build hint items directly from computed intervals with centerX derived from interval midpoints, and rewrote titlebarShortcutHintOverlay to position hint pills using .position(x: centerX, ...) with centered frames.
Default offset alignment and hit-region updates
Sources/ContentView.swift, Sources/Update/MinimalModeSidebarControls.swift
Changed ShortcutHintDebugSettings.defaultTitlebarHintX from 4.0 to 0.0 and updated TitlebarControlsHitRegions.outerLeadingPadding to use the new HeaderChromeControlMetrics.titlebarControlsLeadingPadding constant, aligning both debug offset and hit-region positioning to the new metrics structure.
Test updates validating center-based layout
cmuxTests/ShortcutAndCommandPaletteTests.swift, cmuxTests/UpdatePillReleaseVisibilityTests.swift, cmuxTests/WindowAndDragTests.swift, cmuxUITests/UpdatePillUITests.swift
Updated all test files to expect new deterministic content widths, leading offset values, hit-region alignment, and shortcut-hint positioning based on the refactored center-based layout logic.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • manaflow-ai/cmux#5013: Both PRs adjust Sources/Update/UpdateTitlebarAccessory.swift titlebar layout metrics and their downstream computations affecting sidebar/control positioning.
  • manaflow-ai/cmux#5045: Both PRs refactor titlebar shortcut-hint layout/width reservation in Sources/Update/UpdateTitlebarAccessory.swift around TitlebarControlsLayoutMetrics.
  • manaflow-ai/cmux#5017: Both PRs modify the titlebar/traffic-light layout pipeline via TitlebarControlsLayoutMetrics sizing/offset changes and hit-range calculations.

Poem

🐰 From edges aligned to centers so bright,
The hints now pivot on their focal light,
No left-edge stress, no right-edge squeeze,
Just centered pills dancing with ease!
The metrics refactor makes layout complete,
A centered design, crisp and neat! ✨


Caution

Pre-merge checks failed

Please resolve all errors before merging. Addressing warnings is optional.

  • Ignore

❌ Failed checks (3 errors, 2 warnings)

Check name Status Explanation Resolution
Cmux Swift Blocking Runtime ❌ Error PR introduces Task.sleep(150ms) and DispatchQueue.main.asyncAfter delays in production Swift code violating swift-blocking-runtime.md rule which prohibits Task.sleep and delays in shipped app code. Replace Task.sleep with proper async signal (notification/state transition); replace DispatchQueue.main.asyncAfter with cancellation-aware timer/scheduler or real completion signal.
Cmux Full Internationalization ❌ Error UpdateTitlebarAccessory.swift has hardcoded user-facing strings in menuTitle without String(localized:defaultValue:) API or localization catalog entries. Add String(localized:defaultValue:) to TitlebarControlsStyle.menuTitle cases and corresponding entries to Resources/Localizable.xcstrings for all supported locales.
Cmux Swiftui State Layout ❌ Error New file introduces @ObservableObject/@published state and render-time mutations via DispatchQueue.main.async in .background() modifier, violating SwiftUI state layout rules. Replace @ObservableObject/@published with @Observable macro; move WindowAccessor state writes to .onAppear/.onReceive lifecycle callbacks instead of render-time scheduling.
Description check ⚠️ Warning The description includes a clear summary of the change and its root cause, but lacks testing details, a demo video, and an incomplete checklist as required by the template. Add explicit testing methodology, a demo video URL, and complete the checklist items to fully match the repository's description template requirements.
Docstring Coverage ⚠️ Warning Docstring coverage is 4.76% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (13 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Align titlebar accessory hints' directly and concisely describes the main change: aligning titlebar shortcut hint pills, icons, and hit targets to the same center X.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Cmux Swift Actor Isolation ✅ Passed No actor isolation issues introduced. New constant is pure data; helpers are static pure functions; private struct within View. No Sendable types or background access added.
Cmux No Hacky Sleeps ✅ Passed All changes are Swift code. The runtime-no-hacky-sleeps rule applies only to TypeScript, JavaScript, shell, and build/runtime scripts; Swift is covered by a separate rule.
Cmux Algorithmic Complexity ✅ Passed All loops operate on fixed-size enums (5 cases max) with no scalable collection scanning, per-item rescans, or unbounded algorithms relative to user data (workspaces, files, etc).
Cmux Swift Concurrency ✅ Passed PR adds zero legacy async patterns (DispatchQueue, Combine subscriptions, completion handlers, Tasks). All changes are pure layout/metrics refactoring for titlebar alignment.
Cmux Swift @Concurrent ✅ Passed Nonisolated pure helpers correctly marked; @concurrent properly applied to nonisolated async functions; no concurrency annotation violations detected.
Cmux Swift File And Package Boundaries ✅ Passed Focused layout alignment bug fix with 1-2 line changes across multiple files and net -10 lines to UpdateTitlebarAccessory. All changes are AppKit/UI glue to existing oversized files.
Cmux Swift Logging ✅ Passed PR contains no prohibited logging (print, debugPrint, dump, NSLog, file logging) in production code changes; only constant/value updates and refactoring with no new logging statements added.
Cmux User-Facing Error Privacy ✅ Passed PR contains only layout/positioning logic and internal debug constants; no user-facing errors, alerts, or sensitive information exposure detected.
Cmux Architecture Rethink ✅ Passed Small correctness fix unifying titlebar layout through pure TitlebarControlsLayoutMetrics functions with clear owners and invariants; no new timing/blocking/observer patterns.
Cmux Swift Auxiliary Window Close Shortcuts ✅ Passed PR contains only layout/positioning refactoring with no new NSWindow, NSPanel, NSWindowController, SwiftUI Window, or WindowGroup creation or material window changes.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat-titlebar-accessory-alignment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented May 31, 2026

Greptile Summary

This PR fixes a three-way misalignment in the minimal-mode titlebar: shortcut-hint pills, visible accessory buttons, and the hidden AppKit hit layer now all share the same leading coordinate, sourced from the new HeaderChromeControlMetrics.titlebarControlsLeadingPadding constant (4 pt).

  • Pill positioning is rewritten from right-edge math + ShortcutHintHorizontalPlanner overlap resolution to a simpler buttonCenterX-based .position() call; the artificial hintRightSafetyShift/hintBaseXShift pair that cancelled each other out is removed.
  • Hit-region leading offset (TitlebarControlsHitRegions.outerLeadingPadding) is promoted from a hardcoded 0 to the shared 4 pt constant, closing the gap between AppKit click targets and SwiftUI visuals.
  • leadingOffset drops the trafficLightFrame.maxX guard that was double-applying the traffic-light x-position AppKit had already handled; the parameter is now silently discarded (_) and the constant trafficLightGap is left unreferenced.

Confidence Score: 4/5

Safe to merge; the layout math is consistent and all changed invariants are covered by updated unit and UI tests.

The core alignment arithmetic is correct — buttonCenterX in the SwiftUI overlay and buttonXRanges in the AppKit hit layer now produce the same leading coordinate once the outer hintLeadingPadding offset is accounted for. The three cosmetic issues (dead trafficLightGap constant, stale planner comment, ignored trafficLightFrame parameter still in the function signature) are minor cleanup items that pose no runtime risk.

Sources/Update/UpdateTitlebarAccessory.swift — the dead trafficLightGap constant, stale comment, and ignored parameter are all in this file.

Important Files Changed

Filename Overview
Sources/Update/UpdateTitlebarAccessory.swift Core layout rewrite: replaces right-edge + planner-based pill positioning with center-aligned .position() calls; removes hintRightSafetyShift/hintBaseXShift pair; drops traffic-light x-offset from leadingOffset; leaves a dead trafficLightGap constant and a stale planner comment.
Sources/Update/MinimalModeSidebarControls.swift outerLeadingPadding now sources from HeaderChromeControlMetrics.titlebarControlsLeadingPadding (4 pt) instead of a hardcoded 0, aligning AppKit hit regions with the SwiftUI leading padding.
Sources/WindowChromeMetrics.swift Adds titlebarControlsLeadingPadding = 4 as the single source of truth for the 4 pt leading inset shared by hit regions, hint overlay, and visible controls.
Sources/ContentView.swift defaultTitlebarHintX reset to 0.0 — the old 4.0 offset was compensating for the now-removed hintBaseXShift; with center-aligned pills no compensating offset is needed.
cmuxTests/UpdatePillReleaseVisibilityTests.swift Content-size expectations updated (150 to 136 classic, 136 to 126 compact) and leadingOffset test renamed and asserts 0 instead of trafficLightFrame.maxX+gap, correctly reflecting the removed double-offset.
cmuxUITests/UpdatePillUITests.swift Old inter-pill minimum-spacing assertions replaced with midX-alignment assertions (pill center must match button center); the trailing safety-spacing check is removed in favour of alignment correctness.
cmuxTests/WindowAndDragTests.swift New assertion verifies hit-region leading bound equals hintLeadingPadding + groupPadding.leading, confirming AppKit hit layer and SwiftUI controls share the same leading coordinate.
cmuxTests/ShortcutAndCommandPaletteTests.swift Debug default assertion updated from 4.0 to 0.0 to match the removed artificial x-shift; straightforward synchronisation with ContentView.swift change.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[titlebarControlsLeadingPadding = 4] --> B[TitlebarControlsHitRegions.outerLeadingPadding]
    A --> C[TitlebarControlsLayoutMetrics.hintLeadingPadding]
    B --> D[AppKit hit-region buttonXRanges
minX = outerLeadingPadding + groupPadding.leading]
    C --> E[SwiftUI outer .padding leading
shifts paddedContent by 4 pt]
    E --> F[titlebarShortcutHintOverlay
.position x: buttonCenterX
centered = groupPadding.leading + i*step + size/2]
    D --> G{Same leading coordinate?}
    F --> G
    G --> H[YES - pills, icons, hit targets aligned]
    I[leadingOffset] --> J[ignores trafficLightFrame
AppKit already offsets accessory past traffic lights]
    J --> K[hostingView.frame.x = 0
containerWidth = contentSize.width]
Loading

Comments Outside Diff (1)

  1. Sources/Update/UpdateTitlebarAccessory.swift, line 533-535 (link)

    P2 The inline comment still references "the planner" and "overlap-shift the planner applies", but ShortcutHintHorizontalPlanner is no longer used in this path. Pills are now center-aligned to their buttons without any overlap resolution step, so the comment misleads future readers about what hintReservation actually computes.

    Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Reviews (1): Last reviewed commit: "Align titlebar accessory hints" | Re-trigger Greptile

static let outerLeadingPadding: CGFloat = TitlebarControlsHitRegions.outerLeadingPadding
static let hintRightSafetyShift: CGFloat = 10
static let hintTrailingBaseInset: CGFloat = 8
static let trafficLightGap: CGFloat = 2
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Dead constant after leadingOffset refactor

trafficLightGap is now defined but referenced nowhere in production code. The only call sites were the old leadingOffset body (which now ignores the traffic-light frame entirely) and the test that was updated to expect 0. Leaving an unreachable constant here risks future callers picking it up and re-introducing the double-offset that this PR is specifically removing.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Comment on lines 555 to 562
static func leadingOffset(
trafficLightFrame: NSRect?,
trafficLightFrame _: NSRect?,
debugSnapshot: MinimalModeTitlebarDebugSnapshot
) -> CGFloat {
let debugOffset = MinimalModeTitlebarDebugSettings.leftControlsXOffset(
MinimalModeTitlebarDebugSettings.leftControlsXOffset(
leadingInset: debugSnapshot.leftControlsLeadingInset
)
guard let trafficLightFrame, !trafficLightFrame.isEmpty else {
return debugOffset
}
return max(debugOffset, trafficLightFrame.maxX + trafficLightGap)
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 The trafficLightFrame parameter is now completely ignored — its internal label is _. Since AppKit already positions the titlebar accessory past the traffic lights, the frame is no longer needed for the x-offset calculation. Keeping the parameter in the signature means every call site still computes the frame unnecessarily and future readers may assume the argument influences the result. Removing it makes the contract explicit.

Suggested change
static func leadingOffset(
trafficLightFrame: NSRect?,
trafficLightFrame _: NSRect?,
debugSnapshot: MinimalModeTitlebarDebugSnapshot
) -> CGFloat {
let debugOffset = MinimalModeTitlebarDebugSettings.leftControlsXOffset(
MinimalModeTitlebarDebugSettings.leftControlsXOffset(
leadingInset: debugSnapshot.leftControlsLeadingInset
)
guard let trafficLightFrame, !trafficLightFrame.isEmpty else {
return debugOffset
}
return max(debugOffset, trafficLightFrame.maxX + trafficLightGap)
}
static func leadingOffset(
debugSnapshot: MinimalModeTitlebarDebugSnapshot
) -> CGFloat {
MinimalModeTitlebarDebugSettings.leftControlsXOffset(
leadingInset: debugSnapshot.leftControlsLeadingInset
)
}

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

@azooz2003-bit azooz2003-bit merged commit 9298921 into main May 31, 2026
21 checks passed
@azooz2003-bit azooz2003-bit deleted the feat-titlebar-accessory-alignment branch May 31, 2026 23:36
hhsw2015 pushed a commit to hhsw2015/cmux that referenced this pull request Jun 1, 2026
- Add Send Ctrl-F to Terminal passthrough (manaflow-ai#5011, force-stop CC agents)
- Fix sidebar worktree spawn worktree-setup-as-input bug (manaflow-ai#5032)
- Add boundary-aware ranking layer for command-palette fuzzy search
- Open extension browser as pane tab + polish (manaflow-ai#5053)
- Move sidebar kind selection to titlebar menu, fix clipped tooltip
  and floor sidebar width (manaflow-ai#5045)
- Extract CmuxFoundation package — modular refactor wave 1 (manaflow-ai#5055)
- Center empty sidebar-extension state, fade host bottom edge (manaflow-ai#5057)
- Align titlebar accessory hints (manaflow-ai#5059)
- Restore sidebar minimum width (manaflow-ai#5062)

Conflicts resolved:
- cmux.xcodeproj/project.pbxproj: merge fork's CMUXSettingsCore +
  CMUXSessionDaemon package refs with upstream's new CmuxFoundation
  package reference and product dependency.
austinywang added a commit that referenced this pull request Jun 1, 2026
Branch had diverged behind main, which reworked the titlebar shortcut-hint
layout (#5045 clipping fix, #5059 hint alignment with defaultTitlebarHintX 4->0)
and shrank header chrome sizing. Resolution preserves the branch's intent
(restored release sizes 24/15/17/8, sidebar.left symbol, 3-slot sidebar chrome
button-count plumbing) while adopting main's newer hint-layout machinery:

- WindowChromeMetrics: keep restored sizes; add main's titlebarControlsLeadingPadding.
- TitlebarControlsHitRegions: keep sidebarChromeButtonCount/allTitlebarButtonCount
  (referenced widely by auto-merged code); adopt named outerLeadingPadding.
- contentSize: combine main's two-reservation clipping fix with the branch's
  buttonCount/reservesShortcutHintOverflow threading; bound
  titlebarHintLayoutRightmostExtent to the active slot count for sidebar chrome.
- Drop branch's superseded hint positioning (titlebarButtonRightEdge,
  hintRightSafetyShift) in favor of main's planner (hintInterval/titlebarHintPillWidth).
- Update regression anchors to merged behavior (defaultTitlebarHintX=0):
  classicWithShortcutHints 186->172, sidebar 118->104, roomy fitted spacing 7->14.

vendor/bonsplit working tree checked out to the merged pointer (adds isAudioMuted,
forkConversation* APIs that Workspace.swift now uses).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant