14#include <KConfigGroup>
15#include <KGlobalAccel>
16#include <KLocalizedString>
29static bool s_loadingDesktopSettings =
false;
30static const double GESTURE_SWITCH_THRESHOLD = .25;
32static QString generateDesktopId()
34 return QUuid::createUuid().toString(QUuid::WithoutBraces);
49 Q_ASSERT(!m_virtualDesktopManagement);
50 m_virtualDesktopManagement = management;
52 auto createPlasmaVirtualDesktop = [
this](
VirtualDesktop *desktop) {
70 m_virtualDesktopManagement->
sendDone();
91 const QList<PlasmaVirtualDesktopInterface *> deskIfaces = m_virtualDesktopManagement->
desktops();
92 for (
auto *deskInt : deskIfaces) {
94 deskInt->setActive(
true);
96 deskInt->setActive(
false);
101 std::for_each(m_desktops.constBegin(), m_desktops.constEnd(), createPlasmaVirtualDesktop);
104 m_virtualDesktopManagement->
sendDone();
109 Q_ASSERT(m_id.isEmpty());
116 if (
static_cast<uint
>(m_x11DesktopNumber) == number) {
120 m_x11DesktopNumber = number;
122 if (m_x11DesktopNumber != 0) {
129 if (m_name ==
name) {
138 , m_grid(QList<QList<
VirtualDesktop *>>{QList<VirtualDesktop *>{}, QList<VirtualDesktop *>{}})
152 auto it = desktops.begin();
153 auto end = desktops.end();
154 for (uint y = 0; y <
height; ++y) {
155 QList<VirtualDesktop *> row;
156 for (uint x = 0; x <
width && it != end; ++x) {
166 return gridCoords(VirtualDesktopManager::self()->desktopForX11Id(
id));
171 for (
int y = 0; y < m_grid.count(); ++y) {
172 const auto &row = m_grid.at(y);
173 for (
int x = 0; x < row.count(); ++x) {
174 if (row.at(x) == vd) {
179 return QPoint(-1, -1);
184 if (coords.y() >= m_grid.count()) {
187 const auto &row = m_grid.at(coords.y());
188 if (coords.x() >= row.count()) {
191 return row.at(coords.x());
196VirtualDesktopManager::VirtualDesktopManager(QObject *parent)
198 , m_navigationWrapsAround(false)
199 , m_rootInfo(nullptr)
200 , m_swipeGestureReleasedY(new QAction(this))
201 , m_swipeGestureReleasedX(new QAction(this))
217 m_rootInfo->setCurrentDesktop(
currentDesktop()->x11DesktopNumber());
218 for (
auto *vd : std::as_const(m_desktops)) {
219 m_rootInfo->setDesktopName(vd->x11DesktopNumber(), vd->name().toUtf8().data());
228 return above(desktop, wrap);
230 return below(desktop, wrap);
234 return toLeft(desktop, wrap);
236 return next(desktop, wrap);
260 Q_ASSERT(coords.x() >= 0);
263 if (coords.y() < 0) {
265 coords.setY(m_grid.
height() - 1);
284 Q_ASSERT(coords.x() >= 0);
287 if (coords.x() >= m_grid.
width()) {
308 Q_ASSERT(coords.x() >= 0);
311 if (coords.y() >= m_grid.
height()) {
333 Q_ASSERT(coords.x() >= 0);
336 if (coords.x() < 0) {
338 coords.setX(m_grid.
width() - 1);
356 auto it = std::find(m_desktops.begin(), m_desktops.end(), desktop);
357 Q_ASSERT(it != m_desktops.end());
359 if (it == m_desktops.end()) {
361 return m_desktops.first();
375 auto it = std::find(m_desktops.begin(), m_desktops.end(), desktop);
376 Q_ASSERT(it != m_desktops.end());
377 if (it == m_desktops.begin()) {
379 return m_desktops.last();
390 if (
id == 0 ||
id >
count()) {
393 return m_desktops.at(
id - 1);
398 auto desk = std::find_if(
399 m_desktops.constBegin(),
400 m_desktops.constEnd(),
402 return desk->id() == id;
405 if (desk != m_desktops.constEnd()) {
419 position = std::clamp(position, 0u,
static_cast<uint
>(m_desktops.count()));
421 QString desktopName = name;
422 if (desktopName.isEmpty()) {
423 desktopName = defaultName(position + 1);
427 vd->setX11DesktopNumber(position + 1);
428 vd->setId(generateDesktopId());
429 vd->setName(desktopName);
433 m_rootInfo->setDesktopName(vd->x11DesktopNumber(), vd->name().toUtf8().data());
438 m_rootInfo->setDesktopName(vd->x11DesktopNumber(), vd->name().toUtf8().data());
441 m_desktops.insert(position, vd);
444 for (uint i = position + 1; i < (uint)m_desktops.count(); ++i) {
445 m_desktops[i]->setX11DesktopNumber(i + 1);
447 m_rootInfo->setDesktopName(i + 1, m_desktops[i]->name().toUtf8().data());
456 Q_EMIT
countChanged(m_desktops.count() - 1, m_desktops.count());
471 if (m_desktops.count() == 1) {
475 const int i = m_desktops.indexOf(desktop);
476 m_desktops.remove(i);
478 for (
int j = i; j < m_desktops.count(); ++j) {
479 m_desktops[j]->setX11DesktopNumber(j + 1);
481 m_rootInfo->setDesktopName(j + 1, m_desktops[j]->name().toUtf8().data());
485 if (m_current == desktop) {
486 m_current = (i < m_desktops.count()) ? m_desktops.at(i) : m_desktops.constLast();
495 Q_EMIT
countChanged(m_desktops.count() + 1, m_desktops.count());
497 desktop->deleteLater();
502 return m_current ? m_current->x11DesktopNumber() : 0;
512 if (newDesktop < 1 || newDesktop >
count()) {
522 Q_ASSERT(newDesktop);
523 if (m_current == newDesktop) {
527 m_current = newDesktop;
535 if (
count == uint(m_desktops.count())) {
539 QList<VirtualDesktop *> newDesktops;
540 const uint oldCount = m_desktops.count();
542 if ((uint)m_desktops.count() >
count) {
543 const auto desktopsToRemove = m_desktops.mid(
count);
544 m_desktops.resize(
count);
545 if (m_current && desktopsToRemove.contains(m_current)) {
547 m_current = m_desktops.last();
550 for (
auto desktop : desktopsToRemove) {
552 desktop->deleteLater();
555 while (uint(m_desktops.count()) <
count) {
557 const int x11Number = m_desktops.count() + 1;
558 vd->setX11DesktopNumber(x11Number);
559 vd->setName(defaultName(x11Number));
560 if (!s_loadingDesktopSettings) {
561 vd->setId(generateDesktopId());
567 m_rootInfo->setDesktopName(vd->x11DesktopNumber(), vd->name().toUtf8().data());
571 m_rootInfo->setDesktopName(vd->x11DesktopNumber(), vd->name().toUtf8().data());
577 m_current = m_desktops.at(0);
583 if (!s_loadingDesktopSettings) {
586 for (
auto vd : std::as_const(newDesktops)) {
612 const int n =
count();
613 m_rootInfo->setNumberOfDesktops(n);
614 NETPoint *viewports =
new NETPoint[n];
615 m_rootInfo->setDesktopViewport(n, *viewports);
617 m_rootInfo->setDesktopLayout(NET::OrientationHorizontal, m_grid.
width(), m_grid.
height(), NET::DesktopLayoutCornerTopLeft);
623 m_rows = std::min(m_rows,
count());
625 int columns =
count() / m_rows;
626 if (
count() % m_rows > 0) {
630 m_grid.
update(QSize(columns, m_rows), m_desktops);
638 s_loadingDesktopSettings =
true;
643 KConfigGroup group(m_config, QStringLiteral(
"Desktops"));
644 const int n = group.readEntry(
"Number", 1);
647 for (
int i = 1; i <= n; i++) {
648 QString s = group.readEntry(QStringLiteral(
"Name_%1").arg(i), i18n(
"Desktop %1", i));
650 m_rootInfo->setDesktopName(i, s.toUtf8().data());
652 m_desktops[i - 1]->setName(s);
654 const QString sId = group.readEntry(QStringLiteral(
"Id_%1").arg(i), QString());
656 if (m_desktops[i - 1]->
id().isEmpty()) {
657 m_desktops[i - 1]->setId(sId.isEmpty() ? generateDesktopId() : sId);
659 Q_ASSERT(sId.isEmpty() || m_desktops[i - 1]->id() == sId);
666 int rows = group.readEntry<
int>(
"Rows", 2);
667 m_rows = std::clamp(
rows, 1, n);
669 s_loadingDesktopSettings =
false;
674 if (s_loadingDesktopSettings) {
680 KConfigGroup group(m_config, QStringLiteral(
"Desktops"));
682 for (
int i =
count() + 1; group.hasKey(QStringLiteral(
"Id_%1").arg(i)); i++) {
683 group.deleteEntry(QStringLiteral(
"Id_%1").arg(i));
684 group.deleteEntry(QStringLiteral(
"Name_%1").arg(i));
687 group.writeEntry(
"Number",
count());
689 const uint position = desktop->x11DesktopNumber();
691 QString s = desktop->name();
692 const QString defaultvalue = defaultName(position);
696 m_rootInfo->setDesktopName(position, s.toUtf8().data());
700 if (s != defaultvalue) {
701 group.writeEntry(QStringLiteral(
"Name_%1").arg(position), s);
703 QString currentvalue = group.readEntry(QStringLiteral(
"Name_%1").arg(position), QString());
704 if (currentvalue != defaultvalue) {
705 group.deleteEntry(QStringLiteral(
"Name_%1").arg(position));
708 group.writeEntry(QStringLiteral(
"Id_%1").arg(position), desktop->id());
711 group.writeEntry(
"Rows", m_rows);
717QString VirtualDesktopManager::defaultName(
int desktop)
const
719 return i18n(
"Desktop %1", desktop);
724 initSwitchToShortcuts();
726 addAction(QStringLiteral(
"Switch to Next Desktop"), i18n(
"Switch to Next Desktop"), QKeySequence(), &VirtualDesktopManager::slotNext);
727 addAction(QStringLiteral(
"Switch to Previous Desktop"), i18n(
"Switch to Previous Desktop"), QKeySequence(), &VirtualDesktopManager::slotPrevious);
730 addAction(QStringLiteral(
"Switch One Desktop to the Right"), i18n(
"Switch One Desktop to the Right"), QKeySequence(Qt::CTRL | Qt::META | Qt::Key_Right), &VirtualDesktopManager::slotRight);
731 addAction(QStringLiteral(
"Switch One Desktop to the Left"), i18n(
"Switch One Desktop to the Left"), QKeySequence(Qt::CTRL | Qt::META | Qt::Key_Left), &VirtualDesktopManager::slotLeft);
732 addAction(QStringLiteral(
"Switch One Desktop Up"), i18n(
"Switch One Desktop Up"), QKeySequence(Qt::CTRL | Qt::META | Qt::Key_Up), &VirtualDesktopManager::slotUp);
733 addAction(QStringLiteral(
"Switch One Desktop Down"), i18n(
"Switch One Desktop Down"), QKeySequence(Qt::CTRL | Qt::META | Qt::Key_Down), &VirtualDesktopManager::slotDown);
737 connect(m_swipeGestureReleasedX.get(), &QAction::triggered,
this, &VirtualDesktopManager::gestureReleasedX);
738 connect(m_swipeGestureReleasedY.get(), &QAction::triggered,
this, &VirtualDesktopManager::gestureReleasedY);
740 const auto left = [
this](qreal cb) {
742 m_currentDesktopOffset.setX(cb);
746 const auto right = [
this](qreal cb) {
748 m_currentDesktopOffset.setX(-cb);
757 if (grid().height() > 1) {
758 m_currentDesktopOffset.setY(-cb);
759 Q_EMIT currentChanging(currentDesktop(), m_currentDesktopOffset);
763 if (grid().height() > 1) {
764 m_currentDesktopOffset.setY(cb);
765 Q_EMIT currentChanging(currentDesktop(), m_currentDesktopOffset);
773 findChild<QAction *>(QStringLiteral(
"Switch to Next Desktop")));
775 findChild<QAction *>(QStringLiteral(
"Switch to Previous Desktop")));
778void VirtualDesktopManager::gestureReleasedY()
782 VirtualDesktop *target = m_current;
783 if (m_currentDesktopOffset.y() <= -GESTURE_SWITCH_THRESHOLD) {
784 target = above(m_current, isNavigationWrappingAround());
785 }
else if (m_currentDesktopOffset.y() >= GESTURE_SWITCH_THRESHOLD) {
786 target = below(m_current, isNavigationWrappingAround());
790 if (m_current != target) {
793 Q_EMIT currentChangingCancelled();
795 m_currentDesktopOffset = QPointF(0, 0);
798void VirtualDesktopManager::gestureReleasedX()
802 VirtualDesktop *target = m_current;
803 if (m_currentDesktopOffset.x() <= -GESTURE_SWITCH_THRESHOLD) {
804 target = toLeft(m_current, isNavigationWrappingAround());
805 }
else if (m_currentDesktopOffset.x() >= GESTURE_SWITCH_THRESHOLD) {
806 target = toRight(m_current, isNavigationWrappingAround());
810 if (m_current != target) {
813 Q_EMIT currentChangingCancelled();
815 m_currentDesktopOffset = QPointF(0, 0);
818void VirtualDesktopManager::initSwitchToShortcuts()
820 const QString toDesktop = QStringLiteral(
"Switch to Desktop %1");
821 const KLocalizedString toDesktopLabel = ki18n(
"Switch to Desktop %1");
822 addAction(toDesktop, toDesktopLabel, 1, QKeySequence(Qt::CTRL | Qt::Key_F1), &VirtualDesktopManager::slotSwitchTo);
823 addAction(toDesktop, toDesktopLabel, 2, QKeySequence(Qt::CTRL | Qt::Key_F2), &VirtualDesktopManager::slotSwitchTo);
824 addAction(toDesktop, toDesktopLabel, 3, QKeySequence(Qt::CTRL | Qt::Key_F3), &VirtualDesktopManager::slotSwitchTo);
825 addAction(toDesktop, toDesktopLabel, 4, QKeySequence(Qt::CTRL | Qt::Key_F4), &VirtualDesktopManager::slotSwitchTo);
827 for (uint i = 5; i <= maximum(); ++i) {
828 addAction(toDesktop, toDesktopLabel, i, QKeySequence(), &VirtualDesktopManager::slotSwitchTo);
832QAction *VirtualDesktopManager::addAction(
const QString &name,
const KLocalizedString &label, uint value,
const QKeySequence &key,
void (VirtualDesktopManager::*slot)())
834 QAction *a =
new QAction(
this);
835 a->setProperty(
"componentName", QStringLiteral(
"kwin"));
836 a->setObjectName(name.arg(value));
837 a->setText(label.subs(value).toString());
839 KGlobalAccel::setGlobalShortcut(a, key);
840 connect(a, &QAction::triggered,
this, slot);
844QAction *VirtualDesktopManager::addAction(
const QString &name,
const QString &label,
const QKeySequence &key,
void (VirtualDesktopManager::*slot)())
846 QAction *a =
new QAction(
this);
847 a->setProperty(
"componentName", QStringLiteral(
"kwin"));
848 a->setObjectName(name);
850 KGlobalAccel::setGlobalShortcut(a, key);
851 connect(a, &QAction::triggered,
this, slot);
855void VirtualDesktopManager::slotSwitchTo()
857 QAction *act = qobject_cast<QAction *>(sender());
862 const uint i = act->data().toUInt(&ok);
871 if (enabled == m_navigationWrapsAround) {
874 m_navigationWrapsAround = enabled;
878void VirtualDesktopManager::slotDown()
883void VirtualDesktopManager::slotLeft()
888void VirtualDesktopManager::slotPrevious()
893void VirtualDesktopManager::slotNext()
898void VirtualDesktopManager::slotRight()
903void VirtualDesktopManager::slotUp()
910#include "moc_virtualdesktops.cpp"
void setName(const QString &name)
Wrapper for the org_kde_plasma_virtual_desktop_management interface.
QList< PlasmaVirtualDesktopInterface * > desktops() const
PlasmaVirtualDesktopInterface * createDesktop(const QString &id, quint32 position=std::numeric_limits< uint32_t >::max())
void setRows(quint32 rows)
void desktopCreateRequested(const QString &name, quint32 position)
void desktopRemoveRequested(const QString &id)
void removeDesktop(const QString &id)
void update(const QSize &size, const QList< VirtualDesktop * > &desktops)
QPoint gridCoords(uint id) const
VirtualDesktop * at(const QPoint &coords) const
const QSize & size() const
void aboutToBeDestroyed()
void setId(const QString &id)
void x11DesktopNumberChanged()
void setX11DesktopNumber(uint number)
void setName(const QString &name)
VirtualDesktop(QObject *parent=nullptr)
~VirtualDesktop() override
Manages the number of available virtual desktops, the layout of those and which virtual desktop is th...
VirtualDesktop * previous(VirtualDesktop *desktop=nullptr, bool wrap=true) const
const VirtualDesktopGrid & grid() const
void moveTo(bool wrap=false)
void layoutChanged(int columns, int rows)
void setRootInfo(NETRootInfo *info)
void removeVirtualDesktop(const QString &id)
void setVirtualDesktopManagement(PlasmaVirtualDesktopManagementInterface *management)
VirtualDesktop * desktopForId(const QString &id) const
VirtualDesktop * above(VirtualDesktop *desktop, bool wrap=true) const
void desktopAdded(KWin::VirtualDesktop *desktop)
VirtualDesktop * createVirtualDesktop(uint position, const QString &name=QString())
void countChanged(uint previousCount, uint newCount)
~VirtualDesktopManager() override
void currentChanging(KWin::VirtualDesktop *currentDesktop, QPointF offset)
VirtualDesktop * inDirection(VirtualDesktop *desktop, Direction direction, bool wrap=true)
VirtualDesktop * currentDesktop() const
void navigationWrappingAroundChanged()
void currentChanged(KWin::VirtualDesktop *previousDesktop, KWin::VirtualDesktop *newDesktop)
VirtualDesktop * below(VirtualDesktop *desktop, bool wrap=true) const
void setCount(uint count)
VirtualDesktop * desktopForX11Id(uint id) const
VirtualDesktop * toRight(VirtualDesktop *desktop, bool wrap=true) const
void rowsChanged(uint rows)
VirtualDesktop * toLeft(VirtualDesktop *desktop, bool wrap=true) const
VirtualDesktop * next(VirtualDesktop *desktop=nullptr, bool wrap=true) const
void setNavigationWrappingAround(bool enabled)
bool setCurrent(uint current)
void desktopRemoved(KWin::VirtualDesktop *desktop)
bool isNavigationWrappingAround() const
#define KWIN_SINGLETON_FACTORY_VARIABLE(ClassName, variableName)
InputRedirection * input()