Just A Minnion Just A Minnion - 4 months ago 32
Swift Question

Getting null pointer exception trying to get bounds from current active window with swift on OSX

I am trying to determine if current foreground application is in fullscreen mode (another application). I googled extensively to find an answer and I found similar Objective-C example that I converted the best I could to swift for my case (I'm really bad at Objective-C).

Objective-C example

The problem is that I get an exception because bounds.memory is nil. In debugger it shows memory pointer on bounds as 0x0000000000000000. I believe it's because some applications don't actually have a window and thus have nothing to provide. Second theory is that application has more than one window, but some are not visible (more likely because I check in for-in loop by pid).

So the question is how would I recognise these undrawn windows and skip them?

P.S.

This is my first question in StackOverflow, so if something is wrong with my question, please let me know. I'll try to edit my question accordingly.

// Check if fullscreen application is in foreground
func appSwitched(notification: NSNotification)
{
let pid = NSWorkspace.sharedWorkspace().frontmostApplication!.processIdentifier
let bounds : CGRect! = windowBounds(pid)
print(bounds.height.description)
print(bounds.width.description)
}

// Get bounds of specified processID window
func windowBounds(pid : Int32) -> CGRect
{
var bounds : UnsafeMutablePointer<CGRect>! = UnsafeMutablePointer<CGRect>()

let windowList : CFArrayRef = CGWindowListCopyWindowInfo(CGWindowListOption.OptionOnScreenOnly, CGWindowID())!
for window in windowList as NSArray{
let id = window.objectForKey(kCGWindowOwnerPID) as! NSNumber!
if(id.intValue == pid){
if((window.objectForKey(kCGWindowOwnerName) as! String) != "MyAppName")
{
let success : Bool! = CGRectMakeWithDictionaryRepresentation((window.objectForKey(kCGWindowBounds) as! CFDictionary!), bounds)
if((success) != nil)
{
return bounds.memory
}
} else { break }
}
}
return CGRect()
}

Answer

Generally, your code is using too much ImplicitlyUnwrappedOptionals -- CGRect!, UnsafeMutablePointer<CGRect>!, NSNumber! and Bool!, none of them seems to be required. But other than success : Bool! may not be the cause of your issue, so, I put others aside. (Those may cause other problems, but such cases should be other issues.)

The signature of CGRectMakeWithDictionaryRepresentation is as follows:

public func CGRectMakeWithDictionaryRepresentation(dict: CFDictionary?, _ rect: UnsafeMutablePointer<CGRect>) -> Bool

(Taken from generated header.)

  • The return value is Bool, not Bool? nor Bool!, which means, when assigned to Bool! variable, the variable gets always non-nil. You cannot check if the function has succeeded or not with (success) != nil.

  • The type of the second parameter is UnsafeMutablePointer<CGRect>. When C-function API is claiming UnsafeMutablePointer<T>, you should declare a variable of type T, and pass it as an inout parameter (prefix &).

So, this line of your code:

    var bounds : UnsafeMutablePointer<CGRect>! = UnsafeMutablePointer<CGRect>()

needs to be changed to something like:

    var bounds: CGRect = CGRect()

And this part:

                let success : Bool! = CGRectMakeWithDictionaryRepresentation((window.objectForKey(kCGWindowBounds) as! CFDictionary!), bounds)
                if((success) != nil)
                {
                    return bounds.memory
                }

should be like this:

                let success = CGRectMakeWithDictionaryRepresentation((window.objectForKey(kCGWindowBounds) as! CFDictionary?), &bounds)
                if success {
                    return bounds
                }