Commit Graph

16193 Commits

Author SHA1 Message Date
Mitchell Hashimoto
f5aa271d07 cli: add an ssh-wrapping +ssh action (#12582)
Add a drop-in `ssh` wrapper that sets up the remote environment for
Ghostty. Anything not consumed as one of our own flags is forwarded to
the real, wrapped `ssh` binary. It can be used directly (`ghostty +ssh
user@host`), aliased (`alias ssh='ghostty +ssh --'`), or invoked through
Ghostty's shell integration.

Before exec'ing ssh, `+ssh`:

- Forwards Ghostty environment to the remote (`--forward-env`): sets
TERM=xterm-256color and requests SendEnv forwarding of COLORTERM,
TERM_PROGRAM, and TERM_PROGRAM_VERSION.
- Installs Ghostty's terminfo on the remote (`--terminfo`), informed by
our existing `ssh-cache` system and using our internal xterm-ghostty
terminfo representation.

A third flag, `--cache`, controls cache use; `--cache=false` bypasses
both read and write, which is useful for scripting and for debugging
install failures without polluting the cache.

For shell integration, this replaces the per-shell logic (which made up
roughly a third of our shell integration scripts) with a simple wrapper
function that translates GHOSTTY_SHELL_FEATURES into a `ghostty +ssh`
command line.
2026-05-22 09:04:36 -07:00
Mitchell Hashimoto
a03b52e18b fix: preserve active cursor position during reflow (#12598)
This PR fixes an issue where reflowing could leave the active cursor
attached to a clipped trailing blank cell instead of following the
current write position.
2026-05-22 09:03:52 -07:00
Mitchell Hashimoto
24d664f0ba fix: apply variation selectors to preceding codepoint (#12596)
This fixes a bug where the variation selectors (VS15 & VS16) were
checked against the first codepoint in a cell instead of the previous
codepoint in the cell's grapheme cluster, causing them to be dropped if
that first codepoint was not a valid base.
2026-05-22 09:02:48 -07:00
Mitchell Hashimoto
b78174a68f macOS: update window appearance for About and ConfigurationErrors (#12601)
<img width="1224" height="696" alt="Xnip2026-05-06_19-13-31"
src="https://github.com/user-attachments/assets/ab090dc0-7c06-4a01-8e7c-5d48ca6ccca3"
/>
2026-05-22 08:58:26 -07:00
Mitchell Hashimoto
7e24f0e0bc macOS: use find pasteboard for search needle (#12712)
Fixes the issue described in #12516.

### What
- Inject an `OSPasteboard` into `SearchState`
- Add `OSPasteboard` extension to normalize working with strings between
UIPasteboard/NSPasteboard
- Add `BackportSelectionTextField` which supports text selection for
MacOS 15/iOS 18 and up.
- Read from the pasteboard when the overlay opens and when the app
becomes active
- Write to the pasteboard when the search needle changes
- Annotate `SearchState` as MainActor. `NSPasteboard` isn't thread safe,
and since `SearchState` is already accessed from the main thread,
MainActor enforces our writes be thread safe
- Add SearchState unit tests

### Why
Consistent with other macOS apps, the Find bar's search needle should
persist when re-opened and should sync to the Find bar in other apps.
For example, see Xcode, Notes, Terminal, and Safari.


https://github.com/user-attachments/assets/b6a55a4a-a52c-45bc-ac38-c9df452c11cb
2026-05-22 08:57:45 -07:00
Mitchell Hashimoto
afe4819920 macOS: Re-enable global keybinds after event tap disable events (#12714)
While testing https://github.com/ghostty-org/ghostty/pull/9857, I
encountered the behavior mentioned below. It's pretty frustrating to
encounter, so I've been actually compiling this fix into my test builds
for last month or so, and the issue has not come back. I exclusively use
the QuickTerminal, so my workflow depends on global keybinds working
reliably.

Issue: https://github.com/ghostty-org/ghostty/issues/12294

The solution includes listening to two events that are fired when a tap
is disabled:
- tapDisabledByTimeout
- tapDisabledByUserInput

When these are fired, we re-enable the tap.

Apple's Docs:
https://developer.apple.com/documentation/coregraphics/cgeventtype?language=swift

Related Discussions:
- https://github.com/ghostty-org/ghostty/discussions/11819
- https://github.com/ghostty-org/ghostty/discussions/12091
2026-05-22 08:56:16 -07:00
Mitchell Hashimoto
52f23fb419 macOS: review windows when quitting (#12742)
Inspired by `Terminal.app` which I think is a nice feature.

First two commits contains some changes in `BaseTerminalController` so
that I can use swift concurrency to review those windows in chain more
easily.



https://github.com/user-attachments/assets/41d92432-4ae0-499e-961a-fc247602f3d7


Works with tabs as well, i forgot to record that.
2026-05-22 08:55:14 -07:00
Mitchell Hashimoto
ec15d0e7db gtk: wire up occlusionCallback for non-focused tabs (#12760)
As discussed in #12745, there has been an outstanding plan to make
rendering behavior for non-focused surfaces consistent across platforms.
This PR does that for Linux/GTK using the same patterns as OSX.

The change in `src/apprt/gtk/class/surface.zig` piggybacks on the
existing `glareaMap` / `glareaUnmap` callbacks (added by `e59e27f8b`) by
also calling a new `updateOcclusion(bool)` helper. If you don't like the
helper, or want the helper lifted up further and used on other paths,
let me know and I can revise.

The changes in `src/renderer/Thread.zig` bail on `renderCallback` when
not visible and then block on `drainMailbox` to complete the "catch up"
before trying to draw again.

I want to note that this is more granular than the original #1512, which
was just focused on the top level window state. I can look at that as
well if you want, but given the complexity around how
`XDG_TOPLEVEL_STATE_SUSPENDED` event is fired, I would want to make sure
we discussed things like transparency and single-instance properly first
(e.g., do we render when behind another transparent window).

## Testing

Here's a summary of what I tested:

Tested on Linux/GTK (Ubuntu 26.04, GTK 4.22.2, libadwaita 1.9.0,
Wayland), built `ReleaseFast`. The patched binary has been daily-driven
for ~24 hours as my primary terminal.

| Test | Workload | Result |
|---|---|---|
| Daily drive | byobu × multiple SSH sessions, Claude Code and Codex
producing sustained streaming output, `top` / `btop` redrawing on 1 s
intervals, frequent tab switching | No observed issues over ~24 hours of
mixed use |
| Bell on hidden tab | `sleep 5 && printf '\a'` in background tab | Bell
+ needs-attention indicator both fire; confirms IO-thread → GTK-signal
path is untouched |
| Search highlight survives hide/show | Open search w/ matches
highlighted in tab B → switch to tab A for ~10 s → switch back |
Highlights restored instantly with no stale state; confirms
deferred-replay path (`updateFrame` on `.visible → true`) works
correctly |
| Selection persistence | Select text in tab B → switch tabs → switch
back | Selection preserved exactly |
| Lifecycle (close-all) | Opened 8 surfaces, closed them one at a time,
then process exit + systemd restart | Zero `glib-CRITICAL`, zero `error
in occlusion callback ...` warnings, clean teardown per `journalctl
--user -u app-com.mitchellh.ghostty` |
| Per-thread CPU during workload | `pidstat -t -p <pid>` 30 s with 1
byobu surface focused, 1 background | Hidden surface's renderer thread
sits at 0.00 % every sample; focused surface's renderer shows ~1 % blips
on byobu status ticks |



## AI usage 

Claude Code (Opus 4.7) helped review my patch and monitor / summarize
the jorunald log and pidstat entries.
2026-05-22 08:54:02 -07:00
Jeffrey C. Ollie
10c6121458 build(deps): bump docker/build-push-action from 7.1.0 to 7.2.0 (#12765)
Bumps
[docker/build-push-action](https://github.com/docker/build-push-action)
from 7.1.0 to 7.2.0.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/docker/build-push-action/releases">docker/build-push-action's
releases</a>.</em></p>
<blockquote>
<h2>v7.2.0</h2>
<ul>
<li>Bump <code>@​actions/core</code> from 3.0.0 to 3.0.1 in <a
href="https://redirect.github.com/docker/build-push-action/pull/1525">docker/build-push-action#1525</a></li>
<li>Bump <code>@​docker/actions-toolkit</code> from 0.87.0 to 0.90.0 in
<a
href="https://redirect.github.com/docker/build-push-action/pull/1517">docker/build-push-action#1517</a></li>
<li>Bump brace-expansion from 2.0.2 to 5.0.6 in <a
href="https://redirect.github.com/docker/build-push-action/pull/1534">docker/build-push-action#1534</a></li>
<li>Bump fast-xml-builder from 1.1.4 to 1.2.0 in <a
href="https://redirect.github.com/docker/build-push-action/pull/1529">docker/build-push-action#1529</a></li>
<li>Bump fast-xml-parser from 5.5.7 to 5.8.0 in <a
href="https://redirect.github.com/docker/build-push-action/pull/1521">docker/build-push-action#1521</a></li>
<li>Bump postcss from 8.5.6 to 8.5.10 in <a
href="https://redirect.github.com/docker/build-push-action/pull/1526">docker/build-push-action#1526</a></li>
<li>Bump tar from 6.2.1 to 7.5.15 in <a
href="https://redirect.github.com/docker/build-push-action/pull/1533">docker/build-push-action#1533</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/docker/build-push-action/compare/v7.1.0...v7.2.0">https://github.com/docker/build-push-action/compare/v7.1.0...v7.2.0</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="f9f3042f7e"><code>f9f3042</code></a>
Merge pull request <a
href="https://redirect.github.com/docker/build-push-action/issues/1517">#1517</a>
from docker/dependabot/npm_and_yarn/docker/actions-t...</li>
<li><a
href="812d5fd921"><code>812d5fd</code></a>
chore: update generated content</li>
<li><a
href="b6f6693076"><code>b6f6693</code></a>
chore(deps): Bump <code>@​docker/actions-toolkit</code> from 0.87.0 to
0.90.0</li>
<li><a
href="c1c626eced"><code>c1c626e</code></a>
Merge pull request <a
href="https://redirect.github.com/docker/build-push-action/issues/1525">#1525</a>
from docker/dependabot/npm_and_yarn/actions/core-3.0.1</li>
<li><a
href="51bb284cd4"><code>51bb284</code></a>
chore: update generated content</li>
<li><a
href="5f7884def8"><code>5f7884d</code></a>
chore(deps): Bump <code>@​actions/core</code> from 3.0.0 to 3.0.1</li>
<li><a
href="e01deff7d9"><code>e01deff</code></a>
Merge pull request <a
href="https://redirect.github.com/docker/build-push-action/issues/1521">#1521</a>
from docker/dependabot/npm_and_yarn/fast-xml-parser-...</li>
<li><a
href="3804d49793"><code>3804d49</code></a>
chore: update generated content</li>
<li><a
href="71e8947aac"><code>71e8947</code></a>
chore(deps): Bump fast-xml-parser from 5.5.7 to 5.8.0</li>
<li><a
href="4925ad24cd"><code>4925ad2</code></a>
Merge pull request <a
href="https://redirect.github.com/docker/build-push-action/issues/1526">#1526</a>
from docker/dependabot/npm_and_yarn/postcss-8.5.10</li>
<li>Additional commits viewable in <a
href="bcafcacb16...f9f3042f7e">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=docker/build-push-action&package-manager=github_actions&previous-version=7.1.0&new-version=7.2.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-05-21 20:02:51 -05:00
dependabot[bot]
cb79efa779 build(deps): bump docker/build-push-action from 7.1.0 to 7.2.0
Bumps [docker/build-push-action](https://github.com/docker/build-push-action) from 7.1.0 to 7.2.0.
- [Release notes](https://github.com/docker/build-push-action/releases)
- [Commits](bcafcacb16...f9f3042f7e)

---
updated-dependencies:
- dependency-name: docker/build-push-action
  dependency-version: 7.2.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-05-22 00:23:23 +00:00
Mike Bommarito
14d9e600ac renderer: skip updateFrame when surface is not visible
renderCallback early-returns while !flags.visible to avoid the
cell rebuild for hidden surfaces (tab switch, minimize, etc.).
The .visible → true mailbox handler now runs updateFrame before
drawFrame so the first frame after re-show isn't stale.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-20 22:50:03 -04:00
Mike Bommarito
88d30bb30a gtk: wire occlusionCallback to GLArea map/unmap
Calls core_surface.occlusionCallback(visible) from the existing
glareaMap/glareaUnmap handlers (added in #12698) so the renderer
thread learns when a surface is off-screen.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-20 22:50:03 -04:00
Mitchell Hashimoto
46d54ed673 vouch: enable auto-locking closed issues (#12752) 2026-05-20 09:38:17 -07:00
trag1c
4f94afdb4b vouch: enable auto-locking closed issues 2026-05-20 18:13:49 +02:00
Ken VanDine
25596541ec snap: export TERMINFO_DIRS so child shells find xterm-ghostty (#12662)
## Summary

When Ghostty is installed via snap on Ubuntu, programs running inside
Ghostty (e.g. `clear`) fail with:

```
terminals database is inaccessible
```

The snap ships terminfo at `${SNAP}/share/terminfo` but the launcher
never exports `TERMINFO_DIRS`, so ncurses in child shells falls back to
the host's system database. On Ubuntu 24.04 (ncurses 6.4) the system
database predates the `xterm-ghostty` entry, so the lookup fails.

This is the same fix as the auto-closed #12303 and resolves #12304.

## Fix

Export `TERMINFO_DIRS` in `snap/local/launcher` so all child processes
can resolve the bundled entry without manual setup.

## Local build (how this PR was verified)

Remix the installed store snap by swapping `app/launcher` with the
patched one:

```sh
sudo unsquashfs -d /tmp/g \
  /var/lib/snapd/snaps/ghostty_$(readlink /snap/ghostty/current).snap
sudo cp snap/local/launcher /tmp/g/app/launcher
sudo mksquashfs /tmp/g /tmp/ghostty-test.snap -comp xz -noappend
sudo snap install --dangerous --classic /tmp/ghostty-test.snap
```

Then launch `/snap/bin/ghostty` and run `clear`.

## Test plan

Verified locally on Ubuntu 24.04 / arm64.

- [x] In default `zsh` / `bash` inside Ghostty, `clear` succeeds.
- [x] `infocmp xterm-ghostty` resolves to
`/snap/ghostty/current/share/terminfo/x/xterm-ghostty`.
- [x] No manual copying of terminfo entries into `~/.terminfo/`
required.

## AI Disclosure

Claude Code was used to investigate the root cause and to draft this
single-line launcher change. The fix is identical to the proposal in the
linked discussion (#12304). I manually verified by remixing the
installed snap with the patched launcher and confirming `clear` and
`infocmp xterm-ghostty` work without manually copying terminfo entries
into `~/.terminfo/` (original workaround shared in the discussion).
2026-05-20 16:57:21 +02:00
Mitchell Hashimoto
86444156b4 build(highway): require apple_sdk for darwin builds (#12725)
Noticed this was removed in another PR, but `apple_sdk` is required to
build libghsotty for the iOS simulator, specifically for the x86 version
(see the error log
[here](https://github.com/elias8/libghostty/actions/runs/26075576793/job/76666498246)).
Figured it'd be better to include the SDK in all darwin builds for
consistency.
2026-05-20 06:07:07 -07:00
ghostty-vouch[bot]
19e20f7664 Update VOUCHED list (#12746)
Triggered by [discussion
comment](https://github.com/ghostty-org/ghostty/discussions/12745#discussioncomment-16984203)
from @jcollie.

Vouch: @mjbommar

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-05-20 03:31:15 +00:00
ghostty-vouch[bot]
9bcb30aa11 Update VOUCHED list (#12744)
Triggered by [discussion
comment](https://github.com/ghostty-org/ghostty/discussions/12743#discussioncomment-16981434)
from @bo2themax.

Vouch: @b0uks

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-05-19 20:36:54 +00:00
Lukas
00a989774e macOS: add review windows when quitting
Inspired by Terminal.app
2026-05-19 20:01:32 +02:00
Lukas
8f9b86afa8 macOS: add confirmCloseAsync to return the actual response 2026-05-19 20:00:10 +02:00
Lukas
7f5c233492 macOS: add windowCanBeClosedWithoutConfirmation without any side effects 2026-05-19 19:56:09 +02:00
Mitchell Hashimoto
8150b5b772 Update iTerm2 colorschemes (#12711)
Upstream release:
https://github.com/mbadolato/iTerm2-Color-Schemes/releases/tag/release-20260511-160054-2671288
2026-05-19 09:11:09 -07:00
Mitchell Hashimoto
5f2f08ebda macOS: check the resource the URL refers to (#12731)
- Fixes https://github.com/ghostty-org/ghostty/issues/12727.
[`NSURL.hasDirectoryPath` doesn't do
this](https://developer.apple.com/documentation/foundation/nsurl/hasdirectorypath).

<img width="977" height="177" alt="image"
src="https://github.com/user-attachments/assets/94f77277-8ef0-4573-8ae1-0e54f810463f"
/>

> We don't need to check this in NewTerminalIntent since AppIntent
already appends `/` to the directory.

- Set error when there is no directory to open with
2026-05-19 09:10:05 -07:00
Lukas
3ac7562791 macOS: set error when there is no directory to open with 2026-05-19 09:58:44 +02:00
Lukas
fdf84ef7ce macOS: check the resource the URL refers to.
Fixes #12727. [`NSURL.hasDirectoryPath` doesn't do this](https://developer.apple.com/documentation/foundation/nsurl/hasdirectorypath).

We don't need to check this in NewTerminalIntent since AppIntent already appends `/` to the directory.
2026-05-19 09:58:44 +02:00
ghostty-vouch[bot]
3706abab0c Update VOUCHED list (#12733)
Triggered by [discussion
comment](https://github.com/ghostty-org/ghostty/discussions/12732#discussioncomment-16966426)
from @jcollie.

Vouch: @rewdy

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-05-18 19:17:07 +00:00
Nolin McFarland
bf716a0c39 feat: add extension to normalize OSPasteboard string interface 2026-05-18 10:12:26 -04:00
Elias Andualem
7c2b29a9f3 build(highway): require apple_sdk for darwin builds 2026-05-18 13:44:34 +08:00
Jeffrey C. Ollie
4b7bf0b20e IPC: add +toggle-quick-terminal command (#12661)
Add `+toggle-quick-terminal` as a first-class IPC action, following the
same pattern as `+new-window`. This provides a proper CLI command
(`ghostty +toggle-quick-terminal`) to toggle the quick terminal on a
running Ghostty instance.

Closes discussion #12618
2026-05-17 21:03:09 -05:00
Jeffrey C. Ollie
cfac861794 split_tree: rescale split ratio when resizing (#12699)
Fixes `SplitTree.resize` not rescaling the split ratio to be relative to
the size of the split. Added a unit test for resizing a nested split.

Previously the new ratio was incorrectly calculated relative to the
entire grid. As a consequence resizing a nested split in the GTK app
would cause unexpected size changes like large jumps. E.g. in the
following recording the window has height ~1000px and the resize was
done using a keybind for `resize_split:up,10`. The change is much larger
than 10 pixels.



https://github.com/user-attachments/assets/ba375ddf-5b2f-45e4-8b12-69021ef2f8a8



Note that even with this fix, resizing by a small amount like 10 pixels
might not work at all (depending on window size and layout), because of
the same bug causing #11193 (see my PR #12698). Initially an inaccurate
split ratio will be set and eventually written back to the split tree
datastructure. That incorrect split ratio will be the same before and
after the small resize, so nothing actually changes in the UI.

The split tree implementation for the macOS app already calculates the
ratios correctly.

AI Disclosure
No AI was used, the bug was discovered and all code written by myself.
2026-05-17 20:20:19 -05:00
Jeffrey C. Ollie
4814aee44e gtk: fix invisible splits and focus being lost (#12698)
Fixes #11193 where terminal surfaces might not appear and focus might be
lost when creating multiple nested splits.

These bugs are caused by GTK initially allocating a tiny width/height to
deeply nested splits. For a split with a tiny size, the split ratio will
be set inaccurately e.g. to 1 which means that the right/bottom child of
the split is invisible. If that child is the terminal surface that
should have the focus, it will lose it. In the current implementation
the split ratio can be set at most once, which means the inaccurate
ratio never gets corrected and a surface (or an entire sub-tree of the
layout) will stay invisible.

The following explains the current implementation and bug in more
detail, it is a bit long, but I hope it will make it easier to review
this PR.

### Current Implementation

A split layout is a tree, in code represented by `datastruct/SplitTree`,
where inner nodes are splits and leafs are terminal surface. A split can
be either horizontal or vertical, and has a ratio that defines how its
space should be divided among the 2 children.
The counterpart in the GTK UI is the `apprt/gtk/class/SplitTree` widget
whose `onRebuild/buildTree` functions build a widget tree that has the
same structure as the `datastruct/SplitTree`. The widget tree consists
of a `SplitTreeSplit` widget for every split and a `Surface` widget for
every terminal surface.

A `SplitTreeSplit` widget wraps a `gtk.Paned` widget, which displays its
two children with a divider in between, either horizontally or
vertically. How much space each child gets is determined by 3
properties. `min_position` is always 0 in our case, `max_position`
corresponds to the width/height (for horizontal/vertical splits) of the
widget and `position` is where the divider should be. So `position` is
equivalent to the width/height of the left/top child and thereby also
determines the width/height of the right/bottom child. `SplitTreeSplit`
listens for changes in the 3 properties. If there is one, the
`propPosition`, `propMinPosition` or `propMaxPosition` function gets
triggered and an idle callback for the `onIdle` function is added.

We need to make sure that the widget tree and the `datastruct/SplitTree`
stay in sync.

If we e.g. create a new split or close a surface, the structure of the
split tree changes. In that case `gtk/class/SplitTree.onRebuild` will
completely rebuild the widget tree (the `Surface` widgets are actually
reused) to match the new tree structure. If we resize a split (i.e.
change the split ratio) via action/keybind, we also completely rebuild
the widget tree.

Additionally we need to make sure that for every
`SplitTreeSplit/gtk.Paned` the `position` divided by `max_position`
matches the ratio of the corresponding split node in our
`datastruct/SplitTree`. There are two ways the current implementation
keeps these ratios in sync, both are handled by the
`SplitTreeSplit.onIdle` function.
1. Initially when the widget tree is built, GTK allocates each widget a
size. Specifically it also sets the `position` and `max_position`
properties of each `gtk.Paned` widget, which will trigger the
`SplitTreeSplit.onIdle` function to run. GTK will not necessarily set
position correctly, it is the task of `onIdle` to make sure that the UI
matches the layout defined by the `datastruct/SplitTree`. `onIdle`
checks if `position/max_position` matches the ratio that the split
should have and if not calls `gtk.Paned.setPosition` to update it. This
can only happen once for each split since `onIdle` checks if the
position was set previously. The idea is that we should only ever need
to set the position once, because `gtk.Paned` will automatically keep
its current ratio whenever its size/`max-position` changes (if the
`setPosition` function has been called before). A size change can happen
e.g. because the entire window was resized or because an ancestor split
changed its split ratio.
2. The user can manually change the ratio between the two children of a
split by dragging the divider between them in the UI. When that happens
the `position` property in `gtk.Paned` changes and eventually the
`SplitTreeSplit.onIdle` function gets called. Since `setPosition` should
have already been called when the widget was initially sized, we should
fall through to the second case and write the current ratio back to the
`datastructure/SplitTree`.

The problem with `SplitTreeSplit.onIdle` is that sometimes the split
ratio cannot be set accurately given the current size of the `gtk.Paned`
widget. Because `onIdle` can only set the position/ratio once, any
previous inaccuracy can never get corrected.

For example with many nested vertical splits, GTK might initially
allocate a `gtk.Paned` widget a height of 1. It will have
`max_position=1` and `position=1`. When `onIdle` runs the current ratio
of `position/max_position = 1` is different from the desired ratio of
e.g. 0.5. But a ratio of 0.5 cannot be set, the position can only be 0
or 1 corresponding to a ratio of 0 or 1. The position will then get set
as 1 and can't be changed later. Even when the split later gets a larger
height, it will keep the ratio of 1 and the bottom child will stay
invisible. When the surface that should be focused initially becomes
invisible it loses focus and the focus will never be restored. That is
exactly what happens in the first screencast in the issue description
(#11193).

Another problem with `onIdle` is that the `setPosition` call in `onIdle`
will trigger another idle callback where the position change is
sometimes wrongly interpreted as a manual update and written back to the
tree. Also sometimes the initial ratio in a `gtk.Paned` can already be
correct, in which case position will not get set. The next manual
position update is then not detected as a manual update.

### Changes

`SplitTreeSplit.onIdle` is now able to set the split position every time
the widget is resized, an inaccurate initial ratio will be corrected. To
be able to distinguish a widget resize from a manual position update by
the user, we keep track of whether `max-position`, `position` or both
properties changed. If only `max-position` or both properties changed,
then the widget was resized. If just `position` changed it is a manual
update. This is kind of hacky but works. To verify I checked the source
code for `gtk.Paned`, see the comment in the code on `onIdle`.

`SplitTreeSplit` no longer listens to changes in `min-position`, that
should always be 0 (because we use the default resize/shrink properties
for `gtk.Paned`) and there is already an assert in `onIdle` that checks
that.

It can still happen that a surface initially gets allocated width/height
0 and loses focus. The only reliable way to detect when we can restore
focus, is to listen to the `map/unmap` signals exposed by `gtk.Widget`.
The `Surface` widget now listens to these signals on its `GlArea` child
(because that is where we want to put focus) and stores the current
state in the new `mapped` property. The `SplitTree` widget listens to
changes in that property: when surfaces become mapped, an idle callback
for the new `onRestoreFocus` function is added, which will check whether
the last focused surface is mapped and if so restore focus to it.

### Other possible solutions

Alternatively we could try to only set the split ratio once the split
has its correct final size, but I think it's hard to detect that
reliably. Or we could try to prevent the splits/surfaces from becoming
invisible in the first place by e.g. setting a minimal widget size. But
then you won't get the exactly correct layout and sometimes you do want
a surface to be tiny or invisible e.g. you can drag the divider in a
split all the way to one side.

The ideal solution would probably be to write a custom version of
`gtk.Paned` where you can provide the desired ratio on widget creation.
Then everything will be sized correctly from the start, focus will not
be lost. In terms of performance it would probably be better as well,
because right now there can be multiple rounds of resizes until every
split/surface has its correct size. I have played around with this a
bit, it is definitely possible. But you would have to implement the
divider widget, logic for layouting, handling gestures and co. That is a
bigger undertaking.

### Testing

Tested by creating/modifying deeply nested layouts, dragging split
dividers and resizing splits via keybind. Checked that ratios are
maintained when the window is resized and tested that it works with
zoom. Tested locally with hyprland and in a VM with KDE.

All the bugs described in the issue should be fixed.

### AI Disclosure

Discovered the bug and wrote all code/comments by myself. Used AI in
researching various internals of GTK.
2026-05-17 20:20:01 -05:00
Jeffrey C. Ollie
22b9df25e6 Fix "Available since"
Co-authored-by: Leah Amelia Chen <github@acc.pluie.me>
2026-05-17 14:42:27 -05:00
Nolin McFarland
ed52160612 feat: support BackportSelectionTextField on iOS 18 2026-05-17 12:33:56 -04:00
Nolin McFarland
69cab3d808 feat: select needle when reading from pasteboard 2026-05-17 11:26:32 -04:00
Jeffrey C. Ollie
e90b7c9fad build(deps): bump actions/create-github-app-token from 3.1.1 to 3.2.0 (#12670)
Bumps
[actions/create-github-app-token](https://github.com/actions/create-github-app-token)
from 3.1.1 to 3.2.0.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/actions/create-github-app-token/releases">actions/create-github-app-token's
releases</a>.</em></p>
<blockquote>
<h2>v3.2.0</h2>
<h2><a
href="https://github.com/actions/create-github-app-token/compare/v3.1.1...v3.2.0">3.2.0</a>
(2026-05-12)</h2>
<h3>Features</h3>
<ul>
<li>add support for enterprise-level GitHub Apps (<a
href="https://redirect.github.com/actions/create-github-app-token/issues/263">#263</a>)
(<a
href="952a2a7073">952a2a7</a>)</li>
<li>support full repository names in <code>repositories</code> input (<a
href="https://redirect.github.com/actions/create-github-app-token/issues/372">#372</a>)
(<a
href="85eb8dd414">85eb8dd</a>)</li>
</ul>
<h3>Bug Fixes</h3>
<ul>
<li><strong>deps:</strong> bump <code>@​actions/core</code> from 3.0.0
to 3.0.1 in the production-dependencies group (<a
href="https://redirect.github.com/actions/create-github-app-token/issues/364">#364</a>)
(<a
href="43e5c345bf">43e5c34</a>)</li>
<li>validate private-key input (<a
href="https://redirect.github.com/actions/create-github-app-token/issues/376">#376</a>)
(<a
href="f24bbd8964">f24bbd8</a>)</li>
</ul>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/actions/create-github-app-token/blob/main/CHANGELOG.md">actions/create-github-app-token's
changelog</a>.</em></p>
<blockquote>
<h1>Changelog</h1>
<h2><a
href="https://github.com/actions/create-github-app-token/compare/v3.1.1...v3.2.0">3.2.0</a>
(2026-05-12)</h2>
<h3>Features</h3>
<ul>
<li>add support for enterprise-level GitHub Apps (<a
href="https://redirect.github.com/actions/create-github-app-token/issues/263">#263</a>)
(<a
href="952a2a7073">952a2a7</a>)</li>
<li>support full repository names in <code>repositories</code> input (<a
href="https://redirect.github.com/actions/create-github-app-token/issues/372">#372</a>)
(<a
href="85eb8dd414">85eb8dd</a>)</li>
</ul>
<h3>Bug Fixes</h3>
<ul>
<li><strong>deps:</strong> bump <code>@​actions/core</code> from 3.0.0
to 3.0.1 in the production-dependencies group (<a
href="https://redirect.github.com/actions/create-github-app-token/issues/364">#364</a>)
(<a
href="43e5c345bf">43e5c34</a>)</li>
<li>validate private-key input (<a
href="https://redirect.github.com/actions/create-github-app-token/issues/376">#376</a>)
(<a
href="f24bbd8964">f24bbd8</a>)</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="bcd2ba4921"><code>bcd2ba4</code></a>
chore(main): release 3.2.0 (<a
href="https://redirect.github.com/actions/create-github-app-token/issues/370">#370</a>)</li>
<li><a
href="f24bbd8964"><code>f24bbd8</code></a>
fix: validate private-key input (<a
href="https://redirect.github.com/actions/create-github-app-token/issues/376">#376</a>)</li>
<li><a
href="363531b6d9"><code>363531b</code></a>
docs: capitalize Git as a proper noun in README (<a
href="https://redirect.github.com/actions/create-github-app-token/issues/374">#374</a>)</li>
<li><a
href="fd2801133e"><code>fd28011</code></a>
docs: update procedure to configure Git (<a
href="https://redirect.github.com/actions/create-github-app-token/issues/287">#287</a>)</li>
<li><a
href="85eb8dd414"><code>85eb8dd</code></a>
feat: support full repository names in <code>repositories</code> input
(<a
href="https://redirect.github.com/actions/create-github-app-token/issues/372">#372</a>)</li>
<li><a
href="c9aabb8372"><code>c9aabb8</code></a>
build(deps-dev): bump yaml from 2.8.3 to 2.8.4 in the
development-dependencie...</li>
<li><a
href="e02e816e55"><code>e02e816</code></a>
build(deps-dev): bump undici from 7.24.6 to 8.2.0 (<a
href="https://redirect.github.com/actions/create-github-app-token/issues/366">#366</a>)</li>
<li><a
href="8d835bfd37"><code>8d835bf</code></a>
build(deps-dev): bump esbuild from 0.27.4 to 0.28.0 in the
development-depend...</li>
<li><a
href="952a2a7073"><code>952a2a7</code></a>
feat: add support for enterprise-level GitHub Apps (<a
href="https://redirect.github.com/actions/create-github-app-token/issues/263">#263</a>)</li>
<li><a
href="43e5c345bf"><code>43e5c34</code></a>
fix(deps): bump <code>@​actions/core</code> from 3.0.0 to 3.0.1 in the
production-dependenc...</li>
<li>Additional commits viewable in <a
href="1b10c78c78...bcd2ba4921">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=actions/create-github-app-token&package-manager=github_actions&previous-version=3.1.1&new-version=3.2.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-05-16 19:42:18 -05:00
mitchellh
aed646139d deps: Update iTerm2 color schemes 2026-05-17 00:33:21 +00:00
Nolin McFarland
8fa42c6ec0 feat: add search state unit tests 2026-05-16 20:05:11 -04:00
Nolin McFarland
59eece9a8e feat: use find pasteboard to store search needle 2026-05-16 19:59:20 -04:00
Lukas
b6c6f7630a macos: opacity-toggle setting persists between tabs in a window and to a newly created window (#11583) 2026-05-17 00:45:24 +02:00
ghostty-vouch[bot]
cf24a4856b Update VOUCHED list (#12707)
Triggered by [discussion
comment](https://github.com/ghostty-org/ghostty/discussions/12625#discussioncomment-16940042)
from @bo2themax.

Unvouch: @backnotprop

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-05-16 12:57:27 +00:00
ghostty-vouch[bot]
42ed74bf8c Update VOUCHED list (#12706)
Triggered by [discussion
comment](https://github.com/ghostty-org/ghostty/discussions/12686#discussioncomment-16940039)
from @bo2themax.

Vouch: @nolinmcfarland

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-05-16 12:56:56 +00:00
ghostty-vouch[bot]
0a3598d7a1 Update VOUCHED list (#12705)
Triggered by [discussion
comment](https://github.com/ghostty-org/ghostty/discussions/12625#discussioncomment-16940011)
from @bo2themax.

Vouch: @backnotprop

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-05-16 12:53:21 +00:00
Daniel Kinzler
9f72eb9d7c added back accidentally deleted empty line 2026-05-15 17:52:48 +02:00
Daniel Kinzler
93d1142ada small formatting changes 2026-05-15 17:20:57 +02:00
Jeffrey C. Ollie
0071971b57 Delete test_align (#12688)
Checked in to make sure that this wasn't added intentionally
🙂

Looks like it snuck in in #11868.
2026-05-14 22:50:26 -05:00
ghostty-vouch[bot]
84ad649128 Update VOUCHED list (#12689)
Triggered by
[comment](https://github.com/ghostty-org/ghostty/issues/12688#issuecomment-4456633108)
from @rhodes-b.

Vouch: @vancluever

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-05-15 03:28:40 +00:00
Chris Marchesi
e9213bb1e7 Delete test_align
Checked in to make sure that this wasn't added intentionally 🙂

Looks like it snuck in in #11868.
2026-05-14 20:27:04 -07:00
Leah Amelia Chen
96848d792e config: clear command-palette-entry like keybind (#12682)
After #1368, `command-palette-entry=` will no longer clear the entries
like the documentation says. Since i couldn't find an existing issue or
discussion about this, I assume no one is actually using it. So I put
1.4.0 here, lemme know if you want to change it to 1.3.2.

> I basically copied the `keybind` parsing code and doc.
2026-05-15 03:27:07 +09:00
Lukas
13ca032b1d config: clear command-palette-entry like keybind
After #1368, `command-palette-entry=` will no longer clear the entries like the documentation says. Since i couldn't find an existing issue or discussion about this, I assume no one is actually using it. So I put 1.4.0 here, lemme know if you want to change it to 1.3.2.

> I basically copied the `keybind` parsing code and doc.
2026-05-14 19:43:08 +02:00
ghostty-vouch[bot]
47382f8dcb Update VOUCHED list (#12680)
Triggered by
[comment](https://github.com/ghostty-org/ghostty/issues/12678#issuecomment-4452472142)
from @trag1c.

Denounce: @zaviro

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-05-14 16:15:46 +00:00