Archive for July, 2005

Watching NSEvents

In the midst of investigating how events are passed around within Cocoa and I found some interesting information. Based on the Apple Tech Note - Mac OS X Debugging Magic, it is possible to watch all the events as they are sent.

I was skeptical, but pleasantly surprised to discover that this still works if you have a PyObjC app, including one that is sym-linked! (ie. python setup.py py2app -A)

The magical incantation looks something like:


% defaults write com.mysite.MyApp NSTraceEvents YES
% MyApp.app/Contents/MacOS/MyApp

This will launch the app (MyApp) from the command line, with the events being sent back to the command line. Opening the application as per normal will have the events sent to the Console.

The following will turn of the feature:


% defaults write com.mysite.MyApp NSTraceEvents NO

The results look something like (line breaks added for clarity):


2005-07-27 18:35:57.599 MyApp [2790]
In Application: NSEvent:
type=KeyUp loc=(-395,428) time=152170.8
flags=0x180128 win=0 winNum=15994 ctxt=0xf45f
chars='ƒ' unmodchars='f' repeat=0 keyCode=3

Note: the com.mysite.MyApp bit is actually the value of the CFBundleIdentifier in the Info.plist file. See here for details on setting this up.

DrunkenBlog: On Being and Deliciousness, with Wil Shipley

Another brilliant interview over at DrunkenBlog. Go check it out. Wil Shipley speaks on software, Apple, Cocoa and life.

One of my favourite bits:

Making a simple user interface is a thousand times harder than a complicated one. I could literally write a skeleton of Delicious Library in a day, if I weren’t worried about how all the buttons and fields interacted or looked. Adding the fun to the app is the hard thing …

Opening an AddressBook entry with PyObjC

Having done some user testing on my DateList application, I discovered that they (me and my other test subject) expected something to happen when double clicking on an entry. It seems reasonable to me to open the person in Apple’s AddressBook as the action.

There doesn’t seem to be much information on this, however playing around with the birthday calendar (Tiger iCal feature), there is a URL that seems to work:


addressbook://E15E4D1E-AAE1-4AC2-85DB-98BB906EE988:ABPerson

Passing this to the open shell command opens the appropriate person in AddressBook.

The better question is how to construct one of these. To query an AddressBook entry, we first need to find one. AddressBook has a special reference for the current user called me.


>>> from AddressBook import *
>>> book = ABAddressBook.sharedAddressBook()
>>> book
<ABAddressBook: 0x1133d80>
>>> me = book.me()
>>> type(me)
<objective-c class ABPerson at 0xa4ac3034>

Now that we have a ABPerson, we can determine the UID. The UID property is actually on the base class, ABRecord.


>>> myUID = me.valueForProperty_(kABUIDProperty)
>>> myUID
u'E15E4D1E-AAE1-4AC2-85DB-98BB906EE988:ABPerson'

To open a URL, we need to construct a NSURL:


>>> from Foundation import *
>>> url = NSURL.URLWithString_('addressbook://' + myUID)
>>> url
addressbook://E15E4D1E-AAE1-4AC2-85DB-98BB906EE988:ABPerson

Finally, we pass the NSURL to the openURL_ method of the shared workspace. You get one shared workspace per application, and it can be used for useful things like opening urls, files, applications and some other services such as tracking changes.


>>> from AppKit import *
>>> ws = NSWorkspace.sharedWorkspace()
>>> ws
<NSWorkspace: 0x1134910>
>>> ws.openURL_(url)
1
>>>

openURL_ returns YES (1) if the URL was successfully opened, NO (0) otherwise. At this point AddressBook should open and have selected the entry that you have tagged as you.

Hacking the iTunes library with Python

Bob was having a bit of trouble with his Airport Express. Fortunately for the rest of us, his solution involved delving into the internals of the iTunes library for answers.

Interesting for the simplicity with which PyObjC allows Python idioms to mesh with Apple’s APIs for a neat solution. With a few lines in an interactive shell, Bob manages to locate all the problematic files and set the correct creator code

Ten Essential Development Practices

In this article Damian Conway outlines ten development practices that he considers essential for developing big, business critical systems. Also, incredibly useful for developing big, user critical Cocoa programs.

The examples are in Perl, but the development practices are basic good practice and can be applied to any language.

A short summary:

  1. Design the Module’s Interface First
  2. Write the Test Cases Before the Code
  3. Create Standard Documentation Templates for Modules and Applications
  4. Use a Revision Control System
  5. Create Consistent (Command-Line / User) Interfaces
  6. Agree Upon a Coherent Layout Style and Automate It (with perltidy)
  7. Code in Commented Paragraphs
  8. Throw Exceptions Instead of Returning Special Values or Setting Flags
  9. Add New Test Cases Before you Start Debugging
  10. Don’t Optimize Code—Benchmark It

Creating a .dmg for installation

Having been talked out of making an installer, I still wanted to be able to automate the creation of a .dmg file for easy deployment. Fortunately, this is very simple to do if you don’t want the .dmg to do much.

The short version is:


 % hdiutil create -srcfolder dist/[app name].app [app name].dmg

With [app name] replaced with the name of your application. Obviously, you need to do a proper build of your Python application, the symbolically linked version isn’t good enough.

For example, the Date List sample app can be deployed with:


 % rm -rf dist
 % python setup.py py2app
 % hdiutil create -srcfolder dist/Date List.app Date List.dmg

There are a range of features that are worth adding to a .dmg that is used to deploy software. These include things like background images, license agreements and auto opening the disk image.

This is something to investigate at a future point. The buildDMG script seems to be a good starting point, with the source of Adium providing a good example of how to build one.

Update

It’s been a while since I posted, due to a few other things going on. I also have a couple of articles in the wings that are waiting for me to finish.

On another note, Apple has dropped support for the Java-Objective C bridge. What this means is that if you were using Java for Cocoa development you are now out in the cold. This could lead to more people using Python or Ruby for Cocoa development.

PyObjC patterns

PyObjC - First Steps. Bob Ippolito has posted some common usage patterns for calling Objective C from Python.

Even if you have been using PyObjC for a while, this is a refresher worth reading.

House

For a bit of a change in obsessions, I’ve been watching a lot of the tv series House, partially to recover from snowboarding, and partially to turn my brain off by watching others learn and solve problems.

Classic quote:

House: “You’re British”

Chase: “I’m Australian”

House: “You put the Queen on your money. You’re British”