Skip to content

macos: quick-terminal - dock hide/unhide logic changes#13039

Open
exlee wants to merge 1 commit into
ghostty-org:mainfrom
exlee:macos/quickterminal-dock-hide-logic-change
Open

macos: quick-terminal - dock hide/unhide logic changes#13039
exlee wants to merge 1 commit into
ghostty-org:mainfrom
exlee:macos/quickterminal-dock-hide-logic-change

Conversation

@exlee

@exlee exlee commented Jun 18, 2026

Copy link
Copy Markdown

Quick Terminal Dock / Space Handling

Notes

LLM disclaimer

  • Architecture (2-tiered state machine, state transitions, test shape) is end-to-end owned and developed by me
  • Provisioned code was reviewed by me in multiple passes
  • Edge cases problems were solved by me directly
  • I tested manually repeatedly when working on PR on rebuilt instances; there are no edge cases known to me at this point
  • Codex/ChatGPT 5.5 contribution: guided code generation, initial code analysis, code completion analysis, grooming contextual information visible below

Contextual information

Initial State

Quick Terminal could hide the Dock when shown in a position that conflicts with
the Dock, but the restore path was tied mostly to quick-terminal toggle
and window focus events.

That left a few awkward Space-change cases:

  • Keyboard Space changes could leave the Dock hidden because the expected focus
    or animation callbacks did not restore it.
  • Restoring the Dock immediately on Space change could cause a visible Dock
    flash when the same Quick Terminal window was about to regain focus.
  • Fullscreen Spaces made Dock visibility ambiguous: the Dock is hidden there
    even when user Dock auto-hide is off, so using "Dock is hidden" as the only
    signal could make Quick Terminal mutate user Dock settings at the wrong time.

State Machine

The Dock logic now has two layers.

The first layer is the desired state:

  • shouldBeHidden == true: Quick Terminal currently wants the Dock hidden.
  • shouldBeHidden == false: Quick Terminal no longer wants to own Dock hiding.

The second layer is the managed side-effect state:

  • managedHidden == true: Quick Terminal changed global Dock auto-hide and is
    responsible for restoring it later.
  • managedHidden == false: Quick Terminal has not changed global Dock auto-hide.

The pure reducer is QuickTerminalDockState:

  • If the Dock is visible and shouldBeHidden becomes true, transition to
    hide and mark managedHidden.
  • If Quick Terminal previously managed hiding and shouldBeHidden becomes
    false on a normal Space, transition to show and clear managedHidden.
  • If the Dock is already hidden by the user, Quick Terminal does not mark it as
    managed and does not restore it later.
  • If the active Space is fullscreen, Quick Terminal never performs the show
    transition. It preserves managedHidden so the restore can happen later after
    returning to a normal Space.
flowchart LR
    request["setShouldHide(value) or apply()"]
    desired["Update / read shouldBeHidden"]
    hidden{"Dock hidden?\nDock.autoHide || fullscreen"}
    wantsHide{"shouldBeHidden?"}
    managed{"managedHidden?"}
    fullscreen{"fullscreen Space?"}

    hide["transition: hide\nmanagedHidden = true\nDock.autoHide = true"]
    show["transition: show\nmanagedHidden = false\nDock.autoHide = false"]
    defer["transition: none\nkeep managedHidden = true\nrestore later"]
    noop["transition: none\nno Dock side effect"]

    request --> desired --> wantsHide

    wantsHide -- true --> hidden
    hidden -- false --> hide
    hidden -- true --> noop

    wantsHide -- false --> managed
    managed -- false --> noop
    managed -- true --> fullscreen
    fullscreen -- false --> show
    fullscreen -- true --> defer
Loading

HiddenDock wraps that reducer and performs the AppKit/global Dock side effects
only when the reducer returns hide or show.

Changes

Added

  • Debug logging for requested, applied, and skipped Dock transitions.
  • Focus holding across Space changes: when Quick Terminal still owns focus /
    Dock hiding, it immediately refocuses the same Quick Terminal window instead
    of waiting for the delayed restore path.
  • Fullscreen-safe Dock restore behavior: fullscreen Spaces are treated as
    read-only for Dock restore, so Quick Terminal never unhides the Dock while
    fullscreen is active.

Changed

  • HiddenDock now delegates hide / show decisions to QuickTerminalDockState,
    a testable pure state machine.
  • HiddenDock only performs AppKit/global Dock side effects when the reducer
    returns an explicit hide or show transition.
  • windowDidResignKey no longer restores the Dock during transient focus loss
    from Space movement, avoiding a flash before the same Quick Terminal window is
    re-keyed.

Maintenance

  • Added unit tests for the Dock reducer:
    • user-hidden Dock is not managed by Quick Terminal
    • normal Spaces can hide and show the Dock
    • fullscreen Spaces never show the Dock and defer restoration
    • pending shouldBeHidden is applied if the Dock later becomes visible

Rationale

Area Rationale
Two-layer state machine Quick Terminal needs to distinguish desired state from owned side effects. shouldBeHidden records whether Quick Terminal wants the Dock hidden; managedHidden records whether Quick Terminal actually changed global Dock auto-hide and must restore it later. This avoids interfering with users who already keep the Dock hidden.
Fullscreen defer In fullscreen Spaces, macOS hides the Dock even when Dock auto-hide is disabled. Quick Terminal therefore never performs the show/unhide transition while fullscreen is active; it defers restoration until a normal Space is active again.
Focus holding quickterm -> Space change can briefly produce a non-focused Quick Terminal window. If Quick Terminal still owns focus / Dock hiding, it immediately re-keys the same window instead of restoring the Dock and causing a flash.
Debug logging Dock state bugs are hard to inspect from Cocoa alone. The logging bridge exposes QuickTerminal-specific Dock transitions through the existing Ghostty logger, making requested/applied/skipped transitions visible during manual testing.

@exlee exlee requested a review from a team as a code owner June 18, 2026 10:42
@ghostty-bot ghostty-bot Bot added the os/macos label Jun 18, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant