Commit Graph

15018 Commits

Author SHA1 Message Date
Anh Thang
e2a01beca7 Merge branch 'main' into vi_VN 2026-03-05 08:56:57 +07:00
Mitchell Hashimoto
46522a8779 gtk: +new-window now respects --working-directory and -e (#10809)
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`, `--command`, and `--title`. `-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 is way out of scope at the moment.
2026-03-04 15:09:58 -08:00
Mitchell Hashimoto
436a11dd59 apprt/gtk: reduce split-tree flicker by reusing leaf widgets (#11170)
Fixes #8208

Split-tree updates currently clear `tree_bin` and then wait for every
surface to become parentless before rebuilding. That leaves the split
area blank for one or more frames, which is the visible flicker during
split create/close/ resize/equalize actions.

Keep the previous widget tree attached until the idle rebuild runs, then
swap in the rebuilt tree in one step. During rebuild, reuse existing
leaf widgets by detaching and reparenting them into the new `GtkPaned`
hierarchy instead of recreating wrappers for every leaf.

This removes the parent-settling rebuild path and avoids transient blank
frames while preserving debounced rebuild behavior.
2026-03-04 15:02:04 -08:00
Mitchell Hashimoto
58d6021ec4 apprt/gtk: reduce split-tree flicker by reusing leaf widgets
Fixes #8208

Split-tree updates currently clear `tree_bin` and then wait for every surface
to become parentless before rebuilding. That leaves the split area blank for
one or more frames, which is the visible flicker during split create/close/
resize/equalize actions.

Keep the previous widget tree attached until the idle rebuild runs, then
swap in the rebuilt tree in one step. During rebuild, reuse existing
leaf widgets by detaching and reparenting them into the new `GtkPaned` 
hierarchy instead of recreating wrappers for every leaf.

This removes the parent-settling rebuild path and avoids transient blank
frames while preserving debounced rebuild behavior.
2026-03-04 14:56:51 -08:00
Jeffrey C. Ollie
5bc5820f32 gtk: simplify new-window action memory management with an arena 2026-03-04 16:01:12 -06:00
Mitchell Hashimoto
2cfc9d36d8 Revert "build: link to the system FontConfig by default (#11169)
This reverts commit ee4c6f88c5.

This breaks standard `zig build run` from a dev shell in Nix/NixOS. I
think we need to rethink some of the protections here, possibly only to
apply to packaging/release modes or something.

cc @jcollie
2026-03-04 13:47:48 -08:00
Mitchell Hashimoto
57d877a0d6 Revert "build: link to the system FontConfig by default on non-macOS systems"
This reverts commit 89f9dd7848.
2026-03-04 13:45:41 -08:00
Mitchell Hashimoto
05807f0d72 Revert "build: link to the system FontConfig by default on non-macOS systems (#11152)"
This reverts commit ee4c6f88c5.
2026-03-04 13:44:05 -08: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
f2ce7c348e gtk: +new-window document --title 2026-03-04 14:04:07 -06:00
Jeffrey C. Ollie
ec0f9ef416 gtk: +new-window now respects --title 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
c3febabd28 apprt: unify split-click focus behavior across macOS and GTK; suppress focus-transfer mouse events (#11167)
## Summary

This PR aligns split-pane click behavior across macOS and GTK when focus
changes due to click.

When a left-click is used to transfer focus (window activation or
switching to another split), Ghostty now treats that click as focus-only
and suppresses forwarding mouse press/release events for that
focus-transfer click.

## Changes

1. macOS: suppress focus-transfer left mouse-down and matching mouse-up
in `SurfaceView_AppKit.swift`.
1. GTK: suppress focus-transfer left mouse-down and matching mouse-up in
`src/apprt/gtk/class/surface.zig`.
1. macOS: defer key-window focus sync to next runloop tick to reduce
transient focus churn in `BaseTerminalController.swift`.
1. macOS build/lint: exclude generated/dependency paths from SwiftLint
during build in `.swiftlint.yml` and
`Ghostty.xcodeproj/project.pbxproj`.

## Behavior

1. Focus-transfer split clicks are now focus-only on both macOS and GTK.
1. Matching release is also suppressed for those clicks, avoiding
release-without-press sequences.
1. Platform behavior is consistent for split focus transitions.

## Validation

1. Built macOS target with `xcodebuild -target Ghostty -configuration
Debug -arch arm64`.
1. Ran targeted Zig test command `zig build test
-Dtest-filter=computeFraction`.
1. Ran format/lint for touched files (`swiftlint lint --fix`, `zig
fmt`).
4. Build and (human) tested click scenarios on macOS

## AI Disclosure

AI-assisted.

Thread:
https://ampcode.com/threads/T-019cb9fe-b11b-753f-99e7-8ecc52b73ec4
2026-03-04 11:11:36 -08:00
Mitchell Hashimoto
226d0b9918 zsh: fix extra newlines with leading-newline prompts (#11166)
In our multiline prompt logic, skip the newline immediately after the
first mark to avoid introducing a double newline due to OSC 133;A's
fresh-line behavior.

Fixes: #11003
2026-03-04 11:09:10 -08:00
Mitchell Hashimoto
3bcf329c2b zsh: emit missing prompt markers in line-init (#11165)
Emit semantic prompt markers at line-init if PS1 doesn't contain our
marks. This ensures the terminal sees prompt markers even if another
plugin (like zinit or oh-my-posh) regenerated PS1 after our precmd ran.
We use 133;P instead of 133;A to avoid fresh-line behavior which would
disrupt the display since the prompt has already been drawn. We also
emit 133;B to mark the input area, which is needed for click-to-move.

Fixes: #10572, #10555
2026-03-04 11:08:58 -08:00
Tim Culverhouse
d1468086ef macos: defer key-window focus sync to reduce churn
Amp-Thread-ID: https://ampcode.com/threads/T-019cb9fe-b11b-753f-99e7-8ecc52b73ec4
Co-authored-by: Amp <amp@ampcode.com>
2026-03-04 12:43:51 -06:00
Tim Culverhouse
0fa12f8915 gtk: suppress mouse reports on focus-transfer clicks
Amp-Thread-ID: https://ampcode.com/threads/T-019cb9fe-b11b-753f-99e7-8ecc52b73ec4
Co-authored-by: Amp <amp@ampcode.com>
2026-03-04 12:43:51 -06:00
Tim Culverhouse
3ee8ef4f65 macos: suppress split-focus click mouse reports
Amp-Thread-ID: https://ampcode.com/threads/T-019cb9fe-b11b-753f-99e7-8ecc52b73ec4
Co-authored-by: Amp <amp@ampcode.com>
2026-03-04 12:43:51 -06:00
Kat
0797b281ec Add Kazakh translation (#10670)
Dear maintainers,

This PR adds Kazakh language translation file and necessary edits to
CODEOWNERS and i18n file with the list of locales.

Please review (and squash when committing)

Thank you!
2026-03-04 18:34:51 +00:00
Jon Parise
9386fa6499 zsh: emit missing prompt markers in line-init
Emit semantic prompt markers at line-init if PS1 doesn't contain our
marks. This ensures the terminal sees prompt markers even if another
plugin (like zinit or oh-my-posh) regenerated PS1 after our precmd ran.
We use 133;P instead of 133;A to avoid fresh-line behavior which would
disrupt the display since the prompt has already been drawn. We also
emit 133;B to mark the input area, which is needed for click-to-move.

Fixes: #10555
2026-03-04 12:48:02 -05:00
Jon Parise
9a3dbe10b0 zsh: fix extra newlines with leading-newline prompts
In our multiline prompt logic, skip the newline immediately after the
first mark to avoid introducing a double newline due to OSC 133;A's
fresh-line behavior.

Fixes: #11003
2026-03-04 12:47:05 -05:00
Baurzhan Muftakhidinov
2772c90885 i18n: add Kazakh translation (kk) 2026-03-04 22:02:37 +05:00
Mitchell Hashimoto
53ef42266a macos: Ghostty.Shell.escape unit tests (#11162)
*AI Disclosure:* These were written using the Claude Agent in Xcode
26.3, partly as an excuse to try out that latest integration.
2026-03-04 08:12:15 -08:00
Jon Parise
a716b9c4d4 macos: Ghostty.Shell.escape unit tests 2026-03-04 11:00:03 -05:00
Mitchell Hashimoto
619e33a4fe macos: implement audio bell support with bell-audio-path (#11154)
## Summary

This extends the macOS bell implementation to support the `audio` bell
feature, bringing it to parity with GTK/Linux.

Previously, macOS only had the `system` feature (`NSSound.beep()`). This
PR adds:

- **`audio` bell feature on macOS**: plays the file at `bell-audio-path`
using `NSSound(contentsOfFile:)`, respecting `bell-audio-volume`
- **`cval()` on the `Path` type**: allows `Path` values (a union type)
to be returned through the C API, which is needed for Swift to read
`bell-audio-path`
- **Removes `(GTK only)` restriction** from `bell-audio-path` and
`bell-audio-volume` documentation

## How it works

In `AppDelegate.swift`, when the bell rings and the `audio` feature is
enabled, Ghostty now:
1. Reads `bell-audio-path` from config
2. Loads it as an `NSSound`
3. Applies `bell-audio-volume` and plays it

Falls back gracefully if the path is not set or the file cannot be
loaded.

## Example config

```
bell-features = audio
bell-audio-path = /System/Library/Sounds/Glass.aiff
bell-audio-volume = 0.8
```

## Testing

- Set `bell-features = audio` and `bell-audio-path` to any valid audio
file
- Trigger a bell with `echo -e '\a'`
- Audio should play at the configured volume
2026-03-03 20:08:04 -08:00
Mitchell Hashimoto
98ad1d955c use proper type for optional path 2026-03-03 19:53:15 -08:00
Anh Thang Bui
4d30d886c6 update translation 2026-03-04 09:39:48 +07:00
Anh Thang Bui
2fe55152ca i18n: add Vietnamese translation 2026-03-04 09:28:12 +07:00
Jeffrey C. Ollie
73ce40c623 build(deps): bump cachix/install-nix-action from 31.9.1 to 31.10.0 (#11157)
Bumps
[cachix/install-nix-action](https://github.com/cachix/install-nix-action)
from 31.9.1 to 31.10.0.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/cachix/install-nix-action/releases">cachix/install-nix-action's
releases</a>.</em></p>
<blockquote>
<h2>v31.10.0</h2>
<h2>What's Changed</h2>
<ul>
<li>nix: 2.33.3 -&gt; 2.34.0 by <a
href="https://github.com/github-actions"><code>@​github-actions</code></a>[bot]
in <a
href="https://redirect.github.com/cachix/install-nix-action/pull/267">cachix/install-nix-action#267</a>
Release notes: <a
href="https://discourse.nixos.org/t/nix-2-34-0-released/75818">https://discourse.nixos.org/t/nix-2-34-0-released/75818</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/cachix/install-nix-action/compare/v31.9.1...v31.10.0">https://github.com/cachix/install-nix-action/compare/v31.9.1...v31.10.0</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="19effe9fe7"><code>19effe9</code></a>
Merge pull request <a
href="https://redirect.github.com/cachix/install-nix-action/issues/267">#267</a>
from cachix/create-pull-request/patch</li>
<li><a
href="d3f3b99dd1"><code>d3f3b99</code></a>
nix: 2.33.3 -&gt; 2.34.0</li>
<li>See full diff in <a
href="2126ae7fc5...19effe9fe7">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=cachix/install-nix-action&package-manager=github_actions&previous-version=31.9.1&new-version=31.10.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>
2026-03-03 20:18:08 -06:00
dependabot[bot]
69df92b56a build(deps): bump cachix/install-nix-action from 31.9.1 to 31.10.0
Bumps [cachix/install-nix-action](https://github.com/cachix/install-nix-action) from 31.9.1 to 31.10.0.
- [Release notes](https://github.com/cachix/install-nix-action/releases)
- [Changelog](https://github.com/cachix/install-nix-action/blob/master/RELEASE.md)
- [Commits](2126ae7fc5...19effe9fe7)

---
updated-dependencies:
- dependency-name: cachix/install-nix-action
  dependency-version: 31.10.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-04 00:15:23 +00:00
ghostty-vouch[bot]
c93cf52108 Update VOUCHED list (#11156)
Triggered by [discussion
comment](https://github.com/ghostty-org/ghostty/discussions/10982#discussioncomment-15990906)
from @jcollie.

Vouch: @cmwetherell

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-03-04 00:06:57 +00:00
Mitchell Hashimoto
4c83872317 macOS: Refine tab title editing (#11150)
- Pass through mouse down event to `TabTitleEditor` if needed
- Pass through right mouse down event to `TabTitleEditor` if needed
- Hide close button when editing tab title

Refactor:
- Use a separated struct to hide and restore tab states


https://github.com/user-attachments/assets/e69838f5-e199-437c-b53b-a491e9d5b752
2026-03-03 14:15:32 -08:00
ghostty-vouch[bot]
0149fd7139 Update VOUCHED list (#11155)
Triggered by
[comment](https://github.com/ghostty-org/ghostty/issues/11154#issuecomment-3993830083)
from @mitchellh.

Vouch: @alaasdk

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-03-03 22:02:49 +00:00
Alaa Ali
b215291914 macos: implement audio bell support with bell-audio-path
Extends the macOS bell implementation to support the `audio` bell
feature by playing a user-specified audio file via NSSound.

Previously, macOS only supported the `system` feature (NSSound.beep()).
This change adds support for:
- `audio` bell feature: plays the file at `bell-audio-path` using
  NSSound, respecting the `bell-audio-volume` setting
- Adds `cval()` to the `Path` type so it can be returned via the C API

Also removes the "(GTK only)" restriction from `bell-audio-path` and
`bell-audio-volume` documentation, as these options now work on macOS.

Example config:
  bell-features = audio
  bell-audio-path = /System/Library/Sounds/Glass.aiff
  bell-audio-volume = 0.8
2026-03-03 23:00:50 +01:00
Mitchell Hashimoto
ee4c6f88c5 build: link to the system FontConfig by default on non-macOS systems (#11152)
Because of the global shared state that FontConfig maintains, FontConfig
must be linked dynamically to the same system FontConfig shared library
that GTK uses. Ghostty's default has been changed to always link to the
system FontConfig library on non-macOS systems. If that is overridden
(by specifying `-fno-sys=fontconfig` during the build) Ghostty may crash
when trying to locate glyphs that are not available in the default font.

Fixes #10432
2026-03-03 12:51:44 -08:00
Jeffrey C. Ollie
89f9dd7848 build: link to the system FontConfig by default on non-macOS systems
Because of the global shared state that FontConfig maintains, FontConfig
must be linked dynamically to the same system FontConfig shared library
that GTK uses. Ghostty's default has been changed to always link to the
system FontConfig library on non-macOS systems. If that is overridden
(by specifying `-fno-sys=fontconfig` during the build) Ghostty may crash
when trying to locate glyphs that are not available in the default font.

Fixes #10432
2026-03-03 14:40:00 -06:00
Mitchell Hashimoto
2d5bb18e29 input: send composed text in kitty keyboard protocol (#11149)
When the kitty keyboard protocol "report all keys as escape codes" mode
was active, composed/IME text (e.g. from dead keys or compose sequences)
was silently dropped.

This happened because the composed text is sent within our GTK apprt
with key=unidentified and no unshifted_codepoint, so no kitty entry was
found and the encoder returned without producing any output. The
plain-text fallback was also skipped because report_all bypasses it.

Send composed text as raw UTF-8 when no kitty entry is found, matching
the behavior of Kitty on Linux for me.

Fixes #10049
2026-03-03 09:04:32 -08:00
Mitchell Hashimoto
fdfc9fea2f input: send composed text in kitty keyboard protocol
When the kitty keyboard protocol "report all keys as escape codes" mode
was active, composed/IME text (e.g. from dead keys or compose sequences)
was silently dropped. 

This happened because the composed text is sent within our GTK apprt
with key=unidentified and no unshifted_codepoint, so no kitty entry was
found and the encoder returned without producing any output. The
plain-text fallback was also skipped because report_all bypasses it.

Send composed text as raw UTF-8 when no kitty entry is found, matching
the behavior of Kitty on Linux for me.

Fixes #10049
2026-03-03 08:57:24 -08:00
Mitchell Hashimoto
562721e6d1 fuzz: add OSC parser fuzzer (#11148)
I'm running this now, 10 minutes with nothing but I figure this is a big
enough target we should also add this.
2026-03-03 08:47:17 -08:00
Lukas
4437707132 macos: use a separated struct to hide and restore tab states 2026-03-03 17:42:17 +01:00
Mitchell Hashimoto
d2175d1b56 fuzz: add OSC parser fuzzer 2026-03-03 08:37:45 -08:00
Lukas
78fdff34a9 macos: hide close button when editing tab title 2026-03-03 17:24:56 +01:00
Lukas
661470897e macos: passthrough right mouse down event to TabTitleEditor if needed 2026-03-03 17:24:56 +01:00
Mitchell Hashimoto
2f0039d419 macos: finish editing tab title when the window resigns as key window (#11147)
This fixes #11146 and also #10993. Updated the comments added in #11052.

> After finishing editing when the window resigns as the key window,
using `labelFrame.minY` is fine with the same usage as #10993, but when
double-clicking with text selected it will move up again 🤷🏻‍♂️.

This makes focus state more accurate with cursor shape on the surface,
when editing the title for a tab in another window group.

[Incorrect
example](https://github.com/user-attachments/assets/c3c4e774-a683-44e7-9bb6-3be79ac72ec2)
2026-03-03 08:17:05 -08:00
Lukas
205c05d59d macos: passthrough mouse down event to TabTitleEditor if needed 2026-03-03 17:15:12 +01: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
Lukas
e6e5f3ffe1 macos: finish editing tab title when the window resigns as key window 2026-03-03 16:34:11 +01:00
Mitchell Hashimoto
cb06b9b001 terminfo: add support for SGR dim (#11144)
This PR implements the fix discussed in
https://github.com/ghostty-org/ghostty/discussions/11128.

Before:

<img width="818" height="96" alt="before"
src="https://github.com/user-attachments/assets/788f981f-3d1b-4c60-bf85-0c297641cae7"
/>

After:

<img width="813" height="93" alt="after"
src="https://github.com/user-attachments/assets/a530015a-053a-4680-9a85-812aa8df3d91"
/>
2026-03-03 07:17:32 -08:00
Riccardo Mazzarini
4ce782b63f terminfo: add support for SGR dim
This PR implements the fix discussed in
https://github.com/ghostty-org/ghostty/discussions/11128
2026-03-03 09:48:48 +01:00