diff options
| author | Tommaso Negri <me@tommasongr.com> | 2026-07-27 16:18:34 +0200 |
|---|---|---|
| committer | Tommaso Negri <me@tommasongr.com> | 2026-07-27 16:18:34 +0200 |
| commit | 535b42a7b8304340182ca1367aa42f047eb06bff (patch) | |
| tree | 88e15512f874a00886fc7b97861feb5e92c6aaf5 /Sources/phbar/Models/Notifier.swift | |
| parent | 6d165c74a5a6b471c155b12ab15ef833d6b2aa36 (diff) | |
| download | bar-535b42a7b8304340182ca1367aa42f047eb06bff.tar.gz bar-535b42a7b8304340182ca1367aa42f047eb06bff.zip | |
scaffold basic structure
Diffstat (limited to 'Sources/phbar/Models/Notifier.swift')
| -rw-r--r-- | Sources/phbar/Models/Notifier.swift | 55 |
1 files changed, 55 insertions, 0 deletions
diff --git a/Sources/phbar/Models/Notifier.swift b/Sources/phbar/Models/Notifier.swift new file mode 100644 index 0000000..1124cd4 --- /dev/null +++ b/Sources/phbar/Models/Notifier.swift @@ -0,0 +1,55 @@ +import Foundation + +// Darwin notifications via CoreFoundation — the macOS-native, signal-like way +// to trigger a refresh from the shell with no client binary: +// +// notifyutil -p <prefix><name> +// +// e.g. notifyutil -p house.panini.phbar.touch.workspaces +// +// (notify.h isn't part of Swift's Darwin module, so we go through +// CFNotificationCenter, which talks to the same subsystem.) +// +// The callback fires on an arbitrary thread; handlers must hop to the main +// actor themselves (see AppDelegate.handleRefresh). + +/// Retains the handler for the lifetime of the registration. +private final class NotifyBox { + let handler: @Sendable () -> Void + init(_ handler: @escaping @Sendable () -> Void) { self.handler = handler } +} + +enum Notifier { + static let prefix = "house.panini.phbar.touch." + + /// Register `handler` to fire whenever the notification is posted. + @discardableResult + static func register(_ name: String, handler: @escaping @Sendable () -> Void) + -> UnsafeMutableRawPointer + { + let fullName = prefix + name + let ctx = Unmanaged.passRetained(NotifyBox(handler)).toOpaque() + + CFNotificationCenterAddObserver( + CFNotificationCenterGetDarwinNotifyCenter(), + ctx, + { _, observer, _, _, _ in + guard let observer else { return } + let box = Unmanaged<NotifyBox>.fromOpaque(observer).takeUnretainedValue() + box.handler() + }, + fullName as CFString, + nil, + .deliverImmediately + ) + + return ctx + } + + /// Remove and release a registration. (Optional: process exit clears all.) + static func cancel(_ token: UnsafeMutableRawPointer) { + let center = CFNotificationCenterGetDarwinNotifyCenter() + CFNotificationCenterRemoveEveryObserver(center, token) + Unmanaged<NotifyBox>.fromOpaque(token).release() + } +} |
