Fixes: #8862Fixes: #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.
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.
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.
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
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.
Fixes: #8862Fixes: #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.
## 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
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
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
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!
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
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
## 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
- 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
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
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
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
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
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
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)
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.