Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
jasaldivara opened this issue Jun 30, 2024 · 0 comments

Comments

@jasaldivara
Copy link

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant