crowley code!

Posts tagged “mozilla”

2/25 Firefox 3 — more better (9)

firefox, mozilla

  1. Go to about:config.
  2. Set browser.urlbar.matchOnlyTyped to true.
  3. Profit!

This will cause Firefox to almost revert its address-bar behavior to the familiar Firefox 2 style where it matches the beginning of URLs instead of attempting some hairbrained search. If I’d wanted to search, I would have hit Apple+K.

2/11 More GReader hacking — immersion (2)

delicious, firefox, google, greasemonkey, mozilla

First, some updates to readelicious.  I worked in Mike Malone’s patch to add a keyboard shortcut which I now can’t live without.  I also reworked some bits of it to interact nicely with the new script.

Immersion is another Greasemonkey script that will load the current entry as an <iframe> within Google Reader.  I made this one almost exclusively to look at A Brief Message but it works just as well for leaving a quick comment since it doesn’t interrupt your train of thought like opening a new tab does (I tend to forget new tabs until hours later).

Just like readelicious, immersion adds a link to each entry but also uses ‘i’ for keyboard access to the current entry.

http://svn.rcrowley.org/svn/greasemonkey/immersion.user.js or http://userscripts.org/scripts/show/22685

2/8 readelicious — hacking del.icio.us directly into Google Reader (8)

delicious, firefox, google, greasemonkey, javascript, mozilla

It’s just too many clicks to leave the ol’ feed reader to see an article and save it to del.icio.us. I’m not into that kind of commitment. I am, however, into Greasemonkey so I headed to userscripts.org and discovered two fairly poor attempts to do what I wanted. The first one just took me to the del.icio.us/post page which is a different kind of bad solution. The second one displayed a nice box in the page for editing the info before saving away to del.icio.us but it appeared halfway off of my screen and I didn’t have the patience to figure out why. Here are those two:

Mine has many virtues. First off it actually works and on any browser window size larger than 422 pixels. Secondly it is visually a bit more disruptive than the small Google-styled “window” that one displays but not so obnoxious as to take you off the page entirely. And finally, it automatically pulls the title, link and selected text from the article. Fully featured! As a bonus you get the timeless, classic and beautiful feel of my favorite color, #eee.

Because of the way del.icio.us’ API works, it’ll ask you for your username and password the first time through but after that should behave nicely.

http://svn.rcrowley.org/svn/greasemonkey/readelicious.user.js or http://userscripts.org/scripts/show/22494

1/22 Please don’t X-UA-Compatible me like that (6)

browsers, firefox, html, ie, microsoft, mozilla

The echosphere is making quite a stink about Microsoft’s proposed X-UA-Compatible header to explicitly match HTML pages to rendering engines. There are two possible outcomes, assuming Microsoft goes ahead and implements this HTTP disaster. More likely is that we will be roughly where we are now, with special cases to make IE do what we want and other browsers just working reasonably correctly by themselves. Less likely is that the Redmond dream will be realized and every browser will become a time capsule of rendering engines ready to happily consume whatever 1997 garbage you can throw at it. Oh yeah, if you add the header to all of those ancient pages.

For maximum effect, X-UA-Compatible requires the support of the other browser vendors, otherwise it is just another Microsoft hack with a pretty mask on (read: no regular expressions). (Aside: The ideal solution to problems like the old broken box model would have been to fix it immediately instead of six years later. I can’t help but think that X-UA-Compatible would never have been proposed had that bug not persisted for so long.) In this best-case scenario the cynic in me still sees ignorant developers either omitting this header or setting it only for IE, leaving other browsers to do … something. If the header is set for all of the major vendors (and we’ll just assume that those major vendors will still be the only major vendors down the road) then I must admit, browser bloat is the biggest concern we have. I for one don’t want my Firefox to get any bigger. Just imagine the new and exciting memory leaks!

In the (I think) more likely case of Microsoft pushing ahead with this feature alone then developers have the slight advantage of being able to code to one version of IE instead of several, in addition to Firefox/Webkit/Opera. This may prove to be useful in fixing those sites that IE7 broke. But seriously, why haven’t those already been fixed?

Ultimately, it all comes down to what browsers do if that header isn’t sent or they aren’t paying attention to it at all. It sounds like Microsoft is content to leave everything its IE7 state forever unless told otherwise but I doubt anyone else will be keene on the idea. Microsoft is a much bigger fan of backwards-compatibility than Apple (think Classic Mode) or Mozilla (each new version of Firefox breaks all of my extensions) so I expect to see these others defaulting to their cutting-edge browser unless told to retard themselves. This most-important point of the whole feature is summed up best by Jeremy Keith, “Unless you explicitly declare that you want IE8 to behave as IE8, it will behave as IE7.” I’m a desktop software developer by day and wish I could say to Windows, “Make this app work just like an out-of-the-box Windows XP installation.” I can’t because having such a ridiculous level of backwards-compatibility ultimately makes software too big and unwieldy — it hurts you in the long run. I hope, when framed in the desktop version that the insanity here shows through.

My final thought on the matter is that the best thing Microsoft can do for the future is to push IE7 out to everyone. Like pulling off band-aids, it’s best to do these things fast and deal with the consequences all together. Fixing the IE box model should not take seven years. Get it over with and move forward without the hacks.

Elsewhere:

12/13 Launching a localized XULRunner app (0)

L10n, flickr, mozilla, xulrunner

The average XULRunner developer gets to choose at the beginning of any project whether to work with the 1.8 or 1.9 series. 1.8 gets you stability and heartache; 1.9 gets you trunk-y goodness and a sweet thread library. I’m of course simplifying things.

Until yesterday the prospect of localizing XULRunner itself had not even crossed my mind. An error to be sure but one that was actually easily corrected. We at Flickr chose to work with the 1.9 branch to take advantage of the newly enjoyable thread library. Working with these nightly builds was great as I was able to watch bugs die each time I pulled a new nightly.

The trouble began when I started putting together final builds yesterday. Things like the Mozilla upgrade system, file picker dialog and standard OK/Cancel buttons were not localized because nightly builds come only in English. Bummer. LXR came to my rescue, though. I was able to pull together my own localizations of XULRunner by scraping pieces from the Firefox 2 codebase.

I am not sure what the lesson here is but with ample planning and testing, apps built on XULRunner trunk can be localized just like any other. It would be awesome if, in the future, trunk builds included the entire localization tree, which would allow my build process to just pick out the appropriate JAR file for each language (which is essentially what I do now). Look to the Flickr Uploadr source (more on that soon) for an example of how all this works.

12/1 Fun with Unicode! (7)

c, javascript, mozilla, xulrunner

Why can’t XULRunner do this already?

Without really saying what “this” is, Mozilla wants XULRunner to be the standard play for cross-platform GUI applications and yet it has a bit of trouble interacting with 3rd party libraries. Most mature libraries (say, GraphicsMagick) still use char * or std::string to represent file paths. To interact with them, then, you have to be able to get to a char * representation of files you’re trying to open.

Windows and Mac character encodings 101

As is becoming tradition, Windows makes my life difficult by using UTF-16 as its Unicode of choice. UTF-16 uses 2 bytes (usually) to represent each character, meaning it isn’t binary compatible with ASCII, which uses 1 byte per character. These 2-byte characters are stored in wchar_ts which are twice as wide as chars. It isn’t possible to pass a wchar_t * through normal C libraries that expect strings as char *.

Mac OS X uses UTF-8 internally and is my hero. UTF-8 is used internally to represent strings and has the advantage of using single bytes (that’s char for C programmers playing along) as its base unit. While a single character in UTF-8 can span up to 8 bytes, the in-memory representation of these characters will pass muster with a C compiler. When the UTF-8 bytes are passed through some C library they can arrive intact to the fopen system call, which understands the UTF-8 bytes and acts like you’d expect.

There’s an easy way?

There could be. Using the @mozilla.org/file/local;1 it might be possible to get the path as an nsACString, Mozilla’s portable representation of single-byte ASCII strings. But, the reference warns that the native path available from nsILocalFile is not for passing to C libraries and isn’t guaranteed to be correct. So it’s up to me.

No pain, no gain

Bear with me, this gets ugly. The solution that lets me take paths from JavaScript-land to C-land, open Unicode paths with a normal char * and do so on Windows and Mac OS X is stupefying (and stupid). The iinitial path is stored as a JavaScript string, so the boundary between JavaScript and C will be an nsAString, which represents strings as UTF-16.

The string takes quite a journey here, so let’s cover the easy side first. Macs understand UTF-8, and I’m making a transformation to UTF-8 in JavaScript. This means that the only transform needed in C is a type change, not an encoding change. The UTF-8 string enters C-land as wide characters and is simply cast character-by-character down to an array of bytes.

Windows is quite a bit more work, since a path in Windows that needs Unicode characters can’t easily be represented as a char *. Enter the Windows API function GetShortPathName. This can convert any path to an old-school Windows path that fits in ASCII and uses that familiar “8.3″ naming convention. I got the Mac half working first, so the Windows implementation is actually more complicated than it needs to be — more on that later. Without further ado:

string * conv_path(const nsAString & fake) {

	// Fun with Windows paths
#ifdef XP_WIN

	// UTF-16 but really UTF-8 nsAString to really UTF-8 nsCString
	nsCString utf8 = NS_LossyConvertUTF16toASCII(fake);

	// UTF-8 nsCString to UTF-16 nsEmbedString
	nsEmbedString & utf16 = NS_ConvertUTF8toUTF16(utf8);

	// UTF-16 nsEmbedString to wchar_t[]
	wchar_t * w_arr = new wchar_t[utf16.Length() + 1];
	if (0 == w_arr) return 0;
	wchar_t * w_arr_p = w_arr;
	PRUnichar * w_start = (PRUnichar *)utf16.BeginReading();
	const PRUnichar * w_end = (PRUnichar *)utf16.EndReading();
	while (w_start != w_end) {
		*w_arr_p++ = (wchar_t)*w_start++;
	}
	*w_arr_p = 0;

	// GetShortPathName to get guaranteed ASCII
	wchar_t s_arr[4096];
	if (0 == GetShortPathNameW(w_arr, s_arr, 4096)) {
		delete [] w_arr;
		return 0;
	}
	delete [] w_arr;

	// wchar_t[] to ASCII nsEmbedString
	nsEmbedString ascii;
	wchar_t * s_arr_p = s_arr;
	while (*s_arr_p) {
		ascii.Append((char)*s_arr_p++);
	}

	// Macs don’t need any help since they understand UTF-8
#else
	nsEmbedString ascii;
	ascii.Assign(fake);
#endif

	// Convert the nsEmbedString into a std::string
	char * c_arr = c_arr = new char[ascii.Length() + 1];
	if (0 == c_arr) return 0;
	char * c_arr_p = c_arr;
	PRUnichar * c_start = (PRUnichar *)ascii.BeginReading();
	const PRUnichar * c_end = (PRUnichar *)ascii.EndReading();
	while (c_start != c_end) {
		*c_arr_p++ = (char)*c_start++;
	}
	*c_arr_p = 0;
	string * str = new string(c_arr);
	delete [] c_arr;
	return str;

}

This works simply because, on either platform, the result is a char * that actually uniquely represents the desired file.

My code sucks, let me count the ways

There are of course things that could be better. First of all, after reading the code again (I wrote it Thursday and haven’t looked back), I see that I should refactor a bit. By leaving the string in UTF-16 representation for passing to C-land, I can add a transform from UTF-16 to UTF-8 to the Mac version and greatly simplify the Windows version. I’ll put that on my to-do list. The other place I hope to improve is in the event that GetShortPathName fails. In this case, copying the file under a new ASCII filename to a temporary directory (found using GetTempPath) would still let the file be accessed with a char * path.

Why did I have to do this?

It would be sweeeeeet if Mozilla integrated this code (after a healthy dose of optimization) into the toolkit as something like NS_ConvertToNativePath(nsAString) or some such function. Having this will make integrating with third-party libraries much easier.