TweetFollow Us on Twitter

Script App Example
Volume Number:9
Issue Number:8
Column Tag:Scripting

Related Info: Apple Event Mgr

AppleScript Script Applications

An example of an AppleScript application

By Jens Alfke, Apple Computer, Inc.

Note: Source code files and sample scripts accompanying this article are located on MacTech CD-ROM or source code disks.

About the author

Jens Alfke is a member of the AppleScript engineering team at Apple Computer, where he works on the script editor, the script application framework, and the OSA component API. He would like to thank a lot of obscure, alienated British musicians whose guitar noise made his accomplishments possible and bearable.

Figure 1: Two script applications; one droppable, one not

Introduction

The Script Editor that comes with AppleScript™ allows you to save scripts as tiny applications. By “tiny” I mean really tiny: a base size of less than 2k, plus the data size of the script and its description text. A small but useful script application might weigh in at about 8k. (For the curious: the actual code that runs the applications lives as a component in the AppleScript extension. Each script app just has a stub that dynamically links in the real code.)

In the simplest case, the script runs when the application is launched - whether by a double-click, Apple menu choice, or by being in the Startup Items folder - and then the application immediately quits. You can also make script applications that can have file, folder or disk icons dropped on them and then operate on those items. But much more is possible! This article describes:

• How script applications handle Apple events

• Stay-open applications

• Using quit handlers to override the Quit command

• How to write a script server that can handle many different incoming events, even over the network, and how to call it from another application or script

• How to use script properties to store persistent data

• Periodic actions and script agents (sorry, no bow-ties yet)

Theory of Operation

All Apple® Events sent to a script application are funneled through its script. Every “on ” handler in the script intercepts a particular Apple event and its parameters, and can do anything it wants to in response to that event.

The most basic use of this is to intercept the events that the System 7 Finder® sends to an application when it’s launched. These events are “run” and “open”. (Their internal codes are 'oapp' and 'odoc'.) These are described in the next two sections

“on run” Handlers

The run event is sent to an application when it is launched without any items to open. This happens when the application is not already running, and:

• You double-click the application;

• The application is in the Apple Menu Items folder, and you choose it from the Apple menu;

• The application is in the Startup Items folder, and you restart your Macintosh;

• or some third-party application or launcher utility (such as Magnet™ or OnCue™) launches the script application.

(If the script application was already running when one of these actions occurs, it will be brought to the front, but no events will be sent to it.)

If the script in the script application has an “on run” handler, the handler will intercept the event, and the commands in that handler will run when the application is launched. (If the script has statements that are not part of any handler - not enclosed between “on ” and “end ”, in other words - those statements are an implicit run handler. Thus a script with no handlers at all is really an “on run” handler.)

There is actually one thing that happens first: if the application is supposed to display a startup screen (if “Never Show Startup Screen” was not checked when the application was created, and the user has not disabled the startup screen) then the startup screen will be displayed first. The user must then press the Run button or the Return key before the script’s run handler will be called. This is done so the user has a chance to read the description of the script and decide whether to proceed before running the script.

“on open” Handlers

The open event is sent to an application when Finder icons (whether documents, folders or disks) are dragged onto the application’s icon and dropped there. Unlike the run event, the open event is sent even if the application was already running.

If the script in the script application has an “on open” handler, the commands in that handler will run when items are dropped on the application’s icon. The open handler takes a single parameter; when the handler is called, the value of that parameter is a list of all the items that were dropped. (Each item of the list is an alias; you can convert it to a path name by using “as string”.)

The files, folders or disks are not moved, copied or affected in any way by being dragged onto the application. The Finder just makes a list of their identities and sends that list to the script. Of course, your script could easily use the finderLib script library to tell the Finder to move, copy or otherwise affect the items. That's up to you.

Stay-Open Script Applications

By default, a script application processes one event and then quits. This allows it to perform a single task and then get out of your way. On the other hand, a stay-open script application (one that was saved with the “Stay Open” box checked in the Script Editor save dialog) will stay open once it’s launched and not quit until told to. This has several major uses:

• It's faster for the application to stay around than it is for it to launch and quit every time you drop something on it. If you have a “drop box” that you use very frequently, you might want to make it stay-open.

• Other applications or scripts can send it events other than “run” and “open”, and the script can include handlers that will be triggered by those events. This makes the application into a script server.

• The script can perform periodic actions, even in the background, as long as the application is running.

On the other hand, if your script performs its main function in a run handler (i.e., when the application is launched) it won’t make much sense for the app to stay open, since subsequent double-clicks won’t invoke the run handler.

Script Servers

A script can include any number of handlers for any number of events, as described in the AppleScript Language Reference Manual. Any handler in a script application’s script can be called by another script or another application that can send Apple events.

For example, let’s make a simple script:

/* 1 */

on foobar( message )
 display dialog "Foobar received: " & message
end foobar

We’ll save this as a script application under the name of “Foobar App”, making sure to check “Stay Open” and “Never Show Startup Screen” in the Save As dialog. Now we can write a script to talk to this app:

/* 2 */

tell app "Foobar App" to foobar("Greetings!")

If you run this script (saved as an app, or directly from the script editor) it’ll send a foobar event to “Foobar App”, which will catch the event and display a dialog. (If Foobar App isn’t running the first time you run the script that calls it, AppleScript may put up a standard-file dialog asking you to locate the app.)

Since Apple events can be sent across an AppleTalk network, the client (caller) and server scripts don’t even have to be on the same computer! The remote version of the calling script might look like:

/* 3 */

tell app "Foobar App" of machine "Jens’ Mac" of zone "Scripters"
 foobar("Greetings!")
end tell

Handling Quit Events

By including an “on quit” handler in your script, you can catch the quit event (sent when the user chooses the Quit menu command or presses Command-Q) before the application itself handles it and quits. The commands in the handler could set script properties, tell another application to do something, or display a dialog. The handler can decide whether or not the application should quit by choosing whether to continue the quit. If the handler calls “continue quit”, the application's default quit behavior will be invoked and the application will in fact quit. If the quit handler returns without continuing the quit event, the application will not quit. Here's a handler that checks with the user before quitting:

/* 4 */

on quit
 display dialog "Really quit?" buttons {"No", "Quit"} default button 
"Quit"
 if the button returned of the result is "Quit" then
 continue quit
 end if
 -- If I don't continue the quit, the app will keep running.
end quit

Important: It's possible, through some bug in the quit handler, that it never continues the quit event, making it impossible to quit the application. (For instance, if the handler gets an error before it can call “continue quit”, quitting the application will just produce an error alert without quitting!) As a last resort, use the Emergency Quit command: press Command-Shift-Q, or hold down the Shift key while choosing the Quit menu command. This will immediately quit the application without calling the quit handler.

Persistent data

As described in the Language Reference Manual, AppleScript scripts can have properties. A script property is a variable that can be accessed by any handler in the script, and whose value is stored as part of the script. (By contrast, a regular local variable belongs only to the handler in which it’s declared, and its value is lost as soon as the handler finishes.) A property is declared like so:

property name : initialValue

When a script application quits, the script is saved back to disk if any of its properties were modified. (This happens even if you do an emergency quit via Cmd-Shift-Q.) This makes properties persistent. A property will retain its value until the script changes it, even if you quit the app, reboot or make copies of the script.

All this makes properties extremely useful. Every script application can store its own preferences and other persistent data inside itself, without having to create a separate preference file or contend for space in a central database. The “Folder Watcher” agent shown in the next section makes use of this to remember the modification date of a folder, so it can warn the user when the folder is next modified.

One caveat: when a script is recompiled, the values of all its properties are reset to the initial values specified in the script text.

“on idle” Handlers and Agents

A stay-open script application is sent periodic “idle” events whenever it's running but not processing an incoming event, and can catch them with an “on idle” handler. The commands in that handler will then be run periodically (every 30 seconds, by default.) For instance, if the script includes:

/* 5 */

on idle
 beep
end idle

then the script application, when run, will beep every 30 seconds. To change the rate, return the number of seconds to wait as the result of the script:

/* 6 */

-- This script will beep every 5 seconds.
on idle
 beep
 return 5
end idle

In other words, if the handler returns a positive number, that number becomes the rate (in seconds) at which the idle handler is called. If the result of the handler is a non-numeric value, or less than or equal to zero, the rate will not be changed.

Be careful! The result returned from a handler is just the result of the last statement, even if it doesn't explicitly say “return”. For instance, the following handler will (probably unintentionally) be called only every fifteen minutes:

/* 7 */

on idle
 set x to 30
 beep
 set x to x * x -- BAD! The result (900) will be returned from the handler
end idle

If you want to be sure you're not changing the idle rate, just return zero.

A Simple Agent: Folder Watcher

Here’s a very simple example of an agent: a background task that watches for an interesting situation and then does something in response. This particular agent wakes up every few seconds and checks the modification date of a particular folder (whose path you hard-code into the targetPath property.) If the mod date has changed since it last checked, which means that files have been added to or removed from the folder, it calls the folderChanged function. As shown here it just beeps, but you can add anything you like.

/* 8 */

-- Folder Watcher, a simple agent example
property targetPath : “sneJ:Shared Folders:Jens Public:Drop Box:” -- 
path to target folder

property targetFolder : 0 -- target folder alias (set at startup)
property modDate : 0 -- mod date of folder when last checked

on run
 set targetFolder to alias targetPath -- get alias to the folder
end run

on idle
 set newModDate to modification date of (info for targetFolder)
 if modDate = 0 or newModDate > modDate then
 set modDate to newModDate
 folderChanged(targetFolder)
 end if
 return 3 -- Idle time in seconds
end idle

on folderChanged(f)
 beep
 -- Put anything you want here, and it'll run whenever the
 -- folder is modified. See the “What's New?” sample script 
 -- for a more sophisticated example,  which figures out what 
 -- files have been added and displays their names to the 
 -- user.
end folderChanged

Edit the first line to point to the folder of your choice, save the script as a stay-open application, and run it. The script will now beep every time you drag files into or out of the folder. I find this very useful for a drop-box folder on my disk that’s being shared on the network. Whenever someone connects to it and drops files in, my agent notifies me. It’s almost an e-mail system!

This script application doesn’t cause any noticeable system slowdown. Checking the modification date of a folder is extremely fast; the idle handler in this script runs in the blink of an eye. If you’re really worried, you could slow down the idle rate to once a minute.

Script applications that are launched but not doing anything - just waiting for an event, or for their idle time to come round - take up zero CPU time. The entire process just goes to sleep until woken up by the Process Manager or Event Manager.

Some more powerful agent scripts can be found in the “Sample Scripts” folder of the AppleScript Runtime or Software Development Kit; look in the “Finder Agents” sub-folder.

Some Gotchas

Calling Non-Stay-Open Scripts

There are, unfortunately, a few subtleties having to do with sending events to non-stay-open applications. Here’s the deal:

When AppleScript launches an application as a result of a “tell application ” statement, it first sends the application a run event. (Actually, this is standard behavior for the Macintosh OS. All applications get a run event when launched, in response to which they usually open a new untitled document.) This is normally a good thing, since you can put initialization code in your run handler and be assured that it'll run whenever the application is launched.

However, this does make it difficult to run a non-stay-open script application. The natural way to do it would be:

/* 9 */

tell application "non stay open" to run

Here's what goes wrong: The tell command launches the script application and sends it an implicit run event. The application handles that run event. AppleScript then gets to the explicit run statement in the calling script, and tries to send another run event to the script application. Unfortunately, the application has already handled its one event and quits without responding to the second run. The calling script will wait in vain until it times out, and then get an error.

The culprit in this sad history is the implicit run event sent by the tell statement when it launched the application. AppleScript has to send this event to remain compatible with applications that expect to get this event when they're launched, but we did provide a way around it for special purposes like calling non-stay-open script applications. There is a launch command that explicitly launches an application without sending it a run event. (If the application was already running, the launch command does nothing.)

So the proper way to run a non-stay-open script application is:

/* 10 */

launch application "non stay open" -- Launches, but sends no event
run application "non stay open" -- sends the run event then quits

The launch command launches the application without sending it an event. The run command then sends the run event, and the application will process the event, send back its reply, and quit.

Re-Entrancy Issues

A script application handles incoming events even if it is already running a handler in response to a previous event. This means that execution of a handler can be interrupted while another handler is run, a state known as re-entrancy. However, script applications are not multi-tasking, so two things will never be happening at the same time. The first flow of control halts until the second one finishes.

This can cause problems if both flows of control modify the same script property, or both send commands to an application to modify its data. AppleScript 1.0 does not have multi-tasking facilities (like semaphores or critical-sections) to deal with these issues, so be careful. You might try declaring a “busy” property in your script and setting it to true during critical operations as a crude form of semaphore.

Conclusion

AppleScript script applications offer a lot more than just “a script that runs when you double-click it.” While a real interface builder is still needed (don’t worry, it’s in the works) you can easily build some pretty powerful gizmos - network-visible servers and services, user agents - with the current framework. Go for it!

 

Community Search:
MacTech Search:

Software Updates via MacUpdate

TinkerTool 5.4 - Expanded preference set...
TinkerTool is an application that gives you access to additional preference settings Apple has built into Mac OS X. This allows to activate hidden features in the operating system and in some of the... Read more
Tinderbox 6.3.1 - Store and organize you...
Tinderbox is a personal content management assistant. It stores your notes, ideas, and plans. It can help you organize and understand them. And Tinderbox helps you share ideas through Web journals... Read more
Parallels Desktop 10.2.2 - Run Windows a...
Parallels Desktop is simply the world's bestselling, top-rated, and most trusted solution for running Windows applications on your Mac. With Parallels Desktop for Mac, you can seamlessly run both... Read more
Adobe Premiere Pro CC 2015 9.0.1 - Digit...
Premiere Pro CC 2015 is available as part of Adobe Creative Cloud for as little as $19.99/month (or $9.99/month if you're a previous Premiere Pro customer). Premiere Pro CS6 is still available for... Read more
Adobe After Effects CC 2015 13.5.1 - Cre...
After Effects CC 2015 is available as part of Adobe Creative Cloud for as little as $19.99/month (or $9.99/month if you're a previous After Effects customer). After Effects CS6 is still available... Read more
Adobe Creative Cloud 2.2.0.129 - Access...
Adobe Creative Cloud costs $49.99/month (or less if you're a previous Creative Suite customer). Creative Suite 6 is still available for purchase (without a monthly plan) if you prefer. Introducing... Read more
Tower 2.2.3 - Version control with Git m...
Tower is a powerful Git client for OS X that makes using Git easy and more efficient. Users benefit from its elegant and comprehensive interface and a feature set that lets them enjoy the full power... Read more
Apple Java 2015-001 - For OS X 10.7, 10....
Apple Java for OS X 2015-001 installs the legacy Java 6 runtime for OS X 10.11 El Capitan, OS X 10.10 Yosemite, OS X 10.9 Mavericks, OS X 10.8 Mountain Lion, and OS X 10.7 Lion. This package is... Read more
Adobe Muse CC 2015 2015.0.1 - Design and...
Muse CC 2015 is available as part of Adobe Creative Cloud for as little as $14.99/month (or $9.99/month if you're a previous Muse customer). Muse CS6 is still available for purchase (without a... Read more
Adobe Illustrator CC 2015 19.1.0 - Profe...
Illustrator CC 2015 is available as part of Adobe Creative Cloud for as little as $19.99/month (or $9.99/month if you're a previous Illustrator customer). Illustrator CS6 is still available for... Read more

Tap Delay (Music)
Tap Delay 1.0.0 Device: iOS Universal Category: Music Price: $4.99, Version: 1.0.0 (iTunes) Description: Back in the “old days”, producers and engineers created delay and echo effects using tape machines. Tap Delay combines the warm... | Read more »
This Week at 148Apps: July 20-24, 2015
July is Heating Up With 148Apps How do you know what apps are worth your time and money? Just look to the review team at 148Apps. We sort through the chaos and find the apps you're looking for. The ones we love become Editor’s Choice, standing out... | Read more »
Red Game Without A Great Name (Games)
Red Game Without A Great Name 1.0.3 Device: iOS Universal Category: Games Price: $2.99, Version: 1.0.3 (iTunes) Description: The mechanical bird is flying through an unfriendly, Steampunk world. Help it avoid obstacles and deadly... | Read more »
Warhammer: Arcane Magic (Games)
Warhammer: Arcane Magic 1.0.2 Device: iOS Universal Category: Games Price: $9.99, Version: 1.0.2 (iTunes) Description: Engage in epic battles and tactical gameplay that challenge both novice and veteran in Warhammer: Arcane Magic, a... | Read more »
Mazes of Karradash (Games)
Mazes of Karradash 1.0 Device: iOS Universal Category: Games Price: $1.99, Version: 1.0 (iTunes) Description: The city of Karradash is under attack: the monsters of the Shadow Realms are emerging from the depths.No adventurer is... | Read more »
Battle Golf is the Newest Game from the...
Wrassling was a pretty weird - and equally great - little wressling game. Now the developers, Folmer Kelly and Colin Lane, have turned their attention to a different sport: golfing. This is gonna be weird. [Read more] | Read more »
Qbert Rebooted has the App Store Going...
The weird little orange... whatever... is back, mostly thanks to that movie which shall remain nameless (you know the one). But anyway it's been "rebooted" and now you can play the fancy-looking Qbert Rebooted on iOS devices. [Read more] | Read more »
Giant Monsters Run Amok in The Sandbox...
So The Sandbox has just hit version number 1.99987 (seriously), and it's added a lot more stuff. Just like every other update, really. [Read more] | Read more »
Fish Pond Park (Games)
Fish Pond Park 1.0.0 Device: iOS Universal Category: Games Price: $2.99, Version: 1.0.0 (iTunes) Description: Nurture an idyllic slice of tourist's heaven into the top nature spot of the nation, furnishing it with a variety of... | Read more »
Look after Baby Buddy on your Apple Watc...
Parigami Gold is the new premium version of the match three puzzler that includes Apple Watch support and all new content. You won't simply be sliding tiles around on your wrist, the Apple Watch companion app is an all new mini-game in itself. You'... | Read more »

Price Scanner via MacPrices.net

2.8GHz Mac mini available for $988, includes...
Adorama has the 2.8GHz Mac mini available for $988, $11 off MSRP, including a free copy of Apple’s 3-Year AppleCare Protection Plan. Shipping is free, and Adorama charges sales tax in NY & NJ... Read more
Sale! 13″ 1.6GHz/256GB MacBook Air for $1099,...
B&H Photo has the 13″ 1.6GHz/256GB MacBook Air on sale for $1099 including free shipping plus NY tax only. Their price is $100 off MSRP, and it’s the lowest price available for this model. Read more
iPad mini 4 To Be Upgraded To iPad Air 2 Spec...
There’s a certain inevitability about making Apple product predictions this time of year. Come September, we can pretty reliably count on the release of refreshed iPhones, along with the iOS 9... Read more
Apple restocks refurbished Mac minis for up t...
The Apple Store has restocked Apple Certified Refurbished 2014 Mac minis, with models available starting at $419. Apple’s one-year warranty is included with each mini, and shipping is free: - 1.4GHz... Read more
13-inch 2.5GHz MacBook Pro on sale for $899,...
Best Buy has the 13″ 2.5GHz MacBook Pro available for $899.99 on their online store. Choose free shipping or free instant local store pickup (if available). Their price is $200 off MSRP. Price is... Read more
21-inch 2.9GHz iMac on sale for $1299, save $...
Best Buy has the 21″ 2.9GHz iMac on sale today for $1299.99 on their online store. Choose free shipping or free local store pickup (if available). Their price is $200 off MSRP, and it’s the lowest... Read more
Free Image Sizer 1.3 for iOS Offers Photo Edi...
Xi’An, China based G-Power has announced the release of Image Sizer 1.3 for the iPhone, iPad, and iPod touch, an important update to their free photo editing app. Image Sizer’s collection of easy to... Read more
Sale! 13″ 1.6GHz/128GB MacBook Air for $899,...
B&H Photo has the 13″ 1.6GHz/128GB MacBook Air on sale for $899 including free shipping plus NY tax only. Their price is $100 off MSRP, and it’s the lowest price available for this model. Read more
13-inch Retina MacBook Pros on sale for $100...
Best Buy has 13-inch Retina MacBook Pros on sale for $100 off MSRP on their online store. Choose free shipping or free local store pickup (if available). Prices are for online orders only, in-store... Read more
Will BMW’s i3 Electric Vehicle Be The Automo...
The German-language business journal Manager Magazin’s Michael Freitag reports that Apple and the German performance/luxury automaker Bayerishe Motoren Werke (BMW) are back at far-reaching... Read more

Jobs Board

*Apple* Retail - Multiple Positions (US) - A...
Job Description: Sales Specialist - Retail Customer Service and Sales Transform Apple Store visitors into loyal Apple customers. When customers enter the store, Read more
*Apple* Retail - Multiple Positions (US) - A...
Job Description: Sales. Specialist - Retail Customer Service and Sales. Transform Apple Store visitors into loyal Apple customers. When customers enter the store, Read more
*Apple* Customer Experience (ACE) Leader - A...
…management to deliver on business objectives Training partner store staff on Apple products, services, and merchandising guidelines Coaching partner store staff on Read more
Project Manager - *Apple* Pay Security - Ap...
**Job Summary** The Apple Pay Security team is seeking a highly organized, results-driven Project Manager to drive the development of Apple Pay Security. If you are Read more
*Apple* TV Product Design Internship (Spring...
…the mechanical design effort associated with creating world-class products with the Apple TV PD Group. Responsibilities will include working closely with manufacturing, Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.