This avoids jitter when resizing splits. I didn't see any jitter before
splits but conceptually its possible. The issue is that since we're
updating the overlay DURING A RESIZE, changing the dimensions of any
part of the widget tree causes GTK warnings and a bunch of laggy
updates.
Instead, we copy the label text to a property and update it on the idle
callback along with everything else. This also provides a natural
debounce to the label.
This avoids jitter when resizing splits. I didn't see any jitter before
splits but conceptually its possible. The issue is that since we're
updating the overlay DURING A RESIZE, changing the dimensions of any
part of the widget tree causes GTK warnings and a bunch of laggy
updates.
Instead, we copy the label text to a property and update it on the idle
callback along with everything else. This also provides a natural
debounce to the label.
This also fixes a bug where we were setting custom cursors on the wrong
gtk widget, this showed up most terribly with `mouse-hide-while-typing`
where the mouse would never reappear.
This PR adds a "tabs" title bar style similar to the macOS title bar
style. When `gtk-titlebar-style=tabs` the title bar and the tab bar will
be merged together.
The config entry for controlling this is kept separate from macOS as
macOS has more styles defined that don't map to a GTK title bar style
and it's likely that users that use both macOS and GTK would want
different settings for each platform.
<img width="922" height="722" alt="Screenshot From 2025-08-06 16-38-28"
src="https://github.com/user-attachments/assets/3c2db235-695a-457e-9c96-5039120263fc"
/>
This also fixes a bug where we were setting custom cursors on the wrong
gtk widget, this showed up most terribly with `mouse-hide-while-typing`
where the mouse would never reappear.
This PR adds a "tabs" title bar style similar to the macOS title bar
style. When `gtk-titlebar-style=tabs` the title bar and the tab bar
will be merged together.
The config entry for controlling this is kept separate from macOS as
macOS has more styles defined that don't map to a GTK title bar style
and it's likely that users that use both macOS and GTK would want
different settings for each platform.
We get a ton of leaks from GTK.PopOver when we run the steps given in
the suppression file. I don't see how this could be us since we don't
create or do anything with the popover manually; its simply defined in
the Blueprint file.
The leaks specifically only happen when a Popover shows a sub-menu.
Without that, everything is completely clean. So I actually suspect
there's some leaks in GTK related to this behavior (not sure if they're
on purpose not, a brief look at the code doesn't look like they're
reused).
I tried alternate approaches where we create the Popover AND/OR the
MenuModel in code without the Blueprint file and we get the same leaks.
I'm kind of suspicious about this one but don't see how we can do
anything about it, so I'm going to suppress for now. The suppression
file has detailed repro steps that people can use to hopefully test this
later.
SwiftUI's ImageRenderer must not be called outside the main thread.
The `@MainActor` annotation is only relevant for our own code, not
for calls from frameworks. The machinations around Shortcuts end up
calling the displayRepresentation method outside the main thread.
By capturing the screenshot as NSImage, all data is retained and can
be processed outside the main thread.
Thread in Discord:
https://discord.com/channels/1005603569187160125/1403384231694172372
We get a ton of leaks from GTK.PopOver when we run the steps given in
the suppression file. I don't see how this could be us since we don't
create or do anything with the popover manually; its simply defined in
the Blueprint file.
SwiftUI's ImageRenderer must not be called outside the main thread.
The `@MainActor` annotation is only relevant for our own code, not
for calls from frameworks. The machinations around Shortcuts end up
calling the displayRepresentation method outside the main thread.
By capturing the screenshot as NSImage, all data is retained and can
be processed outside the main thread.
Bumps
[namespacelabs/nscloud-cache-action](https://github.com/namespacelabs/nscloud-cache-action)
from 1.2.15 to 1.2.16.
<details>
<summary>Commits</summary>
<ul>
<li><a
href="305bfa7ea9"><code>305bfa7</code></a>
Merge pull request <a
href="https://redirect.github.com/namespacelabs/nscloud-cache-action/issues/31">#31</a>
from namespacelabs/niklas-new-pnpm</li>
<li><a
href="ca35d05e60"><code>ca35d05</code></a>
Do not touch node_modules in PNPM mode.</li>
<li>See full diff in <a
href="f2d0a9e9ed...305bfa7ea9">compare
view</a></li>
</ul>
</details>
<br />
[](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 merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@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>
This begins to bring back splits to `gtk-ng`. As of this PR, **splits
still don't work**, but the architectural underpinnings for them are all
present. Namely, our tab view now embeds a `GhosttySplitTree` widget
which has a full split tree present, and all the signals and active
surface properties and so on are hooked up to the tree.
In theory, once we hook up split creation, close, etc. everything should
_just work_.
But, this PR is already very large and I don't want to make it even
larger, so I'm opening this PR to add the foundations for this while
keeping `gtk-ng` in the state it more or less is on main right now.
The meat of this is in a pure Zig data structure `SplitTree` added to
`src/datastruct`. This is a Ziggified port of our macOS implementation
(but, much better if I do say so myself). Being in pure Zig lets us
write unit tests easily, control allocations tightly, get our safety
checks, etc. There is coverage in this PR.
## Other Bugs Fixed
- Boxed accessors use the proper `g_boxed_copy/free` functions. Didn't
really cause any issues because this is the first PR where we actually
use custom implementations for that.
- `Surface` properly emits a notify event for focus change
Closes#5372
Discretionary ligatures (denoted by the OpenType feature tag `dlig`) are
sometimes used by programming fonts (e.g. Iosevka) to provide more
"complex" and uncommon ligatures that may be useful in a programming
context. Unfortunately, this has some nasty side effects with certain
Japanese fallback fonts (#5372) due to perhaps a misaligned
understanding of the OpenType spec[^spec].
The spec details that `dlig` ligatures should only be used to contract
sequences of glyphs together into one glyph, and that it should be used
only for "special effect", **at the user's preference** (emphasis mine).
Indeed, it also suggests that:
> UI suggestion: This feature should be off by default.
All of this, combined with the fact that historical, nowadays unused and
even unintelligible Kanji ligatures are explicitly included as examples
of discretionary ligatures, shows that in the Japanese context at least
that the "level of discretion" is significantly higher than what is
found in programming fonts, where it is more understood to be
"opinionated and uncommon", rather than "obsolete and unreadable".
Furthermore, it appears that a lot of common programming fonts don't
even make use of the `dlig` feature — JetBrains Mono, FiraCode and
MonoLisa lack a `dlig` feature altogether, while Inconsolata seems to
only use it for ligatures that are more commonly found in `liga` or
`calt`, such as the `->` ligature. To a lot of people, then, this change
would literally alter nothing.
Therefore, it's my opinion that we should disable `dlig` by default.
It's arguably not being used correctly in the programming font space (or
at least not in a way that's coherent with other fonts), and it only
provides a marginal benefit while potentially rendering entire sentences
in Japanese (and possibly other languages) unreadable out of the box.
If someone upgrades to tip or 1.2 and then asks "why aren't the
ligatures working anymore", then at least they can always just turn on
`dlig` by themselves.
[^spec]:
https://learn.microsoft.com/en-us/typography/opentype/spec/features_ae#tag-dlig