Third (and Final) Preview of Snowl 0.2

I’ve pushed a new preview release of the next version of Snowl. It includes an updated design for the “river of news” view with many improvements suggested by Alex Faaborg and others.

It also supports sending tweets in addition to receiving them via an interface built into the river and stream views. Just click on the “write a message” icon to expose it:

And it supports multiple Twitter accounts (thanks to Boris Zbarsky, who helped resolve a final vexing issue with HTTP auth), so if you happen to have more than one, you can keep track of all of them:

alta88 also contributed a bunch of improvements and bug fixes, including a context menu for sources with some common commands (like Refresh and Unsubscribe). And Atul Varma contributed a patch that will make it easier to plug in support for other sources of messages.

Finally, I fixed a big performance bug that was slowing down database queries for message content linearly with the database’s growth in size. It looked something like this (courtesy beneneuman):

This preview is feature complete, which means no additional features will land in 0.2. From here on out, it’s only important bug fixes, minor look and feel enhancements, localization support, and other low risk/polish/completeness issues until the release of 0.2.

So try it out, and let me know if you run into any of those kinds of problems (or any others, for that matter, as 0.3 development will be gearing up soon).
Link
Install | Discuss | Chat | Bug Reports | Report a Bug | Source Code

Warning: this version is a primitive implementation with many bugs, and subsequent versions will include changes that break functionality and delete all your messages, making you start over from scratch.

 

making OS X stop prompting me for my wireless password

I’ve long had problems automatically reconnecting to a certain WPA Enterprise wireless network from my MacBook Pro running Mac OS X 10.5.

Despite deleting the network from System Preferences > Network > AirPort > Advanced… > Preferred Networks, deleting its password from the login and System keychains using Applications > Utilities > Keychain Access, and then saving the network and credentials anew, the OS would prompt me to reenter my password for it every time I reconnected to it.

Some digging around on the web suggested that folks having a variety of Mac OS X wireless networking problems can sometimes solve them by deleting various configuration files, including /Library/Preferences/SystemConfiguration/com.apple.airport.preferences.plist.

I checked that file, and strangely, it listed a very old password for that wireless network. Turning off AirPort, deleting that file (I made a backup first just in case), and turning AirPort back on has resolved the problem. I can now reconnect to the network repeatedly (including after a reboot) without being prompted for my password.

 

news: links to Google Groups

(Note: updated with a more reliable representation of the link.)
(Note: updated again to support news:<newsgroup-name> links.)

Here’s an obscure hack.

Firefox 3 supports web protocol handlers (f.e. sending mailto: links to Gmail), while Google Groups archives Usenet. But as far as I can tell, Google Groups doesn’t support news: links, even though Firefox can send them to it. It does, however, support retrieving messages by their IDs or newsgroup names, which news: links contain.

So how could we get Google Groups to load news: links passed to it by Firefox?

The solution is to pass them to an intermediary that extracts the IDs/names from the links and passes them to Google Groups. Here’s a data: URL that does that:

data:text/html,
<html><body><script>
var url = '%s';
var stripPrefix = /^news:(\/\/[^\/]+\/)?/;
if (/@/.test(url))
window.location = 'http://groups.google.com/groups?selm='+url.replace(stripPrefix, '');
else
window.location = 'http://groups.google.com/group/'+url.replace(stripPrefix, '');
</script></body></html>

Unfortunately, it isn’t easy to configure Firefox to use this URL as the news: protocol handler. Manually hacking mimeTypes.rdf is most unpleasant, while window.navigator.registerProtocolHandler only registers http(s): URLs.

But it’s possible to construct a javascript: URL that does the same thing registerProtocolHandler does, namely call the handler service and register the handler with it directly.

The only trick is that you have to enter and run it in the Error Console, which has chrome privileges. Otherwise the URL won’t have the privileges it needs to register the handler.

Here’s a javascript: URL that registers the handler:

javascript: var Cc = Components.classes; var Ci = Components.interfaces; var handler = Cc[‘@mozilla.org/uriloader/web-handler-app;1’].createInstance(Ci.nsIWebHandlerApp); handler.name = ‘Google Groups’; handler.uriTemplate = “data:text/html, <html><body><script> var url = ‘%s’; var stripPrefix = /^news:(\/\/[^\/]+\/)?/; if (/@/.test(url)) window.location = ‘http://groups.google.com/groups?selm=’+url.replace(stripPrefix, ”); else window.location = ‘http://groups.google.com/group/’+url.replace(stripPrefix, ”); </script></body></html>”; var eps = Cc[‘@mozilla.org/uriloader/external-protocol-service;1’].getService(Ci.nsIExternalProtocolService); var handlerInfo = eps.getProtocolHandlerInfo(‘news’); handlerInfo.possibleApplicationHandlers.appendElement(handler, false); handlerInfo.alwaysAskBeforeHandling = true; var hs = Cc[‘@mozilla.org/uriloader/handler-service;1′].getService(Ci.nsIHandlerService); hs.store(handlerInfo); window.location = “data:text/html, <body> <p>The news: link handler for Google Groups has been installed. Try it with these links:</p> <ul> <li><a href=’news:mozilla.support.firefox’>news:mozilla.support.firefox</a></li> <li><a href=’news://news.mozilla.org/mozilla.support.firefox’>news://news.mozilla.org/mozilla.support.firefox</a></li> <li><a href=’news:37604264.65F502CD@netscape.com’>news:37604264.65F502CD@netscape.com</a></li> <li><a href=’news://news.mozilla.org/37604264.65F502CD@netscape.com’>news://news.mozilla.org/37604264.65F502CD@netscape.com</a></li> </ul> </body>”;

To use it, copy the URL, open the Error Console (Tools > Error Console or Ctrl/Command+Shift+J), paste the URL into the evaluation field, and press the Evaluate button.

Once you’ve done that, try it out with these links:

When you click one, Firefox will ask you what you want to do with the link, and Google Groups should be an option on the list.

For the curious, here’s a nicely formatted version of the code inside that javascript: URL, which is based on WCCR_addProtocolHandlerButtonCallback:

javascript:
var Cc = Components.classes;
var Ci = Components.interfaces;

var handler = Cc['@mozilla.org/uriloader/web-handler-app;1'].createInstance(Ci.nsIWebHandlerApp);
handler.name = 'Google Groups';
handler.uriTemplate = "data:text/html,
<html><body><script>
var url = '%s';
var stripPrefix = /^news:(\/\/[^\/]+\/)?/;
if (/@/.test(url))
window.location = 'http://groups.google.com/groups?selm='+url.replace(stripPrefix, '');
else
window.location = 'http://groups.google.com/group/'+url.replace(stripPrefix, '');
</script></body></html>";

var eps = Cc['@mozilla.org/uriloader/external-protocol-service;1'].getService(Ci.nsIExternalProtocolService);
var handlerInfo = eps.getProtocolHandlerInfo('news');
handlerInfo.possibleApplicationHandlers.appendElement(handler, false);
handlerInfo.alwaysAskBeforeHandling = true;

var hs = Cc['@mozilla.org/uriloader/handler-service;1'].getService(Ci.nsIHandlerService);
hs.store(handlerInfo);

window.location = "data:text/html,
<body>
<p>The news: link handler for Google Groups has been installed.
Try it with these links:</p>
<ul>
<li><a href='news:mozilla.support.firefox'>news:mozilla.support.firefox</a></li>
<li><a href='news://news.mozilla.org/mozilla.support.firefox'>news://news.mozilla.org/mozilla.support.firefox</a></li>
<li><a href='news:37604264.65F502CD@netscape.com'>news:37604264.65F502CD@netscape.com</a></li>
<li><a href='news://news.mozilla.org/37604264.65F502CD@netscape.com'>news://news.mozilla.org/37604264.65F502CD@netscape.com</a></li>
</ul>
</body>";

Of course Google Groups could make this hack moot by simply supporting news: links and protocol handler registration natively. For info on how to do that, Google Groups, see the news: URL standard in RFC 1738 and these subsequent IETF drafts, then read the Devmo docs on window.navigator.registerProtocolHandler.

 

Working at >Play

Saturday I staffed the Mozilla Labs booth at the >play conference expo along with my colleagues Atul Varma (who also blogged about it) and Jay Patel.  The event went really well, with a steady stream of visitors to our booth who were curious about Mozilla Labs projects and Mozilla in general.

Profit is not a Four Letter Word Here

I noticed early on that my standard spiel about Mozilla being nonprofit wasn’t having the effect it normally has.  Usually people nod approvingly when I explain that we are a mission-driven organization and community, but this time I was getting blank stares or even slight airs of disapproval.

I suppose that’s because the conference was sponsored by a business school, and its attendees are mostly aspiring businesspeople, so nonprofit endeavors like ours don’t have the same cachet they do amongst the web and open source hackers I usually meet at conferences.

The Pitches & Audience Reactions

Nevertheless, everyone was really friendly and positive about Firefox, and many of them had heard of at least some of the labs projects we were demoing (Weave, Ubiquity, Snowl, and the Concept Series, among others).

Everyone I asked also knew what open source was, and they were overall very positive about our plan to get more designers involved in open source development through the Concept Series.

And the booth duty was great for refining my descriptions of those projects.  There’s nothing like saying the same thing over and over again to separate the essence of the point from the redundant, misunderstood, or just plain unnecessary cruft.  By the middle of the day, my pitches were crisp and tight.

Miscellaneous Firefox Feedback

One visitor told me he switched back to Safari because it lets him email a whole page (not just a link) with one click.

Another attendee asked for a lighter-weight variant of the master password feature that protects Show Passwords in the Saved Passwords dialog but doesn’t prompt you to enter the master password each session, so you can protect your passwords from being retrieved by others without the annoyance of having to enter the master every time you restart your browser.

A third person asked for a way to see only unvisited search results when searching the web, so he can check occasionally to see if there’s new information about a search term without having to scroll through all the stuff he’s already seen.

And a professor suggested we could grow marketshare among students by pitching Firefox as the best browser for the popular iLearn online education software, as she solves many of her students’ problems accessing her online classes by getting them to switch browsers.

 

egg timer for lightning talks

Yesterday, for the Lightning Talks portion of the Mozilla Labs Meetup, I couldn’t find a good online egg timer, so I created a simple one and put it up at eggtimer.org.  Since then I’ve found lightningtimer.net, so I guess it wasn’t necessary, but it’s there now anyway.

 


<jstemplate>
<description>Hello world!</description>
<description>{"Hello world!"}</description>
<description value="{'Hello world!'}"/>
</jstemplate>


<description>Hello world!</description>
<description>Hello world!</description>
<description value="Hello world!">


<description>Good { new Date().getHours() > 11 ? "afternoon" : "morning" }.</description>


<description>Good morning.</description>


<?js for each (let i in [1, 2, 3]) { ?>
<description>There's no place like home.</description>
<?js } ?>


<description>There's no place like home.</description>
<description>There's no place like home.</description>
<description>There's no place like home.</description>


<script type="application/javascript">
let people = [
{ name: "Jim", rank: "celebrated", cerealBrand: "Special K" },
{ name: "Midge", rank: "heard of", cerealBrand: "Trix" },
{ name: "Genie", rank: "unknown", cerealBrand: "Muesli" },
];
</script>

<jstemplate>
<table xmlns="http://www.w3.org/1999/xhtml">
<tr>
<th>Name</th>
<th>Rank</th>
<th>Cereal Brand</th>
</tr>
<?js for each (let person in people) { ?>
<tr>
<td>{person.name}</td>
<td>{person.rank}</td>
<td>{person.cerealBrand}</td>
</tr>
<?js } ?>
</table>
</jstemplate>


<table xmlns="http://www.w3.org/1999/xhtml">
<tr>
<th>Name</th>
<th>Rank</th>
<th>Cereal Brand</th>
</tr>
<tr>
<td>Jim</td>
<td>celebrated</td>
<td>Special K</td>
</tr>
<tr>
<td>Midge</td>
<td>heard of</td>
<td>Trix</td>
</tr>
<tr>
<td>Genie</td>
<td>unknown</td>
<td>Muesli</td>
</tr>
</table>

The code is available. Your thoughts & comparisons to JavaScript Templates, Better JavaScript Templates, JSmarty, seethrough and others are welcome!

 

Second Preview of Snowl 0.2

I’ve just pushed the second preview release of the upcoming Snowl 0.2. It adds a non-columnar option to the river view along with grouping by time period to the river and stream views.

Here’s the stream view grouped by day:


And here’s the period selector in the river view:


The second preview release also includes a number of enhancements from alta88, who has added several layout and header options to the list view along with a bunch of other improvements (like a customizable toolbar button for quickly accessing Snowl features).

Here’s the menu for selecting those layout and header options:

This preview release also includes many bug fixes to improve performance and functionality.

Still to come is a lot of behavior and visual design work, a number of additional bug fixes, and several more features, including Twitter-based message sending.

Get Snowl for Firefox

Get the preview release: Snowl for Firefox.

Warning: this version is a primitive implementation with many bugs, and subsequent versions will include changes that break functionality and delete all your messages, making you start over from scratch.

Get Involved

Let us know what you think by posting in the forum, reporting bugs, or conversing with us in the #labs channel on irc.mozilla.org. Or check out the source and submit your bug fixes and enhancements.

 

Easier Access to Sidebars

Alex Faaborg suggested to me a few weeks ago that there should be an easier way to open and close Snowl‘s stream view sidebar, like a button that toggles it open and closed.

That got me thinking that the same is true for other sidebars, as the View > Sidebar menu seems like a relatively obscure and cumbersome way to access them. My inclination was to place a permanent interface on the left-hand side of the browser window, right where sidebars appear, that would be contextual, discoverable, and easily accessible.

Tabs seemed to fit these requirements and are consistent with Firefox’s “one sidebar open at a time” behavior, so, with some helpful input from Dan Mills on how similar interfaces in other applications have behaved, I cooked up an experimental extension that implements a column of vertical tabs representing sidebars down the left-hand side of the browser window.

Dragging a tab to the right opens the corresponding sidebar, while dragging it back to the left closes it. Dragging also lets you set the sidebar width. Or open a sidebar to its previous width by simply clicking its tab (clicking again toggles it closed).

The extension supports both built-in sidebars (Bookmarks, History) and those provided by extensions, as long as the extensions use the standard machinery for defining their sidebars. And it extends that machinery with support for tab icons: just set the image attribute on your tag to the URL of the icon.

It uses the new -moz-transform CSS property to orient text vertically on the tabs (and a bit of the new drag-drop API to start the drag operation) so it only works on recent nightlies. And it’s a prototype, so there’s still some wonkiness in its appearance and behavior.

Check it out in the AMO sandbox, and let me know what you think. (Also note the All-in-One Sidebar, another take on the same concept.)

 

Stuck on Songbird

I’ve tried the Mozilla-based open-source music player Songbird twice before, and each time I reluctantly retreated to iTunes for a variety of reasons: Songbird wouldn’t play my DRM-encumbered iTunes Store tracks, it was cumbersome to use, it kept crashing or wouldn’t start, etc.

But in August I stripped the DRM from my 50 encumbered songs by burning them to four CDs and then ripping them back.  And then I heard that the latest version of Songbird (0.7) had a redesigned interface.  So I decided to give it another try.  And this time it stuck.

The major reason is the interface redesign, which has simplified the application considerably, making it much easier to navigate.  But it also doesn’t crash much anymore and has started up fine every time.

I’ve been using Songbird almost exclusively for the last few weeks, except when I need to burn a CD (which it still doesn’t do) and during the occasional foray into the iTunes Store to see if it has DRM-free versions of songs I can’t find in the Amazon MP3 Store, like Ministry‘s original recording of Jesus Built My Hotrod or The Damned‘s remake of Jet Boy, Jet Girl (sadly, it usually doesn’t).

I even activated its scrobbler support, and it’s been pushing my listening habits to my public last.fm profile, which feels uncomfortably revealing, although no more so than having dozens of my colleagues following my decidedly non-work-related tweets.

And I’ve tried out its Songkick functionality for automatically finding concert dates for the artists in my library, which feels like a killer feature, since it’s so much easier than searching for concerts manually (or tediously programming Ticketmaster/Live Nation to keep me in the loop).

Finally, I’ve sampled its SHOUTcast internet radio integration, which seems like it could be a great way to get someone else to mix my daily soundtrack for me, except that I haven’t yet put in the effort to find the stations I want to listen to from the overwhelmingly voluminous selection of them.

Overall, I’m pretty happy with Songbird.  Support for burning CDs and better integration with the Amazon MP3 Store are the only major features I’m missing.  The rest is just nits.

(Note: recent versions of Songbird supposedly play DRM-encumbered iTunes Store tracks just fine, although I’m glad to be DRM-free anyway and plan to remain so from now on by not purchasing any more encumbered music.)

 

sharing one Mozilla source tree with Linux/WinXP VMs on Mac host OS

Here’s how I shared one Mozilla source tree on my Mac OS X host OS (one Core 2 Duo, 4GB physical RAM) with two VMware Fusion VMs, one running Ubuntu Linux 8.04 (two CPUs, 1GB RAM), the other running Windows XP (one CPU, 512MB RAM):

I checked out the source tree to ~/Mozilla/source on my Mac’s filesystem.

I configured each VM with one shared folder via Fusion’s Virtual Machine > Shared Folders > Shared Folder Settings… configuration dialog. In both cases, I shared my Mac user account’s home folder (/Users/myk). Fusion 2 named both shares myk (Fusion 1 had named the Windows share myk On My Mac).

I made these shares read/write so I could manipulate the tree from the VMs (particularly from the Linux one, where I do most of my development) and also because the Mozilla build process tries to modify the source tree, even when you’re using an objdir (f.e. bug 384978), and the build process runs smoother if you let it.

On Linux, the shared folder showed up at /mnt/hgfs/myk. Because of a limitation in Fusion (described in the release notes as “Shared Folders permissions might be too restrictive in Linux and Mac OS X Server guests”), I had to configure the /etc/fstab entry for the shared folder to mount with my Linux user account’s uid/gid:

# Beginning of the block added by the VMware software
.host:/ /mnt/hgfs vmhgfs defaults,ttl=5,uid=myk,gid=myk 0 0
# End of the block added by the VMware software

Note: this modification gets reset and has to be redone every time I reinstall VMWare Tools (i.e. after each kernel upgrade).

On Windows, the shared folder showed up at Start > My Network Places > Shared Folders on .host. Fusion 2 automatically created a network drive for the shared folder, mapping it to the uppercase drive letter Z:. When I was using Fusion 1, I manually created the network drive via Tools > Map Network Drive in Windows Explorer.

In older build environments, I then had to create /etc/fstab (following the instructions in /etc/fstab.sample) to mount the network drive, but I think simply mapping the drive automagically makes it available at its lowercase Unixy equivalent (f.e. /z) in the latest versions of MozillaBuild (perhaps after a MozillaBuild or Windows restart?).

I only share my source tree, putting config files in ~/Mozilla/configs and builds in ~/Mozilla/builds on the Mac and Linux filesystems and in /home/myk/Mozilla/(configs|builds) on the Windows filesystem (as my home directory on Windows is /c/Documents and Settings/myk, and Mozilla has trouble building to a directory with spaces in its path).

Once configured as described, building on each OS became the simple matter of crafting the build config file, changing to the source directory, and calling make, for example on Linux (with this config file):

cd /mnt/hgfs/myk/Mozilla/source
time MOZCONFIG=~/Mozilla/configs/minefield-opt make -f client.mk build

On Mac (with this config file):

cd ~/Mozilla/source
time MOZCONFIG=~/Mozilla/configs/minefield-opt make -f client.mk build

And on Windows (with this config file):

cd /z/myk/Mozilla/source
time MOZCONFIG=/home/myk/Mozilla/configs/minefield-opt make -f client.mk build

Note: compiling on Linux seems pretty speedy, but compiling on Windows is dog slow, perhaps even slower in Fusion 2 than in 1. I haven’t tried it lately, but it might be faster to share the tree with Windows using SMB.

Note: it’s theoretically possible to compile on two or all three OSes simultaneously, but it does slow down the machine, and I got build failures the few times I tried it (I don’t remember exactly what now, I think something about the Windows build process being unable to access certain files).