Commit Graph

9866 Commits

Author SHA1 Message Date
Jeffrey C. Ollie
9d8fbd15b3 gtk: add +new-tab action (#11762)
This PR adds a `+new-tab` CLI action, useful for automation on GTK. This
mainly re-uses machinery added for the `+new-window`, but adds in a
unique surface ID for identifying surfaces for IPC purposes (and
eliminates use of raw pointers for callbacks from notifications).
2026-08-09 11:31:36 -05:00
Lukas
74f91d1b43 macOS: support drag-handle config 2026-08-09 15:14:50 +02:00
Leah Amelia Chen
05221c11c9 core,gtk: add drag-handle config (#13706)
Fixes hundreds of complaints about the fact that drag handles cannot be
hidden, on GTK at least.

I'm not sure if we ever made an issue for this? If you come across any
discussions asking for this, please link them here :)
2026-08-09 20:10:38 +08:00
Leah Amelia Chen
850ca8c7b1 gtk: rebind is-split after moving split cross-tree
It turns out we never unbound the split from its original tree after
moving, which means `is-split` in particular is desynced and leads to
hilarious artifacts like how `unfocused-split-*` options just stop
working properly. I only realized this is a thing after the naïve
drag handle config option didn't work properly. Fun!
2026-08-09 16:09:02 +08:00
Leah Amelia Chen
65a3e666ef gtk: drag overlay toggle 2026-08-09 16:09:02 +08:00
Leah Amelia Chen
c6e7e9e4e2 config: add drag-handle 2026-08-09 16:09:00 +08:00
Fredrik Fornwall
74efadb446 lib-vt: answer XTGETTCAP queries
Ghostty's full termio path answers XTGETTCAP from the static terminfo
map, but terminal/stream_terminal.zig, which backs libghostty-vt,
parses the same DCS request and then discards it. There is no XTGETTCAP
effect either, so an embedder cannot restore the replies through the
C API.

Programs query these over SSH instead of assuming the remote host has
the client's terminfo entry. This matters more for an embedder than for
the desktop app, which can install its entry on the remote through
shell integration.

Answer the queries in stream_terminal the same way termio does: look
up each requested key in the static terminfo map and write the reply
to the pty, skipping the lookups entirely when no write_pty effect is
set. The map now stores null-terminated responses so they can be
handed straight to write_pty without copying. terminal/dcs.zig and the
termio path are unchanged.

"TN" is handled separately. It names the terminfo entry the terminal
runs as, so it has to agree with TERM -- which is set in
termio/Exec.zig, a layer libghostty-vt does not contain. The library
never sees TERM and cannot answer on the embedder's behalf, and
answering with Ghostty's own entry from the static map would misreport
every embedder, so "TN" is intercepted before the map lookup. The name
is instead configured through a new option,
GHOSTTY_TERMINAL_OPT_TERMINFO_NAME: the string is copied into the
terminal, names longer than 128 bytes are rejected, and while unset
the query goes unanswered.

This is the first dependency from src/terminal on src/terminfo, so
libghostty-vt now carries Ghostty's terminfo table: +16,023 bytes
(+1.9%) on a wasm32-freestanding ReleaseSmall build.

Signed-off-by: Fredrik Fornwall <fredrik@fornwall.net>
2026-08-08 20:15:40 -07:00
Mitchell Hashimoto
94beef81ef libghostty: effect for unknown sequence (APC only this PR) (#13702)
This introduces a new effect for Zig/C callers to detect unknown
sequences.

This PR starts only with APC, but the API shape is such that we can add
other types (OSC next) in future PRs. The goal of this is to have zero
overhead in the disabled/undetected (both) case, and minimal overhead in
the detected case.

This is important in particular for libghostty consumers because it
allows them to implement their own custom protocols and/or support
features libghostty doesn't support. It isn't possible to support them
at the same performance libghostty does but supporting them in general
is usually valuable.

From a Zig API to enable this, users must set `unknown_max_bytes` for
the APC handler AND update their stream handler to recognize unknown
sequences. The built-in `stream_terminal` stream type has an exposed
callback for this, so both must be set.
2026-08-08 19:52:49 -07:00
Mitchell Hashimoto
6b990de5be terminal: C API for unknown sequences 2026-08-08 16:49:45 -07:00
Omkar Chandorkar
a6fc3e0e2e gtk/wayland: clean up blur regions
Destroy temporary Wayland regions after each blur update and release
the previous cached blur region before replacing it. This prevents
resources from leaking while the blur region changes.
2026-08-08 22:28:41 +05:30
Mitchell Hashimoto
b537282411 terminal/apc: support reporting unknown APC sequences 2026-08-08 08:54:32 -07:00
Mitchell Hashimoto
afb351f838 terminal/stream: fast-path APC termination
APC payload bytes are bulk consumed, but the terminating byte still passed 
through the generic parser action loop. Handle ESC and C1 ST directly after 
bulk consumption while leaving other transitions on the scalar path.
2026-08-08 08:54:16 -07:00
Jeffrey C. Ollie
034506f145 gtk: add +new-tab cli action 2026-08-08 10:34:45 -05:00
Mitchell Hashimoto
204989ad90 terminal/snapshot: remove BLAKE3 digests (#13680)
Remove BLAKE3 prefix digests. Keep READY/FINISH as empty records since
they're semantically important markers.

Our existing format (CRC32 per-record, declared counts, strict tag
ordering requirements, etc.) already detect: accidental corruption,
truncation, data omission, and duplication.

BLAKE3 only protects against valid records being swapped or removed
entirely. It is heavy for just that, and callers can solve that anyways
via their own transport (like, just use TCP). For more adversarial
protection, callers can also add layers like TLS or their own alternate
signing methods depending on their own threat models.

Removing the hash improves encode times by ~1.4x, decode times by ~1.3x.
Time-to-READY decoding is effectively unchanged because it was such a
small package to begin with.

**AI usage:** I had it clean up the comments and the tests, but I did
the blake3 removal and marker changes, and wrote the commit message
myself. All reviewed.
2026-08-07 07:53:24 -07:00
Mitchell Hashimoto
0a78672e7c build: fix flatpak/snap, restore rpath opt, fix local gtk4-layer-shell (#13677)
This fixes regressions in the flatpak/snap builds, and knock-on stuff
that was discovered as as a result:

* Update the Zig versions in the flatpak/snap build configuration files.
* Restore the classic `-Dpatch-rpath` option, and add a new
`-Dpatch-interp` option. This ensures that the snap can still use
`-Dpatch-rpath` correctly.
* There seems to be an issue in Zig when parsing IPv6 addresses that
leads to issues loading `resolv.conf` files; when trying to load a
nameserver that has an IPv6 address with a numeric interface index as
the scoped zone ID, Zig will try to resolve the interface as a name
rather than just use the index. This is coming up in snap builds because
the build process seems to, by default, use the exhaustive
`/run/systemd/resolve/resolv.conf` file, versus the simpler stub
(`stub-resolv.conf`) file. We work around this for the time being by
linking the stub at the end of the Zig part, overwriting the link to the
non-stub file.
* Fixed `gtk4-layer-shell` packaging - the migration to external
translate-c meant that non-system builds of the dependency were not
handing the local `gtk4-layer-shell` headers over for translation. Now,
instead, we've extracted the management of the `gtk4-layer-shell` source
and `wayland-protocols` generation to a locally-cached object so that
the source can be shared by both C translation and the library build in
a way that is not coupled to any particular step.
2026-08-07 07:52:31 -07:00
Mitchell Hashimoto
571c62dada font/coretext: creation functions can return null, handle OOM (#13679)
Catch NULL results from CoreFoundation/CoreText creation functions and
return error.OOM rather than null derefs later. I verified that this is
possible but didn't verify the behavior when it happens, this is just
defensive based on the report here: #13671 because it costs us nothing
really.
2026-08-07 07:38:14 -07:00
Owen Giles
987f44260d cli: add g/G as vi-style aliases for Home/End in list-themes 2026-08-06 21:48:36 -05:00
Mitchell Hashimoto
219173ab37 terminal/snapshot: remove BLAKE3 digests
Remove BLAKE3 prefix digests. Keep READY/FINISH as empty records since
they're semantically important markers.

Our existing format (CRC32 per-record, declared counts, strict tag ordering
requirements, etc.) already detect: accidental corruption, truncation,
data omission, and duplication. 

BLAKE3 only protects against valid records being swapped or removed entirely. 
It is heavy for just that, and callers can solve that anyways via their
own transport (like, just use TCP). For more adversarial protection,
callers can also add layers like TLS or their own alternate signing
methods depending on their own threat models.

Removing the hash improves encode times by ~1.4x, decode times by ~1.3x.
Time-to-READY decoding is effectively unchanged because it was such a 
small package to begin with.
2026-08-06 14:12:08 -07:00
Mitchell Hashimoto
daeed25b37 font/coretext: creation functions can return null, handle OOM
Catch NULL results from CoreFoundation/CoreText creation functions and
return error.OOM rather than null derefs later. I verified that this is
possible but didn't verify the behavior when it happens, this is just
defensive based on the report here: #13671 because it costs us nothing
really.
2026-08-06 13:47:06 -07:00
Chris Marchesi
b9113d2e7f build: fix flatpak/snap, restore rpath opt, fix local gtk4-layer-shell
This fixes regressions in the flatpak/snap builds, and knock-on stuff
that was discovered as as a result:

* Update the Zig versions in the flatpak/snap build configuration files.
* Restore the classic -Dpatch-rpath option, and add a new -Dpatch-interp
  option. This ensures that the snap can still use -Dpatch-rpath
  correctly.
* There seems to be an issue in Zig when parsing IPv6 addresses that
  leads to issues loading resolv.conf files; when trying to load a
  nameserver that has an IPv6 address with a numeric interface index as
  the scoped zone ID, Zig will try to resolve the interface as a name
  rather than just use the index. This is coming up in snap builds
  because the build process seems to, by default, use the exhaustive
  /run/systemd/resolve/resolv.conf file, versus the simpler stub
  (stub-resolv.conf) file. We work around this for the time being by
  linking the stub at the end of the Zig part, overwriting the link to
  the non-stub file. 
* Fixed gtk4-layer-shell packaging - the migration to external
  translate-c meant that non-system builds of the dependency were not
  handing the local gtk4-layer-shell headers over for translation. Now,
  instead, we've extracted the management of the gtk4-layer-shell source
  and wayland-protocols generation to a locally-cached object so that
  the source can be shared by both C translation and the library build
  in a way that is not coupled to any particular step.
2026-08-06 13:08:33 -07:00
Lukas
c011ad8707 Update wording
Co-authored-by: Tristan Partin <tristan@partin.io>
2026-08-06 19:38:18 +02:00
Claude Opus 5 (1M context)
a14eba7478 input: update toggle_maximize documentation 2026-08-06 19:13:29 +02:00
Leah Amelia Chen
111877354e core,gtk: add move_tab_to_new_window action (#13621)
Implements most of #2630

This is in reality a really simple change and ideally we can get this
out before the 1.4 string freeze
2026-08-06 22:22:35 +08:00
Mitchell Hashimoto
afa9e4fad0 libghostty: add configurable mode defaults, remove mode_set/get (#13661)
ABI BREAKING: This removes `ghostty_terminal_mode_get` and `_mode_set`.
We can now represent these operations completely with standard
`ghostty_terminal_get` and `ghostty_terminal_set`, which makes it much
more flexible to preserve ABI in the future.

This is all centered around a new `GhosttyTerminalModeConfig` structure
that is an in or out parameter depending on use case.

This also adds a new `GHOSTTY_TERMINAL_OPT_MODE_DEFAULT` option that can
be used to set the _default_ value of mode that happens when a RIS event
(full reset) is sent. Note that not all modes are configurable because
some are set based on live terminal state and aren't modes in and of
themselves.

## Why Delete Functions? Why Not Add?

Once tagged, the goal of `libghostty-vt` is to remain HIGHLY ABI
compatible. We are striving for top tier ABI compatibility similar to
legendary C libraries. That means we need to be highly confident in our
API shapes: functions, structs, etc. and using shapes that we can retain
ABI compatibility even as we add features. Every function is a risk. By
pushing stuff into our `_get/_set` patterns, its easier to maintain ABI
compatibility.
2026-08-06 06:45:54 -07:00
Mitchell Hashimoto
ec58fbc6a2 build: default dependencies to lib-vt mode to avoid Xcode requirements (#13660)
Related to #10651

Default Ghostty dependency builds to libghostty-vt-only mode and avoid
initializing anything that would trigger broader dependency
requirements.

The impact of this is that Zig consumers can import ghostty-vt without
requiring Xcode on macOS.
2026-08-05 22:20:28 -07:00
Mitchell Hashimoto
cfc19e8053 libghostty: add configurable mode defaults, remove mode_set/get
ABI BREAKING: This removes `ghostty_terminal_mode_get` and `_mode_set`.
We can now represent these operations completely with standard 
`ghostty_terminal_get` and `ghostty_terminal_set`, which makes it much
more flexible to preserve ABI in the future.

This is all centered around a new `GhosttyTerminalModeConfig` structure
that is an in or out parameter depending on use case.

This also adds a new `GHOSTTY_TERMINAL_OPT_MODE_DEFAULT` option that
can be used to set the _default_ value of mode that happens when a RIS
event (full reset) is sent.
2026-08-05 22:07:25 -07:00
Mitchell Hashimoto
49fd1ae654 build: default dependencies to lib-vt mode
Related to #10651

Default Ghostty dependency builds to libghostty-vt-only mode and
avoid initializing anything that would trigger broader dependency
requirements.

The impact of this is that Zig consumers can import ghostty-vt without
requiring Xcode on macOS.
2026-08-05 22:01:49 -07:00
Mitchell Hashimoto
f948d42076 termio: replace SegmentedPool with std.MemoryPool (#13659)
The purpose of SegmentedPool was pointer-stable values for the pty write
path, and the std.MemoryPool provides that.

SegmentedPool is actually so old it predates a stdlib memory pool! Just
noting why I did it in the first place. I also wrote it when I was
pretty fucking bad at Zig, so I'm shocked its lasted this long.

The write path is hot , so the replacement was benchmarked against the
old SegmentedPool plus a rewrite simple Pool I did before realizing...
wait... why not just a MemoryPool. Benchmarked using the real 240-byte
xev write request.

```
  workload                    old                     std.MemoryPool
  depth-1 (keystroke echo)    3.93 ns/op              0.96 ns/op
  burst (1MiB paste, d=256)   4.27 ns/op              1.00 ns/op
  cold growth (32 -> 16k)     4.54 ns/op              6.48 ns/op
  malloc create/destroy       15.9 ns/op              (baseline)
```

Cold growth is slower but this is only a cost when the pool grows.

Note this also gets rid of the preallocation, which didn't show any
measurable performance benefit at all. This has the benefit of shrinking
our ThreadData by ~10KB.

This was motivated by #13655
2026-08-05 21:06:16 -07:00
Mitchell Hashimoto
e0ef934f73 termio: replace SegmentedPool with std.MemoryPool
The purpose of SegmentedPool was pointer-stable values for the pty write
path, and the std.MemoryPool provides that. 

SegmentedPool is actually so old it predates a stdlib memory pool!
Just noting why I did it in the first place. I also wrote it when I was
pretty fucking bad at Zig, so I'm shocked its lasted this long.

The write path is hot , so the replacement was benchmarked against the old 
SegmentedPool plus a rewrite simple Pool I did before realizing...
wait... why not just a MemoryPool. Benchmarked using the real 240-byte xev
write request.

  workload                    old                     std.MemoryPool
  depth-1 (keystroke echo)    3.93 ns/op              0.96 ns/op
  burst (1MiB paste, d=256)   4.27 ns/op              1.00 ns/op
  cold growth (32 -> 16k)     4.54 ns/op              6.48 ns/op
  malloc create/destroy       15.9 ns/op              (baseline)

Cold growth is slower but this is only a cost when the pool grows.

Note this also gets rid of the preallocation, which didn't show any
measurable performance benefit at all. This has the benefit of shrinking
our ThreadData by ~10KB.
2026-08-05 20:58:33 -07:00
Mitchell Hashimoto
63da4e84d4 lib: remove backported cutPrefix implementation (#13658)
We can use std.mem.cutPrefix directly now that we're on Zig 0.16.
2026-08-05 20:47:26 -07:00
Jon Parise
1d6bc68298 lib: remove cutPrefix implementation
We can use std.mem.cutPrefix directly now that we're on Zig 0.16.
2026-08-05 23:07:43 -04:00
Jeffrey C. Ollie
f0f3f4d8d8 GTK: move audio bell processing to the application
This fixes #13647 by using at most one GStreamer thread per application.
This was previously addressed in #12815 which used at most one GStreamer
thread per surface. Originally discussed in #12808.
2026-08-05 20:10:53 -05:00
Mitchell Hashimoto
8eecb8fdbf terminal: release Kitty placement pins on eviction (#13656)
Image eviction removed associated placements from storage without
deinitializing them. Pin-backed placements therefore remained registered
with the screen after eviction, allowing graphics-heavy output to
accumulate stale tracked pins.

Pass the owning screen through image insertion and eviction, and
deinitialize each placement before removing it. Cover both the released
pin and a retained image's live pin in the eviction regression test.
2026-08-05 16:31:23 -07:00
Mitchell Hashimoto
ea21a2f141 core: avoid allocating for pwd change actions (#13654)
Surface.handleMessage allocated a null-terminated copy for every working
directory update. OSC 7 values fit within the parser's 2 KiB fixed
buffer, so use stack-fallback storage sized for that bound and its
terminator.

The message type does not enforce the OSC bound, so an oversized future
producer still falls back to the heap. performAction already borrows the
value only for the duration of the call, preserving its existing
lifetime.
2026-08-05 16:28:50 -07:00
Amp
b5e86a4284 terminal/kitty: release evicted placement pins
Image eviction removed associated placements from storage without
deinitializing them. Pin-backed placements therefore remained registered
with the screen after eviction, allowing graphics-heavy output to
accumulate stale tracked pins.

Pass the owning screen through image insertion and eviction, and
deinitialize each placement before removing it. Cover both the released
pin and a retained image's live pin in the eviction regression test.

Co-authored-by: Tim Culverhouse <tfc@ampcode.com>
2026-08-05 23:10:17 +00:00
Jon Parise
f1d225020a core: avoid allocating for small pwd change actions
Surface.handleMessage allocated a null-terminated copy for every working
directory update.

Use a small 256-byte stack-fallback buffer for common working directory
lengths without adding significant pressure to this deep call stack. Longer
paths retain the existing heap behavior, and performAction continues to borrow
the value only for the duration of the call.
2026-08-05 18:31:27 -04:00
Mitchell Hashimoto
9cb2147641 terminal/kitty: evict without scratch allocation (#13627)
Track each image's placement count in its existing metadata. This lets
us use constant-time usage checks (rather than scans) during eviction.

Select the best candidate directly from storage on each eviction,
preserving the existing priority order: unused status, transient hint,
generation, then ID.

Since eviction no longer allocates, it can't fail, so callers no longer
need to handle out-of-memory conditions.
2026-08-05 15:28:41 -07:00
Mitchell Hashimoto
090d161b28 terminal: report overline in DECRQSS SGR response (#13653)
#11638

Report SGR 53 when the active cursor style has overline enabled.
2026-08-05 15:20:19 -07:00
Mitchell Hashimoto
f973bd53ba terminal: report overline in DECRQSS SGR response
#11638

Report SGR 53 when the active cursor style has overline enabled.
2026-08-05 15:09:01 -07:00
Mitchell Hashimoto
8524cb593c terminal/kitty: fix point deletion calculations (d=p, d=c)
Fix d=p and d=c point deletion so only placements intersecting the
target cell are removed. 

Previously, placements spanning multiple rows could be deleted from
columns outside the target because the page-order comparison flattened
row and column coordinates.

Check the rectangle's column independently and use page order only for
its row span, matching Kitty's implementation:
https://github.com/kovidgoyal/kitty/blob/master/kitty/graphics.c

NOTE: I did not look at Kitty's source prior to fixing this. I only
referenced it after the fix to verify that the behavior matches.

Spec:
https://sw.kovidgoyal.net/kitty/graphics-protocol/#deleting-images
2026-08-05 15:00:53 -07:00
Mitchell Hashimoto
9ed61428da libghostty-vt: spacer-tail handling needs to respect slow runtime safety (#13651)
Debug libghostty-vt dependencies embedded in ReleaseFast or ReleaseSmall
binaries no longer panic when narrow text overwrites the tail of a wide
glyph.

Replace the root module's std.debug.runtime_safety gate with
build_options.slow_runtime_safety so mixed optimization modes use the
dependency's safety configuration consistently.
2026-08-05 14:49:10 -07:00
Mitchell Hashimoto
1aeca6705e terminal: color reset should set override to null, not default (#13650)
#12755

Reset previously copied the active default into the override. This is
wrong, a reset should unset the override and defer back to the default.

Reset foreground, background, and cursor colors now resolve through the
current default while explicit OSC overrides remain unchanged across
configuration updates.

Set a configured background in the OSC 11 regression, assert OSC 111
clears its override, then change the default to verify the reset color
follows it.
2026-08-05 14:48:40 -07:00
Mitchell Hashimoto
78dec345b2 terminfo: advertise overline support (#13649)
#12885

Ghostty already implements SGR 53 and 55, but its terminfo description
does not expose the corresponding Smol and Rmol capabilities. Add both
entries so the advertised capabilities match the renderer. Tmux uses
this to gate overline.
2026-08-05 14:48:27 -07:00
Mitchell Hashimoto
0dcb411681 fix screen action fd leak from tempdir (#13644)
Fixes #13219

Screen file actions intentionally retain their temporary directory so
the generated path remains valid after dispatch. The directory and
parent handles were retained with it, while TempDir.deinit also left the
parent handle open.

Each successful action leaked two descriptors. Repeated screen,
scrollback, or selection writes could exhaust the process descriptor
limit and prevent new PTYs, tabs, and windows from opening.

Give TempDir an exhaustive close mode that either deletes or retains its
contents while always releasing both handles. Defer screen-file cleanup,
retaining only after successful dispatch, and cover both lifecycle paths
with descriptor tests.
2026-08-05 14:47:34 -07:00
Mitchell Hashimoto
5033ea83d8 terminal: preserve cursor when formatting tabstops (#13643)
Fixes #13269

Move VT tabstop serialization ahead of screen formatting so
cursor-moving CHA and HTS sequences run before screen state is restored.

Tabstop-enabled snapshots previously finished at the final configured
tabstop instead of the serialized cursor position. Replaying a snapshot
could resume input in the wrong column.

Keep tabstop bytes in their original pin-map accounting and extend the
round-trip test to verify tabstops, cursor position, and map length.
2026-08-05 14:47:25 -07:00
Mitchell Hashimoto
b60970ce25 macos: handle missing CoreText display names (#13642)
Fixes https://github.com/ghostty-org/ghostty/discussions/13262

CTFontCopyDisplayName can return null.
2026-08-05 14:38:31 -07:00
Mitchell Hashimoto
71c2d68eb4 macos: tolerate display link creation failures (#13639)
Fixes #13293

Treat Core Video display link creation as optional when macOS has no
active displays. The previous error path reported every creation failure
as out of memory and aborted renderer initialization.

Tabs created while the session is locked now initialize normally and
fall back to event-driven rendering without vsync.
2026-08-05 14:38:15 -07:00
Mitchell Hashimoto
b30387a80f renderer/metal: clear callback before layer release (#13641)
Fixes https://github.com/ghostty-org/ghostty/discussions/13242

Clear the IOSurfaceLayer display callback when releasing the wrapper.
The host view can retain the backing layer beyond renderer teardown.
This prevents a later Core Animation display pass from invoking the
callback with a freed renderer context.

This doesn't happen the way Ghostty GUI uses our renderer, but it is
possible for folks using ghostty-internal and its straightforward and
easy for us to fix it.
2026-08-05 14:35:31 -07:00
Mitchell Hashimoto
e20564791e libghostty-vt: spacer-tail handling needs to respect slow runtime safety
Debug libghostty-vt dependencies embedded in ReleaseFast or ReleaseSmall
binaries no longer panic when narrow text overwrites the tail of a wide
glyph.

Replace the root module's std.debug.runtime_safety gate with
build_options.slow_runtime_safety so mixed optimization modes use the
dependency's safety configuration consistently.
2026-08-05 14:34:55 -07:00
Mitchell Hashimoto
7cd2f65f5c terminal: color reset should set override to null, not default
#12755

Reset previously copied the active default into the override. This is
wrong, a reset should unset the override and defer back to the default.

Reset foreground, background, and cursor colors now resolve through the
current default while explicit OSC overrides remain unchanged across
configuration updates.

Set a configured background in the OSC 11 regression, assert OSC 111
clears its override, then change the default to verify the reset color
follows it.
2026-08-05 14:30:21 -07:00