Open Source im professionellen Einsatz

Ozphoto, Fotolia.com

Plasmoide programmieren in C++

Plasmagie

Wer den Plasma-Desktop seines KDE 4 mit eigenen kleinen Anzeigetafeln alias Plasmoiden spicken möchte, die Daten aus den Tiefen des Systems auf den Desktop zaubern, dem gibt dieser Artikel den Stab in die Hand. Vorsicht: Die sich eröffnenden Möglichkeiten entfalten womöglich Sogwirkung. Verzauberungsgefahr!

Bei KDEs Wechsel von Version 3 zu 4 war der Plasma-Desktop [1] eine große Veränderung. Statt eines Hintergrundbilds mit Icons ist der jetzige Desktop eine Heimstatt für Plasmoide, auch Desktop-Widgets genannt. Sie setzen Icons, inszenieren eine Slideshow, zeigen den RSS-Feed an oder twittern. Mit oder ohne Spezialeditor (siehe Kasten "Der Plasmoid-Editor Plasmate") ist es auch nicht schwer, eigene Plasmoide zu schreiben.

Der Plasmoid-Editor
Plasmate

Dieser Artikel leitet C++-Programmierer zu ihrer ersten Plasma-Desktopapplikation. Plasmoide können aber auch in anderen Sprachen entstehen, zum Beispiel Javascript, Ruby oder Python. Um die Plasmoid-Erstellung zu erleichtern, hat das KDE-Projekt den Plasmoid-Editor Plasmate gestartet (Abbildung 1, [4]). Eine installierte KDE-Version 4.3 vorausgesetzt ist der Code im SVN-Repository von KDE-Playground erhältlich:

svn co svn://anonsvn.kde.org/home/kde/trunk/playground/base/plasma/plasmate 

Der Plasmoid-Editor ist noch nicht als stabil freigegeben. Mit der Beschreibung in der KDE-Dokumentation Techbase können Neugierige ihn jedoch schon mal ausprobieren.

Abbildung 1: Der Editor Plasmate zeigt im oberen Teil die bearbeitete Datei, im mittleren Teil den Programmtext und im unteren Teil außerdem eine Vorschau.

Abbildung 1: Der Editor Plasmate zeigt im oberen Teil die bearbeitete Datei, im mittleren Teil den Programmtext und im unteren Teil außerdem eine Vorschau.

Wer das möchte, braucht eine KDE-4-Entwicklungsumgebung mit den passenden Bibliotheken und Headern sowie GCC [2]. Für diesen Artikel kam ein Kubuntu 9.04 mit KDE 4.2 zum Einsatz. Wer Plasmoide anwendet, braucht einen Plasma-Desktop und das aus den Programmdateien für die eigene KDE-Version erzeugte Binary. Auf dem FTP-Server des Linux-Magazins [3] befinden sich die Programmierbeispiele dieses Artikels in Quellcode-Form, die sich Interessierte - alternativ zum nachprogrammieren - nach der Anleitung dieses Artikels kompilieren und installieren dürfen.

So tickt Plasma

Der Plasma-Desktop besteht grundsätzlich aus zwei Ebenen. Die eine ist für die Datenquellen oder Data Engines zuständig, die andere kümmert sich um die Visualisierung. Das Trennungsgebot ist entscheidend, denn so kann der Plasmoid-Programmierer dieselben Daten auf verschiedene Weisen darstellen, ohne jedes Mal die Datenquelle neu zu implementieren.

Dank der C++-Basisklasse namens »Plasma::DataEngine« beantworten die verarbeiteten Data Engines Anfragen, nehmen Minimalintervalle für Aktualisierungen entgegen und bewältigen asynchrone Ereignisse oder mehrere Werte einer Variablen. In gleicher Weise ist die Klasse »Plasma::Applet« Ausgangspunkt, um die kleinen Programme für den Plasma-Desktop zu erstellen. Aus diesen Applets entstehen zusammen mit einer Desktopdatei und einem grafischen Anstrich später Plasmoide.

Beispiel-Plasmoid: Belastungsampel

Als Beispiel zeigt ein einfaches Applet die durchschnittliche Systemauslastung pro Minute in Form einer Ampel (Abbildung 2). Ihre Lichter signalisieren leichte, hohe oder zu hohe Belastung mit den Farben Grün, Gelb und Rot. Eine Schnittstelle zu den benötigten Daten gibt es bereits: den KDE-Systemmonitor.

Abbildung 2: Das Beispiel-Plasmoid Loadlight in Aktion. Es indiziert minütlich die Systemauslastung mittels Ampelfarben.

Abbildung 2: Das Beispiel-Plasmoid Loadlight in Aktion. Es indiziert minütlich die Systemauslastung mittels Ampelfarben.

Der erste Schritt ist die Headerdatei (Listing 1). Zeile 9 leitet die Klasse »PlasmaLoadLight« von der Klasse »Plasma::Applet« ab. Die Konstruktoren »paintInterface()« und »init()« implementieren virtuelle Funktionen. Das entlastet den Programmierer von aufwändigen Initialisierungen in »init()«. Die Methode »paintInterface()« dient später dazu, die Visualisierung neu aufzubauen.

Listing 1:
Loadlight.h

01 #ifndef LOADLIGHT_H
02 #define LOADLIGHT_H
03 
04 #include <Plasma/Applet> 
05 #include <Plasma/DataEngine>
06 
07 class QSizeF;
08 
09 class PlasmaLoadLight : public Plasma::Applet
10 { 
11     Q_OBJECT
12 
13 public:
14     PlasmaLoadLight( QObject *parent,
15                      const QVariantList &args ); 
16     void init();
17     void paintInterface( QPainter *painter,
18        const QStyleOptionGraphicsItem *option,
19        const QRect &contentsRect ); 
20 
21 protected slots:
22     void sourceAdded( const QString &name ); 
23     void dataUpdated( const QString &sourceName, 
24         const Plasma::DataEngine::Data &data ); 
25
26 private:
27     double m_load;
28 };
29 
30 #endif // LOADLIGHT_H

Es folgen die zwei Slots »sourceAdded()« und »dataUpdated()«. Slots sind Rückfrage-Funktionen, die sich mit einem Signal verbinden. Zeile 27 deklariert die Private-Variable »m_load« dieser Klasse, die den zuletzt abgeholten Belastungsstand des Systems speichert.

In Listing 2 implementieren die Zeilen 4 bis 11 den Konstruktor. Der Einfachheit halber sind der Standardhintergrund und eine Anfangsgröße gesetzt. Der andere Teil der Klasseninitialisierung erfolgt in den Zeilen 13 bis 17 in der »init()«-Methode. Sie fordert die Datenquelle »systemmonitor« an und verbindet das Signal »sourceAdded()« mit dem gleichnamigen Slot. Das bewirkt, dass bei jeder vom Systemmonitor gemeldeten Information der Slot »sourceAdded()« in Aktion tritt: Die Datenquelle sendet dann ein Signal und ruft damit die Funktion »sourceAdded()« in den Zeilen 19 bis 29 auf.

Listing 2:
Loadlight.cpp

01 #include "loadlight.h"
02 #include <QPainter>
03 
04 PlasmaLoadLight::PlasmaLoadLight( QObject *parent,
05   const QVariantList &args )
06     : Plasma::Applet( parent, args ),
07     m_load( 0.75 )
08 {
09  setBackgroundHints( DefaultBackground );
10  resize( 100, 100 );
11 }
12 
13 void PlasmaLoadLight::init()
14 {
15  connect( dataEngine( "systemmonitor" ), SIGNAL(sourceAdded(QString)),
16              this, SLOT(sourceAdded(QString)) );
17 }
18 
19 void PlasmaLoadLight::sourceAdded( const QString &name )
20 {
21  if( name == "cpu/system/loadavg1" )
22  {
23    dataEngine( "systemmonitor" )->connectSource( name, this, 1000 );
24    disconnect( dataEngine( "systemmonitor" )
25                SIGNAL(sourceAdded(QString)),
26                this,
27                SLOT(sourceAdded(QString)) );
28   }
29 }
30 
31 void PlasmaLoadLight::dataUpdated( const QString &sourceName,
32 const Plasma::DataEngine::Data &data )
33 {
34  if( sourceName != "cpu/system/loadavg1" )
35      return;
36  if( data.keys().count() == 0 )
37      return;
38  m_load = data[data.keys()[0]].toDouble();
39  update();
40 }
41 
42 void PlasmaLoadLight::paintInterface( QPainter *painter,
43   const QStyleOptionGraphicsItem *option,
44   const QRect &contentsRect )
45 {
46  if( m_load < 0.5 )
47    painter->setBrush( Qt::green );
48  else if( m_load > 0.95 )
49    painter->setBrush( Qt::red );
50  else
51    painter->setBrush( Qt::yellow );
52    painter->drawEllipse( contentsRect );
53 
54   QFont f;
55   f.setPixelSize( contentsRect.height()/4 );
56   painter->setFont( f );
57   painter->drawText( contentsRect,
58                      Qt::AlignCenter,
59                      QString::number( m_load, 'f', 2 ) );
60 }
61 
62 K_EXPORT_PLASMA_APPLET(loadlight, PlasmaLoadLight)
63 
64 #include "loadlight.moc"

Diesen Artikel als PDF kaufen

Express-Kauf als PDF

Umfang: 5 Heftseiten

Preis € 0,99
(inkl. 19% MwSt.)

Als digitales Abo

Als PDF im Abo bestellen

comments powered by Disqus

Ausgabe 07/2013

Preis € 6,40

Insecurity Bulletin

Insecurity Bulletin

Im Insecurity Bulletin widmet sich Mark Vogelsberger aktuellen Sicherheitslücken sowie Hintergründen und Security-Grundlagen. mehr...

Linux-Magazin auf Facebook