Skip to content

Commit

Permalink
feat: customize quick terminal size
Browse files Browse the repository at this point in the history
This commit introduce `quick-terminal-size` option which allows to
define the size of the quick terminal.

It also fixes an issue where the quick terminal position was not
properly updated when reloading the configuration.

Resolves ghostty-org#2384
  • Loading branch information
dmehala committed Dec 28, 2024
1 parent 8de95f6 commit 3da908a
Show file tree
Hide file tree
Showing 8 changed files with 386 additions and 39 deletions.
16 changes: 16 additions & 0 deletions include/ghostty.h
Original file line number Diff line number Diff line change
Expand Up @@ -348,6 +348,22 @@ typedef struct {
size_t len;
} ghostty_config_color_list_s;

// config.QuickTerminalSize
typedef enum {
GHOSTTY_QUICK_TERMINAL_PIXEL_UNIT,
GHOSTTY_QUICK_TERMINAL_PERCENTAGE_UNIT,
} ghostty_config_quick_terminal_unit_e;

typedef struct {
uint16_t value;
ghostty_config_quick_terminal_unit_e unit;
} ghostty_config_quick_terminal_dimension_s;

typedef struct {
ghostty_config_quick_terminal_dimension_s* dimensions;
size_t len;
} ghostty_config_quick_terminal_size_s;

// apprt.Target.Key
typedef enum {
GHOSTTY_TARGET_APP,
Expand Down
4 changes: 4 additions & 0 deletions macos/Ghostty.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@
A5E112952AF73E8A00C6E0C2 /* ClipboardConfirmationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5E112942AF73E8A00C6E0C2 /* ClipboardConfirmationController.swift */; };
A5E112972AF7401B00C6E0C2 /* ClipboardConfirmationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5E112962AF7401B00C6E0C2 /* ClipboardConfirmationView.swift */; };
A5FEB3002ABB69450068369E /* main.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5FEB2FF2ABB69450068369E /* main.swift */; };
AB315D402D1DCC6B0012D326 /* QuickTerminalSize.swift in Sources */ = {isa = PBXBuildFile; fileRef = AB315D3F2D1DCC630012D326 /* QuickTerminalSize.swift */; };
AEE8B3452B9AA39600260C5E /* NSPasteboard+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = AEE8B3442B9AA39600260C5E /* NSPasteboard+Extension.swift */; };
AEF9CE242B6AD07A0017E195 /* TerminalToolbar.swift in Sources */ = {isa = PBXBuildFile; fileRef = AEF9CE232B6AD07A0017E195 /* TerminalToolbar.swift */; };
C159E81D2B66A06B00FDFE9C /* OSColor+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = C159E81C2B66A06B00FDFE9C /* OSColor+Extension.swift */; };
Expand Down Expand Up @@ -183,6 +184,7 @@
A5E112942AF73E8A00C6E0C2 /* ClipboardConfirmationController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ClipboardConfirmationController.swift; sourceTree = "<group>"; };
A5E112962AF7401B00C6E0C2 /* ClipboardConfirmationView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ClipboardConfirmationView.swift; sourceTree = "<group>"; };
A5FEB2FF2ABB69450068369E /* main.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = main.swift; sourceTree = "<group>"; };
AB315D3F2D1DCC630012D326 /* QuickTerminalSize.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QuickTerminalSize.swift; sourceTree = "<group>"; };
AEE8B3442B9AA39600260C5E /* NSPasteboard+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSPasteboard+Extension.swift"; sourceTree = "<group>"; };
AEF9CE232B6AD07A0017E195 /* TerminalToolbar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TerminalToolbar.swift; sourceTree = "<group>"; };
C159E81C2B66A06B00FDFE9C /* OSColor+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "OSColor+Extension.swift"; sourceTree = "<group>"; };
Expand Down Expand Up @@ -434,6 +436,7 @@
A5CBD05A2CA0C5910017A1AE /* QuickTerminal */ = {
isa = PBXGroup;
children = (
AB315D3F2D1DCC630012D326 /* QuickTerminalSize.swift */,
A5CBD05B2CA0C5C70017A1AE /* QuickTerminal.xib */,
A5CBD05D2CA0C5E70017A1AE /* QuickTerminalController.swift */,
A5CBD0632CA122E70017A1AE /* QuickTerminalPosition.swift */,
Expand Down Expand Up @@ -633,6 +636,7 @@
A5333E1C2B5A1CE3008AEFF7 /* CrossKit.swift in Sources */,
A59444F729A2ED5200725BBA /* SettingsView.swift in Sources */,
A56D58862ACDDB4100508D2C /* Ghostty.Shell.swift in Sources */,
AB315D402D1DCC6B0012D326 /* QuickTerminalSize.swift in Sources */,
A5985CD72C320C4500C57AD3 /* String+Extension.swift in Sources */,
A59630A22AF0415000D64628 /* Ghostty.TerminalSplit.swift in Sources */,
A5FEB3002ABB69450068369E /* main.swift in Sources */,
Expand Down
16 changes: 13 additions & 3 deletions macos/Sources/Features/QuickTerminal/QuickTerminalController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ class QuickTerminalController: BaseTerminalController {
override var windowNibName: NSNib.Name? { "QuickTerminal" }

/// The position for the quick terminal.
let position: QuickTerminalPosition
private var position: QuickTerminalPosition

/// The current state of the quick terminal
private(set) var visible: Bool = false
Expand Down Expand Up @@ -72,7 +72,7 @@ class QuickTerminalController: BaseTerminalController {
syncAppearance(ghostty.config)

// Setup our initial size based on our configured position
position.setLoaded(window)
derivedConfig.quickTerminalSize.apply(window, position)

// Setup our content
window.contentView = NSHostingView(rootView: TerminalView(
Expand Down Expand Up @@ -306,6 +306,9 @@ class QuickTerminalController: BaseTerminalController {

private func syncAppearance(_ config: Ghostty.Config) {
guard let window else { return }

// Update the quick terminal size right away
config.quickTerminalSize.apply(window, config.quickTerminalPosition)

// If our window is not visible, then delay this. This is possible specifically
// during state restoration but probably in other scenarios as well. To delay,
Expand Down Expand Up @@ -390,25 +393,32 @@ class QuickTerminalController: BaseTerminalController {

// Update our derived config
self.derivedConfig = DerivedConfig(config)

self.position = self.derivedConfig.quickTerminalPosition

syncAppearance(config)
}

private struct DerivedConfig {
let quickTerminalScreen: QuickTerminalScreen
let quickTerminalAnimationDuration: Double
let quickTerminalAutoHide: Bool
let quickTerminalPosition: QuickTerminalPosition
let quickTerminalSize: QuickTerminalSize

init() {
self.quickTerminalScreen = .main
self.quickTerminalAnimationDuration = 0.2
self.quickTerminalAutoHide = true
self.quickTerminalPosition = .top
self.quickTerminalSize = .init()
}

init(_ config: Ghostty.Config) {
self.quickTerminalScreen = config.quickTerminalScreen
self.quickTerminalAnimationDuration = config.quickTerminalAnimationDuration
self.quickTerminalAutoHide = config.quickTerminalAutoHide
self.quickTerminalPosition = config.quickTerminalPosition
self.quickTerminalSize = config.quickTerminalSize
}
}
}
Expand Down
37 changes: 3 additions & 34 deletions macos/Sources/Features/QuickTerminal/QuickTerminalPosition.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,36 +7,6 @@ enum QuickTerminalPosition : String {
case right
case center

/// Set the loaded state for a window.
func setLoaded(_ window: NSWindow) {
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)
}
}

/// Set the initial state for a window for animating out of this position.
func setInitial(in window: NSWindow, on screen: NSScreen) {
// We always start invisible
Expand Down Expand Up @@ -67,13 +37,12 @@ enum QuickTerminalPosition : String {
switch (self) {
case .top, .bottom:
finalSize.width = screen.frame.width

case .left, .right:
finalSize.height = screen.frame.height

case .center:
finalSize.width = screen.frame.width / 2
finalSize.height = screen.frame.height / 3
break
}

return finalSize
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@ enum QuickTerminalScreen {

case "mouse":
self = .mouse

case "macos-menu-bar":
self = .menuBar

default:
return nil
}
Expand Down
81 changes: 81 additions & 0 deletions macos/Sources/Features/QuickTerminal/QuickTerminalSize.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import Cocoa
import GhosttyKit

class QuickTerminalSize {
enum Size {
case percent(value: Double)
case pixel(value: UInt)

init?(c_dimension: ghostty_config_quick_terminal_dimension_s) {
switch(c_dimension.unit) {
case GHOSTTY_QUICK_TERMINAL_PIXEL_UNIT:
self = .pixel(value: UInt(c_dimension.value))
case GHOSTTY_QUICK_TERMINAL_PERCENTAGE_UNIT:
self = .percent(value: Double(c_dimension.value) / 100.0)
default:
return nil
}
}

func apply(value: CGFloat) -> CGFloat {
switch(self) {
case .pixel(let fixed_size):
return CGFloat(fixed_size);
case .percent(let pct):
return value * pct;
}
}
}

var mainDimension: Size;
var secondDimension: Size;

init() {
self.mainDimension = Size.percent(value: 0.25)
self.secondDimension = Size.percent(value: 0.25)
}

init(config: ghostty_config_quick_terminal_size_s) {
switch (config.len) {
case 1:
self.mainDimension = Size(c_dimension: config.dimensions[0]) ?? Size.percent(value: 0.25)
self.secondDimension = Size.percent(value: 0.25)
case 2:
self.mainDimension = Size(c_dimension: config.dimensions[0]) ?? Size.percent(value: 0.25)
self.secondDimension = Size(c_dimension: config.dimensions[1]) ?? Size.percent(value: 0.25)
default:
self.mainDimension = Size.percent(value: 0.25)
self.secondDimension = Size.percent(value: 0.25)
}
}

/// Set the window size.
func apply(_ window: NSWindow, _ position: QuickTerminalPosition) {
guard let screen = window.screen ?? NSScreen.main else { return }
switch (position) {
case .top, .bottom:
window.setFrame(.init(
origin: window.frame.origin,
size: .init(
width: screen.frame.width,
height: self.mainDimension.apply(value: screen.frame.height))
), display: false)

case .left, .right:
window.setFrame(.init(
origin: window.frame.origin,
size: .init(
width: self.mainDimension.apply(value: screen.frame.width),
height: screen.frame.height)
), display: false)

case .center:
window.setFrame(.init(
origin: window.frame.origin,
size: .init(
width: self.mainDimension.apply(value: screen.frame.width),
height: self.secondDimension.apply(value: screen.frame.height))
), display: false)
}
}
}
8 changes: 8 additions & 0 deletions macos/Sources/Ghostty/Ghostty.Config.swift
Original file line number Diff line number Diff line change
Expand Up @@ -406,6 +406,14 @@ extension Ghostty {
_ = ghostty_config_get(config, &v, key, UInt(key.count))
return v
}

var quickTerminalSize: QuickTerminalSize {
guard let config = self.config else { return .init() }
var v: ghostty_config_quick_terminal_size_s = .init()
let key = "quick-terminal-size"
_ = ghostty_config_get(config, &v, key, UInt(key.count))
return .init(config: v);
}
#endif

var resizeOverlay: ResizeOverlay {
Expand Down
Loading

0 comments on commit 3da908a

Please sign in to comment.