scripting: Introduce VirtualDesktopModel

This can be useful for QML scripts that deal with virtual desktops.

The virtual desktop model keeps a copy of virtual desktop objects to
avoid hitting asserts in QAbstractItemModel (it has some asserts to
ensure that indices passed to beginInsertRows() or beginRemoveRows()
make sense).
This commit is contained in:
Vlad Zahorodnii 2021-08-03 10:30:20 +03:00
parent 2e56b718ea
commit d73610d6d6
6 changed files with 153 additions and 4 deletions

View file

@ -101,6 +101,7 @@ set(kwin_SRCS
screens.cpp
scripting/v2/clientmodel.cpp
scripting/v3/clientmodel.cpp
scripting/v3/virtualdesktopmodel.cpp
scripting/dbuscall.cpp
scripting/screenedgeitem.cpp
scripting/scriptedeffect.cpp

View file

@ -20,6 +20,7 @@
#include "v2/clientmodel.h"
#include "v3/clientmodel.h"
#include "v3/virtualdesktopmodel.h"
#include "input.h"
#include "options.h"
@ -649,6 +650,7 @@ void KWin::Scripting::init()
qmlRegisterType<ScreenEdgeItem>("org.kde.kwin", 3, 0, "ScreenEdgeItem");
qmlRegisterType<ScriptingModels::V3::ClientModel>("org.kde.kwin", 3, 0, "ClientModel");
qmlRegisterType<ScriptingModels::V3::ClientFilterModel>("org.kde.kwin", 3, 0, "ClientFilterModel");
qmlRegisterType<ScriptingModels::V3::VirtualDesktopModel>("org.kde.kwin", 3, 0, "VirtualDesktopModel");
qmlRegisterSingletonType<QtScriptWorkspaceWrapper>("org.kde.kwin", 3, 0, "Workspace", [](QQmlEngine *qmlEngine, QJSEngine *jsEngine) {
Q_UNUSED(qmlEngine)

View file

@ -0,0 +1,91 @@
/*
SPDX-FileCopyrightText: 2021 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "virtualdesktopmodel.h"
#include "virtualdesktops.h"
namespace KWin::ScriptingModels::V3
{
VirtualDesktopModel::VirtualDesktopModel(QObject *parent)
: QAbstractListModel(parent)
{
VirtualDesktopManager *manager = VirtualDesktopManager::self();
connect(manager, &VirtualDesktopManager::desktopCreated,
this, &VirtualDesktopModel::handleVirtualDesktopAdded);
connect(manager, &VirtualDesktopManager::desktopRemoved,
this, &VirtualDesktopModel::handleVirtualDesktopRemoved);
m_virtualDesktops = manager->desktops();
}
void VirtualDesktopModel::create(uint position, const QString &name)
{
VirtualDesktopManager::self()->createVirtualDesktop(position, name);
}
void VirtualDesktopModel::remove(uint position)
{
if (position < m_virtualDesktops.count()) {
VirtualDesktopManager::self()->removeVirtualDesktop(m_virtualDesktops[position]);
}
}
void VirtualDesktopModel::handleVirtualDesktopAdded(VirtualDesktop *desktop)
{
const int position = desktop->x11DesktopNumber() - 1;
beginInsertRows(QModelIndex(), position, position);
m_virtualDesktops.insert(position, desktop);
endInsertRows();
}
void VirtualDesktopModel::handleVirtualDesktopRemoved(VirtualDesktop *desktop)
{
const int index = m_virtualDesktops.indexOf(desktop);
Q_ASSERT(index != -1);
beginRemoveRows(QModelIndex(), index, index);
m_virtualDesktops.removeAt(index);
endRemoveRows();
}
QHash<int, QByteArray> VirtualDesktopModel::roleNames() const
{
QHash<int, QByteArray> roleNames = QAbstractListModel::roleNames();
roleNames.insert(DesktopRole, QByteArrayLiteral("desktop"));
return roleNames;
}
VirtualDesktop *VirtualDesktopModel::desktopFromIndex(const QModelIndex &index) const
{
if (!index.isValid() || index.row() < 0 || index.row() >= m_virtualDesktops.count()) {
return nullptr;
}
return m_virtualDesktops[index.row()];
}
QVariant VirtualDesktopModel::data(const QModelIndex &index, int role) const
{
VirtualDesktop *desktop = desktopFromIndex(index);
if (!desktop) {
return QVariant();
}
switch (role) {
case Qt::DisplayRole:
case DesktopRole:
return QVariant::fromValue(desktop);
default:
return QVariant();
}
}
int VirtualDesktopModel::rowCount(const QModelIndex &parent) const
{
return parent.isValid() ? 0 : m_virtualDesktops.count();
}
} // namespace KWin::ScriptingModels::V3

View file

@ -0,0 +1,50 @@
/*
SPDX-FileCopyrightText: 2021 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#pragma once
#include <QAbstractListModel>
namespace KWin
{
class VirtualDesktop;
namespace ScriptingModels::V3
{
/**
* The VirtualDesktopModel class provides a data model for the virtual desktops.
*/
class VirtualDesktopModel : public QAbstractListModel
{
Q_OBJECT
public:
enum Role {
DesktopRole = Qt::UserRole + 1,
};
explicit VirtualDesktopModel(QObject *parent = nullptr);
QHash<int, QByteArray> roleNames() const override;
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
public Q_SLOTS:
void create(uint position, const QString &name = QString());
void remove(uint position);
private:
KWin::VirtualDesktop *desktopFromIndex(const QModelIndex &index) const;
void handleVirtualDesktopAdded(KWin::VirtualDesktop *desktop);
void handleVirtualDesktopRemoved(KWin::VirtualDesktop *desktop);
QVector<KWin::VirtualDesktop *> m_virtualDesktops;
};
} // namespace ScriptingModels::V3
} // namespace KWin

View file

@ -483,15 +483,19 @@ VirtualDesktop *VirtualDesktopManager::createVirtualDesktop(uint position, const
}
void VirtualDesktopManager::removeVirtualDesktop(const QString &id)
{
auto desktop = desktopForId(id);
if (desktop) {
removeVirtualDesktop(desktop);
}
}
void VirtualDesktopManager::removeVirtualDesktop(VirtualDesktop *desktop)
{
//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;

View file

@ -285,6 +285,7 @@ public:
* @param id the string id of the desktop to remove
*/
void removeVirtualDesktop(const QString &id);
void removeVirtualDesktop(VirtualDesktop *desktop);
/**
* Updates the net root info for new number of desktops