NSColor ... right or wrong?

I am trying to draw a rectangle that is honoring the NSColor modes for light vs dark
in the same color as the Window Background

here is what I get

the “lighter” of the two colors is the basic NSWindow with no color changes [#F6F6F6]
the “darker” is [#323232]

context.setFillColor(NSColor.windowBackgroundColor.cgColor)

any idea which is “wrong”… seems most windows I tested are the “lighter” color… which then asks why would Apple define the named color differently?

don’t forget they often have various blending modes applied to the window etc

maybe that factors in ?

best I can tell that doesn’t apply…
So unless I can find another solution… I’m definining my own in the Asset Catalog

context.setFillColor( NSColor(named:"dsWindowBackgroundColor")!.cgColor)

this gives the visual I require

visual effect views and lord knows what other layers etc

you can inspect the view hierarchy of an app in Xcode

details on my blog somewhere :stuck_out_tongue:

Maybe https://developer.apple.com/documentation/appkit/nscolor/1534707-underpagebackgroundcolor

nope… that is darker still

Hmm, what about “context”? Is that correct? It might automatically make it darker to emphasise the rectangle. What happens when you set the rectangle directly?

that IS setting it directly

public override func draw(_ dirtyRect: NSRect) {
		super.draw(dirtyRect)
		let context: CGContext = ds$CGContext
		context.setFillColor( NSColor(named:"dsWindowBackgroundColor")!.cgColor)
		context.fill(dirtyRect)

this shows “correctly”… using the Apple defined color does not

ds$CGContext is just a typeAlias so I can use the same code for iOS if required

cgColor?

  • Remember that NSColor contains a lot of “magic” inside that knows how to render a given color in any appearance. CGColor however doesn’t… so avoid storing the CGColor extracted from an NSColor – e.g. if you assign it to a layer’s backgroundColor, it won’t automatically switch to a dark variant when needed, even if the original NSColor would.

Wouldn’t this work:

context.setFillColor(NSColor.windowBackgroundColor)

no setFillColor and SetStroke require cgColor

but it isn’t that the color being display is “wrong”… it IS the RGB color from the named Color
the problem is any other window I display doesn’t seem to use that color

windowBackgroundColor
Light: #ECECECFF
Dark: #323232FF (note fully opaque)

but when examined on a “real application window”
Light : #F6F6F6FF
Dark : #2A2A2AFF

since the named color is Alpha=255 then there is no “blending” and both are examined using the sRGB colorspace

Look at view hierarchy, you’ll be able to see what Apple use for the window background.

Last I checked, it wasn’t a color. It was a NSVisualEffectView, but that was a couple of years ago, so who knows what they use now.

It’s also worth mentioning that some colors are not meant to be drawn, only applied to controls. You’ll have to experiment to figure out which and to what (again, exploding the view hierarchies help here).

1 Like

I went through this whole NSColor nightmare while developing a Swift app with some custom views. It seems like the new way is to use a subclass of a NSVisualEffectView and set it’s material. That’s what I ended up doing.

As you can see most window and control colors are now deprecated and I couldn’t find another way to match the OS styles particularly in Monterey.

this has nothing to do with materials, layering, blending or colorspaces.

The color that Apple defines as NSColor.windowBackgroundColor is NOT the one being used

Could it be that the lighter color is the windowBackgroundColor of an unselected window, and the darker one the color of a selected one?

I’m still on Mojave so can’t check the values on newer ones, but checking the colours of the top and sidebar on a finder window I get for an unselected window F6F6F6 (steady value) and for a selected one something around E1E1E3 (value vary depending on where I measure, but pretty close to your value).

So if you unselect your app and measure the box colour with the included Digital Color Meter app - what do you get?

Btw the Digital Color Meter app has ECECEC as window background colour whether it is selected or unselected.

Not a solution, but I also came across an interesting article on how to handle colour compatibility: Backwards compatibility for iOS 13 system colors

Might have found an answer here: swift - How to reliably retrieve a window's background color on macOS with SwiftUI? - Stack Overflow

The window’s background is not composed by a color, is a NSVisualEffectView with .windowBackground as material.

You can achieve that with this code:

struct EffectView: NSViewRepresentable {
    @State var material: NSVisualEffectView.Material = .headerView
    @State var blendingMode: NSVisualEffectView.BlendingMode = .withinWindow

    func makeNSView(context: Context) -> NSVisualEffectView {
        let view = NSVisualEffectView()
        view.material = material
        view.blendingMode = blendingMode
        return view
    }
    
    func updateNSView(_ nsView: NSVisualEffectView, context: Context) {
        nsView.material = material
        nsView.blendingMode = blendingMode
    }
}

And apply that to your view:

struct ContentView: View {
    var body: some View {
        EffectView(material: .windowBackground)
            .overlay(Text("Window Real Background"))
            .padding(30)
    }
}

The output is this (nothing to see because it mimetizes with background):

The reason why the background is an NSVisualEffectView is because the Window Tinting of macOS Big Sur, that changes the background according to wallpaper predominant color:

P.S. The other answers are also illuminating - eg

The windowBackground is a real window’s background color, you just compare it not with real window background, but with theme view below hosting controller view

Here is a hierarchy (you can verify it yourself in view debug mode)

That view debugger is seriously cool!

In my search I also came across an interesting site: CodeGrepper

eg

Is that not what I said two days ago?
Which could have been validated by simply exploring the view hierarchy.

Yeah, a lot of the colors and even color effects are NOT what Apple actually uses, those days ended long ago, Apple PJ does whatever it feels like, without giving a damn about 3rd Party Developers.

1 Like

I think so - but don’t look at me … I have no clue :wink:

I’m not a top notch programmer, just pretty good at finding information …

I didn’t know about the colours etc, and certainly not about the view debugger … just trying to find an answer for a question that intrigued me (while my wife said I SHOULD mow the lawn instead) … which is now done too :hot_face:

I guess this article might be useful for you to: how to handle colour compatibility: Backwards compatibility for iOS 13 system colors

1 Like

Me neither mate, am not even good at finding information some times… I tend to end up reading a lot more .h files now than ever and even in those cases, they’re often incomplete or don’t explain what this key, method, property does. What’s even worse if having to read “private” API to figure out the values from a public function… I guess I should be grateful that Apple even makes private API .h files available for security researchers (not regular developers).

AFAIK, swift doesn’t use .h files, so I guess that’ll be going away one day too.

The colors have not been quite right for some time now, I had to probe the view hierarchy quite a bit when I wanted App Wrapper to be more consistent with the OS and couldn’t find these things in the documentation. I went in further while I was putting together the App Kit, and Aqua Swatch really helps (it does more than just colors, it does materials, icons and system fonts).

Good job, I’ve yet to get to my chores today. I’ve been a bit relaxed as it’s been ~35˙c for the last few days.

Trouble is with a lot of documentation and especially 3rd Party documentation, is what works on one version, may not work on anything newer :frowning:

This irritates me to no end, as someone who wants to build an app that at least looks like it was created with love and care.

1 Like

What makes it works its that a lot of tutorial or information on the internet don’t even give you proper context what version of the SDK, etc.

I spent days with the same issue as @DaveS while working on some custom views for a splitter and button, gave up on fill, using material was the only solution that worked properly.

1 Like