Adobe
Products
Acrobat
Creative Cloud
Creative Suite
Digital Marketing Suite
Digital Publishing Suite
Elements
Photoshop
Touch Apps
Student and Teacher Editions
More products
Solutions
Creative tools for business
Digital marketing
Digital media
Education
Financial services
Government
Web Experience Management
More solutions
Learning Help Downloads Company
Buy
Home use for personal and home office
Education for students, educators, and staff
Business for small and medium businesses
Licensing programs for businesses, schools, and government
Special offers
Search
 
Info Sign in
Welcome,
My cart
My orders My Adobe
My Adobe
My orders
My information
My preferences
My products and services
Sign out
Why sign in? Sign in to manage your account and access trial downloads, product extensions, community areas, and more.
Adobe
Products Sections Buy   Search  
Solutions Company
Help Learning
Sign in Sign out My orders My Adobe
Preorder Estimated Availability Date. Your credit card will not be charged until the product is shipped. Estimated availability date is subject to change. Preorder Estimated Availability Date. Your credit card will not be charged until the product is ready to download. Estimated availability date is subject to change.
Qty:
Purchase requires verification of academic eligibility
Subtotal
Review and Checkout
Adobe Developer Connection / Adobe AIR Developer Center / AIR Quick Starts for HTML/JavaScript developers /

Creating toast-style windows

by Joe Ward

Joe Ward

Modified

9 June 2010

Page tools

Share on Facebook
Share on Twitter
Share on LinkedIn
Bookmark
Print
Adobe AIR Flex

Requirements

Prerequisite knowledge

General experience building HTML-based applications is suggested. For more details on getting started with this Quick Start, refer to Building the Quick Start sample applications with HTML.

User Level

Intermediate

Required products

  • Adobe AIR

Sample files

  • WordUpHTML.zip
  • WordUpHTML.air

When an application needs to display informational messages without disturbing the user's workflow, toast-style windows can be the right solution. The WordUp example application, shown in Figure 1, creates toast windows with the following attributes:

  • Chromeless
  • Displayed above other windows
  • Do not steal the keyboard or mouse focus
  • Expire so the user doesn't have to close them
  • Persist when the user is away from the computer

The WordUp example illustrates how to use the following Adobe AIR APIs:

  • HTMLLoader.createRootWindow() to create and display the toast windows
  • NativeApplication to detect user presence and to use the dock or system tray icons
  • Screen to place multiple toast windows on the desktop without overlapping
  • EventDispatcher to dispatch events between JavaScript objects
WordUp application
Figure 1. This sample application displays a toast window containing a random message.

Note: This is a sample application provided, as is, for instructional purposes.

The WordUp example application

The WordUp example application runs in the background with no visible main window. When a timer fires, the application displays a "toast" window containing a random message. After several seconds, the message expires and the toast window closes automatically.

To detect when the user is present, the application listens for userIdle and userPresent events from the NativeApplication object. When the userIdle event is dispatched, messages are queued until the next userPresent event. A userIdle event is dispatched when no keyboard or mouse input has been detected within an interval determined by the NativeApplication.idleThreshold property. The default interval is a reasonable 5 minutes, but WordUp resets the value to less than a minute so the change in application behavior can be more easily observed.

To test the application, launch the WordUp installer file (WordUpHTML.air) file. On Windows, a system tray icon is displayed in the notification area of the task bar. On Mac OS X, the normal triangle under the dock icon shows that the application is running. After about 5 seconds, the first message will pop up from the bottom of the screen. It will then disappear after a few moments.

To exit the application on Windows, right-click the system tray icon and select Exit WordUp from the menu. On Mac OS X, click and hold the dock icon to open the menu and select Quit WordUp.

Understanding the code

WordUp is an HTML-based project and uses windows created with the HTMLLoader createRootWindow() method. You can also create windows with the JavaScript window.open() method, but you have less control over the appearance of the window chrome.

Note: For more information about the AIR functions and APIs used in this example, see the AIR API Reference for HTML Developers.

Initializing a windowless application

The first step to creating a windowless application is to make sure that the initial window that is created automatically by AIR never becomes visible. The visibility of this window is controlled in two places. The first place is within the <initialWindow> element of the application descriptor file. If <visible>true</visible> is placed within this element, then the window will be visible on application startup. WordUp sets the visible element to false (although false is the default value, so this is not strictly necessary). The second place window visibility is controlled is the visible property of the native window itself. The visible property can be set to directly true or false with an assignment statement and it will also be set to true when the native window activate() method is called.

It is often a good idea to give the user some indication that an application is running, even when it has no visible windows. On Mac OS X, the application dock icon serves this purpose. On Windows, the system tray icon can be used. The Mac dock icon automatically appears in the dock when the application is running and provides a default menu for exiting the application so WordUp doesn't need to change the dock icon properties. However, the Windows system tray icon is only shown if you assign an image to it.

WordUp detects whether it is running on an operating system that supports system tray icons using the static NativeApplication.supportsSystemTrayIcon property. If so, it adds a tool tip and a menu containing an exit command using the following code (defined in WordUpHTML.html):

if(air.NativeApplication.supportsSystemTrayIcon){ air.NativeApplication.nativeApplication.icon.tooltip = "WordUp"; air.NativeApplication.nativeApplication.icon.menu = new air.NativeMenu(); var exitCommand = air.NativeApplication.nativeApplication.icon.menu.addItem(new air.NativeMenuItem("Exit WordUp")); exitCommand.addEventListener(air.Event.SELECT,function(event){ air.NativeApplication.nativeApplication.exit(); }); }

To initialize the application logic, WordUp creates a DisplayManager object (defined in MessageCenter.js), which manages the pop-up toast windows, and a new MessageGenerator object (defined in MessageGenerator.js), which periodically generates an event containing a random message:

window.messageGenerator = new MessagGenerator(); messageGenerator.addEventListener("message", onMessage); window.displayManager = new DisplayManager(); function onMessage(evt){ displayManager.queueMessage(evt.message); }

The onMessage() event handler function puts the message text on the message queue of the DisplayManager object.

Creating a toast-style window

The DisplayManager object periodically checks its message queue to see if there are any messages to be displayed. If so, it creates a new Message object, which handles the creation and placement of the message window. In turn, the Message object (defined in Message.js) creates an HTML window to display the message. To create the display window, the Message code creates a NativeWindowInitOptions object and sets the appropriate options for the window. The important options for a toast-style window are type and the systemChrome:

var windowOptions = new air.NativeWindowInitOptions(); windowOptions.type = air.NativeWindowType.LIGHTWEIGHT; windowOptions.systemChrome = air.NativeWindowSystemChrome.NONE;

WordUp uses the lightweight window type so that the Windows toolbar or Mac Windows menu does not display an entry for the window. When the lightweight type is used, the systemChrome option must also be set to none.

The new window is then created by calling the createRootWindow() method of the HTMLLoader object:

var htmlLoader = air.HTMLLoader.createRootWindow(false, windowOptions, false);

Next, the properties of the native window object are set and the message.html file, which defines the visual style for the message window, is loaded:

htmlLoader.window.nativeWindow.width = 250; htmlLoader.window.nativeWindow.y = currentScreen.bounds.height; htmlLoader.window.nativeWindow.alwaysInFront = true; htmlLoader.addEventListener(air.Event.HTML_DOM_INITIALIZE, onInitialize); htmlLoader.addEventListener("layoutComplete", onComplete); htmlLoader.window.nativeWindow.addEventListener(air.Event.CLOSE, onClose); //load the html file for the window htmlLoader.load(new air.URLRequest("../html/message.html"));

Setting the window size

Setting the size of the HTML window to fit its content is more involved than simply setting the width and height. Because the content size depends on both message length and the CSS rules of the display window, WordUp loads the html file into the message window, sets the message text, and then waits for the HTML to finish computing the layout. It then resizes the containing window to suit the final layout. (You could also choose a fixed window size and let the message scroll if it is too large.)

During the page loading sequence, the HTMLLoader object returned by the call to createRootWindow() dispatches an htmlDOMInitialize event to signal that the child window and document objects have been created. At this point, none of the window scripts have been parsed and no nodes have been added to the DOM, so you can initialize any variables in the window that must have valid values before the window load event occurs. WordUp uses the htmlDOMInitialize event to pass the message test to the new window:

var onInitialize = function (){ htmlLoader.removeEventListener(air.Event.HTML_DOM_INITIALIZE, onInitialize); htmlLoader.window.message = message; }

This message variable is accessed in the page load event handler, which inserts the text into a placeholder element in the document. The width of the window is set to 250 pixels at creation and this establishes one dimension of the layout. The other dimension, height, cannot be determined until the message text is actually inserted into the DOM and the HTML environment finishes laying out the content. THe HTMLLoader object dispatches an htmlBoundsChange event whenever the size of the HTML content changes. The resizeWindow() function (defined in message.html) responds to this event by changing the size of the native window object based on the size of the body element (plus the top and bottom margins). This allows window to display the HTML content without clipping or scrolling:

resizeWindow = function (){ window.htmlLoader.removeEventListener(air.Event.HTML_BOUNDS_CHANGE, resizeWindow); window.nativeWindow.height = document.body.offsetHeight + 20; event = new air.Event("layoutComplete", false, false); htmlLoader.dispatchEvent(event); }

The resizeWindow() function in turn dispatches a layoutComplete event to signal that the final window size has been set. (AIR does not define a layoutComplete event, but you can use any string as the event type as long as the same type is used in both the call to addEventListener() and the Event object constructor.) The Message object that created the window listens for the layoutComplete event and, when it is received, searches for an open spot on the desktop to place the window.

Placing the message window

The Message object uses the AIR Screen API to find a spot to display the new message. The findSpotForMessage() function searches for an open area starting with the lower-right-hand corner of the first screen in the air.Screen.screens array. When it finds an open spot, it animates a window movement from the bottom of the screen to its appointed destination.

To check whether a message window is already displayed in a given spot, WordUp loops through the NativeApplication.nativeApplication.openedWindows array. It tests whether the rectangle defined by the area being considered intersects the rectangle defined by the bounds of an existing message window:

var isOccupied = function (testRect){ var occupied = false; //i starts at one to skip the hidden initial window for (var i = 1; i < air.NativeApplication.nativeApplication.openedWindows.length; i++){ occupied = air.NativeApplication.nativeApplication.openedWindows[i].bounds.intersects(testRect); if(occupied) {break;} } return occupied; }

The animation of the window location is achieved by moving the window one quarter of the distance remaining to its final destination in response to the enterFrame event dispatched by the native window object:

var animateY = function (endY){ var dY = 0; Message.prototype.isAnimating = true; var animate = function(event){ dY = Math.floor((endY - htmlLoader.window.nativeWindow.y)/4); htmlLoader.window.nativeWindow.y = htmlLoader.window.nativeWindow.y + dY; if( htmlLoader.window.nativeWindow.y <= endY){ htmlLoader.window.nativeWindow.y = endY; Message.prototype.isAnimating = false; htmlLoader.stage.removeEventListener(air.Event.ENTER_FRAME, animate); } } htmlLoader.stage.addEventListener(air.Event.ENTER_FRAME, animate); }

Once the window reaches its destination, the event listener is removed.

Note: The enterFrame event is dispatched at the underlying frame rate of the application. This event is a convenient way to control animation in an AIR application, but you could use the JavaScript setInterval() function if you prefer.

Detecting user presence

WordUp uses the NativeApplication userIdle and userPresent events to determine whether the user is actively using the computer. The idleThreshold property determines how long the computer must be inactive before the userIdle event is dispatched. By default, the threshold is five minutes, but WordUp lowers the threshold to 30 seconds so that the effect of the change is easier to see.

air.NativeApplication.nativeApplication.idleThreshold = 30; air.NativeApplication.nativeApplication.addEventListener(air.Event.USER_IDLE, pause); air.NativeApplication.nativeApplication.addEventListener(air.Event.USER_PRESENT, resume);

In response to these events, WordUp suspends or restarts the DisplayManager timer that checks the queue for messages to display:

//Stop the timer when the user is away var pause = function (){ air.trace("idle"); poller.stop(); } //Start the timer when the user returns var resume = function (){ air.trace("present"); poller.start(); }

Dispatching events

There are several ways to dispatch messages between two objects. One of the easiest ways is to take advantage of the EventDispatcher class available in AIR. Although you cannot extend an AIR class through class inheritance in JavaScript, you can include an EventDispatcher object as a member of a JavaScript object and forward calls to the addEventListener(), removeEventListener(), and dispatchEvent() to this object. An example of this technique is used by the MessageGenerator object to dispatch message events.

First, a new EventDispatcher variable is created (as a local variable in the object constructor):

var dispatcher = new air.EventDispatcher();

Next, public functions are added to the MessageGenerator object, which forward the event-related functions to the dispatcher object:

this.addEventListener = function (){ dispatcher.addEventListener.apply(this, Array.prototype.slice.apply(arguments)); } this.removeEventListener = function (){ dispatcher.removeEventListener.apply(this, Array.prototype.slice.apply(arguments)); } this.dispatchEvent = function (event){ dispatcher.dispatchEvent(event); }

The event objects dispatched using this technique must inherit from the ActionScript Event object (or one of its subclasses). Because of the different inheritance schemes, you cannot extend the Event object to add your own data in JavaScript. However, you can use an existing Event subclass that already has members of the appropriate data type. For the MessageGenerator object, the TextEvent class is used because it has a text property, which holds a string. The following function creates and dispatches a TextEvent object containing the message text:

var createMessageEvent = function() { var messageEvent = new window.runtime.flash.events.TextEvent("message", false, false, generator.getMessage()); dispatcher.dispatchEvent(messageEvent); }

The TextEvent isn't commonly used in a JavaScript-based AIR application because it is normally only dispatched by an ActionScript TextField object. Therefore, the class isn't included in the AIRAliases.js script and you must use the full reference name, including the window.runtime variable, the package name, and the class name.

Note: If none of the existing Event subclasses are appropriate for transmitting your custom event data, you can define (and compile) a new class in ActionScript and import the SWF file containing the class using a script tag. The custom class can then be used in your JavaScript application. For more information on using ActionScript libraries, see Using ActionScript Libraries within an HTML page in the Developing Adobe AIR Applications with HTML and Ajax guide (http://www.adobe.com/go/learn_air_html?content=ProgrammingHTMLAndJavaScript_07.html).

Products

  • Acrobat
  • Creative Cloud
  • Creative Suite
  • Digital Marketing Suite
  • Digital Publishing Suite
  • Elements
  • Mobile Apps
  • Photoshop
  • Touch Apps
  • Student and Teacher Editions

Solutions

  • Digital marketing
  • Digital media
  • Web Experience Management

Industries

  • Education
  • Financial services
  • Government

Help

  • Product help centers
  • Orders and returns
  • Downloading and installing
  • My Adobe

Learning

  • Adobe Developer Connection
  • Adobe TV
  • Training and certification
  • Forums
  • Design Center

Ways to buy

  • For personal and home office
  • For students, educators, and staff
  • For small and medium businesses
  • For businesses, schools, and government
  • Special offers

Downloads

  • Adobe Reader
  • Adobe Flash Player
  • Adobe AIR
  • Adobe Shockwave Player

Company

  • News room
  • Partner programs
  • Corporate social responsibility
  • Career opportunities
  • Investor Relations
  • Events
  • Legal
  • Security
  • Contact Adobe
Choose your region United States (Change)
Choose your region Close

North America

Europe, Middle East and Africa

Asia Pacific

  • Canada - English
  • Canada - Français
  • Latinoamérica
  • México
  • United States

South America

  • Brasil
  • Africa - English
  • Österreich - Deutsch
  • Belgium - English
  • Belgique - Français
  • België - Nederlands
  • България
  • Hrvatska
  • Česká republika
  • Danmark
  • Eastern Europe - English
  • Eesti
  • Suomi
  • France
  • Deutschland
  • Magyarország
  • Ireland
  • Israel - English
  • ישראל - עברית
  • Italia
  • Latvija
  • Lietuva
  • Luxembourg - Deutsch
  • Luxembourg - English
  • Luxembourg - Français
  • الشرق الأوسط وشمال أفريقيا - اللغة العربية
  • Middle East and North Africa - English
  • Moyen-Orient et Afrique du Nord - Français
  • Nederland
  • Norge
  • Polska
  • Portugal
  • România
  • Россия
  • Srbija
  • Slovensko
  • Slovenija
  • España
  • Sverige
  • Schweiz - Deutsch
  • Suisse - Français
  • Svizzera - Italiano
  • Türkiye
  • Україна
  • United Kingdom
  • Australia
  • 中国
  • 中國香港特別行政區
  • Hong Kong S.A.R. of China
  • India - English
  • 日本
  • 한국
  • New Zealand
  • 台灣

Southeast Asia

  • Includes Indonesia, Malaysia, Philippines, Singapore, Thailand, and Vietnam - English

Copyright © 2012 Adobe Systems Incorporated. All rights reserved.

Terms of Use | Privacy Policy and Cookies (Updated)

Ad Choices

Reviewed by TRUSTe: site privacy statement