NSColor Declare Help

I’m going crazy here.

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 problem is, Apple have deprecated colorUsingColorSpaceName, instead you have to use colorUsingColorSpace.

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)
1 Like

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
1 Like