Archive for September, 2005

Re-opening the main NSWindow

I was faced with what seemed a very simple problem, when I closed the window on my application, I didn’t have a way to open it again. For a document based application, it isn’t too much of an issue, the framework allows you to open or create a new document.

Mac OS X is a bit divided at the moment on this functionality. There are some single window apps that behave this way, and others that close themselves when you close the main window. System Preferences is an example of this.

For my application, I wanted it to have a single main window, and I wanted the user to be able to click on the dock icon and have it re-open if it wasn’t already there. Same as Mail, Address Book, iTunes and others.

The trick to making this happen is the applicationShouldHandleReopen:hasVisibleWindows: method of your application delegate. This method is called with the NSApplication and a flag to indicate whether or not any windows are visible for the application.


def applicationShouldHandleReopen_hasVisibleWindows_(self, theApp, hasVisibleWindows):
    if hasVisibleWindows:
        return True

    for win in theApp.windows():
        # Autosave Name set in .nib
        if win.frameAutosaveName() == 'mainWindow':
            win.makeKeyAndOrderFront_(NSNormalWindowLevel)
            return False

    return True

To be honest, my first version was a bit simpler again, the for loop looked remarkably like:


    win = theApp.windows()[0]

Too many years programming and I couldn’t leave the [0] alone. Given that there could be more than one window in my application, I needed a way to identify the window that I needed to open. Cocoa provides such a feature, the AutoSave name for a window. This property can be set in Interface Builder.

Simply give your main window a name, I chose ‘mainWindow’, and search for a window with that name.

Once you have a handle on the NSWindow, you need to call makeKeyAndOrderFront:. This method makes the window the Key window, which gives it keyboard focus and makes it visible. The method requires a window level and given that the main window isn’t doing anything strange, I used NSNormalWindowLevel.

The test for visible windows is a bit of a shortcut. If there is already a visible window, I don’t want any extra ones showing up, so I return True and let Cocoa deal with the Dock click (or Application open) as it normally would. If I did open a window, then I return False, as there is nothing further for Cocoa to do.

In the end, a simple solution to a simple problem.

Web Feed workflow

Having just returned from nine days snowboarding with no internet access, I’m presented with the daunting task of catching up. Work and my few personal email accounts weren’t too bad, with unread counts in the low hundreds. However, NetNewsWire was happily advising me that I had over 600 unread posts.

I’ve grouped my feeds into groups that are roughly topic based, but also based on whether I can live without reading them. This allowed me to simple mark as read about half the unread count. I’ve probably missed some things, but they were likely to be things I could live without.

What troubles me is the remaining posts. There is probably about half of those that I will want to catch up on. The catch is that I won’t know which half until working my way through them all. I’m not sure if this is a good or a bad thing.

On one hand, I won’t miss things that I would normally have missed by my previous web browsing workflow (visit sites and check). On the flip side, I’m now getting rather close to information overload. The next step from here is to try and cull out feeds that I’m not as interested in.

At least I can listen to tunes on my iPod nano while I sort it all out.

Crossroads on Languages

Recently, I’ve been distracted by reading Paul Graham’s essays as a result of a Tim Bray posting.

My interests have been serious piqued as a result of one of his themes of using Lisp to write web applications. As a higher order language, the theory is that programmers will be more productive and that given the types of programmers who learn Lisp, you can attract better programmers.

It is a very interesting argument. Something that I’ve been giving lots of thought. My interests at the moment are in learning to write native Mac OS X applications. Python fell in my lap as an option mostly due to my background in Miranda and then the more popular (and powerful, useful, free) Haskell.

Part of my motivation behind learning Cocoa programming has been to write a native application that talks to a web based back end. For some tasks, I’m still not convinced that a web browser is the Right Thing, regardless of how much AJAX code you put in place. This is why the Cocoa apps I’ve been writing have typically avoided building their own data layer. One is built on regular expressions and the other on Address Book and iCal.

The bit I’ve been avoiding is writing the back end. Past experiences on this have been in Perl, which is useful, but I just don’t like. I’d rather not have to put $ signs everywhere.

Python seems to have the clean aspect and enough libraries for doing things so I’d been assuming that I’d use Python for the back end too. However, most of my thinking in Python is really derived from my Haskell days, so why not write the back end in Haskell?

I also may have been distracted somewhat by a few other developments such as Ruby on Rails and Django, as even with a thick client in Cocoa talking to a back end, in this day and age, an application really should have a web based version too.

Investigation has also gone into using XUL as it is both web based, cross platform and somewhat richer than AJAX.

All in all, it is a happy time to be in where there is such a wide range of equally valid choices. It now comes down to a question of tradeoffs.

A brief interlude

Another Glitch in the Call

(Sung to the tune of a recent Pink Floyd song.)

We don’t need no indirection
We don’t need no flow control
No data typing or declarations
Did you leave the lists alone?

Hey! Hacker! Leave those lists alone!

Chorus:
All in all, it’s just a pure-LISP function call.
All in all, it’s just a pure-LISP function call.