From 79971c62a622bc9ac730ae6dee7359cc22914ad8 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Fri, 18 Aug 2023 09:09:43 -0700 Subject: [PATCH] macos: pass around a base surface_config_s rather than a new tab --- include/ghostty.h | 11 +++---- .../Features/Primary Window/PrimaryView.swift | 6 ++-- .../Primary Window/PrimaryWindow.swift | 4 +-- .../Primary Window/PrimaryWindowManager.swift | 15 +++++----- macos/Sources/Ghostty/AppState.swift | 8 ++--- macos/Sources/Ghostty/Ghostty.SplitView.swift | 16 +++++----- macos/Sources/Ghostty/Package.swift | 2 +- macos/Sources/Ghostty/SurfaceView.swift | 12 ++++---- src/apprt/embedded.zig | 29 ++++++++++--------- 9 files changed, 51 insertions(+), 52 deletions(-) diff --git a/include/ghostty.h b/include/ghostty.h index d3ac633e4..31d2c7e5b 100644 --- a/include/ghostty.h +++ b/include/ghostty.h @@ -252,17 +252,12 @@ typedef void (*ghostty_runtime_set_title_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_new_tab_cb)(void *, ghostty_surface_config_s); typedef void (*ghostty_runtime_close_surface_cb)(void *, bool); typedef void (*ghostty_runtime_focus_split_cb)(void *, ghostty_split_focus_direction_e); typedef void (*ghostty_runtime_goto_tab_cb)(void *, int32_t); typedef void (*ghostty_runtime_toggle_fullscreen_cb)(void *, bool); -typedef struct { - uint8_t font_size; -} ghostty_new_tab_config_s; - -typedef void (*ghostty_runtime_new_tab_cb)(void *, ghostty_new_tab_config_s); - typedef struct { void *userdata; bool supports_selection_clipboard; @@ -272,11 +267,11 @@ typedef struct { ghostty_runtime_read_clipboard_cb read_clipboard_cb; ghostty_runtime_write_clipboard_cb write_clipboard_cb; ghostty_runtime_new_split_cb new_split_cb; + ghostty_runtime_new_tab_cb new_tab_cb; ghostty_runtime_close_surface_cb close_surface_cb; ghostty_runtime_focus_split_cb focus_split_cb; ghostty_runtime_goto_tab_cb goto_tab_cb; ghostty_runtime_toggle_fullscreen_cb toggle_fullscreen_cb; - ghostty_runtime_new_tab_cb new_tab_cb; } ghostty_runtime_config_s; //------------------------------------------------------------------- @@ -298,6 +293,8 @@ bool ghostty_app_tick(ghostty_app_t); void *ghostty_app_userdata(ghostty_app_t); void ghostty_app_keyboard_changed(ghostty_app_t); +ghostty_surface_config_s ghostty_surface_config_new(); + ghostty_surface_t ghostty_surface_new(ghostty_app_t, ghostty_surface_config_s*); void ghostty_surface_free(ghostty_surface_t); ghostty_app_t ghostty_surface_app(ghostty_surface_t); diff --git a/macos/Sources/Features/Primary Window/PrimaryView.swift b/macos/Sources/Features/Primary Window/PrimaryView.swift index 07bbec947..b62e630b7 100644 --- a/macos/Sources/Features/Primary Window/PrimaryView.swift +++ b/macos/Sources/Features/Primary Window/PrimaryView.swift @@ -11,8 +11,8 @@ struct PrimaryView: View { // We need this to report back up the app controller which surface in this view is focused. let focusedSurfaceWrapper: FocusedSurfaceWrapper - // If this is set, we inherit the fontSize from the parent tab or window. - let fontSize: UInt8? + // If this is set, this is the base configuration that we build our surface out of. + let baseConfig: ghostty_surface_config_s? // We need access to our window to know if we're the key window to determine // if we show the quit confirmation or not. @@ -74,7 +74,7 @@ struct PrimaryView: View { self.appDelegate.confirmQuit = $0 }) - Ghostty.TerminalSplit(onClose: Self.closeWindow, fontSize: self.fontSize) + Ghostty.TerminalSplit(onClose: Self.closeWindow, baseConfig: self.baseConfig) .ghosttyApp(ghostty.app!) .background(WindowAccessor(window: $window)) .onReceive(gotoTab) { onGotoTab(notification: $0) } diff --git a/macos/Sources/Features/Primary Window/PrimaryWindow.swift b/macos/Sources/Features/Primary Window/PrimaryWindow.swift index 1762f29f7..6f6e0ba73 100644 --- a/macos/Sources/Features/Primary Window/PrimaryWindow.swift +++ b/macos/Sources/Features/Primary Window/PrimaryWindow.swift @@ -16,7 +16,7 @@ class FocusedSurfaceWrapper { class PrimaryWindow: NSWindow { var focusedSurfaceWrapper: FocusedSurfaceWrapper = FocusedSurfaceWrapper() - static func create(ghostty: Ghostty.AppState, appDelegate: AppDelegate, fontSize: UInt8? = nil) -> PrimaryWindow { + static func create(ghostty: Ghostty.AppState, appDelegate: AppDelegate, baseConfig: ghostty_surface_config_s? = nil) -> PrimaryWindow { let window = PrimaryWindow( contentRect: NSRect(x: 0, y: 0, width: 800, height: 600), styleMask: [.titled, .closable, .miniaturizable, .resizable], @@ -28,7 +28,7 @@ class PrimaryWindow: NSWindow { ghostty: ghostty, appDelegate: appDelegate, focusedSurfaceWrapper: window.focusedSurfaceWrapper, - fontSize: fontSize + baseConfig: baseConfig )) // We do want to cascade when new windows are created diff --git a/macos/Sources/Features/Primary Window/PrimaryWindowManager.swift b/macos/Sources/Features/Primary Window/PrimaryWindowManager.swift index 4a608704f..987dc86a2 100644 --- a/macos/Sources/Features/Primary Window/PrimaryWindowManager.swift +++ b/macos/Sources/Features/Primary Window/PrimaryWindowManager.swift @@ -1,5 +1,6 @@ import Cocoa import Combine +import GhosttyKit import SwiftUI // PrimaryWindowManager manages the windows and tabs in the primary window @@ -97,22 +98,22 @@ class PrimaryWindowManager { guard let surfaceView = notification.object as? Ghostty.SurfaceView else { return } guard let window = surfaceView.window else { return } - let fontSizeAny = notification.userInfo?[Ghostty.Notification.NewTabKey] - let fontSize = fontSizeAny as? UInt8 + let configAny = notification.userInfo?[Ghostty.Notification.NewTabKey] + let config = configAny as? ghostty_surface_config_s - self.addNewTab(to: window, withFontSize: fontSize) + self.addNewTab(to: window, withBaseConfig: config) } - private func addNewTab(to window: NSWindow, withFontSize fontSize: UInt8? = nil) { - guard let controller = createWindowController(withFontSize: fontSize) else { return } + private func addNewTab(to window: NSWindow, withBaseConfig config: ghostty_surface_config_s? = nil) { + guard let controller = createWindowController(withBaseConfig: config) else { return } guard let newWindow = addManagedWindow(windowController: controller)?.window else { return } window.addTabbedWindow(newWindow, ordered: .above) newWindow.makeKeyAndOrderFront(nil) } - private func createWindowController(withFontSize fontSize: UInt8? = nil) -> PrimaryWindowController? { + private func createWindowController(withBaseConfig config: ghostty_surface_config_s? = nil) -> PrimaryWindowController? { guard let appDelegate = NSApplication.shared.delegate as? AppDelegate else { return nil } - let window = PrimaryWindow.create(ghostty: ghostty, appDelegate: appDelegate, fontSize: fontSize) + let window = PrimaryWindow.create(ghostty: ghostty, appDelegate: appDelegate, baseConfig: config) Self.lastCascadePoint = window.cascadeTopLeft(from: Self.lastCascadePoint) let controller = PrimaryWindowController(window: window) controller.windowManager = self diff --git a/macos/Sources/Ghostty/AppState.swift b/macos/Sources/Ghostty/AppState.swift index 97f8f4743..94ba3ad11 100644 --- a/macos/Sources/Ghostty/AppState.swift +++ b/macos/Sources/Ghostty/AppState.swift @@ -61,11 +61,11 @@ extension Ghostty { 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) }, + new_tab_cb: { userdata, surfaceConfig in AppState.newTab(userdata, config: surfaceConfig) }, close_surface_cb: { userdata, processAlive in AppState.closeSurface(userdata, processAlive: processAlive) }, focus_split_cb: { userdata, direction in AppState.focusSplit(userdata, direction: direction) }, goto_tab_cb: { userdata, n in AppState.gotoTab(userdata, n: n) }, - toggle_fullscreen_cb: { userdata, nonNativeFullscreen in AppState.toggleFullscreen(userdata, useNonNativeFullscreen: nonNativeFullscreen) }, - new_tab_cb: { userdata, newTabConfig in AppState.newTab(userdata, config: newTabConfig) } + toggle_fullscreen_cb: { userdata, nonNativeFullscreen in AppState.toggleFullscreen(userdata, useNonNativeFullscreen: nonNativeFullscreen) } ) // Create the ghostty app. @@ -263,12 +263,12 @@ extension Ghostty { ) } - static func newTab(_ userdata: UnsafeMutableRawPointer?, config: ghostty_new_tab_config_s) { + static func newTab(_ userdata: UnsafeMutableRawPointer?, config: ghostty_surface_config_s) { guard let surface = self.surfaceUserdata(from: userdata) else { return } var userInfo: [AnyHashable : Any] = [:]; if config.font_size != 0 { - userInfo[Notification.NewTabKey] = config.font_size as UInt8; + userInfo[Notification.NewTabKey] = config; } NotificationCenter.default.post( diff --git a/macos/Sources/Ghostty/Ghostty.SplitView.swift b/macos/Sources/Ghostty/Ghostty.SplitView.swift index 9142dd037..a3e224139 100644 --- a/macos/Sources/Ghostty/Ghostty.SplitView.swift +++ b/macos/Sources/Ghostty/Ghostty.SplitView.swift @@ -8,11 +8,11 @@ extension Ghostty { struct TerminalSplit: View { @Environment(\.ghosttyApp) private var app let onClose: (() -> Void)? - let fontSize: UInt8? + let baseConfig: ghostty_surface_config_s? var body: some View { if let app = app { - TerminalSplitRoot(app: app, onClose: onClose, fontSize: fontSize) + TerminalSplitRoot(app: app, onClose: onClose, baseConfig: baseConfig) } } } @@ -68,9 +68,9 @@ extension Ghostty { @Published var surface: SurfaceView /// Initialize a new leaf which creates a new terminal surface. - init(_ app: ghostty_app_t, _ fontSize: UInt8?) { + init(_ app: ghostty_app_t, _ baseConfig: ghostty_surface_config_s?) { self.app = app - self.surface = SurfaceView(app, fontSize) + self.surface = SurfaceView(app, baseConfig) } } @@ -142,14 +142,14 @@ extension Ghostty { @State private var node: SplitNode @State private var requestClose: Bool = false let onClose: (() -> Void)? - let fontSize: UInt8? + let baseConfig: ghostty_surface_config_s? @FocusedValue(\.ghosttySurfaceTitle) private var surfaceTitle: String? - init(app: ghostty_app_t, onClose: (() ->Void)? = nil, fontSize: UInt8? = nil) { + init(app: ghostty_app_t, onClose: (() ->Void)? = nil, baseConfig: ghostty_surface_config_s? = nil) { self.onClose = onClose - self.fontSize = fontSize - _node = State(wrappedValue: SplitNode.noSplit(.init(app, fontSize))) + self.baseConfig = baseConfig + _node = State(wrappedValue: SplitNode.noSplit(.init(app, baseConfig))) } var body: some View { diff --git a/macos/Sources/Ghostty/Package.swift b/macos/Sources/Ghostty/Package.swift index 25a10b8ce..006433c72 100644 --- a/macos/Sources/Ghostty/Package.swift +++ b/macos/Sources/Ghostty/Package.swift @@ -79,7 +79,7 @@ extension Ghostty.Notification { static let ghosttyGotoTab = Notification.Name("com.mitchellh.ghostty.gotoTab") static let GotoTabKey = ghosttyGotoTab.rawValue - /// New tab. Has font size of currently focused surface in the userinfo. + /// New tab. Has base surface config requestesd in userinfo. static let ghosttyNewTab = Notification.Name("com.mitchellh.ghostty.newTab") static let NewTabKey = ghosttyNewTab.rawValue diff --git a/macos/Sources/Ghostty/SurfaceView.swift b/macos/Sources/Ghostty/SurfaceView.swift index 1960edd60..11f809fc9 100644 --- a/macos/Sources/Ghostty/SurfaceView.swift +++ b/macos/Sources/Ghostty/SurfaceView.swift @@ -137,7 +137,7 @@ extension Ghostty { // so we'll use that to tell ghostty to refresh. override var wantsUpdateLayer: Bool { return true } - init(_ app: ghostty_app_t, _ fontSize: UInt8?) { + init(_ app: ghostty_app_t, _ baseConfig: ghostty_surface_config_s?) { self.markedText = NSMutableAttributedString() // Initialize with some default frame size. The important thing is that this @@ -146,11 +146,11 @@ extension Ghostty { super.init(frame: NSMakeRect(0, 0, 800, 600)) // Setup our surface. This will also initialize all the terminal IO. - var surface_cfg = ghostty_surface_config_s( - userdata: Unmanaged.passUnretained(self).toOpaque(), - nsview: Unmanaged.passUnretained(self).toOpaque(), - scale_factor: NSScreen.main!.backingScaleFactor, - font_size: fontSize ?? 0) + var surface_cfg = baseConfig ?? ghostty_surface_config_new() + surface_cfg.userdata = Unmanaged.passUnretained(self).toOpaque() + surface_cfg.nsview = Unmanaged.passUnretained(self).toOpaque() + surface_cfg.scale_factor = NSScreen.main!.backingScaleFactor + guard let surface = ghostty_surface_new(app, &surface_cfg) else { self.error = AppError.surfaceCreateError return diff --git a/src/apprt/embedded.zig b/src/apprt/embedded.zig index ea2c32919..3e2eb9323 100644 --- a/src/apprt/embedded.zig +++ b/src/apprt/embedded.zig @@ -59,6 +59,9 @@ pub const App = struct { /// views then this can be null. new_split: ?*const fn (SurfaceUD, input.SplitDirection) callconv(.C) void = null, + /// New tab with options. + new_tab: ?*const fn (SurfaceUD, apprt.Surface.Options) callconv(.C) void = null, + /// Close the current surface given by this function. close_surface: ?*const fn (SurfaceUD, bool) callconv(.C) void = null, @@ -70,14 +73,6 @@ pub const App = struct { /// Toggle fullscreen for current window. toggle_fullscreen: ?*const fn (SurfaceUD, bool) callconv(.C) void = null, - - /// New tab with options. - new_tab: ?*const fn (SurfaceUD, apprt.App.NewTabOptions) callconv(.C) void = null, - }; - - pub const NewTabOptions = extern struct { - /// The font size to inherit. If 0, default font size will be used. - font_size: u8 = 0, }; core_app: *CoreApp, @@ -170,7 +165,7 @@ pub const Surface = struct { userdata: ?*anyopaque = null, /// The pointer to the backing NSView for the surface. - nsview: *anyopaque = undefined, + nsview: ?*anyopaque = null, /// The scale factor of the screen. scale_factor: f64 = 1, @@ -180,10 +175,13 @@ pub const Surface = struct { }; pub fn init(self: *Surface, app: *App, opts: Options) !void { + const nsview = objc.Object.fromId(opts.nsview orelse + return error.NSViewMustBeSet); + self.* = .{ .app = app, .core_surface = undefined, - .nsview = objc.Object.fromId(opts.nsview), + .nsview = nsview, .content_scale = .{ .x = @floatCast(opts.scale_factor), .y = @floatCast(opts.scale_factor), @@ -609,11 +607,9 @@ pub const Surface = struct { break :font_size @intCast(self.core_surface.font_size.points); }; - const options = apprt.App.NewTabOptions{ + func(self.opts.userdata, .{ .font_size = font_size, - }; - - func(self.opts.userdata, options); + }); } /// The cursor position from the host directly is in screen coordinates but @@ -685,6 +681,11 @@ pub const CAPI = struct { }; } + /// Returns initial surface options. + export fn ghostty_surface_config_new() apprt.Surface.Options { + return .{}; + } + /// Create a new surface as part of an app. export fn ghostty_surface_new( app: *App,