How to get WindowCount of other applications using Swift - swift

how do I get the current WindowCount of other applications?
I'm using Swift as programming language and developing for OS X.
Have a nice day.

Import CoreGraphics and check out CGWindowListCopyWindowInfo:
import CoreGraphics
let kCGNullWindowID: UInt32 = 0
// Check the documentation for other options
guard let windows = CGWindowListCopyWindowInfo([.OptionOnScreenOnly], kCGNullWindowID) as NSArray? as? [[String: AnyObject]] else {
fatalError("Can't find windows")
}
var windowCount = [String: Int]()
windows.forEach {
let ownerName = $0[kCGWindowOwnerName as String] as! String
if let count = windowCount[ownerName] {
windowCount[ownerName] = count + 1
} else {
windowCount[ownerName] = 1
}
}
print(windowCount)

Related

Get human readable name for Mac model on Ventura

I have used the following code for get the model identifier of a Mac computer:
public static var modelIdentifier: String {
var size = 0
sysctlbyname("hw.model", nil, &size, nil, 0)
var machine = [CChar](repeating: 0, count: Int(size))
sysctlbyname("hw.model", &machine, &size, nil, 0)
return String(cString: machine)
}
This model identifier is used in this variable to get a human readable name of the device:
public static var marketingModel: String {
guard let currentIdentifier = NSLocale.current.languageCode else { return String.hyphen }
let modelIdentifier = self.modelIdentifier
var path = "/System/Library/PrivateFrameworks/ServerInformation.framework/Versions/A/Resources/"
path += currentIdentifier + ".lproj"
path += "/SIMachineAttributes.plist"
if let fileData = FileManager.default.contents(atPath: path) {
if let plistContents = try? PropertyListSerialization.propertyList(from: fileData, format: nil)
as? [String: Any]
{
if let contents = plistContents[modelIdentifier] as? [String: Any],
let localizable = contents["_LOCALIZABLE_"] as? [String: String]
{
let marketingModel = localizable["marketingModel"] ?? String.hyphen
return marketingModel
}
}
}
return String.hyphen
}
This returned strings like MacBook Pro (16-inch, 2019). However, on the latest MacOS Ventura build, no string is returned for Mac Mac Studio (Mac13,1).
Is there another way to get this string? Do I have to look in a different plist?
I have used the IORegistryExplorer and found a key that contains this information.
By running the following code in a playground, you can extract the name:
import Cocoa
import IOKit
let mainEntry = IORegistryEntryFromPath(kIOMainPortDefault, "IOService:/AppleARMPE/product")
let property = IORegistryEntryCreateCFProperty(mainEntry, "product-description" as CFString, kCFAllocatorDefault, 0)
if let bytes = property?.takeRetainedValue() as? Data
{
let array = [UInt8](bytes)
let terminatedModelString = String(cString: array)
Swift.print(terminatedModelString)
}
IOObjectRelease(mainEntry)
The key suggests that this will only work for Apple Silicon based machines. For Intel based machines, you can still use the code from my initial question.

CFDictionary get Value for Key in Swift3

I've a problem with accessing a specific (or any) key in a CFDictionary.
Honestly I don't really get the way you need to do this in Swift and I think it's overly complicated...
My Code:
if let session = DASessionCreate(kCFAllocatorDefault) {
let mountedVolumes = FileManager.default.mountedVolumeURLs(includingResourceValuesForKeys: [], options: [])!
for volume in mountedVolumes {
if let disk = DADiskCreateFromVolumePath(kCFAllocatorDefault, session, volume as CFURL) {
let diskinfo = DADiskCopyDescription(disk);
var volumeValue = CFDictionaryGetValue(diskinfo, <#T##key: UnsafeRawPointer!##UnsafeRawPointer!#>)
}
}
What I want to achieve: Get the Value for the Key or field DAVolumeNetwork into the variable volumeValue.
I guess I need to pass the kDADiskDescriptionVolumeNetworkKey to the CFDictionaryGetValue Method? How do I achieve this?
Don't use CFDictionary in Swift. (It is possible, but not worth the effort, see below.)
CFDictionary is toll-free
bridged with NSDictionary, which in turn can be cast to a Swift Dictionary.
The value of the kDADiskDescriptionVolumeNetworkKey key is a
CFBoolean which can be cast to a Swift Bool.
Example:
if let session = DASessionCreate(kCFAllocatorDefault),
let mountedVolumes = FileManager.default.mountedVolumeURLs(includingResourceValuesForKeys: []) {
for volume in mountedVolumes {
if let disk = DADiskCreateFromVolumePath(kCFAllocatorDefault, session, volume as CFURL),
let diskinfo = DADiskCopyDescription(disk) as? [NSString: Any] {
if let networkValue = diskinfo[kDADiskDescriptionVolumeNetworkKey] as? Bool {
print(networkValue)
}
}
}
}
Just for the sake of completeness: This is the necessary pointer
juggling to call CFDictionaryGetValue in Swift 3:
if let session = DASessionCreate(kCFAllocatorDefault),
let mountedVolumes = FileManager.default.mountedVolumeURLs(includingResourceValuesForKeys: []) {
for volume in mountedVolumes {
if let disk = DADiskCreateFromVolumePath(kCFAllocatorDefault, session, volume as CFURL),
let diskinfo = DADiskCopyDescription(disk) {
if let ptr = CFDictionaryGetValue(diskinfo, Unmanaged.passUnretained(kDADiskDescriptionVolumeNetworkKey).toOpaque()) {
let networkValue = Unmanaged<NSNumber>.fromOpaque(ptr).takeUnretainedValue()
print(networkValue.boolValue)
}
}
}
}
You can cast CFDictionaryRef to a Swift dictionary:
if let disk = DADiskCreateFromVolumePath(kCFAllocatorDefault, session, volume as CFURL), let diskinfo = DADiskCopyDescription(disk) as? [String: AnyObject] {
}
and then cast kDADiskDescriptionVolumeNetworkKey to a Swift string:
var volumeValue = diskinfo[kDADiskDescriptionVolumeNetworkKey as String]

Checking anyobject value in Swift

With the following piece of code:
let decoded = NSJSONSerialization.JSONObjectWithData(data as! NSData, options: NSJSONReadingOptions.MutableContainers, error: nil) as! [String:AnyObject]
I get [latitude: 40.3654922, won: 1, longitude: 49.9384457, winnerID: 552e].
And now I want to check if won object equal to '1' do something. But I cannot check the value of the object. I s any way to do it?
With swift 1.2, you can do:
if let won = decoded["won"] as? Int where won == 1 {
// do something
}
Take a look at swift 1.2 release note (included in Xcode 6.3 release notes), we find that if let now support multiple condition check. For example:
if let a = foo(), b = bar() where a < b,
let c = baz() {
}
or
if someValue > 42 && someOtherThing < 19, let a = getOptionalThing() where a > someValue {
}
Very powerful!
if let won = decoded["won"] as? Int {
if won == 1 {
// do something
}
}

how to cast from CFTypeRef to AXUIElement in Swift

This code produces the expected debugging output type = AXUIElement, but dumps stack and says the dynamic cast failed at the actual point of the cast:
func mainWindow() {
var ptr: Unmanaged<AnyObject>?
let kAXMainWindow: CFString! = "AXMainWindow" as NSString
let appRef: AXUIElement! = AXUIElementCreateApplication(self.pid()).takeRetainedValue()
let err = AXUIElementCopyAttributeValue(appRef, kAXMainWindow, &ptr)
if err == AXError(kAXErrorSuccess) {
let val: AnyObject? = ptr?.takeRetainedValue()
if val != nil {
let value: AnyObject = val!
let description = CFCopyTypeIDDescription(CFGetTypeID(value))
println("type = \(description)")
let element = value as AXUIElement
}
else {
println("got nil result")
}
}
}
What's the right way to get this done?
This code worked as of XCode 6.1 and Swift 1.1.
However, it's 3 years later now and Swift has gotten a lot better. Still, this is still a top result when you search for how to work with the Accessibility API from Swift. So I'm back to update with the current simplest way I know:
func AXUIWindowArray(processIdentifier pid:pid_t) -> [AXUIElement] {
var result = [AXUIElement]()
var windowList: AnyObject? = nil // [AXUIElement]
let appRef = AXUIElementCreateApplication(pid)
if AXUIElementCopyAttributeValue(appRef, "AXWindows" as CFString, &windowList) == .success {
result = windowList as! [AXUIElement]
}
return result
}

CMFormatDescription to CMVideoFormatDescription

I'm trying to get the resolution of the camera of a device using swift.
I'm using CMVideoFormatDescriptionGetDimensions which requires a CMVideoFormatDescription, but AVCaptureDevice.formatDescription returns a CMFormatDescription. I've tried a multitude of ways to cast CMFormatDescription to CMVideoFormatDescription and can't seem to get it working.
Below is a sample of the code that I'm using:
for format in device.formats as [AVCaptureDeviceFormat] {
let videoDimensions = CMVideoFormatDescriptionGetDimensions(format.formatDescription)
}
This doesn't seem possible in Swift at the moment. One solution then would be to write a helper function in objective-c, such as:
CMVideoDimensions CMFormatDescriptionGetDimensions(CMFormatDescriptionRef formatDescription)
{
if (CMFormatDescriptionGetMediaType(formatDescription) == kCMMediaType_Video)
return CMVideoFormatDescriptionGetDimensions(formatDescription);
else
return (CMVideoDimensions) {
.width = 0,
.height = 0
};
}
Include the header with the function prototype in the Swift bridging header so that it will be accessible as a global function from your Swift code.
I was able to get the resolution using the swift method below:
let captureDevice = AVCaptureDevice.defaultDeviceWithMediaType(AVMediaTypeVideo) as AVCaptureDevice
let formatDesc = captureDevice.activeFormat.formatDescription
let dimensions = CMVideoFormatDescriptionGetDimensions(formatDesc)
Here's a solution in pure Swift, really only usable for logging purposes and such. Paste the following function in your class or somewhere else:
func widthAndHeightFromTrack(track: AVAssetTrack) -> CGSize {
let str = track.formatDescriptions.description
let regex = try! NSRegularExpression(pattern: "[0-9]{2,4} x [0-9]{2,4}", options: [])
if let result = regex.firstMatchInString(str, options: [], range: NSMakeRange(0, str.characters.count)) {
let dimensionString = (str as NSString).substringWithRange(result.range)
let dimensionArray = dimensionString.componentsSeparatedByString(" x ")
let width = Int(dimensionArray[0])
let height = Int(dimensionArray[1])
return CGSize(width: width!, height: height!)
}
return CGSizeZero
}
Example usage:
let allTracks: AVAsset = someAVAsset.tracksWithMediaType(AVMediaTypeVideo)
let videoTrack = allTracks[0]
let videoTrackDimensions = widthAndHeightFromTrack(videoTrack)
// You now have a CGSize, print it
print("Dimensions: \(videoTrackDimensions)")
Of course, the above solution will completely break whenever Apple changes something in the string representation of the CMFormatDescription. But it's useful for logging the dimensions.
Maybe, question is too old, but the Swift issue is still not fixed.
public extension AVURLAsset {
var audioFormatDescription: CMAudioFormatDescription? {
if let track = self.tracks(withMediaType: .audio).first,
let untypedDescription = track.formatDescriptions.first {
// hacks, warnings, disablings of swiftlint below are wrork-around of
// Swift bug: it fails converting 'Any as CMFormatDescription'
let forceTyped: CMFormatDescription?
//swiftlint:disable force_cast
= untypedDescription as! CMAudioFormatDescription
//swiftlint:enable force_cast
if let description = forceTyped {
return description
} else {
return nil
}
} else {
return nil
}
}
}