2009-05-25

Netbeans + OpenJDK = frustration

Although I sometimes claim to try out the various IDEs every few years, what I really mean is that I try out Eclipse every few years. I've only tried Intellij once, recently, and to be honest I think I killed it after a couple of minutes waiting for it to start. I'm pretty sure I never got round to actually doing anything with it.

As for Netbeans, I'm not sure I've even seen it since 1999. Not on my desktop or anyone else's. When I complain of bloated, slow, unresponsive IDEs, I always think of Netbeans. But when I've complained of crashy, bloated, slow, and unresponsive IDEs, well, I'm more likely to have been thinking of Eclipse.

Today I thought I'd fix a few of Sun's simpler Swing bugs in JColorChooser. The kind that have been "fix understood" since 2003 but which shouldn't take more than a few minutes to fix. The aggravating "have the bastards ever tried to actually use this shit?" stuff.

Going to the OpenJDK website, I saw they were advertising Netbeans (currently version 6.5.1) as an easy way to get into OpenJDK development. Fair enough, I thought, I'll give that a go.

The instructions should have warned me off. Don't expect any special OpenJDK-building integration. Netbeans doesn't let you deal with Mercurial forests without manually installing the forest extension; the instructions go straight to downloading a .zip source bundle. Okay. They then go on to explain where to find Netbeans project files to open, but they seem to have moved since the instructions were written. find(1) found them, and I opened the small "swing" project...

My first problem was where Netbeans hung my X11 server. I was selecting text at the time, in the first file I double-clicked on, just to see what the editor was like. Thankfully I was using Linux, so I could switch to a different virtual terminal, log in and kill Netbeans, and then switch back to the virtual terminal with X11.

After restarting Netbeans, I tried to build the "swing" project, but it won't build out of the box (this was OpenJDK 1.7.0-b59). Something to do with Nimbus. (Of course!) So naively I thought I'd open the "world" project and build that. Only Netbeans couldn't really open that project on my puny machine. 4 cores and 4 GiB of RAM just isn't enough, seemingly. I sat waiting for it to finish (because the UI was really unresponsive during its "scanning" process) but it took long enough (using only one core) that the screensaver came on. And, presumably for reasons related to my first problem, I couldn't unlock the screensaver until I switched virtual terminal to kill Netbeans.

Don't get me wrong, I saw hints of interesting features in Netbeans. Its behavior when you return to a file you've edited externally but not in Netbeans, for example, feels better than Evergreen's behavior; Evergreen alerts you to the modification by drawing a watermark behind the content, and requires you to manually "Revert to Saved", showing you a diff when you do so. This is sometimes useful — if you've got a generated file open, for example, it's really nice to be able to keep one golden version while you experiment with the code that generates the file, seeing a diff after each run from the convenience of your editor. But automatically and silently reverting to saved seems a lot more convenient for the more common case where you've simply pull new changes from version control, or you used Vim over SSH on your bus ride home or whatever.

Netbeans was also pretty good-looking for a Swing application, although somewhat uneven; the directory chooser looked like some SwingSet Metal horror that probably hadn't changed since 1999.

And Netbeans' uninstall.sh script (in the directory you installed Netbeans in) seems to work perfectly, too, which was a relief. But overall this was a bad enough experience that I fear it will be 2019 before I give Netbeans another try.

The silly part is that building OpenJDK is pretty quick and easy. (At least compared to fighting Netbeans.) Download and install a source .zip, download and install the remaining binary plug (some SNMP crap), install the things you don't have that the README-builds.html lists, and "make". I also had to install libxtst-dev, which I didn't see mentioned, and I found that the Makefiles don't appear to be "make -j"-safe.

So there's not much difficult about building OpenJDK any more. How about slow?

Even on my too-puny-for-Netbeans 2007-vintage Core 2 Quad with 4 GiB of RAM, a clean build only took about 45 minutes. (With the build seemingly never using more than two cores.)

Despite it being something any monkey could do, if they were of a mind to, it's strangely gratifying to run your own JVM at the end:

$ ./build/linux-amd64/bin/java -version
openjdk version "1.7.0-internal"
OpenJDK Runtime Environment (build 1.7.0-internal-elliotth_2009_05_24_21_45-b00)
OpenJDK 64-Bit Server VM (build 16.0-b03, mixed mode)

If you're wondering why I used a source .zip rather than using Mercurial to check out the forests, it's not that I haven't tried Mercurial a few times. It's just "too hard".

I'll try Mercurial again when I'm running an OS that has a sufficiently up-to-date package. Hopefully one day Sun's choice of Mercurial will look like a wise long-term decision, but it's a bummer that it makes life hard for casuals like me right now. Hopefully, just as building OpenJDK was once "too hard", but is now – once you have the source – perfectly reasonable, we'll be able to say the same about Mercurial.

2009-05-13

Confessions of a Windows hater

I've slightly changed my working environment recently, for the first time in years. Other than adding the System Monitor applet to the panel at the top of my GNOME desktop, I've basically been using the default setup since I switched to GNOME a few years ago.

The default setup has a panel at the top of the screen and another at the bottom. The top panel has a few menus, an icon that gets you a new web browser, a few other icons, a clock, and a weird log out/shut down/reboot button duplicating part of one of the menus. The bottom panel has a button to hide all windows, a big space for buttons representing windows, a little representation of your virtual desktops, and a trash can.

Type "ubuntu" into your favorite image search.

Of these things, the only things I used frequently were the icon that gets me a new web browser and the clock. I used the buttons representing windows too, to some extent, but I didn't really like them and often felt like they were costing me more time than they were saving me. Certainly the experience was nothing like as smooth as Mac OS' dock.

What I didn't know was that the top panel and the bottom panel aren't fundamentally different. They're both the same kind of container, different only in the stuff they happen to have in them. I learned this when I saw someone else's desktop and noticed that they'd moved the buttons representing windows into their top panel, and removed their bottom panel entirely. Even on a 30" display, pixels are valuable, and vertical pixels especially so.

I immediately switched to just one panel. Being a Unix/Mac OS kind of person, I kept the top panel. The bottom panel had always bothered me a bit, possibly because it's so Windows-like, but having tried my single panel in both places, I have to say I much prefer it at the bottom of the screen. I can actually feel myself having to look up when it's at the top. You could argue that's good, because it's not particularly useful, and you may as well have it out of the way, but being a miserable sod, I find that just makes it even more annoying when i do have to use it. I also find it easier to hit the web browser icon when it's at the bottom rather than the top; possibly just because it's easier for my eyes to keep up with my mousing.

What about the sides? Good question. On Mac OS, I've only ever used the dock at the side. Left or right. I don't much care. I love this, because it takes the least space, and that space is horizontal space, which I have more of anyway. It works well on Mac OS because everything in the dock is basically square. Any text only shows when you point, and it shows over the desktop, where there's plenty of space anyway. The other reason it works is that the Mac's dock only has one entry per application, rather than one per window.

If you find the exact right pixel to click (right-click the little grip to the left of the buttons; the nice big space on the right gets you a completely different menu) you can set the "Always group windows" property to get a lame-ass imitation of this. It's okay in terms of saving space, but the behavior shows the usual lack of respect for the user and what they might be trying to do. In particular, you can't easily bring all an application's windows to the front. That's not a big problem for something like a web browser or terminal emulator where an application's various windows aren't closely related other than by parentage, but it's a pain for applications that have a small number of genuinely related windows: you can't conveniently bring "the application" to the front. It's even quite awkward to hide (minimize) all of an application's windows. Certainly nothing approaching the "click to show, command-H to hide" I so miss from Mac OS. What else is wrong? The visual indication of minimized windows could be more distinct (as it is, the title is simply surrounded by square brackets). The title shown in the panel is the application title if you have more than one window, but the window title if you only have one window. I'm sure this was well-intentioned, and it does sound reasonable until you use it, but it just doesn't work if you keep opening and closing windows. The text you're looking for keeps changing, and its position changes too, though I'll admit that I honestly can't work out what the sorting criteria are. Random shuffle? Finally, most difficult to fix, you only get an entry per window. So if you use tabs, you'll only see the title of the currently-visible tab in each window. This really sucks, but even the non-free OSes don't get this right yet.

Even with those reservations, I'm still happier like this. I have enough windows open at any given time that the other style just isn't useful. Fifty little buttons all with nothing more than an icon and "..." may as well not be there at all for all the good it does. (Which strikes me as odd; surely users who don't open many windows don't really need the buttons anyway?)

Just as I thought I was done messing with configuration, I accidentally removed my "Applications", "Places", and "System" menus. Which was 99% fine by me, but I do actually need them once a week or so. So I choose "Add to Panel..." and add "Main Menu" back. Only it turns out that "Main Menu" is just an Ubuntu logo. Clicking on it gets you a single menu that's basically the "Applications" menu with the semi-useful bits of the other menus tacked on the bottom. So there's a few hundred more pixels you can save: remove the menus and add "Main Menu" back for no loss of functionality but plenty more space. (The new menu is nice and easy to hit, too, being right in the corner.)

The one change I made after this was to swap the relative positions of the system monitor and my web browser and terminal emulator icons. I originally had the icons right after the wordy menus, and the system monitor in the wasteland to the right. Even when I switched to one panel at the bottom, I saw no reason to change this. But making the menus really small moved those icons further from the center of the screen where, on average, my mouse pointer is. Swapping the two moves the buttons closer to hand. (Or, if you prefer, brings them within range of a single mouse sweep rather than requiring two, which is far more aggravating than you'd credit.)

Anyway, here are my suggestions again:

1. One panel is enough for the stuff that actually does anything.

2. The bottom of the screen seems to be a better place for this panel than the top.

3. "Always group windows" isn't as stupid as the default behavior.

4. Removing the menus and adding "Main Menu" back looks and feels better.

The only other things I have in my panel are the "lock screen" icon and the date/time/weather thingy. I used to have the "lock screen" icon with the other two, but I found myself sometimes confusing the terminal emulator icon and the lock screen icon, or at least pausing to make sure which one I wanted to press (they're both basically small dark squares representing monitors), which is stupid when one of them I want a hundred times a day and the other maybe twice. (No, I don't lock my machine when I go for a piss. I piss in the corner of the office.) Moving the lock screen icon out next to the clock thingy cured that.

I will admit that, all in all, I've made my desktop look a lot more like Windows than it did. But I'm man enough to admit it's better for it. And I'm grumpy enough to wish I didn't have to waste my declining years pissing about with stuff that shouldn't be getting in my way in the first place.

Maybe next year I'll learn how to use gconftool(1) to stop the window manager from opening every window in the top left corner right on top of the last one, as soon as the screen is too "full" to place the window in completely empty space. (You know, ten seconds after you log in.) Presumably GNOME developers have 15" displays and only open one maximized window at a time, like the Windows users of Windows-haters' myth?

2009-05-07

Playing mp3s from Java

JNI

It's pretty obvious that mp3d needs to be able to actually play mp3s. This was another reason why I initially chose C++, my assumption being that there would be plenty of C++ mp3-playing libraries to choose from.

In a way, there were. But, perhaps because audio code isn't very portable and perhaps because Linux's audio API is abandoned for something new every six months or so, the libraries I came across were mainly focused on decoding mp3 data in some raw form. Presumably if I'd looked hard enough I'd have found the other pieces of the puzzle and been able to put them together, but after a brief search I gave up and started looking at command-line tools instead.

Spawning subprocesses

This is how the first version worked. If all you want to do is play an mp3 from start to finish and have no real control over – or feedback about – what's going on, this is a really easy option. But I was surprised by the strange programmatic interfaces offered. mplayer(1) seemed the best overall, and does indeed have a mode where it expects to communicate via a pipe, but the command set available seemed to assume a greater autonomy for mplayer than I was looking for. I wanted to keep the "playlist" in my server, for example, and basically use mplayer as my low-level API. It wasn't clear that I could really do that, and the various bits of calling code I could find on the web didn't suggest otherwise.

When I used mplayer from Java, I actually used Unix signals to control it, but I soon decided I wanted more control, and didn't particularly want to be tied to running on Linux (even though personally I'm unlikely to ever run mp3d anywhere else).

javax.sound

You might think that Java would have built-in support for the most popular audio format, but it doesn't. Presumably licensing problems. I hope this will be fixed by OpenJDK, at least for Linux, where it seems possible that whatever Free library they use for audio will have out of the box support for mp3 (and ogg and all kinds of other thus-far neglected formats).

Sun's bug database considers JMF (remember that?) to be the answer.

JavaZOOM JLayer

Despite the awful name (though I of all people should be careful about throwing stones where naming is concerned) JavaZOOM's JLayer is "the" Java library for decoding/playing mp3s. There may be others, but this is the one that everyone seems to use, so it was the one I went for too.

The API is a bit odd. Some of the names suggest no native speakers of English were involved. You stop a Player by calling "close", for example.

The API is also rather limited. If seems like more of a demo for the underlying mp3 decoder than an real API anyone's actually expected to use. If all you want to do is play an mp3 from start to finish, without pause or fast-forward (though you can stop prematurely), you're fine. Anything else and you'll be using the low-level API to shuffle frames from the decoder to the audio device.

Even the trivial case isn't well documented, so here's the minimal sample:

  String filename = "muzak.mp3";
  AudioDevice audioDevice = FactoryRegistry.systemRegistry().createAudioDevice();
  Player player = new Player(new FileInputStream(filename), audioDevice);
  player.play();

The call to "play" will block until the mp3's finished playing, but you can call "close" in another thread if you want.

(I'd have sent in patches, but the project doesn't have any visible source repository and appears pretty dormant.)

This is actually pretty much the code I'm using in mp3 at the moment. I keep expecting to want more, but I'm not yet convinced. I will admit to having used SIGSTOP and SIGCONT from a shell on a couple of occasions, but "pause" doesn't make as much sense as you might think on the web. Maybe if I bound my "media keys" on all my machines to POST appropriate form data I'd be more convinced. That would actually be pretty cool.

Without moving to something distinctly more AJAXy, though, I'm not sure "pause" fits the UI. And you probably would have to present it for the benefit of other users.