78 lines
3.5 KiB
Swift
78 lines
3.5 KiB
Swift
import Adw
|
|
import GObject
|
|
import Gtk
|
|
|
|
/// Collects the reactive resources created while mounting one subtree so
|
|
/// they can be released together when that subtree unmounts.
|
|
///
|
|
/// Holds subscription tokens, signal handles, and dependency trackers, plus
|
|
/// child registries for independently-unmountable sub-subtrees (e.g. each
|
|
/// `ForEach` row). `teardown()` cancels tokens, disconnects handles, tears
|
|
/// down trackers, and recurses into children.
|
|
@_spi(Portico) @MainActor public final class NodeRegistry {
|
|
private var tokens: [SubscriptionToken] = []
|
|
private var gtkHandles: [Gtk.SignalHandle] = []
|
|
private var adwHandles: [Adw.SignalHandle] = []
|
|
private var gobjectHandles: [GObject.SignalHandle] = []
|
|
private var trackers: [DependencyTracker] = []
|
|
private var children: [NodeRegistry] = []
|
|
private var owners: [AnyObject] = []
|
|
|
|
@_spi(Portico) public init() {}
|
|
|
|
/// Registers a subscription token to cancel on teardown.
|
|
@_spi(Portico) public func add(_ token: SubscriptionToken) { tokens.append(token) }
|
|
|
|
/// Registers a Gtk signal handle to disconnect on teardown.
|
|
@_spi(Portico) public func add(_ handle: Gtk.SignalHandle) { gtkHandles.append(handle) }
|
|
|
|
/// Registers an Adw signal handle to disconnect on teardown.
|
|
@_spi(Portico) public func add(_ handle: Adw.SignalHandle) { adwHandles.append(handle) }
|
|
|
|
/// Registers a GObject signal handle to disconnect on teardown.
|
|
@_spi(Portico) public func add(_ handle: GObject.SignalHandle) { gobjectHandles.append(handle) }
|
|
|
|
/// Registers a dependency tracker to detach from its state boxes on teardown.
|
|
@_spi(Portico) public func add(_ tracker: DependencyTracker) { trackers.append(tracker) }
|
|
|
|
/// Registers a child registry for an independently-unmountable sub-subtree.
|
|
@_spi(Portico) public func addChild(_ child: NodeRegistry) { children.append(child) }
|
|
|
|
/// Retains a stateful mount owner until this registry tears down.
|
|
@_spi(Portico) public func addOwner(_ owner: AnyObject) { owners.append(owner) }
|
|
|
|
/// `true` when nothing has registered here and no child registry exists.
|
|
///
|
|
/// Lets a caller check that a mount left no reactive residue - the
|
|
/// "a static value costs nothing after mount" property.
|
|
@_spi(Portico) public var isEmpty: Bool {
|
|
tokens.isEmpty && gtkHandles.isEmpty && adwHandles.isEmpty
|
|
&& gobjectHandles.isEmpty && trackers.isEmpty && children.isEmpty
|
|
&& owners.isEmpty
|
|
}
|
|
|
|
/// Removes a child registry (called after the child has been torn down,
|
|
/// e.g. a removed `ForEach` row) so this registry no longer retains it.
|
|
@_spi(Portico) public func removeChild(_ child: NodeRegistry) {
|
|
children.removeAll { $0 === child }
|
|
}
|
|
|
|
/// Releases every registered resource and recurses into child registries.
|
|
/// Safe to call more than once (token cancel and handle disconnect are
|
|
/// idempotent).
|
|
@_spi(Portico) public func teardown() {
|
|
for t in tokens { t.cancel() }
|
|
tokens.removeAll()
|
|
for i in gtkHandles.indices { gtkHandles[i].disconnect() }
|
|
gtkHandles.removeAll()
|
|
for i in adwHandles.indices { adwHandles[i].disconnect() }
|
|
adwHandles.removeAll()
|
|
for i in gobjectHandles.indices { gobjectHandles[i].disconnect() }
|
|
gobjectHandles.removeAll()
|
|
for tr in trackers { tr.teardown() }
|
|
trackers.removeAll()
|
|
for c in children { c.teardown() }
|
|
children.removeAll()
|
|
owners.removeAll()
|
|
}
|
|
}
|