From f3996ff0f872938038729574e565aa5100d374a6 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Wed, 9 Aug 2023 13:41:22 -0700 Subject: [PATCH] apprt: primary clipboard awareness (selection clipboard) --- src/Surface.zig | 16 ++++++++-------- src/apprt/gtk.zig | 24 ++++++++++++++++++------ src/apprt/structs.zig | 8 ++++++++ src/termio/Exec.zig | 2 +- 4 files changed, 35 insertions(+), 15 deletions(-) diff --git a/src/Surface.zig b/src/Surface.zig index ddbc050e6..fc90c96e3 100644 --- a/src/Surface.zig +++ b/src/Surface.zig @@ -601,11 +601,11 @@ pub fn handleMessage(self: *Surface, msg: Message) !void { .clipboard_read => |kind| try self.clipboardRead(kind), .clipboard_write => |req| switch (req) { - .small => |v| try self.clipboardWrite(v.data[0..v.len]), - .stable => |v| try self.clipboardWrite(v), + .small => |v| try self.clipboardWrite(v.data[0..v.len], .standard), + .stable => |v| try self.clipboardWrite(v, .standard), .alloc => |v| { defer v.alloc.free(v.data); - try self.clipboardWrite(v.data); + try self.clipboardWrite(v.data, .standard); }, }, @@ -725,7 +725,7 @@ fn clipboardRead(self: *const Surface, kind: u8) !void { return; } - const data = self.rt_surface.getClipboardString() catch |err| { + const data = self.rt_surface.getClipboardString(.standard) catch |err| { log.warn("error reading clipboard: {}", .{err}); return; }; @@ -755,7 +755,7 @@ fn clipboardRead(self: *const Surface, kind: u8) !void { self.io_thread.wakeup.notify() catch {}; } -fn clipboardWrite(self: *const Surface, data: []const u8) !void { +fn clipboardWrite(self: *const Surface, data: []const u8, loc: apprt.Clipboard) !void { if (!self.config.clipboard_write) { log.info("application attempted to write clipboard, but 'clipboard-write' setting is off", .{}); return; @@ -773,7 +773,7 @@ fn clipboardWrite(self: *const Surface, data: []const u8) !void { try dec.decode(buf, data); assert(buf[buf.len] == 0); - self.rt_surface.setClipboardString(buf) catch |err| { + self.rt_surface.setClipboardString(buf, loc) catch |err| { log.err("error setting clipboard string err={}", .{err}); return; }; @@ -1972,7 +1972,7 @@ pub fn performBindingAction(self: *Surface, action: input.Binding.Action) !void }; defer self.alloc.free(buf); - self.rt_surface.setClipboardString(buf) catch |err| { + self.rt_surface.setClipboardString(buf, .standard) catch |err| { log.err("error setting clipboard string err={}", .{err}); return; }; @@ -1980,7 +1980,7 @@ pub fn performBindingAction(self: *Surface, action: input.Binding.Action) !void }, .paste_from_clipboard => { - const data = self.rt_surface.getClipboardString() catch |err| { + const data = self.rt_surface.getClipboardString(.standard) catch |err| { log.warn("error reading clipboard: {}", .{err}); return; }; diff --git a/src/apprt/gtk.zig b/src/apprt/gtk.zig index 5c1465ac1..e7ea3ca73 100644 --- a/src/apprt/gtk.zig +++ b/src/apprt/gtk.zig @@ -913,9 +913,11 @@ pub const Surface = struct { // )); } - pub fn getClipboardString(self: *Surface) ![:0]const u8 { - const clipboard = c.gtk_widget_get_clipboard(@ptrCast(self.gl_area)); - + pub fn getClipboardString( + self: *Surface, + clipboard_type: apprt.Clipboard, + ) ![:0]const u8 { + const clipboard = getClipboard(@ptrCast(self.gl_area), clipboard_type); const content = c.gdk_clipboard_get_content(clipboard) orelse { // On my machine, this NEVER works, so we fallback to glfw's // implementation... @@ -933,12 +935,22 @@ pub const Surface = struct { return std.mem.sliceTo(ptr, 0); } - pub fn setClipboardString(self: *const Surface, val: [:0]const u8) !void { - const clipboard = c.gtk_widget_get_clipboard(@ptrCast(self.gl_area)); - + pub fn setClipboardString( + self: *const Surface, + val: [:0]const u8, + clipboard_type: apprt.Clipboard, + ) !void { + const clipboard = getClipboard(@ptrCast(self.gl_area), clipboard_type); c.gdk_clipboard_set_text(clipboard, val.ptr); } + fn getClipboard(widget: *c.GtkWidget, clipboard: apprt.Clipboard) ?*c.GdkClipboard { + return switch (clipboard) { + .standard => c.gtk_widget_get_clipboard(widget), + .selection => c.gtk_widget_get_primary_clipboard(widget), + }; + } + pub fn getCursorPos(self: *const Surface) !apprt.CursorPos { return self.cursor_pos; } diff --git a/src/apprt/structs.zig b/src/apprt/structs.zig index 9ca2434d4..5e379af71 100644 --- a/src/apprt/structs.zig +++ b/src/apprt/structs.zig @@ -23,3 +23,11 @@ pub const IMEPos = struct { x: f64, y: f64, }; + +/// The clipboard type. +/// +/// If this is changed, you must also update ghostty.h +pub const Clipboard = enum(u1) { + standard = 0, // ctrl+c/v + selection = 1, // also known as the "primary" clipboard +}; diff --git a/src/termio/Exec.zig b/src/termio/Exec.zig index a02428c73..a3d8a45ab 100644 --- a/src/termio/Exec.zig +++ b/src/termio/Exec.zig @@ -1417,7 +1417,7 @@ const StreamHandler = struct { } pub fn clipboardContents(self: *StreamHandler, kind: u8, data: []const u8) !void { - // Note: we ignore the "kind" field and always use the primary clipboard. + // Note: we ignore the "kind" field and always use the standard clipboard. // iTerm also appears to do this but other terminals seem to only allow // certain. Let's investigate more.