IsDarkMode

is the global IsDarkMode flag a calculation that should be avoided repetitively? (like for listbox rows)

ie/ does it call into the macOS framework every time or something else ???

The docs don’t have any kind of indication either way

@Greg O’Lone ? @Travis Hill ?

We set global variable in the AppearanceChanged to avoid an overhead of a function call.

If we can get an answer from staff we might not have to do such workarounds :slight_smile:

Guess I’ll have to resort to implementing something like this chunk of Swift code

// NSAppearance extension

@objc(rsIsDarkMode)
public var isDarkMode: Bool {
   let isDarkMode: Bool

   if #available(macOS 10.14, *) {
      if self.bestMatch(from: [.darkAqua, .aqua]) == .darkAqua {
         isDarkMode = true
      } else {
         isDarkMode = false
      }
    } else {
        isDarkMode = false
    }

    return isDarkMode
}

since an appearance is a composite thing and may / may not actually match light or dark exactly but will still be “most like” one or the other

Still would like to know what the framework IS actually doing on 10.14

NSAppearanceMBS class is available in our plugins.

Sure … but setting one would trigger appearance changed BUT if I set an appearance and its still most like Dark Mode what does the framework return ?

people would like to know otherwise we have to work around the frameworks IsDarkMode check as well

and is it cached ? or not ? so that calling it repeatedly (like in drawing a listbox with lots of cells) isnt hammered by it calling into the OS all the time ?

inquiring minds want to know

Looking on a sample result in process activity, I see it called effectiveAppearance from NSApplication class.
Same amount of time is used for sel_registerName and respondsToSelector.

So I would highly recommend to cache the value.
And I really would have expected Xojo runtime to cache it.

<https://xojo.com/issue/55681>

Xojo should hire Norman :wink:

HA !

IsDarkMode calls into the macOS framework every time it is called. The tricky part is that macOS doesn’t guarantee that the value will be updated until after the first paint is done, so it’s entirely possible that it will be incorrect in the AppearanceChanged event.

so really appearance changed should just invalidate the window & all controls and then the paint events would have it right

IMLE the paint event is the only guaranteed place that you’ll get the correct theme. I’ve even seen a window get deactivated and then magically switch to light mode; and switch back when activated. The controls still stay the same, but the appearance values return the wrong theme.

IMHO DarkMode should be considered like Retina; play dumb and use the appropriate API to draw stuff; then it should be right.

I do things like cache certain colors (as they have to be converted for use in Xojo API); then on the appearance changed event I flush that cache. When a function uses that color (via the paint event) it’s then re-cached. I don’t believe that this is the most optimal; but so far I’ve not had a problem because of it.

which kind of also makes the same argument
the appearance changed event should just invalidate everything and cause a paint event at which point dark mode can be correctly checked (and hat check is still not cached but …)
now if only the framework did that automatically instead of each of us having to do that

In MacOS 10.14, when using catalog colors, the drawRect (aka Paint), of an NSView, is the place to reassign colors. The appearance changed event of the window should have given us whether to expect darkmode or light mode is upcoming. IsDarkmode isn’t yet updated, and is actually too late if you cannot use a catalog color.

[quote=436436:@Norman Palardy]which kind of also makes the same argument
the appearance changed event should just invalidate everything and cause a paint event at which point dark mode can be correctly checked (and hat check is still not cached but …)
now if only the framework did that automatically instead of each of us having to do that[/quote]
Considering you and I worked on this together, I’m surprised that you don’t remember that effectively that is what happens. The problem (in Xojo and in objective-c) is that checking this property before an on-screen paint has occurred is just too early. And yet when we researched this in the fall, we found numerous cases of people having this problem and the answer was usually the equivalent of “just wait and check it in the first paint event.”

The only other thing we could have done I guess is we could have made IsDarkMode a method of the Graphics class and then tried to only made it work within the context of a paint event… but then you would still have had to store your own cache somewhere.

Well, have you considered that dark mode may not switch while app is active in front?
Users need to click in system preferences or switch to Terminal app to do it.

First you could cache the value.
When you get app.activate you set a flag.
Then in paint event check if flag is set and update the property. Clear the flag.

If you’re caching colors or doing drawing based on NSColor outside of a paint event, you need to be sure NSAppearance.currentAppearance is set to the effectiveAppearance of the view or sharedApplication . Otherwise NSColor may return values based on darkMode or Aqua. with no apparent logic.

Here’s a stackOverflow thread

I would expect Xojo to do that when the AppearanceChanged event fires to ensure that NSColor works as expected inside the event.

what i recall doesnt help anyone else know what is going on (which was the genesis of the question posted)