Qtopia Home - Classes - Hierachy - Annotated - Functions - Qt Embedded |

# Writing Qtopia Plugins

- Introduction
- Writing the functionality
- Subclassing the interface
- Implementing the interface
- Creating an instance
- Loading Plugins

## Introduction

Plugins are implemented in Qtopia via a COM-like layer. The basic steps to writing any Qtopia plugin are:

- Write the functionality that the plugin will provide.
- Subclass the interface for the plugin you wish to write.
- Provide implemetations for the interface methods.
- Create an instance of the plugin.

There are also some basic rules to follow when writing a plugin:

- Due to the implementation details of moc, it is important that any QObject subclasses in your plugin have unique names to prevent clashes between two plugins. As a rule, use a unique prefix for all classes including internal classes. For example, if a plugin "foo" has an internal helper class that is a QObject subclass, it should be named FooHelper rather than Helper.
- Plugins should not leak memory. Since a plugin may be unloaded at any time it is important to cleanup all used memory when your plugin interface is destructed.

## Writing the functionality

Consider the following fictious plugin interface:

    // {05E0A4AB-DDC5-4449-85A9-828100DE00A9}
    #ifndef IID_WidgetPlugin
    #define IID_WidgetPlugin QUuid( 0x05e0a4ab, 0xddc5, 0x4449, 0x85, 0xa9, 0x82, 0x81, 0x00, 0xde, 0x00, 0xa9)
    #endif

    struct WidgetPluginInterface : public QUnknownInterface
    {
        virtual QWidget *widget( QWidget *parent ) = 0;
        virtual QString name() const = 0;
    };

This is a simple interface that provides a plugin name and a widget that is created with the supplied parent.

IID_WidgetPlugin defines a unique ID for this interface.

The plugin that we are writing provides a widget that draws an ellipse in its center. The code below implements the functionality that this plugin provides.

    class EllipseWidget : public QWidget
    {
        Q_OBJECT
    public:
        EllipseWidget( QWidget *parent=0 ) : QWidget( parent, "Ellipse" )
        {
        }

    protected:
        void paintEvent( QPaintEvent * )
        {
            QPainter p( this );
            p.drawEllipse( rect() );
        }
    };

## Subclassing the interface

Now you can subclass the WidgetPluginInterface:

    struct CirclePlugin : public WidgetPluginInterface
    {
    public:
        virtual QWidget *widget( QWidget *parent );
        virtual QString name() const;

        QRESULT queryInterface( const QUuid&, QUnknownInterface** );
        Q_REFCOUNT

    protected:
        CircleWidget *w;
        ulong ref;
    };

There are two things to note in the CirclePlugin struct:

- the queryInterface() function allows the plugin loader to query what interfaces the plugin implements.
- Q_REFCOUNT is a macro to simplify the reference counting. This macro expects the ulog ref variable to be present.

## Implementing the interface

The constructor an destructor are straight-forward. The most important point is that ref must be initialised with 0.

    CirclePlugin::CirclePlugin()
        : w(0), ref(0)
    {
    }

    CirclePlugin::~CirclePlugin()
    {
        delete w;
    }

The queryInterface() function can be implemented using the following boilerplate code:

    QRESULT CirclePlugin::queryInterface( const QUuid &uuid, QUnknownInterface **iface )
    {
        *iface = 0;
        if ( uuid == IID_QUnknown )
            *iface = this;
        else if ( uuid == IID_WidgetPlugin )
            *iface = this;
        else
            return QS_FALSE;

        (*iface)->addRef();
        return QS_OK;
    }

A plugin can provide several interfaces. At the very least QUnknownInterface is provided by all plugins.

The widget() function returns the widget.

    QWidget *CirclePlugin::widget( QWidget *parent )
    {
        if ( !w )
            w = new CircleWidget( parent );
        return w;
    }

The name() function returns the name of the plugin.

    QString CirclePlugin::name()
    {
        return qApp->translate( "WidgetPlugin", "Circle" );
    }

## Creating an instance

You must also create an instance of the widget plugin using the following boilerplate code:

    Q_EXPORT_INTERFACE()
    {
        Q_CREATE_INSTANCE( CirclePlugin )
    }

## Loading Plugins

The recommended method for loading plugins is to use the PluginLoader class. The PluginLoader class provides simplified enumeration and loading of plugins and provides safety in cases where the system has been booted in Safe Mode.

    PluginLoader loader( "Widgets" );
    QStringList list = pluginLoader.list();
    QStringList::Iterator it;
    QValueList<WidgetPluginInterface*> widgetsList;
    for ( it = list.begin(); it != list.end(); ++it ) {
        WidgetPluginInterface *iface = 0;
        if ( pluginLoader.queryInterface( *it, IID_WidgetPlugin, (QUnknownInterface**)&iface ) == QS_OK && iface ) {
            widgetsList.append( iface );
        }
    }

The PluginLoader class expects the plugins to be installed in the $QPEDIR/plugins/type directory.