mirror of
https://invent.kde.org/marcoa/shift-shell.git
synced 2026-04-29 15:03:09 +00:00
Make it possible to move windows between screens if there's more than one
This commit is contained in:
parent
1de0f3ec58
commit
4aa1bc3a8c
3 changed files with 118 additions and 0 deletions
|
|
@ -7,6 +7,8 @@
|
||||||
import QtQuick 2.0
|
import QtQuick 2.0
|
||||||
import QtQuick.Layouts 1.1
|
import QtQuick.Layouts 1.1
|
||||||
import QtQuick.Window 2.2
|
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.taskmanager 0.1 as TaskManager
|
||||||
import org.kde.plasma.core 2.0 as PlasmaCore
|
import org.kde.plasma.core 2.0 as PlasmaCore
|
||||||
import org.kde.plasma.components 3.0 as PlasmaComponents
|
import org.kde.plasma.components 3.0 as PlasmaComponents
|
||||||
|
|
@ -17,7 +19,9 @@ Item {
|
||||||
height: window.height/2
|
height: window.height/2
|
||||||
|
|
||||||
//Workaround
|
//Workaround
|
||||||
|
required property var model
|
||||||
property bool active: model.IsActive
|
property bool active: model.IsActive
|
||||||
|
readonly property point taskScreenPoint: Qt.point(model.ScreenGeometry.x, model.ScreenGeometry.y)
|
||||||
onActiveChanged: {
|
onActiveChanged: {
|
||||||
//sometimes the task switcher window itself appears, screwing up the state
|
//sometimes the task switcher window itself appears, screwing up the state
|
||||||
if (model.IsActive) {
|
if (model.IsActive) {
|
||||||
|
|
@ -128,6 +132,20 @@ Item {
|
||||||
text: model.AppName
|
text: model.AppName
|
||||||
color: PlasmaCore.Theme.textColor
|
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 {
|
PlasmaComponents.ToolButton {
|
||||||
z: 99
|
z: 99
|
||||||
icon.name: "window-close"
|
icon.name: "window-close"
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@
|
||||||
#include <QtQml>
|
#include <QtQml>
|
||||||
|
|
||||||
#include <KWayland/Client/connection_thread.h>
|
#include <KWayland/Client/connection_thread.h>
|
||||||
|
#include <KWayland/Client/output.h>
|
||||||
#include <KWayland/Client/plasmashell.h>
|
#include <KWayland/Client/plasmashell.h>
|
||||||
#include <KWayland/Client/plasmawindowmanagement.h>
|
#include <KWayland/Client/plasmawindowmanagement.h>
|
||||||
#include <KWayland/Client/registry.h>
|
#include <KWayland/Client/registry.h>
|
||||||
|
|
@ -23,6 +24,76 @@
|
||||||
static const QString s_kwinService = QStringLiteral("org.kde.KWin");
|
static const QString s_kwinService = QStringLiteral("org.kde.KWin");
|
||||||
constexpr int ACTIVE_WINDOW_UPDATE_INVERVAL = 250;
|
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<int, QByteArray> 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<QObject *>(o);
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
QVector<KWayland::Client::Output *> m_outputs;
|
||||||
|
};
|
||||||
|
|
||||||
// helper class to expose the NOTIFY in the properties
|
// helper class to expose the NOTIFY in the properties
|
||||||
class KwinVirtualKeyboardInterface : public OrgKdeKwinVirtualKeyboardInterface
|
class KwinVirtualKeyboardInterface : public OrgKdeKwinVirtualKeyboardInterface
|
||||||
{
|
{
|
||||||
|
|
@ -41,6 +112,7 @@ TaskPanel::TaskPanel(QObject *parent, const QVariantList &args)
|
||||||
: Plasma::Containment(parent, args)
|
: Plasma::Containment(parent, args)
|
||||||
, m_showingDesktop(false)
|
, m_showingDesktop(false)
|
||||||
, m_windowManagement(nullptr)
|
, m_windowManagement(nullptr)
|
||||||
|
, m_outputsModel(new OutputsModel(this))
|
||||||
{
|
{
|
||||||
setHasConfigurationInterface(true);
|
setHasConfigurationInterface(true);
|
||||||
m_activeTimer = new QTimer(this);
|
m_activeTimer = new QTimer(this);
|
||||||
|
|
@ -49,6 +121,8 @@ TaskPanel::TaskPanel(QObject *parent, const QVariantList &args)
|
||||||
connect(m_activeTimer, &QTimer::timeout, this, &TaskPanel::updateActiveWindow);
|
connect(m_activeTimer, &QTimer::timeout, this, &TaskPanel::updateActiveWindow);
|
||||||
initWayland();
|
initWayland();
|
||||||
|
|
||||||
|
qmlRegisterUncreatableType<KWayland::Client::Output>("org.kde.plasma.phone.taskpanel", 1, 0, "Output", "nope");
|
||||||
|
qmlRegisterUncreatableType<OutputsModel>("org.kde.plasma.phone.taskpanel", 1, 0, "OutputsModel", "nope");
|
||||||
qmlRegisterSingletonType<OrgKdeKwinVirtualKeyboardInterface>("org.kde.plasma.phone.taskpanel",
|
qmlRegisterSingletonType<OrgKdeKwinVirtualKeyboardInterface>("org.kde.plasma.phone.taskpanel",
|
||||||
1,
|
1,
|
||||||
0,
|
0,
|
||||||
|
|
@ -87,6 +161,9 @@ void TaskPanel::initWayland()
|
||||||
}
|
}
|
||||||
auto *registry = new Registry(this);
|
auto *registry = new Registry(this);
|
||||||
registry->create(connection);
|
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) {
|
connect(registry, &Registry::plasmaWindowManagementAnnounced, this, [this, registry](quint32 name, quint32 version) {
|
||||||
m_windowManagement = registry->createPlasmaWindowManagement(name, version, this);
|
m_windowManagement = registry->createPlasmaWindowManagement(name, version, this);
|
||||||
qRegisterMetaType<QVector<int>>("QVector<int>");
|
qRegisterMetaType<QVector<int>>("QVector<int>");
|
||||||
|
|
@ -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")
|
K_PLUGIN_CLASS_WITH_JSON(TaskPanel, "metadata.json")
|
||||||
|
|
||||||
#include "taskpanel.moc"
|
#include "taskpanel.moc"
|
||||||
|
|
|
||||||
|
|
@ -9,12 +9,14 @@
|
||||||
|
|
||||||
#include <Plasma/Containment>
|
#include <Plasma/Containment>
|
||||||
|
|
||||||
|
class OutputsModel;
|
||||||
class QAbstractItemModel;
|
class QAbstractItemModel;
|
||||||
|
|
||||||
namespace KWayland
|
namespace KWayland
|
||||||
{
|
{
|
||||||
namespace Client
|
namespace Client
|
||||||
{
|
{
|
||||||
|
class Output;
|
||||||
class PlasmaWindowManagement;
|
class PlasmaWindowManagement;
|
||||||
class PlasmaWindow;
|
class PlasmaWindow;
|
||||||
class PlasmaShell;
|
class PlasmaShell;
|
||||||
|
|
@ -31,6 +33,7 @@ class TaskPanel : public Plasma::Containment
|
||||||
Q_PROPERTY(bool hasCloseableActiveWindow READ hasCloseableActiveWindow NOTIFY hasCloseableActiveWindowChanged)
|
Q_PROPERTY(bool hasCloseableActiveWindow READ hasCloseableActiveWindow NOTIFY hasCloseableActiveWindowChanged)
|
||||||
Q_PROPERTY(QWindow *panel READ panel WRITE setPanel NOTIFY panelChanged)
|
Q_PROPERTY(QWindow *panel READ panel WRITE setPanel NOTIFY panelChanged)
|
||||||
Q_PROPERTY(Plasma::Types::Location location READ location WRITE setLocation NOTIFY locationChanged)
|
Q_PROPERTY(Plasma::Types::Location location READ location WRITE setLocation NOTIFY locationChanged)
|
||||||
|
Q_PROPERTY(QAbstractItemModel *outputs READ outputs CONSTANT)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
TaskPanel(QObject *parent, const QVariantList &args);
|
TaskPanel(QObject *parent, const QVariantList &args);
|
||||||
|
|
@ -53,6 +56,10 @@ public:
|
||||||
}
|
}
|
||||||
bool hasCloseableActiveWindow() const;
|
bool hasCloseableActiveWindow() const;
|
||||||
|
|
||||||
|
QAbstractItemModel *outputs() const;
|
||||||
|
|
||||||
|
Q_INVOKABLE void sendWindowToOutput(const QString &uuid, KWayland::Client::Output *output);
|
||||||
|
|
||||||
public Q_SLOTS:
|
public Q_SLOTS:
|
||||||
void forgetActiveWindow();
|
void forgetActiveWindow();
|
||||||
|
|
||||||
|
|
@ -76,6 +83,7 @@ private:
|
||||||
KWayland::Client::PlasmaWindowManagement *m_windowManagement = nullptr;
|
KWayland::Client::PlasmaWindowManagement *m_windowManagement = nullptr;
|
||||||
QPointer<KWayland::Client::PlasmaWindow> m_activeWindow;
|
QPointer<KWayland::Client::PlasmaWindow> m_activeWindow;
|
||||||
QTimer *m_activeTimer;
|
QTimer *m_activeTimer;
|
||||||
|
OutputsModel *m_outputsModel;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue