kde-workspace/plasma/applets/pager/pager.cpp

469 lines
14 KiB
C++
Raw Normal View History

/* This file is part of the KDE project
Copyright (C) 2023 Ivailo Monev <xakepa10@gmail.com>
2014-11-13 19:30:51 +02:00
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License version 2, as published by the Free Software Foundation.
2014-11-13 19:30:51 +02:00
This library 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
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
2014-11-13 19:30:51 +02:00
#include "pager.h"
#include <QX11Info>
#include <QGridLayout>
#include <QLabel>
#include <Plasma/Svg>
2014-11-13 19:30:51 +02:00
#include <Plasma/FrameSvg>
#include <Plasma/SvgWidget>
2014-11-13 19:30:51 +02:00
#include <Plasma/Theme>
#include <Plasma/ToolTipManager>
#include <KCModuleInfo>
#include <KWindowSystem>
#include <KIcon>
#include <KIconLoader>
#include <KDebug>
#include <netwm.h>
2014-11-13 19:30:51 +02:00
// standard issue margin/spacing
static const int s_spacing = 4;
static PagerApplet::PagerMode s_defaultpagermode = PagerApplet::ShowName;
2014-11-13 19:30:51 +02:00
static QString kElementPrefixForDesktop(const int desktop, const bool hovered)
2014-11-13 19:30:51 +02:00
{
if (hovered) {
return QString::fromLatin1("hover");
} else if (KWindowSystem::currentDesktop() == desktop) {
return QString::fromLatin1("active");
}
return QString::fromLatin1("normal");
2014-11-13 19:30:51 +02:00
}
static QRectF kAdjustRect(const QRectF &rect)
{
QRectF result = rect;
result.setWidth(result.width() - (s_spacing * 2));
return result;
}
static QFont kGetFont()
2014-11-13 19:30:51 +02:00
{
QFont font = KGlobalSettings::smallestReadableFont();
font.setBold(true);
return font;
2014-11-13 19:30:51 +02:00
}
static bool kHandleMouseEvent(QGraphicsSceneMouseEvent *event)
{
if (event->button() == Qt::MiddleButton) {
NETRootInfo netrootinfo(QX11Info::display(), NET::WM2ShowingDesktop | NET::Supported);
if (!netrootinfo.isSupported(NET::WM2ShowingDesktop)) {
kWarning() << "NET::WM2ShowingDesktop is not supported";
return false;
}
// that is how the showdesktop does it - it tracks the state internally
static bool s_didshow = false;
if (netrootinfo.showingDesktop() || s_didshow) {
s_didshow = false;
netrootinfo.setShowingDesktop(false);
} else {
s_didshow = true;
netrootinfo.setShowingDesktop(true);
}
return true;
}
return false;
}
class PagerSvg : public Plasma::SvgWidget
2014-11-13 19:30:51 +02:00
{
Q_OBJECT
public:
PagerSvg(const int desktop, const PagerApplet::PagerMode pagermode, QGraphicsItem *parent = nullptr);
2014-11-13 19:30:51 +02:00
void setup(const PagerApplet::PagerMode pagermode);
2014-11-13 19:30:51 +02:00
protected:
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) final;
QSizeF sizeHint(Qt::SizeHint which, const QSizeF & constraint) const final;
void hoverEnterEvent(QGraphicsSceneHoverEvent *event) final;
void hoverLeaveEvent(QGraphicsSceneHoverEvent *event) final;
// handled here too
void mouseReleaseEvent(QGraphicsSceneMouseEvent *event) final;
2014-11-13 19:30:51 +02:00
private Q_SLOTS:
void slotClicked(const Qt::MouseButton button);
void slotUpdate();
void slotUpdateSvgAndToolTip();
2014-11-13 19:30:51 +02:00
private:
int m_desktop;
bool m_hovered;
Plasma::FrameSvg* m_framesvg;
PagerApplet::PagerMode m_pagermode;
};
2014-11-13 19:30:51 +02:00
PagerSvg::PagerSvg(const int desktop, const PagerApplet::PagerMode pagermode, QGraphicsItem *parent)
: Plasma::SvgWidget(parent),
m_desktop(desktop),
m_hovered(false),
m_framesvg(nullptr),
m_pagermode(pagermode)
2014-11-13 19:30:51 +02:00
{
slotUpdateSvgAndToolTip();
setAcceptHoverEvents(true);
connect(
this, SIGNAL(clicked(Qt::MouseButton)),
this, SLOT(slotClicked(Qt::MouseButton))
);
connect(
KWindowSystem::self(), SIGNAL(currentDesktopChanged(int)),
this, SLOT(slotUpdate())
);
connect(
KWindowSystem::self(), SIGNAL(desktopNamesChanged()),
this, SLOT(slotUpdate())
);
connect(
Plasma::Theme::defaultTheme(), SIGNAL(themeChanged()),
this, SLOT(slotUpdateSvgAndToolTip())
);
}
void PagerSvg::setup(const PagerApplet::PagerMode pagermode)
{
m_pagermode = pagermode;
update();
}
2014-11-13 19:30:51 +02:00
void PagerSvg::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
Q_UNUSED(option);
Q_UNUSED(widget);
const QRectF brect = boundingRect();
m_framesvg->setElementPrefix(kElementPrefixForDesktop(m_desktop, m_hovered));
m_framesvg->resizeFrame(brect.size());
m_framesvg->paintFrame(painter, brect);
switch (m_pagermode) {
case PagerApplet::ShowNumber: {
painter->save();
painter->setFont(kGetFont());
painter->translate(s_spacing, 0);
painter->drawText(kAdjustRect(brect.toRect()), QString::number(m_desktop), QTextOption(Qt::AlignCenter));
painter->restore();
break;
}
case PagerApplet::ShowName: {
painter->save();
painter->setFont(kGetFont());
painter->translate(s_spacing, 0);
painter->drawText(kAdjustRect(brect.toRect()), KWindowSystem::desktopName(m_desktop), QTextOption(Qt::AlignCenter));
painter->restore();
break;
}
}
2014-11-13 19:30:51 +02:00
}
QSizeF PagerSvg::sizeHint(Qt::SizeHint which, const QSizeF &constraint) const
{
QSizeF result = Plasma::SvgWidget::sizeHint(which, constraint);
if (result.isNull()) {
// scalable images don't really scale well with hints..
result = (size() * 0.4);
}
if (m_pagermode == PagerApplet::ShowName) {
result.setWidth(result.width() * 2.5);
}
return result;
}
void PagerSvg::hoverEnterEvent(QGraphicsSceneHoverEvent *event)
2014-11-13 19:30:51 +02:00
{
Q_UNUSED(event);
m_hovered = true;
update();
2014-11-13 19:30:51 +02:00
}
void PagerSvg::hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
2014-11-13 19:30:51 +02:00
{
Q_UNUSED(event);
m_hovered = false;
update();
2014-11-13 19:30:51 +02:00
}
void PagerSvg::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
{
if (kHandleMouseEvent(event)) {
event->accept();
return;
}
Plasma::SvgWidget::mouseReleaseEvent(event);
}
void PagerSvg::slotClicked(const Qt::MouseButton button)
{
if (button == Qt::LeftButton) {
KWindowSystem::setCurrentDesktop(m_desktop);
}
}
void PagerSvg::slotUpdate()
{
update();
}
void PagerSvg::slotUpdateSvgAndToolTip()
2014-11-13 19:30:51 +02:00
{
if (m_framesvg) {
delete m_framesvg;
2014-11-13 19:30:51 +02:00
}
m_framesvg = new Plasma::FrameSvg(this);
m_framesvg->setImagePath("widgets/pager");
setSvg(m_framesvg);
Plasma::ToolTipContent plasmatooltip;
plasmatooltip.setMainText(QString::fromLatin1("<center>%1</center>").arg(KWindowSystem::desktopName(m_desktop)));
Plasma::ToolTipManager::self()->setContent(this, plasmatooltip);
2014-11-13 19:30:51 +02:00
}
PagerApplet::PagerApplet(QObject *parent, const QVariantList &args)
: Plasma::Applet(parent, args),
m_layout(nullptr),
m_adddesktopaction(nullptr),
m_removedesktopaction(nullptr),
m_pagermode(s_defaultpagermode),
m_pagermodebox(nullptr),
m_spacer(nullptr),
m_kcmdesktopproxy(nullptr)
{
KGlobal::locale()->insertCatalog("plasma_applet_pager");
setAspectRatioMode(Plasma::AspectRatioMode::IgnoreAspectRatio);
setHasConfigurationInterface(true);
2014-11-13 19:30:51 +02:00
m_layout = new QGraphicsLinearLayout(Qt::Horizontal, this);
// early setup to get proper initial size
slotUpdateLayout();
adjustSize();
2014-11-13 19:30:51 +02:00
}
void PagerApplet::init()
2014-11-13 19:30:51 +02:00
{
KConfigGroup configgroup = config();
const PagerApplet::PagerMode oldpagermode = m_pagermode;
m_pagermode = static_cast<PagerApplet::PagerMode>(configgroup.readEntry("pagerMode", static_cast<int>(s_defaultpagermode)));
if (oldpagermode != m_pagermode) {
// layout again with the new mode for size hints to apply correctly
slotUpdateLayout();
}
connect(
KWindowSystem::self(), SIGNAL(numberOfDesktopsChanged(int)),
this, SLOT(slotUpdateLayout())
);
2014-11-13 19:30:51 +02:00
}
void PagerApplet::createConfigurationInterface(KConfigDialog *parent)
2014-11-13 19:30:51 +02:00
{
QWidget* widget = new QWidget();
QGridLayout* widgetlayout = new QGridLayout(widget);
QLabel* pagermodelabel = new QLabel(widget);
pagermodelabel->setText(i18n("Text:"));
widgetlayout->addWidget(pagermodelabel, 0, 0);
m_pagermodebox = new QComboBox(widget);
m_pagermodebox->addItem(i18n("Desktop number"), static_cast<int>(PagerApplet::ShowNumber));
m_pagermodebox->addItem(i18n("Desktop name"), static_cast<int>(PagerApplet::ShowName));
m_pagermodebox->setCurrentIndex(static_cast<int>(m_pagermode));
widgetlayout->addWidget(m_pagermodebox, 0, 1);
m_spacer = new QSpacerItem(1, 1, QSizePolicy::Expanding, QSizePolicy::Expanding);
widgetlayout->addItem(m_spacer, 1, 0, 1, 2);
widget->setLayout(widgetlayout);
// doesn't look like media visualization but ok.. (that's what the clock applet uses)
parent->addPage(widget, i18n("Appearance"), "view-media-visualization");
m_kcmdesktopproxy = new KCModuleProxy("desktop");
parent->addPage(
m_kcmdesktopproxy, m_kcmdesktopproxy->moduleInfo().moduleName(),
m_kcmdesktopproxy->moduleInfo().icon()
);
connect(parent, SIGNAL(applyClicked()), this, SLOT(slotConfigAccepted()));
connect(parent, SIGNAL(okClicked()), this, SLOT(slotConfigAccepted()));
connect(m_pagermodebox, SIGNAL(currentIndexChanged(int)), parent, SLOT(settingsModified()));
connect(m_kcmdesktopproxy, SIGNAL(changed(bool)), parent, SLOT(settingsModified()));
2014-11-13 19:30:51 +02:00
}
QList<QAction*> PagerApplet::contextualActions()
2014-11-13 19:30:51 +02:00
{
return m_actions;
2014-11-13 19:30:51 +02:00
}
void PagerApplet::wheelEvent(QGraphicsSceneWheelEvent *event)
{
const int currentdesktop = KWindowSystem::currentDesktop();
if (event->delta() < 0) {
KWindowSystem::setCurrentDesktop(currentdesktop + 1);
} else {
KWindowSystem::setCurrentDesktop(currentdesktop - 1);
}
}
void PagerApplet::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
{
if (kHandleMouseEvent(event)) {
event->accept();
return;
}
Plasma::Applet::mouseReleaseEvent(event);
}
// NOTE: keep in sync with:
// plasma/applets/lockout/lockout.cpp
void PagerApplet::updateSizes()
2014-11-13 19:30:51 +02:00
{
switch (m_layout->orientation()) {
case Qt::Horizontal: {
setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding);
2014-11-13 19:30:51 +02:00
break;
}
case Qt::Vertical: {
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
2014-11-13 19:30:51 +02:00
break;
}
2014-11-13 19:30:51 +02:00
}
emit sizeHintChanged(Qt::PreferredSize);
2014-11-13 19:30:51 +02:00
}
void PagerApplet::constraintsEvent(Plasma::Constraints constraints)
2014-11-13 19:30:51 +02:00
{
// perfect size finder
// qDebug() << Q_FUNC_INFO << size();
if (constraints & Plasma::SizeConstraint || constraints & Plasma::FormFactorConstraint) {
switch (formFactor()) {
case Plasma::FormFactor::Horizontal: {
m_layout->setOrientation(Qt::Horizontal);
updateSizes();
return;
2014-11-13 19:30:51 +02:00
}
case Plasma::FormFactor::Vertical: {
m_layout->setOrientation(Qt::Vertical);
updateSizes();
return;
2014-11-13 19:30:51 +02:00
}
default: {
break;
2014-11-13 19:30:51 +02:00
}
}
const QSizeF appletsize = size();
if (appletsize.width() >= appletsize.height()) {
m_layout->setOrientation(Qt::Horizontal);
2014-11-13 19:30:51 +02:00
} else {
m_layout->setOrientation(Qt::Vertical);
2014-11-13 19:30:51 +02:00
}
updateSizes();
2014-11-13 19:30:51 +02:00
}
}
void PagerApplet::slotUpdateLayout()
2014-11-13 19:30:51 +02:00
{
QMutexLocker locker(&m_mutex);
foreach (PagerSvg* pagersvg, m_pagersvgs) {
m_layout->removeItem(pagersvg);
2014-11-13 19:30:51 +02:00
}
qDeleteAll(m_pagersvgs);
m_pagersvgs.clear();
2014-11-13 19:30:51 +02:00
const int numberofdesktops = KWindowSystem::numberOfDesktops();
m_layout->setContentsMargins(s_spacing, s_spacing, s_spacing, s_spacing);
for (int i = 0; i < numberofdesktops; i++) {
PagerSvg* pagersvg = new PagerSvg(i + 1, m_pagermode, this);
m_layout->addItem(pagersvg);
m_pagersvgs.append(pagersvg);
2014-11-13 19:30:51 +02:00
}
m_actions.clear();
if (!m_adddesktopaction) {
m_adddesktopaction = new QAction(
KIcon("list-add"), i18n("&Add Virtual Desktop"),
this
);
2014-11-13 19:30:51 +02:00
}
m_actions.append(m_adddesktopaction);
connect(
m_adddesktopaction, SIGNAL(triggered(bool)),
this , SLOT(slotAddDesktop())
);
if (numberofdesktops > 1) {
if (!m_removedesktopaction) {
m_removedesktopaction = new QAction(
KIcon("list-remove"), i18n("&Remove Last Virtual Desktop"),
this
);
}
m_actions.append(m_removedesktopaction);
connect(
m_removedesktopaction, SIGNAL(triggered(bool)),
this , SLOT(slotRemoveDesktop())
);
2014-11-13 19:30:51 +02:00
}
locker.unlock();
2014-11-13 19:30:51 +02:00
updateSizes();
// shrink or expand in panels but not otherwise, due to size hints it may happen anyway but it
// will not happen by adjustSize() call
const Plasma::FormFactor formfactor = formFactor();
switch (formFactor()) {
case Plasma::FormFactor::Planar:
case Plasma::FormFactor::MediaCenter:
case Plasma::FormFactor::Application: {
break;
}
default: {
adjustSize();
break;
}
}
2014-11-13 19:30:51 +02:00
}
void PagerApplet::slotAddDesktop()
2014-11-13 19:30:51 +02:00
{
NETRootInfo netrootinfo(QX11Info::display(), NET::NumberOfDesktops);
netrootinfo.setNumberOfDesktops(netrootinfo.numberOfDesktops() + 1);
2014-11-13 19:30:51 +02:00
}
void PagerApplet::slotRemoveDesktop()
2014-11-13 19:30:51 +02:00
{
NETRootInfo netrootinfo(QX11Info::display(), NET::NumberOfDesktops);
const int numberofdesktops = netrootinfo.numberOfDesktops();
if (numberofdesktops > 1) {
netrootinfo.setNumberOfDesktops(netrootinfo.numberOfDesktops() - 1);
2014-11-13 19:30:51 +02:00
} else {
kWarning() << "there is only one desktop";
2014-11-13 19:30:51 +02:00
}
}
void PagerApplet::slotConfigAccepted()
{
Q_ASSERT(m_pagermodebox != nullptr);
const int pagermodeindex = m_pagermodebox->currentIndex();
m_pagermode = static_cast<PagerApplet::PagerMode>(pagermodeindex);
KConfigGroup configgroup = config();
configgroup.writeEntry("pagerMode", pagermodeindex);
slotUpdateLayout();
m_kcmdesktopproxy->save();
emit configNeedsSaving();
}
2015-02-27 09:28:46 +00:00
#include "moc_pager.cpp"
#include "pager.moc"