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()