mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-08-02 14:57:31 +03:00
apprt/embedded: close surface callback
This commit is contained in:
@ -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 {
|
||||||
|
@ -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 }
|
||||||
|
@ -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() }
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
@ -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 = {} });
|
||||||
},
|
},
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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,
|
||||||
|
@ -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
|
||||||
|
Reference in New Issue
Block a user