2014-11-13 19:30:51 +02:00
|
|
|
/***************************************************************************
|
|
|
|
* Copyright (C) 2007 by Daniel Laidig <d.laidig@gmx.de> *
|
|
|
|
* Copyright (C) 2012 by Luís Gabriel Lima <lampih@gmail.com> *
|
|
|
|
* *
|
|
|
|
* 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 <math.h>
|
|
|
|
|
|
|
|
#include <QFont>
|
|
|
|
#include <QTimer>
|
2015-08-12 13:11:16 +03:00
|
|
|
#include <QtGui/qx11info_x11.h>
|
2014-11-13 19:30:51 +02:00
|
|
|
#include <QDBusInterface>
|
|
|
|
#include <QTextDocument>
|
|
|
|
#include <QDesktopWidget>
|
|
|
|
#include <QtGui/QGraphicsLinearLayout>
|
|
|
|
#include <QtDeclarative/QDeclarativeEngine>
|
|
|
|
#include <QtDeclarative/QDeclarativeContext>
|
|
|
|
|
|
|
|
#include <KCModuleInfo>
|
|
|
|
#include <KCModuleProxy>
|
|
|
|
#include <KColorScheme>
|
|
|
|
#include <KConfigDialog>
|
|
|
|
#include <KGlobalSettings>
|
|
|
|
#include <KIconLoader>
|
|
|
|
#include <KWindowSystem>
|
|
|
|
#include <NETRootInfo>
|
|
|
|
|
|
|
|
#include <Plasma/FrameSvg>
|
|
|
|
#include <Plasma/PaintUtils>
|
|
|
|
#include <Plasma/Theme>
|
|
|
|
#include <Plasma/ToolTipManager>
|
|
|
|
#include <Plasma/DeclarativeWidget>
|
|
|
|
#include <Plasma/Package>
|
|
|
|
|
|
|
|
#include <taskmanager/task.h>
|
|
|
|
|
|
|
|
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())
|
|
|
|
{
|
2016-01-14 05:21:48 +02:00
|
|
|
setAcceptHoverEvents(true);
|
2014-11-13 19:30:51 +02:00
|
|
|
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<CurrentDesktopSelected>(cg.readEntry("currentDesktopSelected",
|
|
|
|
static_cast<int>(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<QAction*> 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<WId> 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);
|
2015-04-20 14:10:36 +00:00
|
|
|
NET::WindowType type = info.windowType(NET::NormalMask | NET::DialogMask |
|
2014-11-13 19:30:51 +02:00
|
|
|
NET::UtilityMask | NET::DesktopMask | NET::DockMask |
|
2016-03-26 22:15:58 +00:00
|
|
|
NET::SplashMask | NET::ToolbarMask | NET::MenuMask);
|
2014-11-13 19:30:51 +02:00
|
|
|
|
|
|
|
// 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.
|
2016-03-26 22:15:58 +00:00
|
|
|
if (type == NET::Desktop || type == NET::Dock || type == NET::Splash
|
|
|
|
|| type == NET::Menu || type == NET::Toolbar ||
|
2014-11-13 19:30:51 +02:00
|
|
|
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)
|
|
|
|
|
2015-01-15 20:23:51 +00:00
|
|
|
if (dirty[NETWinInfo::PROTOCOLS] & (NET::WMGeometry | NET::WMDesktop)) {
|
2014-11-13 19:30:51 +02:00
|
|
|
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 += "<br />•" + Qt::escape(visibleName);
|
|
|
|
} else {
|
|
|
|
data.addResource(Plasma::ToolTipContent::ImageResource,
|
|
|
|
QUrl("wicon://" + QString::number(taskCounter)),
|
|
|
|
QVariant(icon));
|
|
|
|
subtext += "<br /><img src=\"wicon://" + QString::number(taskCounter)
|
|
|
|
+ "\"/> ";
|
|
|
|
}
|
|
|
|
|
|
|
|
QFontMetricsF metrics(KGlobalSettings::taskbarFont());
|
|
|
|
const QString combined = (active ? "<u>" : "")
|
|
|
|
+ Qt::escape(visibleName).replace(' ', " ")
|
|
|
|
+ (active ? "</u>" : "");
|
|
|
|
// 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("<br>• <i>" + i18np("and 1 other", "and %1 others",
|
|
|
|
taskCounter - displayedTaskCounter) + "</i>");
|
|
|
|
}
|
|
|
|
|
|
|
|
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<QMimeData*>(mime);
|
|
|
|
if (!mimeData)
|
|
|
|
return;
|
|
|
|
bool ok;
|
|
|
|
QList<WId> ids = TaskManager::Task::idsFromMimeData(mimeData, &ok);
|
|
|
|
if (ok) {
|
|
|
|
foreach (const WId &id, ids) {
|
|
|
|
KWindowSystem::setOnDesktop(id, desktop + 1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-02-27 09:28:46 +00:00
|
|
|
#include "moc_pager.cpp"
|