Royal Hall in Mt Lawley may not be the Savoy Ballroom of old, but it was certainly full of Lindy Hoppers tonight. Steph and I went down, paid our $5 and had a bit of a dance. I really enjoy swing dancing. It's nice to have an excuse to go.
![]() | ![]() |


I appear to have misplaced my glasses. I had a pretty bad headache when I got home, so I'm not even sure if I was wearing them when I came in. I've turned the house upside down looking for them, but can't seem to find them. I'm sure that Steph will be able to put her hands on them straight away when she gets home.
I need to have my eyes retested, so I could be attempting to get that done now, but it's raining outside and without glasses I probably shouldn't be driving. Also, I quite like the frames (and they were a little bit expensive, because they're hypoallergenic titanium), I was hoping to be able to reuse them.
I'd never noticed just how wonky the platforms at Perth Station are. The only reason I realised was because the regular Fremantle train had been moved one platform down to make way for the football train, and I had to tie up my shoe.


My Linux desktop machine appears to have done what can only be described as "blowing an O-ring". The machine is really stuffed. Started off behaving funny, yesterday it was freezing some and today it simply doesn't power on. It feels like logic board failure on the most epic level. Annoyingly, I was also halfway through doing my tax.
I needed to get my files off. Unfortunately the disk is SATA (I don't own a SATA caddy), and is formatted with LVM and ext3. I also needed enough disk space to store the contents.
Thankfully Alex had a SATA to USB widget, all I needed was power. I supplied this by cracking open a USB CD burner, which is just a drive in a 5 1/4 inch bay. Then used a SATA/molex power widget. Ok, so I can plug the disk into another computer, I should be there... unfortunately that computer is a Mac.
No worries I think, just use Ubuntu from VMware and forward the USB disk. From there I can probe the LVM, mount my home volume and rsync it back onto the Mac's HDD. Easy!
Just this week the Government released their so called Green Paper, discussing the implementation of a carbon trading system for Australia.
One of the dot points in this system is that petrol would be included from the outset, but as the carbon tax was phased in, the fuel excise would be phased out. Essentially replacing one tax for another, which is how I had anticipated things would happen.
The Greens don't approve. They feel that a carbon tax should be phased in on top of the excise. Otherwise how can we effectively provide a financial motivator for people to reduce their dependence on oil? Where their reasoning appears to fall down however is that they've in effect created an imbalance in the market, in their proposal petrol will always be more expensive than other energy sources, even if it would lead to lower emissions. Possum agrees. The goal is to foster innovation into sustainable power and lower emissions, which I feel is best achieved by levelling the playing field and then cranking up the carbon price. Let the market sort out the details.
That said, some things the Greens are saying make sense. Tax breaks to compensate for carbon costs seems backwards to me too. Why not use the money to pay for a nationwide power efficiency campaign: Efficient Eye for the Wasteful Energy Consumer. Offering rebates for making your home more energy efficient and providing a consulting service to help reduce energy usage. I suspect this will happen, but I'm not sure to what extent.
Some other parts of the plan I'd probably need to be an economist to comment on. Specifically the way permits will be issued for things like the aluminium industry. The point has been made that raising prices too sharply on these companies will simply cause them to move future operations offshore, where they will be able to emit to their heart's content. If this is true or not really depends on the costs to the company, something that I can't immediately model in my head.
So what do you think? Have the brakes and the accelerator been pressed at the same time?
A little bit related to this was something Stephanie told me today. The Water Corporation is observing that people who have installed grey water recycling systems to capture their water for reuse on the garden are now using 20-60% more water than previously. Why? Well, no one is completely sure yet, but it's possible that the idea of recycling the water allows them to appease their middle class guilt. It doesn't matter that the tap is running, I'll be able to put that water on the garden.
(posted on Thursday July 17th, 2008 at 08:02 pm — 15 comments)
The Canonical hackers are common thugs. If I didn't write a pro-Bazaar post, they were sending someone around to my house.



Many GNOME modules are adopting tabs as the new desktop metaphor. I found this interesting, because I'd recently been thinking about how someone would replace the GNOME workspace switcher applet. I have some anecdotal evidence to suggest that many users don't understand what the little grey and blue boxes on their panel are for, so since I'm still stuck in Istanbul, I wrote a quick patch to move the workspace switcher to be on top of the panel.

One thing that Australia has gotten right (and Europe has still not) is banning smoking in enclosed spaces. It's been a long time since I've had to come home from somewhere and wash my hair and change my clothes because I smelt like a cigarette. I always forget just how anti-smoking Australia is (but I really do prefer it that way).
The closing party was good (the boat was better), but the beer cups were only half full.



I have to say, I'm in love with the new Openisimus tee. I think this could possibly become a favourite.
The second core day of GUADEC happened. I haven't come away with many thoughts, except that we need to bring on GTK+ 3.0 as soon as possible (I suspect it's 1.5 years away). Did come away with three O'Reilly books for £50 (for work): C++ in a Nutshell, Getting Started With Intel Thread Building Blocks and The Definitive ANTLR Reference. With that much money I would have only been able to buy one of those books in Australia (they were 40% off).

![]() | ![]() |
Went to hang with the Openisimus guys for dinner last night followed by beers on their terrace. A beautiful view looking over west Istanbul and right next to the Galata Tower.


GUADEC in Istanbul. Baring a few initial problems (transfer to the hotel never arrived, the taxi took me to the wrong hotel and my Visa didn't initally work), things have been pretty awesome so far. In a word, I would describe Istanbul as 'odd'.



This update comes courtesy of free wireless at Changi Airport, where I'm transiting on my way to Istanbul. The wave of humidity as you come off the aircraft at Singapore is always familiar and inviting. The Indian vegetarian restaurants in the terminals make me so happy. I am having a 10pm snack of samosa. Flying always makes me hungry. Mmm, cardamomy.
It is Stephanie's birthday today (meaning I left the country), so last night we went to the Fly By Night club in Fremantle to see Peter Combe. Peter Combe was a seminal part of so many Australian children's formative years. His revival just goes to demonstrate how we're all really still kids at heart.


I am currently writing an ANTLR grammar for parsing a config file, that is full of rules like this:
phaseDefinitionEntry : genericDefinitionEntry | prop=PhaseStringProperty ':' value=STRING -> ^($prop $value) | prop=PhaseDateProperty ':' value=DATE -> ^($prop $value) | cardDefinition ; genericDefinitionEntry : prop=GenericStringProperty ':' value=STRING -> ^($prop $value) | prop=GenericDateProperty ':' value=DATE -> ^($prop $value) ; // all of the not phase properties and the types they take notPhaseDefinitionEntry : prop=NotPhaseStringProperty ':' value=STRING -> ^($prop $value) | prop=NotPhaseBooleanProperty ':' value=BOOLEAN -> ^($prop $value) ;The purpose of these rules is to validate the correct properties are being used in the correct blocks and that those properties are of the correct type. It seems however that I'm duplicating a lot of rules that I really don't want to be duplicating. I feel like I should just be able to have a generic assignment rule that I can pass a list of valid properties and their type to.
Finished off the cupboards this morning. Need to go and get one more door. Having it missing is annoying the pants off me.


One reason, I think, that our townhouse had been on the market for so long, which led to us getting it relatively cheaply was that when people walked in, their first impression was "half a kitchen". My first impression, on the other hand, was "half an Ikea kitchen", knowing full well that the rest of the kitchen was only a day away.
We knew that we had to get it done soon, since by the time I'm back from GUADEC, Dad (and Mum) would be off to Europe themselves, so we went to Ikea today to purchase cabinets. It didn't take long to put them up (especially since Dad has done this before). I just need to put the doors on tomorrow and install some other fittings that we got at the same time. We'll also need to get some lighting for the underside so that we can really light up the workspaces.
Suddenly it feels like a proper kitchen, going from this to this:

For those who haven't been paying much attention, we've moved out of our old flat that we were renting in Crawley into a townhouse in Highgate. Which by my calculation costs us $65/day in interest, or something like that. The ADSL has been reconnected, so rather than interacting with each other, the house is full of the sounds of gentle tapping.
Some amount of stuff has now been unpacked. The bedroom is operational, as is most of the lounge. The kitchen is close (although we're meant to be installing more kitchen cabinets this weekend). The study is currently just a pile of boxes. A lot of that is books and penguins.


After managing to be delayed by two days (apparently ANZ doesn't know how to file paperwork) our new townhouse settled today. We'll have a housewarming once we're actually settled in (which could be a while, since I'll be in Turkey for the 2nd week of July).

There are many times when you are writing a GTK+ application, where you want to display data from a list of objects in a GtkTreeView. At this point, many people will create a GtkListStore and write code to update the list store when the master list is changed. These people will then spend the rest of their time hating themselves and GTK+.
Some people will use the GtkListStore as their list and store their data in it, along with several columns of strings for displaying in the UI. This is marginally better, but eventually this abstraction springs a leak, and many police hours are lost coaxing this person away from the edge of the roof. Those who live and breath object orientation will write their own GtkTreeModel.
People commonly assume however, that writing a GtkTreeModel is hard. There are all of those methods to implement, and it's not clear what they all do or how it all works. What many people don't realise is that there is an easy way and a less-easy way and often the easy way will do. Generally what people want from their model is to be able to store a list of objects and be able to request a number of columns based on those objects. Additionally, they want their model to push updates to any views that might be listening.
So what we want is a list-based tree model. It turns out this is easily done by overloading GtkListStore (or we could use GtkTreeStore).
Overloading GtkListStore/GtkTreeStore
For what we're doing, 99% of the complicated stuff about writing a GtkTreeModel, such as iterating through rows and storing data, is already handled by GtkListStore and GtkTreeStore. In order to make the magic happen all we need to do is wrap the column handling between the underlying store (which has one column) and the presented model (which has any many columns as we like).
To do this we need to overload three methods of the GtkTreeModel interface: get_n_columns(), get_column_type() and get_value().
First, we need to create an object that inherits GtkListStore and implements GtkTreeModel (don't like writing GObjects by hand, try Ross' generator). Since we're implementing an interface, the G_DEFINE_TYPE() macro is expanded to:
G_DEFINE_TYPE_EXTENDED (MyListStore, my_list_store, GTK_TYPE_LIST_STORE, 0,
G_IMPLEMENT_INTERFACE (GTK_TYPE_TREE_MODEL,
my_list_store_tree_model_iface_init));my_list_store_tree_model_iface_init() is the method that is called to hook up the interface method calls. It is called after our parent's method. Thus we can simply hook up the three methods we want to override and leave the rest as the parent set them:/* our parent's model iface */
static GtkTreeModelIface parent_iface = { 0, };
static void
my_list_store_tree_model_iface_init (GtkTreeModelIface *iface)
{
/* this is where we override the interface methods */
/* first make a copy of our parent's interface to call later */
parent_iface = *iface;
/* now put in our own overriding methods */
iface->get_n_columns = my_list_store_get_n_columns;
iface->get_column_type = my_list_store_get_column_type;
iface->get_value = my_list_store_get_value;
}Note that first we made a copy of our parent's interface call table. This is so we can call our parent's interface methods when required.static void
my_list_store_init (MyListStore *self)
{
/* initialise the underlying storage for the GtkListStore */
GType types[] = { MY_TYPE_TEST_OBJECT };
gtk_list_store_set_column_types (GTK_LIST_STORE (self), 1, types);
}Our list store is storing objects of type MyTestObject. We could just as easily store any sort of data that can be represented by GLib (e.g. for structs use G_TYPE_POINTER), but objects are nice because they have reference counting (no need to manage destruction) and signals (so we can find out when they change).static int
my_list_store_get_n_columns (GtkTreeModel *self)
{
/* validate our parameters */
g_return_val_if_fail (MY_IS_LIST_STORE (self), 0);
return N_COLUMNS;
}
static GType
my_list_store_get_column_type (GtkTreeModel *self, int column)
{
GType types[] = {
MY_TYPE_TEST_OBJECT,
G_TYPE_INT,
};
/* validate our parameters */
g_return_val_if_fail (MY_IS_LIST_STORE (self), G_TYPE_INVALID);
g_return_val_if_fail (column >= 0 && column < N_COLUMNS, G_TYPE_INVALID);
return types[column];
}In order to implement get_value() we need a way to access our underlying data storage, but because we've overridden these three methods, it's not as simple as calling gtk_tree_model_get(). This is where saving our parent's interface comes in. We can write a new method to get the object from the underlying data storage:/* retreive an object from our parent's data storage,
* unref the returned object when done */
static MyTestObject *
my_list_store_get_object (MyListStore *self, GtkTreeIter *iter)
{
GValue value = { 0, };
MyTestObject *obj;
/* validate our parameters */
g_return_val_if_fail (MY_IS_LIST_STORE (self), NULL);
g_return_val_if_fail (iter != NULL, NULL);
/* retreive the object using our parent's interface, take our own
* reference to it */
parent_iface.get_value (GTK_TREE_MODEL (self), iter, 0, &value);
obj = MY_TEST_OBJECT (g_value_dup_object (&value));
g_value_unset (&value);
return obj;
}Now we can use this to write the get_value() method. This method uses a GValue to marshal the requested value. First the GValue must be initialised to the required type (use the get_column_type() method you wrote), then we must set the value to contain the desired information (here using the switch statement).static void
my_list_store_get_value (GtkTreeModel *self, GtkTreeIter *iter, int column,
GValue *value)
{
MyTestObject *obj;
/* validate our parameters */
g_return_if_fail (MY_IS_LIST_STORE (self));
g_return_if_fail (iter != NULL);
g_return_if_fail (column >= 0 && column < N_COLUMNS);
g_return_if_fail (value != NULL);
/* get the object from our parent's storage */
obj = my_list_store_get_object (MY_LIST_STORE (self), iter);
/* initialise our GValue to the required type */
g_value_init (value,
my_list_store_get_column_type (GTK_TREE_MODEL (self), column));
switch (column)
{
case OBJECT_COLUMN:
/* the object itself was requested */
g_value_set_object (value, obj);
break;
case ID_COLUMN:
/* the objects id was requested */
g_value_set_int (value, my_test_object_get_id (obj));
break;
default:
g_assert_not_reached ();
}
/* release the reference gained from my_list_store_get_object() */
g_object_unref (obj);
}That's pretty much all there is to it. Change notification is pretty straightforward too, write yourself a new add/append method that hooks up a useful signal/signals (e.g. notify) and have the callback call gtk_tree_model_row_changed(). I'm leaving this as an exercise to the reader.gcc -o test `pkg-config --cflags --libs gtk+-2.0` my-list-store.c my-test-object.c.
Some time ago I asked about how to do drag and drop between two GtkTreeView widgets, but I never posted the followup.
It actually turns out to be really simple when you know how (tm).
The very brief version: your GtkTreeModel needs to implement one or both of the interfaces GtkTreeDragSourceIface and GtkTreeDragDestIface (depending on whether you want it to be able to be a source or a target or both). Each of these interfaces requires you to implement a pair of methods. Specifically drag_data_get and drag_data_delete for the source; and row_drop_possible and drag_data_received for the dest. The parameters and return types for these are documented.
You will then need to mark the treeview as accepting drags/drops/cats:
const GtkTargetEntry targets[] = {
{ "x-target/my-layer", GTK_TARGET_SAME_APP, 0 },
};
gtk_tree_view_enable_model_drag_source (treeview,
GDK_BUTTON1_MASK, targets, 1,
GDK_ACTION_MOVE);
gtk_tree_view_enable_model_drag_dest (treeview, targets, 1,
GDK_ACTION_MOVE);static gboolean
my_layers_model_drag_data_get (GtkTreeDragSource *self, GtkTreePath *path,
GtkSelectionData *selection_data)
{
GtkTreeIter iter;
if (!gtk_tree_model_get_iter (GTK_TREE_MODEL (self), &iter, path))
{
return FALSE;
}
/* check selection_data to see that we have the correct target here */
// layer = ...
/* copy in the layer pointer */
selection_data->length = sizeof (layer);
selection_data->data = malloc (selection_data->length);
memcpy (selection_data->data, &layer, selection_data->length);
return TRUE;
}Although I've not done it, you should be able to easily set up other these/other targets to also allow drag and drop with other widget elements that aren't tree views. Also handle multiple targets, which my example should probably be doing, but isn't.
Apparently it has been reported in the international media that Perth was levelled by a tornado. Some international friends have got in contact to check that we're ok. Unfortunately you're not rid of me that easy. Rockingham, which is 40km south of here, was what was actually hit (not Perth), and some people lost their roofs/washing, but as far as I know no one was killed. I did get very wet walking between the bus stop and my office though.
My aunt, uncle and their family live in Rockingham, but since I've heard nothing, I assume they're fine too.
