From ed8b5bc28381c2ce97520c13d1280d05d71b7fd7 Mon Sep 17 00:00:00 2001 From: SoraTenshi Date: Wed, 13 Sep 2023 23:16:33 +0200 Subject: [PATCH 1/9] macos: allow to hide decorations --- include/ghostty.h | 2 ++ .../Features/Primary Window/PrimaryWindow.swift | 13 +++++++++++-- src/config/CAPI.zig | 4 ++++ 3 files changed, 17 insertions(+), 2 deletions(-) diff --git a/include/ghostty.h b/include/ghostty.h index 7b4afa1d5..48c1990bc 100644 --- a/include/ghostty.h +++ b/include/ghostty.h @@ -309,6 +309,7 @@ typedef struct { void *nsview; double scale_factor; uint16_t font_size; + bool render_decoration; } ghostty_surface_config_s; typedef void (*ghostty_runtime_wakeup_cb)(void *); @@ -364,6 +365,7 @@ bool ghostty_config_get(ghostty_config_t, void *, const char *, uintptr_t); ghostty_input_trigger_s ghostty_config_trigger(ghostty_config_t, const char *, uintptr_t); uint32_t ghostty_config_errors_count(ghostty_config_t); ghostty_error_s ghostty_config_get_error(ghostty_config_t, uint32_t); +bool ghostty_config_render_decoration(ghostty_config_t); ghostty_app_t ghostty_app_new(const ghostty_runtime_config_s *, ghostty_config_t); void ghostty_app_free(ghostty_app_t); diff --git a/macos/Sources/Features/Primary Window/PrimaryWindow.swift b/macos/Sources/Features/Primary Window/PrimaryWindow.swift index b959e494b..258c7d19b 100644 --- a/macos/Sources/Features/Primary Window/PrimaryWindow.swift +++ b/macos/Sources/Features/Primary Window/PrimaryWindow.swift @@ -15,11 +15,20 @@ class FocusedSurfaceWrapper { // such as non-native fullscreen. class PrimaryWindow: NSWindow { var focusedSurfaceWrapper: FocusedSurfaceWrapper = FocusedSurfaceWrapper() - + + static func getStyleMask(render_decoration: Bool) -> NSWindow.StyleMask { + var mask: NSWindow.StyleMask = [.resizable, .closable, .miniaturizable] + if render_decoration { + mask.insert(.titled) + } + return mask + } + static func create(ghostty: Ghostty.AppState, appDelegate: AppDelegate, baseConfig: ghostty_surface_config_s? = nil) -> PrimaryWindow { + let decorations = baseConfig?.render_decoration ?? ghostty_config_render_decoration(ghostty.config) let window = PrimaryWindow( contentRect: NSRect(x: 0, y: 0, width: 800, height: 600), - styleMask: [.titled, .closable, .miniaturizable, .resizable], + styleMask: getStyleMask(render_decoration: decorations), backing: .buffered, defer: false) window.center() diff --git a/src/config/CAPI.zig b/src/config/CAPI.zig index be2a491e7..46cc8edad 100644 --- a/src/config/CAPI.zig +++ b/src/config/CAPI.zig @@ -119,6 +119,10 @@ export fn ghostty_config_get_error(self: *Config, idx: u32) Error { return .{ .message = err.message.ptr }; } +export fn ghostty_config_render_decoration(self: *Config) bool { + return self.@"window-decoration"; +} + /// Sync with ghostty_error_s const Error = extern struct { message: [*:0]const u8 = "", From 4c1cf5efe3e50f4af07fe476dc6dd2cbe1b2fc00 Mon Sep 17 00:00:00 2001 From: SoraTenshi Date: Wed, 13 Sep 2023 23:18:02 +0200 Subject: [PATCH 2/9] fixup! macos: allow to hide decorations --- src/config/Config.zig | 1 - 1 file changed, 1 deletion(-) diff --git a/src/config/Config.zig b/src/config/Config.zig index 3faf0101a..629392436 100644 --- a/src/config/Config.zig +++ b/src/config/Config.zig @@ -242,7 +242,6 @@ keybind: Keybinds = .{}, /// If false, windows won't have native decorations, i.e. titlebar and /// borders. -/// Currently only supported with GTK. @"window-decoration": bool = true, /// Whether to allow programs running in the terminal to read/write to From 3cb21dd76e6a5ee396a0cf3a3012a9f1944f5f66 Mon Sep 17 00:00:00 2001 From: SoraTenshi Date: Wed, 13 Sep 2023 23:39:18 +0200 Subject: [PATCH 3/9] Store and restore style mask on fullscreen --- macos/Sources/Helpers/FullScreenHandler.swift | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/macos/Sources/Helpers/FullScreenHandler.swift b/macos/Sources/Helpers/FullScreenHandler.swift index a85864b5b..e7bbf1c00 100644 --- a/macos/Sources/Helpers/FullScreenHandler.swift +++ b/macos/Sources/Helpers/FullScreenHandler.swift @@ -6,6 +6,7 @@ class FullScreenHandler { var previousTabGroupIndex: Int? var previousContentFrame: NSRect? var isInFullscreen: Bool = false + var previousStyleMask: NSWindow.StyleMask? = nil // We keep track of whether we entered non-native fullscreen in case // a user goes to fullscreen, changes the config to disable non-native fullscreen @@ -89,6 +90,7 @@ class FullScreenHandler { // This is important: it gives us the full screen, including the // notch area on MacBooks. + self.previousStyleMask = window.styleMask window.styleMask.remove(.titled) // Set frame to screen size, accounting for the menu bar if needed @@ -126,8 +128,8 @@ class FullScreenHandler { func leaveFullscreen(window: NSWindow) { guard let previousFrame = previousContentFrame else { return } - // Restore title bar - window.styleMask.insert(.titled) + // Restore the style mask + window.styleMask = self.previousStyleMask! // Restore previous presentation options NSApp.presentationOptions = [] From ddb9be0971a9d75c4fd62c6b62bc2424f77e3096 Mon Sep 17 00:00:00 2001 From: SoraTenshi Date: Thu, 14 Sep 2023 00:08:16 +0200 Subject: [PATCH 4/9] Remove custom CAPI function and use the already existing get_config function --- include/ghostty.h | 1 - .../Features/Primary Window/PrimaryWindow.swift | 11 +++++++---- src/config/CAPI.zig | 4 ---- 3 files changed, 7 insertions(+), 9 deletions(-) diff --git a/include/ghostty.h b/include/ghostty.h index 48c1990bc..b2c6ba6f3 100644 --- a/include/ghostty.h +++ b/include/ghostty.h @@ -365,7 +365,6 @@ bool ghostty_config_get(ghostty_config_t, void *, const char *, uintptr_t); ghostty_input_trigger_s ghostty_config_trigger(ghostty_config_t, const char *, uintptr_t); uint32_t ghostty_config_errors_count(ghostty_config_t); ghostty_error_s ghostty_config_get_error(ghostty_config_t, uint32_t); -bool ghostty_config_render_decoration(ghostty_config_t); ghostty_app_t ghostty_app_new(const ghostty_runtime_config_s *, ghostty_config_t); void ghostty_app_free(ghostty_app_t); diff --git a/macos/Sources/Features/Primary Window/PrimaryWindow.swift b/macos/Sources/Features/Primary Window/PrimaryWindow.swift index 258c7d19b..17632f694 100644 --- a/macos/Sources/Features/Primary Window/PrimaryWindow.swift +++ b/macos/Sources/Features/Primary Window/PrimaryWindow.swift @@ -16,19 +16,22 @@ class FocusedSurfaceWrapper { class PrimaryWindow: NSWindow { var focusedSurfaceWrapper: FocusedSurfaceWrapper = FocusedSurfaceWrapper() - static func getStyleMask(render_decoration: Bool) -> NSWindow.StyleMask { + static func getStyleMask(renderDecoration: Bool) -> NSWindow.StyleMask { var mask: NSWindow.StyleMask = [.resizable, .closable, .miniaturizable] - if render_decoration { + if renderDecoration { mask.insert(.titled) } return mask } static func create(ghostty: Ghostty.AppState, appDelegate: AppDelegate, baseConfig: ghostty_surface_config_s? = nil) -> PrimaryWindow { - let decorations = baseConfig?.render_decoration ?? ghostty_config_render_decoration(ghostty.config) + var renderDecoration = false; + let configString = "window-decoration" + _ = ghostty_config_get(ghostty.config, &renderDecoration, configString, UInt(configString.count)) + let window = PrimaryWindow( contentRect: NSRect(x: 0, y: 0, width: 800, height: 600), - styleMask: getStyleMask(render_decoration: decorations), + styleMask: getStyleMask(renderDecoration: baseConfig?.render_decoration ?? renderDecoration), backing: .buffered, defer: false) window.center() diff --git a/src/config/CAPI.zig b/src/config/CAPI.zig index 46cc8edad..be2a491e7 100644 --- a/src/config/CAPI.zig +++ b/src/config/CAPI.zig @@ -119,10 +119,6 @@ export fn ghostty_config_get_error(self: *Config, idx: u32) Error { return .{ .message = err.message.ptr }; } -export fn ghostty_config_render_decoration(self: *Config) bool { - return self.@"window-decoration"; -} - /// Sync with ghostty_error_s const Error = extern struct { message: [*:0]const u8 = "", From 81efb2dfe518779ae289c78bda0ddacc9b5849bb Mon Sep 17 00:00:00 2001 From: Will Pragnell Date: Wed, 13 Sep 2023 15:24:38 -0700 Subject: [PATCH 5/9] macos: always use latest window decoration config from runtime --- macos/Sources/Features/Primary Window/PrimaryWindow.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/macos/Sources/Features/Primary Window/PrimaryWindow.swift b/macos/Sources/Features/Primary Window/PrimaryWindow.swift index 17632f694..10aa1576e 100644 --- a/macos/Sources/Features/Primary Window/PrimaryWindow.swift +++ b/macos/Sources/Features/Primary Window/PrimaryWindow.swift @@ -31,7 +31,7 @@ class PrimaryWindow: NSWindow { let window = PrimaryWindow( contentRect: NSRect(x: 0, y: 0, width: 800, height: 600), - styleMask: getStyleMask(renderDecoration: baseConfig?.render_decoration ?? renderDecoration), + styleMask: getStyleMask(renderDecoration: renderDecoration), backing: .buffered, defer: false) window.center() From 48de8c08375e8d231c4b34d7d6fd97b97a94b89d Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Wed, 13 Sep 2023 22:03:39 -0700 Subject: [PATCH 6/9] c: remove unused struct field --- include/ghostty.h | 1 - 1 file changed, 1 deletion(-) diff --git a/include/ghostty.h b/include/ghostty.h index b2c6ba6f3..7b4afa1d5 100644 --- a/include/ghostty.h +++ b/include/ghostty.h @@ -309,7 +309,6 @@ typedef struct { void *nsview; double scale_factor; uint16_t font_size; - bool render_decoration; } ghostty_surface_config_s; typedef void (*ghostty_runtime_wakeup_cb)(void *); From 2b380ad37e063d6ddc9c1daf79921b57b5f1738f Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Wed, 13 Sep 2023 22:08:32 -0700 Subject: [PATCH 7/9] macos: stylistic changes --- .../Primary Window/PrimaryWindow.swift | 23 ++- macos/Sources/Ghostty/AppState.swift | 135 ++++++++++-------- macos/Sources/Helpers/FullScreenHandler.swift | 5 +- 3 files changed, 84 insertions(+), 79 deletions(-) diff --git a/macos/Sources/Features/Primary Window/PrimaryWindow.swift b/macos/Sources/Features/Primary Window/PrimaryWindow.swift index 10aa1576e..04ba7bdac 100644 --- a/macos/Sources/Features/Primary Window/PrimaryWindow.swift +++ b/macos/Sources/Features/Primary Window/PrimaryWindow.swift @@ -16,22 +16,10 @@ class FocusedSurfaceWrapper { class PrimaryWindow: NSWindow { var focusedSurfaceWrapper: FocusedSurfaceWrapper = FocusedSurfaceWrapper() - static func getStyleMask(renderDecoration: Bool) -> NSWindow.StyleMask { - var mask: NSWindow.StyleMask = [.resizable, .closable, .miniaturizable] - if renderDecoration { - mask.insert(.titled) - } - return mask - } - static func create(ghostty: Ghostty.AppState, appDelegate: AppDelegate, baseConfig: ghostty_surface_config_s? = nil) -> PrimaryWindow { - var renderDecoration = false; - let configString = "window-decoration" - _ = ghostty_config_get(ghostty.config, &renderDecoration, configString, UInt(configString.count)) - let window = PrimaryWindow( contentRect: NSRect(x: 0, y: 0, width: 800, height: 600), - styleMask: getStyleMask(renderDecoration: renderDecoration), + styleMask: getStyleMask(renderDecoration: ghostty.windowDecorations), backing: .buffered, defer: false) window.center() @@ -57,6 +45,15 @@ class PrimaryWindow: NSWindow { return window } + static func getStyleMask(renderDecoration: Bool) -> NSWindow.StyleMask { + var mask: NSWindow.StyleMask = [.resizable, .closable, .miniaturizable] + if renderDecoration { + mask.insert(.titled) + } + + return mask + } + override var canBecomeKey: Bool { return true } diff --git a/macos/Sources/Ghostty/AppState.swift b/macos/Sources/Ghostty/AppState.swift index 253c705f8..3dec00975 100644 --- a/macos/Sources/Ghostty/AppState.swift +++ b/macos/Sources/Ghostty/AppState.swift @@ -10,21 +10,21 @@ extension Ghostty { enum AppReadiness { case loading, error, ready } - + struct Info { var mode: ghostty_build_mode_e var version: String } - + /// The AppState is the global state that is associated with the Swift app. This handles initially /// initializing Ghostty, loading the configuration, etc. class AppState: ObservableObject { /// The readiness value of the state. @Published var readiness: AppReadiness = .loading - + /// Optional delegate weak var delegate: GhosttyAppStateDelegate? - + /// The ghostty global configuration. This should only be changed when it is definitely /// safe to change. It is definite safe to change only when the embedded app runtime /// in Ghostty says so (usually, only in a reload configuration callback). @@ -35,7 +35,7 @@ extension Ghostty { ghostty_config_free(old) } } - + /// The ghostty app instance. We only have one of these for the entire app, although I guess /// in theory you can have multiple... I don't know why you would... @Published var app: ghostty_app_t? = nil { @@ -44,13 +44,13 @@ extension Ghostty { ghostty_app_free(old) } } - + /// True if we need to confirm before quitting. var needsConfirmQuit: Bool { guard let app = app else { return false } return ghostty_app_needs_confirm_quit(app) } - + /// Build information var info: Info { let raw = ghostty_info() @@ -59,10 +59,19 @@ extension Ghostty { length: Int(raw.version_len), encoding: NSUTF8StringEncoding ) ?? "unknown" - + return Info(mode: raw.build_mode, version: String(version)) } - + + /// True if we want to render window decorations + var windowDecorations: Bool { + guard let config = self.config else { return true } + var v = false; + let key = "window-decoration" + _ = ghostty_config_get(config, &v, key, UInt(key.count)) + return v; + } + /// Cached clipboard string for `read_clipboard` callback. private var cached_clipboard_string: String? = nil @@ -73,14 +82,14 @@ extension Ghostty { readiness = .error return } - + // Initialize the global configuration. guard let cfg = Self.loadConfig() else { readiness = .error return } self.config = cfg; - + // Create our "runtime" config. The "runtime" is the configuration that ghostty // uses to interface with the application runtime environment. var runtime_cfg = ghostty_runtime_config_s( @@ -110,7 +119,7 @@ extension Ghostty { return } self.app = app - + // Subscribe to notifications for keyboard layout change so that we can update Ghostty. NotificationCenter.default.addObserver( self, @@ -120,19 +129,19 @@ extension Ghostty { self.readiness = .ready } - + deinit { // This will force the didSet callbacks to run which free. self.app = nil self.config = nil - + // Remove our observer NotificationCenter.default.removeObserver( self, name: NSTextInputContext.keyboardSelectionDidChangeNotification, object: nil) } - + /// Initializes a new configuration and loads all the values. static func loadConfig() -> ghostty_config_t? { // Initialize the global configuration. @@ -140,19 +149,19 @@ extension Ghostty { AppDelegate.logger.critical("ghostty_config_new failed") return nil } - + // Load our configuration files from the home directory. ghostty_config_load_default_files(cfg); ghostty_config_load_cli_args(cfg); ghostty_config_load_recursive_files(cfg); - + // TODO: we'd probably do some config loading here... for now we'd // have to do this synchronously. When we support config updating we can do // this async and update later. - + // Finalize will make our defaults available. ghostty_config_finalize(cfg) - + // Log any configuration errors. These will be automatically shown in a // pop-up window too. let errCount = ghostty_config_errors_count(cfg) @@ -166,14 +175,14 @@ extension Ghostty { AppDelegate.logger.warning("config error: \(message)") } } - + return cfg } - + /// Returns the configuration errors (if any). func configErrors() -> [String] { guard let cfg = self.config else { return [] } - + var errors: [String] = []; let errCount = ghostty_config_errors_count(cfg) for i in 0.. UnsafePointer? { // We only support the standard clipboard if (location != GHOSTTY_CLIPBOARD_STANDARD) { return nil } - + guard let appState = self.appState(fromSurface: userdata) else { return nil } guard let str = NSPasteboard.general.string(forType: .string) else { return nil } - + // Ghostty requires we cache the string because the pointer we return has to remain // stable until the next call to readClipboard. appState.cached_clipboard_string = str return (str as NSString).utf8String } - + static func writeClipboard(_ userdata: UnsafeMutableRawPointer?, string: UnsafePointer?, location: ghostty_clipboard_e) { // We only support the standard clipboard if (location != GHOSTTY_CLIPBOARD_STANDARD) { return } - + guard let valueStr = String(cString: string!, encoding: .utf8) else { return } let pb = NSPasteboard.general pb.declareTypes([.string], owner: nil) pb.setString(valueStr, forType: .string) } - + static func reloadConfig(_ userdata: UnsafeMutableRawPointer?) -> ghostty_config_t? { guard let newConfig = Self.loadConfig() else { AppDelegate.logger.warning("failed to reload configuration") return nil } - + // Assign the new config. This will automatically free the old config. // It is safe to free the old config from within this function call. let state = Unmanaged.fromOpaque(userdata!).takeUnretainedValue() state.config = newConfig - + // If we have a delegate, notify. if let delegate = state.delegate { delegate.configDidReload(state) } - + return newConfig } - + static func wakeup(_ userdata: UnsafeMutableRawPointer?) { let state = Unmanaged.fromOpaque(userdata!).takeUnretainedValue() - + // Wakeup can be called from any thread so we schedule the app tick // from the main thread. There is probably some improvements we can make // to coalesce multiple ticks but I don't think it matters from a performance // standpoint since we don't do this much. DispatchQueue.main.async { state.appTick() } } - + static func setTitle(_ userdata: UnsafeMutableRawPointer?, title: UnsafePointer?) { let surfaceView = Unmanaged.fromOpaque(userdata!).takeUnretainedValue() guard let titleStr = String(cString: title!, encoding: .utf8) else { return } @@ -351,12 +360,12 @@ extension Ghostty { surfaceView.title = titleStr } } - + static func setMouseShape(_ userdata: UnsafeMutableRawPointer?, shape: ghostty_mouse_shape_e) { let surfaceView = Unmanaged.fromOpaque(userdata!).takeUnretainedValue() surfaceView.setCursorShape(shape) } - + static func setMouseVisibility(_ userdata: UnsafeMutableRawPointer?, visible: Bool) { let surfaceView = Unmanaged.fromOpaque(userdata!).takeUnretainedValue() surfaceView.setCursorVisibility(visible) @@ -372,10 +381,10 @@ extension Ghostty { ] ) } - + static func newTab(_ userdata: UnsafeMutableRawPointer?, config: ghostty_surface_config_s) { guard let surface = self.surfaceUserdata(from: userdata) else { return } - + NotificationCenter.default.post( name: Notification.ghosttyNewTab, object: surface, @@ -384,10 +393,10 @@ extension Ghostty { ] ) } - + static func newWindow(_ userdata: UnsafeMutableRawPointer?, config: ghostty_surface_config_s) { guard let surface = self.surfaceUserdata(from: userdata) else { return } - + NotificationCenter.default.post( name: Notification.ghosttyNewWindow, object: surface, @@ -396,7 +405,7 @@ extension Ghostty { ] ) } - + /// Returns the GhosttyState from the given userdata value. static private func appState(fromSurface userdata: UnsafeMutableRawPointer?) -> AppState? { let surfaceView = Unmanaged.fromOpaque(userdata!).takeUnretainedValue() @@ -405,7 +414,7 @@ extension Ghostty { guard let app_ud = ghostty_app_userdata(app) else { return nil } return Unmanaged.fromOpaque(app_ud).takeUnretainedValue() } - + /// Returns the surface view from the userdata. static private func surfaceUserdata(from userdata: UnsafeMutableRawPointer?) -> SurfaceView? { return Unmanaged.fromOpaque(userdata!).takeUnretainedValue() @@ -428,7 +437,7 @@ extension EnvironmentValues { get { self[GhosttyAppKey.self] } set { self[GhosttyAppKey.self] = newValue } } - + var ghosttyConfig: ghostty_config_t? { get { self[GhosttyConfigKey.self] } set { self[GhosttyConfigKey.self] = newValue } @@ -439,7 +448,7 @@ extension View { func ghosttyApp(_ app: ghostty_app_t?) -> some View { environment(\.ghosttyApp, app) } - + func ghosttyConfig(_ config: ghostty_config_t?) -> some View { environment(\.ghosttyConfig, config) } diff --git a/macos/Sources/Helpers/FullScreenHandler.swift b/macos/Sources/Helpers/FullScreenHandler.swift index e7bbf1c00..2fe650587 100644 --- a/macos/Sources/Helpers/FullScreenHandler.swift +++ b/macos/Sources/Helpers/FullScreenHandler.swift @@ -1,17 +1,16 @@ import SwiftUI import GhosttyKit -class FullScreenHandler { - var previousTabGroup: NSWindowTabGroup? +class FullScreenHandler { var previousTabGroup: NSWindowTabGroup? var previousTabGroupIndex: Int? var previousContentFrame: NSRect? - var isInFullscreen: Bool = false var previousStyleMask: NSWindow.StyleMask? = nil // We keep track of whether we entered non-native fullscreen in case // a user goes to fullscreen, changes the config to disable non-native fullscreen // and then wants to toggle it off var isInNonNativeFullscreen: Bool = false + var isInFullscreen: Bool = false func toggleFullscreen(window: NSWindow, nonNativeFullscreen: ghostty_non_native_fullscreen_e) { let useNonNativeFullscreen = nonNativeFullscreen != GHOSTTY_NON_NATIVE_FULLSCREEN_FALSE From 833be445ba4ab1af922dc691aeec74693725d73f Mon Sep 17 00:00:00 2001 From: SoraTenshi Date: Fri, 15 Sep 2023 11:16:18 +0200 Subject: [PATCH 8/9] Spawn alert box on new tab if decorations disabled Stray spaces Fix check for windowDecoration --- .../Features/Primary Window/PrimaryWindow.swift | 2 +- macos/Sources/Ghostty/AppState.swift | 10 ++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/macos/Sources/Features/Primary Window/PrimaryWindow.swift b/macos/Sources/Features/Primary Window/PrimaryWindow.swift index 04ba7bdac..51194ad91 100644 --- a/macos/Sources/Features/Primary Window/PrimaryWindow.swift +++ b/macos/Sources/Features/Primary Window/PrimaryWindow.swift @@ -15,7 +15,7 @@ class FocusedSurfaceWrapper { // such as non-native fullscreen. class PrimaryWindow: NSWindow { var focusedSurfaceWrapper: FocusedSurfaceWrapper = FocusedSurfaceWrapper() - + 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), diff --git a/macos/Sources/Ghostty/AppState.swift b/macos/Sources/Ghostty/AppState.swift index 3dec00975..f61928f82 100644 --- a/macos/Sources/Ghostty/AppState.swift +++ b/macos/Sources/Ghostty/AppState.swift @@ -385,6 +385,16 @@ extension Ghostty { static func newTab(_ userdata: UnsafeMutableRawPointer?, config: ghostty_surface_config_s) { guard let surface = self.surfaceUserdata(from: userdata) else { return } + guard self.appState(fromSurface: userdata)?.windowDecorations else { + let alert = NSAlert() + alert.messageText = "Tabs are disabled" + alert.informativeText = "Enable window decorations to use tabs" + alert.addButton(withTitle: "OK") + alert.alertStyle = .warning + _ = alert.runModal() + return + } + NotificationCenter.default.post( name: Notification.ghosttyNewTab, object: surface, From d911c49f4481ac4a853aa3196dce4761a19459a1 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Sun, 17 Sep 2023 12:01:36 -0700 Subject: [PATCH 9/9] macos: remove unnecessary call --- macos/Sources/Ghostty/AppState.swift | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/macos/Sources/Ghostty/AppState.swift b/macos/Sources/Ghostty/AppState.swift index f61928f82..e0dab0b75 100644 --- a/macos/Sources/Ghostty/AppState.swift +++ b/macos/Sources/Ghostty/AppState.swift @@ -305,7 +305,8 @@ extension Ghostty { // We only support the standard clipboard if (location != GHOSTTY_CLIPBOARD_STANDARD) { return nil } - guard let appState = self.appState(fromSurface: userdata) else { return nil } + guard let surface = self.surfaceUserdata(from: userdata) else { return nil } + guard let appState = self.appState(fromView: surface) else { return nil } guard let str = NSPasteboard.general.string(forType: .string) else { return nil } // Ghostty requires we cache the string because the pointer we return has to remain @@ -384,8 +385,9 @@ extension Ghostty { static func newTab(_ userdata: UnsafeMutableRawPointer?, config: ghostty_surface_config_s) { guard let surface = self.surfaceUserdata(from: userdata) else { return } - - guard self.appState(fromSurface: userdata)?.windowDecorations else { + + guard let appState = self.appState(fromView: surface) else { return } + guard appState.windowDecorations else { let alert = NSAlert() alert.messageText = "Tabs are disabled" alert.informativeText = "Enable window decorations to use tabs" @@ -417,9 +419,8 @@ extension Ghostty { } /// Returns the GhosttyState from the given userdata value. - static private func appState(fromSurface userdata: UnsafeMutableRawPointer?) -> AppState? { - let surfaceView = Unmanaged.fromOpaque(userdata!).takeUnretainedValue() - guard let surface = surfaceView.surface else { return nil } + static private func appState(fromView view: SurfaceView) -> AppState? { + guard let surface = view.surface else { return nil } guard let app = ghostty_surface_app(surface) else { return nil } guard let app_ud = ghostty_app_userdata(app) else { return nil } return Unmanaged.fromOpaque(app_ud).takeUnretainedValue()