Program initialization

As MAFW is based on GObject the first step to write a MAFW based application is to initialize the GType system. You can do this by invoking g_type_init at the beginning of your program:

g_type_init ();
    

Of course, this step is not necessary if the developer is using another GObject based framework, like GTK+. In this case, initializing such framework already initializes the GType system.

The next step is to check for available extensions (sources and renderers). Depending on whether you are using in-process or out-of-process extensions, this process may differ slightly:

Loading out-of-process extensions

As we already pointed out, with the out-of-process approach extensions are loaded by the mafw-dbus-wrapper in a separate address space and they are shared by all applications, which use these extensions through DBUS services. In order to use these out-of-process extensions, the first step is to discover their availability on the bus. This is done by invoking mafw_shared_init. Once the discovery has been started, the application will be notified of new available extensions through signals. Likewise, when a certain extension is no longer available, a signal is received on the application side so the situation can be handled properly.

/* Start extension discovery service */
registry = MAFW_REGISTRY(mafw_registry_get_instance());
if (registry == NULL) {
        /* Error management here */
}

mafw_shared_init(registry, &error);
if (error != NULL) {
        /* Error management here */
} 

g_signal_connect(registry,
		 "renderer-added", G_CALLBACK(renderer_added_cb), NULL);

g_signal_connect(registry,
		 "renderer-removed", G_CALLBACK(renderer_removed_cb), NULL);

g_signal_connect(registry,
		 "source-added", G_CALLBACK(source_added_cb), NULL);

g_signal_connect(registry,
		 "source-removed", G_CALLBACK(source_removed_cb), NULL);
      

The MafwRegistry object is a singleton instance where all the available extensions are registered. It provides an interface for application developers to access the available sources and renderers. In the case of out-of-process extensions, the registry will provide proxies to the actual remote extensions that handle the DBUS communications transparently for the application developer.

After getting a reference to the MafwRegistry object, invoking mafw_shared_init starts the extension discovery, which will look for available extensions and register them. Whenever a new extension is found or removed, the registry emits a signal to inform the application.

It is also possible that extensions were loaded in the registry before the application attached its signal handlers. In this case the application will not get any signals for these extensions and has to query the registry for them using mafw\_registry\_get\_renderers and mafw\_registry\_get\_sources. One should notice that these lists of available extensions must not be freed:

extension_list = mafw_registry_get_renderers(registry);
while (extension_list)
{
	renderer_added_cb(registry, G_OBJECT(extension_list->data), NULL);
	extension_list = g_list_next(extension_list);
}

extension_list = mafw_registry_get_sources(registry);
while (extension_list)
{
	source_added_cb(registry, G_OBJECT(extension_list->data), NULL);
	extension_list = g_list_next(extension_list);
}
      

Notice that these lists of available extensions should not be freed.

The source-added and renderer-added callbacks look like this:

static void 
source_added_cb(MafwRegistry *registry, GObject *source, gpointer user_data)
{
	if (MAFW_IS_SOURCE(source)) {
                /* Handle new source extension */
	}
}

static void 
renderer_added_cb(MafwRegistry *registry, GObject *renderer, gpointer user_data)
{
	if (MAFW_IS_RENDERER(renderer)) {
                /* Handle new renderer extension here */
	}
}
      

Loading in-process extensions

Contrary to the out-of-process approach, in-process extensions are loaded in the same address space of the application's process. In this case we do not have to start a discovery process, instead we can either load all the available plugins or load specific plugins. As in the out-of-process case, this is done through the MafwRegistry object.

registry = MAFW_REGISTRY(mafw_registry_get_instance());
if (registry == NULL) {
        /* Error management here */
}
      

Loading all available extensions

After getting a reference to the registry, execute:

mafw_registry_load_plugins(registry);
          

Loading extensions manually

Individual extensions can be loaded manually by using mafw_registry_load_plugin and declaring the extension to load:

mafw_registry_load_plugin(MAFW_REGISTRY(registry),
                           "mafw-plugin.so", &error);
if (error != NULL) {
        /* Error management here */
} 
          

The second parameter of mafw_registry_load_plugin can be just a filename (in this case the default plugin directory will be used) or the absolute path of the plugin file.

Being aware of loaded extensions

As in the out-of-process approach, the application has to be informed of loaded extensions. The same code as for the out-of-process case can be used here.

Querying available extensions after loading

This approach loads the extensions in the registry first and then queries it for the lists of available renderers and sources, like this:

mafw_registry_load_plugins(registry);

extension_list = mafw_registry_get_renderers(registry);
while (extension_list)
{
	renderer_added_cb(registry, G_OBJECT(extension_list->data), NULL);
	extension_list = g_list_next(extension_list);
}

extension_list = mafw_registry_get_sources(registry);
while (extension_list)
{
	source_added_cb(registry, G_OBJECT(extension_list->data), NULL);
	extension_list = g_list_next(extension_list);
}
          
Using signals and callbacks

This approach is more asynchronous and it is recommended because it can easily handle sources or renderers added after the application was started. It is done by connecting callbacks to the "source-added" and "renderer-added" signals. As soon as a plugin is loaded, a signal is emitted and the application can react to it, preparing everything to use that extension, like this:

registry = MAFW_REGISTRY(mafw_registry_get_instance());
if (registry == NULL) {
        /* Error handling here */
}

g_signal_connect(registry,
		 "renderer_added", G_CALLBACK(renderer_added_cb), NULL);

g_signal_connect(registry,
		 "source_added", G_CALLBACK(source_added_cb), NULL);

g_signal_connect(registry,
		 "renderer_removed", G_CALLBACK(renderer_removed_cb), NULL);

g_signal_connect(registry,
		 "source_removed", G_CALLBACK(source_removed_cb), NULL);

mafw_registry_load_plugins(registry);
          

The form of the callbacks for these signals is the same as in the out-of-process case.

In-process versus out-of-process extensions

There are a few issues to consider when making the decision of using in-process or out-of-process extensions:

  • In-process extensions do not need inter-process communications, speeding up certain operations.
  • Out-of-process extensions use multiple processes and DBUS (which serializes and integrates these communications nicely with the main loop) avoiding the need of threads in the main application in most cases. In the in-process case, developers may need to use threads or idle calls to execute certain extension operations in order to avoid blocking the user interface while the extensions work (for example source browsing).
  • In the in-process case, signals coming from extensions are normal GObject signals. However, in the out-of-process case, these signals have to be sent through DBUS. For developers, this means that callbacks for these signals are not invoked as soon as the signal is emitted, but as soon as the DBUS message is received and processed by the main loop.