feat: add macos-window-shadow

optionally enable the window shadow (and border) like Terminal.app
This commit is contained in:
Haze Booth
2024-06-07 00:21:09 -04:00
parent 54ccefe838
commit d5e6fcd170
6 changed files with 42 additions and 20 deletions

View File

@ -71,8 +71,8 @@ class TerminalController: NSWindowController, NSWindowDelegate,
super.init(window: nil)
// Initialize our initial surface.
guard let ghostty_app = ghostty.app else { preconditionFailure("app must be loaded") }
self.surfaceTree = tree ?? .leaf(.init(ghostty_app, baseConfig: base))
guard ghostty.app != nil else { preconditionFailure("app must be loaded") }
self.surfaceTree = tree ?? .leaf(.init(ghostty, baseConfig: base))
// Setup our notifications for behaviors
let center = NotificationCenter.default

View File

@ -236,6 +236,14 @@ extension Ghostty {
return v
}
var macosWindowShadow: Bool {
guard let config = self.config else { return false }
var v = false;
let key = "macos-window-shadow"
_ = ghostty_config_get(config, &v, key, UInt(key.count))
return v
}
var backgroundColor: Color {
var rgb: UInt32 = 0
let bg_key = "background"

View File

@ -168,13 +168,13 @@ extension Ghostty {
}
class Leaf: ObservableObject, Equatable, Hashable, Codable {
let app: ghostty_app_t
let app: Ghostty.App
@Published var surface: SurfaceView
weak var parent: SplitNode.Container?
/// Initialize a new leaf which creates a new terminal surface.
init(_ app: ghostty_app_t, baseConfig: SurfaceConfiguration? = nil, uuid: UUID? = nil) {
init(_ app: Ghostty.App, baseConfig: SurfaceConfiguration? = nil, uuid: UUID? = nil) {
self.app = app
self.surface = SurfaceView(app, baseConfig: baseConfig, uuid: uuid)
}
@ -182,14 +182,14 @@ extension Ghostty {
// MARK: - Hashable
func hash(into hasher: inout Hasher) {
hasher.combine(app)
hasher.combine(app.app)
hasher.combine(surface)
}
// MARK: - Equatable
static func == (lhs: Leaf, rhs: Leaf) -> Bool {
return lhs.app == rhs.app && lhs.surface === rhs.surface
return lhs.app.app == rhs.app.app && lhs.surface === rhs.surface
}
// MARK: - Codable
@ -203,7 +203,7 @@ extension Ghostty {
// Decoding uses the global Ghostty app
guard let del = NSApplication.shared.delegate,
let appDel = del as? AppDelegate,
let app = appDel.ghostty.app else {
appDel.ghostty.app != nil else {
throw TerminalRestoreError.delegateInvalid
}
@ -212,7 +212,7 @@ extension Ghostty {
var config = SurfaceConfiguration()
config.workingDirectory = try container.decode(String?.self, forKey: .pwd)
self.init(app, baseConfig: config, uuid: uuid)
self.init(appDel.ghostty, baseConfig: config, uuid: uuid)
}
func encode(to encoder: Encoder) throws {
@ -223,7 +223,7 @@ extension Ghostty {
}
class Container: ObservableObject, Equatable, Hashable, Codable {
let app: ghostty_app_t
let app: Ghostty.App
let direction: SplitViewDirection
@Published var topLeft: SplitNode
@ -335,7 +335,7 @@ extension Ghostty {
// MARK: - Hashable
func hash(into hasher: inout Hasher) {
hasher.combine(app)
hasher.combine(app.app)
hasher.combine(direction)
hasher.combine(topLeft)
hasher.combine(bottomRight)
@ -344,7 +344,7 @@ extension Ghostty {
// MARK: - Equatable
static func == (lhs: Container, rhs: Container) -> Bool {
return lhs.app == rhs.app &&
return lhs.app.app == rhs.app.app &&
lhs.direction == rhs.direction &&
lhs.topLeft == rhs.topLeft &&
lhs.bottomRight == rhs.bottomRight
@ -363,12 +363,12 @@ extension Ghostty {
// Decoding uses the global Ghostty app
guard let del = NSApplication.shared.delegate,
let appDel = del as? AppDelegate,
let app = appDel.ghostty.app else {
appDel.ghostty.app != nil else {
throw TerminalRestoreError.delegateInvalid
}
let container = try decoder.container(keyedBy: CodingKeys.self)
self.app = app
self.app = appDel.ghostty
self.direction = try container.decode(SplitViewDirection.self, forKey: .direction)
self.split = try container.decode(CGFloat.self, forKey: .split)
self.topLeft = try container.decode(SplitNode.self, forKey: .topLeft)

View File

@ -9,8 +9,8 @@ extension Ghostty {
@FocusedValue(\.ghosttySurfaceTitle) private var surfaceTitle: String?
var body: some View {
if let app = self.ghostty.app {
SurfaceForApp(app) { surfaceView in
if self.ghostty.app != nil {
SurfaceForApp(self.ghostty) { surfaceView in
SurfaceWrapper(surfaceView: surfaceView)
}
.navigationTitle(surfaceTitle ?? "Ghostty")
@ -24,7 +24,7 @@ extension Ghostty {
@StateObject private var surfaceView: SurfaceView
init(_ app: ghostty_app_t, @ViewBuilder content: @escaping ((SurfaceView) -> Content)) {
init(_ app: Ghostty.App, @ViewBuilder content: @escaping ((SurfaceView) -> Content)) {
_surfaceView = StateObject(wrappedValue: SurfaceView(app))
self.content = content
}

View File

@ -85,6 +85,8 @@ extension Ghostty {
// I don't think we need this but this lets us know we should redraw our layer
// so we'll use that to tell ghostty to refresh.
override var wantsUpdateLayer: Bool { return true }
private let app: Ghostty.App
// State machine for mouse cursor visibility because every call to
// NSCursor.hide/unhide must be balanced.
@ -95,9 +97,10 @@ extension Ghostty {
case pendingHidden
}
init(_ app: ghostty_app_t, baseConfig: SurfaceConfiguration? = nil, uuid: UUID? = nil) {
init(_ app: Ghostty.App, baseConfig: SurfaceConfiguration? = nil, uuid: UUID? = nil) {
self.markedText = NSMutableAttributedString()
self.uuid = uuid ?? .init()
self.app = app
// Initialize with some default frame size. The important thing is that this
// is non-zero so that our layer bounds are non-zero so that our renderer
@ -121,7 +124,7 @@ extension Ghostty {
// Setup our surface. This will also initialize all the terminal IO.
let surface_cfg = baseConfig ?? SurfaceConfiguration()
var surface_cfg_c = surface_cfg.ghosttyConfig(view: self)
guard let surface = ghostty_surface_new(app, &surface_cfg_c) else {
guard let surface = ghostty_surface_new(app.app, &surface_cfg_c) else {
self.error = AppError.surfaceCreateError
return
}
@ -369,8 +372,16 @@ extension Ghostty {
// Set the window transparency settings
window.isOpaque = false
window.hasShadow = false
window.backgroundColor = .clear
if app.config.macosWindowShadow {
window.hasShadow = true
// NOTE(haze): I have no idea why this works, but it does. This emulates the
// aesthetic of `Terminal.app`.
window.backgroundColor = .white.withAlphaComponent(0.001)
} else {
window.hasShadow = false
window.backgroundColor = .clear
}
// If we have a blur, set the blur
ghostty_set_window_background_blur(surface, Unmanaged.passUnretained(window).toOpaque())

View File

@ -976,6 +976,9 @@ keybind: Keybinds = .{},
/// This option only applies to new windows when changed.
@"macos-titlebar-tabs": bool = false,
/// If `true`, render the drop shadow behind the macOS window.
@"macos-window-shadow": bool = true,
/// If `true`, the *Option* key will be treated as *Alt*. This makes terminal
/// sequences expecting *Alt* to work properly, but will break Unicode input
/// sequences on macOS if you use them via the *Alt* key. You may set this to