Fix terminal background rendering

This commit is contained in:
Lawrence Chen 2026-01-22 20:53:41 -08:00
parent b40f3dec35
commit 4c326d6abd
26 changed files with 194 additions and 2 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 619 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 95 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 95 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 243 KiB

View file

@ -0,0 +1,68 @@
{
"images" : [
{
"filename" : "16.png",
"idiom" : "mac",
"scale" : "1x",
"size" : "16x16"
},
{
"filename" : "16@2x.png",
"idiom" : "mac",
"scale" : "2x",
"size" : "16x16"
},
{
"filename" : "32.png",
"idiom" : "mac",
"scale" : "1x",
"size" : "32x32"
},
{
"filename" : "32@2x.png",
"idiom" : "mac",
"scale" : "2x",
"size" : "32x32"
},
{
"filename" : "128.png",
"idiom" : "mac",
"scale" : "1x",
"size" : "128x128"
},
{
"filename" : "128@2x.png",
"idiom" : "mac",
"scale" : "2x",
"size" : "128x128"
},
{
"filename" : "256.png",
"idiom" : "mac",
"scale" : "1x",
"size" : "256x256"
},
{
"filename" : "256@2x.png",
"idiom" : "mac",
"scale" : "2x",
"size" : "256x256"
},
{
"filename" : "512.png",
"idiom" : "mac",
"scale" : "1x",
"size" : "512x512"
},
{
"filename" : "512@2x.png",
"idiom" : "mac",
"scale" : "2x",
"size" : "512x512"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 610 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 74 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 74 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 198 KiB

View file

@ -0,0 +1,68 @@
{
"images" : [
{
"filename" : "16.png",
"idiom" : "mac",
"scale" : "1x",
"size" : "16x16"
},
{
"filename" : "16@2x.png",
"idiom" : "mac",
"scale" : "2x",
"size" : "16x16"
},
{
"filename" : "32.png",
"idiom" : "mac",
"scale" : "1x",
"size" : "32x32"
},
{
"filename" : "32@2x.png",
"idiom" : "mac",
"scale" : "2x",
"size" : "32x32"
},
{
"filename" : "128.png",
"idiom" : "mac",
"scale" : "1x",
"size" : "128x128"
},
{
"filename" : "128@2x.png",
"idiom" : "mac",
"scale" : "2x",
"size" : "128x128"
},
{
"filename" : "256.png",
"idiom" : "mac",
"scale" : "1x",
"size" : "256x256"
},
{
"filename" : "256@2x.png",
"idiom" : "mac",
"scale" : "2x",
"size" : "256x256"
},
{
"filename" : "512.png",
"idiom" : "mac",
"scale" : "1x",
"size" : "512x512"
},
{
"filename" : "512@2x.png",
"idiom" : "mac",
"scale" : "2x",
"size" : "512x512"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View file

@ -0,0 +1,6 @@
{
"info" : {
"author" : "xcode",
"version" : 1
}
}

View file

@ -20,6 +20,7 @@
A50010A4 /* SplitTree.swift in Sources */ = {isa = PBXBuildFile; fileRef = A50010A0 /* SplitTree.swift */; };
A50010A5 /* SplitView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A50010A1 /* SplitView.swift */; };
A50010A6 /* TerminalSplitTreeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A50010A2 /* TerminalSplitTreeView.swift */; };
A5001100 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = A5001101 /* Assets.xcassets */; };
/* End PBXBuildFile section */
/* Begin PBXCopyFilesBuildPhase section */
@ -52,6 +53,7 @@
A50010A0 /* SplitTree.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Splits/SplitTree.swift; sourceTree = "<group>"; };
A50010A1 /* SplitView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Splits/SplitView.swift; sourceTree = "<group>"; };
A50010A2 /* TerminalSplitTreeView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Splits/TerminalSplitTreeView.swift; sourceTree = "<group>"; };
A5001101 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@ -65,11 +67,23 @@
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXResourcesBuildPhase section */
A5001102 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
A5001100 /* Assets.xcassets in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXGroup section */
A5001040 = {
isa = PBXGroup;
children = (
A5001041 /* Sources */,
A5001101 /* Assets.xcassets */,
A5001016 /* GhosttyKit.xcframework */,
A5001017 /* ghostty.h */,
A5001018 /* GhosttyTabs-Bridging-Header.h */,
@ -113,6 +127,7 @@
buildPhases = (
A5001051 /* Sources */,
A5001030 /* Frameworks */,
A5001102 /* Resources */,
A5001020 /* Embed Frameworks */,
);
buildRules = (
@ -239,7 +254,7 @@
A5001082 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_APPICON_NAME = "AppIcon-Debug";
CODE_SIGN_ENTITLEMENTS = "";
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;

View file

@ -107,7 +107,7 @@ class GhosttyApp {
runtimeConfig.supports_selection_clipboard = true
runtimeConfig.wakeup_cb = { userdata in
DispatchQueue.main.async {
// Wakeup - trigger redraw if needed
GhosttyApp.shared.tick()
}
}
runtimeConfig.action_cb = { app, target, action in
@ -211,6 +211,7 @@ class GhosttyApp {
func tick() {
guard let app = app else { return }
ghostty_app_tick(app)
AppDelegate.shared?.tabManager?.tickRender()
}
private func updateDefaultBackground(from config: ghostty_config_t?) {
@ -447,6 +448,7 @@ class GhosttyApp {
blue: CGFloat(change.b) / 255,
alpha: 1.0
)
surfaceView.applySurfaceBackground()
if backgroundLogEnabled {
logBackground("OSC background change tab=\(surfaceView.tabId?.uuidString ?? "unknown") color=\(surfaceView.backgroundColor?.description ?? "nil")")
}
@ -559,11 +561,13 @@ class TerminalSurface: Identifiable {
return
}
ghostty_surface_set_content_scale(surface, scale, scale)
ghostty_surface_set_size(
surface,
UInt32(view.bounds.width * scale),
UInt32(view.bounds.height * scale)
)
ghostty_surface_refresh(surface)
setupDisplayLink()
}
@ -603,7 +607,9 @@ class TerminalSurface: Identifiable {
func updateSize(width: CGFloat, height: CGFloat, scale: CGFloat) {
guard let surface = surface else { return }
ghostty_surface_set_content_scale(surface, scale, scale)
ghostty_surface_set_size(surface, UInt32(width * scale), UInt32(height * scale))
ghostty_surface_refresh(surface)
if let view = attachedView, let metalLayer = view.layer as? CAMetalLayer {
metalLayer.contentsScale = scale
@ -611,6 +617,12 @@ class TerminalSurface: Identifiable {
}
}
func renderIfVisible() {
guard let view = attachedView else { return }
guard view.window != nil, view.bounds.width > 0, view.bounds.height > 0 else { return }
ghostty_surface_draw(surface)
}
func applyWindowBackgroundIfActive() {
surfaceView.applyWindowBackgroundIfActive()
}
@ -678,11 +690,20 @@ class GhosttyNSView: NSView, NSUserInterfaceValidations {
return base.withAlphaComponent(opacity)
}
func applySurfaceBackground() {
let color = effectiveBackgroundColor()
if let metalLayer = layer as? CAMetalLayer {
metalLayer.backgroundColor = color.cgColor
metalLayer.isOpaque = color.alphaComponent >= 1.0
}
}
func applyWindowBackgroundIfActive() {
guard let window else { return }
if let tabId, let selectedId = AppDelegate.shared?.tabManager?.selectedTabId, tabId != selectedId {
return
}
applySurfaceBackground()
let color = effectiveBackgroundColor()
window.backgroundColor = color
window.isOpaque = color.alphaComponent >= 1.0
@ -745,10 +766,16 @@ class GhosttyNSView: NSView, NSUserInterfaceValidations {
if window != nil {
attachSurfaceIfNeeded()
updateSurfaceSize()
applySurfaceBackground()
applyWindowBackgroundIfActive()
}
}
override func viewDidChangeBackingProperties() {
super.viewDidChangeBackingProperties()
updateSurfaceSize()
}
override func setFrameSize(_ newSize: NSSize) {
super.setFrameSize(newSize)
attachSurfaceIfNeeded()

View file

@ -204,6 +204,14 @@ class TabManager: ObservableObject {
})
}
func tickRender() {
for tab in tabs {
for surface in tab.splitTree.map({ $0 }) {
surface.renderIfVisible()
}
}
}
func addTab() {
let newTab = Tab(title: "Terminal \(tabs.count + 1)")
tabs.append(newTab)