diff --git a/containments/taskpanel/package/contents/ui/Task.qml b/containments/taskpanel/package/contents/ui/Task.qml index 6eb52884..abd91972 100644 --- a/containments/taskpanel/package/contents/ui/Task.qml +++ b/containments/taskpanel/package/contents/ui/Task.qml @@ -7,6 +7,8 @@ import QtQuick 2.0 import QtQuick.Layouts 1.1 import QtQuick.Window 2.2 +import QtQuick.Controls 2.2 as QQC2 +import org.kde.plasma.phone.taskpanel 1.0 import org.kde.taskmanager 0.1 as TaskManager import org.kde.plasma.core 2.0 as PlasmaCore import org.kde.plasma.components 3.0 as PlasmaComponents @@ -17,7 +19,9 @@ Item { height: window.height/2 //Workaround + required property var model property bool active: model.IsActive + readonly property point taskScreenPoint: Qt.point(model.ScreenGeometry.x, model.ScreenGeometry.y) onActiveChanged: { //sometimes the task switcher window itself appears, screwing up the state if (model.IsActive) { @@ -128,6 +132,20 @@ Item { text: model.AppName color: PlasmaCore.Theme.textColor } + Repeater { + id: rep + model: plasmoid.nativeInterface.outputs + delegate: PlasmaComponents.ToolButton { + text: model.modelName + visible: model.position !== delegate.taskScreenPoint + display: rep.count < 3 ? QQC2.Button.IconOnly : QQC2.Button.TextBesideIcon + icon.name: "tv" //TODO provide a more adequate icon + + onClicked: { + plasmoid.nativeInterface.sendWindowToOutput(delegate.model.WinIdList[0], model.output) + } + } + } PlasmaComponents.ToolButton { z: 99 icon.name: "window-close" diff --git a/containments/taskpanel/taskpanel.cpp b/containments/taskpanel/taskpanel.cpp index 804c5eb7..fe09ae73 100644 --- a/containments/taskpanel/taskpanel.cpp +++ b/containments/taskpanel/taskpanel.cpp @@ -12,6 +12,7 @@ #include #include +#include #include #include #include @@ -23,6 +24,76 @@ static const QString s_kwinService = QStringLiteral("org.kde.KWin"); constexpr int ACTIVE_WINDOW_UPDATE_INVERVAL = 250; +class OutputsModel : public QAbstractListModel +{ +public: + enum Roles { + Model = Qt::DisplayRole, + Geometry = Qt::UserRole, + Position, + Output, + }; + + OutputsModel(QObject *parent) + : QAbstractListModel(parent) + { + } + + QHash roleNames() const override + { + return { + {Model, "modelName"}, + {Geometry, "geometry"}, + {Position, "position"}, + {Output, "output"}, + }; + } + + void createOutput(wl_output *output) + { + auto newOutput = new KWayland::Client::Output(this); + connect(newOutput, &KWayland::Client::Output::removed, this, [this, newOutput] { + auto i = m_outputs.indexOf(newOutput); + Q_ASSERT(i >= 0); + beginRemoveRows({}, i, i); + m_outputs.removeAt(i); + endRemoveRows(); + }); + newOutput->setup(output); + beginInsertRows({}, m_outputs.count(), m_outputs.count()); + m_outputs.append(newOutput); + endInsertRows(); + } + + int rowCount(const QModelIndex &parent) const override + { + return parent.isValid() ? 0 : m_outputs.count(); + } + + QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override + { + if (index.row() >= m_outputs.count()) { + return {}; + } + + auto o = m_outputs[index.row()]; + switch (role) { + case Model: + return o->model(); + case Geometry: + return o->geometry(); + case Position: + return o->globalPosition(); + case Output: + return QVariant::fromValue(o); + } + return {}; + } + +private: + QVector m_outputs; +}; + // helper class to expose the NOTIFY in the properties class KwinVirtualKeyboardInterface : public OrgKdeKwinVirtualKeyboardInterface { @@ -41,6 +112,7 @@ TaskPanel::TaskPanel(QObject *parent, const QVariantList &args) : Plasma::Containment(parent, args) , m_showingDesktop(false) , m_windowManagement(nullptr) + , m_outputsModel(new OutputsModel(this)) { setHasConfigurationInterface(true); m_activeTimer = new QTimer(this); @@ -49,6 +121,8 @@ TaskPanel::TaskPanel(QObject *parent, const QVariantList &args) connect(m_activeTimer, &QTimer::timeout, this, &TaskPanel::updateActiveWindow); initWayland(); + qmlRegisterUncreatableType("org.kde.plasma.phone.taskpanel", 1, 0, "Output", "nope"); + qmlRegisterUncreatableType("org.kde.plasma.phone.taskpanel", 1, 0, "OutputsModel", "nope"); qmlRegisterSingletonType("org.kde.plasma.phone.taskpanel", 1, 0, @@ -87,6 +161,9 @@ void TaskPanel::initWayland() } auto *registry = new Registry(this); registry->create(connection); + connect(registry, &Registry::outputAnnounced, m_outputsModel, [this, registry](quint32 name, quint32 version) { + m_outputsModel->createOutput(registry->bindOutput(name, version)); + }); connect(registry, &Registry::plasmaWindowManagementAnnounced, this, [this, registry](quint32 name, quint32 version) { m_windowManagement = registry->createPlasmaWindowManagement(name, version, this); qRegisterMetaType>("QVector"); @@ -213,6 +290,21 @@ void TaskPanel::closeActiveWindow() } } +void TaskPanel::sendWindowToOutput(const QString &uuid, KWayland::Client::Output *output) +{ + const auto windows = m_windowManagement->windows(); + for (auto w : windows) { + if (w->uuid() == uuid) { + w->sendToOutput(output); + } + } +} + +QAbstractItemModel *TaskPanel::outputs() const +{ + return m_outputsModel; +} + K_PLUGIN_CLASS_WITH_JSON(TaskPanel, "metadata.json") #include "taskpanel.moc" diff --git a/containments/taskpanel/taskpanel.h b/containments/taskpanel/taskpanel.h index 408f2999..2657f0df 100644 --- a/containments/taskpanel/taskpanel.h +++ b/containments/taskpanel/taskpanel.h @@ -9,12 +9,14 @@ #include +class OutputsModel; class QAbstractItemModel; namespace KWayland { namespace Client { +class Output; class PlasmaWindowManagement; class PlasmaWindow; class PlasmaShell; @@ -31,6 +33,7 @@ class TaskPanel : public Plasma::Containment Q_PROPERTY(bool hasCloseableActiveWindow READ hasCloseableActiveWindow NOTIFY hasCloseableActiveWindowChanged) Q_PROPERTY(QWindow *panel READ panel WRITE setPanel NOTIFY panelChanged) Q_PROPERTY(Plasma::Types::Location location READ location WRITE setLocation NOTIFY locationChanged) + Q_PROPERTY(QAbstractItemModel *outputs READ outputs CONSTANT) public: TaskPanel(QObject *parent, const QVariantList &args); @@ -53,6 +56,10 @@ public: } bool hasCloseableActiveWindow() const; + QAbstractItemModel *outputs() const; + + Q_INVOKABLE void sendWindowToOutput(const QString &uuid, KWayland::Client::Output *output); + public Q_SLOTS: void forgetActiveWindow(); @@ -76,6 +83,7 @@ private: KWayland::Client::PlasmaWindowManagement *m_windowManagement = nullptr; QPointer m_activeWindow; QTimer *m_activeTimer; + OutputsModel *m_outputsModel; }; #endif