Thursday, May 8th, 2008

Growl for Windows and a Web Notification API

Category: Gears, JavaScript

>I have talked before about the desire for a Notification API on the Web. As a Mac user, I would love to see Growl from JavaScript, and there have been libraries written from as far back as protoGrowl.

The difference is between a JavaScript API that does notifications on the desktop, versus trying to get little custom notifications inside the browser window itself. I am talking about the former.

Brian Dunnington has developed Growl for Windows, and with his latest version, he allows you to talk to the system via JavaScript.

You can check out the growl.js library.

What was interesting was the implementation side, and the paths Brian went down to get this working. I asked him for his thoughts, and he wrote up the following:

One of the biggest new features in the latest version of Growl for Windows (v1.2 alpha) is the ability to receive notifications from websites running in your browser. i spent quite a bit of time working out the best way to handle this functionality and thought i would share my thought process.

since Growl can already receive notifications over the network, i figured that it would be easiset to build the Web-based notification system on top of that. Growl receives network notifications using a simple protocol over UDP. ok – first hurdle: browsers and javascript dont do UDP, so i figured i would have to go with some kind of add-on. i wanted the solution to work cross-browser, so Firefox extensions and ActiveX plug-ins were ruled out. i also wanted the solution to work for the broadest range of people, so i didnt want to write a custom add-on (a la Gears). i knew that Flash and Silverlight both had networking support, but neither can do UDP, so they were both quickly ruled out.

that left Java as the only other widely-installed cross-browser extension at my disposal. Java obviously has robust networking support, including UDP, so i headed down that path. the biggest problem now was that i have never created a Java applet, nor even written a line of Java code. but the syntax was familiar enough, and i was able to find some good sample code on the net that i was able to mash into a tiny applet that could send UDP packets. it actually worked brilliantly, and i was quite happy with myself for solving the problem so easily.

but of course, it was not that easy. there is that little restriction known as the ‘same-origin policy’. running the applet on my localhost worked great, but as soon as i ran it from any other location, i would get a secuirty exception. i tried all kinds of combinations of values for the CODE and CODEBASE attributes, including file:// urls and even encoding the applet code as a data: uri, but i was thwarted at every turn (as so i should have been – the entire reason the restriction is in place is to prevent what i was trying to do). right before i gave up on the applet idea, i had the realization that if i could serve the applet up from the local host, then it would be able to communicate with the local host later. but configuring and installing a simple web server just to serve up an applet seemed like overkill. alas, the Java idea was a dead end.

so, it was back to the drawing board. what did the browser have access to that could bridge the gap? i decided to try a custom protocol handler, similar to the Itunes Music Store (itms://). a couple of simple registry entries and i had my growl:// protocol working. i had a helper process that sat in the background and everytime a growl:// url link was clicked, the browser would pass it off to my handler, along with the original url. i decided that i could pass any information as a JSON-encoded string in that url information. again, it worked great and seemed to be a good solution, but that made me sure that it must have a drawback. turns out the drawback in this case was that there was no way for the browser to know if the protocol handler was installed on the user’s machine – if the protocol handler was installed, the browser passed it off nicely and all was good, but if the protocol was not installed, Firefox would present a dialog saying something like ‘firefox doesnt know how to open the address because the protocol is not known’ (IE and Safari both just returned a 404-type page). since i wanted websites to be able to use the communication feature if the user had Growl installed, but not mess up the experience if they didnt, this was a deal breaker.

i was starting to run out of ideas at this point, but i remembered the idea of serving up the Java applet locally. while i was pondering the details of that solution, i thought ‘if i am going to have a local server to serve up the applet, why not skip the applet and just communicate with the local server?’. so i implemented a very simple webserver that runs when Growl is running that can be accessed at something like http://localhost:9889. the idea of using the url to pass JSON was repurposed and soon i was able to pass JSON-encoded Javascript objects to the local server, which code then parse the data and handle it in real application code. i couldnt use ajax to communicate with the local server (same-origin policy strikes again), so i decided to use the hidden iframe technique. i wrote a small js library to abstract everything out, so now you can write code in Javascript that almost mimics the code you would write if you included the Growl libraries in you application code:

javascript
< view plain text >
  1. Growl.NotificationType someKindOfNotification = new Growl.NotificationType("some kind of notification", true);
  2. Growl.register("Website Name", [someKindOfNotification]);
  3. Growl.notify(someKindOfNotification, 'Notification from the web', 'this is the description', Growl.Priority.VeryLow, false);

of course, receiving notifications from websites opens up the possiblity of spam and other noise, so applications that register from the web have their notifications disabled by default (thus requiring the user to explicity grant the notifications they wish to receive). but that is another topic for another day.

Ed: I decided to make today, “Extend the browser through APIs Day”

Related Content:

Posted by Dion Almaer at 11:38 am
8 Comments

++++-
4.2 rating from 25 votes

8 Comments »

Comments feed TrackBack URI

Mh, this API also needs a check method to see if Growl is available. If people looking for fall-back (No, its really not a shameless house advertising ;) )
Roar, inspired by Growl, based on Mootools: http://digitarald.de/project/roar/

Comment by Harald — May 8, 2008

Just wanted to give a holler that Roar is extremely well-done, as are all of Harald’s projects.

In the meantime, I’ll try out windows Growl! Lord knows we need it.

Comment by PaulIrish — May 8, 2008

Let me point you to this comment:
http://www.webappers.com/2008/04/21/send-notifications-instantly-with-growl-mootools/#comment-7477

Growl (on Mac), “standard” Firefox notification otherwise. Combining this Growl solution, LacKac’s CallOut, and the inbrowser messages would be a great thing.

Comment by AndrasBarthazi — May 8, 2008

Fluid (Site-specific browser on top of webkit, like Prism) has a javascript API for growl: http://fluidapp.com/

Comment by Greg — May 9, 2008

I’m developing an .NET APi for displaying Growl-style notifications. It’s an managed DLL you can use in any .NET project like C# and it’s easy to use… just like MessageBox.Show() … ;o)

check out a very early release here: http://www.visualdrugs.net/temp/growl_for_windows.rar

Start TestForm and klick the button. More comming soon.

Ciao SunboX

Comment by SunboX — May 9, 2008

Awesome work hey. i downloaded the latest version , 1.2,
and tried it . Even though Growl is listening correctly and i can see my application registered within Growl’s Application page no message gets displayed which is odd.

Comment by Teroz — May 9, 2008

Actually it seems you can detect a custom handler – have a look at how skype does it: http://download.skype.com/share/skypebuttons/js/skypeCheck.js

Comment by maccman — May 9, 2008

based on Harald’s suggestion, i added the ability to detect if Growl is running from the JS API. i also changed the JS implementation to no longer require the hidden IFRAME to do the communication. you can now use Growl.isRunning() to check if Growl is installed and running, and there is an event called onInitialized that you can implement that gets fired when Growl (or the lack thereof) is detected.

the Growl for Windows project was built specifically to handle Growl notifications on windows machines (not a browser-based notification system), so this library only hooks into that functionality. the other projects listed here (protoGrowl, Roar, CallOut, etc) look cool in their own rights since they provide browser-based fallback if Growl is not available. a unified notification system would be great to finally see.

Comment by brian dunnington — May 12, 2008

Leave a comment

You must be logged in to post a comment.