rhx/SwiftGdk

Threading convenience functions

lschmierer opened this issue · 1 comments

In my GTK project, I need to communicate with the main thread to update the UI.

To be able to use Swift closures, I am using something along the lines

typealias ThreadCallback = () -> Bool

class ThreadCallbackHolder {
    public let call: ThreadCallback
    
    public init(_ closure: @escaping ThreadCallback) {
        self.call = closure
    }
}

func _threadsAddIdle(data: ThreadCallbackHolder, handler: @convention(c) @escaping (gpointer) -> gboolean) -> Int {
    let opaqueHolder = Unmanaged.passRetained(data).toOpaque()
    let callback = unsafeBitCast(handler, to: GSourceFunc.self)
    let rv = threadsAddIdleFull(priority: Int(G_PRIORITY_DEFAULT_IDLE), function: callback, data: opaqueHolder, notify: {
        if let swift = $0 {
            let holder = Unmanaged<ThreadCallbackHolder>.fromOpaque(swift)
            holder.release()
        }
    })
    return rv
}

func threadsAddIdle(callback: @escaping ThreadCallback) -> Int {
    let rv = _threadsAddIdle(data: ThreadCallbackHolder(callback)) {
        let holder = Unmanaged<ThreadCallbackHolder>.fromOpaque($0).takeUnretainedValue()
        let rv: gboolean = holder.call() ? 1 : 0
        return rv
    }
    return rv
}

I think this would be a useful addition.

rhx commented

I have committed a closure wrapper around threadsAddIdle() now. Please note, though, that Gdk threading functions have been removed upstream under gtk 4. So if you want to use continue to use threads in gtk4, make sure that you only call gdk/gtk functions on the main thread, using either the underlying GLib functions, or Dispatch in Swift.