Files
ggbond268--mactools/Plugins/XcodeClean/Sources/XcodeCleanRunningMonitor.swift
T
wehub-resource-sync 1d1286fadb
Build / Build and test (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 13:18:38 +08:00

74 lines
2.2 KiB
Swift

import AppKit
import Foundation
@MainActor
protocol XcodeCleanRunningMonitoring: AnyObject {
var isXcodeRunning: Bool { get }
var onStateChange: (() -> Void)? { get set }
func start()
func stop()
func refresh()
}
@MainActor
final class XcodeCleanRunningMonitor: XcodeCleanRunningMonitoring {
nonisolated static let xcodeBundleIdentifier = "com.apple.dt.Xcode"
private(set) var isXcodeRunning: Bool = false
var onStateChange: (() -> Void)?
private var observers: [NSObjectProtocol] = []
private let workspace: NSWorkspace
init(workspace: NSWorkspace = .shared) {
self.workspace = workspace
}
func start() {
guard observers.isEmpty else { return }
let center = workspace.notificationCenter
let launched = center.addObserver(
forName: NSWorkspace.didLaunchApplicationNotification,
object: nil,
queue: .main
) { [weak self] notification in
guard let app = notification.userInfo?[NSWorkspace.applicationUserInfoKey] as? NSRunningApplication,
app.bundleIdentifier == Self.xcodeBundleIdentifier
else { return }
Task { @MainActor [weak self] in self?.refresh() }
}
let terminated = center.addObserver(
forName: NSWorkspace.didTerminateApplicationNotification,
object: nil,
queue: .main
) { [weak self] notification in
guard let app = notification.userInfo?[NSWorkspace.applicationUserInfoKey] as? NSRunningApplication,
app.bundleIdentifier == Self.xcodeBundleIdentifier
else { return }
Task { @MainActor [weak self] in self?.refresh() }
}
observers = [launched, terminated]
refresh()
}
func stop() {
for observer in observers {
workspace.notificationCenter.removeObserver(observer)
}
observers.removeAll()
}
func refresh() {
let nextValue = workspace.runningApplications.contains { app in
app.bundleIdentifier == Self.xcodeBundleIdentifier
}
guard nextValue != isXcodeRunning else { return }
isXcodeRunning = nextValue
onStateChange?()
}
}