This code works to get the current system accent colour on macOS:
Declare Function NSClassFromString Lib "AppKit" (aClassName As CFStringRef) As Ptr
Declare Function controlAccentColor Lib "AppKit" selector "controlAccentColor" (ob_id As Ptr) As Ptr
Declare Function getRedComponent Lib "AppKit" selector "redComponent"(ob_id As Ptr) As CGFloat
Declare Function getGreenComponent Lib "AppKit" selector "greenComponent"(ob_id As Ptr) As CGFloat
Declare Function getBlueComponent Lib "AppKit" selector "blueComponent"(ob_id As Ptr) As CGFloat
Declare Function getAlphaComponent Lib "AppKit" selector "alphaComponent"(ob_id As Ptr) As CGFloat
Declare Function colorUsingColorSpaceName Lib "AppKit" selector "colorUsingColorSpaceName:"(ob_id As Ptr, csName As CFStringRef) As Ptr
Var c As Ptr = controlAccentColor(NSClassFromString("NSColor"))
c = colorUsingColorSpaceName(c, "NSCalibratedRGBColorSpace")
Var r As Integer = getRedComponent(c)*255
Var g As Integer = getGreenComponent(c)*255
Var b As Integer = getBlueComponent(c)*255
Var a As Integer = 256-getAlphaComponent(c)*255
Return RGB(r, g, b, a)
The code above works up to and including controlAccentColor but I am failing to replace the colorUsingColorSpaceName() method.
I think the equivalent NSColorSpace object to the string “NSCalibratedRGBColorSpace” is genericRGBColorSpace so I tried getting a reference to an NSColorSpace object and calling that property like this:
// Get an NSColorSpace object.
Var nscolorspace As Ptr = NSClassFromString("NSColorSpace")
// Get a generic RGB NSColorSpace object.
Declare Function genericRGBColorSpace Lib "AppKit" selector "genericRGBColorSpace" (nsColorSpaceObjID As Ptr) As Ptr
Var rgbColorSpace As Ptr = genericRGBColorSpace(nscolorspace)
but the app crashes with this (trimmed) stack trace:
Termination Signal: Illegal instruction: 4
Termination Reason: Namespace SIGNAL, Code 0x4
Terminating Process: exc handler [57080]
Application Specific Information:
Crashing on exception: +[NSColor genericRGBColorSpace]: unrecognized selector sent to class 0x7fff8fe6f160
I think this means that I’m sending genericRGBColorSpace to an NSColor instance which doesn’t make sense as my code is calling that property on what is returned from NSClassWithString("NSColorSpace") which should be an NSColorSpace.
Can anyone help at all. I bloody hate declares. Maybe @samRowlands or @pidog?
It’s working here on 10.15.6. Here’s my code with your two chunks combined…
Declare Function NSClassFromString Lib "AppKit" (aClassName As CFStringRef) As Ptr
Declare Function controlAccentColor Lib "AppKit" selector "controlAccentColor" (ob_id As Ptr) As Ptr
Declare Function getRedComponent Lib "AppKit" selector "redComponent"(ob_id As Ptr) As CGFloat
Declare Function getGreenComponent Lib "AppKit" selector "greenComponent"(ob_id As Ptr) As CGFloat
Declare Function getBlueComponent Lib "AppKit" selector "blueComponent"(ob_id As Ptr) As CGFloat
Declare Function getAlphaComponent Lib "AppKit" selector "alphaComponent"(ob_id As Ptr) As CGFloat
Declare Function colorUsingColorSpace Lib "AppKit" selector "colorUsingColorSpace:"(ob_id As Ptr, space As ptr) As Ptr
Var c As Ptr = controlAccentColor(NSClassFromString("NSColor"))
// Get an NSColorSpace object.
Var nscolorspace As Ptr = NSClassFromString("NSColorSpace")
// Get a generic RGB NSColorSpace object.
Declare Function genericRGBColorSpace Lib "AppKit" selector "genericRGBColorSpace" (nsColorSpaceObjID As Ptr) As Ptr
Var rgbColorSpace As Ptr = genericRGBColorSpace(nscolorspace)
c = colorUsingColorSpace(c, rgbColorSpace)
Var r As Integer = getRedComponent(c)*255
Var g As Integer = getGreenComponent(c)*255
Var b As Integer = getBlueComponent(c)*255
Var a As Integer = 256-getAlphaComponent(c)*255
Return RGB(r, g, b, a)
Not all colors are colors, some need to be drawn and then sampled, while some simply cannot be used with the Xojo color property and must be drawn using declares.
Your crash is because you’re trying to create a colorspace from a color and it doesn’t know how to do that. You need to create a colorspace from a NSColorSpace.
Once you said it was working for you I painstakingly trawled through my code path to find the bug.
I had split out some of the declares into helper methods, one of them was GetNSClassWithString(className As String) As Ptr. The problem was, in that method I wasn’t using className I was using "NSColor" (cut and paste error).
Once I noticed that bug - it works great. Thanks so much.
And if, for example, you need the native system colors for a self-designed Listbox (CellBackgroundPaint-Event) - this function provides them.
Shared Function HighlightColor(hasFocus As Boolean) As Color
Var cBackground As Color
#If TargetCocoa
Const kAppKit = "AppKit"
Declare Function NSClassFromString Lib kAppKit (aClassName As CFStringRef) As Ptr
Static NSColor As Ptr = NSClassFromString("NSColor")
Declare Function alternateSelectedControlColor Lib kAppKit Selector "alternateSelectedControlColor" (obj As Ptr) As Ptr
Declare Function secondarySelectedControlColor Lib kAppKit Selector "secondarySelectedControlColor" (obj As Ptr) As Ptr
Declare Function colorUsingColorSpace Lib kAppKit Selector "colorUsingColorSpace:"(ob_id As Ptr, space As ptr) As Ptr
' Get an NSColorSpace object.
Var nscolorspace As Ptr = NSClassFromString("NSColorSpace")
' Get a generic RGB NSColorSpace object.
Declare Function genericRGBColorSpace Lib kAppKit Selector "genericRGBColorSpace" (nsColorSpaceObjID As Ptr) As Ptr
Var rgbColorSpace As Ptr = genericRGBColorSpace(nscolorspace)
Var theColor As Ptr = If(hasFocus, alternateSelectedControlColor(NSColor), secondarySelectedControlColor(NSColor))
Var rgbColor As Ptr = colorUsingColorSpace(thecolor, rgbColorSpace)
If rgbColor <> Nil Then
Declare Function getRedComponent Lib kAppKit Selector "redComponent"(ob_id As Ptr) As CGFloat
Declare Function getGreenComponent Lib kAppKit Selector "greenComponent"(ob_id As Ptr) As CGFloat
Declare Function getBlueComponent Lib kAppKit Selector "blueComponent"(ob_id As Ptr) As CGFloat
Declare Function getAlphaComponent Lib kAppKit Selector "alphaComponent"(ob_id As Ptr) As CGFloat
Var r As Integer = getRedComponent(rgbColor) * 255
Var g As Integer = getGreenComponent(rgbColor) * 255
Var b As Integer = getBlueComponent(rgbColor) * 255
Var a As Integer = 256 - getAlphaComponent(rgbColor) * 255
cBackground = Color.RGB(r, g, b, a)
Else
cBackground = Color.HighlightColor
End If
#Else
cBackground = Color.HighlightColor
#EndIf
Return cBackground
End Function