Reference counting

There’s nothing wrong with adding a reference to the GObjects that you’ll pass to a deferred call.

For example (also read GdkLock, for the gdk_threads_enter thing):

static gboolean
callback (gpointer user_data) {
  GObject *instance = user_data;
  gdk_threads_enter ();
  /* work with instance and don't worry */
  gdk_threads_leave ();
  return FALSE;
}

static void
MyMethod (GObject *instance) {
  g_timeout_add_full (G_PRIORITY_DEFAULT, 5*1000,
		callback, g_object_ref (instance),
		(GDestroyNotify) g_object_unref);
}

Don’t do this:

static gboolean
callback (gpointer user_data) {
  GObject *instance = user_data;
  /* work with instance AND worry */
  return FALSE;
}

static void
MyMethod (GObject *instance) {
  g_timeout_add_full (G_PRIORITY_DEFAULT, 5*1000,
		callback, instance, NULL);
}

The problem is that most applications have multiple contexts. Either are those contexts threads or multiple code-paths for ‘instance’ to become finalized. For example D-Bus handlers, threads (yes, some people use them) or callbacks caused by GtkWidgets. Your timeout’s callback depends on that ‘instance’, therefore it’s required that you add a reference. Just like how a garbage collected higher language would add a reference to make sure that the instance wont be garbage collected during ‘callback’.

When I look at a lot of GLib/Gtk+ consuming code, I conclude that some people seem to be afraid of g_object_ref. Some people seem to believe that overuse of it creates memory leaks. The reality is much more simple: one misuse of it, causes a memory leak. Using it when required, doesn’t. Just be careful for cyclic references: an instance ‘A’ that references another instance ‘B’, that itself references ‘A’. Sometimes there is a type in between ‘A’ and ‘B’, like a container type. Use weak references for those situations in stead. Do use references when they are required, though.

In the example above nothing guarantees you that callback wont be interrupted. Nothing even guarantees you that callback will be started with a valid instance in its user_data. I have seen people putting G_IS_OBJECT checks at the top of their callback implementation. This is wrong and doesn’t really make it any better. Right after that runtime check your callback can get interrupted and you can again find the instance becoming finalized while using it in ‘callback’. By adding a reference, you are sure about the reference that you added. You are also sure that g_timeout_add_full will make sure that the GDestroyNotify will eventually execute. So you are sure that the g_object_ref is not causing any reference leak.

Also note that code like this is fine, indeed. Sure the two g_object_ref calls are atomic increments and therefore a little bit slower than avoiding one of the two. But it’s consistent. When a new developer reads that code he’ll immediately recognize that my_thing_get_instance returns a reference. It’s my opinion that readability is more important than a micro optimization hack.

static gboolean
callback (gpointer user_data) {
  GObject *instance = user_data;
  gdk_threads_enter ();
  /* work with instance and don't worry */
  gdk_threads_leave ();
  return FALSE;
}

static void
MyMethod (void) {
  GObject *instance = my_thing_get_instance ();
  ...
  g_timeout_add_full (G_PRIORITY_DEFAULT, 5*1000,
		callback, g_object_ref (instance),
		(GDestroyNotify) g_object_unref);
  ...
  g_object_unref (instance);
}

Web 2.0 !!!

A few days ago I got this reply on one of my blog posts:

Phil:

Your post — and your work — miss the point entirely. Nobody cares how email works, they just want it to work.

Gmail (and most other webmail applications) makes everything else obsolete. I can’t imagine why Evolution is even shipped with Gnome anymore.

Web-based email clients are the standard.

-Anon

I just finished the E-mail client the guy wants. Here it is!

using GLib;
using Gtk;
using WebKit;

class Web20EmailClient : Window {
	WebView view;
	construct {
		view = new WebView ();
		view.open ("http://gmail.com");
		view.set_size_request (640, 480);
		add (view);
	}
	static void main (string[] args) {
		Gtk.init (ref args);
		var win = new Web20EmailClient ();
		win.show_all ();
		Gtk.main ();
	}
}