From b56ffa6285c9e79722514c3823ebfa98f7cb716e Mon Sep 17 00:00:00 2001 From: Thorsten Ball Date: Sat, 29 Jul 2023 21:05:49 +0200 Subject: [PATCH] Add config setting to turn non-native fullscreen on or off --- include/ghostty.h | 2 +- macos/Sources/ContentView.swift | 8 ++++++-- macos/Sources/FullScreenHandler.swift | 21 ++++++++++++++++++--- macos/Sources/Ghostty/AppState.swift | 9 ++++++--- macos/Sources/Ghostty/Package.swift | 1 + src/Surface.zig | 4 +++- src/apprt/embedded.zig | 6 +++--- src/apprt/gtk.zig | 2 +- src/config.zig | 6 ++++++ 9 files changed, 45 insertions(+), 14 deletions(-) diff --git a/include/ghostty.h b/include/ghostty.h index 2cb915ddd..14d8d2b02 100644 --- a/include/ghostty.h +++ b/include/ghostty.h @@ -239,7 +239,7 @@ typedef void (*ghostty_runtime_new_split_cb)(void *, ghostty_split_direction_e); 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 *); +typedef void (*ghostty_runtime_toggle_fullscreen_cb)(void *, bool); typedef struct { void *userdata; diff --git a/macos/Sources/ContentView.swift b/macos/Sources/ContentView.swift index 11787bb63..b0cfaa6e3 100644 --- a/macos/Sources/ContentView.swift +++ b/macos/Sources/ContentView.swift @@ -110,8 +110,12 @@ struct ContentView: View { // currently focused window. guard let window = self.window else { return } guard window.isKeyWindow else { return } - - self.fsHandler.toggleFullscreen(window: window) + + // Check whether we use non-native fullscreen + guard let useNonNativeFullscreenAny = notification.userInfo?[Ghostty.Notification.NonNativeFullscreenKey] else { return } + guard let useNonNativeFullscreen = useNonNativeFullscreenAny as? Bool else { return } + + self.fsHandler.toggleFullscreen(window: window, nonNativeFullscreen: useNonNativeFullscreen) // After toggling fullscreen we need to focus the terminal again. self.focused = true } diff --git a/macos/Sources/FullScreenHandler.swift b/macos/Sources/FullScreenHandler.swift index c3bddaab1..b182d4c9c 100644 --- a/macos/Sources/FullScreenHandler.swift +++ b/macos/Sources/FullScreenHandler.swift @@ -7,12 +7,27 @@ class FullScreenHandler { var previousStyleMask: NSWindow.StyleMask? var isInFullscreen: Bool = false - func toggleFullscreen(window: NSWindow) { + // 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 + + func toggleFullscreen(window: NSWindow, nonNativeFullscreen: Bool) { if isInFullscreen { - leaveFullscreen(window: window) + if nonNativeFullscreen || isInNonNativeFullscreen { + leaveFullscreen(window: window) + isInNonNativeFullscreen = false + } else { + window.toggleFullScreen(nil) + } isInFullscreen = false } else { - enterFullscreen(window: window) + if nonNativeFullscreen { + enterFullscreen(window: window) + isInNonNativeFullscreen = true + } else { + window.toggleFullScreen(nil) + } isInFullscreen = true } } diff --git a/macos/Sources/Ghostty/AppState.swift b/macos/Sources/Ghostty/AppState.swift index b763444fa..f3e8a64c4 100644 --- a/macos/Sources/Ghostty/AppState.swift +++ b/macos/Sources/Ghostty/AppState.swift @@ -63,7 +63,7 @@ extension Ghostty { 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 in AppState.toggleFullscreen(userdata) } + toggle_fullscreen_cb: { userdata, nonNativeFullscreen in AppState.toggleFullscreen(userdata, useNonNativeFullscreen: nonNativeFullscreen) } ) // Create the ghostty app. @@ -219,12 +219,15 @@ extension Ghostty { } } - static func toggleFullscreen(_ userdata: UnsafeMutableRawPointer?) { + static func toggleFullscreen(_ userdata: UnsafeMutableRawPointer?, useNonNativeFullscreen: Bool) { + // togo: use non-native fullscreen guard let surface = self.surfaceUserdata(from: userdata) else { return } NotificationCenter.default.post( name: Notification.ghosttyToggleFullscreen, object: surface, - userInfo: [:] + userInfo: [ + Notification.NonNativeFullscreenKey: useNonNativeFullscreen, + ] ) } diff --git a/macos/Sources/Ghostty/Package.swift b/macos/Sources/Ghostty/Package.swift index 6045d6dbb..d4b3a9fa9 100644 --- a/macos/Sources/Ghostty/Package.swift +++ b/macos/Sources/Ghostty/Package.swift @@ -81,6 +81,7 @@ extension Ghostty.Notification { /// Toggle fullscreen of current window static let ghosttyToggleFullscreen = Notification.Name("com.mitchellh.ghostty.toggleFullscreen") + static let NonNativeFullscreenKey = ghosttyToggleFullscreen.rawValue } // Make the input enum hashable. diff --git a/src/Surface.zig b/src/Surface.zig index fdf562923..df2612a55 100644 --- a/src/Surface.zig +++ b/src/Surface.zig @@ -146,6 +146,7 @@ const DerivedConfig = struct { clipboard_trim_trailing_spaces: bool, confirm_close_surface: bool, mouse_interval: u64, + macos_non_native_fullscreen: bool, pub fn init(alloc_gpa: Allocator, config: *const configpkg.Config) !DerivedConfig { var arena = ArenaAllocator.init(alloc_gpa); @@ -160,6 +161,7 @@ const DerivedConfig = struct { .clipboard_trim_trailing_spaces = config.@"clipboard-trim-trailing-spaces", .confirm_close_surface = config.@"confirm-close-surface", .mouse_interval = config.@"click-repeat-interval" * 1_000_000, // 500ms + .macos_non_native_fullscreen = config.@"macos-non-native-fullscreen", // Assignments happen sequentially so we have to do this last // so that the memory is captured from allocs above. @@ -1213,7 +1215,7 @@ pub fn keyCallback( .toggle_fullscreen => { if (@hasDecl(apprt.Surface, "toggleFullscreen")) { - self.rt_surface.toggleFullscreen(); + self.rt_surface.toggleFullscreen(self.config.macos_non_native_fullscreen); } else log.warn("runtime doesn't implement toggleFullscreen", .{}); }, diff --git a/src/apprt/embedded.zig b/src/apprt/embedded.zig index 1b5c3c4b8..f39f21c6b 100644 --- a/src/apprt/embedded.zig +++ b/src/apprt/embedded.zig @@ -66,7 +66,7 @@ pub const App = struct { goto_tab: ?*const fn (SurfaceUD, usize) callconv(.C) void = null, /// Toggle fullscreen for current window. - toggle_fullscreen: ?*const fn (SurfaceUD) callconv(.C) void = null, + toggle_fullscreen: ?*const fn (SurfaceUD, bool) callconv(.C) void = null, }; core_app: *CoreApp, @@ -374,13 +374,13 @@ pub const Surface = struct { func(self.opts.userdata, n); } - pub fn toggleFullscreen(self: *Surface) void { + pub fn toggleFullscreen(self: *Surface, nonNativeFullscreen: bool) void { const func = self.app.opts.toggle_fullscreen orelse { log.info("runtime embedder does not toggle_fullscreen", .{}); return; }; - func(self.opts.userdata); + func(self.opts.userdata, nonNativeFullscreen); } /// The cursor position from the host directly is in screen coordinates but diff --git a/src/apprt/gtk.zig b/src/apprt/gtk.zig index a5fabc577..328141414 100644 --- a/src/apprt/gtk.zig +++ b/src/apprt/gtk.zig @@ -483,7 +483,7 @@ const Window = struct { } /// Toggle fullscreen for this window. - fn toggleFullscreen(self: *Window) void { + fn toggleFullscreen(self: *Window, _: bool) void { const is_fullscreen = c.gtk_window_is_fullscreen(self.window); if (is_fullscreen == 0) { c.gtk_window_fullscreen(self.window); diff --git a/src/config.zig b/src/config.zig index 86ea3a7ef..7d2a7fc24 100644 --- a/src/config.zig +++ b/src/config.zig @@ -221,6 +221,12 @@ pub const Config = struct { /// The default value is "detect". @"shell-integration": ShellIntegration = .detect, + /// If true, fullscreen mode on macOS will not use the native fullscreen, + /// but make the window fullscreen without animations and using a new space. + /// That's faster than the native fullscreen mode since it doesn't use + /// animations. + @"macos-non-native-fullscreen": bool = false, + /// This is set by the CLI parser for deinit. _arena: ?ArenaAllocator = null,