From afc6a9976f2f8c794a8e979c2091124210db4b29 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Wed, 9 Aug 2023 14:29:39 -0700 Subject: [PATCH] apprt/embedded: support selection clipboard --- include/ghostty.h | 9 +++++++-- macos/Sources/Ghostty/AppState.swift | 14 ++++++++++---- src/apprt/embedded.zig | 26 ++++++++++++++++++++------ src/apprt/glfw.zig | 2 +- 4 files changed, 38 insertions(+), 13 deletions(-) diff --git a/include/ghostty.h b/include/ghostty.h index 5b75ea1ad..da767c37f 100644 --- a/include/ghostty.h +++ b/include/ghostty.h @@ -29,6 +29,11 @@ typedef void *ghostty_config_t; typedef void *ghostty_surface_t; // Enums are up top so we can reference them later. +typedef enum { + GHOSTTY_CLIPBOARD_STANDARD, + GHOSTTY_CLIPBOARD_SELECTION, +} ghostty_clipboard_e; + typedef enum { GHOSTTY_SPLIT_RIGHT, GHOSTTY_SPLIT_DOWN @@ -238,8 +243,8 @@ typedef struct { typedef void (*ghostty_runtime_wakeup_cb)(void *); typedef const ghostty_config_t (*ghostty_runtime_reload_config_cb)(void *); typedef void (*ghostty_runtime_set_title_cb)(void *, const char *); -typedef const char* (*ghostty_runtime_read_clipboard_cb)(void *); -typedef void (*ghostty_runtime_write_clipboard_cb)(void *, const char *); +typedef const char* (*ghostty_runtime_read_clipboard_cb)(void *, ghostty_clipboard_e); +typedef void (*ghostty_runtime_write_clipboard_cb)(void *, const char *, ghostty_clipboard_e); typedef void (*ghostty_runtime_new_split_cb)(void *, ghostty_split_direction_e); typedef void (*ghostty_runtime_close_surface_cb)(void *, bool); typedef void (*ghostty_runtime_focus_split_cb)(void *, ghostty_split_focus_direction_e); diff --git a/macos/Sources/Ghostty/AppState.swift b/macos/Sources/Ghostty/AppState.swift index 4f5a1358d..3d15c3bc5 100644 --- a/macos/Sources/Ghostty/AppState.swift +++ b/macos/Sources/Ghostty/AppState.swift @@ -57,8 +57,8 @@ extension Ghostty { wakeup_cb: { userdata in AppState.wakeup(userdata) }, reload_config_cb: { userdata in AppState.reloadConfig(userdata) }, set_title_cb: { userdata, title in AppState.setTitle(userdata, title: title) }, - read_clipboard_cb: { userdata in AppState.readClipboard(userdata) }, - write_clipboard_cb: { userdata, str in AppState.writeClipboard(userdata, string: str) }, + read_clipboard_cb: { userdata, loc in AppState.readClipboard(userdata, location: loc) }, + write_clipboard_cb: { userdata, str, loc in AppState.writeClipboard(userdata, string: str, location: loc) }, new_split_cb: { userdata, direction in AppState.newSplit(userdata, direction: direction) }, close_surface_cb: { userdata, processAlive in AppState.closeSurface(userdata, processAlive: processAlive) }, focus_split_cb: { userdata, direction in AppState.focusSplit(userdata, direction: direction) }, @@ -170,7 +170,10 @@ extension Ghostty { ) } - static func readClipboard(_ userdata: UnsafeMutableRawPointer?) -> UnsafePointer? { + static func readClipboard(_ userdata: UnsafeMutableRawPointer?, location: ghostty_clipboard_e) -> UnsafePointer? { + // We only support the standard clipboard + if (location != GHOSTTY_CLIPBOARD_STANDARD) { return nil } + guard let appState = self.appState(fromSurface: userdata) else { return nil } guard let str = NSPasteboard.general.string(forType: .string) else { return nil } @@ -180,7 +183,10 @@ extension Ghostty { return (str as NSString).utf8String } - static func writeClipboard(_ userdata: UnsafeMutableRawPointer?, string: UnsafePointer?) { + static func writeClipboard(_ userdata: UnsafeMutableRawPointer?, string: UnsafePointer?, location: ghostty_clipboard_e) { + // We only support the standard clipboard + if (location != GHOSTTY_CLIPBOARD_STANDARD) { return } + guard let valueStr = String(cString: string!, encoding: .utf8) else { return } let pb = NSPasteboard.general pb.declareTypes([.string], owner: nil) diff --git a/src/apprt/embedded.zig b/src/apprt/embedded.zig index 5c4c7bbc5..fe9016ab6 100644 --- a/src/apprt/embedded.zig +++ b/src/apprt/embedded.zig @@ -47,10 +47,10 @@ pub const App = struct { /// Read the clipboard value. The return value must be preserved /// by the host until the next call. If there is no valid clipboard /// value then this should return null. - read_clipboard: *const fn (SurfaceUD) callconv(.C) ?[*:0]const u8, + read_clipboard: *const fn (SurfaceUD, c_int) callconv(.C) ?[*:0]const u8, /// Write the clipboard value. - write_clipboard: *const fn (SurfaceUD, [*:0]const u8) callconv(.C) void, + write_clipboard: *const fn (SurfaceUD, [*:0]const u8, c_int) callconv(.C) void, /// Create a new split view. If the embedder doesn't support split /// views then this can be null. @@ -239,13 +239,27 @@ pub const Surface = struct { ); } - pub fn getClipboardString(self: *const Surface) ![:0]const u8 { - const ptr = self.app.opts.read_clipboard(self.opts.userdata) orelse return ""; + pub fn getClipboardString( + self: *const Surface, + clipboard_type: apprt.Clipboard, + ) ![:0]const u8 { + const ptr = self.app.opts.read_clipboard( + self.opts.userdata, + @intCast(@intFromEnum(clipboard_type)), + ) orelse return ""; return std.mem.sliceTo(ptr, 0); } - pub fn setClipboardString(self: *const Surface, val: [:0]const u8) !void { - self.app.opts.write_clipboard(self.opts.userdata, val.ptr); + pub fn setClipboardString( + self: *const Surface, + val: [:0]const u8, + clipboard_type: apprt.Clipboard, + ) !void { + self.app.opts.write_clipboard( + self.opts.userdata, + val.ptr, + @intCast(@intFromEnum(clipboard_type)), + ); } pub fn setShouldClose(self: *Surface) void { diff --git a/src/apprt/glfw.zig b/src/apprt/glfw.zig index 6705dc7e2..625355cae 100644 --- a/src/apprt/glfw.zig +++ b/src/apprt/glfw.zig @@ -526,7 +526,7 @@ pub const Surface = struct { .standard => glfw.setClipboardString(val), .selection => { // Not supported except on Linux - if (comptime builtin.os.tag != .linux) return ""; + if (comptime builtin.os.tag != .linux) return; glfwNative.setX11SelectionString(val.ptr); }, }