Eight is Special
Update: A quick grep through the gaim sources for the current CVS head shows that gaim_add_eight()
isn't actually used anywhere in the code (anymore, at least). Ah well.
Xfmedia Refactoring
I've finally started my huge Xfmedia refactoring project. The idea is to make it a lot more maintainable and modularised. I've been doing this in tiny pieces for many months now (XfmediaPlaylist, XfmediaVideoWindow), but I can't really go any further without ripping huge pieces of the codebase apart and stitching them back together the way I want everything to be. I realise it's been a couple months since I released 0.9.1, but it'll likely be a couple more months (at best) before 0.10.0. I think 0.9.1 is fairly stable and featureful. Unfortunately, 0.10.0 probably won't have many user-visible changes, but I expect the plugin interface will finally be stable, or at least in a state where I can promise backward-compatibility for future releases.
Anyway, here's an initial sketch of how my current thinking looks with regard to object structure:
XfmediaApplication: This is more of a meta-object, but it'll keep track of "global" data and handle starting up the app, as well as tearing it down. I haven't decided yet, but it eventually may make sense to allow XfmediaApplication to instantiate multiple xfmedia main windows in the same process, so you can have multiple copies of xfmedia running in the same process space. I'm not really sure what this means for plugin interaction yet, so this may never become a reality. I doubt 0.10.0 will have this ability, but maybe in a future version.
I'm a bit less certain about how the next two objects fit.
XfmediaPlayer will be a very thin layer on top of XfmediaXine. It will know how to play streams and handle usual playback operations, as well as interact with the GUI.
XfmediaMainWindow is a GtkWindow representing the controls/playlist window. It'll act as a container for the XfmediaPlaylist, and hold the time label, song/status label, and control buttons and slider.
I'm not sure if XfmediaPlayer should be the container for XfmediaMainWindow, or the reverse. On one hand, it makes sense for the window to contain the player, but I think I'd rather have the player as the super-object, which will hold the main window, and know that it should do some UI-related things when playback events occur. E.g., if a stream is started from the stop state, the play button in the UI should change to a pause button. There doesn't seem to be a great way to handle this case with the reverse relationship.
So I guess the object relationships should go like this:
XfmediaApplication
XfmediaPlayer
XfmediaXine XfmediaMainWindow
- XfmediaInfobar
- XfmediaPlaylist
- XfmediaPlaylistQueue
XfmediaVideoWindow
XfmediaTrayIcon (?)
There will be only one XfmediaApplication per process, and this can be considered as a pseudo-global. The various XfmediaPlugin objects (one per plugin) will live as sort of a peer to XfmediaPlayer, and can (obviously) control playback, and probably modify or interact with some parts of the UI. I'll have to be careful to compartmentalise this properly, as I'm sure there are parts of the UI plugins shouldn't be allowed to touch. Fortunately, the XfmediaPlugin object shouldn't have to change, aside from adding new object signals.
There are a few other things that are just floating around.
There's the settings system, which isn't an object at all: just a set of global functions that act on a global settings store. That's definitely a problem if I want multiple xfmedia instances in a single process, since, e.g., you might not want a systray icon for each instance, or you might not want each instance to be sticky on all workspaces. This is going to be a bit of a pain, because all the xfmedia_settings_get_*() calls have only one argument for convenience. Also, when xfmedia exits, which instance gets to write out the settings file? Only the first one? This sounds a bit messy. But supporting multiple settings files for each instance is pretty messy too.
The remote control interface isn't an object either, but it's probably ok (almost) as-is, since it knows how to operate on a specific "session" of xfmedia.
Next we have the keybindings system, which probably needs to be mostly redone. Fortunately it currently acts on a specific XfmediaMainwin instance (which will become XfmediaMainWindow), so it should be relatively easy to modify it to operate on an XfmediaPlayer, and thus be multi-instance-safe. However, all the keybindings are stored in the same file, so I'm not sure it's useful to have separate keybindings for each instance. Also, I'd rather use a standard GTK mechanism for doing keybindings, so I'll probably rethink this at some point (GtkAction?).
The mediamarks editor and menu are keyed to a particular mainwin instance, but, again, I'm not sure it makes sense to make this per-instance. There's only one mediamarks file, supporting more than one in a "smart" manner is pretty difficult, and if you look at them like bookmarks, a web browser doesn't have different bookmarks per window.
The tray icon is something I'm not sure about yet. Having multiple tray icons for each instance sounds a bit silly. I'm thinking about the possibility of a single tray icon being able to control all the instances of xfmedia in the same process. The problem with this approach kinda defeats the purpose of the tray icon: to offer a few simple features of xfmedia just a couple quick mouse clicks away. Increasing the complexity of the tray icon directly contradicts this. At some point I might move the tray icon into a plugin.
Next there's playlist-files.h, which is mainly a set of utility functions for reading and saving various playlist types. It mostly operates on a XfmediaPlaylist instance right now, which I think is fine. The playlist files don't need to know about the player engine at all; they just need to know the contents of the playlist (or just how to load stuff into it).
The "jump to file" box is a bit awkward right now. Originally it was a separate window, but now it's integrated into the XfmediaPlaylist widget. So it's in a separate file, somewhat kludged into playlist.c. This needs to be integrated properly (though it really does work fine as-is) for maintenance's sake.
The last piece is the equaliser window, which I never finished because xine handles EQ in a rather weird way, and I never figured it out well enough to make it work right. I might come back to this at some point, in which case it'll just be a child of XfmediaPlayer, and nobody else needs to know a thing about it, except perhaps how to show and hide it.
A final question is what to do about XfmediaXine: should plugins be able to interact with it directly. I'm thinking no. This allows me to support other playback engines in the future (which probably won't happen, but it's not wise to close the door on the possibility), and helps make sure I've abstracted player details into XfmediaPlayer properly.
So I guess that's about it. Comments? Questions? Not saying I'll listen, but I'm curious to know what people think...
Television
I just watched 5 solid hours of television.
I haven’t watched “real” television since May 7th 1989.
Status
I just quit my job. Whether or not I’ll wind up with a new job in the technology sector remains up in the air. I would prefer not, but it just pays better than any other job you can get with a high school diploma.
That said, I’m hoping to free up some energy for programming efforts I actually like. The problem with working a job in a field that you consider your hobby, is it saps your energy to pursue your real life, and to pursue your hobby as a hobby. Perhaps now Mousepad will get back into shape.
I have a roadmap of sorts for Mousepad. My goal is to get the Mousepad rewrite up to the functionality of the last release. The only real difference should be that Mousepad will be more maintainable than the old Leafpad mess, and potentially faster. This should only take a day or three, should I find the time. This will become the 0.3.0 release. The 0.3.0 “series” (har har) will be the last of “classic” Mousepad.
The goal for the 0.3.0 series is to have a text editor that opens fast, provides no real frills, and has no dependencies outside of those provided by or required for the current stable version of Xfce.
0.3.1 – recent file support. I have a half finished little lib that handles the spec, which I will likely polish off.
0.3.2 – session support. If 4.4 is out, we can just depend on libexo outright, if not, we’ll probably want have a little “miniexo” inside the Mousepad tree.
At this point, I’d like to begin taking Mousepad in a somewhat more feature heavy direction. That may upset some people, who are just looking for a Notepad clone. These people may fork with my blessing. They can move to requiring libexo for session support, using the recent file support that will appear in Gtk+ 2.10, and maybe even using D-bus to keep all Mousepad windows shoehorned in the same process. Up to them. I need a little more from my text editor than that.
The new goal of Mousepad is to be a fast and slim general purpose text editor, much in the vein of BBedit (the classic Macintosh editor) and Nedit (the greatest editor ever that doesn’t use Gtk). Tentatively this is the direction at that point.
0.4.x – Syntax highlighting (with GtkSourceView, or possibly Scintilla)
0.5.x – Tabs.
0.6.0 – Miscellania – templates, open as copy, revert to saved, yadda yadda. The tiny little time savers release.
0.7.0 – Scripts. Little snippets of code in any language which can either process the whole document, or just a selection.
0.8.0+ – The future! GtkSpell, maybe? Toolbar perhaps? A real plugin system? A function browser?
Syntax highlighting and tabs are no brainers as features, and will likely be simple to implement. After that, I’ll need a little input from users, so all of this is subject to change.
A real concern I have is that by adding features I lose what makes Mousepad appealing now (speed, simplicity) while not bringing enough to the table to be useful relative to older text editors (Vi, Emacs, Nedit, or my console editor of choice, Joe), thus bringing the Gedit hell to Xfce. I think I can walk that line. We’ll just have to wait and see.
Gaim Not so Fun
A while back, I was interested in hacking on Gaim. I didn't end up doing all that much: I resurrected one of the plugins from the dead, and messed around a bit, but other things (like saving myself from almost failing out of college) got in the way. The one thing I remember is that I never really liked hanging out in #gaim on Freenode. Some of the developers and "crazy patch writers", were, in my limited experience, arrogant assholes (not saying that I don't get that way sometimes, but this was chronic). At the time I was somewhat new to the OSS scene: I had been using OSS for a few years, but I hadn't really gotten too involved in the development side of things, so I didn't think too much of it: maybe that's just how things were "supposed" to be.
And so I stopped hanging out in #gaim. Time passed, and I found an awesome community of OSS developers who were welcoming and friendly, and just thrilled to have extra help. More time passed, and, though I rarely thought about it, I still had a pretty dim view of the Gaim developers.
Today I head over to Planet GNOME, and stumble upon this, and also this. And suddenly I feel validated. It's really sad: Gaim is a very high-profile OSS project, and it's a shame to see that the people behind it can't handle playing nice with each other. And now, with Sean Egan (Gaim lead developer) hired by Google, it seems like Google pretty much owns Gaim. I can certainly understand the lure of a good job with a company like Google, but it looks like a pretty crappy situation.
Ah well. The OSS world tends to route around stupidities. If enough people think Gaim needs to fork, it'll happen. If enough people think we need a new, better-designed IM client, it'll happen. If the current situation works itself out positively, all the better. Only time will tell.
Tablettage
So I finally ordered my Nokia 770 Internet Tablet, with the sweet developer discount. I was a bit afraid I'd been left out when I saw a bunch of other people ordering and receiving theirs. I guess they were just giving out the coupon codes in batches or something.
Anyway, it looks like a really cool device, and I'm looking forward to hacking on it. I was poking around the API documentation for the platform, and it seems like there's a lot to mess around with. The little guy has quite a bit of potential. I've been looking for the chance to cut my teeth on programming for an embedded device, and this looks like the perfect opportunity.
Annoyingly, the only shipping methods were fedex 2nd day, and overnight, and the 2nd day is $15. Lame. And of course that means it'll arrive nice and quickly... and then sit at my rental office for 5 days until I get back from Germany. Figures.
Wizards
Hmm, according to this, I'm a "wizard" at programming. Somehow methinks this dude overestimates the skill required to work with multithreaded apps. I think I'm pretty damned good, but I don't think I'd call myself a wizard. (Not to mention that that'd be pretty presumptuous.)
I also disagree with several of the statements in those slides as to why events are easier to handle than threads. For starters, I'll say that I do agree that locking isn't easy. In more complex cases, it's easy to forget a lock somewhere and get corrupted data, or to mis-design a situation where you can get deadlocks.
However, the statement "with threads, even the simplest application faces the full complexity" is a bit disingenuous. There are several tools available for communication between threads (such as locking queues) that allow a programmer to avoid nasty locking situations. Are they suitable for all situations? No, of course not. But sometimes, with a simpler multithreaded application, you can get away with ignoring mutexes, semaphores, condition variables, etc., depending on how the application works with its data -- or rather, how the application needs to share its data between different threads. Sometimes all that is necessary is to have a single data structure that holds "aggregate" data provided by multiple threads, and in that case all you need is a single mutex to protect that data structure. Sure, there are more complicated examples, but that's just my point: there are varying levels of complexity in multithreaded applications.
I'm also not seeing how the event-driven model is all that easy. It usually requires thinking about your program flow in a completely different manner than if you're using threads. Event-driven apps require asynchronous callbacks, and often a complicated state machine.
A great example of this stems from my work on my mail watcher plugin for the Xfce panel. The original mail checker had a terrible flaw: all network I/O was done synchronously, so any network delays would cause the whole panel to become unresponsive. I considered both solutions to this problem:
Using an event-driven model, single-threaded, with non-blocking network sockets
Using a multithreaded design, one thread per connection, with blocking sockets
Ultimately, I chose the second option. This way, I could have this program flow on checking for new messages:
Convert the server's hostname into an IP address.
Connect to the server.
Do the initial handshaking with the server and authenticate.
Check for new messages.
Log off from the server and disconnect.
With a multithreaded system, I could do all of these in succession, without worrying about blocking. Either each step could complete in the blink of an eye, or it could take 30 seconds for each step. It doesn't matter.
With an event driven system, I'd have to have a state machine with a state for every single time I try to receive data from the network. That means one state each for steps #1 and #2, two to four states for #3, one or two states for each message folder in #4, and at least once state for #5.
I suppose that isn't so terrible, but consider that because of how the C library works, there's no way to make #1 non-blocking. Also, for secure SSL connections, I would probably have to use a more complex interface into the security library I was using to avoid blocking within the library.
So eventually I decided to use threads. In the end, I had a couple small locking problems, which were immediately apparent and not difficult to fix. I don't recall encountering any deadlock situations.
I guess it just really depends on how your mind works best...
Sony is LAME
Apparently, the Go.exe binary that comes with the same discs infected with the Sony rootkit is statically linked to LAME, and thus a GPL violation.
Wow. Sony – You’ve made my day.