apprt/embedded: close surface callback

This commit is contained in:
Mitchell Hashimoto
2023-03-08 15:05:15 -08:00
parent fa9ee0815f
commit 6c857877e8
8 changed files with 46 additions and 5 deletions

View File

@ -31,6 +31,7 @@ typedef void (*ghostty_runtime_set_title_cb)(void *, const char *);
typedef const char* (*ghostty_runtime_read_clipboard_cb)(void *); typedef const char* (*ghostty_runtime_read_clipboard_cb)(void *);
typedef void (*ghostty_runtime_write_clipboard_cb)(void *, const char *); typedef void (*ghostty_runtime_write_clipboard_cb)(void *, const char *);
typedef void (*ghostty_runtime_new_split_cb)(void *, ghostty_split_direction_e); typedef void (*ghostty_runtime_new_split_cb)(void *, ghostty_split_direction_e);
typedef void (*ghostty_runtime_close_surface_cb)(void *);
typedef struct { typedef struct {
void *userdata; void *userdata;
@ -39,6 +40,7 @@ typedef struct {
ghostty_runtime_read_clipboard_cb read_clipboard_cb; ghostty_runtime_read_clipboard_cb read_clipboard_cb;
ghostty_runtime_write_clipboard_cb write_clipboard_cb; ghostty_runtime_write_clipboard_cb write_clipboard_cb;
ghostty_runtime_new_split_cb new_split_cb; ghostty_runtime_new_split_cb new_split_cb;
ghostty_runtime_close_surface_cb close_surface_cb;
} ghostty_runtime_config_s; } ghostty_runtime_config_s;
typedef struct { typedef struct {

View File

@ -57,7 +57,8 @@ extension Ghostty {
set_title_cb: { userdata, title in AppState.setTitle(userdata, title: title) }, set_title_cb: { userdata, title in AppState.setTitle(userdata, title: title) },
read_clipboard_cb: { userdata in AppState.readClipboard(userdata) }, read_clipboard_cb: { userdata in AppState.readClipboard(userdata) },
write_clipboard_cb: { userdata, str in AppState.writeClipboard(userdata, string: str) }, write_clipboard_cb: { userdata, str in AppState.writeClipboard(userdata, string: str) },
new_split_cb: { userdata, direction in AppState.newSplit(userdata, direction: ghostty_split_direction_e(UInt32(direction))) } new_split_cb: { userdata, direction in AppState.newSplit(userdata, direction: ghostty_split_direction_e(UInt32(direction))) },
close_surface_cb: { userdata in AppState.closeSurface(userdata) }
) )
// Create the ghostty app. // Create the ghostty app.
@ -90,6 +91,11 @@ extension Ghostty {
]) ])
} }
static func closeSurface(_ userdata: UnsafeMutableRawPointer?) {
guard let surface = self.surfaceUserdata(from: userdata) else { return }
NotificationCenter.default.post(name: Notification.ghosttyCloseSurface, object: surface)
}
static func readClipboard(_ userdata: UnsafeMutableRawPointer?) -> UnsafePointer<CChar>? { static func readClipboard(_ userdata: UnsafeMutableRawPointer?) -> UnsafePointer<CChar>? {
guard let appState = self.appState(fromSurface: userdata) else { return nil } guard let appState = self.appState(fromSurface: userdata) else { return nil }
guard let str = NSPasteboard.general.string(forType: .string) else { return nil } guard let str = NSPasteboard.general.string(forType: .string) else { return nil }

View File

@ -143,15 +143,23 @@ extension Ghostty {
.onReceive(pub) { onNewSplit(notification: $0) } .onReceive(pub) { onNewSplit(notification: $0) }
case .horizontal: case .horizontal:
SplitView(.horizontal, left: { SplitView(.horizontal, left: {
let pub = NotificationCenter.default.publisher(for: Ghostty.Notification.ghosttyCloseSurface, object: state.topLeft)
TerminalSplitChild(app, topLeft: state.topLeft) TerminalSplitChild(app, topLeft: state.topLeft)
.onReceive(pub) { _ in closeTopLeft() }
}, right: { }, right: {
let pub = NotificationCenter.default.publisher(for: Ghostty.Notification.ghosttyCloseSurface, object: state.bottomRight!)
TerminalSplitChild(app, topLeft: state.bottomRight!) TerminalSplitChild(app, topLeft: state.bottomRight!)
.onReceive(pub) { _ in closeBottomRight() }
}) })
case .vertical: case .vertical:
SplitView(.vertical, left: { SplitView(.vertical, left: {
let pub = NotificationCenter.default.publisher(for: Ghostty.Notification.ghosttyCloseSurface, object: state.topLeft)
TerminalSplitChild(app, topLeft: state.topLeft) TerminalSplitChild(app, topLeft: state.topLeft)
.onReceive(pub) { _ in closeTopLeft() }
}, right: { }, right: {
let pub = NotificationCenter.default.publisher(for: Ghostty.Notification.ghosttyCloseSurface, object: state.bottomRight!)
TerminalSplitChild(app, topLeft: state.bottomRight!) TerminalSplitChild(app, topLeft: state.bottomRight!)
.onReceive(pub) { _ in closeBottomRight() }
}) })
} }
} }

View File

@ -510,6 +510,9 @@ extension Ghostty.Notification {
/// Posted when a new split is requested. The sending object will be the surface that had focus. The /// Posted when a new split is requested. The sending object will be the surface that had focus. The
/// userdata has one key "direction" with the direction to split to. /// userdata has one key "direction" with the direction to split to.
static let ghosttyNewSplit = Notification.Name("com.mitchellh.ghostty.newSplit") static let ghosttyNewSplit = Notification.Name("com.mitchellh.ghostty.newSplit")
/// Close the calling surface.
static let ghosttyCloseSurface = Notification.Name("com.mitchellh.ghostty.closeSurface")
} }
// MARK: Surface Environment Keys // MARK: Surface Environment Keys

View File

@ -946,6 +946,12 @@ pub fn keyCallback(
} else log.warn("runtime doesn't implement newSplit", .{}); } else log.warn("runtime doesn't implement newSplit", .{});
}, },
.close_surface => {
if (@hasDecl(apprt.Surface, "closeSurface")) {
try self.rt_surface.closeSurface();
} else log.warn("runtime doesn't implement closeSurface", .{});
},
.close_window => { .close_window => {
_ = self.app_mailbox.push(.{ .close = self }, .{ .instant = {} }); _ = self.app_mailbox.push(.{ .close = self }, .{ .instant = {} });
}, },

View File

@ -47,7 +47,10 @@ pub const App = struct {
/// Create a new split view. If the embedder doesn't support split /// Create a new split view. If the embedder doesn't support split
/// views then this can be null. /// views then this can be null.
new_split: ?*const fn (SurfaceUD, input.Binding.Action.SplitDirection) callconv(.C) void = null, new_split: ?*const fn (SurfaceUD, input.SplitDirection) callconv(.C) void = null,
/// Close the current surface given by this function.
close_surface: ?*const fn (SurfaceUD) callconv(.C) void = null,
}; };
core_app: *CoreApp, core_app: *CoreApp,
@ -161,6 +164,15 @@ pub const Surface = struct {
func(self.opts.userdata, direction); func(self.opts.userdata, direction);
} }
pub fn closeSurface(self: *const Surface) !void {
const func = self.app.opts.close_surface orelse {
log.info("runtime embedder does not closing a surface", .{});
return;
};
func(self.opts.userdata);
}
pub fn getContentScale(self: *const Surface) !apprt.ContentScale { pub fn getContentScale(self: *const Surface) !apprt.ContentScale {
return self.content_scale; return self.content_scale;
} }

View File

@ -278,8 +278,8 @@ pub const Config = struct {
); );
try result.keybind.set.put( try result.keybind.set.put(
alloc, alloc,
.{ .key = .w, .mods = .{ .super = true } }, .{ .key = .w, .mods = .{ .super = true, .shift = true } },
.{ .close_window = {} }, .{ .close_surface = {} },
); );
try result.keybind.set.put( try result.keybind.set.put(
alloc, alloc,

View File

@ -184,7 +184,11 @@ pub const Action = union(enum) {
/// in the direction given. /// in the direction given.
new_split: SplitDirection, new_split: SplitDirection,
/// Close the current window or tab /// Close the current "surface", whether that is a window, tab, split,
/// etc. This only closes ONE surface.
close_surface: void,
/// Close the window, regardless of how many tabs or splits there may be.
close_window: void, close_window: void,
/// Quit ghostty /// Quit ghostty