stompin' at the savoy

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.

stompin' at the savoysteph at the hop

Some of the people at these things are amazingly good. Like outstandingly, amazingly good. I can only assume that people who want to dance with them have to write their names on a list. Many of the moves I've learnt and promptly forgotten, some of them are so far beyond my level. Personally I'm always surprised when I'm approached to see if I want to dance. I assume it's a sympathy thing.

these shoes were made for dancin'

As well as dancing, I took the camera (obviously). Someone asked if I worked as a professional photographer? Clearly I had too much equipment. I think I took 150-odd shots (and typically have only kept about 18). I spent a set of batteries in the flash gun. When I ejected them out they were hot to touch, much like I imagine the spent casings in a revolver. No wonder they call it a flash gun.

All 18 Photos (posted on Sunday July 27th, 2008 at 01:01 am — 3 comments)

ch-ch-ch-choices

crystal penguin

Every day we make choices. Often they are made without a moment's thought.
Sometimes those choices shape our lives, even if only for a few years.

You just hope you make the right ones.
(posted on Wednesday July 23rd, 2008 at 06:24 pm — 5 comments)

MY NAME IS POKEY THE PENGUIN. I LIKE TO READ BOOKS. EVERY MORNING, I PRACTICE KUNG FU!

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.

do you suppose these platforms were once straight?
do you suppose this platform was built straight?

There was a food fair on the Fremantle Esplanade for Burma relief last Sunday. We went for lunch before going to see Batman. It was being run by the Buddhist societies, so most things were vegetarian. The non-vegetarians were all off in one corner. Stephanie has a proper writeup.

wokmancer
wokmancer

Been relearning C++ and having a look at gtkmm. Both C++ and gtkmm have aspects that I like (strongly typed properties and signals, pretty neat — though I wish C++ had these as high level objects, I suppose this is where Vala comes in) and having the STL is pretty neat (related: why doesn't GLib give the complexity of functions for its data structures like the STL does?), but there remains things about C++ that just annoy me... why aren't methods just in the class block? Why is calling other constructors from your own so naff? Why isn't the 'virtual' keyword inferred?

One of these days maybe someone will create my ideal language. It will have Java's syntax, garbage collection, Haskell-style strong typing, Python's standard library, signals as first-class ideas and C# style property accessors. It will compile to native code, and be faster than everything else. Source files will have the extension .awesome!

Update: so I found my glasses, they were on the end of the bed between the sheets. I must have taken then off when I got changed after getting home last night, and then made the bed over them. Thankfully, titanium is both strong and flexible, so they've survived unharmed. (posted on Wednesday July 23rd, 2008 at 12:52 pm — 18 comments)

the mother of all jury rigs

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!


yes, it's plugged in via the keyboard

I feel like there should be awards for hacks like this. (posted on Sunday July 20th, 2008 at 01:54 am — 8 comments)

have the Greens got it wrong?

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)

bzr

The Canonical hackers are common thugs. If I didn't write a pro-Bazaar post, they were sending someone around to my house.

world's oldest shopping mall?

So as research, I went to several bazaars. It's almost surreal, you can really buy anything you need. Besides the clearly tourist oriented sections, there were places selling plants, open hessian bags of pet food (in the same way you might sell grains), plants, leaches (!), hardware, ammonium nitrate, spices, clothes and kitchenware.

You could smell the spice markets before you reached them. The spices were so fresh and fragrant, I wish it was possible to bring some back (Australia has pretty strict biosecurity). I think the spice vendors were a little sick of people taking photographs and not buying spices though.

spices

Everywhere throughout the markets there were water sellers. Mostly children with prams and wheeled carts filled with water bottles. But there was one man who was taking a more traditional approach. Dressed in traditional garb, with a large silver cistern on his back with a tab over his shoulder and a pouch full of cups.

Somehow my suitcase is much fuller and heavier than when I arrived (I didn't even buy very much). GUADEC has been a lot of fun this year, but I'm pretty exhausted and worn out. I'm looking forward to getting home.

exploding pigeons
(posted on Sunday July 13th, 2008 at 10:33 am — 2 comments)

GNOME 3.0 panel

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.


This requires compositing to get the nice curved edges on the tabs. I couldn't be bothered making it use XSHAPE. (posted on Saturday July 12th, 2008 at 10:11 pm — 24 comments)

dial excitement to 11

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.

rocking out at Club GNOME

Since the party was in Taksim, we figured we'd try and find one of the restaurants listed on HappyCow that were in the area. Murray had a desire for felafel, so we went to Felafel House. It was pretty tasty, but I'm not sure if Murray's Germans really knew what they were ordering.

who loves beer?
who loves beer? luis loves beer!

It's good to see that bikeshedding and small-picture thinking is alive and well in the GNOME community. This was highlighted through Federico's keynote. Federico offered a very interesting big picture view of something he thought might work (they weren't new ideas, but they've certainly never appeared in a real desktop environment before) and then offered a few possible ideas for how this stuff might be implemented. It was interesting stuff. Although some people made some very valid points (many of which Federico agreed with) a lot of people seemed distracted with implementation details that hardly seem relevant at this point. Especially when they were things that could easily be changed. They were so hung up on details that had little bearing to the overarching idea or the majority of the code that would be required.

more istanbul from the Openismus roof

All in all, it's been a pretty awesome GUADEC. There has been a tiny language barrier, and the hotel and the university were a little further apart than one might plan for, but I (and it appears) have had a blast. (posted on Saturday July 12th, 2008 at 10:08 am — 32 comments)

boat people

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).

another building on the strait

Collabora (well, I hear it was all Daf's excellent idea) took everyone out on a boat in the Bosphorous strait for drinks and cake. The Whisky BoF (who have the awesome acronym SMASHED) and the Icecream Deathmatch were held on board.

icecream deathmatchgnome cake
(posted on Friday July 11th, 2008 at 01:23 am)

murray's view is better than mine

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.

galata tower

I hadn't even thought about it, but my work emailed today to check that everyone was ok following the attack on the US consulate here in Istanbul. Everyone is fine and the conference continues. There has been no obvious change in security levels here, in fact no one here knew until they read it as part of their news feed the next day (great to see how tuned into the news your average GNOME hacker is).

sunset over istanbul
(posted on Thursday July 10th, 2008 at 12:26 pm — 4 comments)

NOTHING RIDES YOU LIKE A GOOD PAID OF HOT PANTS!

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'.

seagulls

It's like having Europeans that have been relocated to south-east Asia. Road rules appear to mostly be guidelines. Taxis will do 120kph weaving between traffic without seatbelts. The roads are also really slick (as in very smooth). Shopkeepers and restaurant owners will constantly try to get you into their store.

Vegetarian food seems easily enough come by, but vegan food is a little more challenging. Some of the food I've had looked vegan (but how can you really be sure?), but I've also ended up with a meal that appeared to be spinach and sour cream.

obelisk

The GUADEC startup days were suitably relaxed; catching up with people and such.

Release Notes
Although it's really Murray's turn, he's going to be a little bit busy in the coming months, so I've agreed to run the release notes effort for 2.24. I'm hoping that we can get an early start this time around, and I'm hoping to restart the Sneak Peak articles, but I need your help.

Don't worry that you're not a strong English speaker or a good writer. You can still help with the release notes effort and you can help with the most important part. The most important task in creating release notes is research. This means looking at all of the GNOME modules, reading their NEWS entries, talking to their maintainers and writing bullet points with exciting user visible changes on the wiki page. It also means looking at the Roadmap, finding out what has actually been implemented and checking that it works as described (or describe it better).

Unlike previous efforts, this time around we're using roadmap-list to coordinate the effort. Subscribe and get involved.

Finally, if you're a maintainer, or you want to help out and you're here at GUADEC; come and have a chat with me. Luis has already fingered me out, but I'd love to actually chat with you about what needs to be done. Remember, good release notes mean people see a good release.

tiny bird believes in values you believe in
(posted on Wednesday July 9th, 2008 at 12:07 pm — 5 comments)

loose change (the new tax system will be fairer on all Australians)

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.

unchain my heart!
Peter Combe

He had the same support act as last year (De Grussa Band aka De Grussa Starship or perhaps Jefferson Starship). Only this year they were prepared with three costume changes. One of these may have been as the Mario Brothers.

mario bros.
the only place you can buy them is the Willigee General Store

Travelling brings people together (OMG how great is this pun?). On my flight here I managed to discuss both how global warming has affected the Kentish summer, and whether Crumper satchels are superior to Crumpler backpacks (we both concluded the satchel is where it's at).

Peter Combe photos

I apologise if this post contains jokes that only my brother will find funny. More from Istanbul (hopefully). (posted on Sunday July 6th, 2008 at 09:53 pm — 2 comments)

dear Lazyweb (or at least the part that knows ANTLR)

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.

Does anyone know how I might achieve this? (posted on Monday June 30th, 2008 at 03:41 pm — 1 comment)

further adventures in the life of the home handypenguin

Finished off the cupboards this morning. Need to go and get one more door. Having it missing is annoying the pants off me.

i'm a professional

Went to Bunnings (or as Dad calls it: Church) to pick up bits and pieces so that I could install the Asker aluminum railing on top of the tiles (one of those ones you can hook various things into). Put holes into the wall and then realised that the hooks weren't going to clear the tiles (oops). Went back to Bunnings to purchase some 11mm square pine to use as a buffer. Doesn't look too shabby, but it'll need painting at some point. Ended up taking much longer than I intended, which meant I didn't get much else done besides installing a smoke alarm (why no smoke alarm, crazy previous owners?).

Went out to dinner last night at That Little Mexican Place in North Perth (see Steph's review) with frellies. There were a few couples having swoony, candlelit dinners. We didn't have the heart to tell them that the candles were fake.

fake plastic candle

They certainly had us fooled, until a certain person attempted to give into his pyromania (no, not me). While flickering light circuits are common (Jaycar sell a kit), it was the uneven faux melted wax that really had me fooled. Clearly this is a product aimed at the restaurant market, not only did it have a rechargeable battery, there was a DC socket on the bottom for recharging it. (posted on Sunday June 29th, 2008 at 08:18 pm — 7 comments)

little known faktums

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:

little known faktums

Currently we're using our portable kitchen island to separate the kitchen off from the rest of the space. Eventually I want to put more cupboards here with the matching kitchen bench on top. I think that would really set the whole thing off. (posted on Saturday June 28th, 2008 at 11:36 pm — 8 comments)

reverse cowgirl plumbing

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.

tux is ready to move
Tux on moving day

Had some fun with the drain on the bathroom sink. It was one of those funny pop-up/pop-down ones that doesn't have a plug, but the spring has jammed up, so it got stuck closed. Not only that, when we tried to remove it, they'd glued it in with about a litre of silicon sealant (which although not how it's meant to be done, is apparently common with cowboy plumbers). It eventually came out (Dad was willing to be a lot more forceful than I was) and I was able to get a replacement part. We've opted for a regular one that uses a plug.

Slowly discovering more funny errors. Like the door that had its lock-tongue backwards, and how our front door knob collides with our security screen. Still, I do think things are slowly coming together. We've not yet interacted with anyone from our strata, but some of the neighbors over the way appear to be real characters. Real, noisy, nonsense-talking characters.

squishy on stairs
on the stairs

Our old flat is the cleanest it's ever been; including when we took possession of it. Mum and Dad came to help, and everything has been scrubbed until it is spotless. We give the keys back tomorrow. I'm a little sad to be saying goodbye, but I knew this time would come eventually. (posted on Tuesday June 24th, 2008 at 11:15 pm — 2 comments)

i can be homeownr

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).

sold!
I was saving this photo for this post, but then Steph stole it

We'll be moving on Friday.

What's funny is how many people congratulate you. It's not like we had a baby or anything... just signed on to 6 figure debt. (posted on Wednesday June 18th, 2008 at 10:20 pm — 7 comments)

leveraging GtkTreeModel

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.

Next we need to initialise the underlying storage for the list in our init() method:
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).

For this example, we'll make our model have 2 columns: one for the object itself, and one for an 'id' that we can request from the object. Our first two interface methods are very straightforward:
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.

Putting it all Together
If you didn't follow that, or don't care and just want the code: here it is.

Compile it with gcc -o test `pkg-config --cflags --libs gtk+-2.0` my-list-store.c my-test-object.c.

The model is 93 lines in C, it should be even shorter in Vala, C++ or Python. Feel free to post reimplementations of this example in other languages in the comments.

This example demonstrates how to overload a GtkListStore or GtkTreeStore to store a list of objects, but export a number of columns based on data available from those objects. This allows the programmer to use the model as the data structure in which all of their objects are stored without having to worry about keeping multiple data structures up to date.

Further Leverage
Of course, it's possible to implement the full GtkTreeModel interface, e.g. if you want to write a tree model that backs onto a database, a filesystem or even some other data structure (e.g. GList, or something legacy). I'll put up an example of this at some point in the future.

Finally, don't just assume that GtkTreeModels can only be used with GtkTreeViews. GtkTreeModel emits signals with items are added, removed or changed, thus making it a really useful way to track items in a list. For example, I am currently using it to manage layers in a canvas. Each window has a single model assigned to it, which is used by both the treeview controlling the layers and the canvas drawing each layer. By pushing the treeview around (or the objects it contains), both the window and the canvas update automatically. It's almost like one of those OO paradigms you learnt about in school. I've also connected tree models to a number of different widgets to display the row information (e.g. a pie chart).

awesome stairs
(posted on Tuesday June 17th, 2008 at 07:28 pm — 24 comments)

dragging between GtkTreeView (part II)

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);

Finally in your get/received methods, you will need to marshal/demarshal something useful through your GtkSelectionData. If you've said GTK_TARGET_SAME_APP, then you can just marshal a pointer. GTK+ provides some handy API in gtk_tree_[sg]et_row_drag_data, but this only works if your atom is GTK_TREE_MODEL_ROW, and not something cool like "x-target/my-layer". GTK+ also offers some other API to marshal other types of data (like pixbufs) across a GtkSelectionData, but not something simple like a pointer. If you're feeling lazy:
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.

This could possibly be part of a larger article on writing your own GtkTreeModels (you really should do this, why aren't you?), but I'd only write that if people were really, really nice to me.

i can't remember what this is
(posted on Monday June 16th, 2008 at 10:50 pm — 1 comment)

not dead yet

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.

5 by 5
(posted on Monday June 9th, 2008 at 11:16 pm — 1 comment)

Back 20

Livejournal

Navigation

Related Links

Syndication

RSS 2.0 Atom FOAF

Planetarium

Web Presence

Hacking Life   UCC   GNOME

Contact Me

License

Creative Commons License