Close Window Based on Kcgwindowname Value

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



Leave a reply



Submit