• Skip to content
  • Skip to link menu
KDE 4.1 API Reference
  • KDE API Reference
  • API Reference
  • Sitemap
  • Contact Us
 

Applets

battery.cpp

Go to the documentation of this file.
00001 /***************************************************************************
00002  *   Copyright (C) 2007-2008 by Riccardo Iaconelli <riccardo@kde.org>      *
00003  *   Copyright (C) 2007-2008 by Sebastian Kuegler <sebas@kde.org>          *
00004  *   Copyright (C) 2007 by Luka Renko <lure@kubuntu.org>                   *
00005  *                                                                         *
00006  *   This program is free software; you can redistribute it and/or modify  *
00007  *   it under the terms of the GNU General Public License as published by  *
00008  *   the Free Software Foundation; either version 2 of the License, or     *
00009  *   (at your option) any later version.                                   *
00010  *                                                                         *
00011  *   This program is distributed in the hope that it will be useful,       *
00012  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
00013  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
00014  *   GNU General Public License for more details.                          *
00015  *                                                                         *
00016  *   You should have received a copy of the GNU General Public License     *
00017  *   along with this program; if not, write to the                         *
00018  *   Free Software Foundation, Inc.,                                       *
00019  *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA .        *
00020  ***************************************************************************/
00021 
00022 #include "battery.h"
00023 
00024 #include <QApplication>
00025 #include <QPainter>
00026 #include <QStyleOptionGraphicsItem>
00027 #include <QFont>
00028 #include <QGraphicsSceneHoverEvent>
00029 
00030 #include <KDebug>
00031 #include <KIcon>
00032 #include <KLocalizedString>
00033 #include <KSharedConfig>
00034 #include <KDialog>
00035 #include <KColorScheme>
00036 #include <KConfigDialog>
00037 #include <KGlobalSettings>
00038 
00039 #include <plasma/svg.h>
00040 #include <plasma/theme.h>
00041 #include <plasma/animator.h>
00042 
00043 Battery::Battery(QObject *parent, const QVariantList &args)
00044     : Plasma::Applet(parent, args),
00045       m_batteryStyle(0),
00046       m_theme(0),
00047       m_animId(-1),
00048       m_alpha(1),
00049       m_fadeIn(true),
00050       m_acAnimId(-1),
00051       m_acAlpha(1),
00052       m_acFadeIn(false),
00053       m_batteryAnimId(-1),
00054       m_batteryAlpha(1),
00055       m_batteryFadeIn(true),
00056       m_isHovered(false),
00057       m_numOfBattery(0)
00058 {
00059     kDebug() << "Loading applet battery";
00060     setAcceptsHoverEvents(true);
00061     setHasConfigurationInterface(true);
00062     resize(128, 128);
00063     //setAspectRatioMode(Plasma::ConstrainedSquare );
00064     m_textRect = QRect();
00065 }
00066 
00067 void Battery::init()
00068 {
00069     KConfigGroup cg = config();
00070     m_showBatteryString = cg.readEntry("showBatteryString", false);
00071     m_showMultipleBatteries = cg.readEntry("showMultipleBatteries", true);
00072 
00073     QString svgFile = QString();
00074     if (cg.readEntry("style", 0) == 0) {
00075         m_batteryStyle = OxygenBattery;
00076         svgFile = "widgets/battery-oxygen";
00077     } else {
00078         m_batteryStyle = ClassicBattery;
00079         svgFile = "widgets/battery";
00080     }
00081     m_theme = new Plasma::Svg(this);
00082     m_theme->setImagePath(svgFile);
00083     m_theme->setContainsMultipleImages(false);
00084 
00085     m_theme->resize(contentsRect().size());
00086     m_font = QApplication::font();
00087     m_font.setWeight(QFont::Bold);
00088 
00089     m_boxAlpha = 128;
00090     m_boxHoverAlpha = 192;
00091 
00092     readColors();
00093     connect(Plasma::Theme::defaultTheme(), SIGNAL(themeChanged()), SLOT(readColors()));
00094 
00095     const QStringList& battery_sources = dataEngine("powermanagement")->query(I18N_NOOP("Battery"))[I18N_NOOP("sources")].toStringList();
00096 
00097     //connect sources
00098     connectSources();
00099 
00100     foreach (const QString &battery_source, battery_sources) {
00101         kDebug() << "BatterySource:" << battery_source;
00102         dataUpdated(battery_source, dataEngine("powermanagement")->query(battery_source));
00103     }
00104     dataUpdated(I18N_NOOP("AC Adapter"), dataEngine("powermanagement")->query(I18N_NOOP("AC Adapter")));
00105     m_numOfBattery = battery_sources.size();
00106     kDebug() << battery_sources.size();
00107 }
00108 
00109 void Battery::constraintsEvent(Plasma::Constraints constraints)
00110 {
00111     if (constraints & (Plasma::FormFactorConstraint | Plasma::SizeConstraint)) {
00112         if (formFactor() == Plasma::Vertical) {
00113             setMaximumSize(QWIDGETSIZE_MAX, qMax(m_textRect.height(), contentsRect().width()));
00114             //kDebug() << "Vertical FormFactor";
00115         } else if (formFactor() == Plasma::Horizontal) {
00116             setMaximumSize(qMax(m_textRect.width(), contentsRect().height()), QWIDGETSIZE_MAX);
00117             //kDebug() << "Horizontal FormFactor" << m_textRect.width() << contentsRect().height();
00118         }
00119     }
00120 
00121     if (constraints & (Plasma::SizeConstraint | Plasma::FormFactorConstraint) && m_theme) {
00122         m_theme->resize(contentsRect().size().toSize());
00123         m_font.setPointSize(qMax(KGlobalSettings::smallestReadableFont().pointSize(),
00124                                  qRound(contentsRect().height() / 10)));
00125     }
00126 }
00127 
00128 void Battery::dataUpdated(const QString& source, const Plasma::DataEngine::Data &data)
00129 {
00130     if (source.startsWith(I18N_NOOP("Battery"))) {
00131         m_batteries_data[source] = data;
00132     } else if (source == I18N_NOOP("AC Adapter")) {
00133         m_acadapter_plugged = data[I18N_NOOP("Plugged in")].toBool();
00134         showAcAdapter(m_acadapter_plugged);
00135     } else {
00136         kDebug() << "Applet::Dunno what to do with " << source;
00137     }
00138     update();
00139 }
00140 
00141 void Battery::createConfigurationInterface(KConfigDialog *parent)
00142 {
00143     QWidget *widget = new QWidget();
00144     ui.setupUi(widget);
00145     parent->setButtons( KDialog::Ok | KDialog::Cancel | KDialog::Apply );
00146     parent->addPage(widget, parent->windowTitle(), icon());
00147     connect(parent, SIGNAL(applyClicked()), this, SLOT(configAccepted()));
00148     connect(parent, SIGNAL(okClicked()), this, SLOT(configAccepted()));
00149     ui.styleGroup->setSelected(m_batteryStyle);
00150     ui.showBatteryStringCheckBox->setChecked(m_showBatteryString ? Qt::Checked : Qt::Unchecked);
00151     ui.showMultipleBatteriesCheckBox->setChecked(m_showMultipleBatteries ? Qt::Checked : Qt::Unchecked);
00152 }
00153 
00154 void Battery::configAccepted()
00155 {
00156     KConfigGroup cg = config();
00157 
00158     if (m_showBatteryString != ui.showBatteryStringCheckBox->isChecked()) {
00159         m_showBatteryString = !m_showBatteryString;
00160         cg.writeEntry("showBatteryString", m_showBatteryString);
00161         showLabel(m_showBatteryString);
00162     }
00163 
00164     if (m_showMultipleBatteries != ui.showMultipleBatteriesCheckBox->isChecked()) {
00165         m_showMultipleBatteries = !m_showMultipleBatteries;
00166         cg.writeEntry("showMultipleBatteries", m_showMultipleBatteries);
00167         kDebug() << "Show multiple battery changed: " << m_showMultipleBatteries;
00168     }
00169 
00170     if (ui.styleGroup->selected() != m_batteryStyle) {
00171         QString svgFile = QString();
00172         if (ui.styleGroup->selected() == OxygenBattery) {
00173             svgFile = "widgets/battery-oxygen";
00174         } else {
00175             svgFile = "widgets/battery";
00176         }
00177         if (m_acadapter_plugged) {
00178             showAcAdapter(false);
00179         }
00180         showBattery(false);
00181         m_batteryStyle = ui.styleGroup->selected();
00182         delete m_theme;
00183         m_theme = new Plasma::Svg(this);
00184         m_theme->setImagePath(svgFile);
00185         kDebug() << "Changing theme to " << svgFile;
00186         cg.writeEntry("style", m_batteryStyle);
00187         m_theme->resize(contentsRect().size());
00188         if (m_acadapter_plugged) {
00189             showAcAdapter(true);
00190         }
00191         showBattery(true);
00192     }
00193 
00194     //reconnect sources
00195     disconnectSources();
00196     connectSources();
00197 
00198     emit configNeedsSaving();
00199 }
00200 
00201 void Battery::readColors()
00202 {
00203     m_textColor = Plasma::Theme::defaultTheme()->color(Plasma::Theme::TextColor);
00204     m_boxColor = Plasma::Theme::defaultTheme()->color(Plasma::Theme::BackgroundColor);
00205     m_boxColor.setAlpha(m_boxAlpha);
00206 }
00207 
00208 void Battery::hoverEnterEvent(QGraphicsSceneHoverEvent *event)
00209 {
00210     showLabel(true);
00211     //showAcAdapter(false); // to test the animation without constant plugging
00212     //showBattery(false); // to test the animation without constant plugging
00213     m_isHovered = true;
00214     Applet::hoverEnterEvent(event);
00215 }
00216 
00217 void Battery::hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
00218 {
00219     if (!m_showBatteryString) {
00220         showLabel(false);
00221     }
00222     //showAcAdapter(true); // to test the animation without constant plugging
00223     //showBattery(true); // to test the animation without constant plugging
00224     //m_isHovered = false;
00225     Applet::hoverLeaveEvent(event);
00226 }
00227 
00228 Battery::~Battery()
00229 {
00230 }
00231 
00232 void Battery::showLabel(bool show)
00233 {
00234     if (m_fadeIn == show) {
00235         return;
00236     }
00237     m_fadeIn = show;
00238     const int FadeInDuration = 150;
00239 
00240     if (m_animId != -1) {
00241         Plasma::Animator::self()->stopCustomAnimation(m_animId);
00242     }
00243     m_animId = Plasma::Animator::self()->customAnimation(40 / (1000 / FadeInDuration), FadeInDuration,
00244                                                       Plasma::Animator::EaseOutCurve, this,
00245                                                       "animationUpdate");
00246 }
00247 
00248 QRectF Battery::scaleRectF(const qreal progress, QRectF rect) {
00249     if (progress == 1) {
00250         return rect;
00251     }
00252     // Scale
00253     qreal w = rect.width()*progress;
00254     qreal h = rect.width()*progress;
00255 
00256     // Position centered
00257     rect.setX((rect.width() - w)/2);
00258     rect.setY((rect.height() - h)/2);
00259 
00260     rect.setWidth(w);
00261     rect.setHeight(h);
00262 
00263     return rect;
00264 }
00265 
00266 void Battery::showAcAdapter(bool show)
00267 {
00268     if (m_acFadeIn == show) {
00269         return;
00270     }
00271     m_acFadeIn = show;
00272     const int FadeInDuration = 300;
00273     // As long as the animation is running, we fake it's still plugged in so it gets
00274     // painted in paintInterface()
00275     m_acadapter_plugged = true;
00276 
00277     if (m_acAnimId != -1) {
00278         Plasma::Animator::self()->stopCustomAnimation(m_acAnimId);
00279     }
00280     m_acAnimId = Plasma::Animator::self()->customAnimation(40 / (1000 / FadeInDuration), FadeInDuration,
00281                                                       Plasma::Animator::EaseOutCurve, this,
00282                                                       "acAnimationUpdate");
00283 }
00284 
00285 void Battery::showBattery(bool show)
00286 {
00287     if (m_batteryFadeIn == show) {
00288         return;
00289     }
00290     m_batteryFadeIn = show;
00291     const int FadeInDuration = 300;
00292 
00293     if (m_batteryAnimId != -1) {
00294         Plasma::Animator::self()->stopCustomAnimation(m_batteryAnimId);
00295     }
00296     m_batteryAnimId = Plasma::Animator::self()->customAnimation(40 / (1000 / FadeInDuration), FadeInDuration,
00297                                                       Plasma::Animator::EaseOutCurve, this,
00298                                                       "batteryAnimationUpdate");
00299 }
00300 
00301 void Battery::animationUpdate(qreal progress)
00302 {
00303     if (progress == 1) {
00304         m_animId = -1;
00305     }
00306     if (!m_fadeIn) {
00307         qreal new_alpha = m_fadeIn ? progress : 1 - progress;
00308         m_alpha = qMin(new_alpha, m_alpha);
00309     } else {
00310         m_alpha = m_fadeIn ? progress : 1 - progress;
00311     }
00312     m_alpha = qMax(qreal(0.0), m_alpha);
00313     update();
00314 }
00315 
00316 void Battery::acAnimationUpdate(qreal progress)
00317 {
00318     if (progress == 1) {
00319         m_acAnimId = -1;
00320     }
00321     m_acAlpha = m_acFadeIn ? progress : 1 - progress;
00322     // During the fadeout animation, we had set it to true (and lie)
00323     // now the animation has ended, we _really_ set it to not show the adapter
00324     if (!m_acFadeIn && (progress == 1)) {
00325         m_acadapter_plugged = false;
00326     }
00327     update();
00328 }
00329 
00330 void Battery::batteryAnimationUpdate(qreal progress)
00331 {
00332     if (progress == 1) {
00333         m_batteryAnimId = -1;
00334     }
00335     m_batteryAlpha = m_batteryFadeIn ? progress : 1 - progress;
00336     update();
00337 }
00338 
00339 void Battery::paintLabel(QPainter *p, const QRect &contentsRect, const QString& labelText)
00340 {
00341     // Store font size, we want to restore it shortly
00342     int original_font_size = m_font.pointSize();
00343 
00344     // Fonts smaller than smallestReadableFont don't make sense.
00345     m_font.setPointSize(qMax(KGlobalSettings::smallestReadableFont().pointSize(), m_font.pointSize()));
00346     QFontMetrics fm(m_font);
00347     qreal text_width = fm.width(labelText);
00348 
00349     // Longer texts get smaller fonts
00350     if (labelText.length() > 4) {
00351         if (original_font_size/1.5 < KGlobalSettings::smallestReadableFont().pointSize()) {
00352             m_font.setPointSize((KGlobalSettings::smallestReadableFont().pointSize()));
00353         } else {
00354             m_font.setPointSizeF(original_font_size/1.5);
00355         }
00356         fm = QFontMetrics(m_font);
00357         text_width = (fm.width(labelText) * 1.2);
00358     } else {
00359         // Smaller texts get a wider box
00360         text_width = (text_width * 1.4);
00361     }
00362     if (formFactor() == Plasma::Horizontal ||
00363         formFactor() == Plasma::Vertical) {
00364         m_font = KGlobalSettings::smallestReadableFont();
00365         m_font.setWeight(QFont::Bold);
00366         fm = QFontMetrics(m_font);
00367         text_width = (fm.width(labelText)+8);
00368     }
00369     p->setFont(m_font);
00370 
00371     // Let's find a good position for painting the background
00372     m_textRect = QRectF(qMax(qreal(0.0), contentsRect.left() + (contentsRect.width() - text_width) / 2),
00373                             contentsRect.top() + ((contentsRect.height() - (int)fm.height()) / 2 * 0.9),
00374                             qMin(contentsRect.width(), (int)text_width),
00375                             fm.height() * 1.2 );
00376 
00377     // Poor man's highlighting
00378     m_boxColor.setAlphaF(m_alpha);
00379     p->setPen(m_boxColor);
00380     m_boxColor.setAlphaF(m_alpha*0.5);
00381     p->setBrush(m_boxColor);
00382 
00383     // Find sensible proportions for the rounded corners
00384     float round_prop = m_textRect.width() / m_textRect.height();
00385 
00386     // Tweak the rounding edge a bit with the proportions of the textbox
00387     qreal round_radius = 35.0;
00388     p->drawRoundedRect(m_textRect, round_radius / round_prop, round_radius, Qt::RelativeSize);
00389 
00390     m_textColor.setAlphaF(m_alpha);
00391     p->setPen(m_textColor);
00392     p->drawText(m_textRect, Qt::AlignCenter, labelText);
00393 
00394     // Reset font and box
00395     m_font.setPointSize(original_font_size);
00396     m_boxColor.setAlpha(m_boxAlpha);
00397 }
00398 
00399 void Battery::paintBattery(QPainter *p, const QRect &contentsRect, const int batteryPercent, const bool plugState)
00400 {
00401     QString fill_element = QString();
00402     if (plugState && m_theme->hasElement("Battery")) {
00403         m_theme->paint(p, scaleRectF(m_batteryAlpha, contentsRect), "Battery");
00404 
00405         if (m_batteryStyle == OxygenBattery) {
00406             if (batteryPercent > 95) {
00407                 fill_element = "Fill100";
00408             } else if (batteryPercent > 80) {
00409                 fill_element = "Fill80";
00410             } else if (batteryPercent > 50) {
00411                 fill_element = "Fill60";
00412             } else if (batteryPercent > 20) {
00413                 fill_element = "Fill40";
00414             } else if (batteryPercent > 10) {
00415                 fill_element = "Fill20";
00416             } // Don't show a fillbar below 11% charged
00417         } else { // OxyenStyle
00418             if (batteryPercent > 95) {
00419                 fill_element = "Fill100";
00420             } else if (batteryPercent > 90) {
00421                 fill_element = "Fill90";
00422             } else if (batteryPercent > 80) {
00423                 fill_element = "Fill80";
00424             } else if (batteryPercent > 70) {
00425                 fill_element = "Fill70";
00426             } else if (batteryPercent > 55) {
00427                 fill_element = "Fill60";
00428             } else if (batteryPercent > 40) {
00429                 fill_element = "Fill50";
00430             } else if (batteryPercent > 30) {
00431                 fill_element = "Fill40";
00432             } else if (batteryPercent > 20) {
00433                 fill_element = "Fill30";
00434             } else if (batteryPercent > 10) {
00435                 fill_element = "Fill20";
00436             } else if (batteryPercent >= 5) {
00437                 fill_element = "Fill10";
00438             } // Lower than 5%? Show no fillbar.
00439         }
00440     }
00441     //kDebug() << "plugState:" << plugState;
00442 
00443     // Now let's find out which fillstate to show
00444     if (plugState && !fill_element.isEmpty()) {
00445         if (m_theme->hasElement(fill_element)) {
00446             m_theme->paint(p, scaleRectF(m_batteryAlpha, contentsRect), fill_element);
00447         } else {
00448             kDebug() << fill_element << " does not exist in svg";
00449         }
00450     }
00451 
00452     if (m_acadapter_plugged) {
00453         //QRectF ac_rect = QRectF(contentsRect.topLeft(), QSizeF(contentsRect.width()*m_acAlpha, contentsRect.height()*m_acAlpha));
00454         m_theme->paint(p, scaleRectF(m_acAlpha, contentsRect), "AcAdapter");
00455     }
00456 
00457     // For small FormFactors, we're drawing a shadow
00458     if (formFactor() == Plasma::Vertical ||
00459         formFactor() == Plasma::Horizontal) {
00460         if (plugState) {
00461             m_theme->paint(p, contentsRect, "Shadow");
00462         }
00463     }
00464     if (plugState && m_theme->hasElement("Overlay")) {
00465         m_theme->paint(p, scaleRectF(m_batteryAlpha, contentsRect), "Overlay");
00466     }
00467 }
00468 
00469 void Battery::paintInterface(QPainter *p, const QStyleOptionGraphicsItem *option, const QRect &contentsRect)
00470 {
00471     Q_UNUSED( option );
00472 
00473     p->setRenderHint(QPainter::SmoothPixmapTransform);
00474     p->setRenderHint(QPainter::Antialiasing);
00475 
00476     if (m_numOfBattery == 0) {
00477         QRectF ac_contentsRect(contentsRect.topLeft(), QSizeF(qMax(qreal(0.0), contentsRect.width() * m_acAlpha), qMax(qreal(0.0), contentsRect.height() * m_acAlpha)));
00478         if (m_acadapter_plugged) {
00479             m_theme->paint(p, ac_contentsRect, "AcAdapter");
00480         }
00481         // Show that there's no battery
00482         paintLabel(p, contentsRect, I18N_NOOP("n/a"));
00483         return;
00484     }
00485 
00486     if (m_showMultipleBatteries) {
00487         // paint each battery with own charge level
00488         int battery_num = 0;
00489         int width = contentsRect.width()/m_numOfBattery;
00490         QHashIterator<QString, QHash<QString, QVariant > > battery_data(m_batteries_data);
00491         while (battery_data.hasNext()) {
00492             battery_data.next();
00493             QRect corect = QRect(contentsRect.left()+battery_num*width,
00494                                  contentsRect.top(),
00495                                  width, contentsRect.height());
00496 
00497             // paint battery with appropriate charge level
00498             paintBattery(p, corect, battery_data.value()[I18N_NOOP("Percent")].toInt(), battery_data.value()[I18N_NOOP("Plugged in")].toBool());
00499 
00500             if (m_showBatteryString || m_isHovered) {
00501                 // Show the charge percentage with a box on top of the battery
00502                 QString batteryLabel;
00503                 if (battery_data.value()[I18N_NOOP("Plugged in")].toBool()) {
00504                     batteryLabel = battery_data.value()[I18N_NOOP("Percent")].toString();
00505                     batteryLabel.append("%");
00506                 } else {
00507                     batteryLabel = I18N_NOOP("n/a");
00508                 }
00509                 paintLabel(p, corect, batteryLabel);
00510             }
00511             ++battery_num;
00512         }
00513     } else {
00514         // paint only one battery and show cumulative charge level
00515         int battery_num = 0;
00516         int battery_charge = 0;
00517         bool has_battery = false;
00518         QHashIterator<QString, QHash<QString, QVariant > > battery_data(m_batteries_data);
00519         while (battery_data.hasNext()) {
00520             battery_data.next();
00521             if (battery_data.value()[I18N_NOOP("Plugged in")].toBool()) {
00522                 battery_charge += battery_data.value()[I18N_NOOP("Percent")].toInt();
00523                 has_battery = true;
00524                 ++battery_num;
00525             }
00526         }
00527         if (battery_num > 0) {
00528             battery_charge = battery_charge / battery_num;
00529         }
00530         // paint battery with appropriate charge level
00531         paintBattery(p, contentsRect,  battery_charge, has_battery);
00532         if (m_showBatteryString || m_isHovered) {
00533             // Show the charge percentage with a box on top of the battery
00534             QString batteryLabel;
00535             if(has_battery) {
00536                 batteryLabel = QString::number(battery_charge);
00537                 batteryLabel.append("%");
00538             } else {
00539                 batteryLabel = I18N_NOOP("n/a");
00540             }
00541             paintLabel(p, contentsRect, batteryLabel);
00542         }
00543     }
00544 }
00545 
00546 void Battery::connectSources() {
00547     const QStringList& battery_sources = dataEngine("powermanagement")->query(I18N_NOOP("Battery"))[I18N_NOOP("sources")].toStringList();
00548 
00549     foreach (const QString &battery_source, battery_sources) {
00550         dataEngine("powermanagement")->connectSource(battery_source, this);
00551     }
00552 
00553     dataEngine("powermanagement")->connectSource(I18N_NOOP("AC Adapter"), this);
00554 }
00555 
00556 void Battery::disconnectSources()
00557 {
00558     const QStringList& battery_sources = dataEngine("powermanagement")->query(I18N_NOOP("Battery"))[I18N_NOOP("sources")].toStringList();
00559 
00560     foreach (const QString &battery_source ,battery_sources) {
00561         dataEngine("powermanagement")->disconnectSource(battery_source, this);
00562     }
00563 
00564     dataEngine("powermanagement")->disconnectSource(I18N_NOOP("AC Adapter"), this);
00565 }
00566 
00567 #include "battery.moc"

Applets

Skip menu "Applets"
  • Main Page
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members

API Reference

Skip menu "API Reference"
  • KWin
  •   KWin Libraries
  • Libraries
  •   libkworkspace
  •   libplasma
  •   libsolidcontrol
  •   libtaskmanager
  • Plasma
  •   Animators
  •   Applets
  •   Engines
  • Solid Modules
Generated for API Reference by doxygen 1.5.4
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal