I'm trying to match and vertically align the text (timer/"0:00" in the screenshots) with macOS Time/Date item on the Status Bar.
On the built-in display (white font) it needs baselineOffset: 0.5 to align with Time/Date. External display (black font) does not require such.
However, if screen focus changes to inactive (when clicking mouse on different screen to switch "screen" focus), the alignment changes, but in opposite directions on built-in vs external.
I've tried different resolutions on both 27" 4K and 14" MBP - same result.
TLDR table
(screen active) (offset is 0)
vertical offset screen focus
0 0.5 active inactive
built-in low OK low OK
external OK high OK low
Please see the screenshots and the code snippet for more details.
baselineOffset
On vs Off (white: built-in, black: external)
active vs inactive screen (white: built-in, black: external)
class AppDelegate: NSObject, NSApplicationDelegate {
private var statusItem: NSStatusItem!
// ...
private func updateStatusBar() {
guard let button = statusItem.button else { return }
let title = “0:00”
DispatchQueue.main.async {
let attributes: [NSAttributedString.Key: Any] = [
.font: NSFont.systemFont(ofSize: NSFont.systemFontSize, weight: .regular),
.foregroundColor: NSColor.textColor,
.baselineOffset: 0.5
]
let attributedTitle = NSAttributedString(string: title, attributes: attributes)
button.attributedTitle = attributedTitle
}
}
// ...
}
@main
class App {
static func main() {
let app = NSApplication.shared
let delegate = AppDelegate()
app.delegate = delegate
app.run()
}
}
I was able to solve this oddity by converting text into image.
As far as my testing goes: Liquid Retina (camera notch) has a slightly different vertical alignment for text and will behave oddly (passive vs active desktop focus, aligns opposite ways, etc), unlike all other displays I've checked (external 4K 16:9, M1 Air 16:10).
However, the images were always aligned, so:
class AppDelegate {
//...
let status: NSMutableAttributedString() = NSAttributedString(string: "Hello World"))
DispatchQueue.main.async {
let size = status.size()
let image = NSImage(size: size)image.lockFocus()
status.draw(at: .zero)
image.isTemplate = true
image.unlockFocus()
button.image = image
}
}
Also, Time and Date on macOS is aligned slightly higher than the rest status bar icons/text.