Recent

Author Topic: How to make Cocoa respond to Dark Theme (Mojave/High Sierra)  (Read 14449 times)

Hansaplast

  • Hero Member
  • *****
  • Posts: 674
  • Tweaking4All.com
    • Tweaking4All
How to make Cocoa respond to Dark Theme (Mojave/High Sierra)
« on: September 17, 2018, 06:11:07 pm »
Cocoa has made some impressive progress and I'm not even touching Carbon anymore (compliments to the guys doing all the hard work! Awesome!).


I was wondering if anyone knows how to make the widget set (Cocoa) respond to the Dark Theme?
I've noticed that Lazarus applications under GTK2 do nicely adapt to theme changes.
Under Windows on the other hand, the new "Dark mode" in Windows 10 is somewhat ignored (something about UWP / Metro Style apps?).


Anyhoo - from the Cocoa Internals Wiki page I got the impression that system colors are tried to be retrieved from the OS (using NSColor), hoping a Cocoa application would adapt to theme changes. Which is not the case.
Note: A simple test with XCode 9.4.1 shows that even Obj-C applications will not adapt.


From Apple's own documentation "Supporting Dark Mode in Your Interface", I assumed using "Use a semantic color defined by the NSColor class" would offer support for themes out of the box.


So I'm confused why this doesn't seem to work.
Any input, suggestions, help, etc. is most welcome ...

skalogryz

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 2770
    • havefunsoft.com
Re: How to make Cocoa respond to Dark Theme (Mojave/High Sierra)
« Reply #1 on: September 17, 2018, 06:47:04 pm »
Anyhoo - from the Cocoa Internals Wiki page I got the impression that system colors are tried to be retrieved from the OS (using NSColor), hoping a Cocoa application would adapt to theme changes. Which is not the case.
Which is the case. Try trunk with TTreeView on Darktheme. You should see that the control's background and font are adapting. (instead of staying black on white)

Hansaplast

  • Hero Member
  • *****
  • Posts: 674
  • Tweaking4All.com
    • Tweaking4All
Re: How to make Cocoa respond to Dark Theme (Mojave/High Sierra)
« Reply #2 on: September 17, 2018, 11:00:47 pm »

Thanks for the reply Dmitry :)

I did build a simple application, just threw some controls on it (as suggested TTreeView as well), compiled it with Cocoa 64bit (Lazarus 2.1.0 r59039 FPC 3.0.4 x86_64-darwin-cocoa (alpha)).
Whatever I do, the application looks identical in regular theme and dark theme.
(changing the theme before starting the application)
Tried it with High Sierra and Mojave.

Am I missing something?

skalogryz

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 2770
    • havefunsoft.com
Re: How to make Cocoa respond to Dark Theme (Mojave/High Sierra)
« Reply #3 on: September 17, 2018, 11:13:55 pm »
Well, maybe Apple lied about it's "all being automatic".
Or maybe it's "automatic" for an application launched through Xib/Nib (Xcode project).
But that contradicts the documentation:
Quote
Apps inherit the default system appearance, windows inherit their app's appearance, and views inherit the appearance of their nearest ancestor (either a superview or window)

Are you using macOS extensions in your app?
If not, try to put MacOSFormProp on your form.
If yes, try to remove MacOSFormProp from your from.
« Last Edit: September 17, 2018, 11:17:52 pm by skalogryz »

Hansaplast

  • Hero Member
  • *****
  • Posts: 674
  • Tweaking4All.com
    • Tweaking4All
Re: How to make Cocoa respond to Dark Theme (Mojave/High Sierra)
« Reply #4 on: September 17, 2018, 11:59:46 pm »

I tried it originally without macOS Extension.

Just tested it by adding macOS extensions (thanks for making that available!), but I get the same result.
With MacOSFormProp I can set it to Dark Theme manually (design time) and programmatically (runtime), but it will not inherit what the system theme is using (even tried it with leaving Appearance blank).


I am pretty much an idiot with XCode, but I did try to throw some controls on a form and compiled it, to see the same effect. So the documentation is ahead and waiting for of Mojave, or something else wrong, or it's user error (of course an option as well).
Any simple tests I can do?


p.s.
Changing MacOSFormProp.Appearance seems to work under High Sierra - I can change the theme (for example: MacOSFormProp1.Appearance:='NSAppearanceNameVibrantDark').
Under Mojave changing the Appearance soes not seem to have an effect - it's stuck on the theme set at application startup.


I'll do some more tinkering tomorrow ...  :)

skalogryz

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 2770
    • havefunsoft.com
Re: How to make Cocoa respond to Dark Theme (Mojave/High Sierra)
« Reply #5 on: September 18, 2018, 12:16:10 am »
Any simple tests I can do?
Carbon? how does it look?

skalogryz

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 2770
    • havefunsoft.com
Re: How to make Cocoa respond to Dark Theme (Mojave/High Sierra)
« Reply #6 on: September 18, 2018, 01:51:55 am »
another test comes from a near by thread.
1) delete the bundle (that comes with archive) and create a new bundle using Project Options -> Applications.
2) remove line with alrt.runModal (it crashes the app).
3) compile and run, see if DarkMode is picked up
« Last Edit: September 18, 2018, 02:04:53 am by skalogryz »

Hansaplast

  • Hero Member
  • *****
  • Posts: 674
  • Tweaking4All.com
    • Tweaking4All
Re: How to make Cocoa respond to Dark Theme (Mojave/High Sierra)
« Reply #7 on: September 18, 2018, 11:55:50 am »
Thank Dmitry,


I updated to the latest SVN.
I do this almost every day - did you notice that newly opened forms/dialogs, in the IDE, now open behind already open forms/dialogs?
Anyhoo, then installed macOS extensions fresh, deleted and recreated the bundle and now I can change appearances (High Sierra and Mojave). However, the application still does not auto-detect what theme is currently being used though (at startup and while running).


Strangely enough, it does respond instantly to changing accent colors in the theme (eg. selecting different highlight color - not sure if you have Mojave running or not, I run it in a VM for now).
Getting closer though  :)


I read at StackOverflow a method to register for notification when the theme changes (maybe an option for MacOSFormProp, something like "AutoTheme" boolean);
Quote
To monitor the current state of the setting, you register as an observer of a distributed notification (within an appropriate method), like this:
Code: [Select]
[[NSDistributedNotificationCenter defaultCenter] addObserver:self selector:@selector(darkModeChanged:) name:@"AppleInterfaceThemeChangedNotification" object:nil];And you create a method to act as the message selector for the notification, like this:

Code: [Select]
-(void)darkModeChanged:(NSNotification *)notif
{
    NSLog(@"Dark mode changed"); // set Appearance to the right theme here?
}


skalogryz

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 2770
    • havefunsoft.com
Re: How to make Cocoa respond to Dark Theme (Mojave/High Sierra)
« Reply #8 on: September 18, 2018, 02:24:39 pm »
I read at StackOverflow a method to register for notification when the theme changes (maybe an option for MacOSFormProp, something like "AutoTheme" boolean);
I presume "Aqua" theme is "Auto"

Hansaplast

  • Hero Member
  • *****
  • Posts: 674
  • Tweaking4All.com
    • Tweaking4All
Re: How to make Cocoa respond to Dark Theme (Mojave/High Sierra)
« Reply #9 on: September 18, 2018, 05:48:25 pm »


Sorry for the confusion - I meant;
"AutoTheme", or whichever one would want to call it, as a suggested property for MacOSFormProp.
If set to TRUE, then at application start the current OS theme will be detected and applied, and/or an addObserver is added so the application gets notified by the OS when the theme changes.
Just a thought.


I'll try to tinker with it and I'll post what I came up with. So far I keep getting stuck at the Cocoa call.
So far I found the following, but I'll admit that I'm stuck at the SEL parameter:
Code: Pascal  [Select][+][-]
  1. procedure addObserver_selector_name_object(observer: id; aSelector: SEL; aName: NSString; anObject: NSString); message 'addObserver:selector:name:object:';


I did create a little application to check Lazarus colors - I can post it here if anyone cares for it (screenshot attached).



skalogryz

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 2770
    • havefunsoft.com
Re: How to make Cocoa respond to Dark Theme (Mojave/High Sierra)
« Reply #10 on: September 18, 2018, 06:09:34 pm »
so, if you've DarkTheme selected on Mojave.
And then launch the demo and select "Light" first. and then you switch back to "Aqua"

Do colors remain light?
(in other words "Aqua"<>"system default theme"?)

Hansaplast

  • Hero Member
  • *****
  • Posts: 674
  • Tweaking4All.com
    • Tweaking4All
Re: How to make Cocoa respond to Dark Theme (Mojave/High Sierra)
« Reply #11 on: September 18, 2018, 11:32:42 pm »

Not sure what you're asking ... so I'll try to go through the steps, hopefully clarifying things.


1) Aqua is the default system theme after a fresh OS install.
Obviously the user can change the theme, potentially making the active OS theme no longer Aqua, but for example VibrantDark or VibrantLight.


2) A Lazarus Cocoa application will not detect/pickup whatever OS theme is active when it starts.
So if VibrantDark is the current OS Theme, the application would not have a clue and just show the Aqua theme for it's controls.
The only option to get your application to show it's control in VibrantDark is to use your macOS extension and force Appearance to VibrantDark.


3) A Lazarus Cocoa application will also not detect/pickup when a theme get's change.
Changing the OS theme will have zero influence on the application while it's running.


For 2) and 3): I noticed the same behavior with a Cocoa application build with XCode (v9.4.1) application, so I presume this is expected behavior.

From what I have read; the OS will not change NSColor values when the OS theme changes.
Instead your application needs to register a function with NSDistributedNotificationCenter, (name "AppleInterfaceThemeChangedNotification") so that the OS can notify the application that a different theme is being used. The passed function then has to set Appearance to make the actual change. MacOSFormProp, could be used in that particular case.


That's why I was thinking of implementing this somehow in your MacOSFormProp component.
I'm trying to figure it out myself, but I'll admit it's a bit over my head.


I found this to be a good read, it clarified quite a bit for me (but then again, I'm not a a Cocoa guru like you are): https://mackuba.eu/2018/07/04/dark-side-mac-1/



So trying to understand your question; Theme = Dark, App starts with "VibrantLight", switch OS theme to Aqua => changes nothing for the application. The colors remain as they were when the application started.

Hansaplast

  • Hero Member
  • *****
  • Posts: 674
  • Tweaking4All.com
    • Tweaking4All
Re: How to make Cocoa respond to Dark Theme (Mojave/High Sierra)
« Reply #12 on: September 18, 2018, 11:50:36 pm »

Note:
When changing accent colors, the Lazarus application WILL see this for
- clMenubar,
- clHotLight and
- clHighlight.


Strangely enough NOT for clMenuHighlight will NOT pick up the change.


I did a small screen recording, maybe that clarifies. https://goo.gl/pAKMP2

skalogryz

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 2770
    • havefunsoft.com
Re: How to make Cocoa respond to Dark Theme (Mojave/High Sierra)
« Reply #13 on: September 19, 2018, 07:24:51 am »
Strangely enough NOT for clMenuHighlight will NOT pick up the change.
I did a small screen recording, maybe that clarifies. https://goo.gl/pAKMP2
There's an easy answer for it.
clMenuHighlight is mapped to Apple's "selectedMenuItemColor" (see the code and the wiki)
"selectedMenuItemColor" has been announced deprecated in 10.14 and you can see the effect.

Hansaplast

  • Hero Member
  • *****
  • Posts: 674
  • Tweaking4All.com
    • Tweaking4All
Re: How to make Cocoa respond to Dark Theme (Mojave/High Sierra)
« Reply #14 on: September 19, 2018, 11:27:17 am »
Thanks Dmitry ... I did not know that. [size=78%](for others; [/size][/size][size=78%]reference[/size][/size][size=78%])[/size]


I guess that will be a problem for later, since Apple says "Use an NSVisualEffectView with an appropriate material instead.".
I couldn't find an example on how to find the actual color based on that.


Would you happen to know how to use (docs):


Code: Pascal  [Select][+][-]
  1. NSDistributedNotificationCenter.addObserver_selector_name_object();


From examples (Swift etc) I have seen, the second parameter (aSelector:SEL) is used to point to a function.
The only thing I found was:


Code: Pascal  [Select][+][-]
  1.  _fpc_objc_sel_type = record
  2.   end;
  3.   SEL = ^_fpc_objc_sel_type;


 

TinyPortal © 2005-2018