diff options
| author | user <user@clank> | 2026-09-02 15:45:32 +0200 |
|---|---|---|
| committer | user <user@clank> | 2026-09-02 15:45:32 +0200 |
| commit | 311979f10132697b990a670c6c99b19c1c33d623 (patch) | |
| tree | 4d96e1a3c74e1a95594e83d8a175ad47d5d51584 /vendor/libghostty-vt/src/apprt/gtk/class | |
| parent | contrib/vendor-check: watching upstream is one command now (diff) | |
| download | slosh-311979f10132697b990a670c6c99b19c1c33d623.tar.gz slosh-311979f10132697b990a670c6c99b19c1c33d623.tar.xz slosh-311979f10132697b990a670c6c99b19c1c33d623.zip | |
vendor: libghostty-vt bedb6f2 -> 3c1ef5b3 (2026-09-01)
Three weeks of upstream: 504 commits, 120 touching the terminal core
-- OSC 5522, kitty relative placements, C0 fixes, the wuffs pixel
path. Rebuilt from ghostty's own dist step (zig build dist
-Demit-lib-vt=true), zig floor unchanged at 0.16.0, and slosh's C
usage compiled unmodified.
Patch 0001 is re-implemented, not retired: upstream rewrote the area
into ImageStorage.clearScreen but kept the behaviour we patch out --
a terminal clear still reclaims transmitted-but-unplaced images,
which breaks the upload-once place-per-frame pattern the protocol's
two verbs exist for. The patch now removes just that sweep; the
placement clearing and orphan reaping stay upstream's. Their recent
'preserve data on unmatched delete' fixes the same class of bug, so
sending ours upstream remains the way to actually retire it.
Diffstat (limited to 'vendor/libghostty-vt/src/apprt/gtk/class')
3 files changed, 65 insertions, 46 deletions
diff --git a/vendor/libghostty-vt/src/apprt/gtk/class/clipboard_confirmation_dialog.zig b/vendor/libghostty-vt/src/apprt/gtk/class/clipboard_confirmation_dialog.zig index d44d38a..d993b55 100644 --- a/vendor/libghostty-vt/src/apprt/gtk/class/clipboard_confirmation_dialog.zig +++ b/vendor/libghostty-vt/src/apprt/gtk/class/clipboard_confirmation_dialog.zig @@ -193,11 +193,11 @@ pub const ClipboardConfirmationDialog = extern struct { const priv = self.private(); const req = priv.request orelse return; switch (req.*) { - .osc_52_write => { + .osc_52_write, .kitty_write => { self.as(Dialog.Parent).setHeading(i18n._("Authorize Clipboard Access")); self.as(Dialog.Parent).setBody(i18n._("An application is attempting to write to the clipboard. The current clipboard contents are shown below.")); }, - .osc_52_read => { + .osc_52_read, .kitty_read => { self.as(Dialog.Parent).setHeading(i18n._("Authorize Clipboard Access")); self.as(Dialog.Parent).setBody(i18n._("An application is attempting to read from the clipboard. The current clipboard contents are shown below.")); }, @@ -205,6 +205,7 @@ pub const ClipboardConfirmationDialog = extern struct { self.as(Dialog.Parent).setHeading(i18n._("Warning: Potentially Unsafe Paste")); self.as(Dialog.Parent).setBody(i18n._("Pasting this text into the terminal may be dangerous as it looks like some commands may be executed.")); }, + .list => unreachable, } } diff --git a/vendor/libghostty-vt/src/apprt/gtk/class/surface.zig b/vendor/libghostty-vt/src/apprt/gtk/class/surface.zig index b5e8b0b..9d45bc6 100644 --- a/vendor/libghostty-vt/src/apprt/gtk/class/surface.zig +++ b/vendor/libghostty-vt/src/apprt/gtk/class/surface.zig @@ -853,14 +853,24 @@ pub const Surface = extern struct { pub fn bindIsSplit(self: *Self, tree: *SplitTree) void { const priv = self.private(); - if (priv.is_split_binding) |bind| bind.unbind(); + if (priv.is_split_binding) |binding| { + binding.unbind(); + binding.unref(); + priv.is_split_binding = null; + } - priv.is_split_binding = tree.as(gobject.Object).bindProperty( + const binding = tree.as(gobject.Object).bindProperty( "is-split", self.as(gobject.Object), "is-split", .{ .sync_create = true }, ); + // The ref created by bindProperty is owned by the binding itself. + // We need another ref to prevent the binding object from being + // freed if the source object (SplitTree) is finalized. Otherwise + // our pointer to the binding could become stale. + binding.ref(); + priv.is_split_binding = binding; } /// Callback used to determine whether unfocused-split-fill / unfocused-split-opacity @@ -1378,19 +1388,11 @@ pub const Surface = extern struct { if (entry.native == keycode) break :w3c entry.key; } else .unidentified; - // Consult the pre-remapped XKB keyval/keysym to get the (possibly) - // remapped key. If the W3C key or the remapped key - // is eligible for remapping, we use it. - // - // See the docs for `shouldBeRemappable` for why we even have to - // do this in the first place. - if (gtk_key.keyFromKeyval(keyval)) |remapped| { - if (w3c_key.shouldBeRemappable() or remapped.shouldBeRemappable()) - break :keycode remapped; - } - - // Return the original physical key - break :keycode w3c_key; + break :keycode gtk_key.remapKey( + w3c_key, + keyval, + key_event.isModifier() != 0, + ); }; // Get our modifier for the event @@ -1575,7 +1577,11 @@ pub const Surface = extern struct { // https://gitlab.gnome.org/GNOME/libadwaita/-/commit/a7738a4d269bfdf4d8d5429ca73ccdd9b2450421 // https://gitlab.gnome.org/GNOME/libadwaita/-/commit/9759d3fd81129608dd78116001928f2aed974ead if (gtk_xft_dpi <= 0) { - log.warn("gtk-xft-dpi has invalid value ({}), using default", .{gtk_xft_dpi}); + // -1 is a valid value which specifies default scale. + // https://docs.gtk.org/gtk4/property.Settings.gtk-xft-dpi.html + if (gtk_xft_dpi != -1) { + log.warn("gtk-xft-dpi has invalid value ({}), using default", .{gtk_xft_dpi}); + } break :xft_scale 1.0; } @@ -1733,7 +1739,7 @@ pub const Surface = extern struct { self: *Self, clipboard_type: apprt.Clipboard, state: apprt.ClipboardRequest, - ) !bool { + ) !apprt.ClipboardReadResult { return try Clipboard.request( self, clipboard_type, @@ -1889,6 +1895,12 @@ pub const Surface = extern struct { priv.config = null; } + if (priv.is_split_binding) |binding| { + binding.unbind(); + binding.unref(); + priv.is_split_binding = null; + } + if (priv.vadj_signal_group) |group| { group.setTarget(null); group.as(gobject.Object).unref(); @@ -4119,22 +4131,25 @@ const Clipboard = struct { ); } - /// Request data from the clipboard (read the clipboard). This - /// completes asynchronously and will call the `completeClipboardRequest` - /// core surface API when done. - /// - /// Returns true if the request was started, false if the clipboard - /// doesn't contain text (allowing performable keybinds to pass through). + /// Request data from the clipboard (read the clipboard). A started + /// request completes asynchronously and will call the + /// `completeClipboardRequest` core surface API when done. pub fn request( self: *Surface, clipboard_type: apprt.Clipboard, state: apprt.ClipboardRequest, - ) Allocator.Error!bool { + ) Allocator.Error!apprt.ClipboardReadResult { + // The GTK apprt doesn't support the Kitty clipboard protocol + // yet. + if (state == .kitty_read or + state == .kitty_write or + state == .list) return .unsupported; + // Get our requested clipboard const clipboard = get( self.private().gl_area.as(gtk.Widget), clipboard_type, - ) orelse return false; + ) orelse return .unsupported; // For paste requests, check if clipboard has text format available. // This is a synchronous check that allows performable keybinds to @@ -4143,7 +4158,7 @@ const Clipboard = struct { const formats = clipboard.getFormats(); if (formats.containGtype(gobject.ext.types.string) == 0) { log.debug("clipboard has no text format, not starting paste request", .{}); - return false; + return .unavailable; } } @@ -4166,7 +4181,7 @@ const Clipboard = struct { ud, ); - return true; + return .started; } /// Paste explicit text directly into the surface, regardless of the @@ -4179,16 +4194,15 @@ const Clipboard = struct { const surface = self.private().core_surface orelse return; surface.completeClipboardRequest( - .paste, - text, - false, + .{ .paste = .standard }, + .{ .contents = &.{.{ .mime = "text/plain", .data = text }} }, ) catch |err| switch (err) { error.UnsafePaste, error.UnauthorizedPaste, => { showClipboardConfirmation( self, - .paste, + .{ .paste = .standard }, text, ); return; @@ -4232,7 +4246,7 @@ const Clipboard = struct { .request = &req, .@"can-remember" = switch (req) { .osc_52_read, .osc_52_write => true, - .paste => false, + .paste, .list, .kitty_read, .kitty_write => false, }, .@"clipboard-contents" = contents_buf, }, @@ -4269,7 +4283,7 @@ const Clipboard = struct { if (remember) switch (req.*) { .osc_52_read => surface.config.clipboard_read = .allow, .osc_52_write => surface.config.clipboard_write = .allow, - .paste => {}, + .paste, .list, .kitty_read, .kitty_write => {}, }; // Get our text @@ -4286,11 +4300,10 @@ const Clipboard = struct { ?[:0]const u8, ) orelse return; - surface.completeClipboardRequest( - req.*, - text, - true, - ) catch |err| { + surface.completeClipboardRequest(req.*, .{ + .contents = &.{.{ .mime = "text/plain", .data = text }}, + .confirmed = true, + }) catch |err| { log.warn("failed to complete clipboard request: {}", .{err}); }; } @@ -4308,7 +4321,7 @@ const Clipboard = struct { if (remember) switch (req.*) { .osc_52_read => surface.config.clipboard_read = .deny, .osc_52_write => surface.config.clipboard_write = .deny, - .paste => @panic("paste should not be able to be remembered"), + .paste, .list, .kitty_read, .kitty_write => @panic("request should not be able to be remembered"), }; } @@ -4346,8 +4359,7 @@ const Clipboard = struct { const surface = self.private().core_surface orelse return; surface.completeClipboardRequest( req.state, - str, - false, + .{ .contents = &.{.{ .mime = "text/plain", .data = str }} }, ) catch |err| switch (err) { error.UnsafePaste, error.UnauthorizedPaste, diff --git a/vendor/libghostty-vt/src/apprt/gtk/class/surface_scrolled_window.zig b/vendor/libghostty-vt/src/apprt/gtk/class/surface_scrolled_window.zig index 6ccb0a0..ad9a4cc 100644 --- a/vendor/libghostty-vt/src/apprt/gtk/class/surface_scrolled_window.zig +++ b/vendor/libghostty-vt/src/apprt/gtk/class/surface_scrolled_window.zig @@ -89,7 +89,8 @@ pub const SurfaceScrolledWindow = extern struct { const priv = self.private(); if (priv.config_binding) |binding| { - binding.as(gobject.Object).unref(); + binding.unbind(); + binding.unref(); priv.config_binding = null; } @@ -168,18 +169,23 @@ pub const SurfaceScrolledWindow = extern struct { // Unbind old config binding if it exists if (priv.config_binding) |binding| { - binding.as(gobject.Object).unref(); + binding.unbind(); + binding.unref(); priv.config_binding = null; } // Bind config from surface to our config property if (priv.surface) |surface| { - priv.config_binding = surface.as(gobject.Object).bindProperty( + const binding = surface.as(gobject.Object).bindProperty( properties.config.name, self.as(gobject.Object), properties.config.name, .{ .sync_create = true }, ); + // Keep another ref, otherwise the binding would be freed and + // our pointer become stale if the surface gets finalized. + binding.ref(); + priv.config_binding = binding; } } |
