For nearly a year I've been laboring over an Evolution branch named kill-bonobo, whose goal is exactly that: eradicate Bonobo from Evolution once and for all. According to the GNOME release schedule, I'm due for a status report. (Note, this only pertains to the application itself. The data server is already being ported from Bonobo to D-Bus by Ross Burton. The two projects are independent.)
The kill-bonobo branch is strictly an internal cleanup effort, albeit a massive one. It's not about adding features or radically changing the end-user experience. It's about making Evolution easier to maintain and enhance as we enter into the GNOME 3 era. So if I've done a good job, users will hardly notice any difference when the branch is finally merged.
Those who are interested in testing the branch can skip to the "How to Help" section.
Why We Need ItI was not present for the early evolution of Evolution, so this account is based on historical research and discussions with some of the old-timers. Hopefully they won't clobber me for getting the details wrong, or for calling them old-timers.
Evolution's original design consisted of a simple skeletal "shell" which served as the framework for out-of-process Bonobo components. Each component managed different types of information: one for email, one for calendar events, one for contacts, etc. The components talked amongst themselves via CORBA, which handled all the IPC. Ettore Perazzoli, in his paper for the 2001 Ottawa Linux Symposium, wrote:
It is interesting to note that the various pieces of Evolution are currently out-of-process components, and that CORBA deals with the inter-process communication nicely and transparently; it would be possible to turn these components into shared libraries without any substantial changes to the code.And that's exactly what happened. The components were turned into shared libraries sometime later to help address some design issues and to make the application more debuggable. Evolution then became — and has remained — one monolithic process. Most of its functionality is still supplied by in-process Bonobo components loaded at run-time. Bonobo was kept around in part for the menu merging capabilities of libbonoboui, but also because it was already very deeply ingrained in the application by then. To this day, Bonobo still handles all the inter-component communication, even though it's all one process.
Fast forward to present day. Bonobo has fallen out of favor with the rest of the GNOME community and its libraries are now deprecated (or planned to be deprecated — the distinction is unclear). GTK+ has gained a menu merging capability in GtkUIManager, GObject has gained a module loading system in GTypeModule, and developers are scrambling to migrate code away from deprecated libraries and API in preparation for GNOME 3.
Moreover, the inability of Evolution components to interact directly with the central shell continues to be a major design impediment. Certain bugs cannot be fixed and enhancements cannot be implemented with Bonobo in the way. Even something as simple as setting the proper relationship between a dialog window and the main application window can't be done under the current design without breaking the component/shell abstraction.
In short, Bonobo's time has passed and it needs to get gone.
A New ShellI have rewritten Evolution's shell from scratch. While still adhering to the original design principles, it now loads components (I'm calling them "shell backends" just to get away from the CORBA nomenclature) at startup via GTypeModule. Each main shell window provides a central GtkUIManager instance for shell backends to merge and un-merge their menus and tool bars. The new shell provides a bunch of other convenient services that it didn't, or couldn't, before. The API is now mostly stable, and it's documented! (A trend I hope to continue.)
The shell itself is a subclass of UniqueApp from libunique, so Evolution is still a single instance application. In fact, that feature has improved. Starting a second Evolution instance with no command-line options will now raise and focus the current window instead of opening a new one; a behavior greatly preferred by users. Also, Evolution will now terminate when it's finished handling a command-line URI and there are no other Evolution windows running.
InfrastructureBeyond the shell, it's mostly been a matter of slogging through the rest of the code and adapting it to the new shell API and the more modern GTK+ APIs. Turns out, Evolution has a lot of code, and a lot of infrastructure that piggybacks on Bonobo. Needless to say, that's why it's taking so long.
All of the menus and tool bars, and many of the stand-alone buttons and combo boxes, are now proxy widgets for GtkActions. EMenu and EPopup — the mechanisms that allow plugins to extend menus — are being phased out in favor of EPluginUI, which works with GtkUIManager. In fact, many of the plugins themselves are being phased out — their features being properly integrated into the application.
Asynchronous activity tracking — that's those percent-complete and error messages in the status bar — is now more object-oriented. The shell even lends a hand in routing and tracking these activities. I have a number of ideas for leveraging this new framework. Eventually I'd like to eliminate pop-up error dialogs altogether in favor of something less obnoxious, such as "inline" alert messages similar to those in Firefox, gedit, Sound Juicer and Evince. Also, better shutdown management — where Evolution tells you what network activities are keeping it from shutting down and allows you to cancel them.
Just getting the thing to build was another challenge. What I assume was once a nice layered design with clean separation of concerns has grown into a tangled mess of circular dependencies. I've managed to resolve most of the linking issues by shuffling source code around and routing application-wide events through the shell. But there's still the issue of library modules linking to library modules (plugins linking to shell backends and shell backends linking to one another), which is not portable and in fact prevents Evolution from building on Mac OS X.
Shell BackendsThe contact, memo and task backends are done, and I'm currently wrapping up some loose ends on the mailer. All are usable and ready for testing. I personally have been using the kill-bonobo branch for daily email and task management since February.
Calendars, however, are another story. See below.
What's UnfinishedThe branch is about 75% complete. It's usable, but there's still significant work to be done.
The CalendarThe calendar is half-finished and is not yet usable. This is the last major piece left.
I was attempting to split up the massive GnomeCalendar class into smaller, more manageable pieces. But I got burnt out and had to set it aside for awhile, and then never got back to it. At this point I'm in favor of just getting it working as quickly as possible. I can take another shot at refactoring it later when I'm feeling masochistic again.
PluginsMany of the plugins still have to be adapted to EPluginUI and the new shell. This is a highly parallelizable area where I could use some help from volunteers. The working and non-working plugins are listed in "configure.ac" (search for PLUGINS NOT BUILDING YET).
Evolution ExchangeEvolution Exchange (formerly the "Ximian Connector for Microsoft Exchange Server") presents an interesting problem. The evolution-exchange-storage process is the last out-of-process Bonobo component that talks to the shell. Ximian originally released this software under a non-free license, and used the split process design to bypass the linking restrictions imposed by the GPL. Later, after Ximian was acquired by Novell, it was released under an open-source license. But the design remained unchanged, even after Evolution was collapsed into a single process application.
I'm uncertain of what to do with this. To me, the best solution would be to convert the storage process to shared library modules for the Evolution and Evolution Data Server processes. But that could take some doing, and time is short. Plus, Evolution Exchange is being phased out by Evolution MAPI anyway. Another option is to hack together a quick and dirty D-Bus API for the shell, which the storage process can use. But I'm hesitant to expose a poorly thought out D-Bus API just for a corner case.
Third-Party ExtensionsThird-party extensions such as evolution-rss, evolution-brutus, and evolution-jescs will likely require some re-design. I will lend a hand here as much as possible.
How to HelpThe best way to help right now is to test drive the kill-bonobo branch and file Evolution bug reports at http://bugzilla.gnome.org/. Since this is an unofficial branch I have my own little system for tracking reports in Bugzilla. But really, if you do file a bug just mention that you're running the kill-bonobo branch and I'll take care of the rest.
- Existing bugs that the branch may be able to address are tagged with
evolution[kill-bonobo]in the Status Whiteboard field. (Bug List)
- Existing bugs that the branch has successfully addressed are tagged with
evolution[kill-bonobo]in the Status Whiteboard field and the Summary field prefixed with
[KB-Fixed]. (Bug List)
- Regressions that the branch has introduced get tagged with
evolution[kill-bonobo]in the Status Whiteboard field and the Summary field prefixed with
[regression]. These are what I'm looking for. (Bug List)
Evolution developers and contributors looking to hack on stuff could start by picking a non-working plugin and getting it back on its feet (see the previous section). That would probably acquaint you with the new shell API, and possibly expose bugs or shortcomings in the design. Catch me on GimpNet (channel #evolution) if you're interested in this.
For Fedora users, I will attempt to publish a kill-bonobo RPM repository for Fedora 12 / Rawhide in the near future. Stay tuned.