Took 4 days off, did some probing into the possibilities of porting away from C# into a language that doesn't have the trap known as OO modeling. I'm still not sure if I will, but here's what I found. Correct me if I'm wrong or you disagree.
OCaml doesn't seem to have Pango text drawing support, so it's either not an option, or I'd have to use something sane instead (how the heck do I get selectable text anyhow?) It's also a pain to compile anything on OCaml, though the compilation finishes fast and the type errors aren't indecipherable. OCaml's also familiar to me.
Haskell has Pango text drawing, though I don't know how I can cache the layouts for reuse. The compilation process is nice, very effortless. But GHC takes a long time to compile anything. Gtk2Hs starts as fast as C GTK2, which is great. I'm divided on the language. On the other hand it's functional and fast, on the other hand I don't know it.
C is fast. C has full library support. C works on everything. C compiles fast. C is familiar. C is so verbose that my hands hurt just from thinking about it. Not the actual code, perhaps, but the error handling. And you get to write your own data structures from scratch. And debug them.
So, why not C#? For starters, Mono takes 200 ms to start up. 200 ms takes an application from "starts instantly" to "starts pretty quickly." And it's away from your application code's init time, so you have to do more performance hacks. The slow startup isn't really that big a gripe though, since I'm planning to have the app always running in the panel.
The other complaint I have is the class library. It's doing a lot of work to do the wrong thing. The System.IO.Path functions throw an exception if they don't like the characters in your path. And everything dealing with files uses the System.IO.Path functions. So if you have, say, non-UTF-8 characters in your path, FileSystemWatcher throws an exception if you try to monitor that (perfectly valid and existing) path. And the type system doesn't notify you of exception-throwing functions, so you only discover the errors at runtime, and only if you test thoroughly at that.
As a language C# is like a Java. It's relatively verbose, but the type system does provide some safety. I don't much care for the way it gives me enough rope to hang myself with crap side-effect-riddled OO modeling. The numeric library is lacking arbitrary precision numbers and the libraries for basic data structures are inconsistent (Hashtable has Contains but Dictionary
The good things about C# are the runtime and that it's very straightforward. The GC is good as far as I know and the threads are Real Operating System Threads. The standard library is extensive and doesn't usually try to be cute (i.e. doubles are doubles, ints are ints, uints are uints, and so on. Strings are a bit special.) And it's very much an Industry Language, with its Industry Features (like the localization stuff in strings and the localized number formatters.)
Conclusion? I think I'll do a quick straight port to Haskell, and, on noticing that it's not that easy, go back to C# and use the frustration to do push-ups. Sounds like a plan!