Sachin Beniwal 2025-12-17 16:48:48 -05:00 committed by GitHub
commit 22a39361d9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 99 additions and 29 deletions

View File

@ -479,6 +479,15 @@ typedef struct {
ghostty_quick_terminal_size_s secondary;
} ghostty_config_quick_terminal_size_s;
// config.Fullscreen
typedef enum {
GHOSTTY_CONFIG_FULLSCREEN_FALSE,
GHOSTTY_CONFIG_FULLSCREEN_TRUE,
GHOSTTY_CONFIG_FULLSCREEN_NON_NATIVE,
GHOSTTY_CONFIG_FULLSCREEN_NON_NATIVE_VISIBLE_MENU,
GHOSTTY_CONFIG_FULLSCREEN_NON_NATIVE_PADDED_NOTCH,
} ghostty_config_fullscreen_e;
// apprt.Target.Key
typedef enum {
GHOSTTY_TARGET_APP,

View File

@ -204,27 +204,25 @@ class TerminalController: BaseTerminalController, TabGroupCloseCoordinator.Contr
// otherwise the focused terminal, otherwise an arbitrary one.
let parent: NSWindow? = explicitParent ?? preferredParent?.window
if let parent {
if parent.styleMask.contains(.fullScreen) {
// If our previous window was fullscreen then we want our new window to
// be fullscreen. This behavior actually doesn't match the native tabbing
// behavior of macOS apps where new windows create tabs when in native
// fullscreen but this is how we've always done it. This matches iTerm2
// behavior.
if let parent, parent.styleMask.contains(.fullScreen) {
// If our previous window was fullscreen then we want our new window to
// be fullscreen. This behavior actually doesn't match the native tabbing
// behavior of macOS apps where new windows create tabs when in native
// fullscreen but this is how we've always done it. This matches iTerm2
// behavior.
c.toggleFullscreen(mode: .native)
} else if let fullscreenMode = ghostty.config.windowFullscreen {
switch fullscreenMode {
case .native:
// Native has to be done immediately so that our stylemask contains
// fullscreen for the logic later in this method.
c.toggleFullscreen(mode: .native)
} else if ghostty.config.windowFullscreen {
switch (ghostty.config.windowFullscreenMode) {
case .native:
// Native has to be done immediately so that our stylemask contains
// fullscreen for the logic later in this method.
c.toggleFullscreen(mode: .native)
case .nonNative, .nonNativeVisibleMenu, .nonNativePaddedNotch:
// If we're non-native then we have to do it on a later loop
// so that the content view is setup.
DispatchQueue.main.async {
c.toggleFullscreen(mode: ghostty.config.windowFullscreenMode)
}
case .nonNative, .nonNativeVisibleMenu, .nonNativePaddedNotch:
// If we're non-native then we have to do it on a later loop
// so that the content view is setup.
DispatchQueue.main.async {
c.toggleFullscreen(mode: fullscreenMode)
}
}
}

View File

@ -217,14 +217,46 @@ extension Ghostty {
return v
}
var windowFullscreen: Bool {
guard let config = self.config else { return true }
var v = false
/// Returns the fullscreen mode if fullscreen is enabled, or nil if disabled.
/// This parses the `fullscreen` enum config which supports both
/// native and non-native fullscreen modes.
#if canImport(AppKit)
var windowFullscreen: FullscreenMode? {
guard let config = self.config else { return nil }
var v: UnsafePointer<Int8>? = nil
let key = "fullscreen"
_ = ghostty_config_get(config, &v, key, UInt(key.lengthOfBytes(using: .utf8)))
return v
guard ghostty_config_get(config, &v, key, UInt(key.lengthOfBytes(using: .utf8))) else { return nil }
guard let ptr = v else { return nil }
let str = String(cString: ptr)
return switch str {
case "false":
nil
case "true":
.native
case "non-native":
.nonNative
case "non-native-visible-menu":
.nonNativeVisibleMenu
case "non-native-padded-notch":
.nonNativePaddedNotch
default:
nil
}
}
#else
var windowFullscreen: Bool {
guard let config = self.config else { return false }
var v: UnsafePointer<Int8>? = nil
let key = "fullscreen"
guard ghostty_config_get(config, &v, key, UInt(key.lengthOfBytes(using: .utf8))) else { return false }
guard let ptr = v else { return false }
let str = String(cString: ptr)
return str != "false"
}
#endif
/// Returns the fullscreen mode for toggle actions (keybindings).
/// This is controlled by `macos-non-native-fullscreen` config.
#if canImport(AppKit)
var windowFullscreenMode: FullscreenMode {
let defaultValue: FullscreenMode = .native

View File

@ -301,6 +301,7 @@ const DerivedConfig = struct {
mouse_reporting: bool,
mouse_scroll_multiplier: configpkg.MouseScrollMultiplier,
mouse_shift_capture: configpkg.MouseShiftCapture,
fullscreen: configpkg.Fullscreen,
macos_non_native_fullscreen: configpkg.NonNativeFullscreen,
macos_option_as_alt: ?input.OptionAsAlt,
selection_clear_on_copy: bool,
@ -376,6 +377,7 @@ const DerivedConfig = struct {
.mouse_reporting = config.@"mouse-reporting",
.mouse_scroll_multiplier = config.@"mouse-scroll-multiplier",
.mouse_shift_capture = config.@"mouse-shift-capture",
.fullscreen = config.fullscreen,
.macos_non_native_fullscreen = config.@"macos-non-native-fullscreen",
.macos_option_as_alt = config.@"macos-option-as-alt",
.selection_clear_on_copy = config.@"selection-clear-on-copy",

View File

@ -304,7 +304,7 @@ pub const Window = extern struct {
if (priv.config) |config_obj| {
const config = config_obj.get();
if (config.maximize) self.as(gtk.Window).maximize();
if (config.fullscreen) self.as(gtk.Window).fullscreen();
if (config.fullscreen != .false) self.as(gtk.Window).fullscreen();
// If we have an explicit title set, we set that immediately
// so that any applications inspecting the window states see

View File

@ -31,6 +31,7 @@ pub const Keybinds = Config.Keybinds;
pub const MouseShiftCapture = Config.MouseShiftCapture;
pub const MouseScrollMultiplier = Config.MouseScrollMultiplier;
pub const NonNativeFullscreen = Config.NonNativeFullscreen;
pub const Fullscreen = Config.Fullscreen;
pub const RepeatableCodepointMap = Config.RepeatableCodepointMap;
pub const RepeatableFontVariation = Config.RepeatableFontVariation;
pub const RepeatableString = Config.RepeatableString;

View File

@ -1357,10 +1357,27 @@ maximize: bool = false,
/// does not apply to tabs, splits, etc. However, this setting will apply to all
/// new windows, not just the first one.
///
/// On macOS, this setting does not work if window-decoration is set to
/// "none", because native fullscreen on macOS requires window decorations
/// to be set.
fullscreen: bool = false,
/// Allowable values are:
///
/// * `false` - Don't start in fullscreen (default)
/// * `true` - Start in native fullscreen
/// * `non-native` - (macOS only) Start in non-native fullscreen, hiding the
/// menu bar. This is faster than native fullscreen since it doesn't use
/// animations. On non-macOS platforms, this behaves the same as `true`.
/// * `non-native-visible-menu` - (macOS only) Start in non-native fullscreen,
/// keeping the menu bar visible. On non-macOS platforms, behaves like `true`.
/// * `non-native-padded-notch` - (macOS only) Start in non-native fullscreen,
/// hiding the menu bar but padding for the notch on applicable devices.
/// On non-macOS platforms, behaves like `true`.
///
/// Important: tabs DO NOT WORK with non-native fullscreen modes. Non-native
/// fullscreen removes the titlebar and macOS native tabs require the titlebar.
/// If you use tabs, use `true` (native) instead.
///
/// On macOS, `true` (native fullscreen) does not work if `window-decoration`
/// is set to `false`, because native fullscreen on macOS requires window
/// decorations.
fullscreen: Fullscreen = .false,
/// The title Ghostty will use for the window. This will force the title of the
/// window to be this title at all times and Ghostty will ignore any set title
@ -4947,6 +4964,17 @@ pub const NonNativeFullscreen = enum(c_int) {
@"padded-notch",
};
/// Valid values for fullscreen config option
/// c_int because it needs to be extern compatible
/// If this is changed, you must also update ghostty.h
pub const Fullscreen = enum(c_int) {
false,
true,
@"non-native",
@"non-native-visible-menu",
@"non-native-padded-notch",
};
pub const WindowPaddingColor = enum {
background,
extend,