Evolution 2.32 introduces a new framework for extending individual Evolution object classes. It allows finer-grained control and far more flexibility than EPlugin hooks. The extension API is very simple and integrates well with GTypeModule.

Update:

Making Classes Extensible

An Evolution object or widget class can be made extensible in two steps:

1. Add the EExtensible interface when registering the class type. There are no methods to implement; the interface basically acts like a tag for the class.

#include <libebackend/libebackend.h>

G_DEFINE_TYPE_WITH_CODE (
        ECustomWidget, e_custom_widget, GTK_TYPE_WIDGET,
        G_IMPLEMENT_INTERFACE (E_TYPE_EXTENSIBLE, NULL))

2. Load extensions for the class at some point during instance initialization. Generally this should be done toward the end of the initialization code, so extensions get a fully initialized instance to work with.

static void
e_custom_widget_constructed (GObject *object)
{
        /* Initialization code goes here... */

        e_extensible_load_extensions (E_EXTENSIBLE (object));
}

Writing Extensions

Writing a basic Evolution extension involves three steps:

1. Subclass EExtension. See the "hello world" extension below for a complete example.

2. In the class initialization function, specify the GType being extended. The GType must be a GObjectClass that implements the EExtensible interface as described above.

3. Register the extension's own GType. If the extension is to be loaded dynamically using GTypeModule, the type should be registered in the library module's e_module_load() function.

Example

The following is an example of a dynamically loaded extension for the EShell class. It prints a message when an EShell instance is created, and also when the EShell instance is finalized.

#include <shell/e-shell.h>
#include <libebackend/libebackend.h>

typedef struct _EHelloWorld EHelloWorld;
typedef struct _EHelloWorldClass EHelloWorldClass;

struct _EHelloWorld {
        EExtension parent;
};

struct _EHelloWorldClass {
        EExtensionClass parent_class;
};

/* Module Entry Points */
void e_module_load (GTypeModule *type_module);
void e_module_unload (GTypeModule *type_module);

/* Forward Declarations */
GType e_hello_world_get_type (void);

G_DEFINE_DYNAMIC_TYPE (EHelloWorld, e_hello_world, E_TYPE_EXTENSION)

static void
e_hello_world_constructed (GObject *object)
{
        EExtensible *extensible;

        /* This retrieves the EShell instance we're extending. */
        extensible = e_extension_get_extensible (E_EXTENSION (object));

        /* This prints "Hello world from EShell!" */
        g_print ("Hello world from %s!\n", G_OBJECT_TYPE_NAME (extensible));
}

static void
e_hello_world_finalize (GObject *object)
{
        g_print ("Goodbye cruel world!\n");

        /* Chain up to parent's finalize() method. */
        G_OBJECT_CLASS (e_hello_world_parent_class)->finalize (object);
}

static void
e_hello_world_class_init (EHelloWorldClass *class)
{
        GObjectClass *object_class;
        EExtensionClass *extension_class;

        object_class = G_OBJECT_CLASS (class);
        object_class->constructed = e_hello_world_constructed;
        object_class->finalize = e_hello_world_finalize;

        /* Specify the GType of the class we're extending.
         * The class must implement the EExtensible interface. */
        extension_class = E_EXTENSION_CLASS (class);
        extension_class->extensible_type = E_TYPE_SHELL;
}

static void
e_hello_world_class_finalize (EHelloWorldClass *class)
{
        /* This function is usually left empty. */
}

static void
e_hello_world_init (EHelloWorld *extension)
{
        /* The EShell object we're extending is not available yet,
         * but we could still do some early initialization here. */
}

G_MODULE_EXPORT void
e_module_load (GTypeModule *type_module)
{
        /* This registers our EShell extension class with the GObject
         * type system.  An instance of our extension class is paired
         * with each instance of the class we're extending. */
        e_hello_world_register_type (type_module);
}

G_MODULE_EXPORT void
e_module_unload (GTypeModule *type_module)
{
        /* This function is usually left empty. */
}

Extensible Evolution Classes

The following classes are extensible in Evolution 3.10. More to follow.

CompEditor

EAttachmentIconView (API Reference)

EAttachmentTreeView (API Reference)

ECalendarItem

ECalendarView

ECalModel

EClientCache (API Reference)

EDateEdit (API Reference)

EImportAssistant (API Reference)

EMailAccountStore

EMailBrowser

EMailConfigAssistant

EMailConfigConfirmPage

EMailConfigDefaultsPage

EMailConfigIdentityPage

EMailConfigNotebook

EMailConfigProviderPage

EMailConfigSecurityPage

EMailConfigServicePage

EMailConfigSummaryPage

EMailConfigWelcomePage

EMailExtensionRegistry (API Reference)

EMailFormatter (API Reference)

EMailPanedView

EMailPart (API Reference)

EMailSession

EMailUISession

EMeetingStore

EMeetingTimeSelector

EMsgComposer (API Reference)

EShell (API Reference)

EShellContent (API Reference)

EShellSearchbar (API Reference)

EShellSidebar (API Reference)

EShellSwitcher (API Reference)

EShellTaskbar (API Reference)

EShellView (API Reference)

EShellWindow (API Reference)

ESourceConfig (API Reference)

ESpellEntry (API Reference)

ETreeViewFrame (API Reference)

EWebView (API Reference)

EWeekdayChooser

Example Module

The attached example-module.zip contains a build-able source code to create a new module which extends three parts of the Evolution:

  1. Mail view
    • an action in the context menu of the folder list, which is available only when a maildir folder is selected, like the one under On This Computer
    • an action in the Message menu, which requires at least one message to be selected
  2. Message Composer
    • an action into the File menu and a copy of it on the toolbar
  3. Calendar view
    • an action into the context menu of a selected event
    • an action into the Actions menu

The actions print an example data it can gather in respective contexts.

The project can be built using cmake like this:

  1. unzip the file somewhere
  2. enter the example-module/ directory
  3. create the build directory and enter it: $ mkdir _build && cd _build

  4. configure the project with cmake: $ cmake -G "Unix Makefiles" ..
  5. build and install the project: $ make && make install

Make sure you've installed development packages for the evolution-data-server and evolution. The project requires evolution 3.21.91 (see the root CMakeLists.txt REQUIRE_EVOLUTION_VERSION variable), but it can be built with older versions too, with some changes in the composer code.

Apps/Evolution/Extensions (last edited 2017-04-13 14:04:09 by MilanCrha)