Evolution"> GNOME"> Eclipse"> Camel"> EPlugin"> ]> &Evolution; Plugin Development Manual Novell, Inc. MichaelZucchi 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 a 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. long description ? * ... + + ]]> 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. ... ]]> 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. ... ]]> 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. * * ]]> 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 the function to invoke when the 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. + * * ]]> 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 GtkTable. 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. * * ]]> 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 factoryis 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 GtkTable (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. * ]]> 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. + + ]]> 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: 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. 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. 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. If no handler exists, then the data is formatted as an attachment. 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. 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 * ]]> 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 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 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;