# &Evolution; Plugin Development Manual

Novell, Inc.
Michael
Zucchi
2004
Novell, Inc.

## Preface

This document is work-in-progress. Its structure and design is still as fluid as the underlying strucutre and design of some parts of EPlugin. There's no guarantee it will be updated at regular intervals, particularly this version.

The API documentation is currently generated using the Linux kernel-doc script. The stylesheets used to generate the HTML you're seeing seems to have bugs which duplicates some sections. It is also ugly and difficult to navigate.

### Conventions

The following conventions are used in the manual ... (insert details here).

#### XML Annotation

XML definitions are annotated with BNF-style markers to indicate alternative (|), multiples (* or +), and optional (?) items. If no annotation is present then the item must be present once.

|

  Indicates an alternative option. Only one of the items separated by | is to be chosen.

*

  Following an item, * indicates the item may occur any number of times, including no times (0 or more multiple).

+

  Following an item, + indicates the item must occur at least once, but may occur more than ones (1 or more multiple).

?

  Following an item, ? indicates the item may occur at most once, if present (0 or 1 times).

## EPlugin

### Introduction

This book aims to be a comprehensive technical manual for the development of plugins for &Evolution;, a personal information manager for &GNOME;.

Up-to, and including, &Evolution; version 2.0, &Evolution; contained limited extensibility interfaces. There were only two ways to extend &Evolution;; by implementing a new top-level component, or by implementing a &Camel; provider. When implementing a top-level component, there was still little integration, and in effect it was merely a more complex way of writing a separate &GNOME; application. &Camel; providers were only designed to be e-mail storage backends, so were of limited use for general extensibility. Despite this, both mechanisms were used for example for the Exchange Connector, although the system made the integration clumsy and difficult.

This lack of extensibility has severaly stifled external developer contributions by forcing any extensions to be considered as core features. &Evolution; being a commercial product, it has tight usability and quality requirements that limits the ability to experiment with the core feature set in this way. As a result, very few lines of code or new features have been implemented by external contributors.

One of the major goals for the 2.2 release was to implement an extensibility system, given the working name of EPlugin, which must provide a frame-work for both providing extensibility hooks, and for extending the functionality of &Evolution;.

#### Plugin System

Any plugin system will generally have a number of goals:

- Provide a language independent invocation mechanism

- Allow extension of parts of the user interface and processing elements

- Require minimal extra or foreign code to implement in the core application

- Require minimal interface code to implement the extensions

- Not to impact performance or increase resource usage unduly

- Versioning

- Be able to be extended itself fairly easily.

EPlugin manages to fulfill these goals in most cases. EPlugin isn't a single object or interface in itself, although there is an object titled EPlugin, it is a synergistic I've always wanted to use synergistic in a sentence since I read it on the back of the Commodore 64 Users Guide. collection of integrated and continually evolving objects which work together to achieve these goals (and that will definitly be the end of the MarketSpeak). It consists of a loader to invoke extension callbacks, hooks to resolve these callbacks, targets to identify context, and managers which are used by the core code to provide functionality and merging points for the extensions.

EPlugin's design was inspired and influenced by the &eclipse; project. It aims at a lower target however, so it was able more easily implemented in a practical time-frame.

&EPlugin; was chosen as an approach to the problem of adding scriptability to &Evolution;. Instead of just linking to Perl, or Python, or even Mono by itself an approach was taken which focuses on the application end of the system. So instead of making every part of the application export its functionality and have to deal with whatever script engine is present, EPlugin addresses the hooking part of the equation in a language-independent manner. It also attemps to do it in a way which doesn't impact on the application development either.

The EPlugin world is awash with its own language. The next few sections will introduce the basic plugin nomenclature and high-level view of this world.

#### Loaders

The core of EPlugin is a light-weight object loader and callback invocation system. Because of the varied calling conventions of different languages, and to reduce the overhead of the plugin system itself, all callbacks only receive and return a single argument. By using structures to pass complex arguments, native C plugins require no extra overhead, and marshalling details are moved into the plugin implementation itself where required. It also simplifies memory management issues significantly. For example, the C plugin handler merely loads a shared library using GModule, and resolves a symbol by name; and is so all of 50 lines of code, total. The loaders are the only modules which need to interace with non-native code or conventions.

The other task of the plugin core is to load XML definitions of the plugins. Extension hooks are registered with the plugin core before the plugins are scanned, and are automatically instantiated to load each definition appropriately as they are encountered.

At each layer, a level of indirection is used so that new loaders and new hooks can be added transparently, and extend the plugin definition freely with any information they require.

#### Hooks

The hooks A hook is something you can hang your stuff on. which are registered with the loader provide meta-data for the management implementation layer for extending it at run-time. Their primary functions are to load the detail of the XML plugin definition, map it to the implementation, and marshal the implementation callbacks to the common plugin interface. How they do this depends on the implementation itself, and ranges from registering factory methods to simply adding the items directly.

In most cases the physical object need not be loaded until the callback is invoked, since the plugin definitions provide enough contextual information to build the interface or determine when they need to be invoked.

#### Managers

Managers Unlike real managers, these are the ones that do the heavy lifting. provide tools for the core code to extend itself at specific points, and in many cases are the objects used directly in the code to implement core features. In other cases they simply provide the hooks with an entry point into &Evolution;. For example, for the main menu hook, the manager is a thin layer to BonoboUI. On the other hand, EPopup is a complete implementation of a popup menu management system which was already used in &Evolution; 2.0. Some managers are one-off objects used as constructors for other objects, others are view-dependent, and some are static objects, such as the Event routers.

#### Items

Each manager uses a number of items to describe the object they control or create. The items are added to each manager instance from the plugins or from core code. The items from all of these sources are then merged together when required and processed accordingly. For example, menu items are merged into a tree of GtkMenus. Events on the other hand are simply ordered and then invoked in the order of their priority. Items are part of the manager implementation, and in &EPlugin; they are all extensible objects too, which the hooks use to perform mapping to the plugin. Items may be extended by code hooking into the implementation, either the plugin hooks, or the core code.

#### Targets

Targets Think of a target as the target of interest. are view or component specific context objects. They contain enough information to be used as stand-alone contexts to implement callbacks for both core functions and plugin hooks. For example for the mail view, a select target contains a folder and a list of selected messages. An attachment (part) target contains the &Camel; representation of the part and the mime-type for that part. Targets are part of the manager implementation and are extended by subclassing the manager.

### Plugin Loaders

Plugin loaders implement a hool to a new language, or loading system in the plugin system. The actual binding of new languages to the plugin system or other parst of &Evolution;s api's are beyond the scope of this document, some languages make this easier than others.

#### Base Plugin

The EPlugin base class is an abstract class which provides the basic services for plugin implementations. The main services are:

- Resolve plugin type and instantiate an EPlugin object to represent and manage it.

- Load the base structure of the XML plugin definition files.

- Resolve plugin hook types and instantiate an EPluginHook to represent and manage it.

- Provide a simple, language-independent api for invoking plugin callbacks

- Provide I18N context for plugins.

- Some simple static helper methods to simplify each implementing class.

See the for these details.

##### Definition of a Plugin

The base plugin XML definition. Subclasses of EPlugin extend this basic structure with additional parameters or elements as they require.

Note that there may be any number of `e-plugin` elements in a given plugin file, this may be used to simplify distribution of plugin packages.

    <?xml version="1.0">
    <e-plugin-list>
      <e-plugin
        id="unique id"
        type="loader type"
        domain="translation domain" ?
        localedir="locale directory" ?
        name="plugin name"
        ...>
        <description>long description</description> ?
        <author name="real name"? email="email addr"?/> *
        <hook
          class="hook class"
          ...>
        ...
        </hook> +
      </e-plugin> +
    </e-plugin-list>

`id`

  A unique string identifying this plugin. By convention this will follow the java-like class namespace system. e.g. `com.ximian.evolution.test-plugin`

`type`

  The type name of the plugin loader. Currently shlib and mono are the only supported values. If no known handler is registered for this type, the plugin definition is silently ignored.

`domain`

  The translation domain for this plugin, as passed to the `dcgettext` call of the gettext package. If not supplied then the default application domain is used (i.e. "evolution"). This is used to translate translatable strings for display.

`localedir`

  If this and `domain` is defined, then this is the directory of the locale information for this domain. It, and the `domain` will be passed to `bindtextdomain` before any strings are translated. See that function for more information.

`name`

  A short name for the plugin. "Bob's Wonder Extender" might be suitable. This value will be translated.

`description`

  A longer description of the plugin's purpose. This value will be translated.

`author`

  One of the authors who wrote the plugin. Either `name` or `email` may be ommitted. This element may occur multiple times to indicate multiple authors.

`hook`

  This is a list of all of the hooks that this plugin wishes to hook into. See the Plugin Hooks section for the details of the basic hook types defined.

  The hook `class` is resolved using the registered hook types, and if none can be found, or a version mismatch occurs, then the hook is silently ignored.

#### Shared Library Loader

The shared library loader EPluginLib implements a concrete EPlugin type which loads GNU shared libraries via the GModule api. It simply resolves symbols directly from the loaded shared object and invokes them expecting a function signature of EPluginLibFunc.

To manage plugin lifecycle, the function `e_plugin_lib_enable` will be invoked which allows the plugin to initialise itself. Its signature should match EPluginLibEnableFunc, and it will be called with `enable=1`. If the enable function returns non-zero it is assumed to have failed intialisation and will not be invoked further.

##### Definition

The shared library loader only requires one extra parameter in the base plugin definition.

    <e-plugin
      ...
      type="shlib"
      location="/full/path/name.so"
      load-on-startup="true" ?
      ...
      <hook class="...">
       ...
    </e-plugin>

`type`

  The type name of the shared library plugin is `shlib`.

`location`

  The location parameter contains the full path-name of a shared object to load.

`load-on-startup`

  If provided, indicates that the plugin should be loaded and enabled when the application is first started. Normally the plugin is only loaded when necessary, i.e. when a callback is first invoked. Only use this option if you have defined an `e_plugin_lib_enable` callback in your module, and only if absolutely necessary.

##### Invocation

###### Function specification

Where a function spec is required in a plugin hook definition, it should simply be the full name of an exported symbol in the shared object.

###### Callback signature

    		void * function
    		EPlugin * ep
    		void * data

`function`

  The callback function.

`ep`

  The container EPlugin representing this plugin.

`data`

  Hook context data. It is part of the hook's api to specify the type of this pointer.

return value

  Return data. It is part of the hook's api to specify the type of this pointer.

#### Mono Assembly Loader

The mono assembly loader EPluginMono implements a concrete EPlugin type which loads C# assemblies using Mono. Apart from loading the assembly, it can optionally instantiate a class to implement the callback or invoke static methods directly.

##### Definition

The mono assembly loader needs the name of the assembly and optionally the name of the class for handling the callbacks.

    <e-plugin
      ...
      type="mono"
      location="/full/path/name.dll"
      handler="PluginClass" ?
      ...
      <hook class="...">
       ...
    </e-plugin>

`type`

  The type name of a mono assembly plugin is `mono`.

`location`

  The location parameter contains the full path-name of an assembly to load.

`handler`

  If supplied, the handler contains the fully qualified name of the class which handles all callbacks for this plugin. If a handling class is used, then the function specifications become relative to this class.

  This class will be instantiated once upon the first callback invocation, and remain active for the life of the plugin (or application).

##### Invocation

###### Function specification

If no `handler` class is specified, then the function specification must match a static method in the assembly. This is passed to `mono_method_desc_new` and `mono_method_desc_search_in_image`, typically `FunctionName(intptr)`.

If the handler is specified, then the function specification is relative to the handler class. This is passed to `mono_method_desc_new` and `mono_method_desc_search_in_class`, typically `:MethodName(intptr)`.

###### Callback signature

    		IntPtr function
    		IntPtr data

`function`

  The callback method.

`data`

  The hook context data. This is a pointer to unmanaged data, and it is up-to the plugin to interpret this data right now, although some helper binding classes are planned. FIXME: hook-up when they and doco are done.

return value

  The callback return data. It is up to the hook's api to define the type of this pointer. It may be a simple boxed value type, or a memory pointer allocated in unmanaged memory (e.g. a GObject handle or a CamelObject cobject value).

### Plugin Hooks

This chapter will introduce the available plugin hook types. A given plugin can hook into any of these hooks any number of times. Some refer to specific instances of objects and others are implicitly defined.

By design, there is considerable similarity and orthogonality amongst all of the various hook types and management objects.

#### Popup Menus

The popup menu hook lets you hook into any of the context menus in &Evolution;, by name and context. Complex, dynamic, and multi-level menus are created on the fly by merging the items for a given menu as it is being shown. Each component provides its own context targets to self-describe the situation under which the menu is invoked. Plugins and core code alike are then invoked at the user's direction. The popup manager and all context data lives as long as the menu and until a choice is made, simplifying memory management.

The menu is merged from multiple plugins and core application code by using a simple lexiographical sort of an absolute path to the menu item. This merged list is then scanned and expanded into a tree of menus. Individual items can be hidden or inactive based on the target and a simple mask which is defined by the component itself. A rich collection of menu item types are possible, from simple, to checkboxes or images. The popup code is simple, and easy to use, and simplifies the use of popup menu's in the core application anyway, that they are pluggable is a free-bonus.

##### Defining a popup hook

Not sure if this fits here as such. Probably temporary placeholder.

    <hook class="com.ximian.evolution.mail.popup:1.0">
     <menu id="menuid" target="targettype" factory="function spec"? >
      <item
       type="item | toggle | radio | image | submenu | bar"
       active ?
       path="foo/bar"
       label="menu text"
       icon="icon name" ?
       visible="target mask" ?
       enable="target mask" ?
       activate="function spec"/> *
     </menu> *
    </hook>

Menu Tag

`id`

  The id of the menu to which these items should be added.

`target`

  The target expected. There will normally only be one target type defined for any given menu, however some menu's may supply multiple targets depending on context.

`factory`

  If present, then a plugin-specific function specification of the function to invoke when the menu is being created. This function will normally call e_popup_add_items() to add custom menu items. It is used to provide more control than the visible and enable masks provide. The plugin argument is the popup target.

`type`

  The menu item type. The type maps directly to the corresponding EPopupItem types.

`active`

  If present, then radio or toggle menu items are active when first shown. After the first instantiation, they will remember their active state.

`path`

  A '/' separated path used to position the item within menu and in the right submenu. Each menu and plugin should define how its menu's are layed out so other plugins can determine what value to use here.

`label`

  The text to be displayed on the menu item. This will be translated based on the plugin translation domain.

`icon`

  The name of a gnome-icon-theme standard icon, or the full path-name of an icon image to use as menu item icon. This will be blank if not supplied.

`visible`

  A comma separated list of mask enumeration values used to define when this item is shown. What values are valid depend on the menu hook class of the menu being hooked onto.

`enable`

  A comma separated list of mask enumeration values used to define when this item is enabled. What values are valid depend on the menu hook class of the menu being hooked onto. This is currently unimplemented.

`activate`

  A plugin-type specific function specification. This function will be resolved and called when the menu item is activated.

##### Merging Plugin Items

A very simple algorithm is used to form the menu by merging the plugin's menu items with the system menu items for a given menu. What follows is a simple example of how this is done. It will be demonstrated using a simplified menu from the message-list, as used in the &Evolution; Mail component, and a simple plugin which adds a single menu item and menu separator into the middle of the menu, when appropriate.

When the application wishes to show a specific popup menu, it creates a new EPopup object with a unique menu id to manage it. It adds all of the items it wishes to add to the menu (see "Builtin Items" in the following diagrams). The application then asks for the menu to be created. The menu building process adds all of the menu items from all plugins that target this specific menu into a flat list, discarding those which don't match the current Target qualifications. The result is then sorted using a simple ASCII sort, and then a menu built from the remaining items. This is probably best described by some diagrams.

The following two diagrams show how a popup menu is automatically customised depending on the context. On the left of each diagram are all of the menu items which apply to the example menu. The menu label, with the qualifiers listed underneath, with the menu item path along-side. On the right-hand side of each diagram is the result of:

- Selecting items based on the target qualifiers

- Sorting the remaining items based on their path.

- Building this sorted list into a menu.

The actual list of target qualifiers are defined by the application itself. Generally a specific menu will have only one possible target, and a list of matching target qualifiers. The example shows how a plugin can insert a menu item anwhere it wishes in the menu system. Submenus are also supported, and they work in exactly the same manner, with / characters used to separate submenu paths. A submenu must sort into the position immediately before the definition of its items.

###### Merging a menu with many items selected.

Showing how a display list of menu items is selected and then sorted for display.

The first diagram shows when the target qualifiers are `many`, and `mark_unread`. The menu items which operate on only one selected message are not shown. Similarly for those able to be marked as unread (i.e. they are currently read).

###### Merging a menu with one item selected.

Showing how a display list of menu items is selected and then sorted for display with different qualifiers.

This diagram shows when the target qualifiers are `one`, and `mark_read`. The menu items which operate on only many selected messages are not shown. Similarly for those able to be marked as read.

#### Main menus

The main menu hook lets you hook into various main menus in &Evolution;, based on the current active view (component). The system works by piggy-backing on the existing use of the BonoboUI menu system used by all of the &Evolution; components. Bonobo handles the menu merging and user input, and the hook resolves the verb being invoked and redirects it to the plugin. Each view defines a single target which describes the appropriate context. For the Mail view, this is the current folder and currently selected message(s).

Each view keeps track of its own manager object. When it is (de)activated, it also (de)activates the management object which dynamically adds and removes the menu items from the BonoboUIContainer via a supplied BonoboUI XML definition file <perhaps it should embed the bonobouixml>. If the target changes, the view lets the manager know, and it updates the visibility and sensitivity of objects appropriately, allowing reasonably dynamic user-interfaces to be managed automatically. The plugin itself isn't loaded until the menu item in question is invoked

Simple menu items and toggle menu items are supported currently. Also, because actual menu display is driven by BonoboUI, then toolbar items can also be added using this mechanism.

##### Defining a menu hook

Not sure if this fits here as such. Probably temporary placeholder.

    <hook class="com.ximian.evolution.mail.bonoboMenu:1.0">
     <menu id="menuid" target="targettype"
      <ui file="/path/to/bonobo-ui-menu-definition.xml"> +
      <item
       type="item | toggle | radio"
       active ?
       path="/commands/FooBar"
       verb="FooBar"
       visible="target mask" ?
       enable="target mask" ?
       activate="function spec"/> *
     </menu> *
    </hook>

Need to define menu tag

`ui`

  The `ui` element contains a filename of the BonoboUI XML menu definition to load when the view is activated. Any number of `ui` elements may be defined, and they are all loaded.

`type`

  The menu item type. The type maps directly to the corresponding EMenuItem types. `radio` is currently not implemented.

`active`

  If present, then radio or toggle menu items are active when first shown. After the first instantiation, they will remember their active state.

`path`

  The BonoboUI element path corresponding to this menu item.

`verb`

  The BonoboUI verb corresponding to the item to be listened to.

`visible`

  A comma separated list of mask enumeration values used to define when this item is shown. What values are valid depend on the menu hook class of the menu being hooked onto.

`enable`

  A comma separated list of mask enumeration values used to define when this item is sensitive. What values are valid depend on the menu hook class of the menu being hooked onto.

`activate`

  A plugin-type specific function specification. This function will be resolved and called when the menu item is activated. The funciton's parameters will depend on the type of menu item being invoked.

##### Merging Plugin Items

Merging is performed by BonoboUI, and the source of the menu data is defined by the `ui` file.

#### Configuration Pages and Wizards

Configuration pages are somewhat more complex than any of the other types of hookable object. This is reflected in the complexity of the items and callbacks involved.

Essentially, the EConfig object is used in combination to both instrument existing windows and building new content. Each configuration window comprises of several basic elements with some minor variations allowed. It consists of a number of pages in a specific order, each containing a number of titled sections in a specific order, each containing a number of items. The variations are that the top-level widget may be a GtkNotebook or a GnomeDruid; and each section may instrument a GtkBox, or a GtkGrid. The definition of the available hooks will define what form they take.

The EConfig manager uses the description of all the items supplied to it to build the complete window. It can also drive various aspects of the UI, such as navigating through a druid or handling instant-apply vs. modify-and-save dialogues.

##### Event and Data Flow in EMConfig

The flow of information and control signals in the configuration management object.

##### Defining a configuration page hook

Not sure if this fits here as such. Probably temporary placeholder.

    <hook class="com.ximian.evolution.mail.config:1.0">
     <group
      id="window id"
      target="targettype"
      check="function spec"?
      commit="function spec"?
      abort="function spec"?>
      <item
       type="book | druid | page | page_start | page_finish | section | section_grid | item | item_grid"
       path="/absolute/path"
       label="name" | factory="function  spec"
      /> *
     </menu> *
    </hook>

###### Group Element Properties

`id`

  The name of the configuration window to which this hook applies.

`target`

  The type of target this configuration window applies too. This will normally be tied directly to the specific configuration window itself.

`check`

  A callback which will be invoked to validate the configuration or a specific page of the configuration. It will be invoked with a EConfigHookPageCheckData structure, and is expected to return a non-NULL value if the page validates.

  The callback will be expected to handle all `pageid`'s present in the configuration window, and should return `TRUE` for pages it does not recognise. If `pageid=""` (an empty string), then the `check` function should validate all settings. See also .

`commit`

  A callback which will be invoked to commit the configuration data, if the configuration page isn't an instant-apply one. This callback can write any configuration changes to permanent storage. It is not used for instant-apply windows.

`abort`

  A callback which will be invoked to abort the configuration process. This callback is called when the Cancel button is pressed on stateful configuration windows.

###### Item Element Properties

`type`

  The menu item type. The type maps directly to the corresponding EConfigItem types. Only one of `book` and `druid` may be supplied for the entire configuration page, and this will usually already be defined by the application.

`path`

  The path to the configuration item in question. This is a simple string that when sorted using an ASCII sort will place the items in the right order. That is, sections before items before pages before the root object.

`label`

  The textual label of this item. This may only be supplied for the section and page types. For sections it will be the section frame text. For pages this will be the druid page title or the notebook tab text. If a `factory`is supplied then this value is not used. This will be translated based on the plugin translation domain.

`factory`

  If supplied, the factory method used to create the GtkWidget elements for this configuration item. Factories may be supplied for any of the item types. If no `label` is set then the `factory` must be set.

##### Generating Configuration Pages

Configuration items essentially spam 3 dimensions, but are merged in a similar fashion to the way Popup items are merged. The main difference is that there are no target qualifiers used to select which items are shown, it is up to the item factory to either create or not create the item as it sees fit. The EConfig manager takes care of the rest, including removing un-used sections or pages.

All items for a given configuration screen are converted into a list and sorted based on the `path`. The configuration builder then goes through each item, creating container widgets or calling factories as required. If a given page or section is empty, then it is removed automatically. This process isn't only a one-off process. For certain complex configuration screens, items or even pages and sections need to be dynamic based on a previous setting. EConfig supports this mode of operation too, in which case it re-builds the configuration screen the same way, and automatically destroys the old widgets In most cases, in some cases additional manual processing is required in the factory callback. and even re-orders pages and sections where appropriate to make the user-interface consistent.

The following few examples some of the flexibility of the EConfig system.

###### The application defined, unaltered configuration page.

Shows the original HTML Mail settings page.

First we have the original configuration window. This is defined by the application, the application uses EConfig to build this window, and in the process EConfig instruments the sections that the application defines. This allows plugins to add new pages/sections/items anywhere on the page - to a granularity as defined by the application. For example the application may at minimum merely define the top-level notebook or druid object and a number of pages. When the pages are created the application could add as much content as it wants, which would still allow plugins to extend the user interface, but only by adding options to the end of each page. At the other end of the scale the application could enumerate every single item (i.e. row) in every section on every page, allowing plugins to put new items anywhere in the display.

###### A plugin adding a new section to an existing page.

Shows the HTML Mail settings page with a new section and item added by a plugin.

In this case the plugin has merely added a new section on the bottom of the HTML Mail settings page. When the factory is called the plugin has a parent GtkGrid (in this case, it could be a VBox) and borderless frame already defined, and it just has to instantiate its own control widgets, add them to the table, and return one of the widgets. The returned widget is used later if the window needs to be reconfigured, although this particular configuration page is static so it isn't needed.

###### A plugin inserting a new page for its settings.

Shows the plugin adding a new page for its setting as an alternative.

And finally we have exactly the same plugin, which has exactly the same code. But a small change to the plugin definition allows the plugin to add an arbitrary new page (in an arbitrary position) into the whole window. If this was a druid, then new druid pages can also be inserted at arbitrary locations, and page navigation (in a strictly linear manner) is automatically controlled by EConfig as per .

In practice, EConfig provides more than it takes the application to use - generally little or no extra application code is required to use it. It also Or it will - the code needs some tweaking. enforces and simplifies HIG compliance. And as a side-benefit to the application it transparently provides extension hooks for external code to provide a seamlessly integrated user experience.

#### Events

No extensibility framework would be complete without an event system. Events are used to reflect changes in internal state of the application, and track actions by the user. They can contain any information and additionally can be filtered based on the information itself. Special targets are used, as in the other plugin hooks, to hold this information.

Event managers are defined to contain the different event types that a given component can export. Only one event manager object is instantiated for each component, and each plugin listening to events from that component are registered on that event manager directly.

Events handlers have priorities, and can swallow events, allowing some level of complexity of event routing. This feature might not prove useful and may be removed in the future if it isn't.

##### Defining an event hook

Not sure if this fits here as such. Probably temporary placeholder.

    <hook class="com.ximian.evolution.mail.events:1.0">
     <event
       target="target name"
       id="event name"
       type="pass | sink" ?
       priority="signed integer" ?
       enable="target mask" ?
       handle="function spec"/> *
    </hook>

`target`

  The target type of the event listener. This will normally match in a 1:1 relationship to the event `id` itself.

`id`

  The name of the event to listen to. By convention the names will be of the form `target.event`. e.g. `folder.changed`, or `message.read`, etc. Although they are just simple case-sensitive strings.

`type`

  The event listener type. The type maps directly to the corresponding corresponding EEventItem types.

`priority`

  A signed integer specifying the priority of this event listener. 0 (zero) should be used normally, although positive and negative integers in the range -128 to 127 may aslo be used.

`enable`

  A comma separated list of mask enumeration values used to qualify when this event listener is invoked. What values are valid depend on the event hook class.

`handle`

  A plugin-type specific function specification. This function will be resolved and called when an event is routed to this listener.

#### Mail Formatter

The mail formatter plugin will invoke plugin code to format any part of an email based on mime-type. There are several formatters used internally by the mailer for different contexts, and each can be hooked into separately, providing extensible mail formatting for everything from the primary mail display, to printing, to reply quoting and more. If you are implementing a handler for a given mime-type, each formatter appropriate for the data-type should be hooked into, so that it displays properly in all contexts.

Since the management object in this case is the same formatting object as used by the core mail display engine, a plugin may override or reimplement complete new functionality seamlessly.

This plugin hook isn't strictly part of the core functionality as it is provided only by the mail component. It however demonstrates that the plugin system is extensible itself.

##### Defining a formatter hook

Not sure if this fits here as such. Probably temporary placeholder.

    <hook class="com.novell.evolution.mail.format:1.0">
     <group id="formatter type">
      <item
        flags="handler flags"
        mime_type="major/minor"
        format="function spec"/> +
     </group> +
    </hook>

`id`

  The actual formatter this applies to. e.g. EMFormat for the base formatter class, EMFormatHTML for HTML output to a GtkHTML object, etc.

`flags`

  Flags to define whether this is an attachment or inline content.

`id`

  The name of the event to listen to.

`mime_type`

  The type of object this handler formats.

`format`

  A plugin-type specific function specification. This function will be invoked to format objects of the specified `mime_type`.

##### The formatting process

The formatting process is driven by the EMFormat object, although there are different subclasses of this object used for different purposes. These behave quite differently so each must be explained separately. There is the basic formatter type which converts a CamelMimeMessage into a stream of data, and there is a HTML formatter type which uses a GtkHTML object to parse the content and may request further information required to complete the formatting.

A basic formatter goes through the following steps:

1. Outputs pre-amble information. e.g. Flag-For-Followup status. The pre-amble renderer is chosen using the pseudo mime-type `x-evolution/message/prefix`, and can be overridden or added to by plugging in to that type.

2. Looks up a handler for the pseudo mime-type `x-evolution/message/rfc822` and invokes it to begin message formatting. The default handler displays the message headers and then formats the message contents.

3. Using the mime-type of the content object (whether supplied or calculated), a handler is looked up from a per-class table to process the type.

4. If no handler exists, then the data is formatted as an attachment.

5. If a handler exists, then it is invoked to display that type. Depending on whether the data is to be displayed 'inline' or not, the data may also get an attachment expander and button.

6. The handler transforms the part's data, if need be, and writes the appropriate format output to a stream.

For conglomerate types, the formatting process is continued recursively, until all parts have been displayed, as appropriate.

A HTML formatter goes through the same basic steps, but has additional features and requirements. It uses multiple threads. At least one other thread is used for all of the Camel message content operations since some of them may block on remote I/O. This also simplifies cancellation processing. Also, because it has access to a full HTML rendering object, references to embedded content (images, buttons, etc.) are also processed.

Most format handlers don't need to know about all the fiddly details however. If they are just outputting HTML content with no out of band references, they work identical to the basic format handlers with the exception they cannot call any Gtk GUI code because of threading issues. This can still be done by using an IFRAME. If they want to embed an icon or other image, they simply need to insert the HTML IMG tag reference in their format handler, and setup a callback to handle it when GtkHTML requests it. EMFormat has some helper classes to make this only a few lines of code, including generation of the IMG SRC URL. IFRAMEs work identically to IMG tags, and similar process is involved with embedding custom widgets using the OBJECT tag. EMFormatHTML takes care of calling the right callbacks for the right embedded reference from the right thread.

Since format handlers are chained off a given type, then a plugin can also inherit formatting behaviour as well as override it. This gives much greater flexibility since the plugin need only implement its behaviour in specific situations. e.g. an OpenPGP message handler could fall-back to the normal text-formatter if it doesn't detect the ASCII armour in a text/plain part. Or another handler may disable itself based on configuration or state.

All format handlers for all types must also be fully re-entrant code (more or less write-once global and static variables) if they call any other formatting functions.

#### Importers

Importers let &Evolution; import data from other or older programs into its native format.

Importers are driven from a druid in the shell, they can work on individual files, or multiple component application data. All importers go through the same interface, is this data present/supported, how do you control the import, and import the data.

##### Defining an import hook

    <hook class="org.gnome.evolution.import:1.0:1.0">
     <importer
       target="home | uri"
       supported="funcion spec"
       get-widget="function spec" ?
       import="function spec"
       cancel="function spec" ?
       name="name"
       description="description" ?/> *
    </hook>

`target`

  The target type for this importer. File importers are of a type `uri` and application importers are of type `home` (indicating a 'home directory').

`supported`

  A function to call to determine if the file is supported or not. The function will be passed the target, and returns non-NULL if the file is known or the application data exists.

`get-widget`

  A factory method to get a widget to control the import. For file-based importers, this should return a widget which lets the user select the destination for the import. For application importers this should return a widget which lets the user choose what to import. Where possible, the application importer should record whether or not the data has already been imported and default any checkboxes accordingly.

`import`

  The function to call to import the data. This function should generally invoke another thread, or run via an idle handler callback. During the import it may call e_import_status() to report progress. It must call e_import_complete() once the import is complete, or has failed, or there was no work selected by the user.

`cancel`

  This optional callback will be invoked if the user activates the cancel button on the import window. It should try to short-cut further processing where possible.

`name`

  The short name description of the importer, which will be used in the import type selection dropdown, or next to the application importer widgets.

`description`

  A longer description of the importer. Currently unused.

## &Evolution; Hook Points.

This section enumerates all of the published hook points and target types available in each component in &Evolution;.

### Table Format

Id | The hook point id.
Target | The target which this hook uses for its context data. Targets are described in a following section.
Items | If appropriate and defined, specifies identifying path names of items which make up the hook. e.g. popup menu items, and configuration pages. These item specifications allow the plugin writer to position their items appropriately.

### Mail Hooks

Need to find out the right docbook to mark-up most of this text.

#### Popup menus

The mail popup menu class is org.gnome.evolution.mail.popup:1.0.

The plugin callback data will be the target matching the plugin menu itself, and the callback returns no value.

&em-popups;

##### Internal popup menus

The following popup menus are defined, but they are used with no target, and so provide no useful context if they were to be hooked onto.

com.ximian.mail.messagelist.popup.drop is used for the ASK drop type on the message list.

com.ximian.mail.storageset.popup.drop is used for the ASK drop type on the folder tree.

##### Mail Popup Targets

Not sure if this needs to explain the qualifier meanings, or leave it to the in-line comment stuff in the enumeration definition. Maybe it just needs a direct link to the enumeration.

###### Folder Target

This target is used to define actions on a folder context. Normally associated with the folder tree.

Name | `folder`
Structure | EMPopupTargetFolder

Qualifiers

- `folder` = `EM_POPUP_FOLDER_FOLDER`
- `store` = `EM_POPUP_FOLDER_STORE`
- `inferiors` = `EM_POPUP_FOLDER_INFERIORS`
- `delete` = `EM_POPUP_FOLDER_DELETE`
- `select` = `EM_POPUP_FOLDER_SELECT`

###### Selection Target

This target is used to define context for actions associated with a selection of mail messages from a specific folder.

Name | `select`
Structure | EMPopupTargetSelect

Qualifiers

- `one` = `EM_POPUP_SELECT_ONE`
- `many` = `EM_POPUP_SELECT_MANY`
- `mark_read` = `EM_POPUP_SELECT_MARK_READ`
- `mark_unread` = `EM_POPUP_SELECT_MARK_UNREAD`
- `delete` = `EM_POPUP_SELECT_DELETE`
- `undelete` = `EM_POPUP_SELECT_UNDELETE`
- `mailing_list` = `EM_POPUP_SELECT_MAILING_LIST`
- `resend` = `EM_POPUP_SELECT_EDIT`
- `mark_important` = `EM_POPUP_SELECT_MARK_IMPORTANT`
- `mark_unimportant` = `EM_POPUP_SELECT_MARK_UNIMPORTANT`
- `flag_followup` = `EM_POPUP_SELECT_FLAG_FOLLOWUP`
- `flag_completed` = `EM_POPUP_SELECT_FLAG_COMPLETED`
- `flag_clear` = `EM_POPUP_SELECT_FLAG_CLEAR`
- `add_sender` = `EM_POPUP_SELECT_ADD_SENDER`
- `mark_junk` = `EM_POPUP_SELECT_MARK_JUNK`
- `mark_nojunk` = `EM_POPUP_SELECT_MARK_NOJUNK`
- `folder` = `EM_POPUP_SELECT_FOLDER`

###### URI Target

This target defines context for operations on a URI, normally displayed inline somewhere in the message view.

Name | `uri`
Structure | EMPopupTargetURI

Qualifiers

- `http` = `EM_POPUP_URI_HTTP`
- `mailto` = `EM_POPUP_URI_MAILTO`
- `notmailto` = `EM_POPUP_URI_NOT_MAILTO`

###### Message Part Target

This target defines context for operations on messages, or individual message parts. The same target is used for inline images or other content which can be encapsulated in a MIME part (i.e. anything).

Name | `part`
Structure | EMPopupTargetPart

Qualifiers

- `message` = `EM_POPUP_PART_MESSAGE`
- `image` = `EM_POPUP_PART_IMAGE`

###### Attachments Target

This target is used to define context for operations on the mail composer attachment bar.

Name | `attachments`
Structure | EMPopupTargetAttachments

Qualifiers

- `one` = `EM_POPUP_ATTACHMENTS_ONE`
- `many` = `EM_POPUP_ATTACHMENTS_MANY`

#### Main menus

The mail popup menu class is org.gnome.evolution.mail.bonobomenu:1.0.

The plugin callback data will be the target matching the plugin menu itself, and the callback returns no value.

&em-menus;

##### Mail Menu Targets

###### Message Selection Target

This target is used to define context for operations on a selection of messages in the view's message list.

Name | `select`
Structure | EMMenuTargetSelect

Qualifiers

- `one` = `EM_MENU_SELECT_ONE`
- `many` = `EM_MENU_SELECT_MANY`
- `mark_read` = `EM_MENU_SELECT_MARK_READ`
- `mark_unread` = `EM_MENU_SELECT_MARK_UNREAD`
- `delete` = `EM_MENU_SELECT_DELETE`
- `undelete` = `EM_MENU_SELECT_UNDELETE`
- `mailing_list` = `EM_MENU_SELECT_MAILING_LIST`
- `resend` = `EM_MENU_SELECT_EDIT`
- `mark_important` = `EM_MENU_SELECT_MARK_IMPORTANT`
- `mark_unimportant` = `EM_MENU_SELECT_MARK_UNIMPORTANT`
- `flag_followup` = `EM_MENU_SELECT_FLAG_FOLLOWUP`
- `flag_completed` = `EM_MENU_SELECT_FLAG_COMPLETED`
- `flag_clear` = `EM_MENU_SELECT_FLAG_CLEAR`
- `add_sender` = `EM_MENU_SELECT_ADD_SENDER`
- `mark_junk` = `EM_MENU_SELECT_MARK_JUNK`
- `mark_nojunk` = `EM_MENU_SELECT_MARK_NOJUNK`
- `folder` = `EM_MENU_SELECT_FOLDER`

#### Config Windows and Druids

The mail config class is org.gnome.evolution.mail.config:1.0.

&em-configs;

##### Mail Config Targets

###### Account Target

The account target is used for configuring accounts, and so has a pointer to the EAccount being configured. This is a copy of the actual account object, and is copied to the original once the data is ready to commit.

Name | `account`
Structure | EMConfigTargetAccount
Items | Define some of the items available and where they fit in the gui

###### Preferences Target

The preferences target is used for global preferences. As such it just contains a pointer to the global configuration store - a GSettings.

Name | `prefs`
Structure | EMConfigTargetPrefs

###### Folder Target

Name | `folder`
Structure | EMConfigTargetFolder

#### Events

The mail event class is org.gnome.evolution.mail.events:1.0.

&em-events;

##### Mail Event Targets

###### Folder Target

Name | `folder`
Structure | EMEventTargetFolder
Qualifiers | List qualifiers

#### Formatters

The mail formatter hook class is com.novell.evolution.mail.format:1.0.

The mail formatter allows the rendering of attachments to be overridden based on the mime-type of the attachment. There are additional pseudo-mime-types which can be hooked on to to override some basic functions. These types are invalid mime-types so cannot occur in received messages.

`x-evolution/message/prefix` | If it exists, this handler will be called before any other content is output. This can be used to display global message-information, such as follow-up details. Normally this handler should chain its call to the parent handler once it is finished.

`x-evolution/message/rfc822`

This handler is called to output messages, including attached messages. The default handler will output the user-desired message headers and then render the message content. It also does some processing to do with secured message validation contexts. As this is not a simple handler, generally this hook point should only be used to supplement the prefix output where it is desirable to operate on attached messages.

##### Base Formatter

The EMFormat class is the base class for all formatting types. It should only be used to define compound and complex types which do not rely on outputting any textual information, or rely on any screen or print output differences.

Name | `EMFormat`
Target | EMFormatHookTarget

##### HTML Formatter

The EMFormatHTML class is the base class for most formatting types which generate HTML output. It renders output to a GtkHTML object. It uses a fairly complex multi-thread approach to the formatting to ensure the user-interface is not blocked for processing. GtkHTML is used in a limited way by this class for HTML parsing and resolution of embedded objects. Embedded objects and Widgets may not be used from formatters which hook onto this entry point.

Name | `EMFormatHTML`
Target | EMFormatHookTarget

This section needs a huge amount of explanation, and/or more detail needs to be added to another section about the formatter class

##### HTML Display Formatter

The EMFormatHTMLDisplay class is a subclass of EMFormatHTML, and is used as a mail display widget. As such, it has access to all of the facilities of GtkHTML, such as embedded widgets. Like the EMFormatHTML class, this uses a complex multi-thread architecture.

Name | `EMFormatHTMLDisplay`
Target | EMFormatHookTarget

This section needs a huge amount of explanation, and/or more detail needs to be added to another section about the formatter class

##### HTML Print Formatter

The EMFormatHTMLPrint class is a subclass of EMFormatHTML, and is used as a mail printing widget. It cannot access embedded widgets. For most purposes you would normally only connect to the EMFormatHTML hook, and generate generic HTML output which could be printed or shown on-screen if it isn't overriden by the display formatter.

Name | `EMFormatHTMLPrint`
Target | EMFormatHookTarget

This section needs a huge amount of explanation, and/or more detail needs to be added to another section about the formatter class

##### Mail Quote Formatter

The EMFormatQuote class is a subclass of EMFormat, and is used as generator for quoted mail content and for inline-forwarding. This formatter converts message objects into a pure HTML stream, which is not parsed directly, but normally fed to the message composer.

Name | `EMFormatQuote`
Target | EMFormatHookTarget

##### Mail Formatter Targets

There is only one target for all mail formatters, and it is implied automatically for all formatter hooks.

Structure | EMFormatHookTarget

Flags

- `inline` = `EM_FORMAT_HANDLER_INLINE`
- `inline_disposition` = `EM_FORMAT_HANDLER_INLINE_DISPOSITION`

### Contacts Hooks

Hooks available in the contacts component.

#### Popup menus

The contacts popup menu class is org.gnome.evolution.addressbook.popup:1.0.

##### Calendar Popup Targets

TBD

#### Main menus

The addressbook menu class is org.gnome.evolution.addressbook.bonobomenu:1.0.

##### Contacts Menu Targets

TBD

#### Config Windows and Druids

The addressbook config class is org.gnome.evolution.addressbook.config:1.0.

##### Contacts Config Targets

TBD

#### Events

None defined.

### Calendar Hooks

Hooks available in the calendar component.

#### Popup menus

The calendar popup menu class is org.gnome.evolution.calendar.popup:1.0.

&ecal-popups;

##### Calendar Popup Targets

TBD

#### Main menus

The calendar menu class is org.gnome.evolution.calendar.bonobomenu:1.0.

##### Calendar Menu Targets

TBD

#### Config Windows and Druids

The calendar config class is org.gnome.evolution.calendar.config:1.0.

##### Calendar Config Targets

TBD

#### Events

None defined.

### Shell Hooks

#### Main menus

The mail menu class is org.gnome.evolution.shell.bonobomenu:1.0.

The plugin callback data will be the target matching the plugin menu itself, and the callback returns no value.

&es-menus;

#### Events

The shell event class is org.gnome.evolution.shell.events:1.0.

&es-events;

#### Importers

Importers are currently global to the shell. The importer class is org.gnome.evolution.import:1.0.

Each plugin callback is passed the target. Once the target has been passed to get-widget, the same target will be passed to import or cancel. This allows information to be stored non-globally across invocations by utilising the GData field in the target.

&es-importers;

## Reference

This section of the book is a detailed API reference of the objects and methods that implement the core plugin system and hooks.

It contains the detailed information required for all uses of the plugin system. That is, implementors of new hook types, application developers providing hook points, and plugin developers.

### EPlugin

The EPlugin object manages the loading and invocation of physical plugin definitions and plugin binaries. The base EPlugin class is an abstract class which loads plugin definitons, resolving hooks, and provides an api for invoking callbacks.

The EPluginLib object is a concrete derived class of EPlugin which handles loading shared libraries using the GModule interface.

&e-plugin-reference;

### EPopup

The EPopup object manages a single popup menu. It is used to application code as a convenience function for building dynamic popup menus based on a specific context.

The EPopupHook object is loaded by the &EPlugin; system, and is used to provide dynamic extension to the application context menus.

&e-popup-reference;

&em-popup-reference;

### EMenu

The EMenu object manages the menus for a given view or component. It is used by application code to allow the plugin system an entry point to current application view. It may also be used by the application as a convenience function to dynamically alter the menu system based on user context.

The EMenuHook object is loaded by the &EPlugin; system, and is used to provide dynamic extension to the application menus.

&e-menu-reference;

### EConfig

The EConfig object manages the building of dynamic configuration pages to configure specific application objects. The same basic object can be used to fully drive a wizard-like druid object, or to drive a note-book of configuration options. It is used by application code to provide the core controller in a model-view-controller implementation of a UI window.

The EConfigHook object is loaded by the &EPlugin; system, and is used hook in additional configuration items into configuration windows or druids dynamically.

&e-config-reference;

### EEvent

The EEvent object manages broadcast of events for a given component or application. It is used by application code to provide the plugin system with an entry point for user and system state events.

The EEventHook object is loaded by the &EPlugin; system, and is used hook event listeners into dynamically loaded event handlers.

&e-event-reference;

### EMFormat

The EMFormat object drives the formatting of MIME message content for display, print, and replying. EMFormatHTML is an implementation of EMFormat which writes its output to a GtkHTML instance.

The EMFormatHook object is loaded by the &EPlugin; system, and is used hook event listeners into dynamically loaded event handlers.

&em-format-reference;

### EImport

The EImport object is used to hold a list of EImportImporter structures, which are used to drive the importer window.

&e-import-reference;