Archive for January, 2008

Update on my AIR Applications and Libraries

The most important part of my job is writing AIR applications, and I’ve written quite a few. In addition to applications, my team and I have written a great deal of reusable ActionScript library code (Amazon S3 APIs, Exchange APIs, etc.). Everything I’ve written is completely free and open source.

The problem is that I haven’t done a very good job in keeping these applications and libraries synchronized with the the publicly available version of AIR. It’s not that I’m lagging behind, though. In fact, I have the opposite problem: most of this code has been updated to work with the the latest internal versions of AIR so that I can keep banging on, testing, and exercising the latest and greatest runtime.

I just wanted to let everyone know that I will be releasing all my apps the day we release AIR 1.0. If you can’t wait that long, the source code is all available here in Google Code. In theory, all of the libraries should work with the public AIR beta (beta 3), and the applications should all work, as well, as long as the application descriptor’s namespace is set to 1.0.M6 rather than 1.0. Anything that doesn’t work, or any bugs that you find, will be fixed in the final 1.0 release.

Below is a list of almost everything I’ve written that’s worth releasing (I’ve written dozens of test applications that will never see the light of day).

Applications:

  • Apprise: A simple but powerful RSS aggregator.
  • Lineup: A application for viewing your Exchange calendar, and receiving meeting notifications.
  • PixelPerfect: Measure things on your screen in pixels.
  • S3E: Easily manage your Amazon S3 objects and buckets.
  • SPF (Screen Protection Factor): A multi-monitor screen saver.
  • ScreenBoard: Draw on your screen during presentations.
  • HTMLScout: A tool for inspecting the DOM of an HTML page.
  • Timeslide: A simple but useful countdown timer with good visual feedback.

Libraries:

  • as3corelib: The corelib project is an ActionScript 3 Library that contains a number of classes and utilities for working with ActionScript 3.
  • as3fedexlib: A wrapper on top of some of the FedEx XML APIs.
  • as3syndicationlib: Use the syndication library to parse Atom and all versions of RSS easily. This library hides the differences between the formats so you can parse any type of feed without having to know what kind of feed it is.
  • as3awss3lib: This is an AS3 library for accessing Amazon’s S3 service.
  • as3notificationlib: This project makes it easy to add cross-platform notifications to your AIR application. It handles "native system notifications" like the dock icon bouncing and the taskbar icon flashing, and it allows you to easily create alert "pop-ups".
  • as3exchangelib: This is an ActionScript 3 library for talking to Exchange servers. (Currently only supports retrieving meeting information.)
  • as3preferenceslib: An AIR library for storing preferences. It worries about persistence and even encryption for you.
  • as3nativealertlib: This project creates Flex-like alerts, but they are native windows so they can appear outside the bounds of your application.

The source code for all these applications and libraries is available here. You will need to use subversion to download the source.

Converting Stage Coordinates to Screen Coordinates

In the Exchange calendaring application I’m working on (called Lineup), when the user double-clicks on an appointment, I open up an appointment detail window which shows you things like the location, full description, etc. Initially, I was just opening a utility window (a native window with smaller chrome), but after seeing the newest version of iCal, I was inspired to do something more creative. I still open a new window, but it’s a customized transparent window which looks more like a dialog bubble extending from the exact point where the user clicked.

In order for the effect to work properly, I needed to place the window at very precise screen coordinates so that the window was clearly associated with the appointment that was clicked on. At first, I tried doing my own coordinate calculations using the stage x/y coordinates of the double click, and the coordinates of the application window. The problem was that I had no way to take native window chrome into account, so although I got it working on Mac, the window placement was off on Windows.

Fortunately, AIR has an API that does the work for you by taking the coordinates from a "local" mouse event (relative to the window stage) and converting them into screen or global coordinates. The function is NativeWindow.globalToScreen(), and it fixed my problem perfectly. Now, Lineup has iCal-like detail windows that appear right where they are supposed to on Mac, Windows, and eventually on Linux, as well.

Managing Symbolic Links in AIR

I recently wrote an AIR application called SPF, or Screen Protection Factor. It’s a screen saver that will fill however many monitors you have attached to your computer with random pictures from a specified directory. The specified directory is recursively traversed so SPF will find all supported file types (jpg, png, and gif), no matter how deeply nested they are.

While writing SPF, I realized that a carelessly placed symbolic link could easily put my directory traversal code into an infinite loop. Symbolic links (as they are known on Unix systems, including OS X) and junction points (as they are known on Windows) are pointers to files or directories which are mostly indistinguishable from whatever they point to. I use them frequently when doing web development when I don’t want to keep my source code in my web root. Instead, I create a symbolic link in my web root which points to my source tree, and assuming my web server is configured correctly, it’s just like having the same code in two places. Put a symbolic link in the wrong place, however, and you’ve created a circular reference on the file system. Normally this isn’t a problem, until you have a piece of code that is recursively traversing that portion of your file system.

I tried a few stopgap measures to guard against circular references in my SPF code, but there really was no way to gracefully handle the problem without specific APIs. Fortunately, those APIs now exist.

To handle symbolic links, you need two File APIs: the isSymbolicLink property, and the canonicalize function.

isSymbolicLink simply returns a boolean which tells you if the File instance is a symbolic link or a junction point. Simple enough. But what does the symbolic link actually point to? That’s where canonicalize comes in. Call canonicalize, and suddenly the file reference now points to the actual file referenced by the link. Call nativePath, and you get the path of the original file, not the link.

So how does this solve my SPF problem? While traversing the file system, I keep a map of file paths, and before adding a new image to the queue, I check to see if it is already in the map. Before I was able to resolve symbolic links, a circular reference would have me adding the same files infinitely because the path continued to grow. Now, I simply check to see if the file reference is a symbolic link, and if it is, I call canonicalize before adding it to the map. Problem solved.

These two APIs don’t work on Mac aliases or Windows shortcuts, however they don’t have to. AIR will not follow aliases or shortcuts like it will symbolic links, so they cannot get you into the same kind of trouble.

Manual Data Binding in Flex

I’m currently working on an Exchange calendaring client for AIR (more details to come), and I decided early on to use the Cairngorm Flex framework. I’d worked on Cairngorm projects in the past, but I hadn’t ever used Cairngorm in one of my own projects from start to finish. I decided it was time to put it to use, and to make sure it was 100% AIR friendly.

One of the first things you realize about Cairngorm is that it relies very heavily on data binding. Data binding is one of my favorite features of Flex, so I was very happy with how my application was coming together. But then I ran into a snag. I found myself needing to execute a block of code in response to a property change rather than just display the new property value, or update a component’s data provider. Fortunately, Flex has anticipated this issue, and allows you to set up binding manually in a very flexible (naturally) way.

So here’s the scenario:

I have a ControlBar component which has a busy, and a notBusy state. In the busy state, I show a progress bar, and in the notBusy state, the progress bar goes away, and in its place, I show the date and time of the last update. My ModelLocator has a busy property which makes it easy for me to to maintain a global "busy" state for my entire app. Whenever that properly changes, I want to change the state of the ControlBar component, as well as execute a small block of UI-related code.

The key to making this work is the mx.binding.utils.ChangeWatcher class. In the creationComplete handler of my component, I have the following code:

ChangeWatcher.watch(ModelLocator.getInstance(), "busy", onBusyChange);

Believe it or not, that’s it. In my onBusyChange function, I change the state of my component, and do a couple of other small UI-related things. Now whenever the busy property of the ModelLocator changes, my app just does the right thing.

I found that the ChangeWatcher was really the key to making Cairngorm flexible enough to build any type of application. It allowed my team to throw together a pretty nice little Exchange Calendar viewer and notifier which I think will be a big hit with those who use Exchange in a corporate environment, but who aren’t big fans of Outlook. I will release the application and the code with the next public release of AIR.