Abstract

This tutorial needs KDE 4.2 to build.

In this tutorial I will show how to create a simple applet that uses an extender. This applet is basically a very stripped down version of the kuiserver applet. Stripped down to the point where it isn't very useful anymore, but that allows us to focus on extenders.

About extenders

Extenders allow applets to, with only very little extra lines of code, use relocatable widgets. These ExtenderItem objects, can be dragged around by the user, dropped anywhere, and can even be persistent between sessions. They can also keep running, even when the applet that created them, isn't.
The class that shows and manages these extender items is Plasma::Extender.

How to approach extenders

If you want to use extenders in your applet you'll usually have to do a couple of things:

This is quite easy: calling extender() from your applet will instantiate an extender for you if your applet doesn't have an extender yet. Note that an applet cannot have more then one extender. Also note that you should always instantiate an extender in your applet's init() function. An extender requires a scene, which isn't available before the call to init().

Just instantiating an ExtenderItem with your extender as parameter to the constructor will add a new ExtenderItem to this extender. In this tutorial we will add an ExtenderItem whenever a new kuiserver job is created. After instantiating an ExtenderItem you'll usually want to set a name, title, icon, and probably even other information which can be stored by accessing the item's config(). Once you've got an ExtenderItem set up, you'll need to call initExtenderItem(ExtenderItem*) to actually set the QGraphicsWidget that will be wrapped inside this ExtenderItem.

Implement a initExtenderItem(ExtenderItem*) function in your applet

This function will be used to recreate detached ExtenderItems after plasma has been restarted. It will not only be called by your applet after instantiating a new ExtenderItem, it will also be called whenever plasma is started and detached ExtenderItems are restored from configuration. In this function you'll need to extract the required information from the item (name, or other information you have stored in the item's config()), and use this information to create the desired widget to be wrapped inside this item. Then call setWidget on this item to actually wrap this widget inside the ExtenderItem.

The code

Here I will show you our very simple stripped down kuiserver applet. It will show every new job in an ExtenderItem using a Plasma::Meter to display the jobs progress. In the title bar of the ExtenderItem the name of the datasource will be displayed, and the icon of the application that created the job will be shown.
Finally, the items will also be sort of persistent. When plasma is restarted, all detached items will get shown again, but will only show the name of the original datasource it was connected to as title. Kuiserver datasources are not persistent between sessions (yet?) so the meter won't show progress anymore.
As basis for this applet we will use {{class|PopupApplet}. This means that the applet will automatically collapse into an icon when put into a panel. PopupApplet will also take care of setting the correct appearence on your extender, depending of where it's located (top of screen, bottom of screen, desktop). PopupApplet is a convenient base class for all applets that use extenders and I'd strongly advice you to use it.

protected:
//Implement this function to make ExtenderItems persistent.

//This function will get called on plasma start for every
//ExtenderItem that belonged to this applet, and is still
//around. Instantiate the widget to be wrapped in the
//ExtenderItem here.

void initExtenderItem(Plasma::ExtenderItem *item);

public slots:
//We want to add a new ExtenderItem everytime a new job

//is started.

void sourceAdded(const QString &source);

};

K_EXPORT_PLASMA_APPLET(extendertutorial, ExtenderTutorial)

endif

This header should be mostly self explanetory. We use PopupApplet to have a nice basis for this kind of applet. The default implementation of PopupApplet's graphicsWidget() returns it's extender if it has one. This is exactly what we want (display the extender in the popup), so we don't need to implement graphicsWidget().

//We give this item a name, which we don't use in this
//example, but allows us to look up extenderItems by calling
//extenderItem(name). That function is useful to avoid
//duplicating detached ExtenderItems between session, because
//you can check if a certain item already exists.
item->setName(source);

//And we give this item a title. Titles, along with icons and
//names are persistent between sessions.
item->setTitle(source);

//Connect a dataengine. If this applet would display data where
//datasources would have unique names, even between sessions,
//you should do this in initExtenderItem, so that after a plasma
//restart, datasources would still get connected to the
//appropriate sources. Kuiserver jobs are not persistent however,
//so we connect them here.
dataEngine("kuiserver")->connectSource(source,

static_cast<QObject*>(item->widget()), 200);

//Show the popup for 5 seconds if in panel, so the user notices
//that there's a new job running.
showPopup(5000);

}

include "extendertutorial.moc"

This piece of code is well documented so I won't explain this any further.

So there it is, all it takes to make a simple applet that uses an extender. For a more complete example I'd like to point you at the kuiserver applet which is in playground right now. And I'd encourage you to read to api documentation of Extender and ExtenderItem. Especially ExtenderItem has a lot of features that are not used in this example but can be really useful like being able to set a timeout and add custom actions to the item, that are show in the item's drag handle.
I'm looking forward to see your extender using applet, be creative! :)