Commit Graph

844 Commits

Author SHA1 Message Date
Pedro Augusto
1a8f331f16 macOS: implement move_tab_to_new_window
The action and its keybind exist, and GTK implements them, but macOS had no
handler so the binding did nothing there. AppKit already has the command for
window tabs, so this forwards to it.

A window that isn't in a tab group, or is alone in one, is already a window of
its own, so there is nothing to move and the action reports it did nothing.

Implements the remaining macOS half of #2630.
2026-09-12 04:53:30 +01:00
Lukas
572fd58377 macOS: use the same default BellFeatures as config 2026-08-27 23:17:17 +02:00
Lukas
6229d4eb62 macOS: fix AppleScript send key for non-control keys
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-25 17:49:02 +02:00
Lukas
f1b9efed80 macOS: update default behaviour of KeyboardLayout.character(for:modifiers:) 2026-08-25 13:56:21 +02:00
Mitchell Hashimoto
550151882a macos: restore paste semantics for dropped text
Discussion #13979

Dropped paths and text once again honor bracketed paste mode.
IME, dictation, emoji picker, and character viewer commits remain typed input.

sendText calls ghostty_surface_text, which applies the clipboard paste
pipeline and bracketed paste framing when enabled. Separating the
paths at the drag-and-drop caller preserves the input-method behavior
introduced by #13817.
2026-08-24 12:49:42 -07:00
Mitchell Hashimoto
25c61e852f macos: implement Kitty clipboard protocol writes
Programs can now write the system clipboard through the Kitty
clipboard protocol in the macOS app. This also does all the hard work
plumbing through core termio/apprt so GTK should be an easy follow.

This functionality lets clients copy arbitrary representations (images, 
HTML, etc.) into the clipboard. Writes honor `clipboard-write`: allow 
applies silently, deny answers EPERM up front before any data is used, 
and ask shows the standard confirmation prompt.
2026-08-24 12:18:46 -07:00
Mitchell Hashimoto
df14efaf33 macos: preview images in the clipboard read confirmation dialog 2026-08-24 08:33:37 -07:00
Mitchell Hashimoto
af9470b19b macos: Kitty clipboard reads support pw/name session grants 2026-08-24 08:18:36 -07:00
Mitchell Hashimoto
8c7a34d4c9 macos: Kitty clipboard reads serve all clipboard content types 2026-08-24 08:18:36 -07:00
Mitchell Hashimoto
0ce9054bf9 macos: implement Kitty clipboard protocol reads (OSC 5522) 2026-08-24 08:18:36 -07:00
Jon Parise
9886f4817c macos: enforce keyboard layout actor isolation
Text Input Sources APIs are not thread-safe, but shortcut translation could
be called outside a declared main-actor context.

Mark keyboard layout and shortcut conversion as main-actor isolated, update
their tests, and dispatch key-sequence UI notifications to the main queue
before translating their shortcuts.
2026-08-18 12:40:28 -04:00
Jon Parise
761696c349 macos: simplify menu shortcut identity
Separate menu shortcut presentation from lookup identity. Store either a
normalized key equivalent or a physical keycode in a private hashable enum,
allowing Swift to synthesize equality and hashing instead of maintaining
parallel optional-key logic.

Assign display characters directly from KeyboardShortcut and remove unused
NSMenuItem and SwiftUI conversion helpers.
2026-08-18 11:49:46 -04:00
Jon Parise
569ff3307c macos: translate physical menu shortcuts
Translate printable physical keybindings through the current macOS
keyboard layout before assigning menu key equivalents. Previously these
bindings could not be represented because SwiftUI shortcuts are
character-based, so actions such as super+backquote had no native menu
shortcut.

Keep native keycodes as dispatch identity so translated display characters
do not change physical semantics or precedence over Unicode bindings.
Refresh shortcuts when the input source changes, and prevent AppKit from
transforming equivalents that are already localized.
2026-08-18 11:27:06 -04:00
Mitchell Hashimoto
f4309055fb macos: don't put 0x7F as text in key event
Fixes #13869

We already checked `< 0x20` but missed `0x7F` which causes similar
problems.
2026-08-17 06:44:16 -07:00
Mitchell Hashimoto
9009122953 macos: send all insertText commits as key events (#13817)
Partially addresses #13796. Extends #13222.

Previously, `insertText` commits without marked text were delivered via
`sendText`, which applies paste semantics and wraps the text in
bracketed
paste when the program enables it. macOS dictation and other input
methods often commit without marked text, so programs treated dictated
text as a paste: opencode collapsed it into a `"[Pasted ~N lines]"` chip
and Neovim applied paste-mode handling.

`insertText` is only invoked by input methods (IME, dictation, emoji
picker, character viewer); real paste operations use a separate path.
Every non-empty commit is now sent as a key event — the same path
already used for preedit commits since #13222 — so input method text
always arrives as typed input.

Typing is unaffected (the accumulator path returns earlier) and Cmd+V
pastes are unaffected. `committedPreeditTextAction` is renamed to
`committedTextAction` since it no longer only handles preedit commits.

Testing:

- 311 macOS unit tests pass.
- Manually verified on macOS 26: dictation into Opencode and Neovim
  arrives inline with no paste handling; emoji picker inserts inline;
  Chinese IME composition unchanged; dictation in Neovim normal mode now
  behaves as keystrokes, matching Terminal.app.

Notes:

- Dictated "new line" now matches Terminal.app behavior (no newline
  with typed-text semantics). The previous behavior came from the paste
  path preserving the newline; a follow-up could deliver it as an
  Enter keypress if desired.

AI usage: drafted with OMO + OpenCode + DeepSeek V4 Pro assistance;
reviewed, edited, and manually tested by the author.
2026-08-15 14:26:19 -07:00
Samuel Huang
ecbeb60ca5 macos: send all insertText commits as key events
Previously, insertText commits without marked text were delivered via
sendText, which applies paste semantics and wraps the text in bracketed
paste when the program enables it. macOS dictation and other input
methods often commit without marked text, so programs treated dictated
text as a paste and applied paste-specific handling.

insertText is only invoked by input methods (IME, dictation, emoji
picker, character viewer); real paste operations use a separate path.
Send every non-empty commit through the key event path so programs
interpret input method text as typed input. Typing is unaffected (the
accumulator path returns earlier) and Cmd+V pastes are unaffected.

The helper is renamed from committedPreeditTextAction to
committedTextAction since it no longer only handles preedit commits.
2026-08-14 11:29:38 -04:00
Lukas
f2022fe88d macOS: avoid holding SurfaceView when sending notifications 2026-08-14 10:00:15 +02:00
Leah Amelia Chen
1eaf457b18 gtk: add window title renaming (#10999)
Fixes #10469 for GTK.
2026-08-13 01:11:12 +08:00
Lukas
c78226bfae macOS: fix Main actor-isolated static property 'find' warnings 2026-08-12 15:34:54 +02:00
Lukas
97ae257497 macOS: fix warnings in showUserNotification 2026-08-12 15:26:31 +02:00
Lukas
da8b171265 macOS: fix Sendable warning for UnsafeMutablePointer
Swift explicitly [marked UnsafeMutablePointer as non sendable](0568dbf903). Moving from `@unchecked @retroactive` to `nonisolated(unsafe)` is safe for us as per the previous comments
2026-08-12 15:26:30 +02:00
Lukas
daab08ec01 macOS: drop the cross-platform check and abstraction
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-12 14:00:03 +02:00
Lukas
3901168b16 macOS: remove iOS target 2026-08-12 14:00:02 +02:00
Mitchell Hashimoto
b0b9fbc8d5 macOS: support decoding the surrogate pair with UnicodeHexInput (#13737)
Not yet a perfect fix for
https://github.com/ghostty-org/ghostty/discussions/13730
2026-08-11 11:03:01 -07:00
Mitchell Hashimoto
046b8fcc2a macos: defer OSC52 clipboard read confirmations until focused (#13744)
Fixes #10077

Clipboard read confirmations would immediately show a sheet which
grabbed focus. This could be used for a bunch of dumb reasons, including
DoS attacks. But, it also caused focus/sheet loops for programs that did
OSC52 on focus changes (which was seen via some Neovim configs!).

Now, if a surface is unfocused, we bell the surface and show the
confirmation request on next focus. If the surface is not focused or
another request comes in, we cancel the prior one.

This also fixes some memory management issues around clipboard requests
that were likely small leaks (didn't verify the old bug, but verified
the new code, and eyeballed the old).

To implement this, I decided to reorient the whole clipboard
confirmation thing around state on SurfaceView (which simplifies memory
management) and using Combine on BaseTerminalController to get notified.
2026-08-11 06:55:25 -07:00
Mitchell Hashimoto
d695ffff3b macos: defer OSC52 clipboard read confirmations until focused
Fixes #10077

Clipboard read confirmations would immediately show a sheet which
grabbed focus. This could be used for a bunch of dumb reasons, including 
DoS attacks. But, it also caused focus/sheet loops for programs that did
OSC52 on focus changes (which was seen via some Neovim configs!).

Now, if a surface is unfocused, we bell the surface and show the confirmation
request on next focus. If the surface is not focused or another request
comes in, we cancel the prior one.

This also fixes some memory management issues around clipboard requests
that were likely small leaks (didn't verify the old bug, but verified
the new code, and eyeballed the old).
2026-08-11 06:44:23 -07:00
Mitchell Hashimoto
44f06d4e4f macOS: rework for #12712 and #13645 (#13717)
`needleSelection` was introduced in #12712 to select all texts when
syncing pasteboard, the crash happens most on macOS 15 in
`readPasteboardNeedle`. It seems that `objectWillChange` fires
differently there, and it's hard to reproduce on macOS 26/27. I think
guaranteeing from ourside is enough, I believe SwiftUI already as its
own when updating the binding.

**Confirmed with a simple example on macOS 15, it seems a SwiftUI
issue🫪. So I changed the minimal macOS version for text selection to
macOS 26. I don't see an elegant way to fix it.**

<img width="1352" height="849" alt="image"
src="https://github.com/user-attachments/assets/1dfef3f5-ceaa-41dd-bb91-c23dbc5e4ad3"
/>


```swift
struct ContentView: View {
    @State private var text = ""
    @State private var selection: TextSelection?
    var body: some View {
        TextField("Search", text: $text, selection: $selection)
    }
}
```
2026-08-10 18:08:42 -07:00
Lukas
f0e3be3eef macOS: support decoding the surrogate pair with UnicodeHexInput 2026-08-10 22:55:57 +02:00
Jeffrey C. Ollie
8b7c57c756 gtk: add window title renaming
Fixes #10469 for GTK.
2026-08-10 10:07:11 -05:00
Lukas
49e4df7833 macOS: rework for #12712 and #13645 2026-08-09 23:19:47 +02:00
Lukas
74f91d1b43 macOS: support drag-handle config 2026-08-09 15:14:50 +02:00
Lukas
fd98370211 macOS: fix swiftlint 2026-08-07 16:51:19 +02:00
Mitchell Hashimoto
fcee19819e macos: discard debounced selection notification (#13676)
Discard the selection notification payload before debouncing
accessibility changes.

The debouncer previously retained the notification and its surface
object, keeping a closed tab's view and PTY alive after the undo
timeout.
2026-08-07 07:14:54 -07:00
Mitchell Hashimoto
44a05a88aa macos: discard debounced selection notification
Discard the selection notification payload before debouncing
accessibility changes.

The debouncer previously retained the notification and its surface
object, keeping a closed tab's view and PTY alive after the undo
timeout.
2026-08-06 13:05:37 -07:00
Lukas
18f06ef03c macOS: fix unsupported action falls through wrong handling 2026-08-06 16:17:11 +02:00
Mitchell Hashimoto
c9ef382fc9 macos: synchronize cached value access (#13646)
Fixes #13276

Make CachedValue safe for concurrent terminal content reads and expiry.

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

Protect cached values and task handles with an NSLock, and exercise
concurrent reads across repeated expiration in a regression test.
2026-08-05 15:19:03 -07:00
Mitchell Hashimoto
d28bc121a8 macos: synchronize cached value access
Fixes #13276

Make CachedValue safe for concurrent terminal content reads and expiry.

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

Protect cached values and task handles with an NSLock, and exercise
concurrent reads across repeated expiration in a regression test.
2026-08-05 14:18:33 -07:00
Mitchell Hashimoto
74f01cf5df macos: prevent stale search selection crash
Fixes #13266

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

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

Clear selection before publishing new text.
2026-08-05 14:02:46 -07:00
Mitchell Hashimoto
77537c8065 macos: handled untrusted OSC8 hyperlinks more carefully
OSC8 hyperlinks previously executed directly via the NSWorkspace opener
so a malicious application can just do whatever it wanted and trick the
user into opening something through Launch Services.

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

  - Preview text is sanitized, so invisible Unicode characters now show.
  - Questionable-looking URLs require confirmation to open, but a user
    can confirm to open.
  - Very questionable or definitely unsafe URLs are blocked with an 
    alert that only allows the user to copy the link. The alert also
    notifies the user why.
2026-08-05 10:22:28 -07:00
Uzair Aftab
ad96613a8c inspector: add copy and export for terminal IO events
Adds "Copy" and "Export to file" buttons to the Terminal IO inspector
so recorded VT events can be saved outside the app for sharing or
analysis.

Export is wired up through a new export_terminal_io apprt action,
handled with a native save dialog on both macOS and GTK.
2026-07-30 08:08:25 +02:00
Lukas
a6edca2d7c macOS: free surface synchronously in deinit on main thread 2026-07-26 16:12:34 +02:00
Lukas
91f66da245 macos: route IME preedit commits through key events (#13222) 2026-07-08 07:06:44 +02:00
qappell
751a60df61 macos: route IME preedit commits through key events 2026-07-07 13:00:39 -05:00
Lukas
6e267d3363 macOS: use the getOpinionatedStringContents same as paste 2026-07-06 09:04:24 +02:00
Mitchell Hashimoto
f52f8aab95 macos: avoid notification publisher retain cycle
Turns out combine's `publisher(for:,object:)` retains the object!
We verified this with a test script shown below. Fix this with a 
manual filter. Found by @mustafa0x.

```
import Combine
import Foundation

final class Token {
    deinit { print("Token deinitialized") }
}

weak var weakToken: Token?
var publisher: NotificationCenter.Publisher?

// Create scope that will free token.
do {
    let token = Token()
    weakToken = token
    publisher = NotificationCenter.default.publisher(
        for: Notification.Name("TestNotification"),
        object: token
    )
}

print("Retained:", weakToken != nil)
publisher = nil
print("Released:", weakToken == nil)
```
2026-06-25 11:21:21 -07:00
Jon Parise
c4e1ab8883 core: send selection_changed notification
The core had no signal to the apprt when the active selection changed,
so a consumer (e.g. a screen reader) kept reading a stale selection
until some unrelated query refreshed it.

This change adds a payload-less selection_changed action that's fired on
a selection state transition. The apprt reads the current selection
through the normal read path.

This consolidates selection state changes so the notification fires
consistently: all sites route through setSelection rather than calling
screen.select directly, including the mouse paths that previously
bypassed it for clipboard timing.

The new setSelectionAndCopy extends setSelection with the additional
'copy_on_select' behavior.

On macOS, this posts .ghosttySelectionDidChange, which is debounced
before posting a NSAccessibility .selectedTextChanged notification.

GTK has no consumer yet and no-ops the action.
2026-06-02 19:37:49 -04:00
Claude Opus 4.7
eb5c1c7220 fix(macos): mark Swift os.Logger interpolations as public 2026-05-31 16:35:11 +02:00
Jon Parise
e32d7abe6e macos: fix swiftlint opening_brace issue 2026-05-31 10:00:24 -04:00
Adam Bouker
57d202066d macOS: clear stale OSC 11 background cache on config change
SurfaceView caches the background color set by OSC 11 in
backgroundColor. TerminalWindow.preferredBackgroundColor consults
that cache before falling back to derivedConfig.backgroundColor,
so once OSC 11 has fired the cached value masks any later config
change. After a light/dark theme auto-switch this leaves the
window chrome on the previous theme's color until the application
next emits OSC 11.

In ghosttyConfigDidChange, after updating derivedConfig, drop the
cache when it no longer matches the new config-derived background.
A subsequent ghosttyColorDidChange repopulates it as before, so
within-config OSC 11 behavior is unchanged.
2026-05-26 14:11:45 -05:00
minorcell
da541bea63 fix stray brace from conflict resolution 2026-05-23 16:33:33 +08:00