Does anyone know how to use `CGDisplayMode` from m...
# kotlin-native
d
Does anyone know how to use
CGDisplayMode
from macos CoreGraphics in Kotlin (1.6.10)? In particular, I can’t make the following code work:
Copy code
fun main() {
    val displayModes = CGDisplayCopyAllDisplayModes(1, null)!!.toNsArray()
    val displayMode = displayModes.objectAtIndex(0)
    println(displayMode) // prints <CGDisplayMode 0x600003648840> [{ BitsPerPixel = 32; ... }]
    println(displayMode as? CGDisplayMode) // compilation error: java.lang.IllegalStateException: class CGDisplayMode... long stacktrace
    println(displayMode as? CGDisplayModeRef) // prints null
    println((displayMode as? NSObject)?.className) // prints __NSCFType
}

private fun CFArrayRef.toNsArray() = CFBridgingRelease(this) as NSArray
s
Your
toNSArray
function looks problematic. Does it work if you just cast the CFArrayRef to an NSArray without releasing it? You’ll have to release it at some point. It just looks like you’re casting a null to an NSArray. Maybe,
Copy code
private fun CFArrayRef.toNSArray(): NSArrray {
   val arr = this as NSArray
   CFBridgingRelease(this)
   return arr
}
It does feel like an awkward side affect to be releasing the reference in that function. You would get a crash if you called toNSArray twice on the same reference.
d
This
CGDisplayCopyAllDisplayModes(1, null) as NSArray
fails at runtime with
kotlin.TypeCastException
.
Using CFArrayRef directly works:
Copy code
fun main() {
    val displayModes = CGDisplayCopyAllDisplayModes(1, null) as CFArrayRef
    val displayMode = CFArrayGetValueAtIndex(displayModes, 0)!!
    println(displayMode as? CGDisplayModeRef) // prints CPointer(raw=0x...)
    println(CGDisplayModeGetWidth(displayMode as? CGDisplayModeRef)) // prints screen width
    println(CGDisplayModeGetHeight(displayMode as? CGDisplayModeRef)) // prints screen height
}
But it’s not obvious to me how to convert it to NSArray (which as I understand should be convertable to List in Kotlin).
@Sam just checked with the function you suggested and it fails at runtime 😞
Copy code
private fun CFArrayRef.toNsArray(): NSArray {
    val result = this as NSArray // fails at runtime with kotlin.TypeCastException
    CFBridgingRelease(this)
    return result
}
I think overall it feels like the interop with macos API is a bit difficult and confusing.
s
CFArrayRef is a type alias for a CPointer pointing to a CFArray. Using the
pointed
property, you should be able to get to the actual array.
Copy code
public typealias CFArrayRef = kotlinx.cinterop.CPointer<cnames.structs.__CFArray>
Interacting with the lower level Core Foundation API is not fun in either Swift or Kotlin. It usually takes a while to work out the exact magic needed and unfortunately there are more people doing it in Swift than in Kotlin so it isn’t easy to google for.
r
You might be able to do
val arr = CFBridgingRelease(this) as NSArray
.
Where
this
is the
CFArrayRef
in Sam's function
I have some CFBridging Kotlin code in Multiplatform Settings for Keychain stuff if you want a reference https://github.com/russhwolf/multiplatform-settings/blob/master/multiplatform-settings/src/appleMain/kotlin/com/russhwolf/settings/KeychainSettings.kt#L209
It's a bit of a mess but works fine as far as I know
But I mostly use NSData and NSString and arrays might be more complicated
d
@russhwolf hm, I’m not sure how
Copy code
val arr = CFBridgingRelease(this) as NSArray
is different from
Copy code
private fun CFArrayRef.toNsArray() = CFBridgingRelease(this) as NSArray
r
oh sorry you were already doing that
I don't have any more helpful advice then, sorry