Fix mouse interactions in terminal.

This commit is contained in:
Greyson Parrelli
2026-08-13 11:46:48 -04:00
parent 71b3c93521
commit 2daeb6125f
4 changed files with 669 additions and 70 deletions
+9 -53
View File
@@ -1424,10 +1424,17 @@ fn onShortcut(
// Only a terminal needs us to encode a paste for it. A web
// pane has its own clipboard handling, so the key is left
// alone rather than swallowed here.
if (self.focusedTerminal() == null) return 0;
self.paste();
const terminal = self.focusedTerminal() orelse return 0;
terminal.pasteFrom(.standard);
return 1;
},
gdk.KEY_C, gdk.KEY_c => {
// With nothing selected the key is declined rather than
// swallowed, so a web pane's own copy still works and a
// terminal still receives it.
const terminal = self.focusedTerminal() orelse return 0;
return if (terminal.copySelection(.standard)) 1 else 0;
},
else => {},
}
}
@@ -1495,54 +1502,3 @@ fn onShortcut(
return 0;
}
// -------------------------------------------------------------------------
// Paste
//
// GTK4's clipboard API is asynchronous, so the read completes on a later
// main loop turn. We resolve the destination tab at completion time rather
// than capturing it, so closing a tab mid-paste can't leave a dangling
// pointer.
fn paste(self: *Window) void {
const clipboard = self.window.as(gtk.Widget).getClipboard();
clipboard.readTextAsync(null, &onPasteReady, self);
}
fn onPasteReady(
source: ?*gobject.Object,
result: *gio.AsyncResult,
data: ?*anyopaque,
) callconv(.c) void {
const self: *Window = @ptrCast(@alignCast(data.?));
const clipboard: *gdk.Clipboard = @ptrCast(@alignCast(source.?));
var err: ?*glib.Error = null;
const text = clipboard.readTextFinish(result, &err) orelse {
if (err) |e| {
std.log.warn("paste failed: {s}", .{e.f_message orelse "unknown"});
e.free();
}
return;
};
defer glib.free(text);
const terminal = self.focusedTerminal() orelse return;
const session = terminal.session;
// Coerce to a plain slice: encodePaste dispatches on the exact type.
const span: []const u8 = std.mem.span(text);
// Refuse pastes containing control characters that would execute on
// arrival (a newline in unbracketed mode runs the command immediately).
const opts: vt.input.PasteOptions = .fromTerminal(&session.term);
if (!vt.input.isSafePaste(span)) {
std.log.warn("refusing unsafe paste", .{});
return;
}
const parts = vt.input.encodePaste(span, opts) catch |e| {
std.log.warn("paste encode failed: {s}", .{@errorName(e)});
return;
};
for (parts) |part| session.write(part);
}