Home · All Classes · Main Classes · Deprecated

Developing application extensions

Application extensions are plug-ins that can be embedded into an application extension area. They can be run either in the same process as the application or a separate process in the application extension runner. An application extension can optionally have a UI.

Development environment

To develop application extensions, you need:

Developing application extensions and applications that use them

From the developer's point of view, an application extension consists of a shared library, a desktop entry file, and possibly resources (such as images). All the contents are packaged into a Debian package so that the application extensions can be installed to devices.

An application extension is implemented as a Qt plug-in. It is recommended that the shared library name should include the related application and the extension name (for example, libmyapplication-myextension.so). The interface class used as the base class of all application extensions is MApplicationExtensionInterface. The interface provides a method for initialising the plug-in, which must be implemented by the application extension:

 bool MApplicationExtensionInterface::initialize(const QString &interface) 

The extension gets the name of the interface as a parameter. The extension can use this information, but does not need it for any purpose. The boolean return value should indicate whether the initialisation was successful or not.

The interface also has a method for returning the widget used for the UI of the application extension:

 QGraphicsWidget *widget() 

In this method you need to return a pointer to the QGraphicsWidget of your application extension. In case a UI is not required, this method can be left out. Note: The ownership of the QGraphicsWidget is left to the application extension, so you should destroy the widget yourself in the destructor of the extension.

To use application extensions of a particular interface in an application, an instance of MApplicationExtensionArea is created:

new MApplicationExtensionArea(interface, parent);

where interface refers to the interface implemented by the extensions in the area and parent is the parent QGraphicsItem. The area is only populated after init() is called.

Note: To be able to dynamically type cast from MApplicationExtensionInterface to a interface subclass implemented in extension, "-Wl,-E" flags are needed in executables linker flags ('QMAKE_LFLAGS += -Wl,-E'), see GCC faq about dynamic cast and shared libs

To define which extensions can be loaded in the same process as the extension area and which extensions run in separate processes, use setInProcessFilter() and setOutOfProcessFilter() before calling init(). Since these methods take QRegExp objects as their parameter, you can, for example, use QRegExp("$^") to allow no extensions, QRegExp("/test(1|A).desktop$") to allow extensions test1.desktop and testA.desktop and QRegExp() to allow all extensions.

Differences between in-process and out-of-process application extensions

Application extensions and applications that use them are developed differently depending on whether they are run in-process or out-of-process.

In-process extensions:

Out-of-process extensions:

Example of an in-process extension

// demoextensioninterface.h
#ifndef DEMOEXTENSIONINTERFACE_H
#define DEMOEXTENSIONINTERFACE_H

#include <mapplicationextensioninterface.h>

class DemoExtensionInterface : public MApplicationExtensionInterface
{
    Q_INTERFACES(MApplicationExtensionInterface)

public:
    virtual void demoExtensionSpecificOperation() = 0;
};

Q_DECLARE_INTERFACE(DemoExtensionInterface, "com.meego.DemoExtensionInterface/1.0")

#endif
// demoextension.h
#ifndef DEMOEXTENSION_H_
#define DEMOEXTENSION_H_

#include <QObject>
#include <MApplicationExtensionInterface>

class MButton;

class DemoApplicationExtension : public QObject, public DemoExtensionInterface
{
    Q_OBJECT
    Q_INTERFACES(DemoExtensionInterface MApplicationExtensionInterface)

public:
    DemoApplicationExtension();
    virtual ~DemoApplicationExtension();

    virtual void demoExtensionSpecificOperation();

    virtual bool initialize(const QString &interface);
    virtual MWidget *widget();

private:
    MButton *button;
};

#endif

Note: The Q_INTERFACES list must include both the demo-specific interface DemoExtensionInterface and the base interface MApplicationExtensionInterface.

 // demoextension.cpp
#include <MButton>
#include "demoextension.h"
#include <MLibrary>

M_LIBRARY
Q_EXPORT_PLUGIN2(demoextension, DemoApplicationExtension)

DemoApplicationExtension::DemoApplicationExtension() : button(0)
{
}

DemoApplicationExtension::~DemoApplicationExtension()
{
    delete button;
}

void DemoApplicationExtension::demoExtensionSpecificOperation()
{
    // do something specific to the demo extension interface
}

bool DemoApplicationExtension::initialize(const QString &)
{
    button = new MButton("Hello World");

    return true;
}

MWidget *DemoApplicationExtension::widget()
{
    return button;
}

In an application that wants to use the extensions implementing the com.meego.DemoExtensionInterface/1.0 defined above, the application should create the following application extension area:

 //demoapp.pro
...
TEMPLATE = app

QMAKE_LFLAGS = -Wl,-E,--as-needed
...
#include <MApplicationExtensionArea>
#include <demoextensioninterface.h>

...
void DemoApp::createExtensionArea()
{
    MApplicationExtensionArea *extensionArea =
        new MApplicationExtensionArea("com.meego.DemoApplicationExtensionInterface/1.0");
    extensionArea->setInProcessFilter(QRegExp("/demoapp-demoextension2?\\.desktop$"));
    extensionArea->init();
    layout->addItem(extensionArea);

    // Listen to signals about new and removed extensions
    connect(area, SIGNAL(extensionInstantiated(MApplicationExtensionInterface*)),
            this, SLOT(addExtension(MApplicationExtensionInterface*)));
    connect(area, SIGNAL(extensionRemoved(MApplicationExtensionInterface*)),
            this, SLOT(removeExtension(MApplicationExtensionInterface*)));
}

void DemoApp::addExtension(MApplicationExtensionInterface *extension)
{
    DemoExtensionInterface *demoExtension = dynamic_cast<DemoExtensionInterface *>(extension);
    if (demoExtension) {
        // do some extension interface specific things with the extension
        demoExtension->demoExtensionSpecificOperation();
    }
}
...

Application extension desktop file

Application extension must have a .desktop file written according to freedesktop.org desktop entry specification. It is recommended to name the file in a similar manner as the shared library (for example, myapplication-myextension.desktop). The keys Type and Name are required as specified in the desktop entry specification. The type must be X-MeeGoApplicationExtension. The Exec key is optionally used to specify a runner binary (usually mapplicationextensionrunner) which is launched in a separate process to run the application extension binary. If the key is not used, the application extension runs inside the host process.

Application extensions extend the specification by defining a new type MApplicationExtension and the following new keys which are placed into the X-MeeGoApplicationExtension group:

Key Description Value Type Required
Interface Defines the name of the interface implemented by this extension. string YES
Extension Defines the application extension binary. This binary needs to be located in the directory /usr/lib/meegotouch/applicationextensions/. string YES
Identifier Defines an identifier for the application extension. The identifier is used, for example, for defining the application extension specific style resource locations when the extension is run out-of-process. string (can contain characters [a-zA-Z0-9_-]) NO

The following example illustrates an application extension desktop file:

[Desktop Entry]
Type=X-MeeGoApplicationExtension
Name=ExampleExtension
Exec=mapplicationextensionrunner

[X-MeeGoApplicationExtension]
Interface=com.meego.DemoExtensionInterface/1.0
Extension=libdemoapplication-demoextension.so

Using MContainer

Application extension widgets are reparented to an MContainer by default. MContainer can include optional application extension information on its title bar, such as icon, title and additional informative text. If you do not want an application extension to reside in a container, set the container-mode property of the application extension area to false:

MApplicationExtensionAreaStyle {
    container-mode: false;
}

Use following properties and signals in your application extension widget class to provide container information:

Q_PROPERTY(QString applicationExtensionIcon  READ icon  WRITE setIcon)
Q_PROPERTY(QString applicationExtensionTitle READ title WRITE setTitle)
Q_PROPERTY(QString applicationExtensionText  READ text  WRITE setText)

signals:
    // change icon in MContainer
    void applicationExtensionIconChanged(QString newIcon);

    // change title in MContainer
    void applicationExtensionTitleChanged(QString newTitle);

    // change additional text in MContainer
    void applicationExtensionTextChanged(QString newText);

The property and signal names must be as stated above. The property access function names can differ.

Application extension identifier

Every application extension has an application extension identifier string that uniquely identifies the application extension.

The application extension identifier is determined like this:

Application extension styling

Application extensions can define their own styles just like any other application in the MeeGo Touch world.

Styling is done with style sheets and images in the usual way. The only important thing with application extensions is the location of the style resources.

When the application extension is run out-of-process, the resource location is constructed from the application extension identifier. The application extension identifier is used as the application name in the directory name.

When the application extension is run in-process, the resource location is constructed from the library name.

For more information about the directory locations, see Theme directory structure.

You can modify the layout orientation of the application extension area with the layout-orientation style parameter:

MApplicationExtensionAreaStyle {
    layout-orientation: horizontal;
}

Tools to help development

The meegotouch-dev-tools package includes a tool called mapplicationextensiontester. This tool can be used to test application extensions that have an UI. The tool loads application extensions implementing a specified interface to a window where you can interact with it and visually check the results. It is also easy to run the extension in a debugger with this tool.

To load an application extension with the tool, use the following command:

mapplicationextensiontester <interfacename>

where <interfacename> is the interface that the loaded extensions must implement.

Note that the application extensions must be installed to the system before mapplicationextensiontester can use them.


Copyright © 2010 Nokia Corporation
MeeGo Touch