Sunday, February 6, 2011

Minimize to System tray (AIR application)


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.



<?xml version="1.0" encoding="utf-8"?>
<mx:WindowedApplication xmlns:mx="http://www.adobe.com/2006/mxml"
                                           layout="absolute"
                                           creationComplete="initApplication()">
                <mx:Script>
                                <![CDATA[
                                                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
                                                 */
                                                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._____.com/sample16.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
                                                 */
                                                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.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
                                                 */
                                                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
                                                 */
                                                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);
                                                               
                                                                //Adding a submenu Status
                                                                var submenu:NativeMenu=new NativeMenu();
                                                                var onlineNativeMenuItem:NativeMenuItem=new NativeMenuItem("Online");
                                                                var disturbNativeMenuItem:NativeMenuItem=new NativeMenuItem("Do Not Disturb");
                                                                var invisibleNativeMenuItem:NativeMenuItem=new NativeMenuItem("Invisible");
                                                                var offlineNativeMenuItem:NativeMenuItem=new NativeMenuItem("Offline");

                                                                //Add Items to a sub-menu "Status"
                                                                submenu.addItem(onlineNativeMenuItem);
                                                                submenu.addItem(disturbNativeMenuItem);
                                                                submenu.addItem(invisibleNativeMenuItem);
                                                                submenu.addItem(offlineNativeMenuItem);
                                                                //Add the menuitems to the menu
                                                                menu.addItem(openNativeMenuItem);
                                                                menu.addSubmenu(submenu, "Status");
                                                                menu.addItem(new NativeMenuItem("", true));
                                                                //separator
                                                                menu.addItem(exitNativeMenuItem);
                                                                return menu;
                                                }
                                                /**
                                                 * To be able to dock and undock we need to set some eventlisteners
                                                 */
                                                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
                                                 */
                                                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)
                                                 */
                                                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
                                                 */
                                                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
                                                 */
                                                private function closeApp(evt:Event):void
                                                {
                                                                stage.nativeWindow.close();
                                                }
                                ]]>
                </mx:Script>
</mx:WindowedApplication>




No comments:

Post a Comment