Seen while washing dishes

Ice on a puddle? No, it’s salt crystals I found this morning in the bottom of my sphaghetti pot. A little bit of salty water had dried up leaving these crystals behind. There’s several interesting things about the image to me: it demonstrates very well the idea of domains – crystals started at various nucleation points and grew out and met each other. It’s also interesting to see different growth behaviors in different parts of the pot, probably depending on drying rate and salt concentration. In some areas you have long linear crystals; in other areas the growth is more compact. Most of the crystals branch at 90 degree angles, but a few grow in a more spidery pattern. (Somewhat reminiscent of patterns you get in diffusion limited aggregation simulations.)

GUADEC registration fee

First let me say that I don’t think anyone is entirely happy with the registration fee situation. Obviously the fact that payment is only by paypal is far from ideal. I’m not completely in agreement with where the registration levels were set. The website is confusing. But it’s not an attempt to rip people off or discourage people from coming.

Let me explain the levels in a little more detail: there are three levels:

  • Professional: 225EUR (+ 16% VAT == 261EUR). This rate is for attending GUADEC as part of their job function.
  • Professional contributor: 150EUR (+ 16% VAT == 175EUR). This rate is a discount offered to professionals (people attending GUADEC as part of their job function) in various classes of people who contribute to GUADEC and GNOME: speakers, foundation members, employees of advisory board companies, and members of ‘bwcon’ (a local technological organization which is helping put on GUADEC.)
  • Student/hobbyist: 30EUR (+ 16% VAT = 35EUR). This level is for people attending GUADEC for reasons unrelated to their job.

We’re not going to investigate who registers as a hobbyist. We want all members of the GNOME community at GUADEC, so if paying the the professional fee poses a problem for you in any way (moral, financial, typographic), please register as a hobbyist.

So, why charge registration fees at all? The basic reason is that plane tickets are expensive. While our sponsors largely cover costs like the the venue, if we take in more money, we can bring in more GNOME hackers from around the world. I think it’s very reasonable to ask people for who are coming to GUADEC as part of their job to help bring to GUADEC those GNOME contributors that don’t have a company to sponsor them.

Cooking

My cousin Alice from Germany has been staying me this week and exploring Boston, and we’ve done quite a bit of cooking in the evenings.

On Saturday we cooked Indian: a dish of tomatoes and masoor daal (based on a recipe titled rasam, but it didn’t come out remotely like that, though it was tasty enough), potatos and eggplant with fenugreek seeds, and rice with fresh fenugreek leaves.

Monday, I made one of my favorite dishes … a Southeast Asian (quasi-Vietnamese) chicken soup with rice noodles. It’s all about the garnishes: we had bean sprouts, fresh mint and coriander, sliced chiles, lime wedges, and ginger paste.

Tuesday, we made a dish that Alice learned from her brother: rigatoni with winter squash. You basically cook the squash until it is soft, mash it with parmesan and black pepper, and then mix in the cooked pasta. Very good and not at all something that I’d normally make myself. We made it with buttercup squash which gave the whole dish a slightly flourescent yellowish-green color. Apparently it is even better when made with pumpkin.

On Wednesday we cooked cod with the remaining fresh fenugreek, together with couscous with dried cranberries (something that I picked up from Rosanna and Jonathan recently), and a relish of apple, minced serrano peppers, mint, and lemon juice. A real treat and less than a half hour of total preparation and cooking time.

Tonight we took leftover mashed squash from the pasta, and combined it with leftover chicken stock from the soup on Monday night, cooked it for a while with some pieces of star anise, then pureed it, and added a bit of cream. Voila, winter squash soup. We had that with good bread from Whole Foods and a cheese and bean sprout omelet.

All in all, it’s been a fun and tasty week.

Pagers in Luminocity

I’ve been spending some time again this week on Luminocity; mostly redoing the texture handling code. With the rewrite, it can break windows larger than the max allowed texture size into multiple tiles, and I’ve also added mipmap support. After getting the mipmaps working, I quickly hacked up live thumbnailing pagers:

From a code perspective, that screenshot doesn’t have 4 pagers. It’s 5 pagers, one of which happens to be full screen. The effect is similar to what Enlightenment and the GNOME pager had several years ago, but the larger size, higher quality scaling, and immediate updates makes it feel a lot nicer. That’s a lot of screen real estate to take up on the screen, of course; expanding the pager on mouseover might work nicely.

Rotated text in GTK+ and GDK

Many years ago, when Microsoft first added TrueType support to Windows, I remember being very impressed by a demo where a text string was rotated and drawn in different colors. Simple stuff, really, but something that we’ve never been able to do in GTK+ because of the limitations of the ancient X drawing API. (Crude support was added for rotated glyphs for core X fonts eventually, but who wants rotated, non-antialiased text? Can you imagine anything more ugly?) A lot of the pieces have been falling into place over the last few years: GTK+-2.4 required Xft and no longer support core X fonts. Pango-1.6 added PangoMatrix and implemented rotated rendering for the FT2 backend. Over the summer, I added PangoRenderer to Pango, which abstracts out all the positioning, attribute parsing, and so forth in rendering a PangoLayout, making adding rotated rendering for additional backends a lot easier. What was left was writing a PangoRenderer for GDK and some API to rotate GtkLabel. I finally got around to that this week.

I’ve always been just a little confused by transformations when drawing; if I want cairo_rectangle (cr, 0, 0, 1, 1) to drawn a 50 by 50 square at 100 by 100, is that?

cairo_translate (cr, 100, 100);
cairo_scale (cr, 50, 50);

Or is it?

 cairo_scale (cr, 50, 50); cairo_translate (cr, 100, 100);

When I added PangoMatrix to Pango, I decided I was fed up by continually having to try everything both ways, sat down, worked through various examples, and really got it straight in my head. And because of that, I got all the transformations used in the rotated text example above right the first time. A new experience. So, what’s the secret? What helps me is to keep two distinct but equivalent formulations in mind. (I’m talking in terms of Cairo here, but Cairo, Java2D, gnome-print, Postscript, etc all borrowed Postscript’s conventions, so they are the same.) The first formulation defines how the matrices work.

The current transformation matrix gives the transformation from user coordinates (the ones you pass to drawing functions) to device coordinates (the ones that determine what pixels are drawn). Mathematically:

p_device = M * p_user

When you call a Cairo transformation function, that gets added on the user coordinate side. Mathematically:

p_device = M_orig * M_new * p_user

So, say we call cairo_translate (cr, 100, 100) then cairo_scale (cr, 50, 50). We get a transformation that first scales by 50 times in each direction, then translates by 100, 100. That formulation is good to have available, especially if you need to handle the matrices directly (as when implementing bits of Pango or Cairo.) And you can use to check to see which order of the two I quoted is right by taking the point 1,1 and putting it through the two transformations. But it’s not entirely intuitive: you have to think about the transformations in the reverse order they appear in the code. For, writing code what I find easier is:

When you call a Cairo transformation function, that scales/ rotates/translates the axes of the user space coordinate system with respect to themselves.

With that formulation, in mind, it’s easier to see that the order we need is the first one. cairo_translate (cr, 100, 100) shifts the coordinate origin to 100, 100. cairo_scale (cr, 50, 50); then scales up the coordinate axes by 50 times in each direction, leaving the coordinate origin in the same place. (This all would be clearer with a diagram…)

Now if I only could shake the feeling that by writing this I’m courting a collision with a graphics system that uses the opposite convention…