Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions GhosttyTabs.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,7 @@
A5001800A1B2C3D4E5F60718 /* WindowBackdropController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5001801A1B2C3D4E5F60718 /* WindowBackdropController.swift */; };
F57072635F25EBCA741E125D /* SidebarState.swift in Sources */ = {isa = PBXBuildFile; fileRef = D1614EAD3CCF70A177A51BD1 /* SidebarState.swift */; };
A8CBA43C2DA5AB9E3A1E65A4 /* CommandPaletteSearch.swift in Sources */ = {isa = PBXBuildFile; fileRef = 38A09EB2E92203B2E95923A7 /* CommandPaletteSearch.swift */; };
B84BD7AD94EE485B8DDAB6FF /* GhosttySurfaceConfigurationRefresh.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9DAB808A8EC74C40B95F7672 /* GhosttySurfaceConfigurationRefresh.swift */; };
0D56BE882EAD4B67AC44F96D /* TerminalDirectoryOpenSupport.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6B8E2E03F4A64C61B729CF19 /* TerminalDirectoryOpenSupport.swift */; };
A72C9F4179B54DF38E99A021 /* CmuxCLIPathInstaller.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8A4FE96C3F394FC6A6D4B018 /* CmuxCLIPathInstaller.swift */; };
E8BA79E246754A8B99A0B823 /* ScreenIdentity.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47D5AA7D29C94F5CA865B2BF /* ScreenIdentity.swift */; };
Expand Down Expand Up @@ -612,6 +613,7 @@
A5001801A1B2C3D4E5F60718 /* WindowBackdropController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Windowing/WindowBackdropController.swift; sourceTree = "<group>"; };
D1614EAD3CCF70A177A51BD1 /* SidebarState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Sidebar/SidebarState.swift; sourceTree = "<group>"; };
38A09EB2E92203B2E95923A7 /* CommandPaletteSearch.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CommandPalette/CommandPaletteSearch.swift; sourceTree = "<group>"; };
9DAB808A8EC74C40B95F7672 /* GhosttySurfaceConfigurationRefresh.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = App/GhosttySurfaceConfigurationRefresh.swift; sourceTree = "<group>"; };
6B8E2E03F4A64C61B729CF19 /* TerminalDirectoryOpenSupport.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = App/TerminalDirectoryOpenSupport.swift; sourceTree = "<group>"; };
8A4FE96C3F394FC6A6D4B018 /* CmuxCLIPathInstaller.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = App/CmuxCLIPathInstaller.swift; sourceTree = "<group>"; };
47D5AA7D29C94F5CA865B2BF /* ScreenIdentity.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = App/ScreenIdentity.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -1118,6 +1120,7 @@
A5001801A1B2C3D4E5F60718 /* WindowBackdropController.swift */,
D1614EAD3CCF70A177A51BD1 /* SidebarState.swift */,
38A09EB2E92203B2E95923A7 /* CommandPaletteSearch.swift */,
9DAB808A8EC74C40B95F7672 /* GhosttySurfaceConfigurationRefresh.swift */,
6B8E2E03F4A64C61B729CF19 /* TerminalDirectoryOpenSupport.swift */,
8A4FE96C3F394FC6A6D4B018 /* CmuxCLIPathInstaller.swift */,
47D5AA7D29C94F5CA865B2BF /* ScreenIdentity.swift */,
Expand Down Expand Up @@ -1748,6 +1751,7 @@
A5001800A1B2C3D4E5F60718 /* WindowBackdropController.swift in Sources */,
F57072635F25EBCA741E125D /* SidebarState.swift in Sources */,
A8CBA43C2DA5AB9E3A1E65A4 /* CommandPaletteSearch.swift in Sources */,
B84BD7AD94EE485B8DDAB6FF /* GhosttySurfaceConfigurationRefresh.swift in Sources */,
0D56BE882EAD4B67AC44F96D /* TerminalDirectoryOpenSupport.swift in Sources */,
A72C9F4179B54DF38E99A021 /* CmuxCLIPathInstaller.swift in Sources */,
E8BA79E246754A8B99A0B823 /* ScreenIdentity.swift in Sources */,
Expand Down
18 changes: 18 additions & 0 deletions Sources/App/GhosttySurfaceConfigurationRefresh.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
@MainActor
enum GhosttySurfaceConfigurationRefresh {
nonisolated static let forceRefreshReason = "appDelegate.refreshAfterGhosttyConfigReload"

static func applyAfterAppConfigReload(
to surface: ghostty_surface_t?,
source: String,
reloadSurfaceConfiguration: (ghostty_surface_t, Bool, String) -> Void,
refreshHostBackground: () -> Void,
forceRefresh: (String) -> Void
) {
if let surface {
reloadSurfaceConfiguration(surface, true, source)
}
refreshHostBackground()
forceRefresh(forceRefreshReason)
}
}
18 changes: 16 additions & 2 deletions Sources/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4790,8 +4790,22 @@ final class AppDelegate: NSObject, NSApplicationDelegate, UNUserNotificationCent
func refreshTerminalSurfacesAfterGhosttyConfigReload(source: String) {
var refreshedCount = 0
forEachTerminalPanel { terminalPanel in
terminalPanel.hostedView.refreshHostBackgroundAfterGhosttyConfigReload()
terminalPanel.surface.forceRefresh(reason: "appDelegate.refreshAfterGhosttyConfigReload")
let liveSurface = terminalPanel.surface.liveSurfaceForGhosttyAccess(
reason: "appDelegate.refreshAfterGhosttyConfigReload"
)
GhosttySurfaceConfigurationRefresh.applyAfterAppConfigReload(
to: liveSurface,
source: source,
reloadSurfaceConfiguration: { surface, soft, source in
GhosttyApp.shared.reloadSurfaceConfiguration(surface, soft: soft, source: source)
},
refreshHostBackground: {
terminalPanel.hostedView.refreshHostBackgroundAfterGhosttyConfigReload()
},
forceRefresh: { reason in
terminalPanel.surface.forceRefresh(reason: reason)
}
)
refreshedCount += 1
}
#if DEBUG
Expand Down
50 changes: 50 additions & 0 deletions cmuxTests/AppearanceSettingsTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,56 @@ import SwiftUI

@MainActor
final class AppearanceSettingsTests: XCTestCase {
func testAppConfigReloadRefreshUpdatesSurfaceConfigBeforeRedraw() throws {
let fakeSurface = try XCTUnwrap(UnsafeMutableRawPointer(bitPattern: 0x3851))
var events: [String] = []

GhosttySurfaceConfigurationRefresh.applyAfterAppConfigReload(
to: fakeSurface,
source: "appearanceSync:test",
reloadSurfaceConfiguration: { surface, soft, source in
XCTAssertEqual(surface, fakeSurface)
XCTAssertTrue(soft)
events.append("reload:\(source)")
},
refreshHostBackground: {
events.append("host-background")
},
forceRefresh: { reason in
events.append("force-refresh:\(reason)")
}
)

XCTAssertEqual(events, [
"reload:appearanceSync:test",
"host-background",
"force-refresh:\(GhosttySurfaceConfigurationRefresh.forceRefreshReason)"
])
}

func testAppConfigReloadRefreshSkipsSurfaceConfigUpdateWhenSurfaceIsUnavailable() {
var events: [String] = []

GhosttySurfaceConfigurationRefresh.applyAfterAppConfigReload(
to: nil,
source: "appearanceSync:teardown",
reloadSurfaceConfiguration: { _, _, _ in
events.append("reload")
},
refreshHostBackground: {
events.append("host-background")
},
forceRefresh: { reason in
events.append("force-refresh:\(reason)")
}
)

XCTAssertEqual(events, [
"host-background",
"force-refresh:\(GhosttySurfaceConfigurationRefresh.forceRefreshReason)"
])
}

func testResolvedModeDefaultsToSystemWhenUnset() {
let suiteName = "AppearanceSettingsTests.Default.\(UUID().uuidString)"
guard let defaults = UserDefaults(suiteName: suiteName) else {
Expand Down
Loading