From 8a419e5526b1fc69eef06cfae1457b217ae900fe Mon Sep 17 00:00:00 2001 From: cyppe Date: Mon, 29 Dec 2025 09:58:09 +0100 Subject: [PATCH] gtk: pass through keypress when clipboard has no text When paste_from_clipboard is triggered but the clipboard contains no text (e.g., an image), send the raw Ctrl+V keypress to the terminal instead of silently returning. This allows applications to handle their own clipboard reading (e.g., via wl-paste for images on Wayland). --- src/apprt/gtk/class/surface.zig | 34 +++++++++++++++++++++++++++------ 1 file changed, 28 insertions(+), 6 deletions(-) diff --git a/src/apprt/gtk/class/surface.zig b/src/apprt/gtk/class/surface.zig index a14d53c32..965f518c9 100644 --- a/src/apprt/gtk/class/surface.zig +++ b/src/apprt/gtk/class/surface.zig @@ -3814,21 +3814,34 @@ const Clipboard = struct { const self = req.self; defer self.unref(); + const surface = self.private().core_surface orelse return; + var gerr: ?*glib.Error = null; const cstr_ = clipboard.readTextFinish(res, &gerr); + + // If clipboard has no text (error, null, or empty), pass through the + // original keypress so applications can handle their own clipboard + // (e.g., reading images via wl-paste). We send raw Ctrl+V (0x16) + // directly using the text action to bypass bracketed paste encoding. if (gerr) |err| { defer err.free(); - log.warn( - "failed to read clipboard err={s}", - .{err.f_message orelse "(no message)"}, - ); + log.debug("clipboard has no text format: {s}", .{err.f_message orelse "(no message)"}); + passthroughKeypress(surface); return; } - const cstr = cstr_ orelse return; + + const cstr = cstr_ orelse { + passthroughKeypress(surface); + return; + }; defer glib.free(cstr); const str = std.mem.sliceTo(cstr, 0); - const surface = self.private().core_surface orelse return; + if (str.len == 0) { + passthroughKeypress(surface); + return; + } + surface.completeClipboardRequest( req.state, str, @@ -3862,6 +3875,15 @@ const Clipboard = struct { ); } + /// Send raw Ctrl+V (ASCII 22) to the terminal, bypassing paste encoding. + /// This allows applications to handle their own clipboard reading + /// (e.g., for image paste via wl-paste on Wayland). + fn passthroughKeypress(surface: *CoreSurface) void { + _ = surface.performBindingAction(.{ .text = "\\x16" }) catch |err| { + log.warn("error sending passthrough keypress: {}", .{err}); + }; + } + /// The request we send as userdata to the clipboard read. const Request = struct { /// "Self" is reffed so we can't dispose it until the clipboard