home ~ projects ~ socials

Get A List Of Open/Running Apps That Have Windows On A Mac With Swift

Notes

  • This is the first way I got this to work. Wouldn't surprise me to find there's a more straight forward way.
  • This calls the runningApps() function a lot. Would probably be better to memoize that.
import SwiftUI
import CoreGraphics

struct PotentialApp: Identifiable, Hashable {
    let app: NSRunningApplication
    let id: pid_t
}

struct ContentView: View {
    @State private var selectedAppPid = pid_t()
    
    func runningApps() -> [PotentialApp] {
        let kCGNullWindowID: UInt32 = 0
        guard let windows = CGWindowListCopyWindowInfo([.optionOnScreenOnly], kCGNullWindowID) as NSArray? as? [[String: AnyObject]] else {
            return []
        }
        var filteredWindows: [pid_t] = []
        windows.forEach {
            let ownerPid = $0[kCGWindowOwnerPID as String] as! pid_t
            let ownerName = $0[kCGWindowOwnerName as String] as! String
            if ownerName != "Dock" && ownerName != "Window Server" {
                if !filteredWindows.contains(ownerPid) {
                    filteredWindows.append(ownerPid)
                }
            }
        }
        let baseApps = NSWorkspace.shared.runningApplications
        let initialFilteredApps = baseApps.filter {checkApp in
            filteredWindows.contains(checkApp.processIdentifier)
        }
            .sorted(by: {
                $0.localizedName?.lowercased() ?? "unknown name" < $1.localizedName?.lowercased() ?? "unknown name"})
            .map{ PotentialApp(app: $0, id: $0.processIdentifier)}
        return initialFilteredApps
    }
    
    func selectedAppName() -> String? {
        guard let selectedAppIndex = runningApps().firstIndex(where: { $0.app.processIdentifier == selectedAppPid })
        else {
            return Optional.none
        }
        return runningApps()[selectedAppIndex].app.localizedName
    }
    
    var body: some View {
        VStack {
            List(runningApps(), selection: $selectedAppPid) {
                Text($0.app.localizedName ?? "unknown name")
            }
            Divider()
            Text("Selected App: \(selectedAppName() ?? "tbd")")
        }
    }
}

#Preview {
    ContentView()
}
-- end of line --