/*************************************************************************** * Copyright (C) 2007 by Daniel Laidig * * Copyright (C) 2012 by Luís Gabriel Lima * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . * ***************************************************************************/ #include "pager.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include const int FAST_UPDATE_DELAY = 100; const int UPDATE_DELAY = 500; const int MAXDESKTOPS = 20; // random(), find a less magic one if you can. -sreich const qreal MAX_TEXT_WIDTH = 800; Pager::Pager(QObject *parent, const QVariantList &args) : Plasma::Applet(parent, args), m_displayedText(None), m_currentDesktopSelected(DoNothing), m_rows(2), m_columns(0), m_currentDesktop(0), m_addDesktopAction(0), m_removeDesktopAction(0), m_plasmaColorTheme(0), m_showWindowIcons(false), m_desktopDown(false), m_verticalFormFactor(false), m_ignoreNextSizeConstraint(false), m_hideWhenSingleDesktop(false), m_configureDesktopsWidget(0), m_desktopWidget(qApp->desktop()) { setAcceptsHoverEvents(true); setAcceptDrops(true); setHasConfigurationInterface(true); setAspectRatioMode(Plasma::IgnoreAspectRatio); m_dummy = new Plasma::FrameSvg(this); m_dummy->setImagePath("widgets/pager"); // initialize with a decent default m_desktopCount = KWindowSystem::numberOfDesktops(); m_size = QSizeF(176, 88); resize(m_size); } Pager::~Pager() { delete m_plasmaColorTheme; } void Pager::init() { m_pagerModel = new PagerModel(this); updatePagerStyle(); initDeclarativeUI(); createMenu(); m_verticalFormFactor = (formFactor() == Plasma::Vertical); configChanged(); m_timer = new QTimer(this); m_timer->setSingleShot(true); connect(m_timer, SIGNAL(timeout()), this, SLOT(recalculateWindowRects())); connect(KWindowSystem::self(), SIGNAL(currentDesktopChanged(int)), this, SLOT(currentDesktopChanged(int))); connect(KWindowSystem::self(), SIGNAL(windowAdded(WId)), this, SLOT(startTimerFast())); connect(KWindowSystem::self(), SIGNAL(windowRemoved(WId)), this, SLOT(startTimerFast())); connect(KWindowSystem::self(), SIGNAL(activeWindowChanged(WId)), this, SLOT(startTimerFast())); connect(KWindowSystem::self(), SIGNAL(numberOfDesktopsChanged(int)), this, SLOT(numberOfDesktopsChanged(int))); connect(KWindowSystem::self(), SIGNAL(desktopNamesChanged()), this, SLOT(desktopNamesChanged())); connect(KWindowSystem::self(), SIGNAL(stackingOrderChanged()), this, SLOT(startTimerFast())); connect(KWindowSystem::self(), SIGNAL(windowChanged(WId,const ulong*)), this, SLOT(windowChanged(WId,const ulong*))); connect(KWindowSystem::self(), SIGNAL(showingDesktopChanged(bool)), this, SLOT(startTimer())); connect(m_desktopWidget, SIGNAL(screenCountChanged(int)), SLOT(desktopsSizeChanged())); connect(m_desktopWidget, SIGNAL(resized(int)), SLOT(desktopsSizeChanged())); // connect to KWin's reloadConfig signal to get updates on the desktop layout QDBusConnection dbus = QDBusConnection::sessionBus(); dbus.connect(QString(), "/KWin", "org.kde.KWin", "reloadConfig", this, SLOT(configChanged())); connect(Plasma::Theme::defaultTheme(), SIGNAL(themeChanged()), this, SLOT(themeRefresh())); recalculateGridSizes(m_rows); setCurrentDesktop(KWindowSystem::currentDesktop()); } void Pager::updatePagerStyle() { m_pagerStyle["font"] = KGlobalSettings::taskbarFont(); // Desktop background QColor defaultTextColor = Plasma::Theme::defaultTheme()->color(Plasma::Theme::TextColor); m_pagerStyle["textColor"] = QString("#%1").arg(defaultTextColor.rgba(), 0, 16); defaultTextColor.setAlpha(64); // Inactive windows QColor drawingColor = plasmaColorTheme()->foreground(KColorScheme::InactiveText).color(); drawingColor.setAlpha(45); m_pagerStyle["windowInactiveColor"] = QString("#%1").arg(drawingColor.rgba(), 0, 16); // Inactive windows Active desktop drawingColor.setAlpha(90); m_pagerStyle["windowInactiveOnActiveDesktopColor"] = QString("#%1").arg(drawingColor.rgba(), 0, 16); // Inactive window borders drawingColor = defaultTextColor; drawingColor.setAlpha(130); m_pagerStyle["windowInactiveBorderColor"] = QString("#%1").arg(drawingColor.rgba(), 0, 16); // Active window borders m_pagerStyle["windowActiveBorderColor"] = QString("#%1").arg(defaultTextColor.rgba(), 0, 16); // Active windows drawingColor.setAlpha(130); m_pagerStyle["windowActiveColor"] = QString("#%1").arg(drawingColor.rgba(), 0, 16); // Active windows Active desktop drawingColor.setAlpha(155); m_pagerStyle["windowActiveOnActiveDesktopColor"] = QString("#%1").arg(drawingColor.rgba(), 0, 16); emit styleChanged(); } void Pager::initDeclarativeUI() { QGraphicsLinearLayout *layout = new QGraphicsLinearLayout(this); m_declarativeWidget = new Plasma::DeclarativeWidget(this); m_declarativeWidget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); m_declarativeWidget->engine()->rootContext()->setContextProperty("pager", this); Plasma::PackageStructure::Ptr structure = Plasma::PackageStructure::load("Plasma/Generic"); Plasma::Package package(QString(), "org.kde.pager", structure); m_declarativeWidget->setQmlPath(package.filePath("mainscript")); layout->addItem(m_declarativeWidget); setLayout(layout); } void Pager::setCurrentDesktop(int desktop) { if (m_currentDesktop != desktop) { m_currentDesktop = desktop; emit currentDesktopChanged(); } } void Pager::setShowWindowIcons(bool show) { if (m_showWindowIcons != show) { m_showWindowIcons = show; emit showWindowIconsChanged(); } } void Pager::configChanged() { KConfigGroup cg = config(); bool changed = false; const DisplayedText displayedText = (DisplayedText) cg.readEntry("displayedText", (int) m_displayedText); if (displayedText != m_displayedText) { m_displayedText = displayedText; changed = true; emit showDesktopTextChanged(); } const bool showWindowIcons = cg.readEntry("showWindowIcons", m_showWindowIcons); if (showWindowIcons != m_showWindowIcons) { setShowWindowIcons(showWindowIcons); changed = true; } const bool hideWhenSingleDesktop = cg.readEntry("hideWhenSingleDesktop", false); if (hideWhenSingleDesktop != m_hideWhenSingleDesktop) { m_hideWhenSingleDesktop = hideWhenSingleDesktop; changed = true; } const CurrentDesktopSelected currentDesktopSelected = static_cast(cg.readEntry("currentDesktopSelected", static_cast(m_currentDesktopSelected))); if (currentDesktopSelected != m_currentDesktopSelected) { m_currentDesktopSelected = currentDesktopSelected; changed = true; } int rows = m_rows; #ifdef Q_WS_X11 unsigned long properties[] = {0, NET::WM2DesktopLayout }; NETRootInfo info(QX11Info::display(), properties, 2); rows = info.desktopLayoutColumnsRows().height(); #endif if (changed || rows != m_rows) { recalculateGridSizes(rows); recalculateWindowRects(); } } void Pager::constraintsEvent(Plasma::Constraints constraints) { if (constraints & Plasma::SizeConstraint) { // no need to update everything twice (if we are going to flip rows and columns later) if (!(constraints & Plasma::FormFactorConstraint) || m_verticalFormFactor == (formFactor() == Plasma::Vertical) || m_columns == m_rows) { // use m_ignoreNextSizeConstraint to decide whether to try to resize the plasmoid again updateSizes(!m_ignoreNextSizeConstraint); m_ignoreNextSizeConstraint = !m_ignoreNextSizeConstraint; recalculateWindowRects(); } else { update(); } } if (constraints & Plasma::FormFactorConstraint) { if (m_verticalFormFactor != (formFactor() == Plasma::Vertical)) { m_verticalFormFactor = (formFactor() == Plasma::Vertical); // whenever we switch to/from vertical form factor, swap the rows and columns around if (m_columns != m_rows) { // pass in columns as the new rows recalculateGridSizes(m_columns); recalculateWindowRects(); update(); } } if (formFactor() == Plasma::Horizontal) { setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Expanding); } else if (formFactor() == Plasma::Vertical) { setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); } else { setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); } } } KColorScheme *Pager::plasmaColorTheme() { if (!m_plasmaColorTheme) { m_plasmaColorTheme = new KColorScheme(QPalette::Active, KColorScheme::View, Plasma::Theme::defaultTheme()->colorScheme()); } return m_plasmaColorTheme; } void Pager::createMenu() { #ifdef Q_WS_X11 m_addDesktopAction = new QAction(SmallIcon("list-add"),i18n("&Add Virtual Desktop"), this); m_actions.append(m_addDesktopAction); connect(m_addDesktopAction, SIGNAL(triggered(bool)), this , SLOT(slotAddDesktop())); m_removeDesktopAction = new QAction(SmallIcon("list-remove"),i18n("&Remove Last Virtual Desktop"), this); m_actions.append(m_removeDesktopAction); connect(m_removeDesktopAction, SIGNAL(triggered(bool)), this , SLOT(slotRemoveDesktop())); if (m_desktopCount <= 1) { m_removeDesktopAction->setEnabled(false); } else if (m_desktopCount >= MAXDESKTOPS) { m_addDesktopAction->setEnabled(false); } #endif } QList Pager::contextualActions() { return m_actions; } #ifdef Q_WS_X11 void Pager::slotAddDesktop() { NETRootInfo info(QX11Info::display(), NET::NumberOfDesktops); info.setNumberOfDesktops(info.numberOfDesktops() + 1); } void Pager::slotRemoveDesktop() { NETRootInfo info(QX11Info::display(), NET::NumberOfDesktops); int desktops = info.numberOfDesktops(); if (desktops > 1) { info.setNumberOfDesktops(info.numberOfDesktops() - 1); } } #endif void Pager::createConfigurationInterface(KConfigDialog *parent) { QWidget *widget = new QWidget(); ui.setupUi(widget); m_configureDesktopsWidget = new KCModuleProxy("desktop"); parent->addPage(widget, i18n("General"), icon()); parent->addPage(m_configureDesktopsWidget, m_configureDesktopsWidget->moduleInfo().moduleName(), m_configureDesktopsWidget->moduleInfo().icon()); connect(parent, SIGNAL(okClicked()), this, SLOT(configAccepted())); connect(parent, SIGNAL(applyClicked()), this, SLOT(configAccepted())); switch (m_displayedText){ case Number: ui. desktopNumberRadioButton->setChecked(true); break; case Name: ui.desktopNameRadioButton->setChecked(true); break; case None: ui.displayNoneRadioButton->setChecked(true); break; } ui.showWindowIconsCheckBox->setChecked(m_showWindowIcons); switch (m_currentDesktopSelected){ case DoNothing: ui.doNothingRadioButton->setChecked(true); break; case ShowDesktop: ui.showDesktopRadioButton->setChecked(true); break; case ShowDashboard: ui.showDashboardRadioButton->setChecked(true); break; } connect(ui.desktopNumberRadioButton, SIGNAL(toggled(bool)), parent, SLOT(settingsModified())); connect(ui.desktopNameRadioButton, SIGNAL(toggled(bool)), parent, SLOT(settingsModified())); connect(ui.displayNoneRadioButton, SIGNAL(toggled(bool)), parent, SLOT(settingsModified())); connect(ui.showWindowIconsCheckBox, SIGNAL(toggled(bool)), parent, SLOT(settingsModified())); connect(ui.doNothingRadioButton, SIGNAL(toggled(bool)), parent, SLOT(settingsModified())); connect(ui.showDesktopRadioButton, SIGNAL(toggled(bool)), parent, SLOT(settingsModified())); connect(ui.showDashboardRadioButton, SIGNAL(toggled(bool)), parent, SLOT(settingsModified())); connect(m_configureDesktopsWidget, SIGNAL(changed(bool)), parent, SLOT(settingsModified())); } void Pager::recalculateGridSizes(int rows) { // recalculate the number of rows and columns in the grid rows = qBound(1, rows, m_desktopCount); // avoid weird cases like having 3 rows for 4 desktops, where the last row is unused int columns = m_desktopCount / rows; if (m_desktopCount % rows > 0) { columns++; } rows = m_desktopCount / columns; if (m_desktopCount % columns > 0) { rows++; } // update the grid size m_rows = rows; m_columns = columns; updateSizes(); } QRectF Pager::mapToDeclarativeUI(const QRectF &rect) const { QPointF p = mapToItem(m_declarativeWidget, rect.x(), rect.y()); return QRectF(p, rect.size()); } void Pager::updateSizes(bool allowResize /* = true */) { int padding = 2; // Space between miniatures of desktops int textMargin = 3; // Space between name of desktop and border qreal leftMargin = 0; qreal topMargin = 0; qreal rightMargin = 0; qreal bottomMargin = 0; QRect totalRect; for (int x = 0; x < m_desktopWidget->screenCount(); x++) { totalRect |= m_desktopWidget->screenGeometry(x); } qreal ratio = (qreal) totalRect.width() / (qreal) totalRect.height(); // calculate the margins if (formFactor() == Plasma::Vertical || formFactor() == Plasma::Horizontal) { m_dummy->getMargins(leftMargin, topMargin, rightMargin, bottomMargin); if (formFactor() == Plasma::Vertical) { qreal optimalSize = (geometry().width() - KIconLoader::SizeSmall * ratio * m_columns - padding * (m_columns - 1)) / 2; if (optimalSize < leftMargin || optimalSize < rightMargin) { leftMargin = rightMargin = qMax(qreal(0), optimalSize); } } else if (formFactor() == Plasma::Horizontal) { qreal optimalSize = (geometry().height() - KIconLoader::SizeSmall * m_rows - padding * (m_rows - 1)) / 2; if (optimalSize < topMargin || optimalSize < bottomMargin) { topMargin = bottomMargin = qMax(qreal(0), optimalSize); } } } else { getContentsMargins(&leftMargin, &topMargin, &rightMargin, &bottomMargin); } qreal itemHeight; qreal itemWidth; qreal preferredItemHeight; qreal preferredItemWidth; if (formFactor() == Plasma::Vertical) { // work out the preferred size based on the width of the geometry preferredItemWidth = (geometry().width() - leftMargin - rightMargin - padding * (m_columns - 1)) / m_columns; preferredItemHeight = preferredItemWidth / ratio; // make sure items of the new size actually fit in the current geometry itemHeight = (geometry().height() - topMargin - bottomMargin - padding * (m_rows - 1)) / m_rows; if (itemHeight > preferredItemHeight) { itemHeight = preferredItemHeight; } itemWidth = itemHeight * ratio; } else { // work out the preferred size based on the height of the geometry preferredItemHeight = (geometry().height() - topMargin - bottomMargin - padding * (m_rows - 1)) / m_rows; preferredItemWidth = preferredItemHeight * ratio; if (m_displayedText == Name) { // When containment is in this position we are not limited by low width and we can // afford increasing width of applet to be able to display every name of desktops for (int i = 0; i < m_desktopCount; i++) { QFontMetricsF metrics(KGlobalSettings::taskbarFont()); QSizeF textSize = metrics.size(Qt::TextSingleLine, KWindowSystem::desktopName(i+1)); if (textSize.width() + textMargin * 2 > preferredItemWidth) { preferredItemWidth = textSize.width() + textMargin * 2; } } } itemWidth = (geometry().width() - leftMargin - rightMargin - padding * (m_columns - 1)) / m_columns; if (itemWidth > preferredItemWidth) { itemWidth = preferredItemWidth; } itemHeight = preferredItemHeight; if (itemWidth < itemHeight * ratio) { itemHeight = itemWidth / ratio; } } m_widthScaleFactor = itemWidth / totalRect.width(); m_heightScaleFactor = itemHeight / totalRect.height(); m_pagerModel->clearDesktopRects(); QRectF itemRect(QPointF(leftMargin, topMargin) , QSizeF(itemWidth, itemHeight)); for (int i = 0; i < m_desktopCount; i++) { itemRect.moveLeft(leftMargin + (i % m_columns) * (itemWidth + padding)); itemRect.moveTop(topMargin + (i / m_columns) * (itemHeight + padding)); QString name = KWindowSystem::desktopName(i + 1); m_pagerModel->appendDesktopRect(mapToDeclarativeUI(itemRect), name); } // do not try to resize unless the caller has allowed it, // or the height has changed (or the width has changed in a vertical panel) const Plasma::FormFactor f = formFactor(); if (allowResize || (f != Plasma::Vertical && contentsRect().height() != m_size.height()) || (f == Plasma::Vertical && contentsRect().width() != m_size.width())) { // this new size will have the same height/width as the horizontal/vertical panel has given it QSizeF preferred; if (m_hideWhenSingleDesktop && m_desktopCount == 1 && (f == Plasma::Vertical || f == Plasma::Horizontal)) { const bool isVertical = f == Plasma::Vertical; preferred = QSizeF(isVertical ? m_size.width() : 0, isVertical ? 0 : m_size.height()); } else { preferred = QSizeF(ceil(m_columns * preferredItemWidth + padding * (m_columns - 1) + leftMargin + rightMargin), ceil(m_rows * preferredItemHeight + padding * (m_rows - 1) + topMargin + bottomMargin)); } setPreferredSize(preferred); emit sizeHintChanged(Qt::PreferredSize); } m_size = contentsRect().size(); layout()->activate(); } void Pager::recalculateWindowRects() { QList windows = KWindowSystem::stackingOrder(); m_pagerModel->clearWindowRects(); foreach (WId window, windows) { KWindowInfo info = KWindowSystem::windowInfo(window, NET::WMGeometry | NET::WMFrameExtents | NET::WMWindowType | NET::WMDesktop | NET::WMState | NET::XAWMState | NET::WMVisibleName); NET::WindowType type = info.windowType(NET::NormalMask | NET::DialogMask | NET::OverrideMask | NET::UtilityMask | NET::DesktopMask | NET::DockMask | NET::TopMenuMask | NET::SplashMask | NET::ToolbarMask | NET::MenuMask); // the reason we don't check for -1 or Net::Unknown here is that legitimate windows, such // as some java application windows, may not have a type set for them. // apparently sane defaults on properties is beyond the wisdom of x11. if (type == NET::Desktop || type == NET::Dock || type == NET::TopMenu || type == NET::Splash || type == NET::Menu || type == NET::Toolbar || info.hasState(NET::SkipPager) || info.isMinimized()) { continue; } for (int i = 0; i < m_desktopCount; i++) { if (!info.isOnDesktop(i+1)) { continue; } QRectF windowRect = info.frameGeometry(); if (KWindowSystem::mapViewport()) { windowRect = fixViewportPosition(windowRect.toRect()); } windowRect = QRectF(windowRect.x() * m_widthScaleFactor, windowRect.y() * m_heightScaleFactor, windowRect.width() * m_widthScaleFactor, windowRect.height() * m_heightScaleFactor).toRect(); bool active = (window == KWindowSystem::activeWindow()); int windowIconSize = KIconLoader::global()->currentSize(KIconLoader::Small); int windowRectSize = qMin(windowRect.width(), windowRect.height()); windowIconSize = qMax(windowIconSize, windowRectSize / 2); QPixmap icon = KWindowSystem::icon(info.win(), windowIconSize, windowIconSize, true); m_pagerModel->appendWindowRect(i, window, windowRect, active, icon, info.visibleName()); } } update(); } void Pager::configAccepted() { // only write the config here, it will be loaded in by configChanged(), // which is called after this when the config dialog is accepted KConfigGroup cg = config(); DisplayedText displayedText; if (ui.desktopNumberRadioButton->isChecked()) { displayedText = Number; } else if (ui.desktopNameRadioButton->isChecked()) { displayedText = Name; } else { displayedText = None; } cg.writeEntry("displayedText", (int) displayedText); cg.writeEntry("showWindowIcons", ui.showWindowIconsCheckBox->isChecked()); CurrentDesktopSelected currentDesktopSelected; if (ui.doNothingRadioButton->isChecked()) { currentDesktopSelected = DoNothing; } else if (ui.showDesktopRadioButton->isChecked()) { currentDesktopSelected = ShowDesktop; } else { currentDesktopSelected = ShowDashboard; } cg.writeEntry("currentDesktopSelected", (int) currentDesktopSelected); m_configureDesktopsWidget->save(); emit configNeedsSaving(); } void Pager::currentDesktopChanged(int desktop) { if (desktop < 1) { return; // bogus value, don't accept it } setCurrentDesktop(desktop); m_desktopDown = false; startTimerFast(); } void Pager::numberOfDesktopsChanged(int num) { if (num < 1) { return; // refuse to update to zero desktops } #ifdef Q_WS_X11 m_removeDesktopAction->setEnabled(num > 1); m_addDesktopAction->setEnabled(num < MAXDESKTOPS); #endif m_desktopCount = num; m_pagerModel->clearDesktopRects(); recalculateGridSizes(m_rows); recalculateWindowRects(); } void Pager::desktopNamesChanged() { m_pagerModel->clearDesktopRects(); updateSizes(); startTimer(); } void Pager::windowChanged(WId id, const unsigned long* dirty) { Q_UNUSED(id) if (dirty[NETWinInfo::PROTOCOLS] & (NET::WMGeometry | NET::WMDesktop)) { startTimer(); } } void Pager::desktopsSizeChanged() { m_pagerModel->clearDesktopRects(); updateSizes(); startTimer(); } void Pager::startTimer() { if (!m_timer->isActive()) { m_timer->start(UPDATE_DELAY); } } void Pager::startTimerFast() { if (!m_timer->isActive()) { m_timer->start(FAST_UPDATE_DELAY); } } void Pager::wheelEvent(QGraphicsSceneWheelEvent *e) { int newDesk; int desktops = KWindowSystem::numberOfDesktops(); if (e->delta() < 0) { newDesk = m_currentDesktop % desktops + 1; } else { newDesk = (desktops + m_currentDesktop - 2) % desktops + 1; } KWindowSystem::setCurrentDesktop(newDesk); setCurrentDesktop(newDesk); update(); Applet::wheelEvent(e); } void Pager::moveWindow(int window, double x, double y, int targetDesktop, int sourceDesktop) { WId windowId = (WId) window; QPointF dest = QPointF(x, y) - m_pagerModel->desktopRectAt(targetDesktop).topLeft(); dest = QPointF(dest.x()/m_widthScaleFactor, dest.y()/m_heightScaleFactor); // don't move windows to negative positions dest = QPointF(qMax(dest.x(), qreal(0.0)), qMax(dest.y(), qreal(0.0))); // use _NET_MOVERESIZE_WINDOW rather than plain move, so that the WM knows this is a pager request NETRootInfo info(QX11Info::display(), 0); int flags = (0x20 << 12) | (0x03 << 8) | 1; // from tool, x/y, northwest gravity if (!KWindowSystem::mapViewport()) { KWindowInfo windowInfo = KWindowSystem::windowInfo(windowId, NET::WMDesktop | NET::WMState); if (!windowInfo.onAllDesktops()) { KWindowSystem::setOnDesktop(windowId, targetDesktop+1); } // only move the window if it is not full screen and if it is kept within the same desktop // moving when dropping between desktop is too annoying due to the small drop area. if (!(windowInfo.state() & NET::FullScreen) && (targetDesktop == sourceDesktop || windowInfo.onAllDesktops())) { QPoint d = dest.toPoint(); info.moveResizeWindowRequest(windowId, flags, d.x(), d.y(), 0, 0); } } else { // setOnDesktop() with viewports is also moving a window, and since it takes a moment // for the WM to do the move, there's a race condition with figuring out how much to move, // so do it only as one move dest += KWindowSystem::desktopToViewport(targetDesktop+1, false); QPoint d = KWindowSystem::constrainViewportRelativePosition(dest.toPoint()); info.moveResizeWindowRequest(windowId, flags, d.x(), d.y(), 0, 0); } m_timer->start(); } void Pager::changeDesktop(int newDesktop) { if (m_currentDesktop == newDesktop+1) { // toogle the desktop or the dashboard if (m_currentDesktopSelected == ShowDesktop) { NETRootInfo info(QX11Info::display(), 0); m_desktopDown = !m_desktopDown; info.setShowingDesktop(m_desktopDown); } else if (m_currentDesktopSelected == ShowDashboard) { QDBusInterface plasmaApp("org.kde.plasma-desktop", "/App"); plasmaApp.call("toggleDashboard"); } } else { KWindowSystem::setCurrentDesktop(newDesktop + 1); setCurrentDesktop(newDesktop + 1); } } QPixmap Pager::shadowText(const QString &text) { QColor textColor = Plasma::Theme::defaultTheme()->color(Plasma::Theme::TextColor); return Plasma::PaintUtils::shadowText(text, KGlobalSettings::smallestReadableFont(), textColor, textColor.value() < 128 ? Qt::white : Qt::black, QPoint(0, 0), 2); } // KWindowSystem does not translate position when mapping viewports // to virtual desktops (it'd probably break more things than fix), // so the offscreen coordinates need to be fixed QRect Pager::fixViewportPosition( const QRect& r ) { QRect desktopGeom = m_desktopWidget->geometry(); int x = r.center().x() % desktopGeom.width(); int y = r.center().y() % desktopGeom.height(); if( x < 0 ) { x = x + desktopGeom.width(); } if( y < 0 ) { y = y + desktopGeom.height(); } return QRect( x - r.width() / 2, y - r.height() / 2, r.width(), r.height()); } void Pager::themeRefresh() { delete m_plasmaColorTheme; m_plasmaColorTheme = 0; updatePagerStyle(); update(); } void Pager::updateToolTip(int hoverDesktopId) { Plasma::ToolTipContent data; QString subtext; int taskCounter = 0; int displayedTaskCounter = 0; WindowModel *windows = m_pagerModel->windowsAt(hoverDesktopId); const int windowCount = windows ? windows->rowCount() : 0; for (; taskCounter < windowCount; taskCounter++) { WId id = windows->idAt(taskCounter); QString visibleName = windows->visibleNameAt(taskCounter); bool active = (id == KWindowSystem::activeWindow()); if (taskCounter < 4 || active) { // prefer to use the System Settings specified Small icon (usually 16x16) // TODO: should we actually be using Small for this? or Panel, Toolbar, etc? int iconSize = KIconLoader::global()->currentSize(KIconLoader::Small); QPixmap icon = KWindowSystem::icon(id, iconSize, iconSize, true); if (icon.isNull()) { subtext += "
•" + Qt::escape(visibleName); } else { data.addResource(Plasma::ToolTipContent::ImageResource, QUrl("wicon://" + QString::number(taskCounter)), QVariant(icon)); subtext += "
 "; } QFontMetricsF metrics(KGlobalSettings::taskbarFont()); const QString combined = (active ? "" : "") + Qt::escape(visibleName).replace(' ', " ") + (active ? "" : ""); // elide text that is too long subtext += metrics.elidedText(combined, Qt::ElideMiddle, MAX_TEXT_WIDTH, Qt::TextShowMnemonic); displayedTaskCounter++; } } if (taskCounter) { subtext.prepend(i18np("One window:", "%1 windows:", taskCounter)); } if (taskCounter - displayedTaskCounter > 0) { subtext.append("
" + i18np("and 1 other", "and %1 others", taskCounter - displayedTaskCounter) + ""); } data.setMainText(KWindowSystem::desktopName(hoverDesktopId + 1)); data.setSubText(subtext); Plasma::ToolTipManager::self()->setContent(this, data); } void Pager::dropMimeData(QObject* mime, int desktop) { QMimeData* mimeData = qobject_cast(mime); if (!mimeData) return; bool ok; QList ids = TaskManager::Task::idsFromMimeData(mimeData, &ok); if (ok) { foreach (const WId &id, ids) { KWindowSystem::setOnDesktop(id, desktop + 1); } } } #include "moc_pager.cpp"