diff --git a/include/ghostty.h b/include/ghostty.h index fbfe3ee2c..86adca7df 100644 --- a/include/ghostty.h +++ b/include/ghostty.h @@ -657,6 +657,14 @@ typedef enum { GHOSTTY_READONLY_ON, } ghostty_action_readonly_e; +// apprt.action.Screenshot +typedef enum { + GHOSTTY_SCREENSHOT_COPY_PATH, + GHOSTTY_SCREENSHOT_PASTE_PATH, + GHOSTTY_SCREENSHOT_OPEN, + GHOSTTY_SCREENSHOT_COPY_IMAGE, +} ghostty_action_screenshot_e; + // apprt.action.DesktopNotification.C typedef struct { const char* title; @@ -948,6 +956,7 @@ typedef enum { GHOSTTY_ACTION_SEARCH_SELECTED, GHOSTTY_ACTION_READONLY, GHOSTTY_ACTION_COPY_TITLE_TO_CLIPBOARD, + GHOSTTY_ACTION_CAPTURE_SCREENSHOT, } ghostty_action_tag_e; typedef union { @@ -989,6 +998,7 @@ typedef union { ghostty_action_search_total_s search_total; ghostty_action_search_selected_s search_selected; ghostty_action_readonly_e readonly; + ghostty_action_screenshot_e screenshot; } ghostty_action_u; typedef struct { diff --git a/src/Surface.zig b/src/Surface.zig index 99c740c89..1dee42571 100644 --- a/src/Surface.zig +++ b/src/Surface.zig @@ -5591,6 +5591,17 @@ pub fn performBindingAction(self: *Surface, action: input.Binding.Action) !bool screen.dirty.selection = true; try self.queueRender(); }, + + .capture_screenshot => |v| return try self.rt_app.performAction( + .{ .surface = self }, + .capture_screenshot, + switch (v) { + .copy_path => .copy_path, + .paste_path => .paste_path, + .open => .open, + .copy_image => .copy_image, + }, + ), } return true; diff --git a/src/apprt/action.zig b/src/apprt/action.zig index f6865af83..56238c28d 100644 --- a/src/apprt/action.zig +++ b/src/apprt/action.zig @@ -343,6 +343,9 @@ pub const Action = union(Key) { /// otherwise the terminal-set title. copy_title_to_clipboard, + /// Capture a screenshot of the surface. + capture_screenshot: Screenshot, + /// Sync with: ghostty_action_tag_e pub const Key = enum(c_int) { quit, @@ -410,6 +413,7 @@ pub const Action = union(Key) { search_selected, readonly, copy_title_to_clipboard, + capture_screenshot, test "ghostty.h Action.Key" { try lib.checkGhosttyHEnum(Key, "GHOSTTY_ACTION_"); @@ -628,6 +632,25 @@ pub const Readonly = enum(c_int) { } }; +pub const Screenshot = enum(c_int) { + /// Take a screenshot of the surface, write the image to a file on disk, and + /// then copy the path to the image file into the clipboard. + copy_path, + /// Take a screenshot of the surface, write the image to a file on disk, and + /// then paste the path to the image file into the surface. + paste_path, + /// Take a screenshot of the surface, write the image to a file on disk, and + /// then open the image file using an OS-specific image viewer. + open, + /// Take a screenshot of the surface and copy the image data into the + /// clipboard. + copy_image, + + test "ghostty.h Screenshot" { + try lib.checkGhosttyHEnum(Screenshot, "GHOSTTY_SCREENSHOT_"); + } +}; + pub const MouseVisibility = enum(c_int) { visible, hidden, diff --git a/src/apprt/gtk/class/application.zig b/src/apprt/gtk/class/application.zig index 107510b43..6ee9df991 100644 --- a/src/apprt/gtk/class/application.zig +++ b/src/apprt/gtk/class/application.zig @@ -784,6 +784,7 @@ pub const Application = extern struct { .check_for_updates, .undo, .redo, + .capture_screenshot, => { log.warn("unimplemented action={}", .{action}); return false; diff --git a/src/input/Binding.zig b/src/input/Binding.zig index d60f2933b..723feb015 100644 --- a/src/input/Binding.zig +++ b/src/input/Binding.zig @@ -943,6 +943,9 @@ pub const Action = union(enum) { /// this will report performable as false. deactivate_all_key_tables, + /// Capture a screenshot of a surface. + capture_screenshot: Screenshot, + /// Quit Ghostty. quit, @@ -1186,6 +1189,21 @@ pub const Action = union(enum) { pub const default: CloseTabMode = .this; }; + pub const Screenshot = enum { + /// Take a screenshot of the surface, write the image to a file on disk, + /// and then copy the path to the image file into the clipboard. + copy_path, + /// Take a screenshot of the surface, write the image to a file on disk, + /// and then paste the path to the image file into the surface. + paste_path, + /// Take a screenshot of the surface, write the image to a file on disk, + /// and then open the image file using an OS-specific image viewer. + open, + /// Take a screenshot of the surface and copy the image data into the + /// clipboard. + copy_image, + }; + fn parseEnum(comptime T: type, value: []const u8) !T { return std.meta.stringToEnum(T, value) orelse return Error.InvalidFormat; } @@ -1406,6 +1424,7 @@ pub const Action = union(enum) { .deactivate_all_key_tables, .end_key_sequence, .crash, + .capture_screenshot, => .surface, // These are less obvious surface actions. They're surface diff --git a/src/input/command.zig b/src/input/command.zig index ac048eec0..9957ef9bb 100644 --- a/src/input/command.zig +++ b/src/input/command.zig @@ -681,6 +681,29 @@ fn actionCommands(action: Action.Key) []const Command { .description = "Put a little Ghostty in your terminal.", }}, + .capture_screenshot => comptime &.{ + .{ + .action = .{ .capture_screenshot = .copy_path }, + .title = "Capture a Screenshot and Copy Path", + .description = "Capture a screenshot of the active surface and copy the path to the image to the clipboard.", + }, + .{ + .action = .{ .capture_screenshot = .paste_path }, + .title = "Capture a Screenshot and Paste Path", + .description = "Capture a screenshot of the active surface and paste the path to the image.", + }, + .{ + .action = .{ .capture_screenshot = .open }, + .title = "Capture a Screenshot and Open", + .description = "Capture a screenshot of the active surface and open the image.", + }, + .{ + .action = .{ .capture_screenshot = .copy_image }, + .title = "Capture a Screenshot and Copy the Image", + .description = "Capture a screenshot of the active surface and copy the image to the clipboard.", + }, + }, + // No commands because they're parameterized and there // aren't obvious values users would use. It is possible that // these may have commands in the future if there are very