close window based on kCGWindowName value
You can use the accessibility API:
- You need to enable accessibility for your application or Xcode (if
you test your application from Xcode). Open the "Security & Privacy" pane on the "System Preferences"
window. Click the "Privacy" tab.Select "Accessibility" from the list in the left pane.
Click the lock icon to make changes.
Drag/drop your application or Xcode in the right pane.
Here's an example of the swift code (Swift version 2.2) to simulate a click on the red button of the window whose the title start with "Warnings":
func activated(notification: NSNotification) {
if (notification.userInfo![NSWorkspaceApplicationKey]!.localizedName) == "Pages" { // when "Pages" application is active only
let myApp = AXUIElementCreateApplication(notification.userInfo![NSWorkspaceApplicationKey]!.processIdentifier).takeUnretainedValue()
let val1 = UnsafeMutablePointer<AnyObject?>.alloc(1)
if AXUIElementCopyAttributeValue(myApp, kAXWindowsAttribute, val1).rawValue == 0 { // get windows of the "Pages" application
let windowList = val1.memory as? [AXUIElement] ?? []
for w in windowList { // loop each window, get the title of the window, and check if the title starts with "Warning"
if AXUIElementCopyAttributeValue(w, kAXTitleAttribute, val1).rawValue == 0 && (val1.memory as! String).hasPrefix("Warnings") {
if AXUIElementCopyAttributeValue(w, kAXCloseButtonAttribute, val1).rawValue == 0 {// get the red button of the window
AXUIElementPerformAction(val1.memory as! AXUIElement, kAXPressAction); // close the window
}
}
}
}
val1.dealloc(1)
}
}
To check the title equal "Warnings": use val1.memory as! String == "Warnings"
Informations on the infoList
from your code:
How would I go about checking windows for the name I want without
casting to a String?
Use a string instead of the constant, like this:
if item["kCGWindowName"]! as! String == "Warnings" {
What is the value of kCGWindowName?
Something like this...
CFArrayRef windowsInfo = CGWindowListCopyWindowInfo(listOptions, kCGNullWindowID);
for (CFIndex idx=0; idx<CFArrayGetCount(windowsInfo); idx++) {
CFDictionaryRef dict = CFArrayGetValueAtIndex(windowsInfo, idx);
CFStringRef windowName = CFDictionaryGetValue(dict, kCGWindowName);
NSString* nsWindowName = (NSString*)windowName;
}
CFRelease(windowsInfo);
Determine which screen a window is on given the window ID
The reason this information is not available is probably because a window can be on more than one screen at once. If the user has dragged the window so that a portion of it is in one window and the rest in another, there is no such thing as the current screen.
Your window bounds estimation method is probably the best option.
How to know whether a window is minimised or not?
The issue was caused by MS Word.
It creates a full screen window which is not visible but listed among the visible windows. CGWindowListCopyWindowInfo lists visible/minimised windows correctly.
CFArray takeRetainedValue() removal causing crashes
There are some funky changes to accessing CoreFoundation objects in Swift 2. You no longer need to take a retained or unretained value from a CFArray
, you can bridge it directly to a Swift array. You're getting a crash because you're trying to cast a CFArray
to a [[String : AnyObject]]
at runtime and it's returning nil
.
CGWindowListCopyWindowInfo
returns CFArray?
(an optional CFArray
). Trying to bridge CFArray?
to [AnyObject]
will fail, but bridging it to an optional Swift array ([AnyObject]?
) will work. But in order to iterate through that array we must unwrap it. Here I check if the CFArray
returned by CGWindowListCopyWindowInfo
can be unwrapped and bridged to [AnyObject]!
:
if let info = CGWindowListCopyWindowInfo(.OptionAll, CGWindowID(0)) as [AnyObject]! {
for dict in info {
if let windowName = dict[kCGWindowName as String] as? String {
if (windowName == "MyWindowName"){
let windowID = dict[kCGWindowNumber as String] as? Int
print("found window, window number: \(windowID)")
break
}
}
}
}
If for whatever reason CGWindowListCopyWindowInfo
returns nil, we won't try to iterate through it.
Also note that the CFString
constants kCGWindowName
and kCGWindowNumber
can be bridged to a Swift String
object no problem. It's better to use the constants than hardcoded strings, as the value of the constant may change over time.
Related Topics
Swift's Decimal Precision Issue
How to Move an Object Towards a Direction Without Stopping
Swift: Method Overriding in Parameterized Class
How to Center Nspopover When Using Swiftui
Adding Data to a Specific UId in Firebase
How to Bind My Array Controller to My Core Data Model
How to Draw Something on a PDF in Swift
How to Create Travelling Wave in Spritekit
Decrypting Des with Commoncrypto in Swift 3
Swiftui Tabview with List Not Refreshing After Objected Deleted From/Added to Core Data
Arkit: Plot a Node at a Specific Pixel at a Specific Z Distance from Camera
How to Determine Whether a Double Is an Integer
How to Convert a Pair of Bytes into a Float Using Swift
Error: Missing Return in a Closure Expected to Return 'Uiviewcontroller' (Xcode, Swift, iOS 13)