Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
b73694a
fix(cmux-next): unify glass surface backgrounds
teamleaderleo Oct 4, 2026
8e44f3a
fix(cmux-next): keep surface override parsing nonisolated
teamleaderleo Oct 4, 2026
da17ce3
fix(cmux-next): mark surface colors nonisolated
teamleaderleo Oct 4, 2026
fce6f06
fix(cmux-next): avoid isolated surface equality
teamleaderleo Oct 4, 2026
5677c21
fix(cmux-next): make surface overrides equatable
teamleaderleo Oct 4, 2026
532d322
fix(cmux-next): keep surface setting labels as strings
teamleaderleo Oct 4, 2026
cad45c0
fix(cmux-next): preserve dynamic surface labels
teamleaderleo Oct 4, 2026
e32b228
chore(cmux-next): rerun exact-head checks
teamleaderleo Oct 4, 2026
cafd64e
merge feat-cmux-next and reuse landed surface background settings
teamleaderleo Oct 4, 2026
18bf415
fix(cmux-next): apply every surface background override
teamleaderleo Oct 4, 2026
9cb6d2a
Merge remote-tracking branch 'upstream/feat-cmux-next' into fix/feat-…
teamleaderleo Oct 4, 2026
cab3994
fix(cmux-next): keep surface selection internal to app scenes
teamleaderleo Oct 4, 2026
a669a07
Merge remote-tracking branch 'upstream/feat-cmux-next' into fix/feat-…
teamleaderleo Oct 4, 2026
b96489f
fix(cmux-next): keep surface setting namespace instantiable
teamleaderleo Oct 4, 2026
858cb60
fix(cmux-next): retain diff surface override
teamleaderleo Oct 4, 2026
816d8fc
fix(cmux-next): regenerate surface settings artifacts
teamleaderleo Oct 4, 2026
e81d388
Merge remote-tracking branch 'upstream/feat-cmux-next' into fix/feat-…
teamleaderleo Oct 4, 2026
b91d8a3
fix(cmux-next): preserve page engine hooks across background merge
teamleaderleo Oct 4, 2026
c5f4a43
Merge remote-tracking branch 'upstream/feat-cmux-next' into fix/feat-…
teamleaderleo Oct 4, 2026
d9390c2
chore(cmux-next): regenerate merged settings schema
teamleaderleo Oct 4, 2026
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
13 changes: 6 additions & 7 deletions Packages/Shared/CmuxTheme/Sources/CmuxTheme/ThemeTokens.swift
Original file line number Diff line number Diff line change
Expand Up @@ -24,16 +24,15 @@ public struct ThemeTokens: Hashable, Sendable {
public var chromeBackground: ThemeRGB
/// Floating cards (palette, hover card, editors) under or instead of glass.
public var elevatedBackground: ThemeRGB
/// Every pane's tab strip: a shade darker than the window in light
/// themes too, so the strips read as quiet bands (a pure black window
/// has no darker shade; there the strip matches it).
/// Every pane's tab strip: the same ground as the window. Focus and
/// selection fills provide hierarchy without introducing a second
/// background token.
public var stripBackground: ThemeRGB
/// The sidebar's tonal step: a translucent layer over the window's one
/// backdrop (the solid background, or the material and its tint), the
/// foreground at the same 4% the agent pane's sidebar uses.
public var sidebarStep: ThemeRGB
/// The tab strip's tonal step over the window's backdrop: black, so
/// over the opaque background it composites to `stripBackground`.
/// Reserved for the sidebar rules; tab strips do not add a tonal step.
public var stripStep: ThemeRGB

// Text
Expand Down Expand Up @@ -151,9 +150,9 @@ public struct ThemeTokens: Hashable, Sendable {
contentBackground: surface,
chromeBackground: bg.mixed(toward: fg, isDark ? 0.05 : 0.035),
elevatedBackground: bg.mixed(toward: fg, isDark ? 0.07 : 0.02),
stripBackground: bg.mixed(toward: .black, isDark ? 0.22 : 0.05).withAlpha(input.backgroundOpacity),
stripBackground: surface,
sidebarStep: fg.withAlpha(0.04),
stripStep: ThemeRGB.black.withAlpha(isDark ? 0.22 : 0.05),
stripStep: ThemeRGB.black.withAlpha(0),
textPrimary: primary,
textSecondary: secondary,
textTertiary: tertiary,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,12 @@ public import SwiftUI
@Observable
public final class AppSceneAppearance {
public var colors: AppSceneColors = .fallback
public var useSidebarBackground = false

public init() {}
public init(useSidebarBackground: Bool = false) { self.useSidebarBackground = useSidebarBackground }

public func update(from view: NSView) {
let resolved = AppSceneColors.resolve(in: view)
let resolved = AppSceneColors.resolve(in: view, useSidebarBackground: useSidebarBackground)
if resolved != colors { colors = resolved }
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,11 @@ public nonisolated struct AppSceneColors: Sendable, Equatable {

/// Resolves the palette for `view`'s theme scope.
@MainActor
public static func resolve(in view: NSView) -> AppSceneColors {
public static func resolve(in view: NSView, useSidebarBackground: Bool = false) -> AppSceneColors {
view.performWithTheme {
AppSceneColors(
background: c(Palette.sidebarBackground), elevated: c(Palette.elevatedBackground), primary: c(Palette.textPrimary),
background: c(useSidebarBackground ? (Palette.surfaceOverride(.sidebar) ?? Palette.sidebarBackground)
: (Palette.surfaceOverride(.internalPage) ?? Palette.sidebarBackground)), elevated: c(Palette.elevatedBackground), primary: c(Palette.textPrimary),
secondary: c(Palette.textSecondary), tertiary: c(Palette.textTertiary), separator: c(Palette.separator),
hover: c(Palette.hoverFill), selection: c(Palette.selectionFill), badge: c(Palette.badgeFill),
success: c(Palette.success), attention: c(Palette.attention), danger: c(Palette.danger))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ public import SwiftUI
/// section provider wants an `NSView` plus a height for a width).
public final class AppSceneHostingView: NSHostingView<AnyView> {
public let model: AppSceneModel
private let sceneAppearance = AppSceneAppearance()
private let sceneAppearance = AppSceneAppearance(useSidebarBackground: true)
/// Measures heights for a width without laying out this view.
private let measurer: NSHostingController<AnyView>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ public struct AppStoreRootView: View {
case .installed: AppInstalledView(model: model)
}
}
.background(colors.background)
.onAppear { if model.listings.isEmpty { model.refresh() } }
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ struct BookmarkPageColors: Equatable {
/// Call inside `performWithTheme`. theme-scoped
static func resolve() -> BookmarkPageColors {
BookmarkPageColors(
background: fixed(Palette.paneFill), primary: fixed(Palette.textPrimary), secondary: fixed(Palette.textSecondary),
background: fixed(Palette.surfaceOverride(.internalPage) ?? Palette.paneFill), primary: fixed(Palette.textPrimary), secondary: fixed(Palette.textSecondary),
tertiary: fixed(Palette.textTertiary), hover: fixed(Palette.hoverFill), selection: fixed(Palette.selectionFill),
separator: fixed(Palette.separator), danger: fixed(Palette.danger))
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ public final class BookmarksBarView: NSView {

public override func updateLayer() {
performWithTheme {
layer?.backgroundColor = Palette.windowBackground.cgColor
layer?.backgroundColor = Palette.paneFill.cgColor
emptyLabel.textColor = Palette.textTertiary
otherButton.contentTintColor = Palette.textSecondary
overflow.contentTintColor = Palette.textSecondary
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,12 @@ final class CEFHostView: NSView {
updateBackground()
}

/// Until Chromium's page window shows its first frame, the page area is
/// the theme color, never white (`PageBackground`).
/// Until Chromium's page window shows its first frame, the page area
/// follows the shared pane ground. It stays clear over Liquid Glass so
/// the window backdrop remains visible.
private func updateBackground() {
performWithTheme {
layer?.backgroundColor = Palette.pageBackground.cgColor
layer?.backgroundColor = Palette.paneFill.cgColor
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,8 @@ public final class CEFTab: BrowserTab, BrowserOcclusionHosting, BrowserExtension
private func applyPageBackground() {
guard let browser = browserID, let shim = runtime.shim else { return }
_ = shim.browserSetBackgroundColor(browser, PageBackground.chromiumARGB(pastFirstRealPage: pastFirstRealPage,
theme: PageBackground.themeARGB(in: container)))
theme: PageBackground.themeARGB(in: container,
surface: pastFirstRealPage ? nil : .newTabPage)))
}

func creationFailed() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,11 @@ nonisolated enum PageBackground {
/// `Palette.pageBackground` of `view`'s theme scope (its room,
/// workspace or terminal theme) as opaque 0xAARRGGBB, the form
/// `CefBrowserSettings.background_color` takes.
@MainActor static func themeARGB(in view: NSView) -> UInt32 {
argb(view.performWithTheme { Palette.pageBackground })
@MainActor static func themeARGB(in view: NSView, surface: SurfaceKind? = nil) -> UInt32 {
argb(view.performWithTheme {
if let surface, let override = Palette.surfaceOverride(surface) { return override.withAlphaComponent(1) }
return Palette.pageBackground
})
}

/// The app theme's (Ghostty config) page background: Chromium's
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ public import CmuxTheme
/// A part of the window whose background the user may change
/// (`appearance.surfaces.<surface>` in cmux.json, Lawrence R55;
/// plans/cmux-next/surface-backgrounds.md). Its raw value is the cmux.json
/// key. A Chromium page is not a surface: a page paints itself.
/// key. A real web page is not a surface; cmux-owned internal pages are.
public nonisolated enum SurfaceKind: String, CaseIterable, Sendable, Hashable {
case sidebar
case tabBar
Expand All @@ -14,8 +14,11 @@ public nonisolated enum SurfaceKind: String, CaseIterable, Sendable, Hashable {
case home
case browserChrome
case docks
/// The diff viewer page (`--cmux-surface-background` in webviews); it
/// has its own override instead of its host surface's.
/// Native and bundled internal pages such as History, Bookmarks, Tasks and App Store.
case internalPage
/// The draggable and visible split divider line.
case splitDivider
/// The diff viewer page (`--cmux-surface-background` in webviews).
case diff
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ public final class FeedHostView: NSView {

private func resolveColors() {
let colors = performWithTheme {
let background = floating ? Palette.contentBackground : Palette.paneFill
let background = floating ? Palette.contentBackground : (Palette.surfaceOverride(.internalPage) ?? Palette.paneFill)
layer?.backgroundColor = floating ? background.cgColor : nil
return FeedColors.resolved(background: background)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ public final class HistoryPageHostView: NSView {

private func resolveColors() {
let colors = performWithTheme {
let background = Palette.paneFill
let background = Palette.surfaceOverride(.internalPage) ?? Palette.paneFill
layer?.backgroundColor = nil
return HistoryPageColors(
background: Color(nsColor: Self.fixed(background)), primary: Color(nsColor: Self.fixed(Palette.textPrimary)),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ final class HomeHeaderView: NSView {

override func draw(_ dirtyRect: NSRect) {
performWithTheme {
Palette.windowBackground.setFill()
Palette.paneFill.setFill()
bounds.fill()
let paragraph = NSMutableParagraphStyle()
paragraph.alignment = .center
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ public final class HomeView: NSView {

private func applyTheme() {
performWithTheme {
layer?.backgroundColor = Palette.windowBackground.cgColor
layer?.backgroundColor = Palette.paneFill.cgColor
separator.backgroundColor = Palette.separator.cgColor
emptyLabel.font = Typography.body
emptyLabel.textColor = Palette.textTertiary
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ final class DividerHandleView: NSView {
if isEdge {
color = active ? Palette.focusRing.withAlphaComponent(0.45) : .clear
} else {
color = active ? Palette.focusRing.withAlphaComponent(0.6) : (showsIdleLine ? Palette.separator : .clear)
color = active ? Palette.focusRing.withAlphaComponent(0.6) : ((showsIdleLine || Palette.surfaceOverride(.splitDivider) != nil) ? (Palette.surfaceOverride(.splitDivider) ?? Palette.separator) : .clear)
}
Motion.transaction(.hover) {
line.backgroundColor = color.cgColor
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,10 @@ final class PaneOverlayView: NSView {
let attentionColor = attentionMark?.color?.nsColor ?? attentionSettings.color?.nsColor ?? Palette.attention
attention.borderColor = attentionColor.cgColor
border.borderColor = (borderStyle.color?.nsColor ?? Palette.paneBorder).cgColor
dimLayer.backgroundColor = Palette.contentBackground.withAlphaComponent(1).cgColor
// In glass windows the root backdrop owns the ground. An opaque
// inactive-pane veil would hide the painting and reintroduce the
// History/terminal mismatch; paneFill is clear in that mode.
dimLayer.backgroundColor = Palette.paneFill.cgColor
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -254,7 +254,7 @@ public final class PageWebView: NSView, PageSurface, WKNavigationDelegate {
/// `backgrounds`, the app's) replaces the page background; nil keeps the scope's own.
func currentTheme(backgrounds: SurfaceBackgrounds = ThemeScope.app.surfaceBackgrounds) -> WebTheme {
WebTheme(themeTokens, reduceTransparency: NSWorkspace.shared.accessibilityDisplayShouldReduceTransparency,
surface: themeSurface, backgrounds: backgrounds)
surface: themeSurface ?? .internalPage, backgrounds: backgrounds)
}

// MARK: WKNavigationDelegate
Expand Down
Loading
Loading