After an evaluation, GNOME has moved from Bugzilla to GitLab. Learn more about GitLab.
No new issues can be reported in GNOME Bugzilla anymore.
To report an issue in a GNOME project, go to GNOME GitLab.
Do not go to GNOME Gitlab for: Bluefish, Doxygen, GnuCash, GStreamer, java-gnome, LDTP, NetworkManager, Tomboy.
Bug 102547 - Revise theme format
Revise theme format
Product: metacity
Classification: Other
Component: themes
Other other
: High normal
: ---
Assigned To: Thomas Thurman
Metacity maintainers list
Depends on: 86040 96229 99680 102548 105188 107012 113162 113163 113465 114304 114305 121603 121639 121866 122065 123162 129747 129766 151261 151262 308180 321278 331356
Reported: 2003-01-05 04:27 UTC by Havoc Pennington
Modified: 2006-10-07 17:04 UTC
See Also:
GNOME target: ---
GNOME version: ---

proposed patch (6.38 KB, patch)
2004-01-05 21:29 UTC, Sebastien Delestaing
needs-work Details | Review
updated patch (6.40 KB, patch)
2004-01-06 21:15 UTC, Sebastien Delestaing
needs-work Details | Review
Rewritten patch to work against current CVS and taking suggestions into account (6.31 KB, patch)
2006-03-24 01:44 UTC, Thomas Thurman
none Details | Review
As before, with some extra commenting and documentation (7.89 KB, patch)
2006-03-25 00:12 UTC, Thomas Thurman
committed Details | Review
metacity-theme-2: first pass (101.01 KB, patch)
2006-06-28 02:35 UTC, Thomas Thurman
none Details | Review
metacity-theme-2: first pass: changelog (5.41 KB, text/plain)
2006-06-28 02:35 UTC, Thomas Thurman
metacity-theme-2 version of Bright (3.12 KB, application/x-gzip)
2006-06-28 02:37 UTC, Thomas Thurman
metacity-theme-2 version of Crux (20.21 KB, application/x-gzip)
2006-06-28 02:38 UTC, Thomas Thurman
Changes to documentation (4.30 KB, patch)
2006-06-29 00:51 UTC, Thomas Thurman
none Details | Review
Another try at the metacity-theme-2 patch (104.62 KB, patch)
2006-08-17 01:58 UTC, Thomas Thurman
needs-work Details | Review
State of the union (104.10 KB, patch)
2006-10-07 04:00 UTC, Thomas Thurman
committed Details | Review

Description Havoc Pennington 2003-01-05 04:27:12 UTC
Incompatible theme format changes need to be made all at once, 
and then the "metacity-theme-1" file will be renamed to 
"metacity-theme-2" allowing themes to ship both theme-1 and theme-2 files, 
to work with multiple metacity versions.

This is a tracking bug with all bugs that involve theme format changes 
as dependencies.
Comment 1 Havoc Pennington 2004-01-04 21:45:57 UTC
To implement the versioned theme file, some general ideas:

1. in meta_theme_load(), first try the newer theme filename, then try 
   each older theme version filename. 

2. depending on which file we load, set info.format_version = 2 or 
   info.format_version = 1 or whatever

3. for each modification to the theme format, we need to conditionally 
   do the right thing. If something was an error in version 1, it 
   must remain an error when loaded from a file with version 1.

So for example, when changing line width from a simple integer to an
  if (info.format_version > 1)
    /* handle it as an expression */ ;
    /* validate with parse_positive_integer that it is not 
       an expression, then convert to an expression */ ;

4. for each change to the format, we should make a note in
doc/theme-format.txt along with the theme format version 
where the change was made.
Comment 2 Sebastien Delestaing 2004-01-05 21:29:32 UTC
Created attachment 22963 [details] [review]
proposed patch
Comment 3 Rob Adams 2004-01-05 22:44:18 UTC
Rather than multiple files I would suggest that we simply add a
theme_version="..." attribute to the metacity_theme tag.  If the
attribute is missing we assume that it's a version 1 theme.  We then
further specify that metacity should try to load the oldest version
newer than or equal to the current theme version, and ignore anything
that it doesn't understand in the theme file.  Theme authors could
then specify multiple metacity_theme blocks in the XML file with
different versions should they so desire.

This may not work though, since I'm not sure if metacity would
currently barf it if saw an attribute that it doesn't know about or
what it would do if it saw multiple metacity_theme blocks.  I suspect
that it would work and just use the first metacity_theme tag though.
Comment 4 Havoc Pennington 2004-01-06 00:30:41 UTC
Remember that we can't change already-released metacity versions,
themes have to work with old metacity without changing old metacity.

One point is that the multiple files thing seems simple for theme
authors to understand.
Comment 5 Rob Adams 2004-01-06 00:38:24 UTC
that's why I said it might not work -- the question is really how
metacity currently deals with slightly invalid theme format files.
Comment 6 Sebastien Delestaing 2004-01-06 09:14:50 UTC
Frankly, the code sort of implied it was a done deal and I didn't
question Havoc's design :-)
Now that I think of it I can see a number of reasons to have separate

- It's faster. You don't have to open the file to know which versions
of the theme it contains.
- It's simpler. You can have tricky failsafe, like all the way down
from broken user theme v2 to a system theme v1. I realize you can do
that too with one file but imagine the code... Here you have it for free.
- It's consistent wih gtk1/2 scheme.
- If you break the xml formatting by editing the theme file or the
file gets corrupted, you don't break all versions at once.
- and last but not least it's not the same as gtk1 vs. gtk2. It's not
like you want to support older versions forever. Upgrading will be a
no-brainer and I know that as a theme author I will probably not even
provide a v1 file for new themes.

Hope that convinced you :-)
Comment 7 Sebastien Delestaing 2004-01-06 21:13:58 UTC
there are 2 bugs in this patch, one of them a crasher.
updated patch follow.
Comment 8 Sebastien Delestaing 2004-01-06 21:15:39 UTC
Created attachment 23030 [details] [review]
updated patch
Comment 9 Sebastien Delestaing 2004-01-06 22:10:55 UTC
#121603 should be added as a dependency
Comment 10 Sebastien Delestaing 2004-01-24 20:55:30 UTC
Sorry to "ping" you like that but can you please make a call on this
patch ?
Can I continue to work in this direction ?
I have pending updates (namely a "get_theme_version" function, needed
for #86040 and probably all the other dependencies down there).
Comment 11 Rob Adams 2004-01-25 02:13:57 UTC
We're feature-frozen for Gnome 2.6, so it'll have to wait until Gnome
2.8, but I don't think that there's any obstacle to this going in.
Comment 12 Havoc Pennington 2004-01-25 05:53:33 UTC
I do need to review this patch before it goes in, I certainly hope to
be able to do so before GNOME 2.8.

If you want to keep your work in CVS it's totally OK to create a
branch called something like metacity-theme-changes-branch and work
there; to create a branch typically you would first make a tag:
then use cvs rtag to create a branch based on that tag. You can then
recover your entire patch by diffing the branch vs. the tag. See cvs
manual for details.

Of course this is only worthwhile if you're doing a fairly large set
of changes.

In any case, continue to ping us periodically, and I'll also go
through bugs with PATCH keyword. I hope to be back hacking on metacity
more regularly pretty soon.
Comment 13 Havoc Pennington 2004-08-28 03:00:56 UTC
I think it would be nice to target fixing some of the dependencies of this bug
for 2.10. I don't think it's realistic to fix all the dependencies at once, but
we should try to do more than one of them to make bumping the theme format
version worthwhile.

Also, we should add a section to "theme-format.txt" that's "new in theme format
version 2"
Comment 14 Havoc Pennington 2004-08-28 03:07:04 UTC
Comment on attachment 23030 [details] [review]
updated patch

I just looked at this bug again and was reminded of this patch. Some comments.

- no real point using "char" for format_version, due to alignment it will use
up 32 bits anyhow. int is better.

- The current format does
I think the "-1" in the directory name was a mistake, and will end up never
changing. So we shold try versions by scanning for metacity-theme-2,
metacity-theme-1 all under metacity-1.

- if (text == NULL) at top of a for loop that has text == NULL as condition,
redundant I think

- this patch will read a 
file with a new version number, so we can't add it until we have code to parse
the new file format.
Comment 15 Havoc Pennington 2005-01-17 16:49:57 UTC
bug #151261 has a patch showing how to get basic infrastructure for a new format
version in place, though I don't know if we should apply that until we have a
batch of format changes ready.
Comment 16 Rob Adams 2005-05-26 20:18:09 UTC
updating per comments
Comment 17 Elijah Newren 2005-10-07 16:08:23 UTC
Remove old target milestones on old bugs; sorry for the spam.
Comment 18 Thomas Thurman 2006-02-16 20:17:54 UTC
So before any changes to the theme format get checked in, we need to create a branch in CVS they should live in? And then eventually we merge them back to the main branch.
Comment 19 Havoc Pennington 2006-02-17 16:54:55 UTC
That's one approach, but I wouldn't do a CVS branch unless someone was actively planning to go through some of these theme format bugs and work on them, then do the new format version in the next release. If the theme format will only be versioned at some vague time in the future, it's probably easier to just keep the patches in bugzilla.
Comment 20 Thomas Thurman 2006-03-24 01:44:29 UTC
Created attachment 61879 [details] [review]
Rewritten patch to work against current CVS and taking suggestions into account

Attachment 23030 [details] had gone stale by now; I've rewritten it to work cleanly against current CVS. I also took Havoc's suggestions into account.

> this patch will read a 
> file with a new version number, so we can't add it until we have code to parse
> the new file format.

I think we should add this file in HEAD now, before we add the code to parse the new file format. After all, any such code would need to rely on the value of the format_version field, which is added by this patch. And I suppose it's not really such a problem if the format's not well defined for a few weeks: it's not like people are going to be distributing version 2 themes until we make a release which supports them.

Perhaps we could write


so it wouldn't even be possible to use version 2 files unless we deliberately asked for it during development.
Comment 21 Thomas Thurman 2006-03-24 01:48:02 UTC
(Whether we do or not, I'd like to go through a bunch of theme v2 bugs and work on them for the next release.)
Comment 22 Havoc Pennington 2006-03-24 02:55:46 UTC
It looks like I'd elaborated on this patch a bit in the patch on #151261, some of the ideas in there look worthwhile, at least I think the documentation in that other patch is important. (Modified to match whatever the final patch is, of course.) theme-format.txt definitely needs to explain the deal here, and comments in the code need to make very clear the guidelines in comment #1
(again, modified to match the actual patch, obviously)

Comment 23 Thomas Thurman 2006-03-25 00:12:32 UTC
Created attachment 61954 [details] [review]
As before, with some extra commenting and documentation

Okay, I've added a section like that to the theme documentation, and an explanatory comment block to explain what's going on in the code. The section in the documentation doesn't mention what's new in version 2 yet, but we can fill in that section as we go clearing up the other metacity-theme-2 bugs.
Comment 24 Havoc Pennington 2006-04-13 04:29:19 UTC
Suggest establishing a convention for theme version tests, since you may test the same thing in multiple places. i.e. say you add alpha blending, I think in my other patch I had:
 if (theme->version_features & ALPHA_BLENDING)
or something like that. A simpler/better approach might be:
and then use "if (theme->version >= META_THEME_VERSION_WITH_ALPHA_BLENDING)"
around the code that parses this.

Anyway, no need to add that to this patch (the patch looks OK) but something to copy from the other patch is to think through a way to handle this. The multi-version handling will never get tested so the only hope is to be disciplined about docs and conditionalization when adding each new feature to the format.
Comment 25 Thomas Thurman 2006-04-20 20:16:40 UTC
That sounds a good idea.

I want to put in a bunch of work on getting metacity-theme-2 ready. Should I branch in CVS, or shall I just work in HEAD?
Comment 26 Elijah Newren 2006-04-20 23:23:43 UTC
I'd suggest the branch approach; I used it for doing the constraints rewrite last fall.  It allowed me to try out lots of crazy stuff and not have to wait for review, until I had finally gotten everything working.  And it let me make totally destabilizing changes, though I don't know if that's as applicable for you or not.  One more good reason may be that I personally don't care much for theme stuff (and thus don't know much about it), while Havoc has an awful lot of things on his plate these days, so you probably don't want to wait for lots of intermediate reviews.  ;-)
Comment 27 Thomas Thurman 2006-04-22 01:47:01 UTC
Okay, branched with name metacity-theme-2, and this patch checked into the branch. This should be fun!
Comment 28 Thomas Thurman 2006-06-27 02:38:42 UTC
It certainly was!

I believe I have implemented everything necessary now. How should I proceed? Shall I produce an enormous diff between HEAD and metacity-theme-2, attach it to this bug, and ask whether anyone can comment on it?
Comment 29 Rob Adams 2006-06-27 02:53:04 UTC
you'll want to produce a diff between metacity-theme-2 and the start of metacity-theme-2, and then try to apply that diff to head.  It'll probably take some conjoling.  At that point, you'll have a patch against HEAD.

If you diff it between head and metacity-theme-2, then you'd revert all the changes in head that aren't on your branch.  This is the sort of thing that's a lot easier with subversion, but oh well.
Comment 30 Thomas Thurman 2006-06-27 02:56:42 UTC
Thank you.  Well, I hear we're due for subversion soon.

So when I have this patch-against-HEAD, I should post it here and ask for someone to approve or not with all the changes? It'll be pretty huge.
Comment 31 Björn Lindqvist 2006-06-27 06:46:53 UTC
Do you have a design document or something for all changes? Especially something that describes how the new theme format should be parsed would be good.
Comment 32 Thomas Thurman 2006-06-27 12:22:54 UTC
I'll post it with the diff.
Comment 33 Thomas Thurman 2006-06-28 02:35:19 UTC
Created attachment 68095 [details] [review]
metacity-theme-2: first pass

Here's the diff against HEAD...
Comment 34 Thomas Thurman 2006-06-28 02:35:54 UTC
Created attachment 68096 [details]
metacity-theme-2: first pass: changelog

...and the changelog...
Comment 35 Thomas Thurman 2006-06-28 02:37:19 UTC
Created attachment 68097 [details]
metacity-theme-2 version of Bright

I haven't yet produced formal documentation of the element-by-element changes to the XML; I hope to have this finished by tomorrow. Meanwhile, here is a working version of the Bright theme...
Comment 36 Thomas Thurman 2006-06-28 02:38:01 UTC
Created attachment 68098 [details]
metacity-theme-2 version of Crux

...and here's a metacity-theme-2 version of the Crux theme.
Comment 37 Havoc Pennington 2006-06-28 04:04:08 UTC
I was afraid this huge patch would be scarier - it looks manageable, barely. ;-)
On a quick scan-through nothing looks egregiously wrong to me.

Docs in the theme format file would be pretty helpful for reviewing it, and of course to anyone trying to make a multiversion theme.

Comment 38 Thomas Thurman 2006-06-29 00:51:35 UTC
Created attachment 68139 [details] [review]
Changes to documentation

Here's a new section to theme-format.txt, partly based on text Havoc wrote ages ago, explaining in detail all the changes to the XML format.
Comment 39 Elijah Newren 2006-08-07 22:37:43 UTC
Sorry for having been slow to help with the review; since it's after feature freeze, we won't be able to get this in until after 2.16.  But let's make sure to get it in right after 2.16.0.  :)

A couple weeks ago, I started a patch review ignoring the fact that I don't know how themes work at all and just concentrating on the parts I did know.  I haven't yet gotten back to it, but let me at least just cut and paste the comments I wrote down at the time (in strict order going through your patch) so I don't lose them.  Overall it looked okay, I mostly just have nitpicks.

starting in frames.c:

+#include "window.h"

As per the technical gotchas in the HACKING file, this cannot be
included here.

-  if (!(fgeom.top_left_corner_rounded ||
-        fgeom.top_right_corner_rounded ||
-        fgeom.bottom_left_corner_rounded ||
-        fgeom.bottom_right_corner_rounded ||
+  if (!(fgeom.top_left_corner_rounded_radius!=0 ||
+        fgeom.top_right_corner_rounded_radius!=0 ||
+        fgeom.bottom_left_corner_rounded_radius!=0 ||
+        fgeom.bottom_right_corner_rounded_radius!=0 ||

spacing missing here.

-      xrect.y = 3;
-      xrect.width = 1;
-      xrect.height = 2;
-      XUnionRectWithRegion (&xrect, corners_xregion, corners_xregion);
+      for (i=0; i<radius; i++)
+        {
+          const int width = 1 + (radius - sqrt(radius*radius - (radius-i)*(radius-i)));

shouldn't this be round(sqrt(...))?  Otherwise, it's not going to be
clear what the code is doing to those who can't remember how C
implicitly converts floats to ints.  Same thing goes for other 3 cases.

+      tiptext = _("Stick Window On All Workspaces");
+      break;

Not a correct explanation of the feature anymore (created nasty corner
case bugs that would have needed an EWMH change of dubious real value
to fix things to really work that way).  Note that the right click
window menu refers to this as "Always on Visible Workspace"

+          if (point_in_control (frames, frame,
+                                META_FRAME_CONTROL_ABOVE,
+                                event->x, event->y))
+            meta_window_make_above (meta_display_lookup_x_window (

meta_window_make_above() should not be called here (part of that
gotcha where window.h can't be included; you have to make another pair
of functions in core.[ch] which forwards the call to window.c like
other function calls in the surrounding code here)

+            meta_window_unmake_above (meta_display_lookup_x_window (

Same here.

-  meta_verbose ("Updating prelit control from %u to %u\n",
-                frame->prelit_control, control);

What's wrong with this debugging message?

-  /* South resize always has priority over north resize,
+   /* South resize always has priority over north resize,
    * in case of overlap.

The old spacing was correct, not the new one.  ;)

--- src/iconcache.c	20 Jan 2006 22:03:55 -0000	1.8
+++ src/iconcache.c	28 Jun 2006 02:14:35 -0000
@@ -23,6 +23,8 @@
 #include "iconcache.h"
 #include "ui.h"
 #include "errors.h"
+#include "theme.h"
+#include "window.h"

Given that theme.h includes some gtk/gdk headers, iconcache.c should
not include both it and window.h.

+      if (theme->fallback_icon==NULL || theme->fallback_mini_icon==NULL)
+        {
+          get_fallback_icons (screen,
+                              iconp,
+                              ideal_width,
+                              ideal_height,
+                              mini_iconp,
+                              ideal_mini_width,
+                              ideal_mini_height);
+        }
+      if (theme->fallback_icon!=NULL) *iconp = theme->fallback_icon;
+      if (theme->fallback_mini_icon!=NULL) *mini_iconp = theme->fallback_mini_icon;

Style issues: spaces needed around '==' and '!=', then clause on
separate line from if.

+  for (displays = meta_displays_list (); displays != NULL; displays = displays->next) {
+    for (windows = meta_display_list_windows (displays->data); windows != NULL; windows = windows->next) {

Would be nice to split these long lines.  Also, braces should be on
separate line and indented over from other code (a similar braces problem was
also found in lines following this snippet).

   long l;
+  int j;
+      l = j;

Seems odd to have l and j have different types.  Is there a reason for this?


spacing between META_THEME_ALLOWS and the opening parenthesis.  ;-)

-      if (strchr (value, '.'))
+      if (strchr(value, '.') && parse_double (value, &dval, context, error))

spacing between function name and opening parenthesis.  ;-)

+          info->style->window_background_color = meta_color_spec_new_from_string(background, error);

Again.  ;-)

+               if (!success) return;

if & then clauses should be on separate lines.
Comment 40 Thomas Thurman 2006-08-17 01:58:11 UTC
Created attachment 71068 [details] [review]
Another try at the metacity-theme-2 patch

Thanks. Here's another try, addressing the issues you found. Sorry it took so long-- I had to hunt down another bug in it.
Comment 41 Elijah Newren 2006-09-20 17:35:41 UTC
I've started looking at the patches; doing a bit each day.  I'll try to finish up in a week or so and hopefully we can get the patches in soon.

Since I don't know a thing about how the theme code works, though, it'd be great if Havoc could look over it too.
Comment 42 Elijah Newren 2006-09-23 17:58:28 UTC
Comment on attachment 71068 [details] [review]
Another try at the metacity-theme-2 patch

I didn't check theme/theme-parser to closely since I'm not familiar with those parts of the code, but overall the patch looks pretty good to me.  I couldn't find too many issues, just a couple comments:

>+meta_invalidate_default_icons (void)
>+  GSList *displays, *windows;
>+  for (displays = meta_displays_list ();
>+      displays != NULL;
>+      displays = displays->next)

unimportant nitpick: poor alignment here; I'd prefer the 'displays' to line up (much how if's & else if's are handled throughout the code).  Same thing in a few other places...

>+          const int width = 1 + (radius - rint(sqrt(radius*radius - (radius-i)*(radius-i))));

I was unfamiliar with rint(), so I looked it up.  I saw a bunch of stuff about implementationally dependent being either being like floor() or ceil() or even rounding to the nearest even integer, but didn't see anything about rounding to the nearest integer.  Do we really want this instead of e.g. round()?

>@@ -1563,6 +1576,60 @@ meta_frames_button_release_event    (Gtk
>           meta_core_end_grab_op (gdk_display, event->time);
>           break;
>+          if (control == META_FRAME_CONTROL_SHADE)
>+            meta_core_shade (gdk_display, frame->xwindow);
>+          redraw_control (frames, frame, META_FRAME_CONTROL_SHADE);

If redraw_control() is called here, shouldn't this be META_FRAME_CONTROL_UNSHADE?  However, I don't think redraw_control() should be needed here since it isn't used for example with maximize/unmaximize (note that the reason it isn't needed there is because of another difference in get_control() which I'll cover later).  Same thing goes for ABOVE/UNABOVE and STICK/UNSTICK in this same area of the patch.

>-  meta_verbose ("Updating prelit control from %u to %u\n",
>-                frame->prelit_control, control);

What do you have against this debugging message?  ;-)

>@@ -2332,6 +2521,36 @@ get_control (MetaFrames *frames,
>     }
>+  if (POINT_IN_RECT (x, y, fgeom.shade_rect.clickable))
>+    {
>+    }
>+  if (POINT_IN_RECT (x, y, fgeom.unshade_rect.clickable))
>+    {
>+    }

This isn't consistent with how MAXIMIZE/UNMAXIMIZE is done; I'd prefer this were changed so that the code in meta_frames_button_release_event() can also be made consistent with MAXIMIZE/UNMAXIMIZE.  Same thing goes for the ABOVE/UNABOVE and STICK/UNSTICK parts of this area of the patch.
Comment 43 Thomas Thurman 2006-09-26 01:21:25 UTC
Elijah: Before this patch, we've only had one button which toggled,
i.e. maximise/restore. To metacity, these appear to be the same button,
and the only reason that they show up with different images is that
every <frame_style_set> in the theme defines every <frame> twice:
once for non-maximised (with the image on the button being the ordinary
maximise image) and once for maximised (with the image being the
restore image). I didn't implement the three new toggle buttons the
same way, because even if doing two copies of everything isn't an
unreasonable burden on theme authors, writing out each different
<frame> 2**4==16 times with every possible combination of the buttons
might be. So instead I defined the toggle buttons as pairs of
independent buttons which just happen never to be seen at the same time.
Comment 44 Elijah Newren 2006-09-26 01:41:13 UTC
(In reply to comment #43)
> Elijah: Before this patch, we've only had one button which toggled...
> So instead I defined the toggle buttons as pairs of
> independent buttons which just happen never to be seen at the same time.

So, does that imply that fgeom.shade_rect.clickable == fgeom.unshade_rect.clickable, always?  If so, I don't see how get_control() could ever return META_FRAME_CONTROL_UNSHADE.  If not, I'm a bit confused by what those rects do contain.

Also, I don't see the need for redraw_control() in meta_frames_button_release_event() at all now.
Comment 45 Thomas Thurman 2006-09-26 02:05:23 UTC
Yes, it does imply that, and you're right about get_control-- that was a thinko on my part.

I seem to remember adding the calls to redraw_control() to force the button to be redrawn so you could see the toggled state, but I don't remember now: it was a while ago. I'll experiment with and without.
Comment 46 Thomas Thurman 2006-10-07 02:12:25 UTC
Okay, three results of my experimentation:

1) I used rint() because round() is C99. Someone suggested floor() instead, which is a very good idea.

2) Actually fgeom.shade_rect.clickable gets reset (to some sort of "n/a" value, I'm not sure what) when the shade button isn't visible, and so get_control does need to be able to return META_FRAME_CONTROL_UNSHADE and kin. If you disable this, the button becomes unclickable when it's turned to "unshade".

3) I have tried with and without redraw_control() and it makes no difference. It doesn't solve the problem I was trying to address, which is that if you click the button and don't move the mouse at all, the image doesn't update until you do move it (but the action gets carried out). This problem does still exist, but it's probably trivial enough we can address it separately.
Comment 47 Thomas Thurman 2006-10-07 04:00:38 UTC
Created attachment 74189 [details] [review]
State of the union

Here's the current state of play as it exists on my hard disk. Is this good to go?
Comment 48 Elijah Newren 2006-10-07 06:22:34 UTC
Go go go!  Let's watch them theme bugs drop like flies!!!

Thanks for all your awesome work.
Comment 49 Thomas Thurman 2006-10-07 17:04:45 UTC
Hurrah! Thank you!

All checked in!