Follow up PR 242: refresh browser under-page background on theme updates (#272)
* Address PR 242 follow-ups for titlebar and browser background * Restore titlebar border per follow-up scope * Refresh browser under-page color with Ghostty opacity * Browser: theme blank page fallback for about:blank * Browser: keep new tabs webview-less until first nav
This commit is contained in:
parent
356a20e97a
commit
8ac554fb06
3 changed files with 105 additions and 21 deletions
|
|
@ -1005,6 +1005,27 @@ final class BrowserPanel: Panel, ObservableObject {
|
|||
/// Shared process pool for cookie sharing across all browser panels
|
||||
private static let sharedProcessPool = WKProcessPool()
|
||||
|
||||
private static func clampedGhosttyBackgroundOpacity(_ opacity: Double) -> CGFloat {
|
||||
CGFloat(max(0.0, min(1.0, opacity)))
|
||||
}
|
||||
|
||||
private static func resolvedGhosttyBackgroundColor(from notification: Notification? = nil) -> NSColor {
|
||||
let userInfo = notification?.userInfo
|
||||
let baseColor = (userInfo?[GhosttyNotificationKey.backgroundColor] as? NSColor)
|
||||
?? GhosttyApp.shared.defaultBackgroundColor
|
||||
|
||||
let opacity: Double
|
||||
if let value = userInfo?[GhosttyNotificationKey.backgroundOpacity] as? Double {
|
||||
opacity = value
|
||||
} else if let value = userInfo?[GhosttyNotificationKey.backgroundOpacity] as? NSNumber {
|
||||
opacity = value.doubleValue
|
||||
} else {
|
||||
opacity = GhosttyApp.shared.defaultBackgroundOpacity
|
||||
}
|
||||
|
||||
return baseColor.withAlphaComponent(clampedGhosttyBackgroundOpacity(opacity))
|
||||
}
|
||||
|
||||
let id: UUID
|
||||
let panelType: PanelType = .browser
|
||||
|
||||
|
|
@ -1027,6 +1048,10 @@ final class BrowserPanel: Panel, ObservableObject {
|
|||
/// Published URL being displayed
|
||||
@Published private(set) var currentURL: URL?
|
||||
|
||||
/// Whether the browser panel should render its WKWebView in the content area.
|
||||
/// New browser tabs stay in an empty "new tab" state until first navigation.
|
||||
@Published private(set) var shouldRenderWebView: Bool = false
|
||||
|
||||
/// Published page title
|
||||
@Published private(set) var pageTitle: String = ""
|
||||
|
||||
|
|
@ -1090,7 +1115,7 @@ final class BrowserPanel: Panel, ObservableObject {
|
|||
if let url = currentURL {
|
||||
return url.host ?? url.absoluteString
|
||||
}
|
||||
return "Browser"
|
||||
return "New tab"
|
||||
}
|
||||
|
||||
var displayIcon: String? {
|
||||
|
|
@ -1130,7 +1155,7 @@ final class BrowserPanel: Panel, ObservableObject {
|
|||
|
||||
// Match the empty-page background to the terminal theme so newly-created browsers
|
||||
// don't flash white before content loads.
|
||||
webView.underPageBackgroundColor = GhosttyApp.shared.defaultBackgroundColor
|
||||
webView.underPageBackgroundColor = Self.resolvedGhosttyBackgroundColor()
|
||||
|
||||
// Always present as Safari.
|
||||
webView.customUserAgent = BrowserUserAgentSettings.safariUserAgent
|
||||
|
|
@ -1206,6 +1231,7 @@ final class BrowserPanel: Panel, ObservableObject {
|
|||
|
||||
// Navigate to initial URL if provided
|
||||
if let url = initialURL {
|
||||
shouldRenderWebView = true
|
||||
navigate(to: url)
|
||||
}
|
||||
}
|
||||
|
|
@ -1295,6 +1321,13 @@ final class BrowserPanel: Panel, ObservableObject {
|
|||
}
|
||||
}
|
||||
webViewObservers.append(progressObserver)
|
||||
|
||||
NotificationCenter.default.publisher(for: .ghosttyDefaultBackgroundDidChange)
|
||||
.sink { [weak self] notification in
|
||||
guard let self else { return }
|
||||
self.webView.underPageBackgroundColor = Self.resolvedGhosttyBackgroundColor(from: notification)
|
||||
}
|
||||
.store(in: &cancellables)
|
||||
}
|
||||
|
||||
// MARK: - Panel Protocol
|
||||
|
|
@ -1337,6 +1370,7 @@ final class BrowserPanel: Panel, ObservableObject {
|
|||
navigationDelegate = nil
|
||||
uiDelegate = nil
|
||||
webViewObservers.removeAll()
|
||||
cancellables.removeAll()
|
||||
faviconTask?.cancel()
|
||||
faviconTask = nil
|
||||
}
|
||||
|
|
@ -1547,6 +1581,7 @@ final class BrowserPanel: Panel, ObservableObject {
|
|||
guard let url = request.url else { return }
|
||||
// Some installs can end up with a legacy Chrome UA override; keep this pinned.
|
||||
webView.customUserAgent = BrowserUserAgentSettings.safariUserAgent
|
||||
shouldRenderWebView = true
|
||||
if recordTypedNavigation {
|
||||
BrowserHistoryStore.shared.recordTypedNavigation(url: url)
|
||||
}
|
||||
|
|
@ -1649,6 +1684,7 @@ final class BrowserPanel: Panel, ObservableObject {
|
|||
BrowserWindowPortalRegistry.detach(webView: webView)
|
||||
}
|
||||
webViewObservers.removeAll()
|
||||
cancellables.removeAll()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -548,6 +548,8 @@ struct BrowserPanelView: View {
|
|||
}
|
||||
|
||||
private var webView: some View {
|
||||
Group {
|
||||
if panel.shouldRenderWebView {
|
||||
WebViewRepresentable(
|
||||
panel: panel,
|
||||
shouldAttachWebView: isVisibleInUI,
|
||||
|
|
@ -566,6 +568,17 @@ struct BrowserPanelView: View {
|
|||
addressBarFocused = false
|
||||
}
|
||||
})
|
||||
} else {
|
||||
Color(nsColor: GhosttyApp.shared.defaultBackgroundColor)
|
||||
.contentShape(Rectangle())
|
||||
.onTapGesture {
|
||||
onRequestPanelFocus()
|
||||
if addressBarFocused {
|
||||
addressBarFocused = false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.zIndex(0)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -214,6 +214,41 @@ final class BrowserDeveloperToolsConfigurationTests: XCTestCase {
|
|||
XCTAssertTrue(panel.webView.isInspectable)
|
||||
}
|
||||
}
|
||||
|
||||
func testBrowserPanelRefreshesUnderPageBackgroundColorWhenGhosttyBackgroundChanges() {
|
||||
let panel = BrowserPanel(workspaceId: UUID())
|
||||
let updatedColor = NSColor(srgbRed: 0.18, green: 0.29, blue: 0.44, alpha: 1.0)
|
||||
let updatedOpacity = 0.57
|
||||
|
||||
NotificationCenter.default.post(
|
||||
name: .ghosttyDefaultBackgroundDidChange,
|
||||
object: nil,
|
||||
userInfo: [
|
||||
GhosttyNotificationKey.backgroundColor: updatedColor,
|
||||
GhosttyNotificationKey.backgroundOpacity: updatedOpacity
|
||||
]
|
||||
)
|
||||
|
||||
guard let actual = panel.webView.underPageBackgroundColor?.usingColorSpace(.sRGB),
|
||||
let expected = updatedColor.withAlphaComponent(updatedOpacity).usingColorSpace(.sRGB) else {
|
||||
XCTFail("Expected sRGB-convertible under-page background colors")
|
||||
return
|
||||
}
|
||||
|
||||
XCTAssertEqual(actual.redComponent, expected.redComponent, accuracy: 0.005)
|
||||
XCTAssertEqual(actual.greenComponent, expected.greenComponent, accuracy: 0.005)
|
||||
XCTAssertEqual(actual.blueComponent, expected.blueComponent, accuracy: 0.005)
|
||||
XCTAssertEqual(actual.alphaComponent, expected.alphaComponent, accuracy: 0.005)
|
||||
}
|
||||
|
||||
func testBrowserPanelStartsAsNewTabWithoutLoadingAboutBlank() {
|
||||
let panel = BrowserPanel(workspaceId: UUID())
|
||||
|
||||
XCTAssertEqual(panel.displayTitle, "New tab")
|
||||
XCTAssertFalse(panel.shouldRenderWebView)
|
||||
XCTAssertNil(panel.webView.url)
|
||||
XCTAssertNil(panel.currentURL)
|
||||
}
|
||||
}
|
||||
|
||||
@MainActor
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue