- 实时 CPU/GPU/内存/Swap 监控 + Top 进程 - 5 种计量器样式(圆环/条状/纯文本/扇形/紧凑) - 半透明悬浮窗 + 菜单栏图标控制 - 独立设置窗口,每模块可指定行号+列位布局 - 窗口宽高/透明度/字体全局可调
121 lines
4.2 KiB
Swift
121 lines
4.2 KiB
Swift
import AppKit
|
|
|
|
// MARK: - 通知名
|
|
|
|
extension Notification.Name {
|
|
static let showSettingsPanel = Notification.Name("FloatingMonitor.ShowSettings")
|
|
static let resizeMonitorWindow = Notification.Name("FloatingMonitor.ResizeWindow")
|
|
static let refreshIntervalChanged = Notification.Name("FloatingMonitor.RefreshIntervalChanged")
|
|
}
|
|
|
|
// MARK: - AppDelegate
|
|
|
|
final class AppDelegate: NSObject, NSApplicationDelegate {
|
|
private var windowController: FloatingWindowController?
|
|
private var settingsWindowController: SettingsWindowController?
|
|
private var statusItem: NSStatusItem?
|
|
private var statusMenu: NSMenu!
|
|
|
|
let systemMonitor = SystemMonitor()
|
|
|
|
func applicationDidFinishLaunching(_ notification: Notification) {
|
|
NSApp.setActivationPolicy(.accessory)
|
|
|
|
windowController = FloatingWindowController()
|
|
let contentView = ContentView(monitor: systemMonitor, windowController: windowController)
|
|
windowController?.embed(rootView: contentView)
|
|
|
|
let cfg = Configuration.shared
|
|
windowController?.resize(width: cfg.windowWidth, height: cfg.windowHeight)
|
|
|
|
systemMonitor.interval = cfg.refreshInterval
|
|
systemMonitor.topN = cfg.processCount
|
|
systemMonitor.start()
|
|
|
|
setupStatusItem()
|
|
observeResize()
|
|
}
|
|
|
|
// MARK: - 菜单栏
|
|
|
|
private func setupStatusItem() {
|
|
statusItem = NSStatusBar.system.statusItem(withLength: NSStatusItem.squareLength)
|
|
guard let button = statusItem?.button else { return }
|
|
|
|
if let image = NSImage(systemSymbolName: "gauge.with.dots.needle.33percent",
|
|
accessibilityDescription: "Monitor") {
|
|
image.isTemplate = true
|
|
button.image = image
|
|
}
|
|
button.toolTip = "Monitor"
|
|
|
|
statusMenu = NSMenu()
|
|
|
|
let toggleItem = NSMenuItem(title: "显示 Monitor", action: #selector(menuToggleWindow), keyEquivalent: "")
|
|
toggleItem.target = self
|
|
statusMenu.addItem(toggleItem)
|
|
statusMenu.addItem(.separator())
|
|
|
|
let settingsItem = NSMenuItem(title: "显示设置…", action: #selector(menuOpenSettings), keyEquivalent: ",")
|
|
settingsItem.keyEquivalentModifierMask = .command
|
|
settingsItem.target = self
|
|
statusMenu.addItem(settingsItem)
|
|
statusMenu.addItem(.separator())
|
|
|
|
let quitItem = NSMenuItem(title: "退出 Monitor", action: #selector(menuQuit), keyEquivalent: "q")
|
|
quitItem.keyEquivalentModifierMask = .command
|
|
quitItem.target = self
|
|
statusMenu.addItem(quitItem)
|
|
|
|
statusItem?.menu = statusMenu
|
|
|
|
button.target = self
|
|
button.action = #selector(statusItemClicked)
|
|
button.sendAction(on: [.leftMouseDown, .rightMouseDown])
|
|
}
|
|
|
|
@objc private func statusItemClicked() {
|
|
guard let event = NSApp.currentEvent else { return }
|
|
if event.type == .rightMouseDown {
|
|
updateToggleMenuItemTitle()
|
|
} else {
|
|
toggleWindow()
|
|
}
|
|
}
|
|
|
|
@objc private func menuToggleWindow() { toggleWindow() }
|
|
@objc private func toggleWindow() { windowController?.toggleVisible() }
|
|
@objc private func menuOpenSettings() { openSettingsWindow() }
|
|
@objc private func menuQuit() { NSApp.terminate(nil) }
|
|
|
|
private func updateToggleMenuItemTitle() {
|
|
let visible = windowController?.isVisible ?? false
|
|
statusMenu.item(at: 0)?.title = visible ? "隐藏 Monitor" : "显示 Monitor"
|
|
}
|
|
|
|
// MARK: - 设置窗口
|
|
|
|
private func openSettingsWindow() {
|
|
if settingsWindowController == nil {
|
|
settingsWindowController = SettingsWindowController(monitor: systemMonitor)
|
|
}
|
|
settingsWindowController?.show()
|
|
}
|
|
|
|
// MARK: - 监听
|
|
|
|
private func observeResize() {
|
|
NotificationCenter.default.addObserver(
|
|
forName: .resizeMonitorWindow, object: nil, queue: .main
|
|
) { [weak self] notification in
|
|
guard let size = notification.object as? NSSize else { return }
|
|
self?.windowController?.resize(width: size.width, height: size.height)
|
|
}
|
|
}
|
|
|
|
func applicationShouldHandleReopen(_ sender: NSApplication, hasVisibleWindows flag: Bool) -> Bool {
|
|
windowController?.show()
|
|
return true
|
|
}
|
|
}
|