Fixes#7643
This commit address the issue with 3 minor fixes:
1. Initialize ghostty lib before app start, or global allocator will
be null.
2. `addSublayer` should be called on CALayer object, which is the
property 'layer' of UIView
3. According to apple's [document](https://developer.apple.com/documentation/metal/mtlstoragemode/managed?language=objc),
managed storage mode is not supported by iOS. So always use shared
mode.
FYI, another [fix](https://github.com/mitchellh/libxev/pull/204) in libxev
is also required to make iOS app work.
This hides the macOS tab overview when the `escape` key is pressed.
Our solution is a bit blunt here and I don't think its right. I think we
have a first responder problem somewhere but I haven't been able to find
it and find the proper place to implement `cancel` (or equivalent) to
hide the overview. I tried implementing `cancel` in all the places I
expect the responder chain to go through but none worked.
For now let's do this since it is pretty tightly scoped!
This fixes regression of #5690, which kind of comes from #9576. 05b42919d5 (before #9576) has weird behaviours too, restored windows are not properly focused. With this pr, we only order `selectedWindow` front so we won't mess up with its selection state and the order of the tab group.
There is a sparkle-related 'issue' with the previous implementation. When you download/install in the `updateAvailable` state, if you don't install it, then check the updates again. Sparkle loses its downloaded stage in the delegate (it's normal when I use the sparkle source code). This time, when you click install in the `updateAvailable` state, it just uses the previous downloaded package and starts to install, without calling `showReady(toInstallAndRelaunch:)`.
I think removing `readyToInstall` in our customed ui, will reduce one step to install an update for most of the users out there, which makes sense, since the current package is pretty small, only takes a few seconds to download for a normal network, and they intended to install this update.
This includes multiple changes to clean up the "installing" state:
- Ghostty will not confirm quit, since the user has already confirmed
they want to restart to install the update.
- If termination fails for any reason, the popover has a button to retry
restarting.
- The copy and badge symbol have been updated to better match the
reality of the "installing" state.
<img width="1756" height="890" alt="CleanShot 2025-10-12 at 15 04 08@2x"
src="https://github.com/user-attachments/assets/1b769518-e15f-4758-be3b-c45163fa2603"
/>
AI written:
https://ampcode.com/threads/T-623d1030-419f-413f-a285-e79c86a4246b fully
understood.
### Background
Been running Ghostty locally for a while now, and I use the Finder
service a lot. It often confuses me which one is the official one, until
I actually open it.
### Changes
- Use blueprint to distinguish from release app, if no custom icon
specified
- Change BundleDisplayName to Ghostty[Debug]
- Enable Info.plist preprocessing for reading
`$(INFOPLIST_KEY_CFBundleDisplayName)` for providing different services
with different configurations
> (Preprocessing was once reverted
before](https://github.com/ghostty-org/ghostty/commit/6508fec), so I'm
not sure whether this follows the 'rules' here, but for now, there are
no links in the plist file, so I think it’s
[safe](https://developer.apple.com/library/archive/technotes/tn2175/_index.html#:~:text=can%20pass%20the-,%2Dtraditional,-flag%20to%20the)
to enable it
Fixes#8734
This forces the app icon to be set on another event loop tick from
the main startup.
In the future, we should load and set the icon completely in another
thread. It appears that all the logic we have is totally thread-safe.
Fixes#8616
macOS 26 (as of RC1) has some pathological performance bug where the
terminal becomes unusably slow after some period of time. We aren't 100%
sure what triggers the slowdown, but it is app-wide (new tabs or windows
don't resolve it) and Instruments traces point directly to
NSAutoFillHeuristicController. Specifically, to the `debounceTextUpdate`
selector.
This is all not documented as far as I can find and also not open
source, so I have no idea what's going on.
The best I can tell is that the NSAutoFillHeuristicController has
something to do with enabling heuristic-based autofill such as SMS auth
codes in text input fields. I don't know what is causing it to go
haywire.
SMS autofill is not desirable in a terminal app, nor is any of the other
automatic autofill in macOS I know of (contact info, passwords, etc.).
So, we can just disable it.
This default isn't documented but I found it via a strings dump of the
AppKit binary blob and comparing it to the disassembly to see how it is
used. In my limited testing, this seems to work around the problem.
This fixes an issue I noticed where manually launching the `ghostty`
binary in the app bundle via the CLI would open the app but not create a
window or bring it to the front.
This has no meaningful functionality yet, it was one of the paths I was
looking at for #8505 but didn't pursue further. But I still think that
this makes more sense in general for the macOS app and will likely be
more useful later.
Supporting command line, file menu and keybindings.
Default mac shortcut of `super + alt + o` (other)
Not able to test on Linux so excluding `close_other_tabs` from `gtk` for now
make a default short cut for close other tabs
This adds a new configuration option that controls whether folders
dropped onto the Ghostty dock icon open in a new tab (default) or
a new window.
The option accepts two values:
- tab: Opens folders in a new tab in the main window (default)
- window: Opens folders in a new window
This is useful for users who prefer window-based workflows over
tab-based workflows when opening folders via drag and drop.
Fixes#5256
This updates the macOS apprt to implement the `OPEN_URL` apprt action to
use the NSWorkspace APIs instead of the `open` command line utility.
As part of this, we removed the `ghostty_config_open` libghostty API and
instead introduced a new `ghostty_config_open_path` API that returns the
path to open, and then we use the `NSWorkspace` APIs to open it (same
function as the `OPEN_URL` action).
This makes it so `zig build run` can take arguments such as
`--config-default-files=false` or any other configuration. Previously,
it only accepted commands such as `+version`.
Incidentally, this also makes it so that the app in general can now take
configuration arguments via the CLI if it is launched as a new instance
via `open`. For example:
open -n Ghostty.app --args --config-default-files=false
This previously didn't work. This is kind of cool.
To make this work, the libghostty C API was modified so that
initialization requires the CLI args, and there is a new C API to try to
execute an action if it was set.
`zig build run` on macOS now builds the app bundle via the `xcodebuild`
CLI and runs it. The experience for running the app is now very similar
to Linux or the prior GLFW build, where the app runs, blocks the zig
command, and logs to the terminal.
`xcodebuild` has its own build cache system that we can't really hook
into so it runs on every `zig build run` command, but it does cache and
I find its actually relatively fast so I think this is a good
replacement for the glfw-based system.
This is done at the apprt-level for a couple reasons.
(1) For libghostty, we don't have a way to know what the embedding
application is doing, so its risky to create signal handlers that
might overwrite the application's signal handlers.
(2) It's extremely messy to deal with signals and multi-threading.
Apprts have framework access that handles this for us.
For GTK, we use g_unix_signal_add.
For macOS, we use `DispatchSource.makeSignalSource`. This is an awkward
API but made for this purpose.