4

Is it possible in swift to get a list of all apps with a window in the foreground and then set the size and position of these windows.

I get the list of windows properties like this

let type = CGWindowListOption.optionOnScreenOnly
let windowList = CGWindowListCopyWindowInfo(type, kCGNullWindowID) as NSArray? as? [[String: AnyObject]]

for entry  in windowList!
{

  var owner = entry[kCGWindowOwnerName as String] as! String
  var bounds = entry[kCGWindowBounds as String] as? [String: Int]
  var pid = entry[kCGWindowOwnerPID as String] as? Int32

  print ("\(owner)  \(bounds) \(pid)  ")

  if owner == "Erinnerungen"
  { bounds!["X"] = 0
    bounds!["Y"] = 0
    print("reset bounds")

    let appRef = AXUIElementCreateApplication(pid!);  //TopLevel Accessability Object of PID
    print(appRef)

    var value: AnyObject?
    let result = AXUIElementCopyAttributeValue(appRef, kAXWindowsAttribute as CFString, &value)

    if result == .success, let windowList = value as? [AXUIElement]
    { // DO ANYTHING          
    } else
    { print("Result no Success or no valid windowlist returnd")          
    }
  }
}

Now I try to change some of the propierties, but that has no effect. Also trying to get the AttributeValue for the TopLevel Accessability Object of PID returns AXError (kAXErrorCannotComplete = -25204)

mica
  • 3,898
  • 4
  • 34
  • 62
  • The description of that error is: The function cannot complete because messaging failed in some way or because the application with which the function is communicating is busy or unresponsive. – Infinity James Nov 25 '17 at 16:02
  • I tried with 2 system applications terminal and reminders. With both kAXErrorCannotComplete = -25204. Shouldn't system apps support accessibility? – mica Nov 25 '17 at 17:16
  • 1
    I had to switch off the sandbox, to avoid this error – mica Nov 25 '17 at 19:56

1 Answers1

8

Got it thanks to the help of @Martin R

let type = CGWindowListOption.optionOnScreenOnly
let windowList = CGWindowListCopyWindowInfo(type, kCGNullWindowID) as NSArray? as? [[String: AnyObject]]

for entry  in windowList!
{
  let owner = entry[kCGWindowOwnerName as String] as! String
  var bounds = entry[kCGWindowBounds as String] as? [String: Int]
  let pid = entry[kCGWindowOwnerPID as String] as? Int32

  if owner == "Terminal"
  {
    let appRef = AXUIElementCreateApplication(pid!);  //TopLevel Accessability Object of PID

    var value: AnyObject?
    let result = AXUIElementCopyAttributeValue(appRef, kAXWindowsAttribute as CFString, &value)

    if let windowList = value as? [AXUIElement]
    { print ("windowList #\(windowList)")
      if let window = windowList.first 
      {            
        var position : CFTypeRef
        var size : CFTypeRef
        var  newPoint = CGPoint(x: 0, y: 0)
        var newSize = CGSize(width: 800, height: 800)

        position = AXValueCreate(AXValueType(rawValue: kAXValueCGPointType)!,&newPoint)!;
        AXUIElementSetAttributeValue(windowList.first!, kAXPositionAttribute as CFString, position);

        size = AXValueCreate(AXValueType(rawValue: kAXValueCGSizeType)!,&newSize)!;
        AXUIElementSetAttributeValue(windowList.first!, kAXSizeAttribute as CFString, size);
      }
    } 
  }
}
mica
  • 3,898
  • 4
  • 34
  • 62
  • 1
    Thanks! This is the only example I found that actually works with swift. Also it only worked after enabling xcode and xcode helper accessibility control in system preferences -> security & privacy -> accessibility. Also turn off sandbox under your app's capabilities section as suggested by @mica – Shahar Apr 28 '18 at 21:23
  • Gives error `Couldn't lookup symbols: _CGWindowListCopyWindowInfo` – Mark Setchell Jan 07 '22 at 16:22