• Skip to content
  • Skip to link menu
KDE 4.1 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 <QDesktopWidget>
00030 #include <QTimer>
00031 #include <QX11Info>
00032 
00033 #include <KDialog>
00034 #include <KColorScheme>
00035 #include <KConfigDialog>
00036 #include <KGlobalSettings>
00037 #include <KSharedConfig>
00038 #include <KWindowSystem>
00039 #include <NETRootInfo>
00040 #include <KToolInvocation>
00041 #include <kmanagerselection.h>
00042 
00043 #include <plasma/svg.h>
00044 #include <plasma/panelsvg.h>
00045 #include <plasma/theme.h>
00046 #include <plasma/animator.h>
00047 
00048 const int WINDOW_UPDATE_DELAY = 500;
00049 const int DRAG_SWITCH_DELAY = 1000;
00050 
00051 Pager::Pager(QObject *parent, const QVariantList &args)
00052     : Plasma::Applet(parent, args),
00053       m_dialog(0),
00054       m_displayedText(Number),
00055       m_showWindowIcons(false),
00056       m_showOwnBackground(false),
00057       m_rows(2),
00058       m_columns(0),
00059       m_hoverIndex(-1),
00060       m_dragId(0),
00061       m_dirtyDesktop(-1),
00062       m_dragStartDesktop(-1),
00063       m_dragHighlightedDesktop(-1),
00064       m_dragSwitchDesktop(-1)
00065 {
00066     setAcceptsHoverEvents(true);
00067     setAcceptDrops(true);
00068     setHasConfigurationInterface(true);
00069 
00070     m_background = new Plasma::PanelSvg(this);
00071     m_background->setImagePath("widgets/pager");
00072     m_background->setCacheAllRenderedPanels(true);
00073 
00074     // initialize with a decent default
00075     m_desktopCount = KWindowSystem::numberOfDesktops();
00076     m_size = QSizeF(176, 88);
00077     resize(m_size);
00078 }
00079 
00080 void Pager::init()
00081 {
00082     createMenu();
00083     
00084     KConfigGroup cg = config();
00085     m_displayedText = (DisplayedText)cg.readEntry("displayedText", (int)m_displayedText);
00086     m_showWindowIcons = cg.readEntry("showWindowIcons", m_showWindowIcons);
00087     m_rows = globalConfig().readEntry("rows", m_rows);
00088 
00089     if (m_rows < 1) {
00090         m_rows = 1;
00091     } else if (m_rows > m_desktopCount) {
00092         m_rows = m_desktopCount;
00093     }
00094 
00095     m_timer = new QTimer(this);
00096     m_timer->setSingleShot(true);
00097     connect(m_timer, SIGNAL(timeout()), this, SLOT(recalculateWindowRects()));
00098 
00099     m_dragSwitchTimer = new QTimer(this);
00100     m_dragSwitchTimer->setSingleShot(true);
00101     connect(m_dragSwitchTimer, SIGNAL(timeout()), this, SLOT(dragSwitch()));
00102 
00103     connect(KWindowSystem::self(), SIGNAL(currentDesktopChanged(int)), this, SLOT(currentDesktopChanged(int)));
00104     connect(KWindowSystem::self(), SIGNAL(windowAdded(WId)), this, SLOT(windowAdded(WId)));
00105     connect(KWindowSystem::self(), SIGNAL(windowRemoved(WId)), this, SLOT(windowRemoved(WId)));
00106     connect(KWindowSystem::self(), SIGNAL(activeWindowChanged(WId)), this, SLOT(activeWindowChanged(WId)));
00107     connect(KWindowSystem::self(), SIGNAL(numberOfDesktopsChanged(int)), this, SLOT(numberOfDesktopsChanged(int)));
00108     connect(KWindowSystem::self(), SIGNAL(desktopNamesChanged()), this, SLOT(desktopNamesChanged()));
00109     connect(KWindowSystem::self(), SIGNAL(stackingOrderChanged()), this, SLOT(stackingOrderChanged()));
00110     connect(KWindowSystem::self(), SIGNAL(windowChanged(WId,unsigned int)), this, SLOT(windowChanged(WId,unsigned int)));
00111     connect(KWindowSystem::self(), SIGNAL(showingDesktopChanged(bool)), this, SLOT(showingDesktopChanged(bool)));
00112     connect(QApplication::desktop(), SIGNAL(resized(int)), SLOT(desktopsSizeChanged()));
00113 
00114     m_desktopLayoutOwner = new KSelectionOwner( QString( "_NET_DESKTOP_LAYOUT_S%1" )
00115         .arg( QX11Info::appScreen()).toLatin1().constData(), QX11Info::appScreen(), this );
00116     connect( m_desktopLayoutOwner, SIGNAL( lostOwnership()), SLOT( lostDesktopLayoutOwner()));
00117     if ( !m_desktopLayoutOwner->claim( false ))
00118         lostDesktopLayoutOwner();
00119 
00120     recalculateGeometry();
00121 
00122     m_currentDesktop = KWindowSystem::currentDesktop();
00123 }
00124 
00125 void Pager::constraintsEvent(Plasma::Constraints constraints)
00126 {
00127     if (constraints & Plasma::SizeConstraint) {
00128         recalculateGeometry();
00129         recalculateWindowRects();
00130         if (m_background->hasElementPrefix(QString())) {
00131             m_background->setElementPrefix(QString());
00132             m_background->resizePanel(size());
00133         }
00134     }
00135     if (constraints & Plasma::FormFactorConstraint) {
00136         if (formFactor() == Plasma::Horizontal) {
00137             setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Expanding);
00138         } else if (formFactor() == Plasma::Vertical) {
00139             setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
00140         } else {
00141             setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
00142         }
00143     }
00144 }
00145 
00146 void Pager::createMenu()
00147 {
00148     QAction* configureDesktop = new QAction(SmallIcon("configure"),i18n("&Configure Desktops..."), this);
00149     m_actions.append(configureDesktop);
00150     connect(configureDesktop, SIGNAL(triggered(bool)), this , SLOT(slotConfigureDesktop()));
00151 }
00152 
00153 QList<QAction*> Pager::contextualActions()
00154 {
00155   return m_actions;
00156 }
00157 
00158 void Pager::slotConfigureDesktop()
00159 {
00160   QString error;
00161   KToolInvocation::startServiceByDesktopName("desktop", QStringList(), &error);
00162 }
00163 
00164 void Pager::createConfigurationInterface(KConfigDialog *parent)
00165 {
00166     QWidget *widget = new QWidget();
00167     ui.setupUi(widget);
00168     parent->setButtons( KDialog::Ok | KDialog::Cancel | KDialog::Apply );
00169     parent->addPage(widget, parent->windowTitle(), icon());
00170     connect(parent, SIGNAL(applyClicked()), this, SLOT(configAccepted()));
00171     connect(parent, SIGNAL(okClicked()), this, SLOT(configAccepted()));
00172 
00173     ui.displayedTextComboBox->clear();
00174     ui.displayedTextComboBox->addItem(i18n("Desktop Number"));
00175     ui.displayedTextComboBox->addItem(i18n("Desktop Name"));
00176     ui.displayedTextComboBox->addItem(i18n("None"));
00177     ui.displayedTextComboBox->setCurrentIndex((int)m_displayedText);
00178     ui.displayedTextComboBox->setToolTip(i18n("What will appear when the mouse is over a desktop miniature"));
00179     ui.showWindowIconsCheckBox->setChecked(m_showWindowIcons);
00180     ui.spinRows->setValue(m_rows);
00181     ui.spinRows->setMaximum(m_desktopCount);
00182 }
00183 
00184 bool Pager::posOnDesktopRect(const QRectF& r, const QPointF& pos)
00185 {
00186     qreal leftMargin;
00187     qreal topMargin;
00188     qreal rightMargin;
00189     qreal bottomMargin;
00190 
00191     if (m_showOwnBackground && m_background) {
00192         m_background->setElementPrefix(QString());
00193         m_background->getMargins(leftMargin, topMargin, rightMargin, bottomMargin);
00194 
00195         if (r.left() > leftMargin) {
00196             leftMargin = 0;
00197         }
00198         if (r.top() > topMargin) {
00199             leftMargin = 0;
00200         }
00201         if (geometry().width() - r.right() < rightMargin) {
00202             leftMargin = 0;
00203         }
00204         if (geometry().bottom() - r.bottom() < bottomMargin) {
00205             leftMargin = 0;
00206         }
00207 
00208         return r.adjusted(-leftMargin, -topMargin, rightMargin, bottomMargin).contains(pos);
00209     } else {
00210         return r.contains(pos);
00211     }
00212 }
00213 
00214 void Pager::recalculateGeometry()
00215 {
00216     if (!m_rects.isEmpty() && geometry().size() == m_size) {
00217         //kDebug() << "leaving because" << !m_rects.isEmpty() << " and " << contentSize() << "==" << m_size;
00218         return;
00219     }
00220 
00221     int padding = 2; // Space between miniatures of desktops
00222     int textMargin = 3; // Space between name of desktop and border
00223     int columns = m_desktopCount / m_rows + m_desktopCount % m_rows;
00224 
00225     qreal leftMargin;
00226     qreal topMargin;
00227     qreal rightMargin;
00228     qreal bottomMargin;
00229 
00230     if (formFactor() == Plasma::Vertical || formFactor() == Plasma::Horizontal) {
00231         m_background->setElementPrefix(QString());
00232         m_background->getMargins(leftMargin, topMargin, rightMargin, bottomMargin);
00233 
00234         qreal ratio = (qreal)QApplication::desktop()->width() / (qreal)QApplication::desktop()->height();
00235 
00236         //if the final size is going to be really tiny avoid to add extra margins
00237         if (geometry().width() - leftMargin - rightMargin < KIconLoader::SizeSmall*ratio * columns + padding*(columns-1) ||
00238             geometry().height() - topMargin - bottomMargin < KIconLoader::SizeSmall * m_rows + padding*(m_rows-1)) {
00239             m_showOwnBackground = false;
00240             leftMargin = topMargin = rightMargin = bottomMargin = padding = textMargin = 0;
00241         } else {
00242             m_showOwnBackground = true;
00243         }
00244     } else {
00245         getContentsMargins(&leftMargin, &topMargin, &rightMargin, &bottomMargin);
00246     }
00247 
00248     qreal itemHeight;
00249     qreal itemWidth;
00250 
00251     if (formFactor() == Plasma::Vertical) {
00252         itemWidth = (geometry().width() - leftMargin - rightMargin - padding * (columns - 1)) / columns;
00253         m_widthScaleFactor = itemWidth / QApplication::desktop()->width();
00254         itemHeight = QApplication::desktop()->height() * m_widthScaleFactor;
00255         m_heightScaleFactor = m_widthScaleFactor;
00256     } else {
00257         itemHeight = (geometry().height() - topMargin -  bottomMargin - padding * (m_rows - 1)) / m_rows;
00258         m_heightScaleFactor = itemHeight / QApplication::desktop()->height();
00259         itemWidth = QApplication::desktop()->width() * m_heightScaleFactor;
00260         if (m_displayedText == Name) {
00261             // When containment is in this position we are not limited by low width and we can
00262             // afford increasing width of applet to be able to display every name of desktops
00263             for (int i = 0; i < m_desktopCount; i++) {
00264                 QFontMetricsF metrics(KGlobalSettings::taskbarFont());
00265                 QSizeF textSize = metrics.size(Qt::TextSingleLine, KWindowSystem::desktopName(i+1));
00266                 if (textSize.width() + textMargin * 2 > itemWidth) {
00267                      itemWidth = textSize.width() + textMargin * 2;
00268                 }
00269             }
00270         }
00271         m_widthScaleFactor = itemWidth / QApplication::desktop()->width();
00272     }
00273 
00274     m_rects.clear();
00275     m_animations.clear();
00276     QRectF itemRect;
00277     itemRect.setWidth(floor(itemWidth - 1));
00278     itemRect.setHeight(floor(itemHeight - 1));
00279     for (int i = 0; i < m_desktopCount; i++) {
00280         itemRect.moveLeft(leftMargin + floor((i % columns) * (itemWidth + padding)));
00281         itemRect.moveTop(topMargin + floor((i / columns) * (itemHeight + padding)));
00282         m_rects.append(itemRect);
00283         AnimInfo anim;
00284         anim.animId = -1;
00285         anim.fadeIn = true;
00286         anim.alpha = 0;
00287         m_animations.append(anim);
00288     }
00289 
00290     //Resize background svgs as needed
00291     if (m_background->hasElementPrefix("normal")) {
00292         m_background->setElementPrefix("normal");
00293         m_background->resizePanel(itemRect.size());
00294     }
00295     if (m_background->hasElementPrefix("active")) {
00296         m_background->setElementPrefix("active");
00297         m_background->resizePanel(itemRect.size());
00298     }
00299     if (m_background->hasElementPrefix("hover")) {
00300         m_background->setElementPrefix("hover");
00301         m_background->resizePanel(itemRect.size());
00302     }
00303 
00304     m_size = QSizeF(ceil(columns * itemWidth + padding * (columns - 1) + leftMargin + rightMargin),
00305                     ceil(m_rows * itemHeight + padding * (m_rows - 1) + topMargin + bottomMargin));
00306 
00307     //kDebug() << "new size set" << m_size << m_rows << m_columns << columns << itemWidth;
00308 
00309     resize(m_size);
00310     setPreferredSize(m_size);
00311     if (m_desktopLayoutOwner && columns != m_columns) {
00312         // must own manager selection before setting global desktop layout
00313         m_columns = columns;
00314         NET::Orientation orient = NET::OrientationHorizontal;
00315         NETRootInfo i( QX11Info::display(), 0 );
00316         i.setDesktopLayout( orient, columns, m_rows, NET::DesktopLayoutCornerTopLeft );
00317     }
00318 }
00319 
00320 void Pager::recalculateWindowRects()
00321 {
00322     QList<WId> windows = KWindowSystem::stackingOrder();
00323     m_windowRects.clear();
00324     for (int i = 0; i < m_desktopCount; i++) {
00325         m_windowRects.append(QList<QPair<WId, QRect> >());
00326     }
00327     m_activeWindows.clear();
00328     foreach(WId window, windows) {
00329         KWindowInfo info = KWindowSystem::windowInfo(window, NET::WMGeometry | NET::WMFrameExtents | NET::WMWindowType | NET::WMDesktop | NET::WMState | NET::XAWMState);
00330         NET::WindowType type = info.windowType(NET::NormalMask | NET::DialogMask | NET::OverrideMask |
00331                                                NET::UtilityMask | NET::DesktopMask | NET::DockMask |
00332                                                NET::TopMenuMask | NET::SplashMask | NET::ToolbarMask |
00333                                                NET::MenuMask);
00334 
00335         // the reason we don't check for -1 or Net::Unknown here is that legitimate windows, such
00336         // as some java application windows, may not have a type set for them.
00337         // apparently sane defaults on properties is beyond the wisdom of x11.
00338         if (type == NET::Desktop || type == NET::Dock || type == NET::TopMenu ||
00339             type == NET::Splash || type == NET::Menu || type == NET::Toolbar ||
00340             info.hasState(NET::SkipPager) || info.isMinimized()) {
00341             continue;
00342         }
00343 
00344         for (int i = 0; i < m_desktopCount; i++) {
00345             if (!info.isOnDesktop(i+1)) {
00346                 continue;
00347             }
00348             QRect windowRect = info.frameGeometry();
00349             if( KWindowSystem::mapViewport())
00350                 windowRect = fixViewportPosition( windowRect );
00351             windowRect = QRectF(windowRect.x() * m_widthScaleFactor,
00352                                 windowRect.y() * m_heightScaleFactor,
00353                                 windowRect.width() * m_widthScaleFactor,
00354                                 windowRect.height() * m_heightScaleFactor).toRect();
00355             windowRect.translate(m_rects[i].topLeft().toPoint());
00356             m_windowRects[i].append(QPair<WId, QRect>(window, windowRect));
00357             if (window == KWindowSystem::activeWindow()) {
00358                 m_activeWindows.append(windowRect);
00359             }
00360         }
00361     }
00362 
00363     if (m_dirtyDesktop < 0 || m_dirtyDesktop >= m_rects.count()) {
00364         update();
00365     } else {
00366         update(m_rects[m_dirtyDesktop]);
00367     }
00368 }
00369 
00370 void Pager::configAccepted()
00371 {
00372     KConfigGroup cg = config();
00373     bool changed = false;
00374 
00375     if ((int)m_displayedText != ui.displayedTextComboBox->currentIndex()) {
00376         m_displayedText = (DisplayedText)ui.displayedTextComboBox->currentIndex();
00377         cg.writeEntry("displayedText", (int)m_displayedText);
00378         changed = true;
00379     }
00380 
00381     if (m_showWindowIcons != ui.showWindowIconsCheckBox->isChecked()) {
00382         m_showWindowIcons = ui.showWindowIconsCheckBox->isChecked();
00383         cg.writeEntry("showWindowIcons", m_showWindowIcons);
00384         changed = true;
00385     }
00386 
00387     // we need to keep all pager applets consistent since this affects
00388     // the layout of the desktops as used by the window manager,
00389     // so we store the row count in the applet global configuration
00390     if (m_rows != ui.spinRows->value()) {
00391         KConfigGroup globalcg = globalConfig();
00392         m_rows = ui.spinRows->value();
00393         if (m_rows > m_desktopCount) {
00394             m_rows = m_desktopCount;
00395         }
00396         globalcg.writeEntry("rows", m_rows);
00397         changed = true;
00398     }
00399 
00400     if (changed) {
00401         configNeedsSaving();
00402         // force an update
00403         m_columns = 0;
00404         m_size = QSizeF(-1, -1);
00405         recalculateGeometry();
00406         recalculateWindowRects();
00407         update();
00408     }
00409 }
00410 
00411 void Pager::currentDesktopChanged(int desktop)
00412 {
00413     m_currentDesktop = desktop;
00414 
00415     m_dirtyDesktop = -1;
00416 
00417     if (!m_timer->isActive()) {
00418         m_timer->start(WINDOW_UPDATE_DELAY);
00419     }
00420 }
00421 
00422 void Pager::windowAdded(WId id)
00423 {
00424     Q_UNUSED(id)
00425 
00426     KWindowInfo info = KWindowSystem::windowInfo(id, NET::WMGeometry | NET::WMFrameExtents | NET::WMWindowType | NET::WMDesktop | NET::WMState | NET::XAWMState);
00427     m_dirtyDesktop = info.desktop() - 1;
00428 
00429     if (!m_timer->isActive()) {
00430         m_timer->start(WINDOW_UPDATE_DELAY);
00431     }
00432 }
00433 
00434 void Pager::windowRemoved(WId id)
00435 {
00436     Q_UNUSED(id)
00437 
00438     KWindowInfo info = KWindowSystem::windowInfo(id, NET::WMGeometry | NET::WMFrameExtents | NET::WMWindowType | NET::WMDesktop | NET::WMState | NET::XAWMState);
00439     m_dirtyDesktop = info.desktop() - 1;
00440 
00441     if (!m_timer->isActive()) {
00442         m_timer->start(WINDOW_UPDATE_DELAY);
00443     }
00444 }
00445 
00446 void Pager::activeWindowChanged(WId id)
00447 {
00448     Q_UNUSED(id)
00449 
00450     KWindowInfo info = KWindowSystem::windowInfo(id, NET::WMGeometry | NET::WMFrameExtents | NET::WMWindowType | NET::WMDesktop | NET::WMState | NET::XAWMState);
00451     m_dirtyDesktop = info.desktop() - 1;
00452 
00453     if (!m_timer->isActive()) {
00454         m_timer->start(WINDOW_UPDATE_DELAY);
00455     }
00456 }
00457 
00458 void Pager::numberOfDesktopsChanged(int num)
00459 {
00460     m_dirtyDesktop = -1;
00461 
00462     m_desktopCount = num;
00463     if (m_rows > m_desktopCount) {
00464         m_rows = m_desktopCount;
00465     }
00466     m_rects.clear();
00467     recalculateGeometry();
00468 
00469     if (!m_timer->isActive()) {
00470         m_timer->start(WINDOW_UPDATE_DELAY);
00471     }
00472 }
00473 
00474 void Pager::desktopNamesChanged()
00475 {
00476     m_dirtyDesktop = -1;
00477 
00478     m_rects.clear();
00479     recalculateGeometry();
00480 
00481     if (!m_timer->isActive()) {
00482         m_timer->start(WINDOW_UPDATE_DELAY);
00483     }
00484 }
00485 
00486 void Pager::stackingOrderChanged()
00487 {
00488     m_dirtyDesktop = -1;
00489 
00490     if (!m_timer->isActive()) {
00491         m_timer->start(WINDOW_UPDATE_DELAY);
00492     }
00493 }
00494 
00495 void Pager::windowChanged(WId id, unsigned int properties)
00496 {
00497     Q_UNUSED(id)
00498 
00499     if (properties & NET::WMGeometry) {
00500         KWindowInfo info = KWindowSystem::windowInfo(id, NET::WMGeometry | NET::WMFrameExtents | NET::WMWindowType | NET::WMDesktop | NET::WMState | NET::XAWMState);
00501         m_dirtyDesktop = info.desktop() - 1;
00502     } else {
00503         m_dirtyDesktop = -1;
00504     }
00505 
00506     if (properties & NET::WMGeometry ||
00507         properties & NET::WMDesktop) {
00508         if (!m_timer->isActive()) {
00509             m_timer->start(WINDOW_UPDATE_DELAY);
00510         }
00511     }
00512 }
00513 
00514 void Pager::showingDesktopChanged(bool showing)
00515 {
00516     m_dirtyDesktop = -1;
00517 
00518     Q_UNUSED(showing)
00519     if (!m_timer->isActive()) {
00520         m_timer->start(WINDOW_UPDATE_DELAY);
00521     }
00522 }
00523 
00524 void Pager::desktopsSizeChanged()
00525 {
00526     m_dirtyDesktop = -1;
00527 
00528     m_rects.clear();
00529     recalculateGeometry();
00530 
00531     if (!m_timer->isActive()) {
00532         m_timer->start(WINDOW_UPDATE_DELAY);
00533     }
00534 }
00535 
00536 void Pager::mousePressEvent(QGraphicsSceneMouseEvent *event)
00537 {
00538     if (event->buttons() != Qt::RightButton)
00539     {
00540         for (int i = 0; i < m_desktopCount; i++) {
00541             if (posOnDesktopRect(m_rects[i], event->pos())) {
00542                 m_dragStartDesktop = m_dragHighlightedDesktop = i;
00543                 m_dragOriginalPos = m_dragCurrentPos = event->pos();
00544                 if (m_dragOriginal.isEmpty()) {
00545                     m_dragOriginal = m_rects[i].toRect();
00546                 }
00547 
00548                 update();
00549                 return;
00550             }
00551         }
00552     }
00553     Applet::mousePressEvent(event);
00554 }
00555 
00556 void Pager::wheelEvent(QGraphicsSceneWheelEvent *e)
00557 {
00558     int newDesk;
00559     int desktops = KWindowSystem::numberOfDesktops();
00560 
00561     /*
00562        if (m_kwin->numberOfViewports(0).width() * m_kwin->numberOfViewports(0).height() > 1 )
00563        desktops = m_kwin->numberOfViewports(0).width() * m_kwin->numberOfViewports(0).height();
00564        */
00565     if (e->delta() < 0)
00566     {
00567         newDesk = m_currentDesktop % desktops + 1;
00568     }
00569     else
00570     {
00571         newDesk = (desktops + m_currentDesktop - 2) % desktops + 1;
00572     }
00573 
00574     KWindowSystem::setCurrentDesktop(newDesk);
00575     m_currentDesktop = newDesk;
00576     update();
00577 
00578     Applet::wheelEvent(e);
00579 }
00580 
00581 void Pager::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
00582 {
00583     if (m_dragId > 0) {
00584         m_dragCurrentPos = event->pos();
00585         m_dragHighlightedDesktop = -1;
00586         for (int i = 0; i < m_desktopCount; i++) {
00587             if (m_rects[i].contains(event->pos().toPoint())) {
00588                 m_dragHighlightedDesktop = i;
00589                 break;
00590             }
00591         }
00592         m_hoverRect = QRectF();
00593         foreach (const QRectF &rect, m_rects) {
00594             if (rect.contains(event->pos())) {
00595                 m_hoverRect = rect;
00596                 break;
00597             }
00598         }
00599         update();
00600         event->accept();
00601         return;
00602     } else if (m_dragId != -1 && m_dragStartDesktop != -1 &&
00603                (event->pos() - m_dragOriginalPos).toPoint().manhattanLength() > KGlobalSettings::dndEventDelay()) {
00604         m_dragId = -1; // prevent us from going through this more than once
00605         for (int k = m_windowRects[m_dragStartDesktop].count() - 1; k >= 0 ; k--) {
00606             if (m_windowRects[m_dragStartDesktop][k].second.contains(m_dragOriginalPos.toPoint())) {
00607                 m_dragOriginal = m_windowRects[m_dragStartDesktop][k].second;
00608                 m_dragId = m_windowRects[m_dragStartDesktop][k].first;
00609                 event->accept();
00610                 break;
00611             }
00612         }
00613     }
00614 
00615     if (m_dragOriginal.isEmpty()) {
00616         Applet::mouseMoveEvent(event);
00617     }
00618 }
00619 
00620 void Pager::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
00621 {
00622     if (m_dragId > 0) {
00623         if (m_dragHighlightedDesktop != -1) {
00624             QPointF dest = m_dragCurrentPos - m_rects[m_dragHighlightedDesktop].topLeft() - m_dragOriginalPos + m_dragOriginal.topLeft();
00625             dest = QPointF(dest.x()/m_widthScaleFactor, dest.y()/m_heightScaleFactor);
00626             // don't move windows to negative positions
00627             dest = QPointF(qMax(dest.x(), qreal(0.0)), qMax(dest.y(), qreal(0.0)));
00628             if( !KWindowSystem::mapViewport()) {
00629                 KWindowSystem::setOnDesktop(m_dragId, m_dragHighlightedDesktop+1);
00630                 // use _NET_MOVERESIZE_WINDOW rather than plain move, so that the WM knows this is a pager request
00631                 NETRootInfo i( QX11Info::display(), 0 );
00632                 int flags = ( 0x20 << 12 ) | ( 0x03 << 8 ) | 1; // from tool, x/y, northwest gravity
00633                 i.moveResizeWindowRequest( m_dragId, flags, dest.toPoint().x(), dest.toPoint().y(), 0, 0 );
00634             } else {
00635                 // setOnDesktop() with viewports is also moving a window, and since it takes a moment
00636                 // for the WM to do the move, there's a race condition with figuring out how much to move,
00637                 // so do it only as one move
00638                 dest += KWindowSystem::desktopToViewport( m_dragHighlightedDesktop+1, false );
00639                 QPoint d = KWindowSystem::constrainViewportRelativePosition( dest.toPoint());
00640                 NETRootInfo i( QX11Info::display(), 0 );
00641                 int flags = ( 0x20 << 12 ) | ( 0x03 << 8 ) | 1; // from tool, x/y, northwest gravity
00642                 i.moveResizeWindowRequest( m_dragId, flags, d.x(), d.y(), 0, 0 );
00643             }
00644         }
00645         m_timer->start();
00646     } else if (m_dragStartDesktop != -1 && posOnDesktopRect(m_rects[m_dragStartDesktop], event->pos()) &&
00647                m_currentDesktop != m_dragStartDesktop + 1) {
00648         // only change the desktop if the user presses and releases the mouse on the same desktop
00649         KWindowSystem::setCurrentDesktop(m_dragStartDesktop + 1);
00650         m_currentDesktop = m_dragStartDesktop + 1;
00651     }
00652 
00653     m_dragId = 0;
00654     m_dragOriginal = QRect();
00655     m_dragHighlightedDesktop = -1;
00656     m_dragStartDesktop = -1;
00657     m_dragOriginalPos = m_dragCurrentPos = QPointF();
00658 
00659     update();
00660     Applet::mouseReleaseEvent(event);
00661 }
00662 
00663 // If the pager is hovered in drag and drop mode, no hover events are geneated.
00664 // This method provides the common implementation for hoverMoveEvent and dragMoveEvent.
00665 void Pager::handleHoverMove(const QPointF& pos)
00666 {
00667     bool changedHover = !posOnDesktopRect(m_hoverRect, pos);
00668     Plasma::Animator *anim = Plasma::Animator::self();
00669 
00670     if (changedHover && m_hoverIndex > -1) {
00671         if (m_animations[m_hoverIndex].animId != -1) {
00672             Plasma::Animator::self()->stopCustomAnimation(m_animations[m_hoverIndex].animId);
00673         }
00674         m_animations[m_hoverIndex].fadeIn = false;
00675         m_animations[m_hoverIndex].alpha = 1;
00676         m_animations[m_hoverIndex].animId = anim->customAnimation(40 / (1000 / s_FadeOutDuration), s_FadeOutDuration,Plasma::Animator::EaseOutCurve, this,"animationUpdate");
00677     }
00678 
00679     if (!changedHover) {
00680         return;
00681     }
00682 
00683     int i = 0;
00684     foreach (const QRectF &rect, m_rects) {
00685         if (posOnDesktopRect(rect, pos)) {
00686             if (m_hoverRect != rect) {
00687                 m_hoverRect = rect;
00688                 m_hoverIndex = i;
00689                 if (m_animations[m_hoverIndex].animId != -1) {
00690                     anim->stopCustomAnimation(m_animations[i].animId);
00691                 }
00692                 m_animations[m_hoverIndex].fadeIn = true;
00693                 m_animations[m_hoverIndex].alpha = 0;
00694                 m_animations[m_hoverIndex].animId = anim->customAnimation(40 / (1000 / s_FadeInDuration), s_FadeInDuration,Plasma::Animator::EaseInCurve, this,"animationUpdate");
00695                 update();
00696             }
00697             return;
00698         }
00699         i++;
00700     }
00701     m_hoverIndex = -1;
00702     m_hoverRect = QRectF();
00703     update();
00704 }
00705 
00706 // If the pager is hovered in drag and drop mode, no hover events are geneated.
00707 // This method provides the common implementation for hoverLeaveEvent and dragLeaveEvent.
00708 void Pager::handleHoverLeave()
00709 {
00710     if (m_hoverRect != QRectF()) {
00711         m_hoverRect = QRectF();
00712         update();
00713     }
00714 
00715     if (m_hoverIndex != -1) {
00716         if (m_animations[m_hoverIndex].animId != -1) {
00717             Plasma::Animator::self()->stopCustomAnimation(m_animations[m_hoverIndex].animId);
00718         }
00719         m_animations[m_hoverIndex].fadeIn = false;
00720         m_animations[m_hoverIndex].alpha = 1;
00721         m_animations[m_hoverIndex].animId = Plasma::Animator::self()->customAnimation(40 / (1000 / s_FadeOutDuration), s_FadeOutDuration,Plasma::Animator::EaseOutCurve, this,"animationUpdate");
00722         m_hoverIndex = -1;
00723     }
00724 
00725     // The applet doesn't always get mouseReleaseEvents, for example when starting a drag
00726     // on the containment and releasing the mouse on the desktop or another window. This can cause
00727     // weird bugs because the pager still thinks a drag is going on.
00728     // The only reliable event I found is the hoverLeaveEvent, so we just stop the drag
00729     // on this event.
00730     if (m_dragId || m_dragStartDesktop != -1) {
00731         m_dragId = 0;
00732         m_dragOriginal = QRect();
00733         m_dragHighlightedDesktop = -1;
00734         m_dragStartDesktop = -1;
00735         m_dragOriginalPos = m_dragCurrentPos = QPointF();
00736         update();
00737     }
00738 }
00739 
00740 void Pager::hoverEnterEvent(QGraphicsSceneHoverEvent *event)
00741 {
00742     handleHoverMove(event->pos());
00743     Applet::hoverEnterEvent(event);
00744 }
00745 
00746 void Pager::hoverMoveEvent(QGraphicsSceneHoverEvent *event)
00747 {
00748     handleHoverMove(event->pos());
00749 }
00750 
00751 void Pager::hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
00752 {
00753     handleHoverLeave();
00754     Applet::hoverLeaveEvent(event);
00755 }
00756 
00757 void Pager::dragEnterEvent(QGraphicsSceneDragDropEvent *event)
00758 {
00759     //TODO: we need to accept window id drops eventually
00760     event->setAccepted(false);
00761     handleHoverMove(event->pos());
00762 
00763     if (m_hoverIndex != -1) {
00764         m_dragSwitchDesktop = m_hoverIndex;
00765         m_dragSwitchTimer->start(DRAG_SWITCH_DELAY);
00766     }
00767     Applet::dragEnterEvent(event);
00768 }
00769 
00770 void Pager::dragMoveEvent(QGraphicsSceneDragDropEvent *event)
00771 {
00772     handleHoverMove(event->pos());
00773 
00774     if (m_dragSwitchDesktop != m_hoverIndex && m_hoverIndex != -1) {
00775         m_dragSwitchDesktop = m_hoverIndex;
00776         m_dragSwitchTimer->start(DRAG_SWITCH_DELAY);
00777     } else if (m_hoverIndex == -1) {
00778         m_dragSwitchDesktop = m_hoverIndex;
00779         m_dragSwitchTimer->stop();
00780     }
00781     Applet::dragMoveEvent(event);
00782 }
00783 
00784 void Pager::dragLeaveEvent(QGraphicsSceneDragDropEvent *event)
00785 {
00786     handleHoverLeave();
00787 
00788     m_dragSwitchDesktop = -1;
00789     m_dragSwitchTimer->stop();
00790     Applet::dragLeaveEvent(event);
00791 }
00792 
00793 void Pager::animationUpdate(qreal progress, int animId)
00794 {
00795     int i = 0;
00796     foreach (AnimInfo anim, m_animations) {
00797         if (anim.animId == animId) {
00798             break;
00799         }
00800         i++;
00801     }
00802 
00803     if (i >= m_animations.size()) {
00804         return;
00805     }
00806 
00807     m_animations[i].alpha = m_animations[i].fadeIn ? progress : 1 - progress;
00808 
00809     if (progress == 1) {
00810         m_animations[i].animId = -1;
00811         m_animations[i].fadeIn = true;
00812     }
00813 
00814     // explicit update
00815     update();
00816 }
00817 
00818 void Pager::dragSwitch()
00819 {
00820     if (m_dragSwitchDesktop == -1) {
00821         return;
00822     }
00823     KWindowSystem::setCurrentDesktop(m_dragSwitchDesktop + 1);
00824     m_currentDesktop = m_dragSwitchDesktop + 1;
00825 }
00826 
00827 void Pager::paintInterface(QPainter *painter, const QStyleOptionGraphicsItem *option, const QRect &contentsRect)
00828 {
00829     Q_UNUSED( option );
00830     Q_UNUSED( contentsRect );
00831 
00832     KColorScheme plasmaColorTheme = KColorScheme(QPalette::Active, KColorScheme::View, Plasma::Theme::defaultTheme()->colorScheme());
00833     painter->setFont(KGlobalSettings::taskbarFont());
00834 
00835     // Desktop background
00836     QColor defaultTextColor = Plasma::Theme::defaultTheme()->color(Plasma::Theme::TextColor);
00837     QColor hoverColor = defaultTextColor;
00838     hoverColor.setAlpha(64);
00839 
00840     // Inactive windows
00841     QColor drawingColor = plasmaColorTheme.foreground(KColorScheme::InactiveText).color();
00842     drawingColor.setAlpha(50);
00843     QBrush windowBrush(drawingColor);
00844     // Inactive windows Active desktop
00845     drawingColor.setAlpha(192);
00846     QBrush windowBrushActiveDesk(drawingColor);
00847 
00848     // Inactive window borders
00849     drawingColor = plasmaColorTheme.foreground(KColorScheme::NeutralText).color();
00850     drawingColor.setAlpha(238);
00851     QPen windowPen(drawingColor);
00852 
00853     // Active window borders
00854     QPen activeWindowPen(defaultTextColor);
00855 
00856     // Active windows
00857     drawingColor.setAlpha(190);
00858     QBrush activeWindowBrush(drawingColor);
00859     // Active windows Active desktop
00860     drawingColor.setAlpha(228);
00861     QBrush activeWindowBrushActiveDesk(drawingColor);
00862 
00863     if (m_showOwnBackground && (formFactor() == Plasma::Vertical || formFactor() == Plasma::Horizontal)) {
00864         m_background->setElementPrefix(QString());
00865         m_background->paintPanel(painter, contentsRect);
00866     }
00867 
00868     // Draw backgrounds of desktops only when there are not the proper theme elements
00869     painter->setPen(Qt::NoPen);
00870     if (!m_background->hasElementPrefix("hover")) {
00871         for (int i = 0; i < m_desktopCount; i++) {
00872             if (m_rects[i] == m_hoverRect) {
00873                 QColor animHoverColor = hoverColor;
00874                 if (m_animations[i].animId > -1) {
00875                     animHoverColor.setAlpha(hoverColor.alpha()*m_animations[i].alpha);
00876                 }
00877                 painter->setBrush(animHoverColor);
00878                 painter->drawRect(m_rects[i]);
00879             }
00880         }
00881     }
00882 
00883     // Draw miniatures of windows from each desktop
00884     painter->setPen(windowPen);
00885     for (int i = 0; i < m_windowRects.count(); i++) {
00886         for (int j = 0; j < m_windowRects[i].count(); j++) {
00887             QRect rect = m_windowRects[i][j].second;
00888             if (m_rects[m_currentDesktop-1].contains(rect)) {
00889                 if (m_activeWindows.contains(rect)) {
00890                     painter->setBrush(activeWindowBrushActiveDesk);
00891                     painter->setPen(activeWindowPen);
00892                 } else {
00893                     painter->setBrush(windowBrushActiveDesk);
00894                     painter->setPen(windowPen);
00895                 }
00896             } else {
00897                 if (m_activeWindows.contains(rect)) {
00898                     painter->setBrush(activeWindowBrush);
00899                     painter->setPen(activeWindowPen);
00900                 } else {
00901                     painter->setBrush(windowBrush);
00902                     painter->setPen(windowPen);
00903                 }
00904             }
00905             if (m_dragId == m_windowRects[i][j].first) {
00906                 rect.translate((m_dragCurrentPos - m_dragOriginalPos).toPoint());
00907                 painter->setClipRect(option->exposedRect);
00908             } else {
00909                 painter->setClipRect(m_rects[i].adjusted(1, 1, -1, -1));
00910             }
00911             painter->drawRect(rect);
00912             if ((rect.width() > 16) && (rect.height() > 16) && m_showWindowIcons){
00913                 painter->drawPixmap(rect.x() + (rect.width() - 16) / 2, rect.y() + (rect.height() - 16) / 2, 16, 16,
00914                                     KWindowSystem::icon(m_windowRects[i][j].first, 16, 16, true));
00915             }
00916         }
00917     }
00918 
00919     // Draw desktop frame and possibly text over it
00920     painter->setClipRect(option->exposedRect);
00921     painter->setBrush(Qt::NoBrush);
00922 
00923     QString prefix;
00924     for (int i = 0; i < m_desktopCount; i++) {
00925         if (i + 1 == m_currentDesktop || i == m_dragHighlightedDesktop) {
00926             prefix = "active";
00927         } else {
00928             prefix = "normal";
00929         }
00930 
00931         //Paint the panel or fallback if we don't have that prefix
00932         if (m_background->hasElementPrefix(prefix)) {
00933             m_background->setElementPrefix(prefix);
00934             if (m_animations[i].animId > -1) {
00935                 QPixmap pixmap(m_rects[i].size().toSize());
00936                 QColor alphaColor(0,0,0);
00937 
00938                 //alpha of the not-hover element
00939                 alphaColor.setAlphaF(1.0-m_animations[i].alpha);
00940                 pixmap.fill(alphaColor);
00941 
00942                 QPainter buffPainter(&pixmap);
00943                 buffPainter.setCompositionMode(QPainter::CompositionMode_SourceIn);
00944 
00945                 m_background->paintPanel(&buffPainter, QRectF(QPointF(0, 0), m_rects[i].size()));
00946                 buffPainter.end();
00947                 painter->drawPixmap(m_rects[i].topLeft(), pixmap);
00948 
00949                 m_background->setElementPrefix("hover");
00950                 //alpha of the not-hover element
00951                 alphaColor.setAlphaF(m_animations[i].alpha);
00952                 //FIXME: filling again the old pixmap makes a segfault
00953                 pixmap = QPixmap(m_rects[i].size().toSize());
00954                 pixmap.fill(alphaColor);
00955                 buffPainter.begin(&pixmap);
00956                 buffPainter.setCompositionMode(QPainter::CompositionMode_SourceIn);
00957                 m_background->paintPanel(&buffPainter, QRectF(QPointF(0, 0), m_rects[i].size()));
00958                 painter->drawPixmap(m_rects[i].topLeft(), pixmap);
00959             } else {
00960                 //no anims, simpler thing
00961                 if (m_rects[i] == m_hoverRect) {
00962                     m_background->setElementPrefix("hover");
00963                 }
00964                 m_background->paintPanel(painter, m_rects[i], m_rects[i].topLeft());
00965             }
00966         } else {
00967             QPen drawingPen;
00968 
00969             if (i + 1 == m_currentDesktop || i == m_dragHighlightedDesktop) {
00970                 defaultTextColor.setAlphaF(1);
00971                 drawingPen = QPen(defaultTextColor);
00972             } else {
00973                 drawingPen = QPen(plasmaColorTheme.foreground(KColorScheme::InactiveText).color());
00974             }
00975 
00976             painter->setPen(drawingPen);
00977             painter->drawRect(m_rects[i]);
00978         }
00979 
00980         //Draw text
00981         if (m_animations[i].animId == -1) {
00982             defaultTextColor.setAlphaF(1);
00983         }
00984         defaultTextColor.setAlphaF(m_animations[i].alpha / 2 + 0.5);
00985         painter->setPen(defaultTextColor);
00986 
00987         if (m_displayedText==Number) { // Display number of desktop
00988             painter->drawText(m_rects[i], Qt::AlignCenter, QString::number(i+1));
00989         } else if (m_displayedText==Name) { // Display name of desktop
00990             painter->drawText(m_rects[i], Qt::AlignCenter, KWindowSystem::desktopName(i+1));
00991          }
00992     }
00993 }
00994 
00995 void Pager::lostDesktopLayoutOwner()
00996 {
00997     delete m_desktopLayoutOwner;
00998     m_desktopLayoutOwner = NULL;
00999 }
01000 
01001 // KWindowSystem does not translate position when mapping viewports
01002 // to virtual desktops (it'd probably break more things than fix),
01003 // so the offscreen coordinates need to be fixed
01004 QRect Pager::fixViewportPosition( const QRect& r )
01005 {
01006     int x = r.center().x() % qApp->desktop()->width();
01007     int y = r.center().y() % qApp->desktop()->height();
01008     if( x < 0 )
01009         x = x + qApp->desktop()->width();
01010     if( y < 0 )
01011         y = y + qApp->desktop()->height();
01012     return QRect( x - r.width() / 2, y - r.height() / 2, r.width(), r.height());
01013 }
01014 
01015 #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
  •   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