Commit Graph

1847 Commits

Author SHA1 Message Date
Mitchell Hashimoto
4b1e02c7c3 macos: do not load the config errors window when there are no errors
Measured on macOS (Apple Silicon) during app launch, via a startup
timeline instrumented across the Swift app and libghostty:

  config apply, errors step:      35.5ms -> 0.1ms
  main() -> first frame rendered: ~126ms -> ~93ms
  main() -> window visible:       ~193ms -> ~173ms
2026-08-09 19:54:28 -07:00
Lukas
74f91d1b43 macOS: support drag-handle config 2026-08-09 15:14:50 +02:00
Mitchell Hashimoto
2602886144 macOS: fix quit alert missing when hidden (#13686)
Fixes https://github.com/ghostty-org/ghostty/discussions/13685.

Removed presumably deprecated check introduced in
8f1a014afd for update pill
> I checked for auto update as well, it works as before this, and for
manual updates we're not confirming anyway, so I think its safe to
remove it now.

Each BaseTerminalController already has quit check and confirming code
added in that review windows pr. It didn't cover QT before, overriding
it to animate in for showing alert.

[#5450](https://github.com/ghostty-org/ghostty/issues/5450) stays fixed.




https://github.com/user-attachments/assets/dbf36f16-e3ce-4f6a-bc25-367fe48739b9
2026-08-07 13:21:50 -07:00
Lukas
e83cf0b06f macOS: fix quit alert missing when hidden 2026-08-07 20:11:16 +02:00
Mitchell Hashimoto
4693e1b546 macos: sync appearance when new windows are created (#13675)
For new windows to get their appearance synced, we need to call
`syncAppearance` after `super.showWindow(sender)`. All previous calls to
`syncAppearance` on `TerminalWindow` will be ignored because the window
needs to have `isVisible` set to `true`.

This regression was introduced by:
5368adcd29

It added `.dropFirst()` to the `focusedSurface` appearance publishers in
`TerminalController.swift` which removes the initial call of the
subscription.

Fixes https://github.com/ghostty-org/ghostty/issues/13324

(landed on the same fix as @rasitakyol found here:
https://github.com/ghostty-org/ghostty/pull/13341)
2026-08-07 08:02:54 -07:00
Lukas
fd98370211 macOS: fix swiftlint 2026-08-07 16:51:19 +02:00
Mitchell Hashimoto
faeac91fa5 macOS: fix window sizing after dragging a split into a window (#13682)
Regression from
[#13601](https://github.com/ghostty-org/ghostty/issues/13601), but I
don't see why it matters. But the surface's bounds changes after
window's created.
2026-08-07 07:38:48 -07:00
Mitchell Hashimoto
fcee19819e macos: discard debounced selection notification (#13676)
Discard the selection notification payload before debouncing
accessibility changes.

The debouncer previously retained the notification and its surface
object, keeping a closed tab's view and PTY alive after the undo
timeout.
2026-08-07 07:14:54 -07:00
Lukas
96826853bd macOS: fix window sizing after dragging a split into a window 2026-08-07 15:14:30 +02:00
Mitchell Hashimoto
44a05a88aa macos: discard debounced selection notification
Discard the selection notification payload before debouncing
accessibility changes.

The debouncer previously retained the notification and its surface
object, keeping a closed tab's view and PTY alive after the undo
timeout.
2026-08-06 13:05:37 -07:00
Christoffer Winterkvist
e11bfb5139 macos: sync appearance when new windows are created (#13324)
call `syncAppearance` after `super.showWindow` has been called to
ensure that the window is visible.
2026-08-06 19:53:48 +02:00
Lukas
18f06ef03c macOS: fix unsupported action falls through wrong handling 2026-08-06 16:17:11 +02:00
Lukas
301bd6f8b0 macOS: hide settings menu icon on macOS 27
Settings appears to be somehow special and it's not hidden previously.
2026-08-06 12:21:36 +02:00
Mitchell Hashimoto
e88601239d macOS: update command options match order (#13624)
Matches are sorted in the following order:
leadingColor > title > subtitle > description.

Ranking is lexicographic on (colorScore, textScore)

<img height="300" alt="image"
src="https://github.com/user-attachments/assets/1ec99e67-537e-4fc6-b595-d7eec8cbf31d"
/>


### AI Disclosure

Claude reviewed and added unit tests, also did some refactoring of my
original implementation.
2026-08-05 15:29:50 -07:00
Mitchell Hashimoto
ae0ff51c42 macos: defer overlapping clipboard completion (#13648)
Fixes #13074

Overlapping clipboard confirmations now defer denial until the next main
queue turn rather than completing inside the confirmation callback.

This prevents the native request state from being invalidated while its
callback is still active, avoiding the OSC 52 crash reported in #13074.

The deferred closure retains the originating surface view and completes
the ignored request with empty data, preserving the existing deny
behavior.
2026-08-05 15:19:34 -07:00
Mitchell Hashimoto
c9ef382fc9 macos: synchronize cached value access (#13646)
Fixes #13276

Make CachedValue safe for concurrent terminal content reads and expiry.

The expiry task could previously release cached Swift String storage
while another thread retained it, aborting the process during otherwise
normal terminal use.

Protect cached values and task handles with an NSLock, and exercise
concurrent reads across repeated expiration in a regression test.
2026-08-05 15:19:03 -07:00
Mitchell Hashimoto
947e839930 macos: prevent stale search selection crash (#13645)
Fixes #13266

Keep search text and its selection range synchronized as a single state
transition.

Deleting or replacing a search term could leave a String.Index range
from the old value attached to the text field. Applying that range could
crash the app.

Clear selection before publishing new text.
2026-08-05 14:55:37 -07:00
Mitchell Hashimoto
57c1baf43a macos: defer overlapping clipboard completion
Fixes #/13074

Overlapping clipboard confirmations now defer denial until the next
main queue turn rather than completing inside the confirmation callback.

This prevents the native request state from being invalidated while its
callback is still active, avoiding the OSC 52 crash reported in #13074.

The deferred closure retains the originating surface view and completes
the ignored request with empty data, preserving the existing deny
behavior.
2026-08-05 14:24:37 -07:00
Mitchell Hashimoto
d28bc121a8 macos: synchronize cached value access
Fixes #13276

Make CachedValue safe for concurrent terminal content reads and expiry.

The expiry task could previously release cached Swift String storage
while another thread retained it, aborting the process during otherwise
normal terminal use.

Protect cached values and task handles with an NSLock, and exercise
concurrent reads across repeated expiration in a regression test.
2026-08-05 14:18:33 -07:00
Mitchell Hashimoto
880eded158 macos: avoid IOSurface leak on automated surface creation (#13640)
Fixes #13444

A close while AppKit temporarily cleared/changed a surface's window
would leak the surface in the controller's pslit tree. This retained
surface kept a bunch of resources around, particularly large IOSurfaces.

This seems to only be reproducible under scripted load: rapid terminal
creation/destruction so that destruction happens just while there is a
nil window on a surface view.

Track surface ownership in a weak controller map updated alongside the
split tree, with validated fallbacks for existing attachment state.
Resolve scripted and App Intent operations through that ownership, and
route non-confirming root closes directly through the immediate tab or
window close path so teardown always reaches the renderer.
2026-08-05 14:18:22 -07:00
Mitchell Hashimoto
74f01cf5df macos: prevent stale search selection crash
Fixes #13266

Keep search text and its selection range synchronized as a single
state transition.

Deleting or replacing a search term could leave a String.Index range
from the old value attached to the text field. Applying that range
could crash the app.

Clear selection before publishing new text.
2026-08-05 14:02:46 -07:00
Mitchell Hashimoto
7a047553c7 macos: avoid IOSurface leak on automated surface creation
Fixes #13444

A close while AppKit temporarily cleared/changed a surface's window would
leak the surface in the controller's pslit tree. This retained surface kept
a bunch of resources around, particularly large IOSurfaces.

This seems to only be reproducible under scripted load: rapid terminal
creation/destruction so that destruction happens just while there is a nil
window on a surface view.

Track surface ownership in a weak controller map updated alongside the split
tree, with validated fallbacks for existing attachment state. Resolve
scripted and App Intent operations through that ownership, and route
non-confirming root closes directly through the immediate tab or window close
path so teardown always reaches the renderer.
2026-08-05 13:39:48 -07:00
Mitchell Hashimoto
8696bef644 macos: guard fullscreen tab presentation
#13611

Route new-tab window presentation through an Objective-C exception catcher.

AppKit can raise an NSInternalInconsistencyException while selecting a
new tab in native fullscreen.

Catch the presentation exception, report it through the existing error
logging path, and leave Ghostty running when AppKit’s fullscreen window
stack is inconsistent.

This was pretty hard to reproduce but I was able to reproduce it about
1/3rd of the time via AppleScript automation...
2026-08-05 11:25:18 -07:00
Mitchell Hashimoto
77537c8065 macos: handled untrusted OSC8 hyperlinks more carefully
OSC8 hyperlinks previously executed directly via the NSWorkspace opener
so a malicious application can just do whatever it wanted and trick the
user into opening something through Launch Services.

This PR notifies apprt of OSC8 hyperlinks so they can be handled
specially. In this PR, I added macOS-specific handling of OSC8 through a
variety of improvements:

  - Preview text is sanitized, so invisible Unicode characters now show.
  - Questionable-looking URLs require confirmation to open, but a user
    can confirm to open.
  - Very questionable or definitely unsafe URLs are blocked with an 
    alert that only allows the user to copy the link. The alert also
    notifies the user why.
2026-08-05 10:22:28 -07:00
Claude Fable 5
d02ad967b6 macOS: update command options match order
Matches are sorted in the following order:
leadingColor > title > subtitle > description.

Ranking is lexicographic on (colorScore, textScore)
2026-08-05 16:15:01 +02:00
Lukas
c93752a008 macOS: suppress restart tips for auto update 2026-08-05 15:15:40 +02:00
Mitchell Hashimoto
d7f7a4e736 macOS: rename UpdateState.isIdle to isHidden (#13613) 2026-08-04 19:28:05 -07:00
Lukas
a86c49d7af macOS: rename UpdateState.isIdle to isHidden 2026-08-04 22:38:35 +02:00
Lukas
63d08c0342 macOS: show cancel update option when its actually cancellable
`extracting` and `installing` state aren't cancellable by us
2026-08-04 22:18:35 +02:00
Mitchell Hashimoto
b8ab2ff168 macOS: show/search description when subtitle missing in CommandPalette (#13610)
<img width="1125" height="552" alt="image"
src="https://github.com/user-attachments/assets/09866c9b-d5c4-422f-860b-de4de4cca055"
/>
2026-08-04 11:20:01 -07:00
Lukas
066a0b7c45 macOS: show description when subtitle missing in CommandPalette 2026-08-04 20:03:04 +02:00
Mitchell Hashimoto
cfa0ca7106 macos: defer transparent titlebar KVO rebinding
Fixes #13386

Defer transparent-titlebar KVO rebinding to the next main-queue turn.
Track the observed tab group so unchanged bindings are preserved.

Previously, a tab-group callback could invalidate and recreate its own
observation before returning, leaving closed terminal windows registered
with AppKit after the undo timeout. These windows accumulated titlebar and
layer state, increasing memory use and WindowServer CPU with tab churn.

Validated with an AppDelegate change that sat and created/closed tabs
in a loop, then counted weak controllers/windows/nsapp window.

Co-authored-by: Mustafa J <mustafa.0x@gmail.com>
2026-08-04 06:40:41 -07:00
Mitchell Hashimoto
2b6a1e41fc macos: avoid leaking ports while awaiting accessibility
#11799

Creating a CGEventTap without Accessibility permission leaks a Mach
port inside CoreGraphics on every failed attempt. The global keybind
listener retried this once per second while waiting for permission, so
Ghostty eventually exhausted the process port limit.

Request Accessibility access once, poll AXIsProcessTrusted while
access is denied, and create the event tap only after access is
granted. Stop polling before creation so an unrelated tap failure
cannot restart the leaking retry loop.
2026-08-03 20:41:39 -07:00
Lukas
3a606c6c41 macOS: install update with same code path 2026-08-02 21:21:51 +02:00
Mitchell Hashimoto
46edeee407 macOS: fix update error pill is not showing properly (#13540)
`acknowledgement` will call `dismissUpdateInstallation` so the error
state will never happen.
2026-08-01 14:28:06 -07:00
Lukas
cc1d262105 macOS: fix update error pill is not showing properly 2026-08-01 15:35:44 +02:00
Uzair Aftab
ad96613a8c inspector: add copy and export for terminal IO events
Adds "Copy" and "Export to file" buttons to the Terminal IO inspector
so recorded VT events can be saved outside the app for sharing or
analysis.

Export is wired up through a new export_terminal_io apprt action,
handled with a native save dialog on both macOS and GTK.
2026-07-30 08:08:25 +02:00
Mitchell Hashimoto
1ce5d4229e Revert "macOS: fix undo new tab will cause a crash (#9512)" (#13467)
We don't need this anymore after #13364
2026-07-26 14:50:06 -07:00
Lukas
a6edca2d7c macOS: free surface synchronously in deinit on main thread 2026-07-26 16:12:34 +02:00
Lukas
35790a7e56 Revert "macOS: fix undo new tab will cause a crash (#9512)"
This reverts commit fbabafe8e3, reversing
changes made to 7f0468f910.
2026-07-26 16:08:46 +02:00
Lukas
fa3802a70e macOS: change split drag's point style to match HIG 2026-07-23 21:33:47 +02:00
Lukas
2104e0749c macOS: hide visible NSScrollPocket for hidden title bar
Fixes https://github.com/ghostty-org/ghostty/issues/13390
2026-07-20 14:30:43 +02:00
Mitchell Hashimoto
f815f84594 macos: fix quick terminal restoring stale size after display reconnect (#13250)
"Why is my quick terminal not taking up the entire top of my docked Mac
screen after I reconnect?" Boy howdy are you in the right PR.

It turns out that the quick terminal caches its last-closed window frame
per display so it can restore the user's size when reopened. The cache
entry was considered valid whenever the current screen was the same size
*or larger* than when the frame was saved ("persist when screens grow").
This has led to a pattern that was simply maddening. To wit: that rule
breaks across display changes.

When an external display is disconnected and later reconnected at a
different resolution (common after traveling with a laptop, do not even
get me started on projectors) the same display can come back larger than
when the frame was cached. The stale frame is still treated as valid and
restored, so the quick terminal no longer fills the screen (it appears
at a partial width/height). Because the cache is persisted, restarting
Ghostty does not clear it, and the user is slowly driven mad. Welcome to
madness; we have snacks.

This PR addresses this by treating a cached frame as valid when the
screen geometry matches exactly (both backing scale factor and frame
size). On any mismatch we drop the entry and fall back to the configured
quick-terminal-size. Manual resizes are still remembered across toggles
within a stable display configuration.

Fixes the regression reported in #12348.

AI disclaimer: I used AI for this. Of course I used AI for this, my code
is terrible on a good day. Specifically, Claude Code, as well as a
custom harness that has the curious tendency to write commit messages
containing conspiracy theories about the code because I am history's
greatest monster.

Fight me!
2026-07-08 10:49:39 -07:00
Lukas
91f66da245 macos: route IME preedit commits through key events (#13222) 2026-07-08 07:06:44 +02:00
qappell
751a60df61 macos: route IME preedit commits through key events 2026-07-07 13:00:39 -05:00
Lukas
6e267d3363 macOS: use the getOpinionatedStringContents same as paste 2026-07-06 09:04:24 +02:00
Mitchell Hashimoto
b213a72c03 macOS: only read file urls for new-terminal services (#13169)
macOS is already guarding this in Services settings, but guarding what
we actually need anyway
2026-07-05 13:50:34 -07:00
Lukas
10565995b9 macOS: only read file urls for new-terminal services
macOS is already guarding this system, but guarding what we actually need anyway
2026-07-03 13:24:55 +02:00
Lukas
49806fc4cc macOS: read string contents per pasteboard item in order
Pasteboards mixing file URLs with other items will now be pasted as joined string.
2026-07-03 12:53:34 +02:00
Corey Quinn
0274e7ad84 macos: fix quick terminal restoring stale size after display reconnect
The quick terminal caches its last-closed window frame per display so it
can restore the user's size when reopened. The cache entry was considered
valid whenever the current screen was the same size *or larger* than when
the frame was saved ("persist when screens grow"). This has led to a pattern
that was simply maddening. To wit:

That rule breaks across display changes. When an external display is
disconnected and later reconnected at a different resolution (common
after traveling with a laptop) the same display can come back larger
than when the frame was cached. The stale frame is still treated as valid
and restored, so the quick terminal no longer fills the screen (it appears
at a partial width/height). Because the cache is persisted, restarting
Ghostty does not clear it, and the user is slowly driven mad.

Only treat a cached frame as valid when the screen geometry matches
exactly (both backing scale factor and frame size). On any mismatch we
drop the entry and fall back to the configured quick-terminal-size. Manual
resizes are still remembered across toggles within a stable display
configuration.

Fixes the regression reported in #12348.
2026-06-29 15:31:07 -07:00