Page 1 of 1

Welcome to the Tweaking4All community forums!
When participating, please keep the Forum Rules in mind!

Topics for particular software or systems: Start your topic link with the name of the application or system.
For example “MacOS X – Your question“, or “MS Word – Your Tip or Trick“.

Please note that switching to another language when reading a post will not work!

Clear all

Lazarus - macOS - Force Theme (DarkTheme and such)  


Noble Member Admin
Joined: 7 years ago
Posts: 1266
May 3, 2019 3:06 AM  

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, ... ;
    TmacOSThemes = (ThemeSystem, ThemeAqua, ThemeAquaDark, ThemeVibrant, ThemeVibrantDark);
// Force macOS Theme (ThemeSystem, ThemeAqua, ThemeAquaDark, ThemeVibrant, ThemeVibrantDark)
function t4a_ForceTheme(AForm: TComponent; aTheme:TmacOSThemes): Boolean;
{ Force Theme }
function t4a_ForceTheme(AForm: TComponent; aTheme:TmacOSThemes): Boolean;
  ClassByName : id;
  AppearanceString : string;
  AppearanceID : id;
  MyNSWindow : NSWindow;
  MyNSObject : NSObject;
  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';
  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
    if aTheme=ThemeSystem then
      objc_msgSend(MyNSWindow, ObjCSelector('setAppearance:'), nil)
      objc_msgSend(MyNSWindow, ObjCSelector('setAppearance:'), AppearanceID);
    Result := true;
  Result := false;

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.