Skip to content

Cannot call some methods from AboutDialogProtocol (GTK 3) using Array of Strings as a parameter #61

@jasaldivara

Description

@jasaldivara

I want to call some AboutDialogProtocol methods like set(artists:) and set(authors:) Both methods have declared a parameter of the type UnsafeMutablePointer<UnsafePointer<gchar>?>! but I currently cannot call them from Swift.

On the GTK C API documentation those parameters appear as NULL-terminated array of strings (That is a pointer to an array of pointers to char, where the last element is a NULL pointer):

gtk_about_dialog_set_artists (GtkAboutDialog *about,
                              const gchar **artists);

If I call the method with an array of Strings, it doesn't compile:

about.set(artists: [
    "Catalog Icons from Twemoji",
    "Desktop Icons from <a href='https://icons8.com/'>Icons8</a>",
    "Other Icons by Jesús Abelardo Saldívar Aguilar"
    ])
error: cannot convert value of type '[String]' to expected argument type 'UnsafeMutablePointer<UnsafePointer<gchar>?>?' (aka 'Optional<UnsafeMutablePointer<Optional<UnsafePointer<Int8>>>>')
        about.set(artists: [
                           ^

I have tried a snippet from Swift Forums for similar situations (Converting a Swift Array of Strings to a C Array of Strings) with minor modifications, but haven't been successful. The code compiles, but crashes on run time,
possibly because the last element of the array is not null/nil (In the online example, the Vulkan API does not require the last element to be NULL):

https://forums.swift.org/t/create-c-string-array-from-swift/31149/2

extension Collection {
    /// Creates an UnsafeMutableBufferPointer with enough space to hold the elements of self.
    public func unsafeCopy() -> UnsafeMutableBufferPointer<Self.Element> {
        let copy = UnsafeMutableBufferPointer<Self.Element>.allocate(capacity: self.count)
        _ = copy.initialize(from: self)
        return copy
    }
}
extension String {
    /// Create UnsafeMutableBufferPointer holding a null-terminated UTF8 copy of the string
    public func unsafeUTF8Copy() -> UnsafeMutableBufferPointer<gchar> { self.utf8CString.unsafeCopy() }
}
...
let about = AboutDialog();
let artistsCredits = [
    "Iconos del catálogo por <a href='https://github.com/twitter/twemoji'>Twemoji</a>",
    "Otros iconos por Jesús Abelardo Saldívar Aguilar",
    "Iconos de escritorio por <a href='https://icons8.com/'>Icons8</a>"
    ].map({ UnsafePointer($0.unsafeUTF8Copy().baseAddress) }).unsafeCopy().baseAddress
about.set(artists: artistsCredits)
'swift run ChickenPOS' terminated by signal SIGSEGV (Address boundary error)

I haven't yet figured how to add a nil last element.

I think SwiftGtk functions or methods accepting UnsafeMutablePointer<UnsafePointer<gchar>?>! as a parameter sould instead accept an array of strings [String] to make them easier to use.

I'm currently running this on Fedora 40 aarch64, Swift 5.8.1

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions