Using Growl from your AppleScripts

What is Growl?

[b]Growl[/b] is a very popular freeware global notification system written for OS X that installs itself as a preference pane and/or a menubar icon and menu. Applications use Growl to display small notifications in a consistent manner controllable by the user. Notifications can appear even if the application is in the background or hidden when the notification event occurs. Applications that use Growl register a ticket with Growl when they start up and these can be seen in the preference pane. As notifiable events occur, these are sent to Growl for display, e.g., “Feed Download Session Ended”.

A lot of current OS X applications can do this if the user has Growl installed (It is not part of OS X): Firefox, NetNewsWire, NewsFire, Quicksilver, Shiira, Skype, Transmit, Twitterific, VLC media player, Yahoo! Messenger, and Google Notifier, to name only a sub-set of them. There are also plug-ins to enable Growl notifications in other Macintosh applications that don’t build Growl in, and these include iChat, iTunes, Mail, Thunderbird, Safari, MS Entourage, and Camino.

The preference pane provided allows the user to customize the display he/she sees and to turn them off and on as desired. The menubar icon gives easy access to a menu of some of the features as well as a link to the preference pane. If you’re wondering if a particular App. has Growl capability, right-click on the application, choose “Show Package Contents” in the contextual menu, and look in the Frameworks folder for “Growl.framework”.

Growl also installs a daemon; the GrowlHelperApp, and it is AppleScriptable. This article is about using Growl notifications from your scripts.

Gimme an Example

I have a script for getting going in the morning that does a lot of things: it presents a notification of how many emails I have waiting and opens the appropriate mailboxes, it opens The AppleScript BBS and two other forums I follow, and it posts two other notifications telling me about upcoming medical appointments and upcoming extended family birthdays. They’re a good example, so I show them below (click on the figures if you actually want to read them, and note that I’m an old guy):

Figure 2: Upcoming Birthdays

Figure 3: Upcoming Appointments

If I haven’t convinced you that you need Growl, here’s a second opinion by Alex Tan in his ForeverGeek blog. If you’re a lover of the Terminal, you can even post notifications from your shell scripts as shown in this hint from MacOSXHints.

Growl Setup

As mentioned earlier, Growl notifications must be registered with Growl or they won’t happen. In a given script registration, you can declare more than one note and thereafter use any of them without registering again. You don’t have to register more than one note to change the title, content, icon, etc. of a notification, but if you don’t use multiple notes, then the user (probably you) cannot format the notes from a given script separately in the Growl Preference Pane, giving them different background and text colors, for example. The Growl Preference Pane is where these settings happen. Before proceeding to the prefpanes, let’s deal with registering a ticket with Growl.

Scripting a Notification

Assuming that at this point you have downloaded and installed Growl (the latest version is 1.1.2 and saved the uninstaller AppleScript app and weblinks that that come with it, you’re ready to post a note.

The Growl Documentation for AppleScript includes the following script as a sample (I’ve embedded some additional comments and marked them **):


tell application "GrowlHelperApp" -- ** the daemon that is behind the scenes
 -- Make a list of all the notification types that this script will ever send: 
 -- ** They really mean "ever" or you'll have to reregister.
 set the allNotificationsList to {"Test Notification" , "Another Test Notification"}

 -- Make a list of the notifications that will be enabled by default. 
 -- ** We'll see shortly that a note must be enabled and the user can disable it.
 -- Notifications not enabled by default can be enabled later in the 'Applications' tab of the growl prefpane.
 set the enabledNotificationsList to {"Test Notification"} -- ** just one turned on, the other not.

 -- Register our script with growl.
 -- You can optionally (as here) set a default icon for this script's notifications.
 -- ** Theoretically, you only have to register once, but there is absolutely no harm in doing
 -- it every time the script runs, [i]i.e.[/i], leaving this line in your script.
 register as application "Growl AppleScript Sample" all notifications allNotificationsList default notifications enabledNotificationsList icon of application "Script Editor"
	 
 --	Send a Notification...
 -- This one will appear because it was enabled by default.
 notify with name "Test Notification" title "Test Notification" description "This is a test AppleScript notification." application name "Growl AppleScript Sample" 

-- This one will not appear -- it wasn't enabled by default so the user has to turn it on in the 'Applications' tab of the Growl prefpane to see it.
 notify with name "Another Test Notification" title "Another Test Notification :) " description "Alas � you won't see me until you enable me yourself..." application name "Growl AppleScript Sample" 
end tell

After you run and save this script, go to the Growl Menubar menu (the icon looks like this ) and select “Open Growl Preferences…”. Click the “Applications” tab and in the top pane find the ticket for “Growl AppleScript Sample” with a Script Editor icon next to it. It should be enabled, but if you uncheck it, it will no longer show. If you haven’t enabled the Growl Menu, just go to the Growl preference pane in System Preferences and click the Applications tab.

Figure 4 below shows the pane for the Applications tab where the list shows all the tickets Growl has registered. Search in the list for the Growl AppleScript Sample there and select it. You will see that it is enabled. If you uncheck it in this view and run the sample script again, you will not see a growl result even though you have registered it again. The user rules here – not our script.

Figure 4: Application Settings Pane

Figure 5: Application Settings Configuration

Now (and this can be a bit confusing) click on the Configure button, leaving the Growl AppleScript Sample script selected. A new pane appears as shown in Figure 5. The point to remember in this pane is that you are configuring the selection in the previous applications list pane. The name is shown in the title just under the Applications tab on this pane. Next to the name is a button to return to the list view. Below that are two more tabs. The Application tab is to configure several things that don’t yet work for an AppleScript. "Inform nameOfApp when notification is clicked is in the works but not working, but if the “Use custom starting position:” radio button is clicked, it is possible if the style permits, to relocate the starting position of the notification. Bezel, however, cannot be located this way.

When you click on the “Notifications” tab, the pane in Figure 6 below appears. Here, there is a drop-down menu showing the registered notifications for the application or script. Since we have Growl AppleScript Sample selected in the Application list, there are two notifications in the menu: “Another Test Notification” which is not enabled, and “Test Notification” which is. Here you can select the Default style for the notification, and enable or disable it here.

[url=http://files.macscripter.net/unscripted/Growl/NotificationConfig.jpg][/url] [url=http://files.macscripter.net/unscripted/Growl/DisplayOptions.jpg][/url] [i] Figure 6. Notification Configuration[/i] [i]Figure 7. Display Options[/i]

In the next tab, “Display Options”, the pane in Figure 7 appears. You can play with and see how these options will look. Try selecting Bezel, for example, and clicking the Preview button. Note that this is one of the few display formats among the standards that you can move to anywhere on your primary screen. Candybars and Smoke are styles that can be placed on a second display (I have two screens, and use this feature). Priority formats are set here as well, for those styles that support them, as Smoke does. To set the background and text colors for each of the priority levels (the default level is 0) click on their respective boxes. I only use two of these – the default (0), and Emergency (2) levels for smoke. To see what you get, use the Preview button.

Bear in mind that in this tab you are setting the defaults for the display formats and will get a different pane for each. MailMe, doesn’t have a display – it sends mail instead to the address you enter in its pane. If you’re not happy with the styles provided, there are others developed by third parties to be found found in Custom Growl Styles at ResExellence.com.

Growl Registrations must declare the application name that will want the notification (your script), the names you will be giving to the various notifications you want to send (the ‘all’ list), and which ones you want turned on immediately (the defaults list). You can also append the icon of any application to these notifications (as the default – you can change icons later).

Growl Notifications must have a name, a title, a description (which is the text to be displayed below the title), and a “with name” term which specifies which of the notes you’ve registered you want to display. In addition to these, however, you can add the icon of an application, e.g. for iCal: icon of application “iCal”, and this will appear in the note. You can also use PICT images, and more likely, images of your own. These are specified in a notify statement by alias, by posix path, or by URI (file:///PathtomyPic.jpg). Finally, as mentioned earlier, you can set priorities, but there is no way to alter their formats from a script yet – you’ll have to set them in the prefpane.

More Scripts

There is a script in ScriptBuilders to growl your iCal alarms by imAGn Software (free). It’s called GrowlIt. Also available at imAGn’s site. With the developer’s kind permission, I have included it below as an example of how to Growl notifications from applications that don’t growl them.


-- GrowlIt
-- Description:
-- An applescript that displays events and to-do's from iCal as Growl notifications.
-- Based on multiple other Applescripts found in multiple sites.
-- No warranty. Tested with iCal 2.0.5 and Growl 0.7.6 under Mac OS X Tiger 10.4.10
-- Written by L.A. [email]software@imagn.net[/email]
-- Last modified: 08/31/2007
-- Comments with ** added by Adam Bell
-----------------------------------------------------------------------------------------------------------------------------
set myAllNotesList to {"Events"}
set appName to "GrowlIt"
set now to current date -- ** See note on next statement
set startD to now - 2 * hours -- ** By setting time of "now" to 0 this would be all day
set endD to now + 1 * days -- ** Change this if you want a longer preview.
-- ** First register a ticket with Growl...
tell application "GrowlHelperApp" to �
	register as application appName all notifications myAllNotesList default notifications myAllNotesList icon of application "iCal"
-- ** Then get something to Growl about from iCal
tell application "iCal"
	repeat with thisCalendar in calendars
		repeat with thisEvent in ((every event of thisCalendar) whose ((start date ≥ startD and start date ≤ endD) or (end date ≥ now and start date ≤ startD)))
			set theEventSummary to ""
			set theEventDescription to ""
			if exists open file alarm of thisEvent then
				set interValue to trigger interval of open file alarm of thisEvent
				if (start date of thisEvent is greater than (now - (interValue * minutes) - (1 * minutes)) and start date of thisEvent is less than (now - (interValue * minutes) + (1 * minutes))) then
					tell thisEvent
						if exists summary of thisEvent then
							set theEventSummary to (summary & " in " & (interValue * -1) & " minutes")
						end if
						set interValue to trigger interval of first open file alarm of thisEvent
						if exists description of thisEvent then
							set theEventDescription to description
						end if
					end tell
					-- ** Finally, GrowlIt. 
					-- ** Note that the note is "sticky"; you have to click it to dismiss it.
					tell application "GrowlHelperApp" to �
						notify with name "Events" title theEventSummary description theEventDescription application name appName with sticky
				end if
			end if
		end repeat
	end repeat
end tell

The Upsides of Growling Messages

Unlike an AppleScript Dialog, Growl notifications have several advantages.

  • 1. They are quite configurable with a broad array of templates available

  • 2. Some templates provide moveability from the default upper right hand corner
  • 3. Notifications can be made transparent
  • 4. Background and Text colors are configurable
  • 5. Notifications do not block the script, they just inform while the script keeps running
  • 6. More than one can appear at a time and they automatically avoid overlapping.
[b]The Major Downside of Growling Messages[/b]

Unfortunately, Growl does not return a result from a notification so your script cannot determine whether a sticky note has been dismissed or not. Only a dialog will do that.

Checking for Growl

A lot of Mac users, but certainly not all, have Growl installed. If you are going to distribute a script that uses Growl notifications, however, or perhaps one that is bilingual (using a dialog if not Growl) you have to check whether the GrowlHelperApp is running before attempting to register your ticket or the user will get an error. A script like the one that follows shows how I do it:


-- To be saved as "NoteTester.scpt" to give it a name.
tell application "System Events" to set GrowlRunning to exists application process "GrowlHelperApp"
set Message to "So this message appears in Growl"
set altMsg to "So this message is a dialog"

NotifyMe(Message, altMsg, GrowlRunning) -- Obviously, Titles could be included.

-- The Handler
to NotifyMe(msg, altMsg, Growler)
	if Growler then
		tell application "GrowlHelperApp"
			register as application "NoteTester.scpt" all notifications {"Note"} default notifications {"Note"} icon of application "Script Editor"
			
			notify with name "Note" title "GrowlHelperApp is Running" description msg application name "NoteTester.scpt"
		end tell
	else
		display dialog altMsg with title "GrowlHelperApp not Running" with icon 0
	end if
end NotifyMe

A final example needs some explanation. I have a lot of memory, so I leave a lot of applications running all the time: iPulse, Quicksilver, Journler, CopyPaste X, Script Debugger 4, NetNewsWire, Eudora, Camino, iCal, and BBEdit would be a typical set, and there are several faceless applications running as well in my menu bar: twitterific, Google Notifier, Meteo (weather), Growl, MenuCalendarClock, and ChimeHours.app. Logging out and in again, or a restart, rare though they are for me, virtually freeze the machine while all this gets going if I leave them all in the Accounts > Login Items preferences.

To avoid this, I’ve taken eight of them out of my Accounts > Login Items list and moved aliases of each to a “Startup Delayed” folder in my home folder. This way, the machine is mine again much sooner while an startup AppleScript application called Startup.Delayed.app, after a 15-second wait, starts the delayed set at six-second intervals and lets me get to work on what is running. To keep me informed as this process unfolds, I growl a series of notifications only the last of which is sticky, and the iintermediates are set to fade in 3.5 seconds. It goes like this:


-- set up some generic notes
property Note_1 : "15-second pre-launch delay." & return & "To be launched:" & return
property Note_2 : "Now launching "
property Note_3 : "All delayed apps have been launched"
-- set up some generic titles
property Title_1 : "Delayed Startup"
property Title_2 : "Launching Delayed Apps."
property Title_3 : "Delayed launches completed"
-- register these growls
tell application "GrowlHelperApp" to register as application "DelayedNote" all notifications {"Note_1", "Note_2", "Note_3"} default notifications {"Note_1", "Note_2", "Note_3"}
-- get the list of apps and names for the first growl
tell application "Finder"
	set theDSfolder to alias ((path to home folder as text) & "Startup Delayed:")
	set lateStartApps to every item of theDSfolder
	set tNames to name of every item of theDSfolder
	set NList to return
	repeat with N in tNames
		set NList to NList & N & return
	end repeat
	set DSCount to count lateStartApps
	-- Growl the beginning of the delay before launching
	my growlIt(Title_1, Note_1 & NList, false)
	do shell script "sleep 15" -- less cpu intensive than delay 15 though not as accurate.
	-- launch the delayed apps at 6-second intervals, each with a growl.
	repeat with k from 1 to count of lateStartApps
		my growlIt(Title_2, Note_2 & item k of tNames, false)
		open item k of lateStartApps
		do shell script "sleep 6"
	end repeat
	-- announce that I'm done -- leave the note on screen.
	my growlIt(Title_3, Note_3, true)
end tell
-- the handler
to growlIt(aTitle, aNote, hold)
	tell application "GrowlHelperApp" to notify with name "Note_1" title aTitle description return & aNote application name "DelayedNote" image from location alias ((path to documents folder as text) & "Journler-myIcons:Family.tif") sticky hold -- I've included a picture in the growls.
end growlIt

Because I have set the time to live of each of the non-sticky notifications to 3.5 seconds, the appearance on my screen is a series of growls letting me know what’s going on, each of which fades before the next is posted. The last one sticks so I know all is well.

If you don’t have Growl installed in your system, you really should try it. It’s not large, the daemon (GrowlHelperApp) occupies only 43 MB of real memory on my machine, and you’ll get notices from lots of applications that are Growl-enabled. When I don’t need user feedback, I always use growls to tell me what’s going on. When I’m testing scripts with shell scripts that take time, I often use a growl to let me know that the shell script has begun and another to let me know it’s done. Whenever you need an asynchronous message, Growl is the way to go.

Happy Growling!

It just took me a long time to figure this out so i thought I would share…

If you want to add the GrowlHelperApp to your “Library” window in Script Editor you need to navigate to the preference pane file in the Finder at this location:

MacintoshHDName/Users/YourUserName/Library/PreferencePanes/Growl.prefPane

Right-Click on this file and show package contents. Go into the “Resources” folder and you will find the GrowlHelperApp.

In Script Editor, open the Library window and click on the plus sign. Drag and drop the GrowlHelperApp file from the Finder into this open dialog window so you can select it. This seems very roundabout but you can’t navigate into the package contents inside an open window so you have to get in there through the Finder first.

Say dude, awesome post. I have been looking for another way besides dialog and voice to provide messages.

I hide most of my drives from finder completely so I made this script as a way to gain quick access to them. I was using voice output as an error handler. Now that I have read your post I am incorporating Growl into it. I have also included the check statement so that it will use the voice command if Growl is not available.

–Sorry if my code is a bit clunky, I have only been working with applescripts for the last two weeks but have used other languages for some time now. I am new to the Mac seen and will be exploring other Mac specific languages in the future. Any suggestions that could streamline my script or improve it are welcome.

Thx again to Adam Bell for this awesome post.



-- Open Drive
--  Created by DemonXstreeM on 5/28/09

global Message
global altMsg
global GrowlRunning
global Sw

tell application "System Events" to set GrowlRunning to exists application process "GrowlHelperApp"
set Message to "Note"
set altMsg to "Note2"

to NotifyMe(msg, altMsg, Growler)
	if Growler then
		tell application "GrowlHelperApp"
			register as application "OpenDrive" all notifications {"Note", "Note2"} default notifications {"Note", "Note2"} icon of application "Script Editor"
			if Sw = Message then
				notify with name Message title "Alas �" description "Volume name does not exist" application name "OpenDrive"
			else
				notify with name altMsg title "Good By" description "" application name "OpenDrive"
			end if
		end tell
	else
		if Sw = Message then
			say "Volume name does not exist." using "Zarvox"
		else
			say "Good By!" using "Bad News"
		end if
	end if
end NotifyMe

on openDrive()
	-- set myIcon to ("///icon.icns") as POSIX file  -- set custom icon if you like
	try
		tell application "Finder"
			activate
			display dialog "Enter Disk Name" default answer ¬
				"Volume Name" buttons {"Never Mind", "Ok"} default button ¬
				("Ok") with title "Open Drive" -- with icon myIcon  -- if using custom icon
			set dialogInfo to result
			set selectedButton to button returned of dialogInfo
			get selectedButton
			set dName to text returned of dialogInfo
		end tell
		
		if button returned of dialogInfo is ("Ok") then
			do shell script "open /Volumes/" & "'" & dName & "'"
		else
			set Sw to altMsg
			NotifyMe(Message, altMsg, GrowlRunning)
		end if
		
	on error
		set Sw to Message
		NotifyMe(Message, altMsg, GrowlRunning)
		openDrive()
	end try
end openDrive


openDrive()


Hello,

So for an Applescript studio app, there is no need to add the Growl Framework to our ressources ?

From what I understand, the Growl Framework is only useful for ppl developping in cocoa right ?

Yes, there is no need, but consider that the project can only be compiled on a machine with GrowlHelper.app installed and any Growl terminology causes a runtime error if Growl is not installed on the target machine

Yep, but I added a check at startup to make sure that growl is indeed installed and running on the target machine – which keeps errors from happening, like Adam Bell posted up there.

I think I’m good because that looks about right :


on will open theObject
	tell application "System Events" to set Growler to exists application process "GrowlHelperApp"
	if Growler then
		tell application "GrowlHelperApp" to register as application "MyApp" all notifications {"Note"} default notifications {"Note"} icon of application "MyApp"
	end if
end will open

-- my code and blah blah here
set theTitle to "Info"
set msg to "this is a notification"
to DisplayGrowlNote(msg, theTitle, Growler)

to DisplayGrowlNote(msg, theTitle, Growler)
	if Growler then
		tell application "GrowlHelperApp"
			notify with name "Note" title theTitle description msg application name "MyApp"
		end tell
	end if
	set msg to ""
end DisplayGrowlNote

Thanks for your answer StefanK :wink:

This is a really cool thread, and I’m going to try that Delayed Startup script, but I do have one question about Growl.

How do you make it so a Growl alert you run from an AppleScript replaces any other Growl alert that is on the screen, so that the new alert “replaces” the old one immediately, with no delay?

I use an AppleScript to change tracks in iTunes, and when I run it a few times, the notifications start building up and there’s a big delay. I figured setting “Stay on Screen” to “Never” would do the trick, but it doesn’t seem to.

Any ideas?

I live happily with a message or two that doesn’t die but I have figured that if I use some utility to simulate a mouse click with a screen region that would do the trick. There are some stuff like that which I have seen on some linux page but on a Mac Os x in context with timing of milli seconds - a timer library.

So, If you use that utility to click on your corner of the screen before publishing a growl message I guess you would be safe.

It seems as though a custom icon for an applet in Growl System Prefs is broken when you specify your custom app as the provider of the icon. When I say applet, I mean when you save the script as an app to be run in Applications. I’m thinking the applet may be missing some real designation as an application. I’ve tried renaming icons and switching their directories to no avail. Just want to point that out. It doesn’t bother me that much, but just kind of messes with my sense of completion.