1017 Commits

Author SHA1 Message Date
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
Mitchell Hashimoto
2b4d89e11f
macOS: scheme doesn't need to be state 2025-04-25 11:42:12 -07: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)
Some checks are pending
Test / build-flatpak (push) Blocked by required conditions
Test / build-linux (namespace-profile-ghostty-md) (push) Blocked by required conditions
Test / build-linux (namespace-profile-ghostty-md-arm64) (push) Blocked by required conditions
Test / build-linux-libghostty (push) Blocked by required conditions
Test / build-nix (namespace-profile-ghostty-md) (push) Blocked by required conditions
Test / build-nix (namespace-profile-ghostty-md-arm64) (push) Blocked by required conditions
Test / zig-fmt (push) Waiting to run
Test / build-dist (push) Blocked by required conditions
Test / build-macos (push) Blocked by required conditions
Test / build-macos-matrix (push) Blocked by required conditions
Test / build-snap (namespace-profile-ghostty-snap) (push) Blocked by required conditions
Test / build-snap (namespace-profile-ghostty-snap-arm64) (push) Blocked by required conditions
Test / build-windows (push) Blocked by required conditions
Test / build-windows-cross (namespace-profile-ghostty-md, x86-windows-gnu) (push) Blocked by required conditions
Test / build-windows-cross (namespace-profile-ghostty-md, x86_64-windows-gnu) (push) Blocked by required conditions
Test / test (push) Waiting to run
Test / GTK x11=false wayland=false (push) Blocked by required conditions
Test / GTK x11=true wayland=false (push) Blocked by required conditions
Test / GTK x11=false wayland=true (push) Blocked by required conditions
Test / GTK x11=true wayland=true (push) Blocked by required conditions
Test / Build -Dsentry=false (push) Blocked by required conditions
Test / Build -Dsentry=true (push) Blocked by required conditions
Test / test-macos (push) Blocked by required conditions
Test / prettier (push) Waiting to run
Test / alejandra (push) Waiting to run
Test / typos (push) Waiting to run
Test / translations (push) Waiting to run
Test / blueprint-compiler (push) Waiting to run
Test / Test pkg/wuffs (push) Blocked by required conditions
Test / Test build on Debian 12 (push) Blocked by required conditions
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