Qtopia Home - Classes - Hierachy - Annotated - Functions - Licenses - Reference

Writing Qtopia Plug-ins

Introduction

Plug-ins are implemented in Qtopia via a COM-like layer. The basic steps to writing any Qtopia plug-in are:

There are also some basic rules to follow when writing a plug-in:

Writing the functionality

Consider the following fictitious plug-in 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 plug-in name and a widget that is created with the supplied parent.

IID_WidgetPlugin defines a unique ID for this interface.

The plug-in that we are writing provides a widget that draws an ellipse in its center. The code below implements the functionality that this plug-in 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:

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 plug-in can provide several interfaces. At the very least QUnknownInterface is provided by all plug-ins.

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 plug-in.

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

Creating an instance

You must also create an instance of the widget plug-in using the following boilerplate code:

Q_EXPORT_INTERFACE()
{
    Q_CREATE_INSTANCE( CirclePlugin )
}

Loading Plug-ins

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

PluginLoader pluginLoader( "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 plug-ins to be installed in the $QPEDIR/plugins/type directory.


Copyright © 2005 Trolltech Trademarks
Qtopia version 2.2.0