927 Commits

Author SHA1 Message Date
Asadullah Shaikh
9709d934f0 remove "r" & "c" from resize overlay on macOS 2025-04-21 20:25:25 +05:30
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
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
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