diff --git a/abstract_client.h b/abstract_client.h --- a/abstract_client.h +++ b/abstract_client.h @@ -414,6 +414,7 @@ virtual bool performMouseCommand(Options::MouseCommand, const QPoint &globalPos); void setOnAllDesktops(bool set); void setDesktop(int); + virtual void unSetDesktop(int desktop); int desktop() const override { return m_desktop; } diff --git a/abstract_client.cpp b/abstract_client.cpp --- a/abstract_client.cpp +++ b/abstract_client.cpp @@ -494,6 +494,7 @@ if (info) { info->setDesktop(desktop); } + if ((was_desk == NET::OnAllDesktops) != (desktop == NET::OnAllDesktops)) { // onAllDesktops changed workspace()->updateOnAllDesktopsOfTransients(this); @@ -529,6 +530,11 @@ Q_UNUSED(was_desk) } +void AbstractClient::unSetDesktop(int desktop) +{ + Q_UNUSED(desktop) +} + void AbstractClient::setOnAllDesktops(bool b) { if ((b && isOnAllDesktops()) || @@ -906,6 +912,41 @@ setShade(set); } ); + + w->addPlasmaVirtualDesktop(VirtualDesktopManager::self()->currentDesktop()->id()); + //Plasma Virtual desktop management + //show/hide when the window enters/exits from desktop + connect(w, &PlasmaWindowInterface::enterPlasmaVirtualDesktopRequested, this, + [this] (const QString &desktopId) { + m_windowManagementInterface->addPlasmaVirtualDesktop(desktopId); + VirtualDesktop *vd = VirtualDesktopManager::self()->desktopForId(desktopId.toUtf8()); + if (vd) { + workspace()->sendClientToDesktop(this, vd->x11DesktopNumber(), false); + } + } + ); + connect(w, &PlasmaWindowInterface::enterNewPlasmaVirtualDesktopRequested, this, + [this] () { + VirtualDesktopManager::self()->setCount(VirtualDesktopManager::self()->count() + 1); + workspace()->sendClientToDesktop(this, VirtualDesktopManager::self()->count(), false); + } + ); + connect(w, &PlasmaWindowInterface::leavePlasmaVirtualDesktopRequested, this, + [this] (const QString &desktopId) { + VirtualDesktop *vd = VirtualDesktopManager::self()->desktopForId(desktopId.toUtf8()); + if (vd) { + unSetDesktop(vd->x11DesktopNumber()); + } + } + ); + + //set initial visibility + if (w->plasmaVirtualDesktops().isEmpty() || w->plasmaVirtualDesktops().contains(VirtualDesktopManager::self()->currentDesktop()->id())) { + emit windowShown(this); + } else { + workspace()->clientHidden(this); + } + m_windowManagementInterface = w; } diff --git a/activation.cpp b/activation.cpp --- a/activation.cpp +++ b/activation.cpp @@ -413,6 +413,7 @@ */ void Workspace::clientHidden(AbstractClient* c) { +qWarning()<isShown(true) << c->isOnCurrentDesktop() << c->isOnCurrentActivity(); assert(!c->isShown(true) || !c->isOnCurrentDesktop() || !c->isOnCurrentActivity()); activateNextClient(c); } diff --git a/client.h b/client.h --- a/client.h +++ b/client.h @@ -122,6 +122,7 @@ void destroyClient(); virtual QStringList activities() const; + QStringList plasmaDesktops() const override; void setOnActivity(const QString &activity, bool enable); void setOnAllActivities(bool set) override; void setOnActivities(QStringList newActivitiesList) override; diff --git a/client.cpp b/client.cpp --- a/client.cpp +++ b/client.cpp @@ -1342,6 +1342,11 @@ return activityList; } +QStringList Client::plasmaDesktops() const +{ + return QStringList(); +} + /** * if @p on is true, sets on all activities. * if it's false, sets it to only be on the current activity diff --git a/deleted.h b/deleted.h --- a/deleted.h +++ b/deleted.h @@ -52,6 +52,7 @@ void discard(); virtual int desktop() const; virtual QStringList activities() const; + virtual QStringList plasmaDesktops() const; virtual QPoint clientPos() const; virtual QSize clientSize() const; QPoint clientContentPos() const override { diff --git a/deleted.cpp b/deleted.cpp --- a/deleted.cpp +++ b/deleted.cpp @@ -141,6 +141,11 @@ return activityList; } +QStringList Deleted::plasmaDesktops() const +{ + return QStringList(); +} + QPoint Deleted::clientPos() const { return contentsRect.topLeft(); diff --git a/shell_client.h b/shell_client.h --- a/shell_client.h +++ b/shell_client.h @@ -59,6 +59,8 @@ bool eventFilter(QObject *watched, QEvent *event) override; QStringList activities() const override; + QStringList plasmaDesktops() const override; + void unSetDesktop(int desktop) override; QPoint clientContentPos() const override; QSize clientSize() const override; QRect transparentRect() const override; @@ -167,6 +169,7 @@ void addDamage(const QRegion &damage) override; bool belongsToSameApplication(const AbstractClient *other, SameApplicationChecks checks) const override; void doSetActive() override; + void doSetDesktop(int desktop, int was_desk) override; Layer layerForDock() const override; void changeMaximize(bool horizontal, bool vertical, bool adjust) override; void setGeometryRestore(const QRect &geo) override { diff --git a/shell_client.cpp b/shell_client.cpp --- a/shell_client.cpp +++ b/shell_client.cpp @@ -414,6 +414,39 @@ return QStringList(); } +QStringList ShellClient::plasmaDesktops() const +{ + if (!windowManagementInterface()) { + return QStringList(); + } + + return windowManagementInterface()->plasmaVirtualDesktops(); +} + +void ShellClient::doSetDesktop(int desktop, int was_desk) +{ + //we need to redo this, because it can be set again to the same desktop number, + //because the old desktop may have been deleted + if (!windowManagementInterface()/* || desktop == was_desk*/) { + return; + } + + if (desktop == NET::OnAllDesktops) { + windowManagementInterface()->setOnAllDesktops(true); + } else { + windowManagementInterface()->addPlasmaVirtualDesktop(VirtualDesktopManager::self()->desktopForX11Id(desktop)->id()); + } +} + +void ShellClient::unSetDesktop(int desktop) +{ + if (!windowManagementInterface()) { + return; + } + + windowManagementInterface()->removePlasmaVirtualDesktop(VirtualDesktopManager::self()->desktopForX11Id(desktop)->id()); +} + QPoint ShellClient::clientContentPos() const { return -1 * clientPos(); diff --git a/toplevel.h b/toplevel.h --- a/toplevel.h +++ b/toplevel.h @@ -286,6 +286,7 @@ */ virtual int desktop() const = 0; virtual QStringList activities() const = 0; + virtual QStringList plasmaDesktops() const = 0; bool isOnDesktop(int d) const; bool isOnActivity(const QString &activity) const; bool isOnCurrentDesktop() const; @@ -776,7 +777,8 @@ inline bool Toplevel::isOnAllDesktops() const { - return desktop() == NET::OnAllDesktops; + //Wayland client + return surfaceId() > 0 ? plasmaDesktops().isEmpty() || (quint32)plasmaDesktops().count() == VirtualDesktopManager::self()->count() : desktop() == NET::OnAllDesktops; } inline bool Toplevel::isOnAllActivities() const @@ -786,7 +788,7 @@ inline bool Toplevel::isOnDesktop(int d) const { - return desktop() == d || /*desk == 0 ||*/ isOnAllDesktops(); + return desktop() == d || plasmaDesktops().contains(VirtualDesktopManager::self()->desktopForX11Id(d)->id()) || isOnAllDesktops(); } inline bool Toplevel::isOnActivity(const QString &activity) const diff --git a/unmanaged.h b/unmanaged.h --- a/unmanaged.h +++ b/unmanaged.h @@ -39,6 +39,7 @@ static void deleteUnmanaged(Unmanaged* c); virtual int desktop() const; virtual QStringList activities() const; + virtual QStringList plasmaDesktops() const; virtual QPoint clientPos() const; virtual QSize clientSize() const; virtual QRect transparentRect() const; diff --git a/unmanaged.cpp b/unmanaged.cpp --- a/unmanaged.cpp +++ b/unmanaged.cpp @@ -123,6 +123,11 @@ return QStringList(); } +QStringList Unmanaged::plasmaDesktops() const +{ + return QStringList(); +} + QPoint Unmanaged::clientPos() const { return QPoint(0, 0); // unmanaged windows don't have decorations diff --git a/useractions.h b/useractions.h --- a/useractions.h +++ b/useractions.h @@ -145,6 +145,11 @@ **/ void desktopPopupAboutToShow(); /** + * Adjusts the PlasmaDesktop popup to the current values and the location of + * the Client, Wayland only. + **/ + void plasmaDesktopPopupAboutToShow(); + /** * Adjusts the screen popup to the current values and the location of * the Client. **/ @@ -161,6 +166,12 @@ **/ void slotSendToDesktop(QAction *action); /** + * Toggle whether the Client is on a desktop (Wayland only) + * + * @param action Invoked Action containing the Desktop as data element + **/ + void slotToggleOnPlasmaDesktop(QAction *action); + /** * Sends the Client to screen \a screen * * @param action Invoked Action containing the Screen as data element @@ -218,6 +229,10 @@ **/ QMenu* m_desktopMenu; /** + * The move to desktop sub menu, with the Wayland protocol. + **/ + QMenu* m_plasmaDesktopMenu; + /** * The move to screen sub menu. **/ QMenu* m_screenMenu; diff --git a/useractions.cpp b/useractions.cpp --- a/useractions.cpp +++ b/useractions.cpp @@ -604,17 +604,33 @@ void UserActionsMenu::initDesktopPopup() { - if (m_desktopMenu) - return; + if (qobject_cast(m_client.data())) { + if (m_plasmaDesktopMenu) { + return; + } - m_desktopMenu = new QMenu(m_menu); - connect(m_desktopMenu, &QMenu::triggered, this, &UserActionsMenu::slotSendToDesktop); - connect(m_desktopMenu, &QMenu::aboutToShow, this, &UserActionsMenu::desktopPopupAboutToShow); + m_plasmaDesktopMenu = new QMenu(m_menu); + connect(m_plasmaDesktopMenu, &QMenu::triggered, this, &UserActionsMenu::slotToggleOnPlasmaDesktop); + connect(m_plasmaDesktopMenu, &QMenu::aboutToShow, this, &UserActionsMenu::plasmaDesktopPopupAboutToShow); - QAction *action = m_desktopMenu->menuAction(); - // set it as the first item - m_menu->insertAction(m_minimizeOperation, action); - action->setText(i18n("Move To &Desktop")); + QAction *action = m_plasmaDesktopMenu->menuAction(); + // set it as the first item + m_menu->insertAction(m_minimizeOperation, action); + action->setText(i18n("&Desktops")); + + } else { + if (m_desktopMenu) + return; + + m_desktopMenu = new QMenu(m_menu); + connect(m_desktopMenu, &QMenu::triggered, this, &UserActionsMenu::slotSendToDesktop); + connect(m_desktopMenu, &QMenu::aboutToShow, this, &UserActionsMenu::desktopPopupAboutToShow); + + QAction *action = m_desktopMenu->menuAction(); + // set it as the first item + m_menu->insertAction(m_minimizeOperation, action); + action->setText(i18n("Move To &Desktop")); + } } void UserActionsMenu::initScreenPopup() @@ -667,6 +683,7 @@ m_desktopMenu->addSeparator(); const uint BASE = 10; + for (uint i = 1; i <= vds->count(); ++i) { QString basic_name(QStringLiteral("%1 %2")); if (i < BASE) { @@ -690,6 +707,61 @@ action->setEnabled(false); } +void UserActionsMenu::plasmaDesktopPopupAboutToShow() +{ + if (!m_plasmaDesktopMenu) + return; + const VirtualDesktopManager *vds = VirtualDesktopManager::self(); + + m_plasmaDesktopMenu->clear(); + m_plasmaDesktopMenu->setPalette(m_client.data()->palette()); + QAction *action = m_plasmaDesktopMenu->addAction(i18n("&All Desktops")); + action->setData(0); + action->setCheckable(true); + static QPointer allDesktopsGroup; + if (!allDesktopsGroup) { + allDesktopsGroup = new QActionGroup(m_plasmaDesktopMenu); + } + allDesktopsGroup->addAction(action); + + if (!m_client.isNull() && m_client.data()->isOnAllDesktops()) { + action->setChecked(true); + } + m_plasmaDesktopMenu->addSeparator(); + + + const uint BASE = 10; + + for (uint i = 1; i <= vds->count(); ++i) { + QString basic_name(QStringLiteral("%1 %2")); + if (i < BASE) { + basic_name.prepend(QLatin1Char('&')); + } + QWidgetAction *action = new QWidgetAction(m_plasmaDesktopMenu); + QCheckBox *box = new QCheckBox(basic_name.arg(i).arg(vds->name(i).replace(QLatin1Char('&'), QStringLiteral("&&"))), m_plasmaDesktopMenu); + action->setDefaultWidget(box); + + box->setBackgroundRole(m_plasmaDesktopMenu->backgroundRole()); + box->setForegroundRole(m_plasmaDesktopMenu->foregroundRole()); + box->setPalette(m_plasmaDesktopMenu->palette()); + connect(box, &QCheckBox::clicked, action, &QAction::triggered); + m_plasmaDesktopMenu->addAction(action); + action->setData(i); + + if (!m_client.isNull() && + !m_client.data()->isOnAllDesktops() && m_client.data()->isOnDesktop(i)) { + box->setChecked(true); + } + } + + m_plasmaDesktopMenu->addSeparator(); + action = m_plasmaDesktopMenu->addAction(i18nc("Create a new desktop and move there the window", "&New Desktop")); + action->setData(vds->count() + 1); + + if (vds->count() >= vds->maximum()) + action->setEnabled(false); +} + void UserActionsMenu::screenPopupAboutToShow() { if (!m_screenMenu) { @@ -816,6 +888,35 @@ ws->sendClientToDesktop(m_client.data(), desk, false); } +void UserActionsMenu::slotToggleOnPlasmaDesktop(QAction *action) +{ + bool ok = false; + uint desk = action->data().toUInt(&ok); + if (!ok) { + return; + } + if (m_client.isNull()) { + return; + } + + Workspace *ws = Workspace::self(); + VirtualDesktopManager *vds = VirtualDesktopManager::self(); + if (desk == 0) { + // the 'on_all_desktops' menu entry + m_client.data()->setOnAllDesktops(!m_client.data()->isOnAllDesktops()); + return; + } else if (desk > vds->count()) { + vds->setCount(desk); + } + + const QByteArray id = VirtualDesktopManager::self()->desktopForX11Id(desk)->id(); + if (m_client.data()->plasmaDesktops().contains(id)) { + m_client.data()->unSetDesktop(desk); + } else { + ws->sendClientToDesktop(m_client.data(), desk, false); + } +} + void UserActionsMenu::slotSendToScreen(QAction *action) { const int screen = action->data().toInt(); diff --git a/virtualdesktops.h b/virtualdesktops.h --- a/virtualdesktops.h +++ b/virtualdesktops.h @@ -264,6 +264,29 @@ VirtualDesktop *desktopForX11Id(uint id) const; /** + * @returns The VirtualDesktop for the internal desktop string @p id, if no such VirtualDesktop @c null is returned + **/ + VirtualDesktop *desktopForId(const QByteArray &id) const; + + /** + * Create a new virtual desktop at the requested position. + * The difference with setCount is that setCount always adds new desktops at the end of the chain. The Id is automatically generated. + * @param x11DesktopNumber number for the desktop. The desktop created will have an + * x11DesktopNumber guaranteed to be between 1 and numberOfDesktops(). + * @param name The name for the new desktop, if empty the default name will be used. + * @returns the new VirtualDesktop, nullptr if we reached the maximum number of desktops + */ + VirtualDesktop *createVirtualDesktop(uint x11DesktopNumber, const QString &name = QString()); + + /** + * Remove the virtual desktop identified by id, if it exists + * difference with setCount is that is possible to remove an arbitrary desktop, + * not only the last one. + * @param id the string id of the desktop to remove + */ + void removeVirtualDesktop(const QByteArray &id); + + /** * Updates the net root info for new number of desktops **/ void updateRootInfo(); @@ -334,18 +357,21 @@ * @param newCount The new current number of desktops **/ void countChanged(uint previousCount, uint newCount); + /** - * Signal emitted whenever the number of virtual desktops changes in a way - * that existing desktops are removed. - * - * The signal is emitted after the @c count property has been updated but prior - * to the @link countChanged signal being emitted. - * @param previousCount The number of desktops prior to the change. - * @see countChanged - * @see setCount - * @see count - **/ - void desktopsRemoved(uint previousCount); + * A new desktop has been created + * @param desktop the new just crated desktop + */ + void desktopCreated(KWin::VirtualDesktop *desktop); + + /** + * A desktop has been removed and is about to be deleted + * @param desktop the desktop that has been removed. + * It's guaranteed to stil la valid pointer when the signal arrives, + * but it's about to be deleted. + */ + void desktopRemoved(KWin::VirtualDesktop *desktop); + /** * Signal emitted whenever the current desktop changes. * @param previousDesktop The virtual desktop changed from @@ -397,21 +423,6 @@ private: /** - * This method is called when the number of desktops is updated in a way that desktops - * are removed. At the time when this method is invoked the count property is already - * updated but the corresponding signal has not been emitted yet. - * - * Ensures that in case the current desktop is on one of the removed - * desktops the last desktop after the change becomes the new desktop. - * Emits the signal @link desktopsRemoved. - * - * @param previousCount The number of desktops prior to the change. - * @param previousCurrent The number of the previously current desktop. - * @see setCount - * @see desktopsRemoved - **/ - void handleDesktopsRemoved(uint previousCount, uint previousCurrent); - /** * Generate a desktop layout from EWMH _NET_DESKTOP_LAYOUT property parameters. */ void setNETDesktopLayout(Qt::Orientation orientation, uint width, uint height, int startingCorner); @@ -451,6 +462,7 @@ // TODO: QPointer NETRootInfo *m_rootInfo; KSharedConfig::Ptr m_config; + bool m_isLoading = false; KWIN_SINGLETON_VARIABLE(VirtualDesktopManager, s_manager) }; diff --git a/virtualdesktops.cpp b/virtualdesktops.cpp --- a/virtualdesktops.cpp +++ b/virtualdesktops.cpp @@ -27,6 +27,7 @@ #include // Qt #include +#include #include @@ -69,6 +70,7 @@ : m_size(1, 2) // Default to tow rows , m_grid(QVector>{QVector{}, QVector{}}) { + } VirtualDesktopGrid::~VirtualDesktopGrid() = default; @@ -325,6 +327,91 @@ return m_desktops.at(id - 1); } +VirtualDesktop *VirtualDesktopManager::desktopForId(const QByteArray &id) const +{ + auto desk = std::find_if( m_desktops.constBegin(), + m_desktops.constEnd(), + [id]( const VirtualDesktop *desk ){ return desk->id() == id; } ); + if (desk != m_desktops.constEnd()) { + return *desk; + } else { + return nullptr; + } +} + +VirtualDesktop *VirtualDesktopManager::createVirtualDesktop(uint number, const QString &name) +{ + //too many, can't insert new ones + if ((uint)m_desktops.count() == VirtualDesktopManager::maximum()) { + return nullptr; + } + + const uint actualNumber = qBound(0, number, VirtualDesktopManager::maximum()); + auto vd = new VirtualDesktop(this); + vd->setX11DesktopNumber(actualNumber); + //TODO: depend on Qt 5.11, use toString(QUuid::WithoutBraces) + vd->setId(QUuid::createUuid().toString().toUtf8()); + vd->setName(name); + if (m_rootInfo) { + connect(vd, &VirtualDesktop::nameChanged, this, + [this, vd]() { + if (m_rootInfo) { + m_rootInfo->setDesktopName(vd->x11DesktopNumber(), vd->name().toUtf8().data()); + } + } + ); + m_rootInfo->setDesktopName(vd->x11DesktopNumber(), vd->name().toUtf8().data()); + } + + //update the id of displaced desktops + for (uint i = actualNumber; i < (uint)m_desktops.count(); ++i) { + m_desktops[i]->setX11DesktopNumber(i + 1); + if (m_rootInfo) { + m_rootInfo->setDesktopName(i + 1, m_desktops[i]->name().toUtf8().data()); + } + } + + m_desktops.insert(actualNumber - 1, vd); + save(); + + emit desktopCreated(vd); + emit countChanged(m_desktops.count()-1, m_desktops.count()); + return vd; +} + +void VirtualDesktopManager::removeVirtualDesktop(const QByteArray &id) +{ + //don't end up without any desktop + if (m_desktops.count() == 1) { + return; + } + auto desktop = desktopForId(id); + if (!desktop) { + return; + } + + const uint oldCurrent = m_current->x11DesktopNumber(); + const uint i = desktop->x11DesktopNumber() - 1; + m_desktops.remove(i); + + for (uint j = i; j < (uint)m_desktops.count(); ++j) { + m_desktops[j]->setX11DesktopNumber(j + 1); + if (m_rootInfo) { + m_rootInfo->setDesktopName(j + 1, m_desktops[j]->name().toUtf8().data()); + } + } + + const uint newCurrent = qMin(oldCurrent, (uint)m_desktops.count()); + m_current = m_desktops.at(newCurrent - 1); + if (oldCurrent != newCurrent) { + emit currentChanged(oldCurrent, newCurrent); + } + + emit desktopRemoved(desktop); + + desktop->deleteLater(); +} + uint VirtualDesktopManager::current() const { return m_current ? m_current->x11DesktopNumber() : 0; @@ -364,33 +451,51 @@ // nothing to change return; } + QList newDesktops; const uint oldCount = m_desktops.count(); - const uint oldCurrent = current(); - while (uint(m_desktops.count()) > count) { - delete m_desktops.takeLast(); - } - while (uint(m_desktops.count()) < count) { - auto vd = new VirtualDesktop(this); - vd->setX11DesktopNumber(m_desktops.count() + 1); - m_desktops << vd; - } - if (oldCount > count) { - handleDesktopsRemoved(oldCount, oldCurrent); + //this explicit check makes it more readable + if ((uint)m_desktops.count() > count) { + const auto desktopsToRemove = m_desktops.mid(count-1); + m_desktops.resize(count); + int oldCurrent = current(); + for (auto desktop : desktopsToRemove) { + emit desktopRemoved(desktop); + desktop->deleteLater(); + } + int newCurrent = qMin(oldCurrent, m_desktops.count()); + m_current = m_desktops.at(newCurrent - 1); + if (oldCurrent != newCurrent) { + emit currentChanged(oldCurrent, newCurrent); + } + } else { + while (uint(m_desktops.count()) < count) { + auto vd = new VirtualDesktop(this); + vd->setX11DesktopNumber(m_desktops.count() + 1); + if (!m_isLoading) { + vd->setId(QUuid::createUuid().toString().toUtf8()); + } + m_desktops << vd; + newDesktops << vd; + if (m_rootInfo) { + connect(vd, &VirtualDesktop::nameChanged, this, + [this, vd]() { + if (m_rootInfo) { + m_rootInfo->setDesktopName(vd->x11DesktopNumber(), vd->name().toUtf8().data()); + } + } + ); + m_rootInfo->setDesktopName(vd->x11DesktopNumber(), vd->name().toUtf8().data()); + } + } } updateRootInfo(); save(); - emit countChanged(oldCount, m_desktops.count()); -} - -void VirtualDesktopManager::handleDesktopsRemoved(uint previousCount, uint previousCurrent) -{ - if (!m_current) { - m_current = m_desktops.last(); - emit currentChanged(previousCurrent, m_current->x11DesktopNumber()); + for (auto vd : newDesktops) { + emit desktopCreated(vd); } - emit desktopsRemoved(previousCount); + emit countChanged(oldCount, m_desktops.count()); } void VirtualDesktopManager::updateRootInfo() @@ -437,6 +542,8 @@ if (!m_config) { return; } + //FIXME: how to avoid this? + m_isLoading = true; QString groupname; if (screen_number == 0) { groupname = QStringLiteral("Desktops"); @@ -446,14 +553,26 @@ KConfigGroup group(m_config, groupname); const int n = group.readEntry("Number", 1); setCount(n); - if (m_rootInfo) { - for (int i = 1; i <= n; i++) { - QString s = group.readEntry(QStringLiteral("Name_%1").arg(i), i18n("Desktop %1", i)); + //Use kactivitymanagerdrc directly? + + for (int i = 1; i <= n; i++) { + QString s = group.readEntry(QStringLiteral("Name_%1").arg(i), i18n("Desktop %1", i)); + if (m_rootInfo) { m_rootInfo->setDesktopName(i, s.toUtf8().data()); - // TODO: update desktop focus chain, why? -// m_desktopFocusChain.value()[i-1] = i; } + m_desktops[i-1]->setName(s.toUtf8().data()); + s = group.readEntry(QStringLiteral("Id_%1").arg(i), QString()); + if (s.isEmpty()) { + s = QUuid::createUuid().toString(); + } + m_desktops[i-1]->setId(s.toUtf8().data()); + + // TODO: update desktop focus chain, why? +// m_desktopFocusChain.value()[i-1] = i; + } + + if (m_rootInfo) { int rows = group.readEntry("Rows", 2); rows = qBound(1, rows, n); // avoid weird cases like having 3 rows for 4 desktops, where the last row is unused @@ -464,7 +583,9 @@ m_rootInfo->setDesktopLayout(NET::OrientationHorizontal, columns, rows, NET::DesktopLayoutCornerTopLeft); m_rootInfo->activate(); } + s_loadingDesktopSettings = false; + m_isLoading = false; } void VirtualDesktopManager::save() @@ -502,6 +623,8 @@ group.deleteEntry(QStringLiteral("Name_%1").arg(i)); } } + + group.writeEntry(QStringLiteral("Id_%1").arg(i), m_desktops[i-1]->id()); } // Save to disk diff --git a/wayland_server.h b/wayland_server.h --- a/wayland_server.h +++ b/wayland_server.h @@ -54,6 +54,7 @@ class OutputInterface; class PlasmaShellInterface; class PlasmaShellSurfaceInterface; +class PlasmaVirtualDesktopManagementInterface; class PlasmaWindowManagementInterface; class QtSurfaceExtensionInterface; class OutputManagementInterface; @@ -99,6 +100,9 @@ KWayland::Server::ShellInterface *shell() { return m_shell; } + KWayland::Server::PlasmaVirtualDesktopManagementInterface *virtualDesktopManagement() { + return m_virtualDesktopManagement; + } KWayland::Server::PlasmaWindowManagementInterface *windowManagement() { return m_windowManagement; } @@ -226,6 +230,7 @@ KWayland::Server::XdgShellInterface *m_xdgShell6 = nullptr; KWayland::Server::PlasmaShellInterface *m_plasmaShell = nullptr; KWayland::Server::PlasmaWindowManagementInterface *m_windowManagement = nullptr; + KWayland::Server::PlasmaVirtualDesktopManagementInterface *m_virtualDesktopManagement = nullptr; KWayland::Server::QtSurfaceExtensionInterface *m_qtExtendedSurface = nullptr; KWayland::Server::ServerSideDecorationManagerInterface *m_decorationManager = nullptr; KWayland::Server::OutputManagementInterface *m_outputManagement = nullptr; diff --git a/wayland_server.cpp b/wayland_server.cpp --- a/wayland_server.cpp +++ b/wayland_server.cpp @@ -43,6 +43,7 @@ #include #include #include +#include #include #include #include @@ -328,6 +329,12 @@ workspace()->setShowingDesktop(set); } ); + + + m_virtualDesktopManagement = m_display->createPlasmaVirtualDesktopManagement(m_display); + m_virtualDesktopManagement->create(); + m_windowManagement->setPlasmaVirtualDesktopManagementInterface(m_virtualDesktopManagement); + auto shadowManager = m_display->createShadowManager(m_display); shadowManager->create(); @@ -385,6 +392,69 @@ void WaylandServer::initWorkspace() { + //TODO: RFC: those connections are better here or in VirtualDesktopManager itself? + //handle created: from VirtualDesktopManager to the wayland interface + connect(VirtualDesktopManager::self(), &VirtualDesktopManager::desktopCreated, this, + [this](VirtualDesktop *desktop) { + PlasmaVirtualDesktopInterface *pvd = m_virtualDesktopManagement->createDesktop(desktop->id(), desktop->x11DesktopNumber() - 1); + pvd->setName(desktop->name()); + pvd->sendDone(); + connect(desktop, &VirtualDesktop::nameChanged, this, + [this, desktop, pvd]() { + pvd->setName(desktop->name()); + } + ); + } + ); + + //handle removed: from VirtualDesktopManager to the wayland interface + connect(VirtualDesktopManager::self(), &VirtualDesktopManager::desktopRemoved, this, + [this](VirtualDesktop *desktop) { + m_virtualDesktopManagement->removeDesktop(desktop->id()); + } + ); + + //create a new desktop when the client asks to + connect (m_virtualDesktopManagement, &PlasmaVirtualDesktopManagementInterface::desktopCreateRequested, this, + [this](const QString &name, quint32 position) { + VirtualDesktop *vd = VirtualDesktopManager::self()->createVirtualDesktop(position); + if (vd) { + vd->setName(name); + } + } + ); + + //remove when the client asks to + connect (m_virtualDesktopManagement, &PlasmaVirtualDesktopManagementInterface::desktopRemoveRequested, this, + [this](const QString &id) { + //here there can be some nice kauthorized check? + //remove only from VirtualDesktopManager, the other connections will remove it from m_virtualDesktopManagement as well + VirtualDesktopManager::self()->removeVirtualDesktop(id.toUtf8()); + } + ); + + for (quint32 i = 1; i <= VirtualDesktopManager::self()->count(); ++i) { + VirtualDesktop *internalDesktop = VirtualDesktopManager::self()->desktopForX11Id(i); + PlasmaVirtualDesktopInterface *desktop = m_virtualDesktopManagement->createDesktop(internalDesktop->id()); + + desktop->setName(desktop->name()); + desktop->sendDone(); + + connect(desktop, &PlasmaVirtualDesktopInterface::activateRequested, this, + [this, desktop] () { + VirtualDesktopManager::self()->setCurrent(VirtualDesktopManager::self()->desktopForId(desktop->id().toUtf8())); + } + ); + } + //Now we are sure all ids are there + VirtualDesktopManager::self()->save(); + + connect(VirtualDesktopManager::self(), &VirtualDesktopManager::currentChanged, this, + [this]() { + m_virtualDesktopManagement->setActiveDesktop(VirtualDesktopManager::self()->currentDesktop()->id()); + } + ); + if (m_windowManagement) { connect(workspace(), &Workspace::showingDesktopChanged, this, [this] (bool set) { diff --git a/workspace.h b/workspace.h --- a/workspace.h +++ b/workspace.h @@ -457,7 +457,6 @@ void slotReloadConfig(); void updateCurrentActivity(const QString &new_activity); // virtual desktop handling - void moveClientsFromRemovedDesktops(); void slotDesktopCountChanged(uint previousCount, uint newCount); void slotCurrentDesktopChanged(uint oldDesktop, uint newDesktop); diff --git a/workspace.cpp b/workspace.cpp --- a/workspace.cpp +++ b/workspace.cpp @@ -219,7 +219,29 @@ // create VirtualDesktopManager and perform dependency injection VirtualDesktopManager *vds = VirtualDesktopManager::self(); - connect(vds, SIGNAL(desktopsRemoved(uint)), SLOT(moveClientsFromRemovedDesktops())); + connect(vds, &VirtualDesktopManager::desktopRemoved, this, + [this](KWin::VirtualDesktop *desktop) { + //Wayland + if (waylandServer()) { + for (auto it = m_allClients.constBegin(); it != m_allClients.constEnd(); ++it) { + if (!(*it)->isOnAllDesktops() && (*it)->plasmaDesktops().count() == 1) { + const QString deskId = (*it)->plasmaDesktops().first(); + if (desktop->id() == deskId) { + sendClientToDesktop(*it, qMin(desktop->x11DesktopNumber(), VirtualDesktopManager::self()->count()), true); + } + } + } + //X11 + } else { + for (auto it = m_allClients.constBegin(); it != m_allClients.constEnd(); ++it) { + if (!(*it)->isOnAllDesktops() && ((*it)->desktop() > static_cast(VirtualDesktopManager::self()->count()))) { + sendClientToDesktop(*it, VirtualDesktopManager::self()->count(), true); + } + } + } + } + ); + connect(vds, SIGNAL(countChanged(uint,uint)), SLOT(slotDesktopCountChanged(uint,uint))); connect(vds, SIGNAL(currentChanged(uint,uint)), SLOT(slotCurrentDesktopChanged(uint,uint))); vds->setNavigationWrappingAround(options->isRollOverDesktops()); @@ -1074,14 +1096,6 @@ #endif } -void Workspace::moveClientsFromRemovedDesktops() -{ - for (auto it = m_allClients.constBegin(); it != m_allClients.constEnd(); ++it) { - if (!(*it)->isOnAllDesktops() && (*it)->desktop() > static_cast(VirtualDesktopManager::self()->count())) - sendClientToDesktop(*it, VirtualDesktopManager::self()->count(), true); - } -} - void Workspace::slotDesktopCountChanged(uint previousCount, uint newCount) { Q_UNUSED(previousCount)