Implements the behavior from #9788.
Today, middle-click paste always reads from the selection clipboard (or
the
system clipboard on platforms without a selection clipboard). With this
change
it follows `copy-on-select`:
- `true`: selection clipboard (unchanged)
- `clipboard`: system clipboard
- `false`: selection clipboard (also unchanged, preserves traditional
X11
middle-click behavior)
The idea is symmetry: if `copy-on-select = clipboard` writes selections
to the
system clipboard, middle-click should come back from there too.
Also updated the config doc comment, which previously claimed
middle-click
"will always use the selection clipboard".
### Testing
`zig build test` passes locally (macOS, Zig 0.15.2).
Built and runtime-tested via the fork's CI:
https://github.com/007hacky007/ghostty/actions/runs/24707475544 - I'm
running the resulting binary daily and the three `copy-on-select` modes
behave as described above.
Due to a known Gtk issue, the scrolled_window at the root of the
template is free-ed twice on dispose. This causes crashes when used with
GNOME 49 platform (Gtk 4.20, libadwaita 1.8.5).
Workaround this issue by wrapping the root child in another Adw.Bin,
similar to widgets like ResizeOverlay.
LLM was used to perform discovery against a manually recorded Valgrind
trace, and helped tracking down known fixes for this problem. The
comment in code was taken from another instance in the repository.
Fixes https://github.com/ghostty-org/ghostty/discussions/12306
Assisted-by: OpenAI GPT-5.4
Due to a known Gtk issue, the scrolled_window at the root of the
template is free-ed twice on dispose. This causes crashes when used with
GNOME 49 platform (Gtk 4.20, libadwaita 1.8.5).
Workaround this issue by wrapping the root child in another Adw.Bin,
similar to widgets like ResizeOverlay.
LLM was used to perform discovery against a manually recorded Valgrind
trace, and helped tracking down known fixes for this problem.
Fixes https://github.com/ghostty-org/ghostty/discussions/12306
Assisted-by: OpenAI GPT-5.4
Previously `ghostty_app_key_is_binding` (unlike Surface) is just using
`config.keybind` to check whether a KeyEvent is in the set or not.
After this, I can add unit tests for keybinding more easily with dummy
configs.
I didn't find any usages of this in GTK, so it shouldn't affect
anything. ci will see if this is the case:)
This fixes a hardcoded build issue on macOS where Zig unconditionally
forces xcodebuild -create-xcframework to run during compilation, even
when the caller explicitly specifies that they only want the raw
standard C objects/headers (-Demit-lib-vt).
This fixes a hardcoded build issue on macOS where Zig unconditionally forces xcodebuild -create-xcframework to run during compilation, even when the caller explicitly specifies that they only want the raw standard C objects/headers (-Demit-lib-vt).
The Bug:
Around line 155 in build.zig, the libghostty-vt xcframework was being packaged unconditionally for Darwin builds. This caused developers (and wrappers like go-libghostty) attempting to natively build the vt library locally using only the minimal macOS Command Line Tools to experience an immediate crash, as xcodebuild -create-xcframework strictly demands a full Xcode application installation.
The Fix:
Guarded the GhosttyLibVt xcframework creation step with config.emit_xcframework. Because src/build/Config.zig intuitively forces emit_xcframework to default to false whenever emit_lib_vt is invoked, this structurally allows lightweight macOS builds to safely skip the xcodebuild invocation while still correctly compiling the standard .a object library files.
This allows libghostty-vt to be cross-compiled for macOS from non-macOS
platforms. I've updated pkg/apple-sdk to fallback to Zig's embedded
macOS headers if the macOS SDK is not found. Additionally,
CombineArchivesStep has been updated to use Linux tooling on Linux. CI
updated to test this.
This allows libghostty-vt to be cross-compiled for macOS from non-macOS
platforms. I've updated pkg/apple-sdk to fallback to Zig's embedded
macOS headers if the macOS SDK is not found.
Additionally, CombineArchivesStep has been updated to use Linux
tooling on Linux.
Previously `ghostty_app_key_is_binding` (unlike Surface) is just using `config.keybind` to check whether a KeyEvent is in the set or not.
After this, I can add unit tests for keybinding more easily, with dummy configs.
Extract the tight per-byte parsing loop from TerminalParser.step into
a separate noinline function (parseAll). This eliminates a ~20%
benchmark regression that appeared after the highway vendor changes
despite zero changes to the parser source code.
The root cause: the parser benchmark processes 50 MB of input through
a byte-at-a-time DFA loop that is highly sensitive to instruction
cache-line placement on Apple Silicon. The M-series cores fetch
aligned 16-byte blocks; when the loop head lands near the end of a
64-byte cache line (offset 60), only one instruction fits in the
first fetch versus four when aligned to offset 48. This causes ~29%
more cycles for identical instruction counts.
Previously the loop was inlined into the large step() function, so
any code change anywhere in the binary (like the highway vendor
restructuring) could shift the loop across a cache-line boundary.
By making parseAll noinline, the loop gets its own function placement
that is stable regardless of surrounding code changes.
The previous runtime_detect.zig called std.zig.system.resolveTargetQuery
which pulled in the entire Zig target/CPU model table infrastructure for
every architecture (~4,000 symbols, ~175 KB of data tables, ~130 KB of
code). This bloated the binary by ~500 KB and shifted code layout enough
to cause a measurable icache/branch-predictor regression in unrelated
hot paths like the terminal parser (~20% more cycles for identical
instruction counts).
Replace with minimal, direct CPU feature detection per architecture:
CPUID + XGETBV inline assembly on x86, sysctlbyname on Darwin AArch64,
and getauxval/prctl via std.os.linux (direct syscalls, no libc) on
Linux for AArch64, PPC, S390x, RISC-V, and LoongArch.
Split into per-architecture files under src/detect/ for
maintainability.
This uses a custom fork of `hwy/targtes.cpp` that uses an extern
function written in Zig to use Zig's standard CPU detection to avoid
a dependency on Apple SDK headers.
This is on the path to removing Apple SDK requirements to build
libghostty-vt, but will require a lot more work outside of this. The goal
is to get this out of our external dependencies first and then we can
work on removing the internal side.
Adds a FreeType-based `Discover` implementation for Windows. It walks
the system font directory (`%SYSTEMROOT%\Fonts`) and the per-user
directory (`%LOCALAPPDATA%\Microsoft\Windows\Fonts`), matches
descriptors by FreeType `family_name` (falling back to the SFNT name
table), and, when a codepoint is in the descriptor, filters on CMap
coverage.
Wired up as a new `.freetype_windows` backend which `Backend.default()`
now returns on Windows. Existing freetype-only paths are untouched and
no other platform is affected; cross-platform switches were extended to
handle the new enum value the same way they handle `.freetype`.
With this in place, the standard code paths (`+list-fonts`,
`SharedGridSet` font-family lookup, `CodepointResolver` fallback) work
on Windows without any `os.tag == .windows` branches in the caller.
Verified by the `build-libghostty-windows-gnu` CI job. No runtime binary
ships yet on Windows (no apprt), but this is a drop-in for the discovery
API that the Win32 apprt (and the revisited `+list-fonts` PR #12384)
will use. Once this lands, #12384 can be closed and `+list-fonts` will
work on Windows through the ordinary discovery code path, which
addresses the review feedback that `+list-fonts` should only show fonts
the internal discovery can find.
---
AI usage disclosure: developed with Claude Code (Claude Opus 4.7).
Claude drafted the implementation based on my design direction -- I
picked the "add a Discover backend" shape over the ad-hoc approach in
the earlier `+list-fonts` PR. I reviewed each diff and validated it with
a Windows GNU-ABI smoke build before pushing.
Part of the Win32 apprt upstreaming series (see discussion #2563 /
mattn/ghostty#1).
This code was motivated by the need for the glyph protocol handler
(#12352) to be able to validate the provided `glyf` payload, without
having to link freetype or anything (because libghostty-vt needs to be
static). As such it's written specifically to meet those needs, but in
such a way that it can be expanded if we find a need for more in-depth
inspection of `glyf`s in the future.