Commit Graph

802 Commits

Author SHA1 Message Date
Tim Culverhouse
6c8c07981d terminal: add visibility reports
Applications cannot infer whether an unfocused terminal remains visible, so
focus reports are insufficient for avoiding expensive rendering while a
view is hidden.

Implement private mode 2033 and the visibility query/report sequences.
Track conservative per-surface visibility, report every effective change
while enabled, and always answer explicit queries and mode enables. Keep
view visibility across terminal resets because it is owned by the host,
not terminal state.

Co-authored-by: Amp <amp@ampcode.com>
Amp-Thread-ID: https://ampcode.com/threads/T-019fa965-aa5f-7099-85b4-a9679d2c8bd3
2026-07-28 11:04:13 -05:00
Chris Marchesi
e8525c0fd9 Update to Zig 0.16.0
This commit represents the majority of the work necessary to upgrade
Ghostty to use Zig 0.16.0.

Key parts:

* In addition to its previous responsibilities, the global state now
  houses state for global I/O implementations and the process
  environment. It is now also utilized in the main application along
  with the C library. Where necessary, global state is isolated from key
  parts of the implementation (e.g., in libghostty subsystems), and it's
  expected that this list will grow.

* We currently manage our own C translation layer where necessary. In
  these cases, cImport has been removed in favor of the new external
  translate-c package. Due to fixes that have needed be made to properly
  translate the dependencies that were swapped out, as mentioned, we
  have had to backport fixes from the current translate-c package (and
  the upstream Arocc dependency). We will host this ourselves until Zig
  0.17.0 is released with these fixes.

* Where necessary (only a small number of cases), some stdlib code from
  0.15.2 (and even from 0.17.0) has been taken, adopted, and vendored in
  lib/compat.

Co-authored-by: Leah Amelia Chen <hi@pluie.me>
2026-07-21 12:35:05 -07:00
Mitchell Hashimoto
421fe8dabe terminal: integrate compressed pages into PageList
PageList nodes previously exposed Page directly, so introducing a
compressed representation would require every consumer to understand its
state and ownership.

Add resident and compressed node states behind a page access boundary.
Content access transparently recommits and restores retained mappings,
while metadata traversal stays compressed and lifecycle paths can
discard encoded contents without decoding. Compression borrows pool
memory for standard scratch and uses temporary aligned storage for
oversized pages.

Migrate terminal, rendering, search, formatting, and C API consumers to
the new boundary. Hot grow, scroll, and print paths reuse resolved
pages, with an explicit resident-only accessor where live cursor
pointers prove that the page cannot be compressed.

The compression entry point remains private with no production callers,
so normal terminal behavior and scrollback accounting are unchanged.
ReleaseFast terminal-stream comparisons across bulk output, scrolling,
redraw, and erase workloads remain within 2% of the parent revision.
2026-07-09 09:47:11 -07:00
Alex Bennett
fd882c67cc pr review: added saturated arithmetic 2026-06-08 16:50:41 +08:00
Alex Bennett
97777cf5a3 fix: fix tests, change enum fields to lowercase 2026-06-07 23:55:47 +08:00
Alex Bennett
3263ce5122 terminal: support click_events=2 2026-06-07 23:01:53 +08: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
Jon Parise
ab82b8ab72 core: fix use-after-free in Surface.setSelection
setSelection captured the previous selection, then called Screen.select
(which deinits the previous selection's tracked pins), then compared the
new selection against the now-freed previous pin via `sel.eql(prev)`.
That read freed pin memory (use-after-free).

The comparison was a copy-on-select optimization ("only re-copy if the
selection changed"). Remove it rather than repair it because:

- It never fired correctly. It compared against freed memory, so the
  shipped behavior was already "always copy".

- It can't be repaired by copying `prev`'s pin before Screen.select.
  That fixes the use-after-free but not the logic: the call sites (e.g.
  mouse drag release) pass a selection equal to the one already set, so
  a working `eql` skip would suppress the very copy those sites exist to
  perform. A correct optimization would have to compare against the
  last-copied selection (before the mouse event mutated the live one),
  which would require extra state.

- It isn't worth tracking that additional state. The copy runs once per
  selection gesture (mouse up, double-click), which isn't in a hot path,
  so skipping a redundant re-copy only saves a single clipboard write.

Removing the skip eliminates the use-after-free and keeps the behavior
consistent with what we've already been doing.
2026-06-01 20:09:14 -04:00
Mitchell Hashimoto
68959c5c63 terminal: fix selection gesture edge cases
Selection gestures now treat releases with invalidated anchors as dragged,
so a press that crosses screen boundaries cannot also activate links or
prompt clicks on release. Cell drags that create a same-cell selection also
mark the gesture as dragged, which keeps click-only actions from firing
after a threshold-crossing drag.

Autoscroll now resolves the drag pin after moving the viewport instead of
reusing the pin from before the scroll. This keeps the selection aligned
with the row currently under the pointer. The inspector also validates the
tracked click pin before displaying it so stale pins from inactive screens
are ignored.
2026-05-27 06:58:44 -07:00
Mitchell Hashimoto
7d4d1e5819 terminal: add configurable behaviors based on click count 2026-05-27 06:32:51 -07:00
Mitchell Hashimoto
82a73f2bf1 terminal: SelectionGesture press returns standard behaviors 2026-05-27 06:26:07 -07:00
Mitchell Hashimoto
f5f9d32d0a terminal: SelectionGesture deep press 2026-05-26 21:36:22 -07:00
Mitchell Hashimoto
df98b6d983 terminal: SelectionGesture autoscrollTick 2026-05-26 21:26:49 -07:00
Mitchell Hashimoto
141c7d44d2 SelectionGesture: release event 2026-05-26 21:17:03 -07:00
Mitchell Hashimoto
229f4c1f4f terminal: SelectionGesture handles word/line drag 2026-05-26 21:04:22 -07:00
Mitchell Hashimoto
c00cdd886b SelectionGesture: drag events 2026-05-26 20:56:49 -07:00
Mitchell Hashimoto
33f1558801 core: mouse left release renderer lock made more coarse
This will make our selection gesture extraction a bit easier.
2026-05-26 17:02:20 -07:00
Mitchell Hashimoto
14df684a70 core: adapt Surface to use SelectionGesture with press only 2026-05-25 15:48:20 -07:00
Mitchell Hashimoto
60f767dd84 core: guard surface left-click pins with screen generations
Left-click mouse state stored a tracked pin with only the screen key that
owned it. If the alternate screen was removed and later recreated, the key
could match again even though the stored pin belonged to destroyed PageList
storage.

Store the screen generation alongside the left-click pin and resolve the
pin through helpers that require both the key and generation to match. This
keeps selection scrolling, link hover checks, pressure selection, and drag
selection from dereferencing stale tracked pins after screen teardown.
2026-05-23 14:45:13 -07:00
Aditya Bhargava
5871a2d4f0 zig-fmt cleanup 2026-04-27 16:28:23 -04:00
Aditya Bhargava
154169b054 Fix speedy high-resolution scrolling on Linux
Enforcing an absolute minimum of 1 for scroll events causes differing
scroll speeds between high-resolution and standard scroll wheels on
Linux. Since this was added to handle MacOS's precision scrolling
emulation, this patch alters the behaviour so that the absolute minimum
is only enforced on MacOS.

Fixes #11648.
2026-04-27 16:28:23 -04:00
Andrei Lebedev
12ac19939c feat: add middle-click action configuration 2026-04-27 01:27:22 +10:00
Mitchell Hashimoto
e9ca0f8c9a core: Acquire renderer state mutex before calling processLinks (#12463)
Holding the renderer state mutex is a documented precondition of
`processLinks`, but `mouseButtonCallback` previously called the function
without the mutex.

This creates a race with the I/O thread's `processOutput`, which can
prune scrollback pages while `processLinks` is reading them, resulting
in a use-after-free segfault. See
https://github.com/ghostty-org/ghostty/discussions/12409 (Linux: crash
while selecting text).


57b5e1e250/src/Surface.zig (L4354-L4355)


57b5e1e250/src/Surface.zig (L3822-L3824)

995e4e375 (os: open) changed the body of `processLinks` to be
non-trivial and documented the precondition, but the lock was not held
at the call site.
2026-04-25 13:21:38 -07:00
Mitchell Hashimoto
b613ffcfd8 surface: respect semantic prompt boundaries for links (#12435)
Link detection currently expands the clicked location to a full line
before running the configured regexes. When semantic prompt markers are
present, this can cause prompt text and neighboring content to be
matched together even though they are distinct semantic regions.

Use semantic prompt boundaries when selecting the text to inspect for
link matching. This keeps prompt text separate from the content beside
it and avoids folding prompt text into double-click link/path selection.

Add a regression test that models a prompt and command on the same line
and verifies the prompt region and input region remain separate.

----

this is a fix for the issue users reported in
https://github.com/ghostty-org/ghostty/discussions/11415

**disclaimer**: I used codex addon within Cursor to research this
bug/regression and find a proper fix for it.
2026-04-25 10:32:15 -07:00
Vasyl Zuziak
c4a671ba5a fix: remove test as has been suggested in comment 2026-04-25 19:26:22 +02:00
Jesse Rosenstock
28f4676b5d core: Acquire renderer state mutex before calling processLinks
Holding the renderer state mutex is a documented precondition of
`processLinks`, but `mouseButtonCallback` previously called
the function without the mutex.

This creates a race with the I/O thread's `processOutput`, which can
prune scrollback pages while `processLinks` is reading them, resulting
in a use-after-free segfault.  See
https://github.com/ghostty-org/ghostty/discussions/12409 (Linux: crash
while selecting text).

57b5e1e250/src/Surface.zig (L4354-L4355)

57b5e1e250/src/Surface.zig (L3822-L3824)

995e4e375 (os: open) changed the body of `processLinks` to be
non-trivial and documented the precondition, but the lock was not held
at the call site.
2026-04-25 16:36:45 +02:00
Vasyl Zuziak
85dc4b1842 surface: respect semantic prompt boundaries for links
Link detection currently expands the clicked location to a full line
before running the configured regexes. When semantic prompt markers
are present, this can cause prompt text and neighboring content to be
matched together even though they are distinct semantic regions.

Use semantic prompt boundaries when selecting the text to inspect for
link matching. This keeps prompt text separate from the content beside
it and avoids folding prompt text into double-click link/path
selection.

Add a regression test that models a prompt and command on the same
line and verifies the prompt region and input region remain separate.
2026-04-25 15:46:25 +02:00
007hacky007
50e8ebaf60 surface: sync middle-click paste source with copy-on-select
Middle-click paste previously always read from the selection clipboard
(falling back to the standard clipboard on platforms without one).

Now the paste source follows copy-on-select:
- copy-on-select = true: paste from selection clipboard (unchanged)
- copy-on-select = clipboard: paste from system clipboard
- copy-on-select = false: paste from selection clipboard (unchanged)

Fixes ghostty-org/ghostty#9788.
2026-04-20 19:56:45 +02:00
Jeffrey C. Ollie
4b5f2d60e7 core/gtk: ensure that first surface gets marked as focused surface by app 2026-03-31 14:57:41 -05:00
Jeffrey C. Ollie
ff02ed1b34 core: add 64 bit unique ID to every core surface
- Expose that ID as the environment variable GHOSTTY_SURFACE_ID to
  processes running in Ghostty surfaces.
- Add a function to the core app to search for surfaces by ID.
- ID is randomly generated, it has no other meaning other than as a
  unique identifier for the surface. The ID also cannot be zero as that
  is used to indicate a null ID in some situations.
2026-03-31 13:13:05 -05:00
Jeffrey C. Ollie
2ea6029c7a core: address getProcessInfo feedback
* consolidate *.c files into a single file
* consolidate ProcessInfo enums into a single enum
2026-03-19 22:01:16 -05:00
Jeffrey C. Ollie
89ae0ea6ef core: add function to get process info from the surface
This adds a function to the core surface to get process information
about the process(es) running in the terminal. Currently supported is
the PID of the foreground process and the name of the slave PTY.

If there is an error retrieving the information, or the platform does
not support retieving that information `null` is returned.

This will be useful in exposing the foreground PID and slave PTY name to
AppleScript or other APIs.
2026-03-19 22:01:15 -05:00
Mitchell Hashimoto
a811b6074b Lots of duplicate word typos + typo (#11539)
TL;DR: this description is (intentionally) nonsense but I ran
`\b(\w+)\s\1\b` over `src` and stole a singular typo fix from #11528.

Replacement of #11528 with 100% less slop and 99% less AI; I didn't feel
like saying no to free(ish) typo checking. Note that many of the fixes
there were outright incorrect (and clearly had no review from sentient
lifeforms, contrary to its—sorry, it's—description). A lot of extra
double words were caught with a handy `rg --pcre2 '\b(\w+)\s+\1\b' src`;
you could say this PR was “ripgrep-assisted” the way that one was
“AI-assisted”. Rather ironic since that PR also claims to have used grep
via Claude Code, but missed a lot of them.

The its → it's changes from that PR were elided; I decided to run a `rg
"\bit'?s\b" src`, but someone REALLY likes their its, so I reverted my
changes as there were an extremely large number of changes (probably a
hundred files with multiple hundred cases). The only other change was
“baout” → “about”.

# AI Usage

Claude Code was used by proxy for finding baout. Claude Code was used by
proxy for realizing that the correct spelling is about. Claude Code was
not used for fixing it. Oh my god it was so difficult to fix, the
original PR had it so easy. I had to type out the file name (fish's AI
sorry I mean autocomplete helped though) and like, type /baout, press R,
press ab, then save and exit. This is so difficult you know we should
use an AI for this, like this is so hard I don't know how people manage.

All changes were verified by me: I consulted the dictionary to delve
into double-checkment of “in existence; being in evidence; apparent.”
Uhhh insert assorted other AI impersonation here maybe? THE LLM IN ME
WANTS TO ESCAPE PLEASE HELP
2026-03-16 09:52:35 -07:00
Mitchell Hashimoto
ac5e57ce67 input: extract mouse encoding to a pure, testable file
Move mouse event encoding logic from Surface.zig into a new
input/mouse_encode.zig file.

The new file encapsulates event filtering (shouldReport),
button code computation, viewport bounds checking, motion
deduplication, and all five wire formats (X10, UTF-8, SGR,
urxvt, SGR-pixels). This makes the encoding independently
testable and adds unit tests covering each format and edge
case.

Additionally, Surface `mouseReport` can no longer fail, since the only
failure mode is no buffer space which should be impossible. Updated
the signature to remove the error set.
2026-03-15 15:37:54 -07:00
Kat
6fabf775bb Lots of duplicate word typos + typo. 2026-03-16 09:19:09 +11:00
Jaeseok Lee
86d9a04ece config: add equal option to window-padding-balance
Change `window-padding-balance` from `bool` to an enum with three
values:

- `false` - no balancing (default, unchanged)
- `true` - balance with vshift that caps top padding and shifts excess
  to bottom (existing behavior, unchanged)
- `equal` - balance whitespace equally on all four sides

This gives users who prefer truly equal padding a way to opt in without
changing the default behavior.
2026-03-15 13:50:21 +09:00
Mitchell Hashimoto
86c2a2e87f input: add direct set_surface_title and set_tab_title actions
Fixes #11316

This mirrors the `prompt` actions (hence why there is no window action
here) and enables setting titles via keybind actions which importantly
lets this work via command palettes, App Intents, AppleScript, etc.
2026-03-11 09:25:08 -07:00
Mitchell Hashimoto
04d5efc8eb config: working-directory expands ~/ prefix
Fixes #11336

Introduce a proper WorkingDirectory tagged union type with home, inherit,
and path variants. The field is now an optional (?WorkingDirectory) where
null represents "use platform default" which is resolved during Config.finalize
to .inherit (CLI) or .home (desktop launcher).
2026-03-10 14:33:40 -07:00
Jeffrey C. Ollie
e27956fdde gtk: remove modifications to the core for overrides 2026-03-04 14:04:07 -06:00
Jeffrey C. Ollie
002a6cc765 gtk: use simpler method for passing overrides around
As discussed in Discord, this commit drops the `ConfigOverride` object
in favor of a simpler method of passing the overrides around. Completely
avoiding changes to the core wasn't possible but it's very minimal now.
2026-03-04 14:04:07 -06:00
Jeffrey C. Ollie
6961c2265e gtk: +new-window now respects --working-directory and -e
Fixes: #8862
Fixes: #10716

This adds the machinery to pass configuration settings received over
DBus down to the GObject Surface so that that configuration information
can be used to override some settings from the current "live" config
when creating a new window. Currently it's only possible to override
`--working-directory` and `--command`. `-e` on the `ghostty +new-window`
CLI works as well.

Adding more overridable settings is possible, but being able to fully
override any possible setting would better be served with a major
revamp of how Ghostty handles configs, which I is way out of scope at
the moment.
2026-03-04 14:04:06 -06:00
Mitchell Hashimoto
c8a0092301 fix: calculate cell size before presenting gtk window (#10459)
Fixes #7937

Added `computeInitialSize` to GTK `Surface` and call it in GTK
`Application` before the first `present()`, so the window manager
centers the correct size on initial show.

The issue occurs because the core `Surface.recomputeInitialSize()` runs
only after the renderer is initialized. In GTK, the `GLArea` isn’t
realized until after `present()`, so the initial size arrives too late
for WM centering.

**Limitations**: when we precompute size before `present()` we do not
have access to padding, so the sizing will be very slightly off... but
since it is only off a few pixels I was unable to tell visually that it
wasn't perfectly centered.

**Other thoughts**: I was hesitant to make changes to core `Surface`
because the issue is Linux-specific, but it may make sense to extract a
helper from `recomputeInitialSize` to avoid duplicating the sizing math.

**AI Disclosure:** I used AI to explore the project, help with any
language / API questions (I've never used zig before and rarely use
gtk), and make implementation suggestions.
2026-03-03 08:12:48 -08:00
Mitchell Hashimoto
bb646926f8 config: respect cursor-click-to-move for OSC133 click to move
When cursor-click-to-move is set to false, disable all prompt
click-to-move mechanisms including shell-native methods such as OSC 133
cl= (arrow key synthesis) and click_events. 

I forgot to port this config over when we did the OSC133 stuff.

Also update the config documentation to accurately describe the current
behavior.

Fixes #11138
2026-03-02 20:15:49 -08:00
Caleb Spare
0ccaf3d5d6 Clear key state overlay on "ignore" action 2026-02-28 23:35:28 -08:00
Jeffrey C. Ollie
733d307bf4 gtk: update some comments/function names, take min sizes into account 2026-02-21 10:41:33 -06:00
benodiwal
3d0da44e15 feat(config): allow fullscreen config to specify non-native mode directly
Co-Authored-By: Sachin <sachinbeniwal0101@gmail.com>
2026-02-19 14:34:22 -08:00
Mitchell Hashimoto
eb335fb8dd cleanup by just scrolling in the renderer 2026-02-19 14:06:58 -08:00
benodiwal
263469755c refactor: remove unused stream handler scroll-to-bottom code
The renderer approach doesn't need termio changes.

Co-Authored-By: Sachin <sachinbeniwal0101@gmail.com>
2026-02-19 13:54:32 -08:00
benodiwal
e197b95c32 feat: scroll-to-bottom on output via renderer pin tracking
Co-Authored-By: Sachin <sachinbeniwal0101@gmail.com>
2026-02-19 13:53:27 -08:00
Jeffrey C. Ollie
1342eb5944 gtk: revamp cgroup/transient scope handling
This changes the way Ghostty assigns itself and subprocesses to
cgroups and how resource controls are applied.

* Ghostty itself no longer modifies it's own cgroup or moves itself
to a transient scope. To modify the main Ghostty process' resource
controls ensure that you're launching Ghostty with a systemd unit and
use the standard systemd methods for overriding and applying changes
to systemd units.

* If configured (on by default), the process used to run your command
will be moved to a transient systemd scope after it is forked from
Ghostty but before the user's command is executed. Resource controls
will be applied to the transient scope at this time. Changes to
the `linux-cgroup*` configuration entries will not alter existing
commands. If changes are made to the `linux-cgroup*` configuration
entries commands will need to be relaunched. Resource limits can also
be modified after launch outside of Ghostty using systemd tooling. The
transient scope name can be shown by running `systemctl --user whoami`
in a shell running inside Ghostty.

Fixes #2084.
Related to #6669
2026-02-17 12:54:26 -06:00