Discussion: https://github.com/ghostty-org/ghostty/discussions/10104
Summary:
When background blur uses macOS glass styles, the titlebar becomes fully
transparent after opening a new tab. This updates the glass effect
view’s top inset during layout so
the glass layer continues to cover the titlebar area.
Root Cause:
The glass effect view’s top constraint is computed once using the theme
frame’s safe-area top inset. On macOS 26, opening a new tab changes the
titlebar height/safe-area,
but the constraint is never refreshed. That leaves an uncovered strip at
the top, which appears fully transparent.
Fix:
Track the glass view’s top constraint and update its constant on layout.
This keeps the glass layer aligned with the current safe-area inset
while avoiding unnecessary
reconfiguration.
Tests:
- Manual: `zig build run`, open a new tab with `background-opacity < 1`
and `background-blur = macos-glass-regular` and confirm titlebar is no
longer fully transparent.
- Note: automated tests not added; UI behavior is hard to exercise in
existing test suite.
Window position question:
Opening a new tab seems to reset the window position / trigger a
maximize-like behavior on my system. Is this intended (feature) or a
bug? I did not change this behavior in this PR.
AI Assistance:
This change was implemented with AI assistance (Codex) and reviewed by
me.
As far as I understand ghostty already integrates with systemd nowadays,
and manages its own scopes/cgroups for the application and all tabs. As
such, explicitly moving launching ghostty into a separate systemd scope
from nautilus no longer seems necessary. In any case the scope created
by the nautilus extension quickly goes away, suggesting that Ghostty
moves its processes out of this scope, and the process tree looks just
the same when spawning ghostty directly.
As far as I understand ghostty integrates with systemd already nowadays,
and manages its own scopes/cgroups for tabs. As such, explicitly moving
launching ghostty into a separate systemd scope from nautilus no longer
seems necessary.
End the currently active key sequence, if any, and flush the keys up to
this point to the terminal, excluding the key that triggered this
action.
For example: `ctrl+w>escape=end_key_sequence` would encode `ctrl+w` to
the terminal and exit the key sequence. Or, more fancy,
`ctrl+w>catch_all=end_key_sequence` would exit the sequence without
encoding whatever key was invalid!
Normally, an invalid sequence will reset the key sequence and flush all
data including the invalid key. This action allows you to flush only the
prior keys, which is useful when you want to bind something like a
control key (`ctrl+w`) but not send additional inputs.
End the currently active key sequence, if any, and flush the
keys up to this point to the terminal, excluding the key that
triggered this action.
For example: `ctrl+w>escape=end_key_sequence` would encode
`ctrl+w` to the terminal and exit the key sequence.
Normally, an invalid sequence will reset the key sequence and
flush all data including the invalid key. This action allows
you to flush only the prior keys, which is useful when you want
to bind something like a control key (`ctrl+w`) but not send
additional inputs.
## Summary
When `paste_from_clipboard` is triggered but the clipboard contains no
text (e.g., an image), the action now returns `false` to indicate it
couldn't be performed. This enables the `performable:` keybind prefix to
work correctly for paste actions.
## Problem
On GTK/Linux, when a user has `keybind = ctrl+v=paste_from_clipboard`
and the clipboard contains an image (not text), pressing Ctrl+V does
nothing. Applications like `opencode` that handle their own clipboard
reading via `wl-paste` never receive the keypress.
## Solution
Make `clipboardRequest` return `bool` to indicate whether the action
could be performed. For paste requests on GTK, synchronously check if
the clipboard contains text formats before starting the async read. When
no text format is available, return `false`.
Users can now use:
```
keybind = performable:ctrl+v=paste_from_clipboard
```
When the clipboard has no text, the keybind is not consumed and Ctrl+V
passes through to the terminal application.
## Changes
- `Surface.startClipboardRequest` now returns `bool`
- `paste_from_clipboard` / `paste_from_selection` actions return the
result
- GTK apprt checks clipboard formats synchronously before async read
- Embedded apprt always returns `true` (can't check synchronously)
## Testing
1. Add `keybind = performable:ctrl+v=paste_from_clipboard` to config
2. Copy an image to clipboard
3. Open an application that handles image paste (e.g., `opencode`)
4. Press Ctrl+V
5. Image pastes successfully (app receives keypress and handles
clipboard itself)
## Disclaimer
Most of the changes is done with Opus 4.5
From #10074
The test comments explain in detail. I also added a new integrity check
to validate this at runtime. All existing tests pass the integrity
check.
Related to #1525
This implements a _Mouse-only_ approach to moving splits. When you hover
near the top of a split, a grab handle now appears that can be used to
drag the split into any other split position.
> [!NOTE]
>
> **This PR only lets you move splits to _other split positions_.** I
will create follow-up issues to track moving a split out into a new tab
or window.
## Demo
https://github.com/user-attachments/assets/fbeeff13-a03c-4e79-b4ba-95537d43c083
## Other Notes
This PR also lays a ton of the groundwork on macOS for surfaces to be
draggable and copyable (pasteboard) _in general_. That isn't used yet
but there might be some interesting ideas here like pasting screenshots
by simply dragging the surface. I don't know!
- Fixes#9991
> Modifying the subview of NSThemeFrame seems "dangerous" and
unpredictable.
- Provides correct `intrinsicContentSize` as previous
`NSHostingView<TerminalView>` did
> Fixes regression caused by #10046
> [!NOTE]
> AI Proofread some of my comments
Following up on my comment here about ripping out the NSScrollPocket
frame change observer in SurfaceScrollView once it's no longer needed:
https://github.com/ghostty-org/ghostty/pull/9446#issuecomment-3505314976
I tested the full macOS {26.0, 26.1, 26.2} times Xcode {26.0, 26.1,
26.2} matrix, and the fix was actually on the macOS side, i.e., the
workaround is always needed on macOS 26.0 and never on macOS 26.1+,
regardless of Xcode version. So if we want to avoid this kludge when
it's not needed, we have to use `#available` predicates rather than
removing the code outright.
I'll let maintainers judge whether the juice is worth the squeeze.
I also looked into the other 26.0-only workaround, pertaining to the
window title in the tabs titlebar, but I found that even though the
behavior with an empty view is OK on 26.1+, a warning about ambiguous
content size is still logged, so I figured this should be left as-is. I
updated the comment accordingly.