aboutsummaryrefslogtreecommitdiff
path: root/Sources/phbar/Models/AppDelegate.swift
blob: a7ecb5a91438a0ec659519df4adb243037ff8e07 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
import AppKit
import SwiftUI

@MainActor
final class AppDelegate: NSObject, NSApplicationDelegate {
	private var windows: [BarWindow] = []
	private var blocks: [Block] = Config.blocks.map(\.resolved)
	private var tokens: [UnsafeMutableRawPointer] = []

	func applicationDidFinishLaunching(_ notification: Notification) {
		for screen in NSScreen.screens {
			let frame = Screen.barFrame(screen, position: Config.position, height: Config.height)
			let window = BarWindow(contentRect: frame)
			window.contentView = NSHostingView(rootView: BarView(blocks: blocks))
			window.orderFrontRegardless()
			windows.append(window)
		}

		// Register one listener per unique name; a single post fans out to every
		// block with that name (see Notifier).
		for name in Set(blocks.map(\.name)) {
			let token = Notifier.register(name) { [weak self] in
				self?.handleRefresh(name)
			}
			tokens.append(token)
		}

		for block in blocks { block.start() }
	}

	func applicationWillTerminate(_ notification: Notification) {
		for block in blocks { block.stop() }
		for token in tokens { Notifier.cancel(token) }
	}

	/// Called from a Darwin notification handler. Marked `nonisolated` because
	/// libnotify's delivery contract isn't statically visible to Swift, so we
	/// hop back to the main actor explicitly.
	nonisolated func handleRefresh(_ name: String) {
		Task { @MainActor [weak self] in
			guard let self else { return }
			for block in self.blocks where block.name == name {
				block.runScript()
			}
		}
	}
}