Page 1 of 1
Forum

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 bring you to the same post, in Dutch, as there is no translation for that post!




Share:
Notifications
Clear all

Lazarus Pascal - Big Sur - TrayIcon color fix


 Hans
(@hans)
Noble Member Admin
Joined: 8 years ago
Posts: 2027
Topic starter  

With Big Sur, one can no longer rely on dark vs light theme to determine if an TrayIcon should be using light or dark colors.
The system wide menubar is by default transparent and the color and type of wallpaper influences if the background turns out to be light or dark.

After a long search I found that the image of a trayicon (NSStatusItem?) can have an option to do this automatically by using the setTemplate function of the image to true. When doing this, macOS will automatically adjust a transparent icon with only black pixels.

This can be activated relatively easy by adding a single line to the file

lazarus/lcl/interfaces/cocoa/cocoatrayicon.inc 

and simply setting the image to a "template".

In cocoatrayicon.inc add the following line to the lclSetTrayIcon procedure:

image.setTemplate(true);

I've added it below to the if (ATrayIcon.icon <> nil) section (line 11):

procedure TCocoaStatusItemHandle.lclSetTrayIcon(ATrayIcon: TCustomTrayIcon);
var
  image: NSImage;
begin
  TrayIcon := ATrayIcon;
 
  // Shows the icon 
  if (ATrayIcon.icon <> nil) and (ATrayIcon.icon.Handle <> 0) then
  begin
    image := TCocoaBitmap(ATrayIcon.icon.Handle).image;
    image.setTemplate(true); // < --- added this line
    if image <> nil then statusitem.setImage(image);
  end;
 
  // Show the menu
  if (ATrayIcon.PopUpMenu <> nil) then
  begin
    ATrayIcon.PopUpMenu.HandleNeeded();
    //ATrayIcon.PopUpMenu.
    if Assigned(statusitem.menu) and (statusitem.menu.delegate = NSMenuDelegateProtocol(self)) then
      statusitem.menu.setDelegate(nil);
 
    statusitem.setMenu(TCocoaMenu(ATrayIcon.PopUpMenu.Handle));
 
    TCocoaMenu(ATrayIcon.PopUpMenu.Handle).setDelegate( self);
  end;
end;

I've done some testing with this and this work great.

Downside: when using trayicons (menubar) with multiple colors, this may result in not so pretty icons.


ReplyQuote
 Hans
(@hans)
Noble Member Admin
Joined: 8 years ago
Posts: 2027
Topic starter  

All this in a generic function:

Note: this function uses ExtCtrls (for TTrayIcon type) and CocoaGDIObjects (for TCocoaBitmap) 

procedure FixTrayIconColors(aTrayIcon: TTrayIcon);
{$IFDEF DARWIN}
var
  image: NSImage;
{$ENDIF}
begin
  {$IFDEF DARWIN}
    if Assigned(aTrayIcon.Icon) then
      begin
        image := TCocoaBitmap(aTrayIcon.icon.Handle).image;
        image.setTemplate(true);
        aTrayIcon.InternalUpdate;
      end;
  {$ENDIF}
end;         

ReplyQuote

Like what you see and you'd like to help out? 

The best way to help is of course by assisting others with their questions here in the forum, but you can also help us out in other ways:

- Do your shopping at Amazon, it will not cost you anything extra but may generate a small commission for us,
- send a cup of coffee through PayPal ($5, $10, $20, or custom amount),
- become a Patreon,
- donate BitCoin (BTC), or BitCoinCash (BCH).

Share: