import AppKit import ApplicationServices import CoreGraphics /// Diagnostic used by `open SimpleTopBar.app --args --diag-press`. Presses a /// hidden item's accessibility element without revealing it and dumps the /// resulting high-level windows, to see where its menu actually opens. func dumpWindows() { var lines: [String] = [] if let list = CGWindowListCopyWindowInfo([], kCGNullWindowID) as? [[String: Any]] { for window in list { let layer = window[kCGWindowLayer as String] as? Int ?? -1 guard layer > 20 else { continue } let owner = window[kCGWindowOwnerName as String] as? String ?? "?" let bounds = window[kCGWindowBounds as String] as? [String: Any] ?? [:] let x = bounds["X"] as? Double ?? 0 let y = bounds["Y"] as? Double ?? 0 let width = bounds["Width"] as? Double ?? 0 let height = bounds["Height"] as? Double ?? 0 lines.append("\(owner) layer=\(layer) frame=\(Int(x)),\(Int(y)) \(Int(width))x\(Int(height))") } } try? lines.joined(separator: "\n").write(toFile: "/tmp/simpletopbar-windows.txt", atomically: true, encoding: .utf8) exit(0) } /// Diagnostic used by `open SimpleTopBar.app --args --dump-items`. Writes the /// live Accessibility view of the menu bar to /tmp so it can be inspected /// without a GUI, then exits. func dumpMenuBarItems() { var lines: [String] = [] lines.append("bundle=\(Bundle.main.bundleIdentifier ?? "?")") lines.append("authorized=\(AXIsProcessTrusted())") let items = MenuBarItemManager.enumerate() lines.append("count=\(items.count)") for item in items { let pos = MenuBarItemManager.pointAttribute(item.element, kAXPositionAttribute) lines.append("\(item.appName) | \(item.title) | pid=\(item.pid) | id=\(item.id) | system=\(item.isSystem) | pos=\(pos.map { "\(Int($0.x)),\(Int($0.y))" } ?? "?")") } let own = MenuBarItemManager.enumerate(includeOwn: true).filter { $0.pid == ProcessInfo.processInfo.processIdentifier } lines.append("own-status-items=\(own.count)") for item in own { let pos = MenuBarItemManager.pointAttribute(item.element, kAXPositionAttribute) lines.append("OWN \(item.appName) | \(item.title) | id=\(item.id) | pos=\(pos.map { "\(Int($0.x)),\(Int($0.y))" } ?? "?")") } let text = lines.joined(separator: "\n") try? text.write(toFile: "/tmp/simpletopbar-items.txt", atomically: true, encoding: .utf8) print(text) exit(0) } /// Headless verification for `swift run SimpleTopBar --self-test`. /// Exercises the background-app overflow helpers and reports the live split /// between regular and background applications, then exits 0/1. func runSelfTest() { var failures = 0 func check(_ condition: Bool, _ label: String) { print((condition ? "PASS" : "FAIL") + ": " + label) if !condition { failures += 1 } } // clampedVisibleCount never exceeds the total and never goes negative. check(AppListModel.clampedVisibleCount(current: 10, total: 3) == 3, "clamp caps at total") check(AppListModel.clampedVisibleCount(current: -2, total: 5) == 0, "clamp floors at zero") check(AppListModel.clampedVisibleCount(current: 2, total: 5) == 2, "clamp keeps valid value") // nextVisibleCount pages by backgroundPageSize and stops at the total. let page = AppListModel.backgroundPageSize check(AppListModel.nextVisibleCount(current: page, total: 100) == page * 2, "show more pages forward") check(AppListModel.nextVisibleCount(current: 4, total: 5) == 5, "show more stops at total") check(AppListModel.nextVisibleCount(current: 5, total: 5) == 5, "show more is a no-op at the end") // The section reveals exactly `min(visibleCount, total)` entries. let apps = (0..<12).map { index in RunningApp( id: pid_t(index + 1), name: "App \(index)", bundleID: nil, icon: NSImage(), isHidden: false, isActive: false ) } let hidden = max(0, apps.count - 3) check(hidden == 9, "overflow count hides the tail") // Live snapshot: the split must cover every running app exactly once. let running = NSWorkspace.shared.runningApplications.filter { $0.bundleIdentifier != Bundle.main.bundleIdentifier } let regular = running.filter { $0.activationPolicy == .regular }.count let background = running.filter { $0.activationPolicy != .regular }.count print("running=\(running.count) regular=\(regular) background=\(background)") check(regular + background == running.count, "every running app is classified") // Menu bar item discovery degrades gracefully when it cannot read another // app's UI (accessibility not granted, or the element has no extras bar). let systemWide = AXUIElementCreateSystemWide() check(MenuBarItemManager.extrasMenuBar(of: systemWide) == nil, "no extras bar on a non-app element") check(MenuBarItemManager.children(of: systemWide) == nil, "no children on a non-app element") let element = AXUIElementCreateSystemWide() let first = MenuBarItem(id: "1-0", pid: 1, appName: "A", title: "T", icon: NSImage(), isSystem: false, element: element) let same = MenuBarItem(id: "1-0", pid: 1, appName: "A", title: "T", icon: NSImage(), isSystem: false, element: element) let different = MenuBarItem(id: "1-1", pid: 1, appName: "A", title: "T", icon: NSImage(), isSystem: false, element: element) check(first == same, "menu bar items compare by id and title") check(first != different, "different ids are not equal") // Control Center items map to distinct symbols instead of one shared icon. check(MenuBarItemManager.symbolName(for: "Wi\u{2011}Fi, connected, 3 bars") == "wifi", "wi-fi maps to wifi symbol") check(MenuBarItemManager.symbolName(for: "Battery") == "battery.100", "battery maps to battery symbol") check(MenuBarItemManager.symbolName(for: "Now Playing") == "play.circle", "now playing maps to play symbol") check(MenuBarItemManager.symbolName(for: "Control Center") == "switch.2", "control center maps to switch symbol") check(MenuBarItemManager.symbolName(for: "Search") == "magnifyingglass", "search maps to magnifier symbol") check(MenuBarItemManager.symbolName(for: "cmux") == nil, "unknown titles fall back to the app icon") // Tray sections: Apple bundles are "system", everything else is an app. check(MenuBarItemManager.isSystemBundle("com.apple.controlcenter"), "apple bundles classify as system") check(!MenuBarItemManager.isSystemBundle("com.cmux.app"), "third-party bundles classify as apps") check(!MenuBarItemManager.isSystemBundle(nil), "unknown bundles are treated as apps") let authorized = AXIsProcessTrusted() print("accessibility authorized=\(authorized)") if authorized { print("menu bar items discovered=\(MenuBarItemManager.enumerate().count)") } print(failures == 0 ? "ALL PASS" : "\(failures) FAILURE(S)") exit(failures == 0 ? 0 : 1) }