With the introduction of DarkTheme (macOS 10.14.x / Mojave), and the great work of Dmitry, we can now support DarkTheme in our Lazarus applications for macos. Based on some of Dmitry's work, I created a function that allows you to force a theme, or force back to system default theme.
I'm sure this could have been done better, but this works well for me;
...
{$modeswitch objectivec1}
...
uses ..., CocoaAll, ... ;
...
interface
...
Type
TmacOSThemes = (ThemeSystem, ThemeAqua, ThemeAquaDark, ThemeVibrant, ThemeVibrantDark);
...
// Force macOS Theme (ThemeSystem, ThemeAqua, ThemeAquaDark, ThemeVibrant, ThemeVibrantDark)
function t4a_ForceTheme(AForm: TComponent; aTheme:TmacOSThemes): Boolean;
...
implementation
...
{ Force Theme }
function t4a_ForceTheme(AForm: TComponent; aTheme:TmacOSThemes): Boolean;
var
ClassByName : id;
AppearanceString : string;
AppearanceID : id;
MyNSWindow : NSWindow;
MyNSObject : NSObject;
begin
{$IFDEF DARWIN}
Result := false;
if not Assigned(AForm) or not (AForm is TWinControl) then Exit;
MyNSObject := NSObject(TWinControl(AForm).Handle);
if not Assigned(MyNSObject) then Exit;
if MyNSObject.respondsToSelector(ObjCSelector('window')) then
MyNSWindow := objc_msgSend(MyNSObject, ObjCSelector('window'));
if not Assigned(MyNSWindow) then Exit;
case aTheme of
ThemeAqua : AppearanceString := 'NSAppearanceNameAqua';
ThemeAquaDark : AppearanceString := 'NSAppearanceNameDarkAqua';
ThemeVibrant : AppearanceString := 'NSAppearanceNameVibrantLight';
ThemeVibrantDark : AppearanceString := 'NSAppearanceNameVibrantDark';
else AppearanceString := 'NSAppearanceNameAqua';
end;
ClassByName := NSClassFromString( NSSTR('NSAppearance'));
if not Assigned(ClassByName) then Exit; // not suppored in OSX version
AppearanceID := objc_msgSend(ClassByName, ObjCSelector('appearanceNamed:'), NSSTR(@AppearanceString[1]));
if not Assigned(AppearanceID) then Exit;
if MyNSWindow.respondsToSelector(ObjCSelector('setAppearance:')) then
begin
if aTheme=ThemeSystem then
objc_msgSend(MyNSWindow, ObjCSelector('setAppearance:'), nil)
else
objc_msgSend(MyNSWindow, ObjCSelector('setAppearance:'), AppearanceID);
Result := true;
end;
{$ELSE}
Result := false;
{$ENDIF}
end;
This function can be called from within your application, like so (self = the mainform):
t4a_ForceTheme(self, ThemeAquaDark);
Note that in the onPaint event of your form you can correct colors of custom controls if you'd want to.
On theme change (even without this function), the onPaint event of your form will always be called.
Available themes (you can expand the list if you'd like):
ThemeSystem: use system defined theme
Forced themes:
ThemeAqua: the default theme of MacOS
ThemeAquaDark: The DarkTheme used in 10.14 (Mojave) and newer (will not work in macOS prior to Mojave)
ThemeVibrant: a slightly lighter version of the default Aqua theme (I have not seen this one used yet)
ThemeVibrantDark: The DarkTheme used in macOS version prior to 10.14.