Anyway, I'll be speaking this year on Code Reuse with Flex and AIR. The intent of the topic is to talk about how to write code that you can then reuse in both a Flex and AIR application. ( Dan contacted me asking for clarification ). I'll be giving this presentation next week in Connecticut at CFUGitives ( The Southwest CT Adobe User Group) and at the Hartford Adobe User Group. Next month I'll be giving it at the Boston User Group and the 360Flex conference in Atlanta. That's a busy schedule, I think.
Anyway, I'm working on my presentation, and wanted to use a moment to try put my AIR app into the system tray. AFter some search, it appears that Saskovic already did the work for me. I took his code and discovered it wouldn't compile on Beta 3. I did a quick read through of the AIR release notes and was able to convert his code to work on the latest release.
<?xml version=
"1.0" encoding=
"utf-8"?>
<mx:WindowedApplication xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" creationComplete="initApplication()">
<mx:Script>
<![CDATA[
/**
* This example describes how to dock an AIR application to the system tray
* and then undock it again.
* The minimize and close actions of the WindowedApplication are caught, so
* that we can introduce our own actions.
*
* A simple systray menu is presented, to show the usage of that.
*
* @Author: S.Radovanovic
* @Url:
http://www.saskovic.com/blog/?p=5
* @Date: 24-11-2007
* @Author: Jeffry Houser
* @Date: 09-01-2007
* Updated for AIR Beta 3
*/
import mx.controls.Alert;
import mx.events.CloseEvent;
private var dockImage:BitmapData;
/**
* Initialize the application to the default values.
* This method is called upon creationComplete from the Windowed Application
*
* @Author: S.Radovanovic
*/
public function initApplication():void {
//Use the loader object to load an image, which will be used for the systray
//After the image has been loaded into the object, we can prepare the application
//for docking to the system tray
var loader:Loader = new Loader();
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, prepareForSystray);
loader.load(new URLRequest(
"http://www.saskovic.com/images/systray_icon_16.png"));
//Catch the closing event so that the user can decide if it wants to dock or really
//close the application
this.addEventListener(Event.CLOSING, closingApplication);
}
/**
* Check if the user wants to close the application or dock it
*
* @Author: S.Radovanovic
*/
private function closingApplication(evt:Event):void {
//Don't close, so prevent the event from happening
evt.preventDefault();
//Check what the user really want's to do
//Alert.buttonWidth = 110;
Alert.yesLabel =
"Close";
Alert.noLabel =
"Minimize";
Alert.show(
"Close or minimize?",
"Close?",
3, this, alertCloseHandler);
}
// Event handler function for displaying the selected Alert button.
private function alertCloseHandler(event:CloseEvent):void {
if (event.detail==Alert.YES) {
closeApp(event);
} else {
dock();
}
}
/**
* Check to see if the application may be docked and set basic properties
*
* @Author: S.Radovanovic
*/
public function prepareForSystray(event:Event):void {
//Retrieve the image being used as the systray icon
dockImage = event.target.content.bitmapData;
//For windows systems we can set the systray props
//(there's also an implementation for mac's, it's similar and you can find it on the net... ;) )
if (NativeApplication.supportsSystemTrayIcon){
setSystemTrayProperties();
//Set some systray menu options, so that the user can right-click and access functionality
//without needing to open the application
SystemTrayIcon(NativeApplication.nativeApplication .icon).menu = createSystrayRootMenu();
}
}
/**
* Create a menu that can be accessed from the systray
*
* @Author: S.Radovanovic
*/
private function createSystrayRootMenu():NativeMenu{
//Add the menuitems with the corresponding actions
var menu:NativeMenu = new NativeMenu();
var openNativeMenuItem:NativeMenuItem = new NativeMenuItem(
"Open");
var exitNativeMenuItem:NativeMenuItem = new NativeMenuItem(
"Exit");
//What should happen when the user clicks on something...
openNativeMenuItem.addEventListener(Event.SELECT, undock);
exitNativeMenuItem.addEventListener(Event.SELECT, closeApp);
//Add the menuitems to the menu
menu.addItem(openNativeMenuItem);
menu.addItem(new NativeMenuItem(
"",true));
//separator
menu.addItem(exitNativeMenuItem);
return menu;
}
/**
* To be able to dock and undock we need to set some eventlisteners
*
* @Author: S.Radovanovic
*/
private function setSystemTrayProperties():void{
//Text to show when hovering of the docked application icon
SystemTrayIcon(NativeApplication.nativeApplication .icon).tooltip =
"Systray test application";
//We want to be able to open the application after it has been docked
SystemTrayIcon(NativeApplication.nativeApplication .icon).addEventListener(MouseEvent.CLICK, undock);
//Listen to the display state changing of the window, so that we can catch the minimize
stage.nativeWindow.addEventListener(NativeWindowDisplayStateEvent.DISPLAY_STATE_CHANGING, nwMinimized);
//Catch the minimize event
}
/**
* Do the appropriate actions after the windows display state has changed.
* E.g. dock when the user clicks on minize
*
* @Author: S.Radovanovic
*/
private function nwMinimized(displayStateEvent:NativeWindowDisplayStateEvent):void {
//Do we have an minimize action?
//The afterDisplayState hasn't happened yet, but only describes the state the window will go to,
//so we can prevent it!
if(displayStateEvent.afterDisplayState == NativeWindowDisplayState.MINIMIZED) {
//Prevent the windowedapplication minimize action from happening and implement our own minimize
//The reason the windowedapplication minimize action is caught, is that if active we're not able to
//undock the application back neatly. The application doesn't become visible directly, but only after clicking
//on the taskbars application link. (Not sure yet what happens exactly with standard minimize)
displayStateEvent.preventDefault();
//Dock (our own minimize)
dock();
}
}
/**
* Do our own 'minimize' by docking the application to the systray (showing the application icon in the systray)
*
* @Author: S.Radovanovic
*/
public function dock():void {
//Hide the applcation
stage.nativeWindow.visible = false;
//Setting the bitmaps array will show the application icon in the systray
NativeApplication.nativeApplication .icon.bitmaps = [dockImage];
}
/**
* Show the application again and remove the application icon from the systray
*
* @Author: S.Radovanovic
*/
public function undock(evt:Event):void {
//After setting the window to visible, make sure that the application is ordered to the front,
//else we'll still need to click on the application on the taskbar to make it visible
stage.nativeWindow.visible = true;
stage.nativeWindow.orderToFront();
//Clearing the bitmaps array also clears the applcation icon from the systray
NativeApplication.nativeApplication .icon.bitmaps = [];
}
/**
* Close the application
*
* @Author: S.Radovanovic
*/
private function closeApp(evt:Event):void {
stage.nativeWindow.close();
}
]]>
</mx:Script>
</mx:WindowedApplication> I'm not sure if the Blog formatting may have added extra line breaks or not in the comments, so beware of that.
Over the next 3-6 months, I want to blog about the process I use in creating an application, from conception to completion. My plan is to build an "RSS Watcher". Something that can sit in my sustem tray, watch an RSS Feed, and show a pop-up window whenever an RSS Feed changes. I have a preliminary version of this that I hacked together as an example in the presentation. IT uses Saskovic's code along with code from the Adobe example app Wordup.