2
\$\begingroup\$

After resigning active state (going to the background), the mainWindow property of the main window in the app returns false.

Nevertheless, I need a to find that window even when my app is not active, so I came up with the following code, which works:

public let App = NSApplication.sharedApplication() // just some sugar

public extension NSApplication {

    public func frontmostWindow(_ accept: (NSWindow -> Bool)? = nil) -> NSWindow? {
        for windowNumber in NSWindow.windowNumbersWithOptions(0) as? [Int] ?? [] {
            if let window = windowWithWindowNumber(windowNumber) {
                if let accept = accept {
                    if accept(window) {
                        return window
                    }
                } else {
                    return window
                }
            }
        }
        return nil
    }
}

With this, I can now get the first window of my app in the current ordering that passes the provided predicate check (accept: NSWindow -> Bool). This is because I normally would not be interested in the menu bar or the status item, which all have associated windows that belong to my app (which is what I would get if I do not pass any predicate). As an example, say I have some:

class PimpedUpWindow: NSWindow, ExtraTranslucent {}

the frontmost instance of which I wish to find after the app launches and is no longer the active app. Using the extension above I can:

App.frontmostWindow { $0 is PimpedUpWindow } 

or

App.frontmostWindow { $0 is ExtraTranslucent } 

Of course, I can provide any other predicate of type NSWindow -> Bool, but I figure I will often enough want to just check the type or protocol conformance. So I might as well add two convenience methods for just those occasions:

public extension NSApplication {

    public func frontmost <T> (windowOfType: T.Type) -> T? {
        return frontmostWindow { $0 is T } as? T
    }

    public func frontmostWindow <P> (conformingTo: P.Type) -> NSWindow? {
        return frontmostWindow { $0 is P }
    }
}

Now, I can simply:

App.frontmost(PimpedUpWindow)

Which actually returns a PimpedUpWindow?, and:

App.frontmostWindow(ExtraTranslucent)

which returns an NSWindow?.

All ideas, criticisms, and comments very welcome!

\$\endgroup\$
3
\$\begingroup\$

There is a way of improving the code as desired in that it is possible to constrain the type T to T: NSWindow. Upon introducing this change, however, the function will indeed return the first NSWindow in the current ordering, whether or not it is of subtype T (too check this you must construct a test that can actually fail, i.e. by having an NSWindow of a another type above the window you are looking for - e.g. by adding a status item to your app). There is a workaround, however, as described in Optional binding succeeds if it shouldn't. Apart from the solution I stumbled upon in the question (of not constraining T), there is a much preferable option discovered by @vacawama in the answer to the linked question. The workaround is to generalise the variable to Any before type checking, e.g. as follows:

public func frontmost <T: NSWindow> (windowOfType: T.Type) -> T? {
    return frontmostWindow { $0 as Any is T } as? T
}

This improves the api considerably.

\$\endgroup\$
1
\$\begingroup\$

The code bellow seems to do the same with less code. I found the original solution to be a bit cryptic and language specific. The provided code bellow is also easier to modulate, one could imagine getting the backMostWinOfType with a single char change in the sort algorithm. One could argue that running a sort algorithm is superfluous to this task, but it's unlikely to hamper performance as you never have that many windows anyway. Thoughts and corrections are more than welcome.

/**
 * Returns the front most window in NSApp of a spedific class or protocol type
 */
class func frontMostWinOfType<T:NSWindow>(type:T.Type)-> T?{
    var windows:Array<T> = []
    for window : NSWindow in NSApp.windows { if(window as? T != nil) {windows.append(window as! T)}}
    windows.sortInPlace { (a, b) -> Bool in return a.orderedIndex > b.orderedIndex}
    return windows[0]
}
\$\endgroup\$
  • \$\begingroup\$ How is this better than what the OP have ? At Code Review, we want the code and OP to be better! You need to justify and explain. \$\endgroup\$ – Marc-Andre Aug 2 '16 at 12:29
  • \$\begingroup\$ I rather not claim that its better, I Usually leave praise up to other people. I could argue that its less code? I shall begin my future posts with a better explanation. Thanks for the heads up. \$\endgroup\$ – eonist Aug 2 '16 at 12:37
  • \$\begingroup\$ Thanks, and asking a question like that make it seems like you don't know if this is working for op. You should really take a look a bit around and read the help center to know what this site is about. Your answer as currently written is not what we really do here. Try to add why you change it like that ? Which did you take in reading the op code to come out with this one. \$\endgroup\$ – Marc-Andre Aug 2 '16 at 12:42
  • \$\begingroup\$ Thanks Marc-Andre. To be honest I might be missing something concerning the order of windows, would love to hear back from The author of the original question about this. That being said I will add my order code in a moment and some contextual content as you requested. \$\endgroup\$ – eonist Aug 2 '16 at 13:27

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.