3
votes

I cannot figure out how to update the background color of my custom NSView when the user switches in and out of dark mode.

I've read the documentation and followed instructions here:detecting darkmode

The strange thing is that I can get all the subviews to behave correctly, but for some strange reason I can't get the background color of the main view to change. The background color of the view looks correct when I start the app in either mode, but when I switch between modes while the app is running it doesn't update to the new theme.

Would be grateful for any suggestions.

Inside the Custom NSView I have the method

- (void) viewDidChangeEffectiveAppearance
{
    self.needsDisplay = YES;
}

and inside the drawRect I have a do a simple color change before continuing with drawing in the view

NSAppearance *currentAppearance = [NSAppearance  currentAppearance];
if (@available(*, macOS 10.14)) {
    if(currentAppearance.name == NSAppearanceNameDarkAqua) {
        red  = 0.5*red+0.5;
        green = 0.5*green+0.5;
        blue  = 0.5*blue+0.5;
    }
}

Here is a screenshot of darkmode before (the way it should look)

Dark Mode Before

Here is a screenshot of light mode after user switch

Light Mode After

Here is a screenshot of lightmode before (the way it should look)

Light Mode Before

And here is a screenshot of darkmode after user switch

Dark Mode After

ps The reason I'm baffled and have little code to post is that the correct behavior is supposed to happen automatically with little effort. I even deleted the view from the nib and rebuilt it thinking maybe some setting got corrupted, but that didn't solve the problem.

Update: I found the source of the problem. This method gets called in windowDidLoad

- (void) setTransparent:(BOOL)transparent
    {
        if(transparent) {
            [self.window setOpaque:NO];
            NSColor *backgroundColor = [NSColor windowBackgroundColor];
            backgroundColor = [backgroundColor colorWithAlphaComponent: .75];
            [self.window setBackgroundColor:backgroundColor];
            self.window.alphaValue = 0.75;
    }
    else {
            [self.window setOpaque:YES];
            NSColor *backgroundColor = [NSColor windowBackgroundColor];
            backgroundColor = [backgroundColor colorWithAlphaComponent: 1];
            [self.window setBackgroundColor:backgroundColor];
            self.window.alphaValue = 1;
        }
    }

I get the expected behavior if I comment out the call to this method.

Why did this cause me to lose the automatic behavior of background color change when the user changes between light and dark mode?

1
Please explain what you've actually tried, with code examples. The link you reference just appears to explain how to determine if the user is in dark mode, not how to detect when the system switches from/to dark mode.James Bucanek
In my drawRect I check the currentAppearance and adjust text and line colors to work with the Aqua and DarkAqua themes. In my custom NSView I use viewDidChangeEffectiveAppearance to set the needDisplay to YES for the view and all its subviews. This seems to get most of the job done, with the exception of the background color of the custom view.pjg
@JamesBucanek requested for the code not for a description of the code. Questions seeking debugging help ("why isn't this code working?") must include the desired behavior, a specific problem or error and the shortest code necessary to reproduce it in the question itself.Amin Negm-Awad
You don't show the actual drawing of the background color... Always show everything that is relevant. And don't use == to compare strings. They're probably identical pointers, but they may not be and cause this to fail.seth

1 Answers

1
votes

My guess is that you’re not actually using the standard color for the background color.

You are using [NSColor windowBackgroundColor], however then making a copy with a different alpha component (via colorWithAlphaComponent), making it no longer a standard color.

My guess is a lot of the automatic ‘just works’ behaviour happens when you use the standard color definitions. As a test, could you try removing the colorWithAlphaComponent calls (where you are adding the transparency) from your settransparent method and see whether it works? if it does, you might need to find another way to add transparency to your view if you want the automatic behaviour.