Hi-DPI Icons for Status Bar

I’m in the process of modernizing a bunch of my old projects to the latest IDE. One of these projects uses a clickable icon in the status bar (using NSStatusBar.SystemStatusBar.CreateStatusItem from MacOSLib), and I can’t figure out how the get the HiDPI version of the icon to display in the status bar on Retina Macs. It only shows the loDPI version, which looks rather ugly on a retina system where everything else is Hi-Res.
Any helpful hints would be greatly appreciated.

For NSImage you normally make a 2x bitmap with a 1x size.
At least that is what I do regularly.
A file based NSImage could of course load a @2x file automatically.

[quote=330908:@Christian Schmitz]For NSImage you normally make a 2x bitmap with a 1x size.
At least that is what I do regularly.
A file based NSImage could of course load a @2x file automatically.[/quote]
Thanks. I believe that is what I’m doing, unless I’m missing something. Here’s my code:

// initialize Status bar item dim bar as NSStatusBar = NSStatusBar.SystemStatusBar StatusItem = bar.CreateStatusItem(NSStatusBar.NSVariableStatusItemLength, AddressOf StatusItemHandler) StatusItem.title = "" StatusItem.highlightMode = true StatusItem.Image = TrayIcon.BestRepresentation(16,16,2)

I have the scale hardcoded to 2 for testing for now. This ensures that the 2x bitmap is assigned. “TrayIcon” is an image set with a 16x16 (1x) and a 32x32 (2x) bitmap.

The StatusItem.Image.Set method is as follows:

Public Property Image as NSImage Set #if TargetMacOS declare sub setImage lib CocoaLib selector "setImage:" (obj_id as Ptr, image as Ptr) dim imageRef as Ptr if value <> nil then imageRef = value end if setImage self, imageRef #else #pragma unused value #endif End Set End Property

This results in the 32x32 icon being displayed in the status bar at 2x the size (i.e. it’s too big and get’s clipped) instead of it being displayed at 2x the resolution.

What am I doing wrong?

Have you made sure that 1x be at 72dpi and x2 at 144 dpi ?

Yes. The call TrayIcon.BestRepresentation(16,16,2) returns a 32x32 bitmap with 144 for vertical and horizontal resolutions.

Your comment (as well as Christian’s comment regarding ‘1x size’) made me think and look into NSImage some more. As it turns out, NSImage has a ‘SetSize’ method (rather than a ‘Resolution’ property or something along those lines). Passing 16,16 to SetSize appears to scale the 32x32 icon correctly. The following code works:

// initialize Status bar item dim bar as NSStatusBar = NSStatusBar.SystemStatusBar StatusItem = bar.CreateStatusItem(NSStatusBar.NSVariableStatusItemLength, AddressOf StatusItemHandler) StatusItem.title = "" StatusItem.highlightMode = true dim p as NSImage = TrayIcon.BestRepresentation(16,16,2) p.SetSize(16,16) StatusItem.Image = p

Now I just have to find out if I can leave the scale hardcoded to 2, or if I need to dynamically determine the scale of the current screen and use 1 or 2 accordingly, depending on whether the status bar is on a Retina screen or on a regular screen. My app doesn’t open any windows or anything else with a graphics object on the screen that would let me figure out what the current scaling factor is.

[quote=330976:@Roger Meier] dim p as NSImage = TrayIcon.BestRepresentation(16,16,2)
p.SetSize(16,16)
StatusItem.Image = p[/quote]

Without seeing all your code, it sounds to me like you’re trying too hard.

In your project you should have a 16 x 16 image and a 32 x 32, “menuBarIcon” & “menuBarIcon@2x”. When you load the NSImage, you don’t directly load the image, you use the [NSImage imageNamed:] function passing in the name “menuBarIcon” (note: without file extension). This causes the image to be loaded at the size of 16x16, but will display the correct Retina image on a retina display. Make sure that you pass the unmodified image to any API that uses it.

I’m guessing in the library you’re using; the code would look similar to this.

StatusItem.image = NSImage.imageNamed( "TrayIcon" )