@_spi(SGTKInternal) import GLib // MARK: - Raw GLib entry points // // gtk-swift's GLib wrapper exposes no binding for these, and `CGLib` is not a // package product, so declare them directly - same idiom as // Core/View+Conveniences.swift. @_silgen_name("g_source_set_callback") nonisolated func portico_g_source_set_callback( _ source: UnsafeMutableRawPointer, _ fn: @convention(c) (UnsafeMutableRawPointer?) -> Int32, _ data: UnsafeMutableRawPointer?, _ notify: (@convention(c) (UnsafeMutableRawPointer?) -> Void)? ) @_silgen_name("g_source_set_priority") nonisolated func portico_g_source_set_priority( _ source: UnsafeMutableRawPointer, _ priority: Int32 ) @_silgen_name("g_source_attach") nonisolated func portico_g_source_attach( _ source: UnsafeMutableRawPointer, _ context: UnsafeMutableRawPointer? ) -> UInt32 @_silgen_name("g_source_destroy") nonisolated func portico_g_source_destroy(_ source: UnsafeMutableRawPointer) @_silgen_name("g_source_is_destroyed") nonisolated func portico_g_source_is_destroyed(_ source: UnsafeMutableRawPointer) -> Int32 // MARK: - Source Id /// A handle to a live GLib main-loop source created by ``Idle(priority:repeats:_:)`` /// or ``Timeout(interval:priority:repeats:_:)``. /// /// Removal is idempotent and safe at any time, including from inside the /// source's own callback: the handle retains the underlying `GSource` and /// detaches it with `g_source_destroy`, so it never risks acting on a reissued /// source tag the way `g_source_remove` does. /// /// Letting the handle go out of scope does **not** remove the source - unlike /// ``SubscriptionToken``, which cancels on release. Removal is always explicit, /// or automatic via the appearance-scoped ``View/task(priority:_:)`` / /// ``View/task(every:priority:_:)`` modifiers. @MainActor public final class SourceId { /// The GLib source tag (`g_source_get_id`), assigned when the source is /// attached. Exposed for interop with raw GLib APIs only - use ``remove()`` /// to detach the source, never `g_source_remove(rawValue)`. public internal(set) var rawValue: UInt32 = 0 private let source: GLib.Source init(source: GLib.Source) { self.source = source } /// `true` once the source is detached - either by ``remove()``, or by GLib /// after a non-repeating callback returned. public var isRemoved: Bool { portico_g_source_is_destroyed(source.pointer) != 0 } /// Detaches the source from the main loop. Idempotent; safe to call from /// inside the source's own callback. public func remove() { guard !isRemoved else { return } portico_g_source_destroy(source.pointer) } }