Over the weekend I hit a milestone with a science experiment I started
earlier in the year to turn Camel into a GObject-based library with
minimal API breakage.  The short-term goal of this effort is to make it
easier to generate language and D-Bus bindings for Camel.

I now have running code which I've posted to a new evolution-data-server
branch called "camel-gobject" [1].  The branch contains a couple very
small patches (evolution.patch and evolution-exchange.patch) that must
be applied before building Evolution against the GObject-based Camel
library.

Evolution seems to be working just fine with my standard setup, but I
haven't tested all the built-in Camel providers and various third-party
extensions.  If others want to chip in with the testing I'd be grateful.


Techie Details
--------------

My approach was basically to pull off the same stunt that was done to
GtkObject when GObject was introduced: turn the base CamelObject class
into a GObject subclass, and convert the CamelObject API into a set of
thin wrappers for equivalent operations in GObject.  For example:

    camel_object_ref()      now calls   g_object_ref()

    camel_object_unref()    now calls   g_object_unref()

    camel_type_register()   now calls   g_type_register_static()

    ...etc...

Obviously this breaks Camel's ABI.  There's no way around that.

The (intentional) API breakage is very minimal:

    CamelType is now an alias for GType.  It is no longer a pointer
    to the class structure.  That was supposed to be an implementation
    detail anyway, but Camel (and Evo, and Evo-Exchange) exploits that
    in a number of places.  The class structure can be properly accessed
    using camel_type_get_global_classfuncs(), which is now an alias for
    g_type_class_peek().

    The corollary to that is when to fetch the parent class structure.
    Most classes define a static "parent_class" pointer for chaining up
    in class methods.  The "parent_class" pointer should be set in the
    class initialization function, NOT before the type registration in
    get_type().  Just like you would in normal GObject code.  There
    were LOTS of places in Camel were that needed fixing.

    Camel interfaces are dead, but they were never really used anyway.

The other half of the problem was CamelObjectBag.  It formerly shared a
mutex with CamelObject's reference counting, I think because CamelObject
ref's and unref's were non-atomic.  GObject's reference counting is
atomic, so with that issue out of the way I gave each CamelObjectBag its
own mutex, cleaned up the code a bit, and split it off into a separate
source file (camel-object-bag.c).  After an evening's worth of debugging
it seems to be working fine now.


Now What?
---------

So with the "interesting" part now done, next comes the long and tedious
part: rewriting all the internal CamelObject boilerplate into GObject
boilerplate and making sure we're not using any newly deprecated API.
But that can be done gradually and with help from others.

In time I'd also like to explore taking greater advantage of GObject
signals and properties in Camel, and also deprecating CamelArgV and
CamelArgGetV.

I haven't discussed this with the other Evolution/Camel developers yet,
so there are currently no plans to include it in 2.26.  That may change,
but for now it remains purely experimental.

Matthew Barnes


[1]
http://svn.gnome.org/viewvc/evolution-data-server/branches/camel-gobject/


_______________________________________________
Evolution-hackers mailing list
Evolution-hackers@gnome.org
http://mail.gnome.org/mailman/listinfo/evolution-hackers

Reply via email to