apprt/embedded: new_window can be called without a parent

This commit is contained in:
Mitchell Hashimoto
2024-09-24 17:00:38 -07:00
parent bea24f7725
commit 1b31663865
6 changed files with 45 additions and 22 deletions

View File

@ -78,6 +78,12 @@ class TerminalManager {
window.toggleFullScreen(nil)
}
// If our app isn't active, we make it active. All new_window actions
// force our app to be active.
if !NSApp.isActive {
NSApp.activate(ignoringOtherApps: true)
}
// We're dispatching this async because otherwise the lastCascadePoint doesn't
// take effect. Our best theory is there is some next-event-loop-tick logic
// that Cocoa is doing that we need to be after.

View File

@ -631,7 +631,11 @@ extension Ghostty {
}
static func newWindow(_ userdata: UnsafeMutableRawPointer?, config: ghostty_surface_config_s) {
let surface = self.surfaceUserdata(from: userdata)
let surface: SurfaceView? = if let userdata {
self.surfaceUserdata(from: userdata)
} else {
nil
}
NotificationCenter.default.post(
name: Notification.ghosttyNewWindow,

View File

@ -317,6 +317,7 @@ pub fn performAction(
.unbind => unreachable,
.ignore => {},
.quit => try self.setQuit(),
.new_window => try self.newWindow(rt_app, .{ .parent = null }),
.open_config => try self.openConfig(rt_app),
.reload_config => try self.reloadConfig(rt_app),
.close_all_windows => {

View File

@ -3416,19 +3416,22 @@ fn showMouse(self: *Surface) void {
/// will ever return false. We can expand this in the future if it becomes
/// useful. We did previous/next tab so we could implement #498.
pub fn performBindingAction(self: *Surface, action: input.Binding.Action) !bool {
// Handle app-scoped bindings by sending it to the app.
switch (action.scope()) {
.app => {
try self.app.performAction(
// Forward app-scoped actions to the app. Some app-scoped actions are
// special-cased here because they do some special things when performed
// from the surface.
if (action.scoped(.app)) |app_action| {
switch (app_action) {
.new_window => try self.app.newWindow(
self.rt_app,
.{ .parent = self },
),
else => try self.app.performAction(
self.rt_app,
action.scoped(.app).?,
);
return true;
},
// Surface fallthrough and handle
.surface => {},
),
}
return true;
}
switch (action.scoped(.surface).?) {
@ -3653,8 +3656,6 @@ pub fn performBindingAction(self: *Surface, action: input.Binding.Action) !bool
v,
),
.new_window => try self.app.newWindow(self.rt_app, .{ .parent = self }),
.new_tab => {
if (@hasDecl(apprt.Surface, "newTab")) {
try self.rt_surface.newTab();

View File

@ -86,7 +86,8 @@ pub const App = struct {
/// New tab with options.
new_tab: ?*const fn (SurfaceUD, apprt.Surface.Options) callconv(.C) void = null,
/// New window with options.
/// New window with options. The surface may be null if there is no
/// target surface.
new_window: ?*const fn (SurfaceUD, apprt.Surface.Options) callconv(.C) void = null,
/// Control the inspector visibility
@ -495,14 +496,19 @@ pub const App = struct {
}
pub fn newWindow(self: *App, parent: ?*CoreSurface) !void {
_ = self;
// Right now we only support creating a new window with a parent
// through this code.
// The other case is handled by the embedding runtime.
// If we have a parent, the surface logic handles it.
if (parent) |surface| {
try surface.rt_surface.newWindow();
return;
}
// No parent, call the new window callback.
const func = self.opts.new_window orelse {
log.info("runtime embedder does not support new_window", .{});
return;
};
func(null, .{});
}
};

View File

@ -279,7 +279,8 @@ pub const Action = union(enum) {
/// available values.
write_selection_file: WriteScreenAction,
/// Open a new window.
/// Open a new window. If the application isn't currently focused,
/// this will bring it to the front.
new_window: void,
/// Open a new tab.
@ -562,6 +563,10 @@ pub const Action = union(enum) {
.quit,
=> .app,
// These are app but can be special-cased in a surface context.
.new_window,
=> .app,
// Obviously surface actions.
.csi,
.esc,
@ -593,12 +598,12 @@ pub const Action = union(enum) {
.toggle_window_decorations,
.toggle_secure_input,
.crash,
=> .surface,
// These are less obvious surface actions. They're surface
// actions because they are relevant to the surface they
// come from. For example `new_window` needs to be sourced to
// a surface so inheritance can be done correctly.
.new_window,
.new_tab,
.previous_tab,
.next_tab,