In case you’ve been wondering if I had disappeared or something…
I’m in the middle of a session of exams, this week (four of them, to be precise), and I’ve had to cut down hacking time; nevertheless, I’ve been able to commit a set of fixes for the RecentChooser/BookmarkFile code and wrap up a new version of the desktop-bookmark storage spec.
GNOME Dictionary
I’ve also started the rewriting of the low-level implementation of the dictionary protocol client object for the GNOME Dictionary application. I’ve tried one last time to salvage the sane bits of the old code, but it was practically useless. Instead, I designed a new, object-oriented, approach. It’s been three years since I’ve done some networking with C, and I had to do some catch-up in order to write some decent code.
The new client object is called (with a certain lack of creativity) GDictContext
; you create a new context by using the gdict_context_new()
function, and since it inherits from GObject
, all you have to do to destroy it is to call g_object_unref()
on it.
All the querying and replying is done asynchronously; but instead of having callback functions for each command, I preferred a more GTK-like approach; now, you’ll have to connect to signals, which are emitted by the context object when something comes along the wire; thus, creating a client for the dictionary protocol is just a matter of a few lines of code:
static void on_connect (GDictContext *context gpointer user_data) { GError *error = NULL; gdict_context_define (context, NULL, "penguin", &error); if (error) { g_warning ("Error: %s", error->message); g_error_free (error); g_main_loop_quit (main_loop); } } static void on_def_found (GDictContext *context, GDictDefinition *definition, gpointer user_data) { g_print ("Definition for '%s' (from: %s)\n%s\n", gdict_definition_get_word (definition), gdict_definition_get_from (definition), gdict_definition_get_definition (definition)); } ... GDictContext *context; main_loop = g_main_loop_new (NULL, FALSE); context = gdict_context_new ("dict.org", NULL); g_signal_connect (context, "connect", G_CALLBACK (on_connect), NULL); g_signal_connect (context, "definition-found", G_CALLBACK (on_def_found), NULL); gdict_context_connect (context, &connect_error); if (connect_error) { g_warning ("Error: %s", connect_error->message); g_error_free (connect_error); g_object_unref (G_OBJECT (context)); return -1; } g_main_loop_run (main_loop); g_object_unref (G_OBJECT (context)); return 0;
As you can see, no more silly creation of commands and contextes, using redundant, badly defined or over-designed API (which, by the way, badly leaks strings and objects): just lean and mean, OO, event-driven code; I plan to make this a shared library (it already is, albeit it’s not exported), so every public function comes with documentation and follows the same style rules of the other platform libraries; I could even add bindings to it, and write the whole application/applet in an high-level language, like Perl or Python, and the effort would really be minimal.
Right now, the code is still flaky on the response parsing; I plan to make it more robust as soon as the week ends, and I’m free to use more time on it. After that, I’ll attack the UI side – and get a hold on the messy situation of the definition box, the speller tab and the preferences window. This should really take less than the low-level stuff: the code is a lot saner, even though requiring much love. The self-imposed deadline of late November/early December should be fully respected.
Mmm, as one of my favourite features of Gnome a non-memory leaking, stable, faster Dictionary applet will be awesome. :)