Commit Graph

1339 Commits (77b038dcb6c239a2885ebcaeeec9042ad1eb47e3)

Author SHA1 Message Date
Mitchell Hashimoto 1388c277d5 macos: sequoia should use same tab bar identifier as TerminalWindow 2025-06-13 14:43:04 -07:00
Mitchell Hashimoto 8cfc904c0c macos: fix up some sequoia regressions 2025-06-13 14:39:12 -07:00
Mitchell Hashimoto a7df90ee55
macos: remove split zoom accessory when tabs appear 2025-06-13 13:36:42 -07:00
Mitchell Hashimoto f7f0514b9f
macos: move old toolbar into ventura file 2025-06-13 13:14:16 -07:00
Mitchell Hashimoto 59812c3b02
macos: remove TODO 2025-06-13 12:27:44 -07:00
Mitchell Hashimoto b1b74d3421
comments 2025-06-13 12:25:21 -07:00
Mitchell Hashimoto 00d41239da
macOS: prep the tab bar when system appearance changes 2025-06-13 12:22:29 -07:00
Mitchell Hashimoto 17ad77b5b0
macos: fix background color of terminal window to match surface 2025-06-12 21:36:00 -07:00
Mitchell Hashimoto 9d9c451b0a
macos: titlebar tabs handle hidden traffic buttons 2025-06-12 20:03:21 -07:00
Mitchell Hashimoto d84c30ce71
macos: titlebar tabs should be transparent 2025-06-12 18:10:37 -07:00
Mitchell Hashimoto 5f99670247
macos: tahoe titlebar tabs taking shape 2025-06-12 17:52:15 -07:00
Mitchell Hashimoto 6ae8bd737a
macos: hide the reset zoom titlebar accessory when tab bar is shown 2025-06-12 15:13:23 -07:00
Mitchell Hashimoto 5c8f1948ce
macos: remove the duplicated reset zoom accessory view from legacy 2025-06-12 14:42:09 -07:00
Mitchell Hashimoto de40e7ce02
macos: non-native fullscreen should restore toolbars 2025-06-12 14:36:33 -07:00
Mitchell Hashimoto 658ec2eb6f
macos: add reset zoom to all window titles 2025-06-12 14:33:53 -07:00
Mitchell Hashimoto 70029bf82a
macos: tahoe terminal tabs shows title 2025-06-12 13:39:19 -07:00
Mitchell Hashimoto 5877913ab8
macoS: Split out terminal tabs for ventura vs tahoe 2025-06-12 12:06:30 -07:00
Mitchell Hashimoto fd785f98bb
macos: titlebar tabs uses legacy window for now 2025-06-12 11:39:10 -07:00
Mitchell Hashimoto ccfd33022f
macos: only titlebar tabs uses legacy styling now 2025-06-11 15:18:02 -07:00
Mitchell Hashimoto e5cb33e911
typos 2025-06-11 15:18:02 -07:00
Mitchell Hashimoto 63e56d0402
macos: titlebar fonts work with new terminal window 2025-06-11 15:18:02 -07:00
Mitchell Hashimoto a804dab288
macos: native terminal style works with new subclasses 2025-06-11 15:18:02 -07:00
Mitchell Hashimoto dfa7a114de
macos: make transparent titlebars robust against show/hide tabs 2025-06-11 15:18:02 -07:00
Mitchell Hashimoto 3595b2a847
macos: transparent titlebar handles transparent background 2025-06-11 15:18:02 -07:00
Mitchell Hashimoto 6ce7f612a6
macos: transparent titlebar needs to be rehidden when tabs change 2025-06-11 15:18:02 -07:00
Mitchell Hashimoto 7d02977482
macos: add NSView hierarchy debugging code 2025-06-11 15:18:02 -07:00
Mitchell Hashimoto 4d33a73fc4
wip: redo terminal window styling 2025-06-11 15:18:02 -07:00
Mitchell Hashimoto 3db5b3da75
macos: hidden titlebar windows should cascade on new tab
Windows with `macos-titlebar-style = hidden` create new windows when the
new tab binding is pressed. This behavior has existed for a long time.

However, these windows did not cascade, meaning they'd appear overlapped
directly on top of the previous window, which is kind of nasty.

This commit changes it so that new windows created via new tab from a
hidden titlebar window will cascade.
2025-06-10 14:31:41 -07:00
Mitchell Hashimoto 1f340b4b2d
macos: for windowShouldClose, only close the tab if we have multiple
Fixes a regression from our undo/redo rework. We were accidentally
closing the entire window when the "X" button in the tab bar was
clicked.
2025-06-10 12:39:09 -07:00
Mitchell Hashimoto 2b9a6a4820
macos: unsplit window shouldn't allow split zooming
This was always the case, and is a recent regression from the SplitTree
rework. This brings it back to the previous behavior.
2025-06-10 12:11:18 -07:00
Mitchell Hashimoto e4cd90b8a0
macos: set explicit identity for split tree view based on structure
Fixes #7546

SwiftUI uses type and structure to identify views, which can lead
to issues with tree like structures where the shape and type is the same
but the content changes. This was causing #7546.

To fix this, we need to add explicit identity to the split tree view
so that SwiftUI can differentiate when it needs to redraw the view.

We don't want to blindly add Hashable to SplitTree because we don't want
to take into account all the fields. Instead, we add an explicit
"structural identity" to the SplitTreeView that can be used by SwiftUI.
2025-06-08 20:11:58 -07:00
Mitchell Hashimoto 26e1dd8f8e
macos: clear out the surface trees to prevent repeat undo
see the comment
2025-06-08 12:41:45 -07:00
Mitchell Hashimoto 3de3f48faf
macos: fix undo/redo for closing windows with multiple tabs
When closing a window that contains multiple tabs, the undo operation
now properly restores all tabs as a single tabbed window rather than
just restoring the active tab.

The implementation:
- Collects undo states from all windows in the tab group before closing
- Sorts them by their original tab index to preserve order
- Clears tab group references to avoid referencing garbage collected objects
- Restores all windows and re-adds them as tabs to the first window
- Tracks and restores which tab was focused (or focuses the last tab if none were)

AI prompts that generated this commit are below.

Each separate prompt is separated by a blank line, so this session was
made up with many prompts in a back-and-forth conversation.

> We need to update the undo/redo implementation in
> @macos/Sources/Features/Terminal/TerminalController.swift `closeWindowImmediately`
> to handle the case that multiple windows in a tab group are closed all at once,
> and to restore them as a tabbed window. To do this, I think we should collect
> all the `undoStates`, sort them by `tabIndex` (null at the end), and then on j
> restore, restore them one at a time but add them back to the same tabGroup. We
> can't use the tab group in the `undoState` because it will be garbage collected
> by then. To be sure, we should just set it to nil.

I should note at this point that the feature already worked, but the
code quality and organization wasn't up to my standards. If someone
using AI were just trying to make something work, they might be done at
this point.

I do think this is the biggest gap I worry about with AI-assisted
development: bridging between the "it works" stage at a junior quality
and the "it works and is maintainable" stage at a senior quality. I
suspect this will be a balance of LLMs getting better but also senior
code reviewers remaining highly involved in the process.

> Let's extract all the work you just did into a dedicated private method
> called `registerUndoForCloseWindow`

Manual: made some tweaks to comments, moved some lines around, didn’t change
any logic.

> I think we can pull the tabIndex directly from the undoState instead of
> storing it in a tuple.

> Instead of `var undoStates`, I think we can create a `let undoStates` and
> build and filter and sort them all in a chain of functional mappings.

> Okay, looking at your logic for restoration, the `var firstController` and
> conditionals are littly messy. Can you make your own pass at cleaning those
> up and I'll review and provide more specific guidance after.

> Excellent. Perfect. The last thing we're missing is restoring the proper
> focused window of the tab group. We should store that and make sure the
> proper window is made key. If no windows were key, then we should make the
> last one key.

> Excellent. Any more cleanups or comments you'd recommend in the places you
> changed?

Notes on the last one: it gave me a bunch of suggestions, I rejected most but
did accept some.

> Can you write me a commit message summarizing the changes?

It wrote me a part of the commit message you're reading now, but I
always manually tweak the commit message and add my own flair.
2025-06-08 08:08:01 -07:00
Mitchell Hashimoto ec043e1386
macos: red traffic light should be undoable 2025-06-08 07:00:51 -07:00
Mitchell Hashimoto 6f6d493763
macos: show quick terminal on undo/redo 2025-06-07 13:14:21 -07:00
Mitchell Hashimoto 6e77a5a6ca
macos: address quick terminal basic functionality with new API 2025-06-07 13:07:31 -07:00
Mitchell Hashimoto 20744f0482
macos: fix some CI build issues 2025-06-07 12:46:15 -07:00
Mitchell Hashimoto 973a2afdde
macos: make sure we're not registering unnecessary undos 2025-06-07 12:46:15 -07:00
Mitchell Hashimoto b234cb2014
macos: only process reopen if already activated 2025-06-07 12:46:15 -07:00
Mitchell Hashimoto aeede903f5
macos: undo close all windows 2025-06-07 12:46:15 -07:00
Mitchell Hashimoto d92db73f25
macos: undo new tab 2025-06-07 12:46:15 -07:00
Mitchell Hashimoto 636b1fff8a
macos: initial window shouldn't support undo 2025-06-07 12:46:15 -07:00
Mitchell Hashimoto 797c10af37
macos: undo new window 2025-06-07 12:46:15 -07:00
Mitchell Hashimoto 33d128bcff
macos: remove TerminalManager
All logic related to TerminalController is now in TerminalController.
2025-06-07 12:46:15 -07:00
Mitchell Hashimoto 5507ec0fc0
macos: compile errors in CI 2025-06-07 12:46:15 -07:00
Mitchell Hashimoto d2d3852026
macos: remove debug log 2025-06-07 12:46:14 -07:00
Mitchell Hashimoto 49cc88f0d3
macos: configurable undo timeout 2025-06-07 12:46:14 -07:00
Mitchell Hashimoto 3e02c0cbd5
macos: fix an incorrect bindable write during view update 2025-06-07 12:46:14 -07:00
Mitchell Hashimoto b044f4864a
add undo/redo keybindings, default them on macOS 2025-06-07 12:46:14 -07:00
Mitchell Hashimoto e1847da139
macos: more robust undo tab that goes back to the same position 2025-06-07 12:46:14 -07:00
Mitchell Hashimoto 5f74445b14
macos: basic undo tab, not quite working 2025-06-07 12:46:14 -07:00
Mitchell Hashimoto 104cc2adfe
macos: basic undo close window, not very robust yet 2025-06-07 12:46:14 -07:00
Mitchell Hashimoto f571519157
macos: setup undo responders at the AppDelegate level 2025-06-07 12:46:14 -07:00
Mitchell Hashimoto 6d32b01c64
macos: implement a custom ExpiringUndoManager, setup undo for new/close 2025-06-07 12:46:14 -07:00
Mitchell Hashimoto 493b1f5350
wip: undo 2025-06-07 12:46:13 -07:00
Mitchell Hashimoto 41ee578b7a
macos: quick terminal restores previous size when exiting final surface
This fixes a regression from the new split work last week, but it was
also probably an issue before that in a slightly different way.

With the new split work, the quick terminal was becoming unusable when
the final surface explicitly `exit`-ed, because AppKit/SwiftUI would
resize the window to a very small size and you couldn't see the new
terminal on the next toggle.

Prior to this, I think the quick terminal would've reverted to its
original size but I'm not sure (even if the user resized it manually).

This commit saves the size of the quick terminal at the point all
surfaces are exited and restores it when the quick terminal is shown the
next time with a new initial surface.
2025-06-07 12:37:44 -07:00
Mitchell Hashimoto 269d29624b
Add bell feature flags for audio, attention, and title actions on macOS (#7533)
Resolve #7526
2025-06-06 12:59:23 -07:00
Aaron Ruan 5f6a15abef
Add bell feature flags for audio, attention, and title actions on macOS
Signed-off-by: Aaron Ruan <i@ar212.com>
2025-06-06 23:54:34 +08:00
Mitchell Hashimoto 70f030e3c2
macos: dismiss notifications on focus, application exit
I've only recently been using programs that use user notifications heavily
and this commit addresses a number of annoyances I've encountered.

  1. Notifications dispatched while the source terminal surface is
     focused are now only shown for a short time (3 seconds hardcoded)
     and then automatically dismiss.

  2. Notifications are dismissed when the target surface becomes focused
     from an unfocused state. This dismissal happens immediately (no
     delay).

  3. Notifications are dismissed when the application exits.

  4. This fixes a bug where notification callbacks were modifying view
     state, but the notification center doesn't guarantee that the
     callback is called on the main thread. We now ensure that
     the callback is always called on the main thread.
2025-06-06 07:28:32 -07:00
Mitchell Hashimoto 08101b0bc5
macos: fix hasWindowButtons logic (#7504 follow-up) (#7528)
Took another look through #7504 after the merge and realized that the
logic behind the `hasWindowButtons` property wasn't quite sound. It
would return `false` if either _at least one_ button were missing in the
`standardWindowButton(.theButton) == nil` sense, or if _all_ buttons
were hidden in the `isHidden` sense.

With this PR, the logic is rectified: `false` if _all_ buttons are
missing or hidden in any sense, otherwise `true`.

In practice, I suppose Ghostty won't ever instantiate a `TerminalWindow`
where `standardWindowButton(.theButton) == nil`, but might as well get
it right and sleep better at night.
2025-06-05 14:11:10 -07:00
Daniel Wennberg c2c267439b macos: fix hasWindowButtons logic 2025-06-05 13:48:53 -07:00
Mitchell Hashimoto 045c84acb7
macos: split directional navigation should use distance to leaf
Fixes regression from #7523

I messed two things up around spatial navigation in the split tree
that this commit fixes:

  1. The distance in the spatial tree only used a single dimension
     that we were navigating. This commit now uses 2D euclidean
     distance from the top-left corners of nodes. This handles the case
     where the nodes are directly above or below each other better.

  2. The spatial slots include split containers because they are layout
     elements. But we should only navigate to leaf nodes. This was
     causing the wrong navigatin to happen in some scenarios.
2025-06-05 13:43:07 -07:00
Mitchell Hashimoto efc1ceab5d
macOS: New value-based split tree implementation, move split logic out of SwiftUI into AppKit (#7523)
This is a major rework of how we represent, handle, and render splits in
the macOS app.

This new PR moves the split structure into a dedicated, generic
(non-Ghostty-specific) value-type called `SplitTree<V>`. All logic
associated with splits (new split, close split, move split, etc.) is now
handled by notifications on `BaseTerminalController`. The view hierarchy
is still SwiftUI but it has no logic associated with it anymore and
purely renders a static tree of splits.

Previously, the split hierarchy was owned by AppKit in a type called
`SplitNode` (a recursive class that contained the tree structure). All
logic around creating, zooming, etc. splits was handled by notification
listeners directly within the SwiftUI hierarchy. SwiftUI managed a
significant amount of state and we heavily used bindings, publishers,
and more. The reasoning for this is mostly historical: splits date back
to when Ghostty tried to go all-in on SwiftUI. Since then, we've taken a
more balanced approach of SwiftUI for views and AppKit for data and
business logic, and this has proven a lot more maintainable.

## Spatial Navigation

Previously, focus moving was handled by traversing the tree structure.
This led to some awkward behaviors. See:
https://github.com/ghostty-org/ghostty/issues/524#issuecomment-2668396095

In this PR, we now handle focus moving spatially. This means that move
"left" means moving to the visually left split (from the top-left
corner, a future improvement would be to do it from the cursor
position).

Concretely, given the following split structure:

```
+----------+-----+
|          |  b  |
|          |     |
|   a      +-----+
|          |     |
|          |     |
|          |     |
|          |     |
|----------|  d  |
|   c      |     |
|          |     |
+----------+-----+
```

Moving "right" from `c` now moves to `d`. Previously, it would go to
`b`. On Linux, it still goes to `b`.

## Value Types

One of the major architectural shifts is moving **purely to immutable
value types.** Whenever a split property changes such as a new split,
the ratio between splits, zoomed state, etc. we _create an entirely new
`SplitTree` value_ and replace it along the entire view hierarchy. This
is in some ways wasteful, but split hierarchies are relatively small
(even the largest I've seen in practical use are dozens of splits, which
is small for a computer). And using value types lets us get rid of a ton
of change notification soup around the SwiftUI hierarchy. We can rely on
reference counting to properly clean up our closed views.

> [!NOTE]
> 
> As an aside, I think value types are going to make it a lot easier in
the future to implement features like "undo close." We can just keep a
trailing list of surface tree states and just restore them. This PR
doesn't do anything like that, but it's now possible.

## SwiftUI Simplicity

Our SwiftUI view hierarchy is dramatically simplified. See the
difference in `TerminalSplitTreeView` (new) vs `TerminalSplit` (old).
There's so much less logic in our new views (almost none!). All of it is
in the AppKit layer which is just way nicer.

## AI Notes

This PR was heavily written by AI. I reviewed every line of code that
was rewritten, and I did manually rewrite at every step of the way in
minor ways. But it was very much written in concert. Each commit usually
started as an AI agent writing the whole commit, then nudging to get
cleaned up in the right way.

One thing I found in this task was that until the last commit, I kept
the entire previous implementation around and compiling. The agent
having access to a previous working version of code during a refactor
made the code it produced as follow up in the new architecture
significantly better, despite the new architecture having major
fundamental differences in how it works!
2025-06-05 12:59:43 -07:00
Mitchell Hashimoto a2a3863ad2
macOS: Add option to hide window buttons (#7504)
Conversion of #7497 to a PR. This implements a feature requested in
#7331: an option to hide the default window buttons on macOS for a
cleaner aesthetic.

~~Builds on #7502 as it requires the same change to avoid the main
toolbar title showing on top of the tab bar.~~ EDIT: rebased on main now
that #7502 was merged.

I aligned the scope of the new option with `macos-titlebar-style`, since
they both customize titlebar elements. This means it has the same edge
case quirks: For example, if you change the setting, reload the config,
and then open a new tab, the appearance of the current window will
depend on which tab is in the foreground. I did it this way because
`macos-titlebar-style` provided an easy template for which derived
configs and functions to modify. Let me know if you want me to try
adjusting this so that a change in the setting also takes effect for
current windows/tabs, which I _think_ should be possible.

Screenshots:
* `macos-titlebar-style = transparent` (default)
![Screenshot 2025-06-01 at 18 04
56](https://github.com/user-attachments/assets/01fa3953-d2ef-4c39-a6e3-f236488dd841)
![Screenshot 2025-06-01 at 18 07
24](https://github.com/user-attachments/assets/cd463ded-a0b2-4f69-9abe-384e7eecaa27)
* `macos-titlebar-style = tabs`
![Screenshot 2025-06-01 at 17 56
35](https://github.com/user-attachments/assets/bf99d046-cdbb-4e5d-b1c5-d51bbba79007)
![Screenshot 2025-06-01 at 17 56
48](https://github.com/user-attachments/assets/098164b8-bf97-4df1-9dff-c1c17e12665d)
2025-06-05 07:46:57 -07:00
Mitchell Hashimoto 6db455eee5
fix: exit non-native fullscreen on close (#7525)
Fixes https://github.com/ghostty-org/ghostty/discussions/7159.
2025-06-05 07:36:50 -07:00
Mitchell Hashimoto d4249679e3
macos: simplify some ServiceProvider code (#7508)
First, remove the always-inlined openTerminalFromPasteboard code and
combine it with openTerminal. Now that we're doing a bit of work inside
openTerminal, there's little better to having an intermediate, inlined
function.

Second, combine some type-casting operations (saving a .map() call).

Lastly, adjust some variable names because a generic `objs` or `urls`
was a little ambiguous now that we're all in one function scope.
2025-06-05 07:30:03 -07:00
Francisco Giordano 9008e21637 fix: exit non-native fullscreen on close 2025-06-05 07:25:53 -07:00
Mitchell Hashimoto c40ac6b785
input: add focus split directional commands to command palette 2025-06-05 07:11:18 -07:00
Mitchell Hashimoto 1966dfdef7
macos: moving some files around 2025-06-05 07:05:13 -07:00
Mitchell Hashimoto f8e3539b7d
macos: remove the unused resizeEvent code from SplitView 2025-06-05 07:05:13 -07:00
Mitchell Hashimoto 01fa87f2ab
macos: fix iOS builds 2025-06-05 07:05:13 -07:00
Mitchell Hashimoto 9474092f77
macos: remove the old split implementation 2025-06-05 07:05:13 -07:00
Mitchell Hashimoto 69c3c359cb
macos: resize split keybind handling 2025-06-05 07:05:13 -07:00
Mitchell Hashimoto 5299f10e13
macos: unzoom on new split and focus change 2025-06-05 07:05:13 -07:00
Mitchell Hashimoto 19a9156ae1
macos: address remaining todos 2025-06-05 07:05:13 -07:00
Mitchell Hashimoto 6c97e4a59a
macos: fix focus after closing splits 2025-06-05 07:05:13 -07:00
Mitchell Hashimoto 77458ef308
macos: rename surfaceTree2 to surfaceTree 2025-06-05 07:05:13 -07:00
Mitchell Hashimoto f1ed07caf4
macos: Remove the legacy SurfaceTree 2025-06-05 07:05:13 -07:00
Mitchell Hashimoto 22819f8a29
macos: transfer doesBorderTop 2025-06-05 07:05:12 -07:00
Mitchell Hashimoto 8b979d6dce
macos: handle surfaceTreeDidChange 2025-06-05 07:05:12 -07:00
Mitchell Hashimoto ea1ff438f8
macos: handle split zooming 2025-06-05 07:05:12 -07:00
Mitchell Hashimoto b7c01b5b4a
macos: spatial focus navigation 2025-06-05 07:05:12 -07:00
Mitchell Hashimoto ec7fd94d0f
macos: equalize splits works with new tree 2025-06-05 07:05:12 -07:00
Mitchell Hashimoto a389926ca7
macos: use surfaceTree2 needsConfirmQuit 2025-06-05 07:05:12 -07:00
Mitchell Hashimoto aef61661a0
macos: fix up command palette, focusing 2025-06-05 07:05:12 -07:00
Mitchell Hashimoto 7dcfebcd5d
macos: isSplit guarding on focus split directions works 2025-06-05 07:05:12 -07:00
Mitchell Hashimoto 0fb58298a7
macos: focus split previous/next 2025-06-05 07:05:11 -07:00
Mitchell Hashimoto b84b715ddb
macos: unify confirm close in our terminal controllers 2025-06-05 07:05:11 -07:00
Mitchell Hashimoto d1dce1e372
macos: restoration for new split tree 2025-06-05 07:05:11 -07:00
Mitchell Hashimoto 33d94521ea
macos: setup sequence for SplitTree 2025-06-05 07:05:11 -07:00
Mitchell Hashimoto 672d276276
macos: confirm close on split close 2025-06-05 07:05:11 -07:00
Mitchell Hashimoto e3bc3422dc
macos: handle split resizing 2025-06-05 07:05:11 -07:00
Mitchell Hashimoto 1707159441
new SplitTree 2025-06-05 07:05:11 -07:00
Jon Parise 652f551bec macos: simplify some ServiceProvider code
First, remove the always-inlined openTerminalFromPasteboard code and
combine it with openTerminal. Now that we're doing a bit of work inside
openTerminal, there's little better to having an intermediate, inlined
function.

Second, combine some type-casting operations (saving a .map() call).

Lastly, adjust some variable names because a generic `objs` or `urls`
was a little ambiguous now that we're all in one function scope.
2025-06-02 20:11:18 -04:00
Mitchell Hashimoto d1f1be8833
macos: fix small memory leak in surface tree when closing splits
This fixes a small memory leak I found where the `SplitNode.Leaf` was
not being deinitialized properly when closing a split. It would get
deinitialized the next time a split was made or the window was closed,
so the leak wasn't big. The surface view underneath the split was also
properly deinitialized because we forced it, so again, the leak was
quite small.

But conceptually this is a big problem, because when we change the
surface tree we expect the deinit chain to propagate properly through
the whole thing, _including_ to the SurfaceView.

This fixes that by removing the `id(node)` call. I don't find this to be
necessary anymore. I don't know when that happened but we've changed
quite a lot in our split system since it was introduced. I'm also not
100% sure why the `id(node)` was causing a strong reference to begin
with... which bothers me a bit.

AI note: While I manually hunted this down, I started up Claude Code and
Codex in separate tabs to also hunt for the memory leak. They both
failed to find it and offered solutions that didn't work.
2025-06-02 14:12:26 -07:00
Daniel Wennberg 5244f8d6ac Follow-up to #7462: var -> let 2025-06-02 10:14:52 -07:00
Daniel Wennberg 232a46d2dc Add option to hide macOS traffic lights 2025-06-02 09:22:01 -07:00
Daniel Wennberg 12a01c0460 Hide main title when covered by tabs 2025-06-02 09:10:22 -07:00
Daniel Wennberg 85beda9c49 Fix reset zoom button visibility in macOS "tabs" mode when no tabs 2025-06-02 09:09:04 -07:00
Mitchell Hashimoto fd7132db71
macos: quick terminal can equalize splits
Fixes #7480
2025-05-30 15:13:30 -07:00
Jeffrey C. Ollie d3cb6d0d41
GTK: add action to show the GTK inspector
The default keybinds for showing the GTK inspector (`ctrl+shift+i` and
`ctrl+shift+d`) don't work reliably in Ghostty due to the way Ghostty
handles input. You can show the GTK inspector by setting the environment
variable `GTK_DEBUG` to `interactive` before starting Ghostty but that's
not always convenient.

This adds a keybind action that will show the GTK inspector. Due to
API limitations toggling the GTK inspector using the keybind action is
impractical because GTK does not provide a convenient API to determine
if the GTK inspector is already showing. Thus we limit ourselves to
strictly showing the GTK inspector. To close the GTK inspector the user
must click the close button on the GTK inspector window. If the GTK
inspector window is already visible but is hidden, calling the keybind
action will not bring the GTK inspector window to the front.
2025-05-29 16:07:57 -05:00
Daniel Wennberg d1501a4925 fix: properly intialize key event in GlobalEventTap 2025-05-27 22:33:15 -07:00
Jeffrey C. Ollie 48b6807ac9
nix: fix typos 2025-05-26 11:12:30 -05:00
Mitchell Hashimoto a6466c5ca0
macOS: use file parent dir for `openTerminal` service cwd (#7286) (#7292)
Fixes #7286

Previously, when using the "New Ghostty Window/Tab Here" macOS service
on a file, the new terminal window/tab would incorrectly open in the
user's home directory. This was because the service handler only
expected directory paths.

This commit updates the service handler to check if the provided path is
a file. If it is, the handler now uses the file's parent
directory as the working directory for the new Ghostty window or tab,
aligning with user expectations. If the path is a directory, it's used
directly as before.
2025-05-15 20:20:59 -07:00
Aaron Ruan f343e1ba46
Fix comma typo 2025-05-16 00:40:25 +08:00
Aaron Ruan 7ccc181332
macos: add "Check for Updates" action, menu item & key-binding support 2025-05-15 13:34:44 +08:00
Mitchell Hashimoto ecda5ec327
macos: do not send UTF-8 PUA codepoints to key events
Fixes #7337

AppKit encodes functional keys as PUA codepoints. We don't want to send
that down as valid text encoding for a key event because KKP uses that
in particular to change the encoding with associated text.

I think there may be a more specific solution to this by only doing this
within the KKP encoding part of KeyEncoder but that was filled with edge
cases and I didn't want to risk breaking anything else.
2025-05-12 11:42:05 -07:00
Mitchell Hashimoto c4f1c78fcf
macOS: treat C-/ specially again to prevent beep
Fixes #7310
2025-05-11 07:15:46 -07:00
Mitchell Hashimoto a26310e83f
macOS: app key is binding check should include utf-8 chars 2025-05-09 10:45:43 -07:00
Mitchell Hashimoto 5dc88bda6a
macOS: send proper UTF-8 text for more key events 2025-05-09 10:01:06 -07:00
Mitchell Hashimoto d015efc87d
clean up bindings so that they match macOS menus 2025-05-09 10:01:06 -07:00
Mitchell Hashimoto b991d36343
macOS: build 2025-05-09 10:01:06 -07:00
Bryan Lee 800054874e
macOS: switch to using URL instead of String 2025-05-09 10:52:18 +08:00
Bryan Lee 3043012c1b
macOS: simplify path handling in `openTerminal` 2025-05-08 08:34:02 +08:00
Bryan Lee a8b450f03d
macOS: use file parent dir for `openTerminal` service cwd (#7286) 2025-05-08 08:34:02 +08:00
Mitchell Hashimoto 2caa8a3fe1
macOS: move window title handling fully to AppKit
Fixes #7236
Supersedes #7249

This removes all of our `focusedValue`-based tracking of the surface
title and moves it completely to the window controller. The window
controller now sets up event listeners (via Combine) when the focused
surface changes and updates the window title accordingly.

There is some complicated logic here to handle when we lose focus to
something other than a surface. In this case, we want our title to be
the last focused surface so long as it exists.
2025-05-06 14:57:19 -07:00
Mitchell Hashimoto 732500b418
feat: implement toggleMaximize for macOS (#7191)
Resolve #7030
2025-05-06 13:43:57 -07:00
Mitchell Hashimoto e2a0f439c6
macOS: save/restore firstResponder on non-native fullscreen
Fixes #6999

It appears that at some point one of the operations causes focus to move
away for non-native fullscreen. We previously relied on the delegate
method to restore this but a better approach appears to handle this
directly in the fullscreen implementations. This fixes the linked issue.

I still think long term all the `Ghostty.moveFocus` stuff is a code
smell and we should be auditing all that code to see if we can
eliminate it. But this is a step in the right direction, and removes one
of those uses.
2025-05-06 12:59:31 -07:00
Mitchell Hashimoto 9b78917246
macOS: handle scenario cgWindowId is nil
Fixes #7114
Supercedes #7271

This fixes a crash that could occur with non-native fullscreen and
`fullscreen = true` set at once.

The "windowNumber" can be `<= 0` if the window "doesn't have a
window device." I don't fully know all the scenarios this is true but it
is true when the window is not visible, at least.
2025-05-06 10:33:56 -07:00
Mitchell Hashimoto 6e11d947e7
Binding for toggling window float on top (macOS only)
This adds a keybinding and apprt action for #7237.
2025-05-01 09:47:17 -07:00
Martin Hettiger f83729ba48 macos: add float on top feature for terminal windows 2025-05-01 09:13:33 -07:00
Mitchell Hashimoto e5e89bcbe4
macos: key input that clears preedit without text shouldn't encode
Fixes #7225
2025-04-28 14:01:17 -07:00
Aaron Ruan 13f776d483
Rename maximize notification and refine handler 2025-04-28 10:20:29 +08:00
Aaron Ruan 1ec3e331de
Refactor toggleMaximize to use notifications 2025-04-27 08:48:06 +08:00
Mitchell Hashimoto 2b4d89e11f
macOS: scheme doesn't need to be state 2025-04-25 11:42:12 -07:00
Aaron Ruan 334093a9ea
feat: implement toggleMaximize for macOS 2025-04-25 15:59:44 +08:00
Aaron Ruan 1acb1715c3
replace NSVisualEffectView with ultraThinMaterial plus a background color 2025-04-25 10:42:22 +08:00
Aaron Ruan 3827ce9e4c
feat: beautify command palette 2025-04-24 12:46:38 +08:00
Friedrich Stoltzfus f58fba54a0 macOS: add descriptions for PgUp, PgDown, End, and Home keys
These keys were not being assigned a description in the KeyboardShortcut
extension. This caused problems for the macOS command pallete.
2025-04-23 16:05:51 -04:00
Mitchell Hashimoto 9bfe4544bf
macOS: Command palette has no selection by default, selection wraps
#7173

(1) The command palette no longer has any selection by default.
If and when we introduce most recently used commands, defaulting to that
would make sense. A selection only appears when the arrow keys are used
or the user starts typing.

(2) The selection with arrow keys now wraps, so if you press "down" on
the last option, it will wrap to the first option, and if you press "up"
on the first option, it will wrap to the last option. This matches both
VSCode and Zed.
2025-04-23 10:37:20 -07:00
Friedrich Stoltzfus b4b2b10328 macOS: command pallete scroll improvements
Removes the withAnimation closure which caused flashing when scrolling
up or down with arrow keys. Also removes the center anchor to behave
more like other command palletes (e.g., Zed, Raycast).
2025-04-22 16:12:09 -04:00
Mitchell Hashimoto 74e1c47623
macOS: Command Palette (#7153)
This introduces a command palette (inspired by @pluiedev's work in
#5681, but not using it as a base) for macOS.

The command palette is available in the `View` menu and also bindable
via `toggle_command_palette`, default binding is `cmd+shift+p` to match
VSCode.

The commands in the command palette must map to a _bindable_ action,
though they may not have an associated keybinding. This means that any
new binding actions we add in the future can be represented here and
also makes it easy in the future to add configuration to add new custom
entries to the command palette. For this initial PR, the available
commands are hardcoded (`src/input/commands.zig`).

I've noticed in other programs (VSCode, Zed), the command palette
contains pretty much _all available actions_ even if they're basically
useless in the context of a command palette. For example, Zed has the
"toggle command palette" action in the command palette and it... does
nothing (it probably should hide the palette). I followed @pluiedev's
lead and made this subjective in this PR but I wonder if we should
actually force all binding actions to be available.

There are various other improvements I'd like to make but omitted from
this PR for the sake of limiting scope:

* Instead of an entry with no matches doing nothing, we can allow users
to manually input _any_ configurable binding.
* Localization, since macOS doesn't have any yet. But for Linux when we
port this we probably have to change our strings extraction.

## Demo


https://github.com/user-attachments/assets/a2155cfb-d86b-4c1a-82b5-74ba927e4d69
2025-04-22 08:52:27 -07:00
Mitchell Hashimoto ce987ba56d
macOS: Add dock badge notification for bell events (#7118)
Resolves #7108

This PR adds visual notification badges to the Ghostty dock icon when
bell events are triggered while the application is in the background.
This complements the existing dock bounce notification, making it easier
for users to notice when a terminal needs attention.


https://github.com/user-attachments/assets/b54c881f-fea8-4085-8614-432d9e5847b9
2025-04-22 08:39:49 -07:00
Mitchell Hashimoto 5427b0b507
macOS: add description as hover tooltip 2025-04-22 08:36:17 -07:00
Mitchell Hashimoto 3e5fe5de9a
move command filtering into apprt 2025-04-22 08:33:32 -07:00
Mitchell Hashimoto 28404e946b
order commands alphabetically and preserve capitalization 2025-04-21 17:13:12 -07:00
Mitchell Hashimoto a732bb272d
fix CI 2025-04-21 10:54:23 -07:00
Mitchell Hashimoto e33eed0216
macOS: command palette visual tweaks 2025-04-21 10:40:30 -07:00
Mitchell Hashimoto baad082438
macOS: command palette selection tweaks 2025-04-21 10:26:29 -07:00
Mitchell Hashimoto 63b4cb4ead
macOS: fix responder chain 2025-04-21 10:17:02 -07:00
Mitchell Hashimoto 6d2685b5a2
add toggle command palette binding 2025-04-21 10:05:30 -07:00
Mitchell Hashimoto 8bd91e7104
macOS: hook up full action execution 2025-04-21 09:40:08 -07:00
Mitchell Hashimoto afd4ec6de2
macOS: command palette "enter" works 2025-04-21 09:32:51 -07:00
Mitchell Hashimoto 0915a7af46
macOS: extract TerminalCommandPalette 2025-04-21 09:18:46 -07:00
Mitchell Hashimoto 5fab6faf04
macOS: hook up command palette C API to actual command palette 2025-04-21 08:32:42 -07:00
Mitchell Hashimoto be7fb45e9f
command palette SwiftUI view 2025-04-21 08:32:05 -07:00
Mitchell Hashimoto 40c3dbbb31
macOS: remove "r" & "c" from resize overlay (#7142)
as per [#6013](https://github.com/ghostty-org/ghostty/pull/6013) and
[#6040](https://github.com/ghostty-org/ghostty/pull/6040) but for macOS
2025-04-21 08:13:49 -07:00
Asadullah Shaikh 9709d934f0 remove "r" & "c" from resize overlay on macOS 2025-04-21 20:25:25 +05:30
Mitchell Hashimoto 8c02eea48b
macOS: get proper unshifted codepoint with ctrl pressed (#7150)
Fixes a regression where `C-S-c` stopped working properly in both legacy
and Kitty modes (although the Kitty mode side only affected alternates
and not the key itself so it probably worked fine in most programs).

The issue is that `charactersIgnoringModifiers` changes behavior if
`control` is pressed, so it doesn't really ignore all modifiers. We have
to use `characters(byApplyingModifiers:)` to get the proper unshifted
codepoint when `control` is pressed.
2025-04-21 07:52:39 -07:00
Mitchell Hashimoto 643c882597
macOS: use KeyboardShortcut rather than homegrown KeyEquivalent (#7139)
This replaces the use of our custom `Ghostty.KeyEquivalent` with the
SwiftUI `KeyboardShortcut` type. This is a more standard way to
represent keyboard shortcuts and lets us more tightly integrate with
SwiftUI/AppKit when necessary over our custom type.

This PR should have no user impact. This is just some cleanup for future
work.

Note that not all Ghostty triggers can be represented as
KeyboardShortcut values because macOS itself does not support binding
keys such as function keys (e.g. F1-F12) to KeyboardShortcuts.

This isn't an issue since all input also passes through a lower level
libghostty API which can handle all key events, we just can't show these
keyboard shortcuts on things like the menu bar. This was already true
before this commit.
2025-04-21 07:26:34 -07:00
Mitchell Hashimoto 7e00f2fb7f
macOS: get proper unshifted codepoint with ctrl pressed
Fixes a regression where `C-S-c` stopped working properly in both legacy
and Kitty modes (although the Kitty mode side only affected alternates
and not the key itself so it probably worked fine in most programs).

The issue is that `charactersIgnoringModifiers` changes behavior if
`control` is pressed, so it doesn't really ignore all modifiers. We have
to use `characters(byApplyingModifiers:)` to get the proper unshifted codepoint
when `control` is pressed.
2025-04-21 07:23:24 -07:00
Kat d4525f2c57
Correct remaining instances of `change_title_prompt` to `prompt_surface_title`. 2025-04-21 03:41:52 +00:00
Mitchell Hashimoto b05826ac9d
macOS: use KeyboardShortcut rather than homegrown KeyEquivalent
This replaces the use of our custom `Ghostty.KeyEquivalent` with
the SwiftUI `KeyboardShortcut` type. This is a more standard way to
represent keyboard shortcuts and lets us more tightly integrate with
SwiftUI/AppKit when necessary over our custom type.

Note that not all Ghostty triggers can be represented as
KeyboardShortcut values because macOS itself does not support
binding keys such as function keys (e.g. F1-F12) to KeyboardShortcuts.

This isn't an issue since all input also passes through a lower level
libghostty API which can handle all key events, we just can't show these
keyboard shortcuts on things like the menu bar. This was already true
before this commit.
2025-04-19 14:39:48 -07:00
Mitchell Hashimoto 31b2ac4b79
macOS: Do not send control characters as UTF8 keyboard text
Fixes a regression where `ctrl+enter` was not encoding properly since
our input stack changes.
2025-04-19 06:54:36 -07:00
Mitchell Hashimoto e4a37dd383
macOS: only set unshifted codepoint on keyDown/Up events
Other event types trigger an AppKit assertion that doesn't crash the app
but logs some nasty stuff.
2025-04-18 15:14:38 -07:00
Mitchell Hashimoto 18d6faf597
macOS: translation mods should never have "control"
This also lets us get rid of our `C-/` special handling to prevent a
system beep.
2025-04-18 15:10:57 -07:00
Mitchell Hashimoto edb8616341
macos: translationMods should be used for consumed mods calculation
Fixes #7131
Regression from #7121

Our consumed mods should not include "alt" if `macos-option-as-alt` is
set. To do this, we need to calculate our consumed mods based on the
actual translation event mods (if available, only available during
keyDown).
2025-04-18 14:28:26 -07:00
Bryan Lee 90499f0749
macOS: Add dock badge notification for bell events 2025-04-18 09:43:48 +08:00
Mitchell Hashimoto ded9be39c0
macOS: handle preedit text changes outside of key event 2025-04-17 14:24:12 -07:00
Mitchell Hashimoto b3cb38c3fa
macOS/libghostty: rework keyboard input handling
This is a large refactor of the keyboard input handling code in
libghostty and macOS. Previously, libghostty did a lot of things that
felt out of scope or was repeated work due to lacking context. For
example, libghostty would do full key translation from key event to
character (including unshifted translation) as well as managing dead key
states and setting the proper preedit text.

This is all information the apprt can and should have on its own.
NSEvent on macOS already provides us with all of this information,
there's no need to redo the work. The reason we did in the first place
is mostly historical: libghostty powered our initial macOS port years
ago when we didn't have an AppKit runtime yet.

This cruft has already practically been the source of numerous issues, e.g.
#5558, but many other hacks along the way, too.

This commit pushes all preedit (e.g. dead key) handling and key translation
including unshifted keys up into the caller of libghostty.

Besides code cleanup, a practical benefit of this is that key event
handling on macOS is now about 10x faster on average. That's because
we're avoiding repeated key translations as well as other unnecessary
work. This should have a meaningful impact on input latency but I didn't
measure the full end-to-end latency.

A scarier part of this commit is that key handling is not well tested
since its a GUI component. I suspect we'll have some fallout for certain
keyboard layouts or input methods, but I did my best to run through
everything I could think of.
2025-04-17 14:24:12 -07:00
Mitchell Hashimoto cc690eddb5
macOS: Implement basic bell features (no sound)
Fixes #7099

This adds basic bell features to macOS to conceptually match the GTK
implementation. When a bell is triggered, macOS will do the following:

  1. Bounce the dock icon once, if the app isn't already in focus.
  2. Add a bell emoji (🔔) to the title of the surface that triggered
     the bell. This emoji will be removed after the surface is focused
     or a keyboard event if the surface is already focused. This
     behavior matches iTerm2.

This doesn't add an icon badge because macOS's dockTitle.badgeLabel API
wasn't doing anything for me and I wasn't able to fully figure out
why...
2025-04-15 10:41:15 -07:00
Mitchell Hashimoto b77c5634f0
macos: quick terminal uses padded notch mode if notch is visible
Fixes #6612
2025-04-15 08:52:20 -07:00
Mitchell Hashimoto d1c15dbf07
macOS: quick terminal should retain menu if not frontmost
This is a bug I noticed in the following scenario:

  1. Open Ghostty
  2. Fullscreen normal terminal window (native fullscreen)
  3. Open quick terminal
  4. Move spaces, QT follows
  5. Fullscreen the quick terminal

The result was that the menu bar would not disappear since our app is
not frontmost but we set the fullscreen frame such that we expected it.
2025-04-14 11:17:11 -07:00
Mitchell Hashimoto 453e6590e8
macOS: non-native fullscreen should not hide menu on fullscreen space
Fixes #7075

We have to use private APIs for this, I couldn't find a reliable way
otherwise.
2025-04-14 10:38:54 -07:00
Mitchell Hashimoto 6d80388155
macOS: only emit a mouse exited position if we're not dragging
Fixes #7071

When the mouse is being actively dragged, AppKit continues to emit
mouseDragged events which will update our position appropriately. The
mouseExit event we were sending sends a synthetic (-1, -1) position
which was causing a scroll up.
2025-04-13 12:46:39 -07:00
Bryan Lee 9144f4db58
Fix macOS shortcut binding for `close_window` action 2025-04-08 00:44:53 +08:00
Mitchell Hashimoto fe0536aaaf
macos: replay control+key events that go to doCommand
Fixes #7000

Related to #6909, the same mechanism, but it turns out some control+keys
are also handled in this same way (namely control+esc leads to "cancel"
by default, which is not what we want).
2025-04-04 22:09:04 -04:00
Mitchell Hashimoto f228933955
macos: left mouse click while not focused doesn't encode to pty
Fixes #2595

This fixes an issue where a left mouse click on a terminal while not
focused would subsequently be encoded to the pty as a mouse event. This
is atypical for macOS applications in general and wasn't something we
wanted to do.

We do, however, want to ensure our terminal gains focus when clicked
without focus. Specifically, a split. This matches iTerm2 behavior and
is rather nice. We had this behavior before but our logic to make this
work before caused the issue this commit is fixing.

I also tested this with command+click which is a common macOS shortcut
to emit a mouse event without raising the focus of the target window. In
this case, we will properly focus the split but will not encode the
mouse event to the pty. I think we actually do a _better job_ here tha
iTerm2 (but, subjective) because we do encode the pty event properly if
the split is focused whereas iTerm2 never does.
2025-04-04 19:17:03 -04:00
Mitchell Hashimoto 99843cf54d
macos: reset the last command key state when keyDown event
Fixes a regression from #6909
See #6887

In certain scenarios, the last command key state would linger around (I
could only see this happen with global keybinds for unknown reasons
yet). This state is only meant to have an effect within the cycle of a
single keybind and only so we can ensure an event reaches keyDown so it should
be reset if keyDown is ever sent (since, by definition at that point,
keyDown has been reached).

I'm still not happy that this is necessary and I suspect there is a
better root cause to resolve, but I'd rather get this fix in now and
figure out the root cause later.
2025-03-27 07:22:05 -07:00
Mitchell Hashimoto 67f47a6e22
macos: remove special-case cmd+period handling
Fixes #5522

This commit re-dispatches command inputs that are unhandled by our macOS
app so they can be encoded to the pty and handled by the core libghostty
key callback system.

We've had a special case `cmd+period` handling in Ghostty for a very
long time (since well into the private beta). `cmd+period` by default
binds to "cancel" in macOS, so it doesn't encode to the pty. We don't
handle "cancel" in any meaningful way in Ghostty, so we special-cased it
to encode properly to the pty.

However, as shown in #5522, if the user rebinds `cmd+period` at the
system level to some other operation, then this is ignored and we encode
it still. This isn't desirable, we just want to work around not caring
about "cancel."

The callback path that AppKit takes for key events is a bit convoluted.
For command keys, it first calls `performKeyEquivalent`. If this returns
false (we want to continue standard processing), then it calls EITHER
`keyDown` or `doCommand(by:)`. It calls the latter if there is a
standard system command that matches the key event. For `cmd+period` by
default, this is "cancel." Unfortunately, from `doCommand` we can't say
"oops, we don't want to handle this, please continue processing." Its
too late.

So, this commit stores the last command key event from
`performKeyEquivalent` and if we reach `doCommand` for it without having
called `keyDown`, we re-dispatch the event and send it to keyDown.

I'm honestly pretty sus about this whole logic but it is scoped to only
command-keys and I couldn't trigger any adverse behavior in my testing.
It also definitely fixed #5522 as far as I could reproduce it before.
2025-03-25 15:03:27 -07:00
Mitchell Hashimoto 3c49bc5086
os: locale automatically sets LANGUAGE based on macOS preferred 2025-03-07 13:42:00 -08:00
Mitchell Hashimoto edf619205c
add ghostty_translate C API 2025-03-07 13:42:00 -08:00
Bryan Lee 423bc1971b
Make `equalize_splits` action only affect current window 2025-03-04 22:37:32 +08:00
Mitchell Hashimoto 8d395c094b
macos: set title of terminal window immediately if configured
Fixes #5934 for macOS

If a `title` config is set, this change sets the title immediately on
windowDidLoad to ensure that the window appears with the correct title
right away.

If there is any reason to set another title, the `set_title` apprt
action will come on another event loop tick (due to our usage of
notifications) but that's okay since that's already how it works. This
is just to say that setting this here won't break any shell integration
or anything.
2025-03-02 13:27:40 -08:00
Mitchell Hashimoto 17cae57f51
Introduce `reset_window_size` keybinding and apprt action
Related to #6035

This implements the keybind/action portion of #5974 so that this can
have a binding and so that other apprts can respond to this and
implement it this way.
2025-02-28 15:31:17 -08:00
Mitchell Hashimoto afb154ee5d
macos: store default size as computed property 2025-02-28 14:51:56 -08:00
Mikhail Borisov 8838ebf02a Refactor to use height/width from ghostty configuration 2025-02-28 14:17:46 -08:00
Mikhail Borisov f73c1a2c59 "Return to Default Size" implementation
Added support for "Return To Default Size"
2025-02-28 14:17:46 -08:00
Mitchell Hashimoto 1cfe7027e5
Fix Terminal Inspector option turns inactive if toggled in the Quick Terminal (#6024)
Fixed: [2475](https://github.com/ghostty-org/ghostty/issues/2475)

The problem actually existed because of the responder chain, as
previously pointed out in the report (thanks to @mitchellh).

When we first click on Toggle Terminal Inspector:
* the responder chain goes to _toggleTerminalInspector_
(_SurfaceView_AppKit_ implementation).
When we click the second toggleTerminalInspector:
* it tries to find the next responder, but the one available is
_TerminalController_. (if we remove this method from there, the bug will
reproduce even without quick mode)

**Problem**:
TerminalController not available during quick terminal, so there's no
way to toggle inspector
**Solution**:
We add toggleTerminalInspector to the _QuickTerminalController_:
selector, as we did with other similar methods.
2025-02-28 07:09:00 -08:00
Mikhail Borisov 744240c009 Fix Terminal Inspector option turns inactive if toggled in the Quick Terminal 2025-02-28 00:38:29 +01:00
Mitchell Hashimoto ef88d1cba9
feat: respect maximize config on macOS (#5962)
Resolve #5928
2025-02-27 15:25:17 -08:00
Aaron Ruan 5a5478abe1 feat: respect maximize config on macOS
Signed-off-by: Aaron Ruan <i@ar212.com>
2025-02-27 15:10:39 -08:00
McNight b4349d3226 fix(macos): make showNoNewTabAlert method private #5939 2025-02-25 00:18:02 +01:00
McNight 1254c6b981 fix(macos): address MR feedback #5939 2025-02-25 00:17:01 +01:00
McNight aa4aaa200f fix(macos): prevent performing newTab shortcut on QuickTerminalWindow #5939 2025-02-23 19:34:27 +01:00
Mitchell Hashimoto 870b74f4da
macOS: Fix new window focus when created from quick terminal (#5834)
## Root Cause

The issue has two aspects:

1. The window creation process didn't explicitly force focus on the new
window after showing it.
2. More fundamentally, we were relying on `NSApp.isActive` to determine
whether to activate the application, which is problematic because:
- When creating a window from quick terminal, the application is already
"active" but this active state is owned by the quick terminal
- The [`NSApp.isActive`
check](4cfe5522db/macos/Sources/Features/Terminal/TerminalManager.swift (L100))
doesn't accurately reflect our intent - creating a new window is an
explicit user action that should always result in that window gaining
focus

## Solution

Removing the `NSApp.isActive` check.

```swift
// Before
if !NSApp.isActive {
    NSApp.activate(ignoringOtherApps: true)
}

// After
NSApp.activate(ignoringOtherApps: true)
```

Fixes #5688
2025-02-21 15:50:00 -08:00
Aaron Ruan 4291e1c5d7 fix: use surfaceConfig.backgroundColor to determine if the theme is light or dark
Signed-off-by: Aaron Ruan <i@ar212.com>
2025-02-21 15:32:24 -08:00
Bryan Lee c9f8732e5c
Fix new window focus when quick terminal is open 2025-02-18 10:50:01 +08:00
Aaron Ruan 830a117555 fix: vertically center toolbar title more accurately
Signed-off-by: Aaron Ruan <i@ar212.com>
2025-02-17 07:30:14 -08:00
Mitchell Hashimoto 1013ba63ee
[macOS] feat: Add "Split Left" and "Split Up" actions to menubar (#5807)
Fixes #5779
2025-02-16 12:37:11 -08:00
mbrown379 b1df97b33f Add Split Left and Split Up to menu 2025-02-16 15:14:02 -05:00
Albert Dong d7a82f212a Add setting to hide icon from dock/cmd-tab 2025-02-15 10:45:27 -08:00
Damien Mehala a0f243691a feat: add `bring_all_to_front` keybinding
Resolves #4704.
2025-02-14 14:41:49 -08:00
Aswin M Prabhu a581955b9b Add tab title rename feature to macos 2025-02-14 13:29:36 -08:00
Mitchell Hashimoto ac7aa757bd
macos: add `padded-notch` option for `macos-non-native-fullscreen`
Finishes #378
Supercedes #4159

This adds a new enum value for `macos-non-native-fullscreen`:
`padded-notch`. This value will add padding to the top of the window to
account for the notch on applicable devices while still hiding the
menu.

This value is preferred over "visible-menu" by some people because for
screens without a notch, the window will take up the full height.

The plan in the future is that we may color the padded area when a notch
is present. In this commit it appears as transparent.
2025-02-13 20:27:42 -08:00
Mitchell Hashimoto 5105c52ef7
macos: make goto_split, goto_tab, and move_tab performable
Fixes #5552

This makes the mentioned actions performable. This isn't perfect, but it
does so in a way that resolves the user issue in #5552. This commit
returns an action is NOT performed if it doesn't have splits or tabs
(respectiely for the actions), but also reports its ALWAYS performed if
it does.

This latter logic isn't accurate: we should only return performable if
it was actually done. So for example, goto_split:top should do nothing
if we're already at the top. But, we report it as performed today.

This is good enough to resolve the issue and fix the core problem faced
for 1.1.0.
2025-02-13 10:40:07 -08:00
Mitchell Hashimoto 3104b21758
macos: don't remove ctrl modifier for text input
Fixes #5448

We previously removed the ctrl modifier for text commit (IME-style)
to workaround a libghostty quirk (as noted in the comment in the diff).
But this broke other keyboard layouts.

This commit attempts to clean this up slightly -- but not completely --
by removing that hack, and only modifying the ctrl behavior for the
UCKeyTranslate call.

Long term, I plan to remove UCKeyTranslate completely, as noted in the
todo comment already written just below this diff.

This fixes the aforementioned issue and hopefully doesn't regress any
other behavior. I tested the following:

  1. Dvorak Ctrl characters
  2. Ergo-L Ctrl characters
  3. US standard Ctrl characters
  4. Japanese IME input Ctrl input to modify IME state
2025-02-13 09:43:07 -08:00
Bryan Lee f72fd32bf0
Eliminate tab content flickering during tab movement on macOS 2025-02-13 14:59:14 +08:00
Jeffrey C. Ollie 9bac6ecbff
macOS: fix iOS build breakage from #5644 2025-02-12 07:54:50 -06:00
Mitchell Hashimoto cbf562ecb3
apprt/embedded: make performAction return the performable state 2025-02-11 16:43:50 -08:00
Mitchell Hashimoto 58ab66f094
macos: add a variety of artist-drawn alternate icons
This is just a fun change to add a bunch of alternate icons. We don't
want to add too many since this increases the final bundle size but we
also want to have some fun. :)
2025-02-11 14:51:43 -08:00
Mitchell Hashimoto adb187685b
Fix confirm-close-surface not working for hidden quick terminal (#5647)
Fixes #5450.


https://github.com/user-attachments/assets/7090fe55-dd1f-4517-9f8a-ffc3807283db
2025-02-11 12:55:20 -08:00
Bryan Lee c627231b0f Fix confirm-close-surface not working for hidden quick terminal 2025-02-11 12:42:34 -08:00
Bryan Lee 31273aaabc Remember last focused window position for next startup 2025-02-11 12:33:29 -08:00
Mitchell Hashimoto c6da845f33
macos: ensure previously key window regains key on toggle_visibility
Fixes #5690

When we hide the app and then show it again, the previously key window
is lost. This is because we are not using unhide and are manually
doing it (and we're not using unhide for good reasons commented in the
source already).

Modify our hidden state to include what the key window was (as a weak
ref) and restore it when we show the app again.
2025-02-11 11:13:19 -08:00
Mitchell Hashimoto f986a32185
macos: toggle_visibility fullscreen check requires active app
This fixes a regression from #5472. The fullscreen check must check if
the app is active otherwise the guard statement fails and we can't bring
the macOS app back from the background.
2025-02-11 11:01:20 -08:00
Mitchell Hashimoto 1d7f041f55
macos: update Sparkle to 2.6.4 to workaround security issue
https://github.com/ghostty-org/ghostty/security/dependabot/4
2025-02-05 10:45:10 -08:00
Shaps Benkau 8d31f6ce2e Toggling visibility is now ignored when in fullscreen mode. 2025-02-03 13:44:23 -08:00
Mitchell Hashimoto a58b1998a9
macos: hide dock globally if the dock conflicts
Related to #5361

The fix in 5361 wasn't sufficient since it only applied if our app was
in the foreground. Our quick terminal is a non-activating NSPanel to
allow it to work on any space (fullscreen included). This means that
Ghostty doesn't become the active app when the quick terminal is shown
and another app is in the foreground.

To work around this, we now hide the dock globally when the quick
terminal is shown AND the dock is in a conflicting position. We restore
this state when the quick terminal is hidden, loses focus, or Ghostty is
quit.
2025-01-24 20:18:44 -08:00
Mitchell Hashimoto a5a73f8352
macos: autohide dock if quick terminal would conflict with it
Fixes #5328

The dock sits above the level of the quick terminal, and the quick
terminal frame typical includes the dock. Hence, if the dock is visible
and the quick terminal would conflict with it, then part of the terminal
is obscured.

This commit makes the dock autohide if the quick terminal would conflict
with it. The autohide is disabled when the quick terminal is closed.

We can't set our window level above the dock, as this would prevent
things such as input methods from rendering properly in the quick
terminal window.

iTerm2 (the only other macOS terminal I know of that supports a dropdown
mode) frames the terminal around the dock. I think this looks less
aesthetically pleasing and I prefer autohiding the dock instead.

We can introduce a setting to change this behavior if desired later.

Additionally, this commit introduces a mechanism to safely set
app-global presentation options from multiple sources without stepping
on each other.
2025-01-24 14:51:17 -08:00
Mitchell Hashimoto e854b38872
cli: allow renaming config fields to maintain backwards compatibility
Fixes #4631

This introduces a mechanism by which parsed config fields can be renamed
to maintain backwards compatibility. This already has a use case --
implemented in this commit -- for `background-blur-radius` to be renamed
to `background-blur`.

The remapping is comptime-known which lets us do some comptime
validation. The remap check isn't done unless no fields match which
means for well-formed config files, there's no overhead.

For future improvements:

- We should update our config help generator to note renamed fields.
- We could offer automatic migration of config files be rewriting them.
- We can enrich the value type with more metadata to help with
  config gen or other tooling.
2025-01-23 14:16:37 -08:00
Qwerasd 5477eb87c1 macOS: prevent native window drag by top region when titlebar hidden
The native window drag region is driven ultimately by the window's
`contentLayoutRect`, so we can just override it in `TerminalWindow`
to return a rect the size of the full window, disabling the gesture
without causing any side effects by altering the responder chain.
2025-01-23 13:35:52 -08:00
Mitchell Hashimoto b82c70fd3c
fix: quick terminal hidden by macos menu bar (#5222)
ghostty#5000 changed the window level from `.popupMenu` to `.floating`
to improve IME support. However, this introduced a side effect which
render the Quick Terminal (QT) below the macOS menu bar, whereas
previously it would cover it.

When positioned on `right` and `left`, the top of the QT becomes
partially hidden. This PR adjust the size of the QT to ensure it remains
fully visible and stays below the menu bar.

Before #5000:
![Screen Recording 2025-01-19 at 11 14
48](https://github.com/user-attachments/assets/70565c28-783f-4a2a-a8c9-a2eb16ea50e9)
With #5000:
![Screen Recording 2025-01-19 at 11 13
27](https://github.com/user-attachments/assets/184a1205-0a68-4fa0-a0d8-cc37701529af)
This branch:
![Screen Recording 2025-01-19 at 11 17
32](https://github.com/user-attachments/assets/f589d9e1-c5a0-4ed1-9f9b-651f3cb22f58)
2025-01-20 11:12:11 -08:00
Damien Mehala 4956d36ee6
fix: quick terminal hidden by macos menu bar
ghostty#5000 changed the window level from `.popupMenu` to `.floating`
to improve IME support. However, this introduced a side effect which
render the Quick Terminal (QT) below the macOS menu bar, whereas
previously it would cover it.

When positioned on `right` and `left`, the top of the QT becomes
partially hidden. This PR adjust the size of the QT to ensure it remains
fully visible and stays below the menu bar.
2025-01-19 11:04:01 +01:00
Albert Dong da5ac6aeeb Set alert to nil when modal interacted with 2025-01-16 20:57:41 -08:00
Albert Dong 860f1f635c Manually call orderOut on terminal close alert
Allowing the alert to be automatically closed after the completion handler finishes doesn't seem to play well when the completion handler closes the window on which the alert is attached
2025-01-16 14:14:48 -08:00
Mitchell Hashimoto a5853c4de8
macos: respect the "auto" window decoration setting 2025-01-16 14:03:04 -07:00
Leah Amelia Chen 4e0d9b1b27 gtk(wayland): implement server-side decorations 2025-01-14 09:57:59 -08:00
Alexandre Antonio Juca 39bb949973 fix: Ensure file paths derived from pasteboard operations are properly escaped 2025-01-14 00:18:28 +01:00
Qwerasd fca336c32d Metal: blend in Display P3 color space, add option for linear blending
This commit is quite large because it's fairly interconnected and can't
be split up in a logical way. The main part of this commit is that alpha
blending is now always done in the Display P3 color space, and depending
on the configured `window-colorspace` colors will be converted from sRGB
or assumed to already be Display P3 colors. In addition, a config option
`text-blending` has been added which allows the user to configure linear
blending (AKA "gamma correction"). Linear alpha blending also applies to
images and makes custom shaders receive linear colors rather than sRGB.

In addition, an experimental option has been added which corrects linear
blending's tendency to make dark text look too thin and bright text look
too thick. Essentially it's a correction curve on the alpha channel that
depends on the luminance of the glyph being drawn.
2025-01-13 13:50:29 -08:00
Bryan Lee 08314d414f
Preserve full URL when pasting from clipboard 2025-01-14 00:48:56 +08:00
Mitchell Hashimoto ea0704148d
macos: only set quick terminal level to popUpMenu during animation
Fixes #4999

We need to set the level to popUpMenu so that we can move the window
offscreen and animate it over the main menu, but we must reset it back
to floating after the animation is complete so that other higher-level
windows can be shown on top of it such as IME windows.
2025-01-12 12:49:43 -08:00
Mitchell Hashimoto a2d2cfea59
macos: move drop implementation to separate extension 2025-01-11 19:27:36 -08:00
Alexandre Antonio Juca a06fc4ff11 feat: ensure text, files and URLs can be drag and dropped to terminal window 2025-01-11 19:04:45 -08:00
Mitchell Hashimoto 0811b1d5ac
macos: paste multiple files separated by space
https://github.com/ghostty-org/ghostty/discussions/4892#discussioncomment-11808631
2025-01-11 13:58:09 -08:00
Mitchell Hashimoto 200aee9acf
macos: rework toggle_visibility to better match iTerm2
Two major changes:

1. Hiding uses `NSApp.hide` which hides all windows, preserves tabs, and
   yields focus to the next app.

2. Unhiding manually tracks and brings forward only the windows we hid.
   Proper focus should be retained.
2025-01-10 14:40:02 -08:00
Alexandre Antonio Juca 61a78efa83 chore: revert on TerminalManager changes 2025-01-10 14:16:47 -08:00
Alexandre Antonio Juca 3a5aecc216 fix: hide windows without calling orderOut API 2025-01-10 14:16:47 -08:00
Alexandre Antonio Juca 4dd9fe5cfd fix: ensure terminal tabs are reconstructed in main window after toggling visibility 2025-01-10 14:16:47 -08:00
Mitchell Hashimoto 8e52c6d12b
Reduce ghost emoji flash in title bar (#4804)
Fixes #4799

This PR attempts to reduce the flash caused by the ghost emoji in the
title bar when opening new windows.

## Changes:

- Initialize `SurfaceView.title` with empty string instead of ghost
emoji

- Simplify title computation logic in `TerminalView`

- Adding a 500ms fallback timer for "👻"

	- Canceling timer if title is set

## Current Status:

While these changes reduce the initial ghost emoji flash, there's still
a brief moment where a folder emoji appears alone in the title bar when
opening a new window. This suggests there might be a race condition or
timing issue with how the title is being set and updated.


https://github.com/user-attachments/assets/3688c9f3-1727-4379-b04d-0bd6ac105728

Would appreciate feedback on the remaining flash issue and suggestions
for further improvements.
2025-01-10 13:46:45 -08:00
Mitchell Hashimoto 2d7706ec4f
macos: Handle ctrl characters in IME input (#4854)
Fixes:
https://github.com/ghostty-org/ghostty/issues/4634#issuecomment-2573469532

This commit fixes two issues:

1. `libghostty` must not override ctrl+key inputs if we are in a preedit
state. This allows thigs like `ctrl+h` to work properly in an IME.

2. On macOS, when an IME commits text, we strip the control modifier
from the key event we send to libghostty. This is a bit of a hack but
this avoids triggering special ctrl+key handling.
2025-01-08 22:07:15 -08:00
Mitchell Hashimoto 1636ac88fc
macos: Handle ctrl characters in IME input
Fixes: https://github.com/ghostty-org/ghostty/issues/4634#issuecomment-2573469532

This commit fixes two issues:

1. `libghostty` must not override ctrl+key inputs if we are in a preedit
   state. This allows thigs like `ctrl+h` to work properly in an IME.

2. On macOS, when an IME commits text, we strip the control modifier
   from the key event we send to libghostty. This is a bit of a hack but
   this avoids triggering special ctrl+key handling.
2025-01-08 21:54:34 -08:00
Mitchell Hashimoto aafe7deae7
macos: improve initial size calculation
Fixes #4801

Our size calculation before improperly used a screens frame instead of
its visibleFrame. Additionally, we didn't properly account for origin
needing to move in order to fit the window on the screen.

Apparently, setting a frame height to high crashes AppKit. The width
gets clamped by AppKit but the height does not. Fun!
2025-01-08 21:20:58 -08:00
Bryan Lee 5bfb3925ba
Add fallback timer for empty window title 2025-01-09 06:30:47 +08:00
Bryan Lee ea7c54d79d
Simplify let binding in `TerminalView` title logic 2025-01-09 06:30:47 +08:00
Bryan Lee 0651586339
Reduce ghost emoji flash in title bar 2025-01-09 06:30:46 +08:00
Bryan Lee 140ac93884 Add `close_tab` keybinding action for macOS
Implement `close_tab` keybinding action to close the current tab and all splits within that tab.
2025-01-08 12:04:40 -08:00
Mitchell Hashimoto 6ebc02b68d
macos: animate in even if remain on another space 2025-01-08 11:30:26 -08:00
Mitchell Hashimoto 6e54589db4
misc cleanups 2025-01-08 11:28:09 -08:00
Soh Satoh 37db4578c8 Fix the issue that the quick term not shown on first call 2025-01-08 11:03:18 -08:00
Soh Satoh 0ddc1a21a6 fix the comment (quick-terminal-space-behavior) 2025-01-08 11:03:18 -08:00
Soh Satoh 7bb3c31cee Move the quick terminal to active space if toggle() called while opening on another space 2025-01-08 11:03:18 -08:00
Soh Satoh 1493c55348 Merge branch 'main' into show-quick-term-on-another-app 2025-01-08 11:03:18 -08:00
Soh Satoh e2523c25cb Add quick-terminal-space-behavior option 2025-01-08 11:02:19 -08:00
Soh Satoh 2206c509be Show quick terminal on another full-screen app 2025-01-08 10:59:56 -08:00
Wes Campaigne e86b9a112e Implement "Paste Selection" on macOS like Terminal.app 2025-01-08 09:26:13 -08:00
Mitchell Hashimoto 29c2f095a6
macOS: Add Bluetooth permission description. (#4668)
Adds the missing Bluetooth permission to Ghostty's application playlist
manifest file, as it was missing. Tweaks have also been made to existing
permission descriptions to be more readable. Should fix an abrupt crash
in Fastfetch and any other apps that may request Bluetooth permissions.
2025-01-07 20:53:12 -08:00
Mitchell Hashimoto ae0c4d927a
macos: halt NSEvent processing at app scope only if event is handled
Fixes #4677
2025-01-06 07:27:44 -08:00
Mitchell Hashimoto f0c2d3d75a
macos: fix retain cycle preventing window from freeing 2025-01-06 07:02:04 -08:00
Evelyn Harthbrooke dc4774c147 macOS: fixup Photo Library description to make more sense. 2025-01-06 07:13:53 -07:00