diff --git a/App/Sources/MusubiApp.swift b/App/Sources/MusubiApp.swift index 72fc566..f29a36e 100644 --- a/App/Sources/MusubiApp.swift +++ b/App/Sources/MusubiApp.swift @@ -1,3 +1,4 @@ +import AppKit import DesignSystem import NDIKit import OSLog @@ -5,31 +6,35 @@ import SwiftUI @main struct MusubiApp: App { - @State private var sourceList = SourceListModel() - @State private var coordinator: Coordinator = { - MainActor.assumeIsolated { - Coordinator(settings: AppSettings(), outputs: OutputController(), audio: AudioController()) - } - }() + @NSApplicationDelegateAdaptor private var appDelegate: AppDelegate var body: some SwiftUI.Scene { Window("Musubi", id: "main") { - ContentView(sourceList: sourceList, coordinator: coordinator) + ContentView(sourceList: appDelegate.sourceList, coordinator: appDelegate.coordinator) .preferredColorScheme(.dark) - .task { - sourceList.start() - await coordinator.start() - } } .defaultSize(width: 960, height: 600) Settings { - SettingsView(coordinator: coordinator) + SettingsView(coordinator: appDelegate.coordinator) .preferredColorScheme(.dark) } } } +/// Starts discovery, outputs, audio and remote control at launch – independent of any window. +/// As a login item macOS may launch Musubi without opening its window. +@MainActor +final class AppDelegate: NSObject, NSApplicationDelegate { + let sourceList = SourceListModel() + let coordinator = Coordinator(settings: AppSettings(), outputs: OutputController(), audio: AudioController()) + + func applicationDidFinishLaunching(_ notification: Notification) { + sourceList.start() + Task { await coordinator.start() } + } +} + enum Log { static let ndi = Logger(subsystem: "studio.zielke.musubi", category: "ndi") static let audio = Logger(subsystem: "studio.zielke.musubi", category: "audio")