From 1dab2d456e997a603c0d92e46688d4f216213580 Mon Sep 17 00:00:00 2001 From: Friedrich Stoltzfus Date: Wed, 11 Jun 2025 14:41:35 -0400 Subject: [PATCH 1/6] macOS: Add support for quick terminal sizing configuration Added C bindings for the already existing quick-terminal-size configuration. Created a new QuickTerminalSize struct to hold these values in Swift. Updated the QuickTerminal implementation to use the user's configuration if supplied. Retains defaults. Also adds support to customize the width of the quick terminal (height if quick terminal is set to right or left). --- include/ghostty.h | 8 ++ macos/Ghostty.xcodeproj/project.pbxproj | 5 ++ .../QuickTerminalController.swift | 13 +-- .../QuickTerminal/QuickTerminalPosition.swift | 72 +++++++---------- .../QuickTerminal/QuickTerminalSize.swift | 80 +++++++++++++++++++ macos/Sources/Ghostty/Ghostty.Config.swift | 8 ++ src/config/Config.zig | 29 +++++++ 7 files changed, 167 insertions(+), 48 deletions(-) create mode 100644 macos/Sources/Features/QuickTerminal/QuickTerminalSize.swift diff --git a/include/ghostty.h b/include/ghostty.h index 181f7b7f8..a2f2c068e 100644 --- a/include/ghostty.h +++ b/include/ghostty.h @@ -445,6 +445,14 @@ typedef struct { ghostty_config_color_s colors[256]; } ghostty_config_palette_s; +// config.QuickTerminalSize +typedef struct { + uint8_t primary_type; // 0 = none, 1 = percentage, 2 = pixels + float primary_value; + uint8_t secondary_type; // 0 = none, 1 = percentage, 2 = pixels + float secondary_value; +} ghostty_config_quick_terminal_size_s; + // apprt.Target.Key typedef enum { GHOSTTY_TARGET_APP, diff --git a/macos/Ghostty.xcodeproj/project.pbxproj b/macos/Ghostty.xcodeproj/project.pbxproj index cf806c7bd..88a74c433 100644 --- a/macos/Ghostty.xcodeproj/project.pbxproj +++ b/macos/Ghostty.xcodeproj/project.pbxproj @@ -102,6 +102,7 @@ A5AEB1652D5BE7D000513529 /* LastWindowPosition.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5AEB1642D5BE7BF00513529 /* LastWindowPosition.swift */; }; A5B30539299BEAAB0047F10C /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = A5B30538299BEAAB0047F10C /* Assets.xcassets */; }; A5B4EA852DFE691B0022C3A2 /* NSMenuItem+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5B4EA842DFE69140022C3A2 /* NSMenuItem+Extension.swift */; }; + A5BB78B92DF9D8CE009AC3FA /* QuickTerminalSize.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5BB78B82DF9D8CE009AC3FA /* QuickTerminalSize.swift */; }; A5CA378C2D2A4DEB00931030 /* KeyboardLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5CA378B2D2A4DE800931030 /* KeyboardLayout.swift */; }; A5CA378E2D31D6C300931030 /* Weak.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5CA378D2D31D6C100931030 /* Weak.swift */; }; A5CBD0562C9E65B80017A1AE /* DraggableWindowView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5CBD0552C9E65A50017A1AE /* DraggableWindowView.swift */; }; @@ -237,6 +238,7 @@ A5B30538299BEAAB0047F10C /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; A5B3053D299BEAAB0047F10C /* Ghostty.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Ghostty.entitlements; sourceTree = ""; }; A5B4EA842DFE69140022C3A2 /* NSMenuItem+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSMenuItem+Extension.swift"; sourceTree = ""; }; + A5BB78B82DF9D8CE009AC3FA /* QuickTerminalSize.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QuickTerminalSize.swift; sourceTree = ""; }; A5CA378B2D2A4DE800931030 /* KeyboardLayout.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeyboardLayout.swift; sourceTree = ""; }; A5CA378D2D31D6C100931030 /* Weak.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Weak.swift; sourceTree = ""; }; A5CBD0552C9E65A50017A1AE /* DraggableWindowView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DraggableWindowView.swift; sourceTree = ""; }; @@ -608,6 +610,7 @@ A5CBD0632CA122E70017A1AE /* QuickTerminalPosition.swift */, A52FFF562CA90481000C6A5B /* QuickTerminalScreen.swift */, A5CBD05F2CA0C9080017A1AE /* QuickTerminalWindow.swift */, + A5BB78B82DF9D8CE009AC3FA /* QuickTerminalSize.swift */, ); path = QuickTerminal; sourceTree = ""; @@ -865,6 +868,8 @@ A53A297B2DB2E49700B6E02C /* CommandPalette.swift in Sources */, A55B7BB829B6F53A0055DE60 /* Package.swift in Sources */, A51B78472AF4B58B00F3EDB9 /* TitlebarTabsVenturaTerminalWindow.swift in Sources */, + A51B78472AF4B58B00F3EDB9 /* TerminalWindow.swift in Sources */, + A5BB78B92DF9D8CE009AC3FA /* QuickTerminalSize.swift in Sources */, A57D79272C9C879B001D522E /* SecureInput.swift in Sources */, A5CEAFDC29B8009000646FDA /* SplitView.swift in Sources */, A5593FE12DF8D74000B47B10 /* HiddenTitlebarTerminalWindow.swift in Sources */, diff --git a/macos/Sources/Features/QuickTerminal/QuickTerminalController.swift b/macos/Sources/Features/QuickTerminal/QuickTerminalController.swift index 3bd8bc18f..af2032a75 100644 --- a/macos/Sources/Features/QuickTerminal/QuickTerminalController.swift +++ b/macos/Sources/Features/QuickTerminal/QuickTerminalController.swift @@ -109,7 +109,7 @@ class QuickTerminalController: BaseTerminalController { syncAppearance() // Setup our initial size based on our configured position - position.setLoaded(window) + position.setLoaded(window, size: derivedConfig.quickTerminalSize) // Setup our content window.contentView = NSHostingView(rootView: TerminalView( @@ -198,7 +198,7 @@ class QuickTerminalController: BaseTerminalController { // We use the actual screen the window is on for this, since it should // be on the proper screen. guard let screen = window?.screen ?? NSScreen.main else { return frameSize } - return position.restrictFrameSize(frameSize, on: screen) + return position.restrictFrameSize(frameSize, on: screen, terminalSize: derivedConfig.quickTerminalSize) } // MARK: Base Controller Overrides @@ -326,7 +326,7 @@ class QuickTerminalController: BaseTerminalController { } // Move our window off screen to the top - position.setInitial(in: window, on: screen) + position.setInitial(in: window, on: screen, terminalSize: derivedConfig.quickTerminalSize) // We need to set our window level to a high value. In testing, only // popUpMenu and above do what we want. This gets it above the menu bar @@ -357,7 +357,7 @@ class QuickTerminalController: BaseTerminalController { NSAnimationContext.runAnimationGroup({ context in context.duration = derivedConfig.quickTerminalAnimationDuration context.timingFunction = .init(name: .easeIn) - position.setFinal(in: window.animator(), on: screen) + position.setFinal(in: window.animator(), on: screen, terminalSize: derivedConfig.quickTerminalSize) }, completionHandler: { // There is a very minor delay here so waiting at least an event loop tick // keeps us safe from the view not being on the window. @@ -481,7 +481,7 @@ class QuickTerminalController: BaseTerminalController { NSAnimationContext.runAnimationGroup({ context in context.duration = derivedConfig.quickTerminalAnimationDuration context.timingFunction = .init(name: .easeIn) - position.setInitial(in: window.animator(), on: screen) + position.setInitial(in: window.animator(), on: screen, terminalSize: derivedConfig.quickTerminalSize) }, completionHandler: { // This causes the window to be removed from the screen list and macOS // handles what should be focused next. @@ -612,6 +612,7 @@ class QuickTerminalController: BaseTerminalController { let quickTerminalAnimationDuration: Double let quickTerminalAutoHide: Bool let quickTerminalSpaceBehavior: QuickTerminalSpaceBehavior + let quickTerminalSize: QuickTerminalSize let backgroundOpacity: Double init() { @@ -619,6 +620,7 @@ class QuickTerminalController: BaseTerminalController { self.quickTerminalAnimationDuration = 0.2 self.quickTerminalAutoHide = true self.quickTerminalSpaceBehavior = .move + self.quickTerminalSize = QuickTerminalSize() self.backgroundOpacity = 1.0 } @@ -627,6 +629,7 @@ class QuickTerminalController: BaseTerminalController { self.quickTerminalAnimationDuration = config.quickTerminalAnimationDuration self.quickTerminalAutoHide = config.quickTerminalAutoHide self.quickTerminalSpaceBehavior = config.quickTerminalSpaceBehavior + self.quickTerminalSize = config.quickTerminalSize self.backgroundOpacity = config.backgroundOpacity } } diff --git a/macos/Sources/Features/QuickTerminal/QuickTerminalPosition.swift b/macos/Sources/Features/QuickTerminal/QuickTerminalPosition.swift index 7ba124a30..a1da81758 100644 --- a/macos/Sources/Features/QuickTerminal/QuickTerminalPosition.swift +++ b/macos/Sources/Features/QuickTerminal/QuickTerminalPosition.swift @@ -8,72 +8,58 @@ enum QuickTerminalPosition : String { case center /// Set the loaded state for a window. - func setLoaded(_ window: NSWindow) { + func setLoaded(_ window: NSWindow, size: QuickTerminalSize) { guard let screen = window.screen ?? NSScreen.main else { return } - switch (self) { - case .top, .bottom: - window.setFrame(.init( - origin: window.frame.origin, - size: .init( - width: screen.frame.width, - height: screen.frame.height / 4) - ), display: false) - - case .left, .right: - window.setFrame(.init( - origin: window.frame.origin, - size: .init( - width: screen.frame.width / 4, - height: screen.frame.height) - ), display: false) - - case .center: - window.setFrame(.init( - origin: window.frame.origin, - size: .init( - width: screen.frame.width / 2, - height: screen.frame.height / 3) - ), display: false) - } + let dimensions = size.calculate(position: self, screenDimensions: screen.frame.size) + window.setFrame(.init( + origin: window.frame.origin, + size: .init( + width: dimensions.width, + height: dimensions.height) + ), display: false) } /// Set the initial state for a window for animating out of this position. - func setInitial(in window: NSWindow, on screen: NSScreen) { + func setInitial(in window: NSWindow, on screen: NSScreen, terminalSize: QuickTerminalSize) { // We always start invisible window.alphaValue = 0 // Position depends window.setFrame(.init( origin: initialOrigin(for: window, on: screen), - size: restrictFrameSize(window.frame.size, on: screen) + size: restrictFrameSize(window.frame.size, on: screen, terminalSize: terminalSize) ), display: false) } /// Set the final state for a window in this position. - func setFinal(in window: NSWindow, on screen: NSScreen) { + func setFinal(in window: NSWindow, on screen: NSScreen, terminalSize: QuickTerminalSize) { // We always end visible window.alphaValue = 1 // Position depends window.setFrame(.init( origin: finalOrigin(for: window, on: screen), - size: restrictFrameSize(window.frame.size, on: screen) + size: restrictFrameSize(window.frame.size, on: screen, terminalSize: terminalSize) ), display: true) } /// Restrict the frame size during resizing. - func restrictFrameSize(_ size: NSSize, on screen: NSScreen) -> NSSize { + func restrictFrameSize(_ size: NSSize, on screen: NSScreen, terminalSize: QuickTerminalSize) -> NSSize { var finalSize = size + let dimensions = terminalSize.calculate(position: self, screenDimensions: screen.frame.size) + switch (self) { case .top, .bottom: - finalSize.width = screen.frame.width + finalSize.width = dimensions.width + finalSize.height = dimensions.height case .left, .right: - finalSize.height = screen.visibleFrame.height + finalSize.width = dimensions.width + finalSize.height = dimensions.height case .center: - finalSize.width = screen.frame.width / 2 - finalSize.height = screen.frame.height / 3 + finalSize.width = dimensions.width + finalSize.height = dimensions.height } return finalSize @@ -83,16 +69,16 @@ enum QuickTerminalPosition : String { func initialOrigin(for window: NSWindow, on screen: NSScreen) -> CGPoint { switch (self) { case .top: - return .init(x: screen.frame.minX, y: screen.frame.maxY) + return .init(x: screen.frame.origin.x + (screen.frame.width - window.frame.width) / 2, y: screen.frame.maxY) case .bottom: - return .init(x: screen.frame.minX, y: -window.frame.height) + return .init(x: screen.frame.origin.x + (screen.frame.width - window.frame.width) / 2, y: -window.frame.height) case .left: - return .init(x: screen.frame.minX-window.frame.width, y: 0) + return .init(x: screen.frame.minX-window.frame.width, y: screen.frame.origin.y + (screen.frame.height - window.frame.height) / 2) case .right: - return .init(x: screen.frame.maxX, y: 0) + return .init(x: screen.frame.maxX, y: screen.frame.origin.y + (screen.frame.height - window.frame.height) / 2) case .center: return .init(x: screen.visibleFrame.origin.x + (screen.visibleFrame.width - window.frame.width) / 2, y: screen.visibleFrame.height - window.frame.width) @@ -103,16 +89,16 @@ enum QuickTerminalPosition : String { func finalOrigin(for window: NSWindow, on screen: NSScreen) -> CGPoint { switch (self) { case .top: - return .init(x: screen.frame.minX, y: screen.visibleFrame.maxY - window.frame.height) + return .init(x: screen.frame.origin.x + (screen.frame.width - window.frame.width) / 2, y: screen.visibleFrame.maxY - window.frame.height) case .bottom: - return .init(x: screen.frame.minX, y: screen.frame.minY) + return .init(x: screen.frame.origin.x + (screen.frame.width - window.frame.width) / 2, y: screen.frame.minY) case .left: - return .init(x: screen.frame.minX, y: window.frame.origin.y) + return .init(x: screen.frame.minX, y: screen.frame.origin.y + (screen.frame.height - window.frame.height) / 2) case .right: - return .init(x: screen.visibleFrame.maxX - window.frame.width, y: window.frame.origin.y) + return .init(x: screen.visibleFrame.maxX - window.frame.width, y: screen.frame.origin.y + (screen.frame.height - window.frame.height) / 2) case .center: return .init(x: screen.visibleFrame.origin.x + (screen.visibleFrame.width - window.frame.width) / 2, y: screen.visibleFrame.origin.y + (screen.visibleFrame.height - window.frame.height) / 2) diff --git a/macos/Sources/Features/QuickTerminal/QuickTerminalSize.swift b/macos/Sources/Features/QuickTerminal/QuickTerminalSize.swift new file mode 100644 index 000000000..c86f15b84 --- /dev/null +++ b/macos/Sources/Features/QuickTerminal/QuickTerminalSize.swift @@ -0,0 +1,80 @@ +import Cocoa +import GhosttyKit + +struct QuickTerminalSize { + let primary: Size? + let secondary: Size? + + init(primary: Size? = nil, secondary: Size? = nil) { + self.primary = primary + self.secondary = secondary + } + + init(from cStruct: ghostty_config_quick_terminal_size_s) { + self.primary = cStruct.primary_type == 0 ? nil : Size(type: cStruct.primary_type, value: cStruct.primary_value) + self.secondary = cStruct.secondary_type == 0 ? nil : Size(type: cStruct.secondary_type, value: cStruct.secondary_value) + } + + enum Size { + case percentage(Float) + case pixels(UInt32) + + init?(type: UInt8, value: Float) { + switch type { + case 1: + self = .percentage(value) + case 2: + self = .pixels(UInt32(value)) + default: + return nil + } + } + + func toPixels(parentDimension: CGFloat) -> CGFloat { + switch self { + case .percentage(let value): + return parentDimension * CGFloat(value) / 100.0 + case .pixels(let value): + return CGFloat(value) + } + } + } + + struct Dimensions { + let width: CGFloat + let height: CGFloat + } + + func calculate(position: QuickTerminalPosition, screenDimensions: CGSize) -> Dimensions { + let dims = Dimensions(width: screenDimensions.width, height: screenDimensions.height) + + switch position { + case .left, .right: + return Dimensions( + width: primary?.toPixels(parentDimension: dims.width) ?? 400, + height: secondary?.toPixels(parentDimension: dims.height) ?? dims.height + ) + + case .top, .bottom: + return Dimensions( + width: secondary?.toPixels(parentDimension: dims.width) ?? dims.width, + height: primary?.toPixels(parentDimension: dims.height) ?? 400 + ) + + case .center: + if dims.width >= dims.height { + // Landscape + return Dimensions( + width: primary?.toPixels(parentDimension: dims.width) ?? 800, + height: secondary?.toPixels(parentDimension: dims.height) ?? 400 + ) + } else { + // Portrait + return Dimensions( + width: secondary?.toPixels(parentDimension: dims.width) ?? 400, + height: primary?.toPixels(parentDimension: dims.height) ?? 800 + ) + } + } + } +} \ No newline at end of file diff --git a/macos/Sources/Ghostty/Ghostty.Config.swift b/macos/Sources/Ghostty/Ghostty.Config.swift index 241c10632..6050241f8 100644 --- a/macos/Sources/Ghostty/Ghostty.Config.swift +++ b/macos/Sources/Ghostty/Ghostty.Config.swift @@ -475,6 +475,14 @@ extension Ghostty { let str = String(cString: ptr) return QuickTerminalSpaceBehavior(fromGhosttyConfig: str) ?? .move } + + var quickTerminalSize: QuickTerminalSize { + guard let config = self.config else { return QuickTerminalSize() } + var v = ghostty_config_quick_terminal_size_s() + let key = "quick-terminal-size" + guard ghostty_config_get(config, &v, key, UInt(key.count)) else { return QuickTerminalSize() } + return QuickTerminalSize(from: v) + } #endif var resizeOverlay: ResizeOverlay { diff --git a/src/config/Config.zig b/src/config/Config.zig index ef8f48ee9..3169ba3e8 100644 --- a/src/config/Config.zig +++ b/src/config/Config.zig @@ -6705,6 +6705,35 @@ pub const QuickTerminalSize = struct { height: u32, }; + /// C API structure for QuickTerminalSize + pub const C = extern struct { + primary_type: u8, // 0 = none, 1 = percentage, 2 = pixels + primary_value: f32, + secondary_type: u8, // 0 = none, 1 = percentage, 2 = pixels + secondary_value: f32, + }; + + pub fn cval(self: QuickTerminalSize) C { + return .{ + .primary_type = if (self.primary) |p| switch (p) { + .percentage => 1, + .pixels => 2, + } else 0, + .primary_value = if (self.primary) |p| switch (p) { + .percentage => |v| v, + .pixels => |v| @floatFromInt(v), + } else 0, + .secondary_type = if (self.secondary) |s| switch (s) { + .percentage => 1, + .pixels => 2, + } else 0, + .secondary_value = if (self.secondary) |s| switch (s) { + .percentage => |v| v, + .pixels => |v| @floatFromInt(v), + } else 0, + }; + } + pub fn calculate( self: QuickTerminalSize, position: QuickTerminalPosition, From 8a5d4cd19628ffced0e9cfca025224438782bb54 Mon Sep 17 00:00:00 2001 From: Friedrich Stoltzfus Date: Thu, 12 Jun 2025 12:47:03 -0400 Subject: [PATCH 2/6] macOS: update zig and c structs for quick terminal size Applying the feedback given by @pluiedev to use an enum to specify the type of quick terminal size configuration given (pixels or percentage). Updated the Swift code to work with the enum as well. --- include/ghostty.h | 17 +++++-- .../QuickTerminal/QuickTerminalSize.swift | 44 +++++++++-------- src/config/Config.zig | 49 +++++++++++-------- 3 files changed, 66 insertions(+), 44 deletions(-) diff --git a/include/ghostty.h b/include/ghostty.h index a2f2c068e..d24d0ee28 100644 --- a/include/ghostty.h +++ b/include/ghostty.h @@ -446,11 +446,20 @@ typedef struct { } ghostty_config_palette_s; // config.QuickTerminalSize +typedef enum { + GHOSTTY_QUICK_TERMINAL_SIZE_NONE, + GHOSTTY_QUICK_TERMINAL_SIZE_PERCENTAGE, + GHOSTTY_QUICK_TERMINAL_SIZE_PIXELS, +} ghostty_quick_terminal_size_e; + typedef struct { - uint8_t primary_type; // 0 = none, 1 = percentage, 2 = pixels - float primary_value; - uint8_t secondary_type; // 0 = none, 1 = percentage, 2 = pixels - float secondary_value; + ghostty_quick_terminal_size_e type; + uint32_t value; +} ghostty_quick_terminal_size_u; + +typedef struct { + ghostty_quick_terminal_size_u primary; + ghostty_quick_terminal_size_u secondary; } ghostty_config_quick_terminal_size_s; // apprt.Target.Key diff --git a/macos/Sources/Features/QuickTerminal/QuickTerminalSize.swift b/macos/Sources/Features/QuickTerminal/QuickTerminalSize.swift index c86f15b84..b2d39e8eb 100644 --- a/macos/Sources/Features/QuickTerminal/QuickTerminalSize.swift +++ b/macos/Sources/Features/QuickTerminal/QuickTerminalSize.swift @@ -1,35 +1,39 @@ -import Cocoa import GhosttyKit struct QuickTerminalSize { let primary: Size? let secondary: Size? - + init(primary: Size? = nil, secondary: Size? = nil) { self.primary = primary self.secondary = secondary } - + init(from cStruct: ghostty_config_quick_terminal_size_s) { - self.primary = cStruct.primary_type == 0 ? nil : Size(type: cStruct.primary_type, value: cStruct.primary_value) - self.secondary = cStruct.secondary_type == 0 ? nil : Size(type: cStruct.secondary_type, value: cStruct.secondary_value) + self.primary = Size(from: cStruct.primary) + self.secondary = Size(from: cStruct.secondary) } - + enum Size { case percentage(Float) case pixels(UInt32) - - init?(type: UInt8, value: Float) { - switch type { - case 1: - self = .percentage(value) - case 2: - self = .pixels(UInt32(value)) + + init?(from cStruct: ghostty_quick_terminal_size_u) { + switch cStruct.type { + case GHOSTTY_QUICK_TERMINAL_SIZE_NONE: + return nil + case GHOSTTY_QUICK_TERMINAL_SIZE_PERCENTAGE: + let floatValue = withUnsafePointer(to: cStruct.value) { ptr in + ptr.withMemoryRebound(to: Float.self, capacity: 1) { $0.pointee } + } + self = .percentage(floatValue) + case GHOSTTY_QUICK_TERMINAL_SIZE_PIXELS: + self = .pixels(cStruct.value) default: return nil } } - + func toPixels(parentDimension: CGFloat) -> CGFloat { switch self { case .percentage(let value): @@ -39,28 +43,28 @@ struct QuickTerminalSize { } } } - + struct Dimensions { let width: CGFloat let height: CGFloat } - + func calculate(position: QuickTerminalPosition, screenDimensions: CGSize) -> Dimensions { let dims = Dimensions(width: screenDimensions.width, height: screenDimensions.height) - + switch position { case .left, .right: return Dimensions( width: primary?.toPixels(parentDimension: dims.width) ?? 400, height: secondary?.toPixels(parentDimension: dims.height) ?? dims.height ) - + case .top, .bottom: return Dimensions( width: secondary?.toPixels(parentDimension: dims.width) ?? dims.width, height: primary?.toPixels(parentDimension: dims.height) ?? 400 ) - + case .center: if dims.width >= dims.height { // Landscape @@ -77,4 +81,4 @@ struct QuickTerminalSize { } } } -} \ No newline at end of file +} diff --git a/src/config/Config.zig b/src/config/Config.zig index 3169ba3e8..dcc39b3f6 100644 --- a/src/config/Config.zig +++ b/src/config/Config.zig @@ -6707,30 +6707,39 @@ pub const QuickTerminalSize = struct { /// C API structure for QuickTerminalSize pub const C = extern struct { - primary_type: u8, // 0 = none, 1 = percentage, 2 = pixels - primary_value: f32, - secondary_type: u8, // 0 = none, 1 = percentage, 2 = pixels - secondary_value: f32, + primary: CSize, + secondary: CSize, + }; + + pub const CSize = extern struct { + type: Type, + value: u32, + + pub const Type = enum(u8) { none, percentage, pixels }; + + fn none() CSize { + return .{ .type = .none, .value = 0 }; + } + + fn percentage(v: f32) CSize { + return .{ .type = .percentage, .value = @bitCast(v) }; + } + + fn pixels(v: u32) CSize { + return .{ .type = .pixels, .value = v }; + } }; pub fn cval(self: QuickTerminalSize) C { return .{ - .primary_type = if (self.primary) |p| switch (p) { - .percentage => 1, - .pixels => 2, - } else 0, - .primary_value = if (self.primary) |p| switch (p) { - .percentage => |v| v, - .pixels => |v| @floatFromInt(v), - } else 0, - .secondary_type = if (self.secondary) |s| switch (s) { - .percentage => 1, - .pixels => 2, - } else 0, - .secondary_value = if (self.secondary) |s| switch (s) { - .percentage => |v| v, - .pixels => |v| @floatFromInt(v), - } else 0, + .primary = if (self.primary) |p| switch (p) { + .percentage => |v| CSize.percentage(v), + .pixels => |v| CSize.pixels(v), + } else CSize.none(), + .secondary = if (self.secondary) |s| switch (s) { + .percentage => |v| CSize.percentage(v), + .pixels => |v| CSize.pixels(v), + } else CSize.none(), }; } From 4c5800734b7fed0a9604a8a33daabff3ce727075 Mon Sep 17 00:00:00 2001 From: Friedrich Stoltzfus Date: Sat, 21 Jun 2025 10:46:30 -0400 Subject: [PATCH 3/6] macOS: enable quick terminal manual resizing You can now resize the quick terminal both vertically and horizontally. To incorporate adjusting the custom secondary size on the quick terminal we needed to have the ability to resize the width (if from top, bottom, or center), and height (if from right, left, or center). The quick terminal will retain the user's manually adjusted size while the app is open. A new feature with this is that when the secondary size is adjusted (or primary if the quick terminal is center), the size will increase or decrease on both sides of the terminal. --- .../QuickTerminalController.swift | 61 ++++++++++++-- .../QuickTerminal/QuickTerminalPosition.swift | 83 ++++++++++++++----- 2 files changed, 113 insertions(+), 31 deletions(-) diff --git a/macos/Sources/Features/QuickTerminal/QuickTerminalController.swift b/macos/Sources/Features/QuickTerminal/QuickTerminalController.swift index af2032a75..494694da8 100644 --- a/macos/Sources/Features/QuickTerminal/QuickTerminalController.swift +++ b/macos/Sources/Features/QuickTerminal/QuickTerminalController.swift @@ -22,7 +22,7 @@ class QuickTerminalController: BaseTerminalController { private var previousActiveSpace: CGSSpace? = nil /// The window frame saved when the quick terminal's surface tree becomes empty. - /// + /// /// This preserves the user's window size and position when all terminal surfaces /// are closed (e.g., via the `exit` command). When a new surface is created, /// the window will be restored to this frame, preventing SwiftUI from resetting @@ -34,6 +34,9 @@ class QuickTerminalController: BaseTerminalController { /// The configuration derived from the Ghostty config so we don't need to rely on references. private var derivedConfig: DerivedConfig + + /// Tracks if we're currently handling a manual resize to prevent recursion + private var isHandlingResize: Bool = false init(_ ghostty: Ghostty.App, position: QuickTerminalPosition = .top, @@ -76,6 +79,11 @@ class QuickTerminalController: BaseTerminalController { selector: #selector(onNewTab), name: Ghostty.Notification.ghosttyNewTab, object: nil) + center.addObserver( + self, + selector: #selector(windowDidResize(_:)), + name: NSWindow.didResizeNotification, + object: nil) } required init?(coder: NSCoder) { @@ -195,10 +203,45 @@ class QuickTerminalController: BaseTerminalController { } func windowWillResize(_ sender: NSWindow, to frameSize: NSSize) -> NSSize { - // We use the actual screen the window is on for this, since it should - // be on the proper screen. - guard let screen = window?.screen ?? NSScreen.main else { return frameSize } - return position.restrictFrameSize(frameSize, on: screen, terminalSize: derivedConfig.quickTerminalSize) + // Allow unrestricted resizing - users have full control + return frameSize + } + + override func windowDidResize(_ notification: Notification) { + guard let window = notification.object as? NSWindow, + window == self.window, + visible, + !isHandlingResize else { return } + + // For centered positions (top, bottom, center), we need to recenter the window + // when it's manually resized to maintain proper positioning + switch position { + case .top, .bottom, .center: + recenterWindow(window) + case .left, .right: + // For side positions, we may need to adjust vertical centering + recenterWindowVertically(window) + } + } + + private func recenterWindow(_ window: NSWindow) { + guard let screen = window.screen ?? NSScreen.main else { return } + + isHandlingResize = true + defer { isHandlingResize = false } + + let newOrigin = position.centeredOrigin(for: window, on: screen) + window.setFrameOrigin(newOrigin) + } + + private func recenterWindowVertically(_ window: NSWindow) { + guard let screen = window.screen ?? NSScreen.main else { return } + + isHandlingResize = true + defer { isHandlingResize = false } + + let newOrigin = position.verticallyCenteredOrigin(for: window, on: screen) + window.setFrameOrigin(newOrigin) } // MARK: Base Controller Overrides @@ -320,13 +363,15 @@ class QuickTerminalController: BaseTerminalController { guard let screen = derivedConfig.quickTerminalScreen.screen else { return } // Restore our previous frame if we have one + var preserveSize: NSSize? = nil if let lastClosedFrame { window.setFrame(lastClosedFrame, display: false) + preserveSize = lastClosedFrame.size self.lastClosedFrame = nil } // Move our window off screen to the top - position.setInitial(in: window, on: screen, terminalSize: derivedConfig.quickTerminalSize) + position.setInitial(in: window, on: screen, terminalSize: derivedConfig.quickTerminalSize, preserveSize: preserveSize) // We need to set our window level to a high value. In testing, only // popUpMenu and above do what we want. This gets it above the menu bar @@ -357,7 +402,7 @@ class QuickTerminalController: BaseTerminalController { NSAnimationContext.runAnimationGroup({ context in context.duration = derivedConfig.quickTerminalAnimationDuration context.timingFunction = .init(name: .easeIn) - position.setFinal(in: window.animator(), on: screen, terminalSize: derivedConfig.quickTerminalSize) + position.setFinal(in: window.animator(), on: screen, terminalSize: derivedConfig.quickTerminalSize, preserveSize: preserveSize) }, completionHandler: { // There is a very minor delay here so waiting at least an event loop tick // keeps us safe from the view not being on the window. @@ -481,7 +526,7 @@ class QuickTerminalController: BaseTerminalController { NSAnimationContext.runAnimationGroup({ context in context.duration = derivedConfig.quickTerminalAnimationDuration context.timingFunction = .init(name: .easeIn) - position.setInitial(in: window.animator(), on: screen, terminalSize: derivedConfig.quickTerminalSize) + position.setInitial(in: window.animator(), on: screen, terminalSize: derivedConfig.quickTerminalSize, preserveSize: window.frame.size) }, completionHandler: { // This causes the window to be removed from the screen list and macOS // handles what should be focused next. diff --git a/macos/Sources/Features/QuickTerminal/QuickTerminalPosition.swift b/macos/Sources/Features/QuickTerminal/QuickTerminalPosition.swift index a1da81758..bf7ed4b08 100644 --- a/macos/Sources/Features/QuickTerminal/QuickTerminalPosition.swift +++ b/macos/Sources/Features/QuickTerminal/QuickTerminalPosition.swift @@ -20,49 +20,38 @@ enum QuickTerminalPosition : String { } /// Set the initial state for a window for animating out of this position. - func setInitial(in window: NSWindow, on screen: NSScreen, terminalSize: QuickTerminalSize) { + func setInitial(in window: NSWindow, on screen: NSScreen, terminalSize: QuickTerminalSize, preserveSize: NSSize? = nil) { // We always start invisible window.alphaValue = 0 // Position depends window.setFrame(.init( origin: initialOrigin(for: window, on: screen), - size: restrictFrameSize(window.frame.size, on: screen, terminalSize: terminalSize) + size: configuredFrameSize(on: screen, terminalSize: terminalSize, preserveExisting: preserveSize) ), display: false) } /// Set the final state for a window in this position. - func setFinal(in window: NSWindow, on screen: NSScreen, terminalSize: QuickTerminalSize) { + func setFinal(in window: NSWindow, on screen: NSScreen, terminalSize: QuickTerminalSize, preserveSize: NSSize? = nil) { // We always end visible window.alphaValue = 1 // Position depends window.setFrame(.init( origin: finalOrigin(for: window, on: screen), - size: restrictFrameSize(window.frame.size, on: screen, terminalSize: terminalSize) + size: configuredFrameSize(on: screen, terminalSize: terminalSize, preserveExisting: preserveSize) ), display: true) } - /// Restrict the frame size during resizing. - func restrictFrameSize(_ size: NSSize, on screen: NSScreen, terminalSize: QuickTerminalSize) -> NSSize { - var finalSize = size - let dimensions = terminalSize.calculate(position: self, screenDimensions: screen.frame.size) - - switch (self) { - case .top, .bottom: - finalSize.width = dimensions.width - finalSize.height = dimensions.height - - case .left, .right: - finalSize.width = dimensions.width - finalSize.height = dimensions.height - - case .center: - finalSize.width = dimensions.width - finalSize.height = dimensions.height + /// Get the configured frame size for initial positioning and animations. + func configuredFrameSize(on screen: NSScreen, terminalSize: QuickTerminalSize, preserveExisting: NSSize? = nil) -> NSSize { + // If we have existing dimensions from manual resizing, preserve them + if let existing = preserveExisting, existing.width > 0 && existing.height > 0 { + return existing } - - return finalSize + + let dimensions = terminalSize.calculate(position: self, screenDimensions: screen.frame.size) + return NSSize(width: dimensions.width, height: dimensions.height) } /// The initial point origin for this position. @@ -122,4 +111,52 @@ enum QuickTerminalPosition : String { case .right: self == .top || self == .bottom } } + + /// Calculate the centered origin for a window, keeping it properly positioned after manual resizing + func centeredOrigin(for window: NSWindow, on screen: NSScreen) -> CGPoint { + switch self { + case .top: + return CGPoint( + x: screen.frame.origin.x + (screen.frame.width - window.frame.width) / 2, + y: window.frame.origin.y // Keep the same Y position + ) + + case .bottom: + return CGPoint( + x: screen.frame.origin.x + (screen.frame.width - window.frame.width) / 2, + y: window.frame.origin.y // Keep the same Y position + ) + + case .center: + return CGPoint( + x: screen.visibleFrame.origin.x + (screen.visibleFrame.width - window.frame.width) / 2, + y: screen.visibleFrame.origin.y + (screen.visibleFrame.height - window.frame.height) / 2 + ) + + case .left, .right: + // For left/right positions, only adjust horizontal centering if needed + return window.frame.origin + } + } + + /// Calculate the vertically centered origin for side-positioned windows + func verticallyCenteredOrigin(for window: NSWindow, on screen: NSScreen) -> CGPoint { + switch self { + case .left: + return CGPoint( + x: window.frame.origin.x, // Keep the same X position + y: screen.frame.origin.y + (screen.frame.height - window.frame.height) / 2 + ) + + case .right: + return CGPoint( + x: window.frame.origin.x, // Keep the same X position + y: screen.frame.origin.y + (screen.frame.height - window.frame.height) / 2 + ) + + case .top, .bottom, .center: + // These positions don't need vertical recentering during resize + return window.frame.origin + } + } } From ecafe92516bf98c8f4bb9a8ef20384815d9f925e Mon Sep 17 00:00:00 2001 From: Friedrich Stoltzfus Date: Thu, 26 Jun 2025 10:30:30 -0400 Subject: [PATCH 4/6] use decl literals as suggested Applied from the code review Co-authored-by: Leah Amelia Chen --- src/config/Config.zig | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/src/config/Config.zig b/src/config/Config.zig index dcc39b3f6..f461338f6 100644 --- a/src/config/Config.zig +++ b/src/config/Config.zig @@ -6717,9 +6717,7 @@ pub const QuickTerminalSize = struct { pub const Type = enum(u8) { none, percentage, pixels }; - fn none() CSize { - return .{ .type = .none, .value = 0 }; - } + pub const none: CSize = .{ .type = .none, .value = 0 }; fn percentage(v: f32) CSize { return .{ .type = .percentage, .value = @bitCast(v) }; @@ -6733,13 +6731,13 @@ pub const QuickTerminalSize = struct { pub fn cval(self: QuickTerminalSize) C { return .{ .primary = if (self.primary) |p| switch (p) { - .percentage => |v| CSize.percentage(v), - .pixels => |v| CSize.pixels(v), - } else CSize.none(), + .percentage => |v| .percentage(v), + .pixels => |v| .pixels(v), + } else .none, .secondary = if (self.secondary) |s| switch (s) { - .percentage => |v| CSize.percentage(v), - .pixels => |v| CSize.pixels(v), - } else CSize.none(), + .percentage => |v| .percentage(v), + .pixels => |v| .pixels(v), + } else .none, }; } From 982d1bc27dc87d1913f5d8341c35c9da2e0e1acf Mon Sep 17 00:00:00 2001 From: Friedrich Stoltzfus Date: Thu, 26 Jun 2025 10:51:36 -0400 Subject: [PATCH 5/6] macOS: Round quick terminal window position coordinates This resolves an issue where the right side of the quick terminal would not resize equally to the left side if adjusting the width from the left side. --- .../QuickTerminal/QuickTerminalPosition.swift | 32 +++++++++---------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/macos/Sources/Features/QuickTerminal/QuickTerminalPosition.swift b/macos/Sources/Features/QuickTerminal/QuickTerminalPosition.swift index bf7ed4b08..418d8da94 100644 --- a/macos/Sources/Features/QuickTerminal/QuickTerminalPosition.swift +++ b/macos/Sources/Features/QuickTerminal/QuickTerminalPosition.swift @@ -58,19 +58,19 @@ enum QuickTerminalPosition : String { func initialOrigin(for window: NSWindow, on screen: NSScreen) -> CGPoint { switch (self) { case .top: - return .init(x: screen.frame.origin.x + (screen.frame.width - window.frame.width) / 2, y: screen.frame.maxY) + return .init(x: round(screen.frame.origin.x + (screen.frame.width - window.frame.width) / 2), y: screen.frame.maxY) case .bottom: - return .init(x: screen.frame.origin.x + (screen.frame.width - window.frame.width) / 2, y: -window.frame.height) + return .init(x: round(screen.frame.origin.x + (screen.frame.width - window.frame.width) / 2), y: -window.frame.height) case .left: - return .init(x: screen.frame.minX-window.frame.width, y: screen.frame.origin.y + (screen.frame.height - window.frame.height) / 2) + return .init(x: screen.frame.minX-window.frame.width, y: round(screen.frame.origin.y + (screen.frame.height - window.frame.height) / 2)) case .right: - return .init(x: screen.frame.maxX, y: screen.frame.origin.y + (screen.frame.height - window.frame.height) / 2) + return .init(x: screen.frame.maxX, y: round(screen.frame.origin.y + (screen.frame.height - window.frame.height) / 2)) case .center: - return .init(x: screen.visibleFrame.origin.x + (screen.visibleFrame.width - window.frame.width) / 2, y: screen.visibleFrame.height - window.frame.width) + return .init(x: round(screen.visibleFrame.origin.x + (screen.visibleFrame.width - window.frame.width) / 2), y: screen.visibleFrame.height - window.frame.width) } } @@ -78,19 +78,19 @@ enum QuickTerminalPosition : String { func finalOrigin(for window: NSWindow, on screen: NSScreen) -> CGPoint { switch (self) { case .top: - return .init(x: screen.frame.origin.x + (screen.frame.width - window.frame.width) / 2, y: screen.visibleFrame.maxY - window.frame.height) + return .init(x: round(screen.frame.origin.x + (screen.frame.width - window.frame.width) / 2), y: screen.visibleFrame.maxY - window.frame.height) case .bottom: - return .init(x: screen.frame.origin.x + (screen.frame.width - window.frame.width) / 2, y: screen.frame.minY) + return .init(x: round(screen.frame.origin.x + (screen.frame.width - window.frame.width) / 2), y: screen.frame.minY) case .left: - return .init(x: screen.frame.minX, y: screen.frame.origin.y + (screen.frame.height - window.frame.height) / 2) + return .init(x: screen.frame.minX, y: round(screen.frame.origin.y + (screen.frame.height - window.frame.height) / 2)) case .right: - return .init(x: screen.visibleFrame.maxX - window.frame.width, y: screen.frame.origin.y + (screen.frame.height - window.frame.height) / 2) + return .init(x: screen.visibleFrame.maxX - window.frame.width, y: round(screen.frame.origin.y + (screen.frame.height - window.frame.height) / 2)) case .center: - return .init(x: screen.visibleFrame.origin.x + (screen.visibleFrame.width - window.frame.width) / 2, y: screen.visibleFrame.origin.y + (screen.visibleFrame.height - window.frame.height) / 2) + return .init(x: round(screen.visibleFrame.origin.x + (screen.visibleFrame.width - window.frame.width) / 2), y: round(screen.visibleFrame.origin.y + (screen.visibleFrame.height - window.frame.height) / 2)) } } @@ -117,20 +117,20 @@ enum QuickTerminalPosition : String { switch self { case .top: return CGPoint( - x: screen.frame.origin.x + (screen.frame.width - window.frame.width) / 2, + x: round(screen.frame.origin.x + (screen.frame.width - window.frame.width) / 2), y: window.frame.origin.y // Keep the same Y position ) case .bottom: return CGPoint( - x: screen.frame.origin.x + (screen.frame.width - window.frame.width) / 2, + x: round(screen.frame.origin.x + (screen.frame.width - window.frame.width) / 2), y: window.frame.origin.y // Keep the same Y position ) case .center: return CGPoint( - x: screen.visibleFrame.origin.x + (screen.visibleFrame.width - window.frame.width) / 2, - y: screen.visibleFrame.origin.y + (screen.visibleFrame.height - window.frame.height) / 2 + x: round(screen.visibleFrame.origin.x + (screen.visibleFrame.width - window.frame.width) / 2), + y: round(screen.visibleFrame.origin.y + (screen.visibleFrame.height - window.frame.height) / 2) ) case .left, .right: @@ -145,13 +145,13 @@ enum QuickTerminalPosition : String { case .left: return CGPoint( x: window.frame.origin.x, // Keep the same X position - y: screen.frame.origin.y + (screen.frame.height - window.frame.height) / 2 + y: round(screen.frame.origin.y + (screen.frame.height - window.frame.height) / 2) ) case .right: return CGPoint( x: window.frame.origin.x, // Keep the same X position - y: screen.frame.origin.y + (screen.frame.height - window.frame.height) / 2 + y: round(screen.frame.origin.y + (screen.frame.height - window.frame.height) / 2) ) case .top, .bottom, .center: From 270cef24054f8aff29c52622fde9edab4a039a91 Mon Sep 17 00:00:00 2001 From: Friedrich Stoltzfus Date: Mon, 30 Jun 2025 16:35:31 -0400 Subject: [PATCH 6/6] macOS: rename c struct, relocate QuickTerminalSize file Renamed the ghostty_quick_terminal_size_u to ghostty_quick_terminal_size_s and moved the QuickTerminalSize file to the Ghostty folder as requested. --- include/ghostty.h | 6 +++--- macos/Ghostty.xcodeproj/project.pbxproj | 10 +++++----- .../QuickTerminal => Ghostty}/QuickTerminalSize.swift | 2 +- 3 files changed, 9 insertions(+), 9 deletions(-) rename macos/Sources/{Features/QuickTerminal => Ghostty}/QuickTerminalSize.swift (97%) diff --git a/include/ghostty.h b/include/ghostty.h index d24d0ee28..1c6f6f538 100644 --- a/include/ghostty.h +++ b/include/ghostty.h @@ -455,11 +455,11 @@ typedef enum { typedef struct { ghostty_quick_terminal_size_e type; uint32_t value; -} ghostty_quick_terminal_size_u; +} ghostty_quick_terminal_size_s; typedef struct { - ghostty_quick_terminal_size_u primary; - ghostty_quick_terminal_size_u secondary; + ghostty_quick_terminal_size_s primary; + ghostty_quick_terminal_size_s secondary; } ghostty_config_quick_terminal_size_s; // apprt.Target.Key diff --git a/macos/Ghostty.xcodeproj/project.pbxproj b/macos/Ghostty.xcodeproj/project.pbxproj index 8c9ccebc8..ee6679e50 100644 --- a/macos/Ghostty.xcodeproj/project.pbxproj +++ b/macos/Ghostty.xcodeproj/project.pbxproj @@ -101,8 +101,8 @@ A5A6F72A2CC41B8900B232A5 /* AppInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5A6F7292CC41B8700B232A5 /* AppInfo.swift */; }; A5AEB1652D5BE7D000513529 /* LastWindowPosition.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5AEB1642D5BE7BF00513529 /* LastWindowPosition.swift */; }; A5B30539299BEAAB0047F10C /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = A5B30538299BEAAB0047F10C /* Assets.xcassets */; }; + A5B4EA852DFE691B0022C3A2 /* NSMenuItem+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5B4EA842DFE69140022C3A2 /* NSMenuItem+Extension.swift */; }; A5BB78B92DF9D8CE009AC3FA /* QuickTerminalSize.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5BB78B82DF9D8CE009AC3FA /* QuickTerminalSize.swift */; }; - A5B4EA852DFE691B0022C3A2 /* NSMenuItem+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5B4EA842DFE69140022C3A2 /* NSMenuItem+Extension.swift */; }; A5CA378C2D2A4DEB00931030 /* KeyboardLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5CA378B2D2A4DE800931030 /* KeyboardLayout.swift */; }; A5CA378E2D31D6C300931030 /* Weak.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5CA378D2D31D6C100931030 /* Weak.swift */; }; A5CBD0562C9E65B80017A1AE /* DraggableWindowView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5CBD0552C9E65A50017A1AE /* DraggableWindowView.swift */; }; @@ -237,8 +237,8 @@ A5B30531299BEAAA0047F10C /* Ghostty.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Ghostty.app; sourceTree = BUILT_PRODUCTS_DIR; }; A5B30538299BEAAB0047F10C /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; A5B3053D299BEAAB0047F10C /* Ghostty.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Ghostty.entitlements; sourceTree = ""; }; + A5B4EA842DFE69140022C3A2 /* NSMenuItem+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSMenuItem+Extension.swift"; sourceTree = ""; }; A5BB78B82DF9D8CE009AC3FA /* QuickTerminalSize.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QuickTerminalSize.swift; sourceTree = ""; }; - A5B4EA842DFE69140022C3A2 /* NSMenuItem+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSMenuItem+Extension.swift"; sourceTree = ""; }; A5CA378B2D2A4DE800931030 /* KeyboardLayout.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeyboardLayout.swift; sourceTree = ""; }; A5CA378D2D31D6C100931030 /* Weak.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Weak.swift; sourceTree = ""; }; A5CBD0552C9E65A50017A1AE /* DraggableWindowView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DraggableWindowView.swift; sourceTree = ""; }; @@ -464,6 +464,7 @@ A55B7BB429B6F4410055DE60 /* Ghostty */ = { isa = PBXGroup; children = ( + A5BB78B82DF9D8CE009AC3FA /* QuickTerminalSize.swift */, A55B7BB729B6F53A0055DE60 /* Package.swift */, A55B7BBB29B6FC330055DE60 /* SurfaceView.swift */, A5333E212B5A2128008AEFF7 /* SurfaceView_AppKit.swift */, @@ -610,7 +611,6 @@ A5CBD0632CA122E70017A1AE /* QuickTerminalPosition.swift */, A52FFF562CA90481000C6A5B /* QuickTerminalScreen.swift */, A5CBD05F2CA0C9080017A1AE /* QuickTerminalWindow.swift */, - A5BB78B82DF9D8CE009AC3FA /* QuickTerminalSize.swift */, ); path = QuickTerminal; sourceTree = ""; @@ -868,9 +868,9 @@ A53A297B2DB2E49700B6E02C /* CommandPalette.swift in Sources */, A55B7BB829B6F53A0055DE60 /* Package.swift in Sources */, A51B78472AF4B58B00F3EDB9 /* TitlebarTabsVenturaTerminalWindow.swift in Sources */, - A51B78472AF4B58B00F3EDB9 /* TerminalWindow.swift in Sources */, + A51B78472AF4B58B00F3EDB9 /* TitlebarTabsVenturaTerminalWindow.swift in Sources */, A5BB78B92DF9D8CE009AC3FA /* QuickTerminalSize.swift in Sources */, - A51B78472AF4B58B00F3EDB9 /* TerminalWindow.swift in Sources */, + A51B78472AF4B58B00F3EDB9 /* TitlebarTabsVenturaTerminalWindow.swift in Sources */, A5BB78B92DF9D8CE009AC3FA /* QuickTerminalSize.swift in Sources */, A57D79272C9C879B001D522E /* SecureInput.swift in Sources */, A5CEAFDC29B8009000646FDA /* SplitView.swift in Sources */, diff --git a/macos/Sources/Features/QuickTerminal/QuickTerminalSize.swift b/macos/Sources/Ghostty/QuickTerminalSize.swift similarity index 97% rename from macos/Sources/Features/QuickTerminal/QuickTerminalSize.swift rename to macos/Sources/Ghostty/QuickTerminalSize.swift index b2d39e8eb..194407014 100644 --- a/macos/Sources/Features/QuickTerminal/QuickTerminalSize.swift +++ b/macos/Sources/Ghostty/QuickTerminalSize.swift @@ -18,7 +18,7 @@ struct QuickTerminalSize { case percentage(Float) case pixels(UInt32) - init?(from cStruct: ghostty_quick_terminal_size_u) { + init?(from cStruct: ghostty_quick_terminal_size_s) { switch cStruct.type { case GHOSTTY_QUICK_TERMINAL_SIZE_NONE: return nil