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

Applets

pager.cpp

Go to the documentation of this file.
00001 /***************************************************************************
00002  *   Copyright (C) 2007 by Daniel Laidig <d.laidig@gmx.de>                 *
00003  *                                                                         *
00004  *   This program is free software; you can redistribute it and/or modify  *
00005  *   it under the terms of the GNU General Public License as published by  *
00006  *   the Free Software Foundation; either version 2 of the License, or     *
00007  *   (at your option) any later version.                                   *
00008  *                                                                         *
00009  *   This program is distributed in the hope that it will be useful,       *
00010  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
00011  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
00012  *   GNU General Public License for more details.                          *
00013  *                                                                         *
00014  *   You should have received a copy of the GNU General Public License     *
00015  *   along with this program; if not, write to the                         *
00016  *   Free Software Foundation, Inc.,                                       *
00017  *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA .        *
00018  ***************************************************************************/
00019 
00020 #include "pager.h"
00021 
00022 #include <math.h>
00023 
00024 #include <QApplication>
00025 #include <QPainter>
00026 #include <QStyleOptionGraphicsItem>
00027 #include <QFont>
00028 #include <QGraphicsSceneHoverEvent>
00029 #include <QTimer>
00030 #include <QX11Info>
00031 
00032 #include <KDialog>
00033 #include <KColorScheme>
00034 #include <KConfigDialog>
00035 #include <KGlobalSettings>
00036 #include <KSharedConfig>
00037 #include <KWindowSystem>
00038 #include <NETRootInfo>
00039 #include <KToolInvocation>
00040 #include <kmanagerselection.h>
00041 
00042 #include <Plasma/Svg>
00043 #include <Plasma/FrameSvg>
00044 #include <Plasma/PaintUtils>
00045 #include <Plasma/Theme>
00046 #include <Plasma/ToolTipManager>
00047 #include <Plasma/Animator>
00048 
00049 #include <kephal/screens.h>
00050 
00051 #include <taskmanager/task.h>
00052 
00053 const int FAST_UPDATE_DELAY = 200;
00054 const int UPDATE_DELAY = 500;
00055 const int DRAG_SWITCH_DELAY = 1000;
00056 
00057 Pager::Pager(QObject *parent, const QVariantList &args)
00058     : Plasma::Applet(parent, args),
00059       m_displayedText(None),
00060       m_showWindowIcons(false),
00061       m_showOwnBackground(false),
00062       m_rows(2),
00063       m_columns(0),
00064       m_hoverIndex(-1),
00065       m_colorScheme(0),
00066       m_dragId(0),
00067       m_dirtyDesktop(-1),
00068       m_dragStartDesktop(-1),
00069       m_dragHighlightedDesktop(-1),
00070       m_dragSwitchDesktop(-1)
00071 {
00072     setAcceptsHoverEvents(true);
00073     setAcceptDrops(true);
00074     setHasConfigurationInterface(true);
00075 
00076     m_background = new Plasma::FrameSvg(this);
00077     m_background->setImagePath("widgets/pager");
00078     m_background->setCacheAllRenderedFrames(true);
00079 
00080     // initialize with a decent default
00081     m_desktopCount = KWindowSystem::numberOfDesktops();
00082     m_size = QSizeF(176, 88);
00083     resize(m_size);
00084 }
00085 
00086 void Pager::init()
00087 {
00088     createMenu();
00089 
00090     KConfigGroup cg = config();
00091     m_displayedText = (DisplayedText)cg.readEntry("displayedText", (int)m_displayedText);
00092     m_showWindowIcons = cg.readEntry("showWindowIcons", m_showWindowIcons);
00093     m_rows = globalConfig().readEntry("rows", m_rows);
00094 
00095     if (m_rows < 1) {
00096         m_rows = 1;
00097     } else if (m_rows > m_desktopCount) {
00098         m_rows = m_desktopCount;
00099     }
00100 
00101     m_timer = new QTimer(this);
00102     m_timer->setSingleShot(true);
00103     connect(m_timer, SIGNAL(timeout()), this, SLOT(recalculateWindowRects()));
00104 
00105     m_dragSwitchTimer = new QTimer(this);
00106     m_dragSwitchTimer->setSingleShot(true);
00107     connect(m_dragSwitchTimer, SIGNAL(timeout()), this, SLOT(dragSwitch()));
00108 
00109     connect(KWindowSystem::self(), SIGNAL(currentDesktopChanged(int)), this, SLOT(currentDesktopChanged(int)));
00110     connect(KWindowSystem::self(), SIGNAL(windowAdded(WId)), this, SLOT(windowAdded(WId)));
00111     connect(KWindowSystem::self(), SIGNAL(windowRemoved(WId)), this, SLOT(windowRemoved(WId)));
00112     connect(KWindowSystem::self(), SIGNAL(activeWindowChanged(WId)), this, SLOT(activeWindowChanged(WId)));
00113     connect(KWindowSystem::self(), SIGNAL(numberOfDesktopsChanged(int)), this, SLOT(numberOfDesktopsChanged(int)));
00114     connect(KWindowSystem::self(), SIGNAL(desktopNamesChanged()), this, SLOT(desktopNamesChanged()));
00115     connect(KWindowSystem::self(), SIGNAL(stackingOrderChanged()), this, SLOT(stackingOrderChanged()));
00116     connect(KWindowSystem::self(), SIGNAL(windowChanged(WId,unsigned int)), this, SLOT(windowChanged(WId,unsigned int)));
00117     connect(KWindowSystem::self(), SIGNAL(showingDesktopChanged(bool)), this, SLOT(showingDesktopChanged(bool)));
00118     connect(Kephal::Screens::self(), SIGNAL(screenAdded(Kephal::Screen *)), SLOT(desktopsSizeChanged()));
00119     connect(Kephal::Screens::self(), SIGNAL(screenRemoved(int)), SLOT(desktopsSizeChanged()));
00120     connect(Kephal::Screens::self(), SIGNAL(screenResized(Kephal::Screen *, QSize, QSize)), SLOT(desktopsSizeChanged()));
00121     connect(Kephal::Screens::self(), SIGNAL(screenMoved(Kephal::Screen *, QPoint, QPoint)), SLOT(desktopsSizeChanged()));
00122 
00123     m_desktopLayoutOwner = new KSelectionOwner( QString( "_NET_DESKTOP_LAYOUT_S%1" )
00124         .arg( QX11Info::appScreen()).toLatin1().constData(), QX11Info::appScreen(), this );
00125     connect( m_desktopLayoutOwner, SIGNAL( lostOwnership()), SLOT( lostDesktopLayoutOwner()));
00126     if ( !m_desktopLayoutOwner->claim( false ))
00127         lostDesktopLayoutOwner();
00128 
00129     connect(Plasma::Theme::defaultTheme(), SIGNAL(themeChanged()), this, SLOT(themeRefresh()));
00130 
00131     recalculateGeometry();
00132 
00133     m_currentDesktop = KWindowSystem::currentDesktop();
00134 }
00135 
00136 Pager::~Pager()
00137 {
00138     delete m_colorScheme;
00139 }
00140 
00141 void Pager::constraintsEvent(Plasma::Constraints constraints)
00142 {
00143     if (constraints & Plasma::SizeConstraint) {
00144         recalculateGeometry();
00145         recalculateWindowRects();
00146         if (m_background->hasElementPrefix(QString())) {
00147             m_background->setElementPrefix(QString());
00148             m_background->resizeFrame(size());
00149         }
00150     }
00151     if (constraints & Plasma::FormFactorConstraint) {
00152         if (formFactor() == Plasma::Horizontal) {
00153             setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Expanding);
00154         } else if (formFactor() == Plasma::Vertical) {
00155             setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
00156         } else {
00157             setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
00158         }
00159     }
00160 }
00161 
00162 KColorScheme *Pager::colorScheme()
00163 {
00164     if (!m_colorScheme) {
00165         m_colorScheme = new KColorScheme(QPalette::Active, KColorScheme::View, Plasma::Theme::defaultTheme()->colorScheme());
00166     }
00167 
00168     return m_colorScheme;
00169 }
00170 
00171 void Pager::createMenu()
00172 {
00173     QAction* configureDesktop = new QAction(SmallIcon("configure"),i18n("&Configure Desktops..."), this);
00174     m_actions.append(configureDesktop);
00175     connect(configureDesktop, SIGNAL(triggered(bool)), this , SLOT(slotConfigureDesktop()));
00176 }
00177 
00178 QList<QAction*> Pager::contextualActions()
00179 {
00180   return m_actions;
00181 }
00182 
00183 void Pager::slotConfigureDesktop()
00184 {
00185   QString error;
00186   KToolInvocation::startServiceByDesktopName("desktop", QStringList(), &error);
00187 }
00188 
00189 void Pager::createConfigurationInterface(KConfigDialog *parent)
00190 {
00191     QWidget *widget = new QWidget();
00192     ui.setupUi(widget);
00193     parent->addPage(widget, i18n("General"), icon());
00194     connect(parent, SIGNAL(applyClicked()), this, SLOT(configAccepted()));
00195     connect(parent, SIGNAL(okClicked()), this, SLOT(configAccepted()));
00196     connect(ui.configureDesktopsButton, SIGNAL(clicked()), SLOT(slotConfigureDesktop()));
00197 
00198     switch (m_displayedText){
00199         case Number:
00200             ui. desktopNumberRadioButton->setChecked(true);
00201             break;
00202 
00203         case Name:
00204             ui.desktopNameRadioButton->setChecked(true);
00205             break;
00206 
00207         case None:
00208             ui.displayNoneRadioButton->setChecked(true);
00209             break;
00210     }
00211 
00212     ui.showWindowIconsCheckBox->setChecked(m_showWindowIcons);
00213     ui.spinRows->setValue(m_rows);
00214     ui.spinRows->setMaximum(m_desktopCount);
00215 }
00216 
00217 void Pager::recalculateGeometry()
00218 {
00219     if (!m_rects.isEmpty() && geometry().size() == m_size) {
00220         //kDebug() << "leaving because" << !m_rects.isEmpty() << " and " << contentSize() << "==" << m_size;
00221         return;
00222     }
00223 
00224     int padding = 2; // Space between miniatures of desktops
00225     int textMargin = 3; // Space between name of desktop and border
00226     int columns = m_desktopCount / m_rows + m_desktopCount % m_rows;
00227     int rows = m_rows;
00228 
00229     //inverse rows and columns in vertical panel
00230     if (formFactor() == Plasma::Vertical) {
00231         rows = columns;
00232         columns = m_rows;
00233     }
00234 
00235     qreal leftMargin = 0;
00236     qreal topMargin = 0;
00237     qreal rightMargin = 0;
00238     qreal bottomMargin = 0;
00239 
00240     if (formFactor() == Plasma::Vertical || formFactor() == Plasma::Horizontal) {
00241         m_background->setElementPrefix(QString());
00242         m_background->getMargins(leftMargin, topMargin, rightMargin, bottomMargin);
00243 
00244         qreal ratio = (qreal)Kephal::ScreenUtils::desktopGeometry().width() / (qreal)Kephal::ScreenUtils::desktopGeometry().height();
00245 
00246         if (formFactor() == Plasma::Vertical) {
00247             qreal optimalSize = (geometry().width() - KIconLoader::SizeSmall*ratio * columns + padding*(columns-1)) / 2;
00248 
00249             if (optimalSize < leftMargin || optimalSize < rightMargin) {
00250                 leftMargin = rightMargin = qMax(qreal(0), optimalSize);
00251                 m_showOwnBackground = false;
00252             }
00253         } else if (formFactor() == Plasma::Horizontal) {
00254             qreal optimalSize = (geometry().height() - KIconLoader::SizeSmall*rows + padding*(rows-1)) / 2;
00255 
00256             if (optimalSize < topMargin || optimalSize < bottomMargin) {
00257                 topMargin = bottomMargin =  qMax(qreal(0), optimalSize);
00258                 m_showOwnBackground = false;
00259             }
00260         } else {
00261             m_showOwnBackground = true;
00262         }
00263     } else {
00264         getContentsMargins(&leftMargin, &topMargin, &rightMargin, &bottomMargin);
00265     }
00266 
00267     qreal itemHeight;
00268     qreal itemWidth;
00269 
00270     if (formFactor() == Plasma::Vertical) {
00271         itemWidth = (contentsRect().width() - leftMargin - rightMargin - padding * (columns - 1)) / columns;
00272         m_widthScaleFactor = itemWidth / Kephal::ScreenUtils::desktopGeometry().width();
00273         itemHeight = Kephal::ScreenUtils::desktopGeometry().height() * m_widthScaleFactor;
00274         m_heightScaleFactor = m_widthScaleFactor;
00275     } else {
00276         itemHeight = (contentsRect().height() - topMargin - bottomMargin - padding * (rows - 1)) / rows;
00277         m_heightScaleFactor = itemHeight / Kephal::ScreenUtils::desktopGeometry().height();
00278         itemWidth = Kephal::ScreenUtils::desktopGeometry().width() * m_heightScaleFactor;
00279         if (m_displayedText == Name) {
00280             // When containment is in this position we are not limited by low width and we can
00281             // afford increasing width of applet to be able to display every name of desktops
00282             for (int i = 0; i < m_desktopCount; i++) {
00283                 QFontMetricsF metrics(KGlobalSettings::taskbarFont());
00284                 QSizeF textSize = metrics.size(Qt::TextSingleLine, KWindowSystem::desktopName(i+1));
00285                 if (textSize.width() + textMargin * 2 > itemWidth) {
00286                      itemWidth = textSize.width() + textMargin * 2;
00287                 }
00288             }
00289         }
00290         m_widthScaleFactor = itemWidth / Kephal::ScreenUtils::desktopGeometry().width();
00291     }
00292 
00293     m_rects.clear();
00294     m_animations.clear();
00295     QRectF itemRect(QPoint(leftMargin, topMargin) , QSize(floor(itemWidth), floor(itemHeight)));
00296     for (int i = 0; i < m_desktopCount; i++) {
00297         itemRect.moveLeft(leftMargin + floor(i % columns  * (itemWidth + padding)));
00298         itemRect.moveTop(topMargin + floor(i / columns * (itemHeight + padding)));
00299         m_rects.append(itemRect);
00300         AnimInfo anim;
00301         anim.animId = -1;
00302         anim.fadeIn = true;
00303         anim.alpha = 0;
00304         m_animations.append(anim);
00305     }
00306 
00307     //Resize background svgs as needed
00308     if (m_background->hasElementPrefix("normal")) {
00309         m_background->setElementPrefix("normal");
00310         m_background->resizeFrame(itemRect.size());
00311     }
00312 
00313     if (m_background->hasElementPrefix("active")) {
00314         m_background->setElementPrefix("active");
00315         m_background->resizeFrame(itemRect.size());
00316     }
00317 
00318     if (m_background->hasElementPrefix("hover")) {
00319         m_background->setElementPrefix("hover");
00320         m_background->resizeFrame(itemRect.size());
00321     }
00322 
00323     m_size = QSizeF(ceil(columns * itemWidth + padding * (columns - 1) + leftMargin + rightMargin),
00324                     ceil(rows * itemHeight + padding * (rows - 1) + topMargin + bottomMargin));
00325 
00326     //kDebug() << "new size set" << m_size << m_rows << m_columns << columns << itemWidth;
00327 
00328     resize(m_size);
00329     setPreferredSize(m_size);
00330     if (m_desktopLayoutOwner && columns != m_columns) {
00331         // must own manager selection before setting global desktop layout
00332         m_columns = columns;
00333         NET::Orientation orient = NET::OrientationHorizontal;
00334         NETRootInfo i( QX11Info::display(), 0 );
00335         i.setDesktopLayout( orient, columns, rows, NET::DesktopLayoutCornerTopLeft );
00336     }
00337 }
00338 
00339 void Pager::recalculateWindowRects()
00340 {
00341     QList<WId> windows = KWindowSystem::stackingOrder();
00342     m_windowRects.clear();
00343     for (int i = 0; i < m_desktopCount; i++) {
00344         m_windowRects.append(QList<QPair<WId, QRect> >());
00345     }
00346     m_activeWindows.clear();
00347     m_windowInfo.clear();
00348     foreach(WId window, windows) {
00349         KWindowInfo info = KWindowSystem::windowInfo(window, NET::WMGeometry | NET::WMFrameExtents | NET::WMWindowType | NET::WMDesktop | NET::WMState | NET::XAWMState | NET::WMVisibleName);
00350         NET::WindowType type = info.windowType(NET::NormalMask | NET::DialogMask | NET::OverrideMask |
00351                                                NET::UtilityMask | NET::DesktopMask | NET::DockMask |
00352                                                NET::TopMenuMask | NET::SplashMask | NET::ToolbarMask |
00353                                                NET::MenuMask);
00354 
00355         // the reason we don't check for -1 or Net::Unknown here is that legitimate windows, such
00356         // as some java application windows, may not have a type set for them.
00357         // apparently sane defaults on properties is beyond the wisdom of x11.
00358         if (type == NET::Desktop || type == NET::Dock || type == NET::TopMenu ||
00359             type == NET::Splash || type == NET::Menu || type == NET::Toolbar ||
00360             info.hasState(NET::SkipPager) || info.isMinimized()) {
00361             continue;
00362         }
00363 
00364         for (int i = 0; i < m_desktopCount; i++) {
00365             if (!info.isOnDesktop(i+1)) {
00366                 continue;
00367             }
00368 
00369             QRect windowRect = info.frameGeometry();
00370 
00371             if (KWindowSystem::mapViewport()) {
00372                 windowRect = fixViewportPosition( windowRect );
00373             }
00374 
00375             windowRect = QRectF(windowRect.x() * m_widthScaleFactor,
00376                                 windowRect.y() * m_heightScaleFactor,
00377                                 windowRect.width() * m_widthScaleFactor,
00378                                 windowRect.height() * m_heightScaleFactor).toRect();
00379             windowRect.translate(m_rects[i].topLeft().toPoint());
00380             m_windowRects[i].append(QPair<WId, QRect>(window, windowRect));
00381             if (window == KWindowSystem::activeWindow()) {
00382                 m_activeWindows.append(windowRect);
00383             }
00384             m_windowInfo.append(info);
00385         }
00386     }
00387 
00388     update();
00389 }
00390 
00391 void Pager::configAccepted()
00392 {
00393     KConfigGroup cg = config();
00394     bool changed = false;
00395 
00396     DisplayedText displayedText;
00397 
00398     if (ui.desktopNumberRadioButton->isChecked()){
00399         displayedText = Number;
00400 
00401     }else if (ui.desktopNameRadioButton->isChecked()){
00402         displayedText = Name;
00403 
00404     }else{
00405         displayedText = None;
00406     }
00407 
00408     if ((int)m_displayedText != (int)displayedText) {
00409         m_displayedText = displayedText;
00410         cg.writeEntry("displayedText", (int)m_displayedText);
00411         changed = true;
00412     }
00413 
00414     if (m_showWindowIcons != ui.showWindowIconsCheckBox->isChecked()) {
00415         m_showWindowIcons = ui.showWindowIconsCheckBox->isChecked();
00416         cg.writeEntry("showWindowIcons", m_showWindowIcons);
00417         changed = true;
00418     }
00419 
00420     // we need to keep all pager applets consistent since this affects
00421     // the layout of the desktops as used by the window manager,
00422     // so we store the row count in the applet global configuration
00423     if (m_rows != ui.spinRows->value()) {
00424         KConfigGroup globalcg = globalConfig();
00425         m_rows = ui.spinRows->value();
00426         if (m_rows > m_desktopCount) {
00427             m_rows = m_desktopCount;
00428         }
00429         globalcg.writeEntry("rows", m_rows);
00430         changed = true;
00431     }
00432 
00433     if (changed) {
00434         configNeedsSaving();
00435         // force an update
00436         m_columns = 0;
00437         m_size = QSizeF(-1, -1);
00438         recalculateGeometry();
00439         recalculateWindowRects();
00440         update();
00441     }
00442 }
00443 
00444 void Pager::currentDesktopChanged(int desktop)
00445 {
00446     if (desktop < 1) {
00447         return; // bogus value, don't accept it
00448     }
00449 
00450     m_currentDesktop = desktop;
00451     m_dirtyDesktop = -1;
00452 
00453     if (!m_timer->isActive()) {
00454         m_timer->start(FAST_UPDATE_DELAY);
00455     }
00456 }
00457 
00458 void Pager::windowAdded(WId id)
00459 {
00460     Q_UNUSED(id)
00461 
00462     KWindowInfo info = KWindowSystem::windowInfo(id, NET::WMGeometry | NET::WMFrameExtents | NET::WMWindowType | NET::WMDesktop | NET::WMState | NET::XAWMState);
00463     m_dirtyDesktop = info.desktop() - 1;
00464 
00465     if (!m_timer->isActive()) {
00466         m_timer->start(FAST_UPDATE_DELAY);
00467     }
00468 }
00469 
00470 void Pager::windowRemoved(WId id)
00471 {
00472     Q_UNUSED(id)
00473 
00474     KWindowInfo info = KWindowSystem::windowInfo(id, NET::WMGeometry | NET::WMFrameExtents | NET::WMWindowType | NET::WMDesktop | NET::WMState | NET::XAWMState);
00475     m_dirtyDesktop = info.desktop() - 1;
00476 
00477     if (!m_timer->isActive()) {
00478         m_timer->start(FAST_UPDATE_DELAY);
00479     }
00480 }
00481 
00482 void Pager::activeWindowChanged(WId id)
00483 {
00484     Q_UNUSED(id)
00485 
00486     KWindowInfo info = KWindowSystem::windowInfo(id, NET::WMGeometry | NET::WMFrameExtents | NET::WMWindowType | NET::WMDesktop | NET::WMState | NET::XAWMState);
00487     m_dirtyDesktop = info.desktop() - 1;
00488 
00489     if (!m_timer->isActive()) {
00490         m_timer->start(FAST_UPDATE_DELAY);
00491     }
00492 }
00493 
00494 void Pager::numberOfDesktopsChanged(int num)
00495 {
00496     if (num < 1) {
00497         return; // refuse to update to zero desktops
00498     }
00499 
00500     m_dirtyDesktop = -1;
00501     m_desktopCount = num;
00502 
00503     if (m_rows > m_desktopCount) {
00504         m_rows = m_desktopCount;
00505     }
00506 
00507     m_rects.clear();
00508     recalculateGeometry();
00509     recalculateWindowRects();
00510 }
00511 
00512 void Pager::desktopNamesChanged()
00513 {
00514     m_dirtyDesktop = -1;
00515 
00516     m_rects.clear();
00517     recalculateGeometry();
00518 
00519     if (!m_timer->isActive()) {
00520         m_timer->start(UPDATE_DELAY);
00521     }
00522 }
00523 
00524 void Pager::stackingOrderChanged()
00525 {
00526     m_dirtyDesktop = -1;
00527 
00528     if (!m_timer->isActive()) {
00529         m_timer->start(FAST_UPDATE_DELAY);
00530     }
00531 }
00532 
00533 void Pager::windowChanged(WId id, unsigned int properties)
00534 {
00535     Q_UNUSED(id)
00536 
00537     if (properties & NET::WMGeometry) {
00538         KWindowInfo info = KWindowSystem::windowInfo(id, NET::WMGeometry | NET::WMFrameExtents | NET::WMWindowType | NET::WMDesktop | NET::WMState | NET::XAWMState);
00539         m_dirtyDesktop = info.desktop() - 1;
00540     } else {
00541         m_dirtyDesktop = -1;
00542     }
00543 
00544     if (properties & NET::WMGeometry ||
00545         properties & NET::WMDesktop) {
00546         if (!m_timer->isActive()) {
00547             m_timer->start(UPDATE_DELAY);
00548         }
00549     }
00550 }
00551 
00552 void Pager::showingDesktopChanged(bool showing)
00553 {
00554     m_dirtyDesktop = -1;
00555 
00556     Q_UNUSED(showing)
00557     if (!m_timer->isActive()) {
00558         m_timer->start(UPDATE_DELAY);
00559     }
00560 }
00561 
00562 void Pager::desktopsSizeChanged()
00563 {
00564     m_dirtyDesktop = -1;
00565 
00566     m_rects.clear();
00567     recalculateGeometry();
00568 
00569     if (!m_timer->isActive()) {
00570         m_timer->start(UPDATE_DELAY);
00571     }
00572 }
00573 
00574 void Pager::mousePressEvent(QGraphicsSceneMouseEvent *event)
00575 {
00576     if (event->buttons() != Qt::RightButton)
00577     {
00578         for (int i = 0; i < m_rects.count(); ++i) {
00579             if (m_rects[i].contains(event->pos())) {
00580                 m_dragStartDesktop = m_dragHighlightedDesktop = i;
00581                 m_dragOriginalPos = m_dragCurrentPos = event->pos();
00582                 if (m_dragOriginal.isEmpty()) {
00583                     m_dragOriginal = m_rects[i].toRect();
00584                 }
00585 
00586                 update();
00587                 return;
00588             }
00589         }
00590     }
00591     Applet::mousePressEvent(event);
00592 }
00593 
00594 void Pager::wheelEvent(QGraphicsSceneWheelEvent *e)
00595 {
00596     int newDesk;
00597     int desktops = KWindowSystem::numberOfDesktops();
00598 
00599     /*
00600        if (m_kwin->numberOfViewports(0).width() * m_kwin->numberOfViewports(0).height() > 1 )
00601        desktops = m_kwin->numberOfViewports(0).width() * m_kwin->numberOfViewports(0).height();
00602        */
00603     if (e->delta() < 0) {
00604         newDesk = m_currentDesktop % desktops + 1;
00605     } else {
00606         newDesk = (desktops + m_currentDesktop - 2) % desktops + 1;
00607     }
00608 
00609     KWindowSystem::setCurrentDesktop(newDesk);
00610     m_currentDesktop = newDesk;
00611     update();
00612 
00613     Applet::wheelEvent(e);
00614 }
00615 
00616 void Pager::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
00617 {
00618     if (m_dragId > 0) {
00619         m_dragCurrentPos = event->pos();
00620         m_dragHighlightedDesktop = -1;
00621         m_hoverRect = QRectF();
00622         int i = 0;
00623         foreach (const QRectF &rect, m_rects) {
00624             if (rect.contains(event->pos())) {
00625                 m_dragHighlightedDesktop = i;
00626                 m_hoverRect = rect;
00627                 break;
00628             }
00629 
00630             ++i;
00631         }
00632         update();
00633         event->accept();
00634         return;
00635     } else if (m_dragStartDesktop != -1 &&
00636                (event->pos() - m_dragOriginalPos).toPoint().manhattanLength() > KGlobalSettings::dndEventDelay()) {
00637         m_dragId = 0; // prevent us from going through this more than once
00638         for (int k = m_windowRects[m_dragStartDesktop].count() - 1; k >= 0 ; k--) {
00639             if (m_windowRects[m_dragStartDesktop][k].second.contains(m_dragOriginalPos.toPoint())) {
00640                 m_dragOriginal = m_windowRects[m_dragStartDesktop][k].second;
00641                 m_dragId = m_windowRects[m_dragStartDesktop][k].first;
00642                 event->accept();
00643                 break;
00644             }
00645         }
00646     }
00647 
00648     if (m_dragOriginal.isEmpty()) {
00649         Applet::mouseMoveEvent(event);
00650     }
00651 }
00652 
00653 void Pager::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
00654 {
00655     if (m_dragId) {
00656         if (m_dragHighlightedDesktop != -1) {
00657             QPointF dest = m_dragCurrentPos - m_rects[m_dragHighlightedDesktop].topLeft() - m_dragOriginalPos + m_dragOriginal.topLeft();
00658             dest = QPointF(dest.x()/m_widthScaleFactor, dest.y()/m_heightScaleFactor);
00659             // don't move windows to negative positions
00660             dest = QPointF(qMax(dest.x(), qreal(0.0)), qMax(dest.y(), qreal(0.0)));
00661             if (!KWindowSystem::mapViewport()) {
00662                 KWindowInfo info = KWindowSystem::windowInfo(m_dragId, NET::WMDesktop);
00663 
00664                 if (!info.onAllDesktops()) {
00665                     KWindowSystem::setOnDesktop(m_dragId, m_dragHighlightedDesktop+1);
00666                 }
00667 
00668                 // only move the window if it is kept within the same desktop
00669                 // moving when dropping between desktop is too annoying due to
00670                 // the small drop area.
00671                 if (m_dragHighlightedDesktop == m_dragStartDesktop || info.onAllDesktops()) {
00672                     // use _NET_MOVERESIZE_WINDOW rather than plain move, so that the WM knows this is a pager request
00673                     NETRootInfo i( QX11Info::display(), 0 );
00674                     int flags = ( 0x20 << 12 ) | ( 0x03 << 8 ) | 1; // from tool, x/y, northwest gravity
00675                     i.moveResizeWindowRequest( m_dragId, flags, dest.toPoint().x(), dest.toPoint().y(), 0, 0 );
00676                 }
00677             } else {
00678                 // setOnDesktop() with viewports is also moving a window, and since it takes a moment
00679                 // for the WM to do the move, there's a race condition with figuring out how much to move,
00680                 // so do it only as one move
00681                 dest += KWindowSystem::desktopToViewport( m_dragHighlightedDesktop+1, false );
00682                 QPoint d = KWindowSystem::constrainViewportRelativePosition( dest.toPoint());
00683                 NETRootInfo i( QX11Info::display(), 0 );
00684                 int flags = ( 0x20 << 12 ) | ( 0x03 << 8 ) | 1; // from tool, x/y, northwest gravity
00685                 i.moveResizeWindowRequest( m_dragId, flags, d.x(), d.y(), 0, 0 );
00686             }
00687         }
00688         m_timer->start();
00689     } else if (m_dragStartDesktop != -1 && m_dragStartDesktop < m_rects.size() &&
00690                m_rects[m_dragStartDesktop].contains(event->pos()) &&
00691                m_currentDesktop != m_dragStartDesktop + 1) {
00692         // only change the desktop if the user presses and releases the mouse on the same desktop
00693         KWindowSystem::setCurrentDesktop(m_dragStartDesktop + 1);
00694         m_currentDesktop = m_dragStartDesktop + 1;
00695     }
00696 
00697     m_dragId = 0;
00698     m_dragOriginal = QRect();
00699     m_dragHighlightedDesktop = -1;
00700     m_dragStartDesktop = -1;
00701     m_dragOriginalPos = m_dragCurrentPos = QPointF();
00702 
00703     update();
00704     Applet::mouseReleaseEvent(event);
00705 }
00706 
00707 // If the pager is hovered in drag and drop mode, no hover events are geneated.
00708 // This method provides the common implementation for hoverMoveEvent and dragMoveEvent.
00709 void Pager::handleHoverMove(const QPointF& pos)
00710 {
00711     bool changedHover = !m_hoverRect.contains(pos);
00712     Plasma::Animator *anim = Plasma::Animator::self();
00713 
00714     if (changedHover && m_hoverIndex > -1) {
00715         if (m_animations[m_hoverIndex].animId != -1) {
00716             Plasma::Animator::self()->stopCustomAnimation(m_animations[m_hoverIndex].animId);
00717         }
00718         m_animations[m_hoverIndex].fadeIn = false;
00719         m_animations[m_hoverIndex].alpha = 1;
00720         m_animations[m_hoverIndex].animId = anim->customAnimation(40 / (1000 / s_FadeOutDuration), s_FadeOutDuration,Plasma::Animator::EaseOutCurve, this,"animationUpdate");
00721     }
00722 
00723     if (!changedHover) {
00724         return;
00725     }
00726 
00727     int i = 0;
00728     foreach (const QRectF &rect, m_rects) {
00729         if (rect.contains(pos)) {
00730             if (m_hoverRect != rect) {
00731                 m_hoverRect = rect;
00732                 m_hoverIndex = i;
00733                 if (m_animations[m_hoverIndex].animId != -1) {
00734                     anim->stopCustomAnimation(m_animations[i].animId);
00735                 }
00736                 m_animations[m_hoverIndex].fadeIn = true;
00737                 m_animations[m_hoverIndex].alpha = 0;
00738                 m_animations[m_hoverIndex].animId = anim->customAnimation(40 / (1000 / s_FadeInDuration), s_FadeInDuration,Plasma::Animator::EaseInCurve, this,"animationUpdate");
00739                 update();
00740                 updateToolTip();
00741             }
00742             return;
00743         }
00744         ++i;
00745     }
00746     m_hoverIndex = -1;
00747     m_hoverRect = QRectF();
00748     update();
00749 }
00750 
00751 // If the pager is hovered in drag and drop mode, no hover events are geneated.
00752 // This method provides the common implementation for hoverLeaveEvent and dragLeaveEvent.
00753 void Pager::handleHoverLeave()
00754 {
00755     if (m_hoverRect != QRectF()) {
00756         m_hoverRect = QRectF();
00757         update();
00758     }
00759 
00760     if (m_hoverIndex != -1) {
00761         if (m_animations[m_hoverIndex].animId != -1) {
00762             Plasma::Animator::self()->stopCustomAnimation(m_animations[m_hoverIndex].animId);
00763         }
00764         m_animations[m_hoverIndex].fadeIn = false;
00765         m_animations[m_hoverIndex].alpha = 1;
00766         m_animations[m_hoverIndex].animId = Plasma::Animator::self()->customAnimation(40 / (1000 / s_FadeOutDuration), s_FadeOutDuration,Plasma::Animator::EaseOutCurve, this,"animationUpdate");
00767         m_hoverIndex = -1;
00768     }
00769 
00770     // The applet doesn't always get mouseReleaseEvents, for example when starting a drag
00771     // on the containment and releasing the mouse on the desktop or another window. This can cause
00772     // weird bugs because the pager still thinks a drag is going on.
00773     // The only reliable event I found is the hoverLeaveEvent, so we just stop the drag
00774     // on this event.
00775     if (m_dragId || m_dragStartDesktop != -1) {
00776         m_dragId = 0;
00777         m_dragOriginal = QRect();
00778         m_dragHighlightedDesktop = -1;
00779         m_dragStartDesktop = -1;
00780         m_dragOriginalPos = m_dragCurrentPos = QPointF();
00781         update();
00782     }
00783 }
00784 
00785 void Pager::hoverEnterEvent(QGraphicsSceneHoverEvent *event)
00786 {
00787     handleHoverMove(event->pos());
00788     Applet::hoverEnterEvent(event);
00789 }
00790 
00791 void Pager::hoverMoveEvent(QGraphicsSceneHoverEvent *event)
00792 {
00793     handleHoverMove(event->pos());
00794 }
00795 
00796 void Pager::hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
00797 {
00798     handleHoverLeave();
00799     Applet::hoverLeaveEvent(event);
00800 }
00801 
00802 void Pager::dragEnterEvent(QGraphicsSceneDragDropEvent *event)
00803 {
00804     if (event->mimeData()->hasFormat(TaskManager::Task::mimetype())) {
00805         event->setAccepted(true);
00806         return;
00807     }
00808     else event->setAccepted(false);
00809     handleHoverMove(event->pos());
00810 
00811     if (m_hoverIndex != -1) {
00812         m_dragSwitchDesktop = m_hoverIndex;
00813         m_dragSwitchTimer->start(DRAG_SWITCH_DELAY);
00814     }
00815     Applet::dragEnterEvent(event);
00816 }
00817 
00818 void Pager::dragMoveEvent(QGraphicsSceneDragDropEvent *event)
00819 {
00820     handleHoverMove(event->pos());
00821 
00822     if (m_dragSwitchDesktop != m_hoverIndex && m_hoverIndex != -1) {
00823         m_dragSwitchDesktop = m_hoverIndex;
00824         m_dragSwitchTimer->start(DRAG_SWITCH_DELAY);
00825     } else if (m_hoverIndex == -1) {
00826         m_dragSwitchDesktop = m_hoverIndex;
00827         m_dragSwitchTimer->stop();
00828     }
00829     Applet::dragMoveEvent(event);
00830 }
00831 
00832 void Pager::dragLeaveEvent(QGraphicsSceneDragDropEvent *event)
00833 {
00834     handleHoverLeave();
00835 
00836     m_dragSwitchDesktop = -1;
00837     m_dragSwitchTimer->stop();
00838     Applet::dragLeaveEvent(event);
00839 }
00840 
00841 void Pager::dropEvent(QGraphicsSceneDragDropEvent *event)
00842 {
00843     bool ok;
00844     WId id = TaskManager::Task::idFromMimeData(event->mimeData(), &ok);
00845     if (ok) {
00846         for (int i = 0; i < m_rects.count(); ++i) {
00847             if (m_rects[i].contains(event->pos().toPoint())) {
00848                 KWindowSystem::setOnDesktop(id, i + 1);
00849                 m_dragSwitchDesktop = -1;
00850                 break;
00851             }
00852         }
00853     }
00854 }
00855 
00856 void Pager::animationUpdate(qreal progress, int animId)
00857 {
00858     int i = 0;
00859     foreach (AnimInfo anim, m_animations) {
00860         if (anim.animId == animId) {
00861             break;
00862         }
00863         i++;
00864     }
00865 
00866     if (i >= m_animations.size()) {
00867         return;
00868     }
00869 
00870     m_animations[i].alpha = m_animations[i].fadeIn ? progress : 1 - progress;
00871 
00872     if (progress == 1) {
00873         m_animations[i].animId = -1;
00874         m_animations[i].fadeIn = true;
00875     }
00876 
00877     // explicit update
00878     update();
00879 }
00880 
00881 void Pager::dragSwitch()
00882 {
00883     if (m_dragSwitchDesktop == -1) {
00884         return;
00885     }
00886     KWindowSystem::setCurrentDesktop(m_dragSwitchDesktop + 1);
00887     m_currentDesktop = m_dragSwitchDesktop + 1;
00888 }
00889 
00890 void Pager::paintInterface(QPainter *painter, const QStyleOptionGraphicsItem *option, const QRect &contentsRect)
00891 {
00892     Q_UNUSED( option );
00893     Q_UNUSED( contentsRect );
00894 
00895     KColorScheme* plasmaColorTheme = colorScheme();
00896     painter->setFont(KGlobalSettings::taskbarFont());
00897 
00898     // Desktop background
00899     QColor defaultTextColor = Plasma::Theme::defaultTheme()->color(Plasma::Theme::TextColor);
00900     QColor hoverColor = defaultTextColor;
00901     hoverColor.setAlpha(64);
00902 
00903     // Inactive windows
00904     QColor drawingColor = plasmaColorTheme->foreground(KColorScheme::InactiveText).color();
00905     drawingColor.setAlpha(45);
00906     QBrush windowBrush(drawingColor);
00907     // Inactive windows Active desktop
00908     drawingColor.setAlpha(90);
00909     QBrush windowBrushActiveDesk(drawingColor);
00910 
00911     // Inactive window borders
00912     drawingColor = defaultTextColor;
00913     drawingColor.setAlpha(130);
00914     QPen windowPen(drawingColor);
00915 
00916     // Active window borders
00917     QPen activeWindowPen(defaultTextColor);
00918 
00919     // Active windows
00920     drawingColor.setAlpha(130);
00921     QBrush activeWindowBrush(drawingColor);
00922     // Active windows Active desktop
00923     drawingColor.setAlpha(155);
00924     QBrush activeWindowBrushActiveDesk(drawingColor);
00925 
00926     if (m_showOwnBackground && (formFactor() == Plasma::Vertical || formFactor() == Plasma::Horizontal)) {
00927         m_background->setElementPrefix(QString());
00928         m_background->paintFrame(painter);
00929     }
00930 
00931     // Draw backgrounds of desktops only when there are not the proper theme elements
00932     painter->setPen(Qt::NoPen);
00933     if (!m_background->hasElementPrefix("hover")) {
00934         for (int i = 0; i < m_rects.count(); i++) {
00935             if (m_rects[i] == m_hoverRect) {
00936                 QColor animHoverColor = hoverColor;
00937                 if (m_animations[i].animId > -1) {
00938                     animHoverColor.setAlpha(hoverColor.alpha()*m_animations[i].alpha);
00939                 }
00940                 painter->setBrush(animHoverColor);
00941                 painter->drawRect(m_rects[i]);
00942             }
00943         }
00944     }
00945 
00946     // Draw miniatures of windows from each desktop
00947     painter->setPen(windowPen);
00948     for (int i = 0; i < m_windowRects.count(); i++) {
00949         for (int j = 0; j < m_windowRects[i].count(); j++) {
00950             QRect rect = m_windowRects[i][j].second;
00951 
00952             if (m_currentDesktop > 0 &&
00953                 m_currentDesktop <= m_rects.count() &&
00954                 m_rects[m_currentDesktop-1].contains(rect)) {
00955                 if (m_activeWindows.contains(rect)) {
00956                     painter->setBrush(activeWindowBrushActiveDesk);
00957                     painter->setPen(activeWindowPen);
00958                 } else {
00959                     painter->setBrush(windowBrushActiveDesk);
00960                     painter->setPen(windowPen);
00961                 }
00962             } else {
00963                 if (m_activeWindows.contains(rect)) {
00964                     painter->setBrush(activeWindowBrush);
00965                     painter->setPen(activeWindowPen);
00966                 } else {
00967                     painter->setBrush(windowBrush);
00968                     painter->setPen(windowPen);
00969                 }
00970             }
00971             if (m_dragId == m_windowRects[i][j].first) {
00972                 rect.translate((m_dragCurrentPos - m_dragOriginalPos).toPoint());
00973                 painter->setClipRect(option->exposedRect);
00974             } else if (i < m_rects.count()) {
00975                 painter->setClipRect(m_rects[i].adjusted(1, 1, -1, -1));
00976             }
00977             painter->drawRect(rect);
00978             if ((rect.width() > 16) && (rect.height() > 16) && m_showWindowIcons){
00979                 painter->drawPixmap(rect.x() + (rect.width() - 16) / 2, rect.y() + (rect.height() - 16) / 2, 16, 16,
00980                                     KWindowSystem::icon(m_windowRects[i][j].first, 16, 16, true));
00981             }
00982         }
00983     }
00984 
00985     // Draw desktop frame and possibly text over it
00986     painter->setClipRect(option->exposedRect);
00987     painter->setBrush(Qt::NoBrush);
00988 
00989     QString prefix;
00990     for (int i = 0; i < m_rects.count(); i++) {
00991         if (i + 1 == m_currentDesktop || i == m_dragHighlightedDesktop) {
00992             prefix = "active";
00993         } else {
00994             prefix = "normal";
00995         }
00996 
00997         //Paint the panel or fallback if we don't have that prefix
00998         if (m_background->hasElementPrefix(prefix)) {
00999             m_background->setElementPrefix(prefix);
01000             if (m_animations[i].animId > -1) {
01001                 QPixmap normal = m_background->framePixmap();
01002                 m_background->setElementPrefix("hover");
01003                 QPixmap result = Plasma::PaintUtils::transition(normal, m_background->framePixmap(), m_animations[i].alpha);
01004                 painter->drawPixmap(m_rects[i].topLeft(), result);
01005             } else {
01006                 //no anims, simpler thing
01007                 if (m_rects[i] == m_hoverRect) {
01008                     m_background->setElementPrefix("hover");
01009                 }
01010                 m_background->paintFrame(painter, m_rects[i].topLeft());
01011             }
01012         } else {
01013             QPen drawingPen;
01014 
01015             if (i + 1 == m_currentDesktop || i == m_dragHighlightedDesktop) {
01016                 defaultTextColor.setAlphaF(1);
01017                 drawingPen = QPen(defaultTextColor);
01018             } else {
01019                 drawingPen = QPen(plasmaColorTheme->foreground(KColorScheme::InactiveText).color());
01020             }
01021 
01022             painter->setPen(drawingPen);
01023             painter->drawRect(m_rects[i]);
01024         }
01025 
01026         //Draw text
01027         if (m_animations[i].animId == -1) {
01028             defaultTextColor.setAlphaF(1);
01029         }
01030         defaultTextColor.setAlphaF(m_animations[i].alpha / 2 + 0.5);
01031         painter->setPen(defaultTextColor);
01032 
01033         QColor shadowColor(Qt::black);
01034         if (defaultTextColor.value() < 128) {
01035             shadowColor = Qt::white;
01036         }
01037 
01038         QString desktopText = QString();
01039         if (m_displayedText == Number) { // Display number of desktop
01040             desktopText = QString::number(i + 1);
01041         } else if (m_displayedText == Name) { // Display name of desktop
01042             desktopText = KWindowSystem::desktopName(i + 1);
01043         }
01044 
01045         if (!desktopText.isEmpty()) {
01046             int radius = 2;
01047             QPixmap result = Plasma::PaintUtils::shadowText(desktopText,
01048                                                             KGlobalSettings::smallestReadableFont(),
01049                                                             defaultTextColor,
01050                                                             shadowColor, QPoint(0, 0), radius);
01051             QRectF target = m_rects[i];
01052             //take also shadow position and radius into account
01053             //kDebug() << target << result.height();
01054             if (target.height() >= result.height() - radius * 2) {
01055                 QPointF paintPoint = target.center() - (result.rect().center() + QPoint(radius, radius)); 
01056 
01057                 if (paintPoint.x() + radius < target.x() + 1) {
01058                     paintPoint.setX(target.x() + 1 - radius);
01059                 }
01060 
01061                 if (paintPoint.y() + radius < target.y() + 1) {
01062                     paintPoint.setY(target.y() + 1 - radius);
01063                 }
01064 
01065                 target.moveTopLeft(QPointF(0, 0));
01066                 painter->drawPixmap(paintPoint, result, target);
01067             }
01068         }
01069     }
01070 }
01071 
01072 void Pager::lostDesktopLayoutOwner()
01073 {
01074     delete m_desktopLayoutOwner;
01075     m_desktopLayoutOwner = NULL;
01076 }
01077 
01078 // KWindowSystem does not translate position when mapping viewports
01079 // to virtual desktops (it'd probably break more things than fix),
01080 // so the offscreen coordinates need to be fixed
01081 QRect Pager::fixViewportPosition( const QRect& r )
01082 {
01083     QRect desktopGeom = Kephal::ScreenUtils::desktopGeometry();
01084     int x = r.center().x() % desktopGeom.width();
01085     int y = r.center().y() % desktopGeom.height();
01086     if( x < 0 ) {
01087         x = x + desktopGeom.width();
01088     }
01089     if( y < 0 ) {
01090         y = y + desktopGeom.height();
01091     }
01092     return QRect( x - r.width() / 2, y - r.height() / 2, r.width(), r.height());
01093 }
01094 
01095 void Pager::themeRefresh()
01096 {
01097     delete m_colorScheme;
01098     m_colorScheme = 0;
01099 }
01100 
01101 void Pager::updateToolTip()
01102 {
01103     int hoverDesktopNumber = 0;
01104 
01105     for (int i = 0; i < m_desktopCount; i++) {
01106         if (m_rects[i] == m_hoverRect) {
01107             hoverDesktopNumber = i + 1;
01108         }
01109     }
01110 
01111     Plasma::ToolTipContent data;
01112     QString subtext = QString();
01113     int taskCounter = 0;
01114     int displayedTaskCounter = 0;
01115 
01116     QList<WId> windows;
01117 
01118     foreach(KWindowInfo winInfo, m_windowInfo){
01119         if (winInfo.isOnDesktop(hoverDesktopNumber) && !windows.contains(winInfo.win())) {
01120             bool active = (winInfo.win() == KWindowSystem::activeWindow());
01121             if ((taskCounter < 4) || active){    
01122                 QPixmap icon = KWindowSystem::icon(winInfo.win(), 16, 16, true);
01123                 if (icon.isNull()) {
01124                      subtext += "<br />&bull;" + winInfo.visibleName();
01125                 } else {
01126                     data.addResource(Plasma::ToolTipContent::ImageResource, QUrl("wicon://" + QString::number(taskCounter)), QVariant(icon));
01127                     subtext += "<br /><img src=\"wicon://" + QString::number(taskCounter) + "\"/>";
01128                 }
01129                 subtext += (active ? "<u>" : "") + winInfo.visibleName() + (active ? "</u>" : "");
01130 
01131                 displayedTaskCounter++; 
01132                 windows.append(winInfo.win());
01133             }
01134             taskCounter++;
01135         }
01136     }
01137 
01138     if (taskCounter) {
01139         subtext.prepend(i18np("One window:", "%1 windows:", taskCounter));
01140     }
01141 
01142     if (taskCounter - displayedTaskCounter > 0) {
01143         subtext.append("<br>&bull; <i>" + i18np("and 1 other", "and %1 others", taskCounter - displayedTaskCounter) + "</i>");
01144     }
01145 
01146     data.setMainText(KWindowSystem::desktopName(hoverDesktopNumber));
01147     data.setSubText(subtext);
01148 
01149     Plasma::ToolTipManager::self()->setContent(this, data);
01150 }
01151 
01152 #include "pager.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
  •   libsolidcontrol
  •   libtaskmanager
  • Plasma
  •   Animators
  •   Applets
  •   Engines
  • Solid Modules
Generated for API Reference by doxygen 1.5.7
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