taskpanel: Extract navbar and task switcher to components/mobileshell

This commit is contained in:
Devin Lin 2021-12-24 19:18:38 -05:00
parent d4c3c29608
commit 2d87bb3e65
18 changed files with 228 additions and 168 deletions

View file

@ -2,14 +2,19 @@
# SPDX-License-Identifier: GPL-2.0-or-later
qt_add_dbus_interfaces(DBUS_SRCS dbus/org.kde.KWin.ScreenShot2.xml
dbus/org.kde.KScreen.xml)
dbus/org.kde.KScreen.xml
${KWIN_VIRTUALKEYBOARD_INTERFACE})
set(mobileshellplugin_SRCS
mobileshellplugin.cpp
shellutil.cpp
quicksettingsmodel.cpp
vkbdinterface.cpp
displaysmodel.cpp
notifications/notificationthumbnailer.cpp
notifications/notificationfilemenu.cpp
${DBUS_SRCS}
)

View file

@ -0,0 +1,99 @@
/*
* SPDX-FileCopyrightText: 2021 Aleix Pol <apol@kde.org>
* SPDX-FileCopyrightText: 2021 Devin Lin <devin@kde.org>
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "displaysmodel.h"
#include <QGuiApplication>
DisplaysModel::DisplaysModel(QObject *parent)
: QAbstractListModel(parent)
{
if (!QGuiApplication::platformName().startsWith(QLatin1String("wayland"), Qt::CaseInsensitive)) {
return;
}
using namespace KWayland::Client;
ConnectionThread *connection = ConnectionThread::fromApplication(this);
if (!connection) {
return;
}
auto *registry = new Registry(this);
registry->create(connection);
connect(registry, &Registry::outputAnnounced, this, [this, registry](quint32 name, quint32 version) {
createOutput(registry->bindOutput(name, version));
});
connect(registry, &Registry::plasmaWindowManagementAnnounced, this, [this, registry](quint32 name, quint32 version) {
m_windowManagement = registry->createPlasmaWindowManagement(name, version, this);
});
registry->setup();
connection->roundtrip();
}
QHash<int, QByteArray> DisplaysModel::roleNames() const
{
return {
{Model, "modelName"},
{Geometry, "geometry"},
{Position, "position"},
{Output, "output"},
};
}
void DisplaysModel::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();
}
void DisplaysModel::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);
}
}
}
int DisplaysModel::rowCount(const QModelIndex &parent) const
{
return parent.isValid() ? 0 : m_outputs.count();
}
QVariant DisplaysModel::data(const QModelIndex &index, int role) const
{
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 {};
}

View file

@ -0,0 +1,44 @@
/*
* SPDX-FileCopyrightText: 2021 Aleix Pol <apol@kde.org>
* SPDX-FileCopyrightText: 2021 Devin Lin <devin@kde.org>
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#pragma once
#include <QAbstractListModel>
#include <QRect>
#include <KWayland/Client/connection_thread.h>
#include <KWayland/Client/output.h>
#include <KWayland/Client/plasmashell.h>
#include <KWayland/Client/plasmawindowmanagement.h>
#include <KWayland/Client/registry.h>
#include <KWayland/Client/surface.h>
class DisplaysModel : public QAbstractListModel
{
public:
enum Roles {
Model = Qt::DisplayRole,
Geometry = Qt::UserRole,
Position,
Output,
};
DisplaysModel(QObject *parent = nullptr);
void createOutput(wl_output *output);
Q_INVOKABLE void sendWindowToOutput(const QString &uuid, KWayland::Client::Output *output);
QHash<int, QByteArray> roleNames() const override;
int rowCount(const QModelIndex &parent) const override;
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
private:
KWayland::Client::PlasmaWindowManagement *m_windowManagement = nullptr;
QVector<KWayland::Client::Output *> m_outputs;
};

View file

@ -4,14 +4,18 @@
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "mobileshellplugin.h"
#include <QQmlContext>
#include <QQuickItem>
#include "mobileshellplugin.h"
#include "displaysmodel.h"
#include "notifications/notificationfilemenu.h"
#include "notifications/notificationthumbnailer.h"
#include "quicksettingsmodel.h"
#include "shellutil.h"
#include "virtualkeyboardinterface.h"
#include "vkbdinterface.h"
void MobileShellPlugin::registerTypes(const char *uri)
{
@ -24,6 +28,11 @@ void MobileShellPlugin::registerTypes(const char *uri)
qmlRegisterType<QuickSetting>(uri, 1, 0, "QuickSetting");
qmlRegisterType<QuickSettingsModel>(uri, 1, 0, "QuickSettingsModel");
qmlRegisterType<DisplaysModel>(uri, 1, 0, "DisplaysModel");
qmlRegisterSingletonType<OrgKdeKwinVirtualKeyboardInterface>(uri, 1, 0, "KWinVirtualKeyboard", [](QQmlEngine *, QJSEngine *) -> QObject * {
return new KwinVirtualKeyboardInterface;
});
// notifications
qmlRegisterType<NotificationThumbnailer>(uri, 1, 0, "NotificationThumbnailer");
qmlRegisterType<NotificationFileMenu>(uri, 1, 0, "NotificationFileMenu");

View file

@ -11,13 +11,11 @@ import QtQuick.Window 2.2
import QtGraphicalEffects 1.12
import org.kde.taskmanager 0.1 as TaskManager
import org.kde.plasma.plasmoid 2.0
import org.kde.plasma.core 2.0 as PlasmaCore
import org.kde.kquickcontrolsaddons 2.0
import org.kde.plasma.private.nanoshell 2.0 as NanoShell
import org.kde.plasma.private.mobileshell 1.0 as MobileShell
import org.kde.plasma.phone.taskpanel 1.0 as TaskPanel
Item {
id: root
@ -112,7 +110,6 @@ Item {
id: icons
anchors.fill: parent
visible: plasmoid.configuration.PanelButtonsVisible
property real buttonLength: 0
// background colour

View file

@ -8,7 +8,6 @@
import QtQuick 2.12
import QtQuick.Layouts 1.1
import org.kde.plasma.plasmoid 2.0
import org.kde.plasma.core 2.0 as PlasmaCore
import org.kde.kquickcontrolsaddons 2.0
@ -22,6 +21,7 @@ Item {
property double iconSizeFactor: 1
property alias iconSource: icon.source
property alias colorGroup: icon.colorGroup
signal clicked()
Rectangle {

View file

@ -21,9 +21,16 @@ singleton SignalStrengthProvider 1.0 dataproviders/SignalStrengthProvider.qml
singleton VolumeProvider 1.0 dataproviders/VolumeProvider.qml
singleton WifiProvider 1.0 dataproviders/WifiProvider.qml
# /navigationpanel
NavigationPanel 1.0 navigationpanel/NavigationPanel.qml
NavigationPanelAction 1.0 navigationpanel/NavigationPanelAction.qml
# /statusbar
StatusBar 1.0 statusbar/StatusBar.qml
# /taskswitcher
TaskSwitcher 1.0 taskswitcher/TaskSwitcher.qml
# /widgets
MediaControlsWidget 1.0 widgets/MediaControlsWidget.qml
NotificationsWidget 1.0 widgets/NotificationsWidget.qml

View file

@ -9,7 +9,7 @@ import QtQuick 2.15
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
@ -18,6 +18,7 @@ Item {
id: delegate
required property var model
required property var displaysModel
readonly property point taskScreenPoint: Qt.point(model.ScreenGeometry.x, model.ScreenGeometry.y)
readonly property real dragOffset: -control.y
@ -129,7 +130,7 @@ Item {
Repeater {
id: rep
model: plasmoid.nativeInterface.outputs
model: displaysModel
delegate: PlasmaComponents.ToolButton {
Layout.alignment: Qt.AlignVCenter
text: model.modelName
@ -138,7 +139,7 @@ Item {
icon.name: "tv" //TODO provide a more adequate icon
onClicked: {
plasmoid.nativeInterface.sendWindowToOutput(delegate.model.WinIdList[0], model.output)
displaysModel.sendWindowToOutput(delegate.model.WinIdList[0], model.output)
}
}
}

View file

@ -6,8 +6,8 @@
import QtQuick 2.0
import QtQuick.Layouts 1.1
import org.kde.plasma.core 2.0 as PlasmaCore
import org.kde.plasma.core 2.0 as PlasmaCore
PlasmaCore.IconItem {
implicitWidth: PlasmaCore.Units.iconSizes.medium

View file

@ -8,6 +8,7 @@
import QtQuick 2.12
import QtQuick.Layouts 1.1
import QtQuick.Window 2.2
import org.kde.taskmanager 0.1 as TaskManager
import org.kde.plasma.core 2.1 as PlasmaCore
import org.kde.plasma.components 3.0 as PlasmaComponents
@ -43,7 +44,7 @@ NanoShell.FullScreenOverlay {
property bool wasInActiveTask: false // whether we were in an app before opening the task switcher
property bool currentlyDragging: false // whether we are in a swipe up gesture
Component.onCompleted: plasmoid.nativeInterface.panel = window;
property var displaysModel: MobileShell.DisplaysModel {}
enum MovementDirection {
None = 0,
@ -231,6 +232,8 @@ NanoShell.FullScreenOverlay {
width: tasksView.width
height: tasksView.height
displaysModel: window.displaysModel
// account for header offset (center the preview)
y: -tasksView.taskHeaderHeight / 2
@ -273,7 +276,7 @@ NanoShell.FullScreenOverlay {
}
// task panel
NavigationPanel {
MobileShell.NavigationPanel {
id: navPanel
property bool isPortrait: Screen.width <= Screen.height
@ -292,7 +295,7 @@ NanoShell.FullScreenOverlay {
Behavior on backgroundColor { ColorAnimation {} }
leftAction: NavigationPanelAction {
leftAction: MobileShell.NavigationPanelAction {
enabled: true
iconSource: "mobile-task-switcher"
iconSizeFactor: 0.75
@ -305,7 +308,7 @@ NanoShell.FullScreenOverlay {
}
}
middleAction: NavigationPanelAction {
middleAction: MobileShell.NavigationPanelAction {
enabled: true
iconSource: "start-here-kde"
iconSizeFactor: 1
@ -315,7 +318,7 @@ NanoShell.FullScreenOverlay {
}
}
rightAction: NavigationPanelAction {
rightAction: MobileShell.NavigationPanelAction {
enabled: true
iconSource: "mobile-close-app"
iconSizeFactor: 0.75

View file

@ -7,6 +7,7 @@
import QtQuick 2.0
import QtQuick.Layouts 1.1
import QtQuick.Window 2.2
import org.kde.taskmanager 0.1 as TaskManager
TaskManager.PipeWireSourceItem {

View file

@ -0,0 +1,12 @@
/*
* SPDX-FileCopyrightText: 2021 Aleix Pol <apol@kde.org>
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "vkbdinterface.h"
KwinVirtualKeyboardInterface::KwinVirtualKeyboardInterface()
: OrgKdeKwinVirtualKeyboardInterface(QStringLiteral("org.kde.KWin"), QStringLiteral("/VirtualKeyboard"), QDBusConnection::sessionBus())
{
}

View file

@ -0,0 +1,23 @@
/*
* SPDX-FileCopyrightText: 2021 Aleix Pol <apol@kde.org>
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#pragma once
#include <QDBusConnection>
#include <QObject>
#include <QString>
#include <virtualkeyboardinterface.h>
class KwinVirtualKeyboardInterface : public OrgKdeKwinVirtualKeyboardInterface
{
Q_OBJECT
Q_PROPERTY(bool active READ active WRITE setActive NOTIFY activeChanged)
Q_PROPERTY(bool enabled READ enabled WRITE setEnabled NOTIFY enabledChanged)
Q_PROPERTY(bool visible READ visible NOTIFY visibleChanged)
public:
KwinVirtualKeyboardInterface();
};

View file

@ -1,21 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
- SPDX-FileCopyrightText: 2015-2017 Marco Martin <mart@kde.org>
- SPDX-License-Identifier: GPL-2.0-or-later
-->
<kcfg xmlns="http://www.kde.org/standards/kcfg/1.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.kde.org/standards/kcfg/1.0
http://www.kde.org/standards/kcfg/1.0/kcfg.xsd" >
<kcfgfile name=""/>
<group name="General">
<entry name="PanelButtonsVisible" type="Bool">
<default>true</default>
<label>panel chrome visible</label>
</entry>
</group>
</kcfg>

View file

@ -21,8 +21,6 @@ import org.kde.plasma.phone.taskpanel 1.0 as TaskPanel
PlasmaCore.ColorScope {
id: root
width: 600
height: 480
colorGroup: showingApp ? PlasmaCore.Theme.HeaderColorGroup : PlasmaCore.Theme.ComplementaryColorGroup
Plasmoid.backgroundHints: PlasmaCore.Types.NoBackground
@ -99,14 +97,14 @@ PlasmaCore.ColorScope {
// task switcher
Loader {
id: taskSwitcherLoader
sourceComponent: TaskSwitcher {
sourceComponent: MobileShell.TaskSwitcher {
model: tasksModel
taskPanelHeight: root.state === "portrait" ? root.height : root.width
}
}
// bottom navigation panel
NavigationPanel {
MobileShell.NavigationPanel {
id: panel
anchors.fill: parent
opacity: (root.taskSwitcher && root.taskSwitcher.visible) ? 0 : 1 // hide bar when task switcher is open
@ -117,7 +115,7 @@ PlasmaCore.ColorScope {
dragGestureEnabled: true
taskSwitcher: root.taskSwitcher
leftAction: NavigationPanelAction {
leftAction: MobileShell.NavigationPanelAction {
enabled: hasTasks
iconSource: "mobile-task-switcher"
iconSizeFactor: 0.75
@ -128,22 +126,22 @@ PlasmaCore.ColorScope {
}
}
middleAction: NavigationPanelAction {
middleAction: MobileShell.NavigationPanelAction {
enabled: true
iconSource: "start-here-kde"
iconSizeFactor: 1
onTriggered: root.triggerHomescreen()
}
rightAction: NavigationPanelAction {
enabled: TaskPanel.KWinVirtualKeyboard.visible || (plasmoid.nativeInterface.hasCloseableActiveWindow && !taskSwitcher.visible)
rightAction: MobileShell.NavigationPanelAction {
enabled: MobileShell.KWinVirtualKeyboard.visible || (plasmoid.nativeInterface.hasCloseableActiveWindow && !taskSwitcher.visible)
// mobile-close-app (from plasma-frameworks) seems to have less margins than icons from breeze-icons
iconSizeFactor: TaskPanel.KWinVirtualKeyboard.visible ? 1 : 0.75
iconSource: TaskPanel.KWinVirtualKeyboard.visible ? "go-down-symbolic" : "mobile-close-app"
iconSizeFactor: MobileShell.KWinVirtualKeyboard.visible ? 1 : 0.75
iconSource: MobileShell.KWinVirtualKeyboard.visible ? "go-down-symbolic" : "mobile-close-app"
onTriggered: {
if (TaskPanel.KWinVirtualKeyboard.active) {
TaskPanel.KWinVirtualKeyboard.active = false;
if (MobileShell.KWinVirtualKeyboard.active) {
MobileShell.KWinVirtualKeyboard.active = false;
} else if (plasmoid.nativeInterface.hasCloseableActiveWindow) {
var index = taskSwitcher.model.activeTask;
if (index) {

View file

@ -24,95 +24,10 @@
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<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
class KwinVirtualKeyboardInterface : public OrgKdeKwinVirtualKeyboardInterface
{
Q_OBJECT
Q_PROPERTY(bool active READ active WRITE setActive NOTIFY activeChanged)
Q_PROPERTY(bool enabled READ enabled WRITE setEnabled NOTIFY enabledChanged)
Q_PROPERTY(bool visible READ visible NOTIFY visibleChanged)
public:
KwinVirtualKeyboardInterface()
: OrgKdeKwinVirtualKeyboardInterface(QStringLiteral("org.kde.KWin"), QStringLiteral("/VirtualKeyboard"), QDBusConnection::sessionBus())
{
}
};
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);
@ -122,14 +37,6 @@ TaskPanel::TaskPanel(QObject *parent, const QVariantList &args)
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",
1,
0,
"KWinVirtualKeyboard",
[](QQmlEngine *, QJSEngine *) -> QObject * {
return new KwinVirtualKeyboardInterface;
});
connect(this, &Plasma::Containment::locationChanged, this, &TaskPanel::locationChanged);
connect(this, &Plasma::Containment::locationChanged, this, [this] {
@ -161,9 +68,6 @@ 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<int>>("QVector<int>");
@ -174,9 +78,6 @@ void TaskPanel::initWayland()
m_showingDesktop = showing;
emit showingDesktopChanged(m_showingDesktop);
});
// FIXME
// connect(m_windowManagement, &PlasmaWindowManagement::activeWindowChanged, this, &TaskPanel::updateActiveWindow, Qt::QueuedConnection);
connect(m_windowManagement, &KWayland::Client::PlasmaWindowManagement::activeWindowChanged, m_activeTimer, qOverload<>(&QTimer::start));
m_activeTimer->start();
@ -290,21 +191,6 @@ 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"

View file

@ -33,7 +33,6 @@ 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);
@ -58,8 +57,6 @@ public:
QAbstractItemModel *outputs() const;
Q_INVOKABLE void sendWindowToOutput(const QString &uuid, KWayland::Client::Output *output);
public Q_SLOTS:
void forgetActiveWindow();
@ -83,7 +80,6 @@ private:
KWayland::Client::PlasmaWindowManagement *m_windowManagement = nullptr;
QPointer<KWayland::Client::PlasmaWindow> m_activeWindow;
QTimer *m_activeTimer;
OutputsModel *m_outputsModel;
};
#endif