Gtk.ListStores and Clutter.ListModels in Javascript/gjs

It’s surprisingly hard to find this, and the generated documentation is actually misleaingly wrong ((The n_columns parameter is a lie, and will be inferred by gjs from the array size.)), so here’s how to create ListStores and ListModels in Javascript with gjs.

let store = new Gtk.ListStore();
store.set_column_types([GObject.TYPE_STRING, GObject.TYPE_INT]);
store.insert_with_valuesv(-1, [ 0, 1 ], [ "test", 42 ]);
let model = Clutter.ListModel.newv(
    [ GObject.TYPE_STRING, GObject.TYPE_STRING ],
    [ 'Column Name 1', 'Column Name 2' ]);
model.appendv([ 0, 1 ], [ "String 1", "String 2" ]);

The first array is the column numbers you wish to assign, the second array is the values for those columns.

Fundamental GTypes are available as GObject.TYPE_*. You can specify non-basic types using the class, e.g. Clutter.Text.

There are other variations possible, but this should provide the basics required to figure out the rest. ((You’re welcome.))

more on DPI

Daniel Stone recently wrote this amusing summary of why saying OMG I ABSOLUTELY MUST HAVE MY DPI CORRECT is rarely, if ever, correct.

Since most people who say this aren’t considering the two monitor case, I thought I’d provide a illustrative screenshot.

GTK+ resolution independence

This is an old screenshot of the resolution-independence branch of GTK+ running the demo program on two different monitors. It shows that both apps the physical same size, with the same physical size fonts (ignore the size of the title bars, those are provided by Metacity, which is using the system GTK+).

However, the font rendering looks different. This is because of the amount of anti-aliasing that goes into making fonts look smooth when you have less pixels to play with. Notice how in the title bars the font looks the same, even though they’re different sizes. That’s because they’re using the same number of pixels, and thus the same amount of anti-aliasing.

I couldn’t find a screenshot of what happens when you have a window that crosses between two monitors. [Perhaps it’s a nonsense case, but it can come up.] At this point everything just looks like crap. We have to choose the scaling of one monitor or the other. It will look wrong on one monitor or the other. It will be a different size to everything else on that monitor. [Before you suggest it; we can’t divide the window and calculate the scaling separately for each monitor across single widgets].

The thing is, for day to day computing, you don’t really care about the DPI, you care about having readable, attractive fonts and visible, clickable icons. So Federico is right. For some specific applications, you do care about DPI, but those applications can already use the XRandR data to take care of themselves [I have written visualisation apps which do this, presenting a scale on the screen of millimetres on screen to metres in the real world. ((And in using these apps, I’ve found plenty of monitors that return nonsense DPIs, forcing me to hardcode the monitor size in X11.))]

This said, I’m not sure why the only font size settings now in GNOME is a quantised Small, Normal, Large, Larger setting in the Universal Access settings pane. gnome-tweak-tool includes a scaling slider. The slider is hard to use though, especially when your text reflows while using it. Federico’s idea seems better.

As DPI continues to increase, it’s probably worth also applying scaling factors to our scalable window graphics, lest icons and the like become increasingly harder to hit. At this point we will likely need to adopt a resolution independent GTK+. However, again what will matter will be readable fonts and visible icons. Using the actual monitor DPIs will likely not be that important.

mistakes with g_value_set_boxed()

In today’s PSA, mistakes with g_value_set_boxed(). A mistake that’s been made several times by yours truly, and only realised today thanks to Xavier.

At some point in the GLib 2.22 cycle, types such as GArray, GPtrArray, GByteArray and GHashTable ((You can discover what g_boxed_copy() and g_boxed_free() will do for a type by looking for its G_DEFINE_BOXED_TYPE in GLib, which is probably in gobject/gboxed.c.)) gained ref() and unref() methods, which allowed things like g_boxed_copy() and g_boxed_free() to be a stack faster for those types. This was mid-2008.

Danni, who didn’t get the memo, had been occasionally writing bits of code like this:

GArray *array = g_array_new (...);

g_value_set_boxed (value, array);
g_array_free (array, TRUE);

Which, if you read the code, will keep the wrapper alive, so your code won’t crash, but will release all the data the array contains. Similarly for g_ptr_array_free() etc. It nicely zeros out the length of the array, so when you come to read it in your GValue, it looks empty.

The correct thing to do (of course) is unref your data, which will then free the memory and the wrapper when the refcount reaches zero.

GArray *array = g_array_new (...);

g_value_set_boxed (value, array);
g_array_unref (array);

Update: As pointed out in this simple example, you can replace this with the following pattern:

GArray *array = g_array_new (...);

g_value_take_boxed (value, array);

Which passes your ownership to the GValue. Where this falls down is for more complex values built for dbus-glib, where the ownership isn’t clear-cut, and so you need to free the components separately afterwards.

Help! Links in GtkCellRenderers

I’m hoping that someone already has a solution to this, but I couldn’t find one via Google Code Search.

What I want is a GtkCellRenderer that can render markup which contains links, exactly like a modern GtkLabel can. If it can also render small 16px inline images, that would be pretty awesome bonus.

Before I write it myself, does anyone already have one of these (with a GPL-compatible license)?

Quick Tip: gtk_show_uri(): Operation Not Supported

Writing this down because it took me way too long to realise what I was missing.

If you’re getting the error “Operation Not Supported” when calling gtk_show_uri() or g_app_info_launch_default_for_uri(), then you’re most likely missing gvfs, which contains the extension points for all non-file:// URI schemas.

Now here’s the bit I forgot… gvfs has to be installed in the same prefix as glib. So if it works for your system GLib, but not for the one you built in some prefix, you probably forgot to build and install gvfs in that prefix.

LD_PRELOAD GObject lifetime debugging tool

For years and years I’ve dreamt of a tool that would show me what GObjects are currently alive, and let me have a look at information about them. Today, while trying to debug a particularly horrid reference leak (program wedged under refdbg, and without being able to script SIGTRAP I’ve never found this method useful), I actually started writing the tool.

The tool uses LD_PRELOAD to replace g_object_new() — it should really replace g_object_newv() and g_object_new_valist() also, but I didn’t need those — to install a weak reference on the created objects to track their lifetime.

The result of which is something like this:

[danni@adelie src]$ \
 ++ Created object 0x9912530, GabbleGatewayPlugin
 ++ Created object 0x990c460, GabblePluginLoader
 ++ Created object 0x9917ab8, GabbleJabberProtocol
 ++ Created object 0x99172f0, GabbleConnectionManager

You can then list the currently living objects and their reference counts by sending SIGUSR1.

[danni@adelie src]$ killall -USR1 telepathy-gabble
Living Objects:
 - 0x9b47038, GabblePresence: 1 refs
 - 0x990c460, GabblePluginLoader: 2 refs
 - 0x9918ae0, GabbleRosterChannel: 1 refs
 - 0x991cb38, GabbleIMChannel: 1 refs

This by itself was useful in showing which object wasn’t finalized but should have been (and why my object in question also hadn’t finalized), but didn’t show me who was still holding the reference.

My hunch was that the problem was a reference cycle between two objects, so I hacked a bit of code into my tool to list the “connection” property on all objects that had it. [In Telepathy Connection Managers, objects are typically meant to let this go when connections become disconnected.]

  while (g_hash_table_iter_next (&iter, (gpointer) &obj, NULL))
      GObjectClass *klass;
      GObject *conn;

      g_print (" - %p, %s: %u refs\n",
          obj, G_OBJECT_TYPE_NAME (obj), obj->ref_count);

      klass = G_OBJECT_GET_CLASS (obj);
      if (g_object_class_find_property (klass, "connection") != NULL)
          g_object_get (obj,
              "connection", &conn,
          g_print ("\t + connection = %p\n", conn);
          if (conn != NULL)
            g_object_unref (conn);

This showed me which object was still holding a ref it should have let go. [Now I just need to work out why, the code in question is in an abstract base class, for which 5 of 6 concrete classes work correctly.]

If you’re interested, the code is in Git.

The tool could still benefit from a lot of work. For instance, the filtering is pretty basic at the moment and it should support all the ways to create GObjects. Originally I had envisioned this tool as a GUI window that popped up, so that you could click on an object and view all of its properties, connected signals, etc. That would be pretty neat actually.

Update: cassidy has already contributed by adding a listing of the objects remaining when a program exits and thus found a leak in Empathy. Awesome!

g_variant_equal() and dictionaries

For anyone using g_variant_equal() with a type containing a dictionary, you should the aware that, somewhat unexpectedly in my opinion, g_variant_equal() only returns true if (and only if) the keys in the dictionary are in the same order (GVariant implements dictionaries as an array of key-value pairs).

You can resolve this by using a function that recursively checks for semantic equivalence (such as this one).

I’m sure I’m not going to be the only person to find this useful. I’ve filed this as bug #622590.

a threaded processing queue in PyGTK

I'm currently writing a PyGTK client that needs to make network requests using a library that doesn't integrate with the GLib mainloop (python-suds), so I found myself wanting to be able to make network requests without blocking the mainloop, and getting callbacks in my main thread when operations were done. The pattern to use is clearly having a dedicated network thread. In C I might have used GAsyncQueue, however I've found myself quite liking queue.Queue.

The following is a fairly generic class for queuing asynchronous requests. Calling the add_request() method from the main thread queues a function to be run in the worker thread. If the callback or error keywords are provided, these will then be called from the GLib mainloop in the main thread (queued via g_idle_add).

from threading import Thread
from Queue import Queue

import gobject

class ThreadQueue(object):
    def __init__(self):
        self.q = Queue()

        t = Thread(target=self._thread_worker)

    def add_request(self, func, *args, **kwargs):
        """Add a request to the queue. Pass callback= and/or error= as
           keyword arguments to receive return from functions or exceptions.

        self.q.put((func, args, kwargs))

    def _thread_worker(self):
        while True:
            request = self.q.get()

    def do_request(self, (func, args, kwargs)):
        if 'callback' in kwargs:
            callback = kwargs['callback']
            del kwargs['callback']
            callback = None

        if 'error' in kwargs:
            error = kwargs['error']
            del kwargs['error']
            error = None

            r = func(*args, **kwargs)
            if not isinstance(r, tuple): r = (r,)
            if callback: self.do_callback(callback, *r)
        except Exception, e:
            if error: self.do_callback(error, e)
            else: print "Unhandled error:", e

    def do_callback(self, callback, *args):
        def _callback(callback, args):
            return False

        gobject.idle_add(_callback, callback, args)

We can then inherit this class to provide setup for our specific application:

class WebService(ThreadQueue):
    def __init__(self, guid=None, **kwargs):
        """Initialise the service. If guid is not provided, one will be
           requested (returned in the callback). Pass callback= or error=
           to receive notification of readiness."""

        self.guid = guid
        self.add_request(self._setup_client, **kwargs)

    def _setup_client(self):
        print "Setting up client"


        return self.guid

Which we call from our program like this:

class Client(object):
    def __init__(self):
        self.w = WebService(guid=guid, callback=self.client_ready)

    def client_ready(self, guid):
        print "client ready:", guid




What's really cool though is adding methods to the API that are called asynchronously for you. Python makes this possible through the power of decorators. Add the following decorator to a method, and it instead of it being called directly, it will be added to the processing queue.

def async_method(func):
    """Makes the given method asynchronous, meaning when it is called it
       will be queued with add_request.

    def bound_func(obj, *args, **kwargs):
        obj.add_request(func, obj, *args, **kwargs)

    return bound_func

class WebService(ThreadQueue):

    def GetStopInformation(self, stopNo):
        print "Requesting information for stop", stopNo


And that's it! If you can't follow it, don't worry too much. This is possibly the most Pythonesque bit of code I've ever written, but I've tried to make it generic enough that other people can use it for whatever they need. It's currently part of my app that's beginning to take shape, but the source is here.

Incidently, Maemo people: are there Glade definition files allowing me to use Hildon widgets, GtkBuild and Glade 3? That would be super awesome if there were.

GTK+ is crushing my spirit

I want a widget that is the combination of GtkComboBoxEntry and GtkEntryCompletion that can display a tree of options in a nice, indented way without the expanders (but with the rows expanded). Basically, a search box with a drop-down and hierarchical entries. I think I'm going to have to write my own, thought it sounds like something that might be more widely useful than just my application.

penguin in the tree
Visited '[info]'nixwilliams and '[info]'daniel_bethany for a cup of tea, which become lunch (which was delicious) which became more tea, which became waiting out the rain and watching Nicholas Crane trip over a lot. Got wet going home anyway. Now waiting out the rain again before going to the shops. It's a good thing that I like rain; though mostly I like wearing a giant, warm jumper while it rains outside.

status update on Clutter-GTK

Some time ago I wrote about my work on Clutter-GTK. Well, I finally got around to rebasing this branch so it could be merged and ebassi merged it for me last night.

There are still bugs in the code that I've not fixed, but many eyes make all bugs shallow, right?

The code includes a number of examples of how to do things.

If you're going to use these classes, you should understand how they work. There are caveats. Certainly I wouldn't base your entire toolkit around the interchanged use of GtkClutterActor and GtkClutterStandin.

GtkClutterActor takes a GtkWidget, rendered offscreen to an XPixmap, and paints it onto a GL texture which it draws on the Clutter stage. As a result, it can draw that texture anywhere, at any stacking level, and do things like taking events and sending them back to GTK+. Updating of the offscreen pixmap is done using Damage events, and things are generally peachy.

GtkClutterActor Implementation
Things basically work like you expect. Although there are some performance issues where widgets that draw using two expose events will sometimes have a delay between the two Damage events that I've not yet explained, which can cause a visual rip.

If GtkClutterActor lets you embed a GtkWidget into a Clutter stage, then GtkClutterStandin goes the other way around, allowing a ClutterActor to be placed within a GtkContainer; but the implementation is different. The ClutterActor is not rendered into offscreen memory, and then copied into an XPixmap and blitted into GTK+, this would not allow for all of those exciting animations you want to do.

Instead what happens is that GtkClutterStandin reserves space within a GtkContainer for the actor it proxies and then places that actor on top of the texture containing the widget contents.

Bugs should be filed in the Opened Hand Bugzilla.

Creative Commons Attribution-ShareAlike 2.5 Australia
This work by Danielle Madeley is licensed under a Creative Commons Attribution-ShareAlike 2.5 Australia.