mirror of
https://invent.kde.org/marcoa/shift-shell.git
synced 2026-06-25 07:37:42 +00:00
Compare commits
No commits in common. "f09a1db84ae4c0ba419eb789f65cc55d4a94721e" and "30e3006e3fa539897ffe38b04397cae3b48db324" have entirely different histories.
f09a1db84a
...
30e3006e3f
28 changed files with 163 additions and 1913 deletions
|
|
@ -10,12 +10,9 @@
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <QTabletEvent>
|
#include <QTabletEvent>
|
||||||
#include <QTouchEvent>
|
#include <QTouchEvent>
|
||||||
#include <QWheelEvent>
|
|
||||||
|
|
||||||
// how many pixels to move before it starts being registered as a swipe
|
// how many pixels to move before it starts being registered as a swipe
|
||||||
const int SWIPE_REGISTER_THRESHOLD = 10;
|
const int SWIPE_REGISTER_THRESHOLD = 10;
|
||||||
const qreal WHEEL_STEP_PIXEL_DELTA = 48.0;
|
|
||||||
const int TOUCHPAD_SCROLL_END_TIMEOUT = 160;
|
|
||||||
|
|
||||||
SwipeArea::SwipeArea(QQuickItem *parent)
|
SwipeArea::SwipeArea(QQuickItem *parent)
|
||||||
: QQuickItem{parent}
|
: QQuickItem{parent}
|
||||||
|
|
@ -23,10 +20,6 @@ SwipeArea::SwipeArea(QQuickItem *parent)
|
||||||
setAcceptTouchEvents(true);
|
setAcceptTouchEvents(true);
|
||||||
setAcceptedMouseButtons(Qt::LeftButton);
|
setAcceptedMouseButtons(Qt::LeftButton);
|
||||||
setFiltersChildMouseEvents(true);
|
setFiltersChildMouseEvents(true);
|
||||||
|
|
||||||
m_touchpadScrollEndTimer.setSingleShot(true);
|
|
||||||
m_touchpadScrollEndTimer.setInterval(TOUCHPAD_SCROLL_END_TIMEOUT);
|
|
||||||
connect(&m_touchpadScrollEndTimer, &QTimer::timeout, this, &SwipeArea::endTouchpadScroll);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SwipeArea::Mode SwipeArea::mode() const
|
SwipeArea::Mode SwipeArea::mode() const
|
||||||
|
|
@ -232,71 +225,43 @@ void SwipeArea::wheelEvent(QWheelEvent *event)
|
||||||
|
|
||||||
event->setAccepted(false);
|
event->setAccepted(false);
|
||||||
|
|
||||||
const bool isTouchpad = event->deviceType() == QInputDevice::DeviceType::TouchPad;
|
|
||||||
QPointF scrollDelta = event->pixelDelta();
|
|
||||||
if (scrollDelta.isNull() && !event->angleDelta().isNull()) {
|
|
||||||
scrollDelta = QPointF(event->angleDelta()) / QWheelEvent::DefaultDeltasPerStep * WHEEL_STEP_PIXEL_DELTA;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (event->phase()) {
|
switch (event->phase()) {
|
||||||
case Qt::ScrollBegin:
|
case Qt::ScrollBegin:
|
||||||
if (isTouchpad && !m_touchpadScrolling) {
|
if (!m_touchpadScrolling) {
|
||||||
event->accept();
|
event->accept();
|
||||||
startTouchpadScroll(event->points().first().position());
|
|
||||||
|
m_touchpadScrolling = true;
|
||||||
|
m_totalScrollDelta = QPointF{0, 0};
|
||||||
|
Q_EMIT touchpadScrollStarted(event->points().first().position());
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case Qt::ScrollEnd:
|
case Qt::ScrollEnd:
|
||||||
if (m_touchpadScrolling) {
|
if (m_touchpadScrolling) {
|
||||||
endTouchpadScroll();
|
m_touchpadScrolling = false;
|
||||||
event->accept();
|
m_totalScrollDelta = QPointF{0, 0};
|
||||||
|
Q_EMIT touchpadScrollEnded();
|
||||||
}
|
}
|
||||||
return;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// HACK: if it isn't the touchpad, we never get the isBeginEvent() and isEndEvent() events
|
||||||
if (!m_touchpadScrolling) {
|
if (!m_touchpadScrolling) {
|
||||||
if (!isTouchpad || scrollDelta.isNull()) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
startTouchpadScroll(event->points().first().position());
|
|
||||||
}
|
|
||||||
|
|
||||||
for (auto &point : event->points()) {
|
for (auto &point : event->points()) {
|
||||||
event->addPassiveGrabber(point, this);
|
event->addPassiveGrabber(point, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
m_totalScrollDelta = QPointF{m_totalScrollDelta + scrollDelta};
|
auto pixelDelta = event->pixelDelta();
|
||||||
Q_EMIT touchpadScrollMove(m_totalScrollDelta.x(), m_totalScrollDelta.y(), scrollDelta.x(), scrollDelta.y());
|
m_totalScrollDelta = QPointF{m_totalScrollDelta + pixelDelta};
|
||||||
|
Q_EMIT touchpadScrollMove(m_totalScrollDelta.x(), m_totalScrollDelta.y(), pixelDelta.x(), pixelDelta.y());
|
||||||
m_touchpadScrollEndTimer.start();
|
|
||||||
|
|
||||||
event->accept();
|
event->accept();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SwipeArea::startTouchpadScroll(QPointF point)
|
|
||||||
{
|
|
||||||
if (m_touchpadScrolling) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_touchpadScrolling = true;
|
|
||||||
m_totalScrollDelta = QPointF{0, 0};
|
|
||||||
Q_EMIT touchpadScrollStarted(point);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SwipeArea::endTouchpadScroll()
|
|
||||||
{
|
|
||||||
if (!m_touchpadScrolling) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_touchpadScrollEndTimer.stop();
|
|
||||||
m_touchpadScrolling = false;
|
|
||||||
m_totalScrollDelta = QPointF{0, 0};
|
|
||||||
Q_EMIT touchpadScrollEnded();
|
|
||||||
}
|
|
||||||
|
|
||||||
void SwipeArea::setMoving(bool moving)
|
void SwipeArea::setMoving(bool moving)
|
||||||
{
|
{
|
||||||
m_moving = moving;
|
m_moving = moving;
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,6 @@
|
||||||
#include <QPointerEvent>
|
#include <QPointerEvent>
|
||||||
#include <QQmlListProperty>
|
#include <QQmlListProperty>
|
||||||
#include <QQuickItem>
|
#include <QQuickItem>
|
||||||
#include <QTimer>
|
|
||||||
#include <QTouchEvent>
|
#include <QTouchEvent>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -85,8 +84,6 @@ private:
|
||||||
void handlePressEvent(QPointerEvent *event, QPointF point);
|
void handlePressEvent(QPointerEvent *event, QPointF point);
|
||||||
void handleReleaseEvent(QPointerEvent *event, QPointF point);
|
void handleReleaseEvent(QPointerEvent *event, QPointF point);
|
||||||
void handleMoveEvent(QPointerEvent *event, QPointF point);
|
void handleMoveEvent(QPointerEvent *event, QPointF point);
|
||||||
void startTouchpadScroll(QPointF point);
|
|
||||||
void endTouchpadScroll();
|
|
||||||
|
|
||||||
Mode m_mode = Mode::BothAxis;
|
Mode m_mode = Mode::BothAxis;
|
||||||
bool m_interactive = true;
|
bool m_interactive = true;
|
||||||
|
|
@ -113,8 +110,6 @@ private:
|
||||||
|
|
||||||
// the total amount of distance scrolled
|
// the total amount of distance scrolled
|
||||||
QPointF m_totalScrollDelta;
|
QPointF m_totalScrollDelta;
|
||||||
|
|
||||||
QTimer m_touchpadScrollEndTimer;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
QML_DECLARE_TYPE(SwipeArea)
|
QML_DECLARE_TYPE(SwipeArea)
|
||||||
|
|
|
||||||
|
|
@ -17,15 +17,6 @@ MobileShell.SwipeArea {
|
||||||
mode: MobileShell.SwipeArea.VerticalOnly
|
mode: MobileShell.SwipeArea.VerticalOnly
|
||||||
|
|
||||||
required property ActionDrawer actionDrawer
|
required property ActionDrawer actionDrawer
|
||||||
property var virtualDesktopInfo: null
|
|
||||||
|
|
||||||
readonly property real touchpadDirectionLockThreshold: 12
|
|
||||||
readonly property real touchpadWorkspaceSwitchThreshold: 80
|
|
||||||
readonly property real touchpadAxisDominance: 1.25
|
|
||||||
|
|
||||||
property point touchpadStartPoint: Qt.point(0, 0)
|
|
||||||
property string touchpadGestureMode: ""
|
|
||||||
property bool touchpadWorkspaceSwitched: false
|
|
||||||
|
|
||||||
function startSwipe() {
|
function startSwipe() {
|
||||||
if (actionDrawer.intendedToBeVisible) {
|
if (actionDrawer.intendedToBeVisible) {
|
||||||
|
|
@ -63,96 +54,12 @@ MobileShell.SwipeArea {
|
||||||
actionDrawer.offset += offsetY;
|
actionDrawer.offset += offsetY;
|
||||||
}
|
}
|
||||||
|
|
||||||
function workspaceScrollAvailable() {
|
|
||||||
return ShellSettings.Settings.convergenceModeEnabled
|
|
||||||
&& virtualDesktopInfo !== null
|
|
||||||
&& virtualDesktopInfo.numberOfDesktops > 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
function desktopIndexForId(desktopId) {
|
|
||||||
if (virtualDesktopInfo === null || !virtualDesktopInfo.desktopIds) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (let i = 0; i < virtualDesktopInfo.desktopIds.length; ++i) {
|
|
||||||
if (String(virtualDesktopInfo.desktopIds[i]) === String(desktopId)) {
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
function activateAdjacentWorkspace(direction) {
|
|
||||||
if (!workspaceScrollAvailable()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const currentIndex = desktopIndexForId(virtualDesktopInfo.currentDesktop);
|
|
||||||
if (currentIndex < 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const targetIndex = Math.max(0, Math.min(virtualDesktopInfo.desktopIds.length - 1, currentIndex + direction));
|
|
||||||
if (targetIndex !== currentIndex) {
|
|
||||||
virtualDesktopInfo.requestActivate(virtualDesktopInfo.desktopIds[targetIndex]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function startTouchpadScroll(point) {
|
|
||||||
touchpadStartPoint = point;
|
|
||||||
touchpadGestureMode = "";
|
|
||||||
touchpadWorkspaceSwitched = false;
|
|
||||||
|
|
||||||
if (!ShellSettings.Settings.convergenceModeEnabled) {
|
|
||||||
touchpadGestureMode = "drawer";
|
|
||||||
startSwipeWithPoint(point);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function moveTouchpadScroll(totalDeltaX, totalDeltaY, deltaX, deltaY) {
|
|
||||||
if (touchpadGestureMode === "") {
|
|
||||||
const absX = Math.abs(totalDeltaX);
|
|
||||||
const absY = Math.abs(totalDeltaY);
|
|
||||||
|
|
||||||
if (absY >= touchpadDirectionLockThreshold && absY > absX * touchpadAxisDominance) {
|
|
||||||
touchpadGestureMode = "drawer";
|
|
||||||
startSwipeWithPoint(touchpadStartPoint);
|
|
||||||
updateOffset(totalDeltaY);
|
|
||||||
return;
|
|
||||||
} else if (workspaceScrollAvailable() && absX >= touchpadDirectionLockThreshold && absX > absY * touchpadAxisDominance) {
|
|
||||||
touchpadGestureMode = "workspace";
|
|
||||||
} else {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (touchpadGestureMode === "drawer") {
|
|
||||||
updateOffset(deltaY);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!touchpadWorkspaceSwitched && Math.abs(totalDeltaX) >= touchpadWorkspaceSwitchThreshold) {
|
|
||||||
touchpadWorkspaceSwitched = true;
|
|
||||||
activateAdjacentWorkspace(totalDeltaX < 0 ? 1 : -1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function endTouchpadScroll() {
|
|
||||||
if (touchpadGestureMode === "drawer") {
|
|
||||||
endSwipe();
|
|
||||||
}
|
|
||||||
|
|
||||||
touchpadGestureMode = "";
|
|
||||||
touchpadWorkspaceSwitched = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
|
|
||||||
MouseArea {
|
MouseArea {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
acceptedButtons: Qt.NoButton
|
acceptedButtons: Qt.NoButton
|
||||||
hoverEnabled: true
|
hoverEnabled: true
|
||||||
scrollGestureEnabled: false
|
|
||||||
cursorShape: ShellSettings.Settings.convergenceModeEnabled ? Qt.PointingHandCursor : Qt.ArrowCursor
|
cursorShape: ShellSettings.Settings.convergenceModeEnabled ? Qt.PointingHandCursor : Qt.ArrowCursor
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -160,9 +67,9 @@ MobileShell.SwipeArea {
|
||||||
onSwipeEnded: endSwipe()
|
onSwipeEnded: endSwipe()
|
||||||
onSwipeMove: (totalDeltaX, totalDeltaY, deltaX, deltaY) => updateOffset(deltaY);
|
onSwipeMove: (totalDeltaX, totalDeltaY, deltaX, deltaY) => updateOffset(deltaY);
|
||||||
|
|
||||||
onTouchpadScrollStarted: (point) => startTouchpadScroll(point)
|
onTouchpadScrollStarted: (point) => startSwipeWithPoint(point)
|
||||||
onTouchpadScrollEnded: endTouchpadScroll()
|
onTouchpadScrollEnded: endSwipe()
|
||||||
onTouchpadScrollMove: (totalDeltaX, totalDeltaY, deltaX, deltaY) => moveTouchpadScroll(totalDeltaX, totalDeltaY, deltaX, deltaY);
|
onTouchpadScrollMove: (totalDeltaX, totalDeltaY, deltaX, deltaY) => updateOffset(deltaY);
|
||||||
|
|
||||||
// In convergence mode, allow click to toggle the action drawer (mouse-friendly)
|
// In convergence mode, allow click to toggle the action drawer (mouse-friendly)
|
||||||
onClicked: {
|
onClicked: {
|
||||||
|
|
|
||||||
|
|
@ -49,8 +49,6 @@ MobileShellSettings::MobileShellSettings(QObject *parent)
|
||||||
Q_EMIT dynamicTilingEnabledChanged();
|
Q_EMIT dynamicTilingEnabledChanged();
|
||||||
Q_EMIT dynamicTilingWindowRequestChanged();
|
Q_EMIT dynamicTilingWindowRequestChanged();
|
||||||
Q_EMIT dynamicTilingWindowStateChanged();
|
Q_EMIT dynamicTilingWindowStateChanged();
|
||||||
Q_EMIT dynamicTilingLayoutRequestChanged();
|
|
||||||
Q_EMIT dynamicTilingLayoutStateChanged();
|
|
||||||
Q_EMIT snapLayoutsEnabledChanged();
|
Q_EMIT snapLayoutsEnabledChanged();
|
||||||
Q_EMIT allowLogoutChanged();
|
Q_EMIT allowLogoutChanged();
|
||||||
}
|
}
|
||||||
|
|
@ -373,69 +371,6 @@ void MobileShellSettings::reportDynamicTilingWindowState(const QStringList &maxi
|
||||||
Q_EMIT dynamicTilingWindowStateChanged();
|
Q_EMIT dynamicTilingWindowStateChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
QString MobileShellSettings::dynamicTilingLayoutRequestMode() const
|
|
||||||
{
|
|
||||||
auto group = KConfigGroup{m_config, GENERAL_CONFIG_GROUP};
|
|
||||||
return group.readEntry("dynamicTilingLayoutRequestMode", QString{});
|
|
||||||
}
|
|
||||||
|
|
||||||
int MobileShellSettings::dynamicTilingLayoutRequestSerial() const
|
|
||||||
{
|
|
||||||
auto group = KConfigGroup{m_config, GENERAL_CONFIG_GROUP};
|
|
||||||
return group.readEntry("dynamicTilingLayoutRequestSerial", 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void MobileShellSettings::requestDynamicTilingLayoutMode(const QString &mode)
|
|
||||||
{
|
|
||||||
if (mode.isEmpty()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto group = KConfigGroup{m_config, GENERAL_CONFIG_GROUP};
|
|
||||||
const int serial = group.readEntry("dynamicTilingLayoutRequestSerial", 0) + 1;
|
|
||||||
group.writeEntry("dynamicTilingLayoutRequestMode", mode, KConfigGroup::Notify);
|
|
||||||
group.writeEntry("dynamicTilingLayoutRequestSerial", serial, KConfigGroup::Notify);
|
|
||||||
m_config->sync();
|
|
||||||
|
|
||||||
Q_EMIT dynamicTilingLayoutRequestChanged();
|
|
||||||
}
|
|
||||||
|
|
||||||
QString MobileShellSettings::dynamicTilingLayoutMode() const
|
|
||||||
{
|
|
||||||
auto group = KConfigGroup{m_config, GENERAL_CONFIG_GROUP};
|
|
||||||
return group.readEntry("dynamicTilingLayoutMode", QString{});
|
|
||||||
}
|
|
||||||
|
|
||||||
int MobileShellSettings::dynamicTilingLayoutWindowCount() const
|
|
||||||
{
|
|
||||||
auto group = KConfigGroup{m_config, GENERAL_CONFIG_GROUP};
|
|
||||||
return group.readEntry("dynamicTilingLayoutWindowCount", 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
int MobileShellSettings::dynamicTilingLayoutStateSerial() const
|
|
||||||
{
|
|
||||||
auto group = KConfigGroup{m_config, GENERAL_CONFIG_GROUP};
|
|
||||||
return group.readEntry("dynamicTilingLayoutStateSerial", 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void MobileShellSettings::reportDynamicTilingLayoutState(const QString &mode, int windowCount)
|
|
||||||
{
|
|
||||||
const int normalizedWindowCount = windowCount < 0 ? 0 : windowCount;
|
|
||||||
|
|
||||||
auto group = KConfigGroup{m_config, GENERAL_CONFIG_GROUP};
|
|
||||||
if (group.readEntry("dynamicTilingLayoutMode", QString{}) == mode && group.readEntry("dynamicTilingLayoutWindowCount", 0) == normalizedWindowCount) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const int serial = group.readEntry("dynamicTilingLayoutStateSerial", 0) + 1;
|
|
||||||
group.writeEntry("dynamicTilingLayoutMode", mode, KConfigGroup::Notify);
|
|
||||||
group.writeEntry("dynamicTilingLayoutWindowCount", normalizedWindowCount, KConfigGroup::Notify);
|
|
||||||
group.writeEntry("dynamicTilingLayoutStateSerial", serial, KConfigGroup::Notify);
|
|
||||||
m_config->sync();
|
|
||||||
|
|
||||||
Q_EMIT dynamicTilingLayoutStateChanged();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool MobileShellSettings::snapLayoutsEnabled() const
|
bool MobileShellSettings::snapLayoutsEnabled() const
|
||||||
{
|
{
|
||||||
auto group = KConfigGroup{m_config, GENERAL_CONFIG_GROUP};
|
auto group = KConfigGroup{m_config, GENERAL_CONFIG_GROUP};
|
||||||
|
|
|
||||||
|
|
@ -65,11 +65,6 @@ class MobileShellSettings : public QObject
|
||||||
Q_PROPERTY(int dynamicTilingWindowRequestSerial READ dynamicTilingWindowRequestSerial NOTIFY dynamicTilingWindowRequestChanged)
|
Q_PROPERTY(int dynamicTilingWindowRequestSerial READ dynamicTilingWindowRequestSerial NOTIFY dynamicTilingWindowRequestChanged)
|
||||||
Q_PROPERTY(QStringList dynamicTilingMaximizedWindowIds READ dynamicTilingMaximizedWindowIds NOTIFY dynamicTilingWindowStateChanged)
|
Q_PROPERTY(QStringList dynamicTilingMaximizedWindowIds READ dynamicTilingMaximizedWindowIds NOTIFY dynamicTilingWindowStateChanged)
|
||||||
Q_PROPERTY(int dynamicTilingWindowStateSerial READ dynamicTilingWindowStateSerial NOTIFY dynamicTilingWindowStateChanged)
|
Q_PROPERTY(int dynamicTilingWindowStateSerial READ dynamicTilingWindowStateSerial NOTIFY dynamicTilingWindowStateChanged)
|
||||||
Q_PROPERTY(QString dynamicTilingLayoutRequestMode READ dynamicTilingLayoutRequestMode NOTIFY dynamicTilingLayoutRequestChanged)
|
|
||||||
Q_PROPERTY(int dynamicTilingLayoutRequestSerial READ dynamicTilingLayoutRequestSerial NOTIFY dynamicTilingLayoutRequestChanged)
|
|
||||||
Q_PROPERTY(QString dynamicTilingLayoutMode READ dynamicTilingLayoutMode NOTIFY dynamicTilingLayoutStateChanged)
|
|
||||||
Q_PROPERTY(int dynamicTilingLayoutWindowCount READ dynamicTilingLayoutWindowCount NOTIFY dynamicTilingLayoutStateChanged)
|
|
||||||
Q_PROPERTY(int dynamicTilingLayoutStateSerial READ dynamicTilingLayoutStateSerial NOTIFY dynamicTilingLayoutStateChanged)
|
|
||||||
|
|
||||||
// Snap layout picker — only meaningful in convergence mode when dynamic tiling is off.
|
// Snap layout picker — only meaningful in convergence mode when dynamic tiling is off.
|
||||||
Q_PROPERTY(bool snapLayoutsEnabled READ snapLayoutsEnabled WRITE setSnapLayoutsEnabled NOTIFY snapLayoutsEnabledChanged)
|
Q_PROPERTY(bool snapLayoutsEnabled READ snapLayoutsEnabled WRITE setSnapLayoutsEnabled NOTIFY snapLayoutsEnabledChanged)
|
||||||
|
|
@ -307,13 +302,6 @@ public:
|
||||||
int dynamicTilingWindowStateSerial() const;
|
int dynamicTilingWindowStateSerial() const;
|
||||||
Q_INVOKABLE bool isDynamicTilingWindowMaximized(const QString &windowId) const;
|
Q_INVOKABLE bool isDynamicTilingWindowMaximized(const QString &windowId) const;
|
||||||
Q_INVOKABLE void reportDynamicTilingWindowState(const QStringList &maximizedWindowIds);
|
Q_INVOKABLE void reportDynamicTilingWindowState(const QStringList &maximizedWindowIds);
|
||||||
QString dynamicTilingLayoutRequestMode() const;
|
|
||||||
int dynamicTilingLayoutRequestSerial() const;
|
|
||||||
Q_INVOKABLE void requestDynamicTilingLayoutMode(const QString &mode);
|
|
||||||
QString dynamicTilingLayoutMode() const;
|
|
||||||
int dynamicTilingLayoutWindowCount() const;
|
|
||||||
int dynamicTilingLayoutStateSerial() const;
|
|
||||||
Q_INVOKABLE void reportDynamicTilingLayoutState(const QString &mode, int windowCount);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether the SHIFT snap layout picker is enabled.
|
* Whether the SHIFT snap layout picker is enabled.
|
||||||
|
|
@ -374,8 +362,6 @@ Q_SIGNALS:
|
||||||
void dynamicTilingEnabledChanged();
|
void dynamicTilingEnabledChanged();
|
||||||
void dynamicTilingWindowRequestChanged();
|
void dynamicTilingWindowRequestChanged();
|
||||||
void dynamicTilingWindowStateChanged();
|
void dynamicTilingWindowStateChanged();
|
||||||
void dynamicTilingLayoutRequestChanged();
|
|
||||||
void dynamicTilingLayoutStateChanged();
|
|
||||||
void snapLayoutsEnabledChanged();
|
void snapLayoutsEnabledChanged();
|
||||||
void allowLogoutChanged();
|
void allowLogoutChanged();
|
||||||
void lockscreenLeftButtonActionChanged();
|
void lockscreenLeftButtonActionChanged();
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,6 @@ plasma_add_applet(org.kde.plasma.mobile.homescreen.folio
|
||||||
qml/CategoryPanel.qml
|
qml/CategoryPanel.qml
|
||||||
qml/DelegateDragItem.qml
|
qml/DelegateDragItem.qml
|
||||||
qml/DelegateDropArea.qml
|
qml/DelegateDropArea.qml
|
||||||
qml/DynamicTilingLayoutMenu.qml
|
|
||||||
qml/FavouritesBar.qml
|
qml/FavouritesBar.qml
|
||||||
qml/FolderView.qml
|
qml/FolderView.qml
|
||||||
qml/FolderViewTitle.qml
|
qml/FolderViewTitle.qml
|
||||||
|
|
@ -27,7 +26,6 @@ plasma_add_applet(org.kde.plasma.mobile.homescreen.folio
|
||||||
qml/config.qml
|
qml/config.qml
|
||||||
CPP_SOURCES
|
CPP_SOURCES
|
||||||
applicationlistmodel.cpp
|
applicationlistmodel.cpp
|
||||||
applicationusagemodel.cpp
|
|
||||||
delegatetoucharea.cpp
|
delegatetoucharea.cpp
|
||||||
dragstate.cpp
|
dragstate.cpp
|
||||||
favouritesmodel.cpp
|
favouritesmodel.cpp
|
||||||
|
|
|
||||||
|
|
@ -182,17 +182,6 @@ int ApplicationListModel::rowCount(const QModelIndex &parent) const
|
||||||
return m_delegates.count();
|
return m_delegates.count();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<FolioDelegate> ApplicationListModel::delegateForStorageId(const QString &storageId) const
|
|
||||||
{
|
|
||||||
for (const auto &delegate : m_delegates) {
|
|
||||||
if (delegate && delegate->application() && delegate->application()->storageId() == storageId) {
|
|
||||||
return delegate;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sub-categories merged into their canonical parent, mirroring Kickoff's grouping.
|
// Sub-categories merged into their canonical parent, mirroring Kickoff's grouping.
|
||||||
static QString normalizeCategory(const QString &cat)
|
static QString normalizeCategory(const QString &cat)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -12,8 +12,6 @@
|
||||||
#include <QSortFilterProxyModel>
|
#include <QSortFilterProxyModel>
|
||||||
#include <QStringList>
|
#include <QStringList>
|
||||||
|
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
#include <KService>
|
#include <KService>
|
||||||
|
|
||||||
#include "foliodelegate.h"
|
#include "foliodelegate.h"
|
||||||
|
|
@ -47,8 +45,6 @@ public:
|
||||||
|
|
||||||
void load();
|
void load();
|
||||||
|
|
||||||
std::shared_ptr<FolioDelegate> delegateForStorageId(const QString &storageId) const;
|
|
||||||
|
|
||||||
Q_INVOKABLE QStringList allCategories() const;
|
Q_INVOKABLE QStringList allCategories() const;
|
||||||
|
|
||||||
Q_SIGNALS:
|
Q_SIGNALS:
|
||||||
|
|
|
||||||
|
|
@ -1,208 +0,0 @@
|
||||||
// SPDX-FileCopyrightText: 2026 Marco Allegretti
|
|
||||||
// SPDX-License-Identifier: EUPL-1.2
|
|
||||||
|
|
||||||
#include "applicationusagemodel.h"
|
|
||||||
|
|
||||||
#include "applicationlistmodel.h"
|
|
||||||
#include "foliodelegate.h"
|
|
||||||
#include "foliosettings.h"
|
|
||||||
#include "homescreen.h"
|
|
||||||
|
|
||||||
#include <QJsonArray>
|
|
||||||
#include <QJsonDocument>
|
|
||||||
#include <QJsonObject>
|
|
||||||
|
|
||||||
namespace
|
|
||||||
{
|
|
||||||
constexpr qsizetype s_maxStoredEntries = 24;
|
|
||||||
|
|
||||||
QString normalizedStorageId(const QString &storageId)
|
|
||||||
{
|
|
||||||
if (storageId.isEmpty()) {
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
if (storageId.endsWith(QLatin1String(".desktop"))) {
|
|
||||||
return storageId;
|
|
||||||
}
|
|
||||||
|
|
||||||
return storageId + QStringLiteral(".desktop");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ApplicationUsageStore::ApplicationUsageStore(HomeScreen *parent)
|
|
||||||
: QObject{parent}
|
|
||||||
, m_homeScreen{parent}
|
|
||||||
{
|
|
||||||
load();
|
|
||||||
}
|
|
||||||
|
|
||||||
QList<ApplicationUsageEntry> ApplicationUsageStore::entries() const
|
|
||||||
{
|
|
||||||
return m_entries.values();
|
|
||||||
}
|
|
||||||
|
|
||||||
void ApplicationUsageStore::recordUsage(const QString &storageId)
|
|
||||||
{
|
|
||||||
const QString normalizedId = normalizedStorageId(storageId);
|
|
||||||
if (normalizedId.isEmpty()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto &entry = m_entries[normalizedId];
|
|
||||||
entry.storageId = normalizedId;
|
|
||||||
entry.launchCount = std::max(0, entry.launchCount) + 1;
|
|
||||||
entry.lastUsed = QDateTime::currentDateTimeUtc();
|
|
||||||
|
|
||||||
save();
|
|
||||||
Q_EMIT usageChanged();
|
|
||||||
}
|
|
||||||
|
|
||||||
void ApplicationUsageStore::load()
|
|
||||||
{
|
|
||||||
m_entries.clear();
|
|
||||||
|
|
||||||
if (!m_homeScreen) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const QJsonDocument doc = QJsonDocument::fromJson(m_homeScreen->folioSettings()->applicationUsage().toUtf8());
|
|
||||||
const QJsonArray usageArray = doc.array();
|
|
||||||
|
|
||||||
for (const QJsonValue &value : usageArray) {
|
|
||||||
const QJsonObject object = value.toObject();
|
|
||||||
const QString storageId = normalizedStorageId(object.value(QStringLiteral("storageId")).toString());
|
|
||||||
if (storageId.isEmpty()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
ApplicationUsageEntry entry;
|
|
||||||
entry.storageId = storageId;
|
|
||||||
entry.launchCount = object.value(QStringLiteral("launchCount")).toInt();
|
|
||||||
entry.lastUsed = QDateTime::fromString(object.value(QStringLiteral("lastUsed")).toString(), Qt::ISODateWithMs);
|
|
||||||
|
|
||||||
if (entry.launchCount <= 0 || !entry.lastUsed.isValid()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_entries.insert(storageId, entry);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ApplicationUsageStore::save()
|
|
||||||
{
|
|
||||||
if (!m_homeScreen) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
QList<ApplicationUsageEntry> entries = m_entries.values();
|
|
||||||
std::sort(entries.begin(), entries.end(), [](const ApplicationUsageEntry &left, const ApplicationUsageEntry &right) {
|
|
||||||
return left.lastUsed > right.lastUsed;
|
|
||||||
});
|
|
||||||
|
|
||||||
if (entries.size() > s_maxStoredEntries) {
|
|
||||||
entries.resize(s_maxStoredEntries);
|
|
||||||
}
|
|
||||||
|
|
||||||
QJsonArray usageArray;
|
|
||||||
for (const ApplicationUsageEntry &entry : std::as_const(entries)) {
|
|
||||||
QJsonObject object;
|
|
||||||
object.insert(QStringLiteral("storageId"), entry.storageId);
|
|
||||||
object.insert(QStringLiteral("launchCount"), entry.launchCount);
|
|
||||||
object.insert(QStringLiteral("lastUsed"), entry.lastUsed.toString(Qt::ISODateWithMs));
|
|
||||||
usageArray.append(object);
|
|
||||||
}
|
|
||||||
|
|
||||||
m_homeScreen->folioSettings()->setApplicationUsage(QString::fromUtf8(QJsonDocument(usageArray).toJson(QJsonDocument::Compact)));
|
|
||||||
}
|
|
||||||
|
|
||||||
ApplicationUsageModel::ApplicationUsageModel(HomeScreen *homeScreen, ApplicationUsageStore *store, Mode mode)
|
|
||||||
: QAbstractListModel{homeScreen}
|
|
||||||
, m_homeScreen{homeScreen}
|
|
||||||
, m_store{store}
|
|
||||||
, m_mode{mode}
|
|
||||||
{
|
|
||||||
if (m_store) {
|
|
||||||
connect(m_store, &ApplicationUsageStore::usageChanged, this, &ApplicationUsageModel::rebuild);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_homeScreen && m_homeScreen->applicationListModel()) {
|
|
||||||
auto *applicationListModel = m_homeScreen->applicationListModel();
|
|
||||||
connect(applicationListModel, &QAbstractItemModel::rowsInserted, this, &ApplicationUsageModel::rebuild);
|
|
||||||
connect(applicationListModel, &QAbstractItemModel::rowsRemoved, this, &ApplicationUsageModel::rebuild);
|
|
||||||
connect(applicationListModel, &QAbstractItemModel::modelReset, this, &ApplicationUsageModel::rebuild);
|
|
||||||
}
|
|
||||||
|
|
||||||
rebuild();
|
|
||||||
}
|
|
||||||
|
|
||||||
int ApplicationUsageModel::rowCount(const QModelIndex &parent) const
|
|
||||||
{
|
|
||||||
if (parent.isValid()) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return m_entries.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
QVariant ApplicationUsageModel::data(const QModelIndex &index, int role) const
|
|
||||||
{
|
|
||||||
if (!index.isValid() || index.row() < 0 || index.row() >= m_entries.size()) {
|
|
||||||
return QVariant();
|
|
||||||
}
|
|
||||||
|
|
||||||
const ApplicationUsageEntry &entry = m_entries.at(index.row());
|
|
||||||
switch (role) {
|
|
||||||
case Qt::DisplayRole:
|
|
||||||
case DelegateRole:
|
|
||||||
return QVariant::fromValue(m_delegates.at(index.row()).get());
|
|
||||||
case LaunchCountRole:
|
|
||||||
return entry.launchCount;
|
|
||||||
case LastUsedRole:
|
|
||||||
return entry.lastUsed;
|
|
||||||
default:
|
|
||||||
return QVariant();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
QHash<int, QByteArray> ApplicationUsageModel::roleNames() const
|
|
||||||
{
|
|
||||||
return {
|
|
||||||
{DelegateRole, QByteArrayLiteral("delegate")},
|
|
||||||
{LaunchCountRole, QByteArrayLiteral("launchCount")},
|
|
||||||
{LastUsedRole, QByteArrayLiteral("lastUsed")},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
void ApplicationUsageModel::rebuild()
|
|
||||||
{
|
|
||||||
QList<ApplicationUsageEntry> entries = m_store ? m_store->entries() : QList<ApplicationUsageEntry>{};
|
|
||||||
|
|
||||||
std::sort(entries.begin(), entries.end(), [this](const ApplicationUsageEntry &left, const ApplicationUsageEntry &right) {
|
|
||||||
if (m_mode == MostUsed && left.launchCount != right.launchCount) {
|
|
||||||
return left.launchCount > right.launchCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
return left.lastUsed > right.lastUsed;
|
|
||||||
});
|
|
||||||
|
|
||||||
QList<ApplicationUsageEntry> nextEntries;
|
|
||||||
QList<std::shared_ptr<FolioDelegate>> nextDelegates;
|
|
||||||
|
|
||||||
if (m_homeScreen && m_homeScreen->applicationListModel()) {
|
|
||||||
for (const ApplicationUsageEntry &entry : std::as_const(entries)) {
|
|
||||||
auto delegate = m_homeScreen->applicationListModel()->delegateForStorageId(entry.storageId);
|
|
||||||
if (!delegate || !delegate->application()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
nextEntries.append(entry);
|
|
||||||
nextDelegates.append(delegate);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
beginResetModel();
|
|
||||||
m_entries = nextEntries;
|
|
||||||
m_delegates = nextDelegates;
|
|
||||||
endResetModel();
|
|
||||||
}
|
|
||||||
|
|
@ -1,80 +0,0 @@
|
||||||
// SPDX-FileCopyrightText: 2026 Marco Allegretti
|
|
||||||
// SPDX-License-Identifier: EUPL-1.2
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <QAbstractListModel>
|
|
||||||
#include <QDateTime>
|
|
||||||
#include <QHash>
|
|
||||||
#include <QList>
|
|
||||||
#include <QObject>
|
|
||||||
#include <QString>
|
|
||||||
|
|
||||||
#include <QtQmlIntegration/qqmlintegration.h>
|
|
||||||
|
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
class FolioDelegate;
|
|
||||||
class HomeScreen;
|
|
||||||
|
|
||||||
struct ApplicationUsageEntry {
|
|
||||||
QString storageId;
|
|
||||||
int launchCount = 0;
|
|
||||||
QDateTime lastUsed;
|
|
||||||
};
|
|
||||||
|
|
||||||
class ApplicationUsageStore : public QObject
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
public:
|
|
||||||
explicit ApplicationUsageStore(HomeScreen *parent = nullptr);
|
|
||||||
|
|
||||||
QList<ApplicationUsageEntry> entries() const;
|
|
||||||
void recordUsage(const QString &storageId);
|
|
||||||
|
|
||||||
Q_SIGNALS:
|
|
||||||
void usageChanged();
|
|
||||||
|
|
||||||
private:
|
|
||||||
void load();
|
|
||||||
void save();
|
|
||||||
|
|
||||||
HomeScreen *m_homeScreen{nullptr};
|
|
||||||
QHash<QString, ApplicationUsageEntry> m_entries;
|
|
||||||
};
|
|
||||||
|
|
||||||
class ApplicationUsageModel : public QAbstractListModel
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
QML_ELEMENT
|
|
||||||
QML_UNCREATABLE("")
|
|
||||||
|
|
||||||
public:
|
|
||||||
enum Mode {
|
|
||||||
RecentUsage,
|
|
||||||
MostUsed,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum Roles {
|
|
||||||
DelegateRole = Qt::UserRole + 1,
|
|
||||||
LaunchCountRole,
|
|
||||||
LastUsedRole,
|
|
||||||
};
|
|
||||||
|
|
||||||
ApplicationUsageModel(HomeScreen *homeScreen = nullptr, ApplicationUsageStore *store = nullptr, Mode mode = RecentUsage);
|
|
||||||
|
|
||||||
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
|
|
||||||
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
|
|
||||||
QHash<int, QByteArray> roleNames() const override;
|
|
||||||
|
|
||||||
public Q_SLOTS:
|
|
||||||
void rebuild();
|
|
||||||
|
|
||||||
private:
|
|
||||||
HomeScreen *m_homeScreen{nullptr};
|
|
||||||
ApplicationUsageStore *m_store{nullptr};
|
|
||||||
Mode m_mode{RecentUsage};
|
|
||||||
QList<ApplicationUsageEntry> m_entries;
|
|
||||||
QList<std::shared_ptr<FolioDelegate>> m_delegates;
|
|
||||||
};
|
|
||||||
|
|
@ -16,7 +16,6 @@ using namespace Qt::Literals::StringLiterals;
|
||||||
const QString CFG_GROUP_FOLIO = QStringLiteral("Folio");
|
const QString CFG_GROUP_FOLIO = QStringLiteral("Folio");
|
||||||
|
|
||||||
const QString CFG_KEY_FAVORITES = QStringLiteral("favorites");
|
const QString CFG_KEY_FAVORITES = QStringLiteral("favorites");
|
||||||
const QString CFG_KEY_APPLICATION_USAGE = QStringLiteral("applicationUsage");
|
|
||||||
const QString CFG_KEY_PAGES = QStringLiteral("pages");
|
const QString CFG_KEY_PAGES = QStringLiteral("pages");
|
||||||
|
|
||||||
const QString CFG_KEY_HOMESCREEN_ROWS = QStringLiteral("homeScreenRows");
|
const QString CFG_KEY_HOMESCREEN_ROWS = QStringLiteral("homeScreenRows");
|
||||||
|
|
@ -48,17 +47,6 @@ void FolioSettings::setFavorites(const QString &favoritesJson)
|
||||||
Q_EMIT m_homeScreen->configNeedsSaving();
|
Q_EMIT m_homeScreen->configNeedsSaving();
|
||||||
}
|
}
|
||||||
|
|
||||||
QString FolioSettings::applicationUsage() const
|
|
||||||
{
|
|
||||||
return generalConfigGroup().readEntry(CFG_KEY_APPLICATION_USAGE, QStringLiteral("[]"));
|
|
||||||
}
|
|
||||||
|
|
||||||
void FolioSettings::setApplicationUsage(const QString &applicationUsageJson)
|
|
||||||
{
|
|
||||||
generalConfigGroup().writeEntry(CFG_KEY_APPLICATION_USAGE, applicationUsageJson);
|
|
||||||
Q_EMIT m_homeScreen->configNeedsSaving();
|
|
||||||
}
|
|
||||||
|
|
||||||
QString FolioSettings::pages() const
|
QString FolioSettings::pages() const
|
||||||
{
|
{
|
||||||
return generalConfigGroup().readEntry(CFG_KEY_PAGES, u"{}"_s);
|
return generalConfigGroup().readEntry(CFG_KEY_PAGES, u"{}"_s);
|
||||||
|
|
|
||||||
|
|
@ -53,10 +53,6 @@ public:
|
||||||
QString favorites() const;
|
QString favorites() const;
|
||||||
void setFavorites(const QString &favoritesJson);
|
void setFavorites(const QString &favoritesJson);
|
||||||
|
|
||||||
// JSON array
|
|
||||||
QString applicationUsage() const;
|
|
||||||
void setApplicationUsage(const QString &applicationUsageJson);
|
|
||||||
|
|
||||||
// JSON object
|
// JSON object
|
||||||
QString pages() const;
|
QString pages() const;
|
||||||
void setPages(const QString &pagesJson);
|
void setPages(const QString &pagesJson);
|
||||||
|
|
|
||||||
|
|
@ -4,8 +4,6 @@
|
||||||
|
|
||||||
#include "homescreen.h"
|
#include "homescreen.h"
|
||||||
|
|
||||||
#include "windowlistener.h"
|
|
||||||
|
|
||||||
#include <virtualdesktopinfo.h>
|
#include <virtualdesktopinfo.h>
|
||||||
|
|
||||||
#include <KWindowSystem>
|
#include <KWindowSystem>
|
||||||
|
|
@ -60,9 +58,6 @@ HomeScreen::HomeScreen(QObject *parent, const KPluginMetaData &data, const QVari
|
||||||
, m_widgetsManager{new WidgetsManager{this}}
|
, m_widgetsManager{new WidgetsManager{this}}
|
||||||
, m_applicationListModel{new ApplicationListModel{this}}
|
, m_applicationListModel{new ApplicationListModel{this}}
|
||||||
, m_applicationListSearchModel{new ApplicationListSearchModel{this, m_applicationListModel}}
|
, m_applicationListSearchModel{new ApplicationListSearchModel{this, m_applicationListModel}}
|
||||||
, m_applicationUsageStore{new ApplicationUsageStore{this}}
|
|
||||||
, m_recentApplicationsModel{new ApplicationUsageModel{this, m_applicationUsageStore, ApplicationUsageModel::RecentUsage}}
|
|
||||||
, m_mostUsedApplicationsModel{new ApplicationUsageModel{this, m_applicationUsageStore, ApplicationUsageModel::MostUsed}}
|
|
||||||
, m_favouritesModel{new FavouritesModel{this}}
|
, m_favouritesModel{new FavouritesModel{this}}
|
||||||
, m_pageListModel{new PageListModel{this}}
|
, m_pageListModel{new PageListModel{this}}
|
||||||
{
|
{
|
||||||
|
|
@ -89,11 +84,6 @@ HomeScreen::HomeScreen(QObject *parent, const KPluginMetaData &data, const QVari
|
||||||
|
|
||||||
connect(this, &Plasma::Containment::appletAdded, this, &HomeScreen::onAppletAdded);
|
connect(this, &Plasma::Containment::appletAdded, this, &HomeScreen::onAppletAdded);
|
||||||
connect(this, &Plasma::Containment::appletAboutToBeRemoved, this, &HomeScreen::onAppletAboutToBeRemoved);
|
connect(this, &Plasma::Containment::appletAboutToBeRemoved, this, &HomeScreen::onAppletAboutToBeRemoved);
|
||||||
connect(WindowListener::instance(), &WindowListener::windowChanged, this, [this](QString storageId) {
|
|
||||||
if (!WindowListener::instance()->windowsFromStorageId(storageId).empty()) {
|
|
||||||
m_applicationUsageStore->recordUsage(storageId);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
HomeScreen::~HomeScreen() = default;
|
HomeScreen::~HomeScreen() = default;
|
||||||
|
|
@ -139,16 +129,6 @@ ApplicationListSearchModel *HomeScreen::applicationListSearchModel()
|
||||||
return m_applicationListSearchModel;
|
return m_applicationListSearchModel;
|
||||||
}
|
}
|
||||||
|
|
||||||
ApplicationUsageModel *HomeScreen::recentApplicationsModel()
|
|
||||||
{
|
|
||||||
return m_recentApplicationsModel;
|
|
||||||
}
|
|
||||||
|
|
||||||
ApplicationUsageModel *HomeScreen::mostUsedApplicationsModel()
|
|
||||||
{
|
|
||||||
return m_mostUsedApplicationsModel;
|
|
||||||
}
|
|
||||||
|
|
||||||
FavouritesModel *HomeScreen::favouritesModel()
|
FavouritesModel *HomeScreen::favouritesModel()
|
||||||
{
|
{
|
||||||
return m_favouritesModel;
|
return m_favouritesModel;
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,6 @@
|
||||||
#include <QVariant>
|
#include <QVariant>
|
||||||
|
|
||||||
#include "applicationlistmodel.h"
|
#include "applicationlistmodel.h"
|
||||||
#include "applicationusagemodel.h"
|
|
||||||
#include "delegatetoucharea.h"
|
#include "delegatetoucharea.h"
|
||||||
#include "favouritesmodel.h"
|
#include "favouritesmodel.h"
|
||||||
#include "folioapplication.h"
|
#include "folioapplication.h"
|
||||||
|
|
@ -30,8 +29,6 @@ class HomeScreenState;
|
||||||
class FavouritesModel;
|
class FavouritesModel;
|
||||||
class ApplicationListModel;
|
class ApplicationListModel;
|
||||||
class ApplicationListSearchModel;
|
class ApplicationListSearchModel;
|
||||||
class ApplicationUsageModel;
|
|
||||||
class ApplicationUsageStore;
|
|
||||||
|
|
||||||
class HomeScreen : public Plasma::Containment
|
class HomeScreen : public Plasma::Containment
|
||||||
{
|
{
|
||||||
|
|
@ -44,8 +41,6 @@ class HomeScreen : public Plasma::Containment
|
||||||
Q_PROPERTY(WidgetsManager *WidgetsManager READ widgetsManager CONSTANT)
|
Q_PROPERTY(WidgetsManager *WidgetsManager READ widgetsManager CONSTANT)
|
||||||
Q_PROPERTY(ApplicationListModel *ApplicationListModel READ applicationListModel CONSTANT)
|
Q_PROPERTY(ApplicationListModel *ApplicationListModel READ applicationListModel CONSTANT)
|
||||||
Q_PROPERTY(ApplicationListSearchModel *ApplicationListSearchModel READ applicationListSearchModel CONSTANT)
|
Q_PROPERTY(ApplicationListSearchModel *ApplicationListSearchModel READ applicationListSearchModel CONSTANT)
|
||||||
Q_PROPERTY(ApplicationUsageModel *RecentApplicationsModel READ recentApplicationsModel CONSTANT)
|
|
||||||
Q_PROPERTY(ApplicationUsageModel *MostUsedApplicationsModel READ mostUsedApplicationsModel CONSTANT)
|
|
||||||
Q_PROPERTY(FavouritesModel *FavouritesModel READ favouritesModel CONSTANT)
|
Q_PROPERTY(FavouritesModel *FavouritesModel READ favouritesModel CONSTANT)
|
||||||
Q_PROPERTY(PageListModel *PageListModel READ pageListModel CONSTANT)
|
Q_PROPERTY(PageListModel *PageListModel READ pageListModel CONSTANT)
|
||||||
Q_PROPERTY(bool overviewActive READ overviewActive NOTIFY overviewActiveChanged)
|
Q_PROPERTY(bool overviewActive READ overviewActive NOTIFY overviewActiveChanged)
|
||||||
|
|
@ -68,8 +63,6 @@ public:
|
||||||
WidgetsManager *widgetsManager();
|
WidgetsManager *widgetsManager();
|
||||||
ApplicationListModel *applicationListModel();
|
ApplicationListModel *applicationListModel();
|
||||||
ApplicationListSearchModel *applicationListSearchModel();
|
ApplicationListSearchModel *applicationListSearchModel();
|
||||||
ApplicationUsageModel *recentApplicationsModel();
|
|
||||||
ApplicationUsageModel *mostUsedApplicationsModel();
|
|
||||||
FavouritesModel *favouritesModel();
|
FavouritesModel *favouritesModel();
|
||||||
PageListModel *pageListModel();
|
PageListModel *pageListModel();
|
||||||
bool overviewActive() const;
|
bool overviewActive() const;
|
||||||
|
|
@ -92,9 +85,6 @@ private:
|
||||||
WidgetsManager *m_widgetsManager{nullptr};
|
WidgetsManager *m_widgetsManager{nullptr};
|
||||||
ApplicationListModel *m_applicationListModel{nullptr};
|
ApplicationListModel *m_applicationListModel{nullptr};
|
||||||
ApplicationListSearchModel *m_applicationListSearchModel{nullptr};
|
ApplicationListSearchModel *m_applicationListSearchModel{nullptr};
|
||||||
ApplicationUsageStore *m_applicationUsageStore{nullptr};
|
|
||||||
ApplicationUsageModel *m_recentApplicationsModel{nullptr};
|
|
||||||
ApplicationUsageModel *m_mostUsedApplicationsModel{nullptr};
|
|
||||||
FavouritesModel *m_favouritesModel{nullptr};
|
FavouritesModel *m_favouritesModel{nullptr};
|
||||||
PageListModel *m_pageListModel{nullptr};
|
PageListModel *m_pageListModel{nullptr};
|
||||||
bool m_overviewActive{false};
|
bool m_overviewActive{false};
|
||||||
|
|
|
||||||
|
|
@ -1,298 +0,0 @@
|
||||||
// SPDX-FileCopyrightText: 2026 Marco Allegretti
|
|
||||||
// SPDX-License-Identifier: EUPL-1.2
|
|
||||||
|
|
||||||
import QtQuick
|
|
||||||
import QtQuick.Layouts
|
|
||||||
import QtQuick.Shapes 1.8
|
|
||||||
|
|
||||||
import org.kde.kirigami as Kirigami
|
|
||||||
import org.kde.plasma.components 3.0 as PlasmaComponents
|
|
||||||
import org.kde.plasma.private.mobileshell as MobileShell
|
|
||||||
|
|
||||||
Item {
|
|
||||||
id: root
|
|
||||||
|
|
||||||
property int windowCount: 0
|
|
||||||
property string currentMode: ""
|
|
||||||
property color surfaceColor: Kirigami.Theme.backgroundColor
|
|
||||||
property int animationDuration: Kirigami.Units.shortDuration
|
|
||||||
property real maxHeight: 0
|
|
||||||
|
|
||||||
signal layoutModeRequested(string mode)
|
|
||||||
signal dismissRequested()
|
|
||||||
|
|
||||||
readonly property int clampedWindowCount: clampedLayoutWindowCount(windowCount)
|
|
||||||
readonly property var layoutOptions: layoutOptionsForWindowCount(clampedWindowCount)
|
|
||||||
readonly property int optionCount: layoutOptions.length
|
|
||||||
readonly property real rowHeight: Math.max(Kirigami.Units.gridUnit * 2.4,
|
|
||||||
Kirigami.Units.iconSizes.medium + Kirigami.Units.smallSpacing * 2)
|
|
||||||
readonly property real naturalHeight: Kirigami.Units.gridUnit * 2.2
|
|
||||||
+ Math.max(1, optionCount) * rowHeight
|
|
||||||
+ Kirigami.Units.smallSpacing * 3
|
|
||||||
readonly property real preferredHeight: maxHeight > 0 ? Math.min(naturalHeight, maxHeight) : naturalHeight
|
|
||||||
readonly property real cornerRadius: Math.min(MobileShell.Constants.convergenceWorkspaceFrameRadius, height * 0.24)
|
|
||||||
|
|
||||||
clip: true
|
|
||||||
|
|
||||||
function clampedLayoutWindowCount(windowCount) {
|
|
||||||
const count = Math.round(Number(windowCount) || 0)
|
|
||||||
return Math.max(0, Math.min(4, count))
|
|
||||||
}
|
|
||||||
|
|
||||||
function linearLayoutZones(windowCount, orientation) {
|
|
||||||
const count = Math.max(1, clampedLayoutWindowCount(windowCount))
|
|
||||||
let zones = []
|
|
||||||
for (let i = 0; i < count; i++) {
|
|
||||||
if (orientation === "horizontal") {
|
|
||||||
zones.push({ x: 0, y: i / count, w: 1, h: 1 / count })
|
|
||||||
} else {
|
|
||||||
zones.push({ x: i / count, y: 0, w: 1 / count, h: 1 })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return zones
|
|
||||||
}
|
|
||||||
|
|
||||||
function masterLayoutZones(windowCount) {
|
|
||||||
const count = clampedLayoutWindowCount(windowCount)
|
|
||||||
if (count <= 2) {
|
|
||||||
return linearLayoutZones(Math.max(1, count), "vertical")
|
|
||||||
}
|
|
||||||
|
|
||||||
let zones = [{ x: 0, y: 0, w: 0.58, h: 1 }]
|
|
||||||
const stackCount = count - 1
|
|
||||||
for (let i = 0; i < stackCount; i++) {
|
|
||||||
zones.push({ x: 0.58, y: i / stackCount, w: 0.42, h: 1 / stackCount })
|
|
||||||
}
|
|
||||||
return zones
|
|
||||||
}
|
|
||||||
|
|
||||||
function layoutOptionsForWindowCount(windowCount) {
|
|
||||||
const count = clampedLayoutWindowCount(windowCount)
|
|
||||||
if (count < 2) {
|
|
||||||
return []
|
|
||||||
}
|
|
||||||
|
|
||||||
if (count === 2) {
|
|
||||||
return [
|
|
||||||
{
|
|
||||||
mode: "columns",
|
|
||||||
selectedModes: ["master", "columns"],
|
|
||||||
name: i18n("Side by Side"),
|
|
||||||
summary: i18n("2 columns"),
|
|
||||||
zones: linearLayoutZones(count, "vertical")
|
|
||||||
},
|
|
||||||
{
|
|
||||||
mode: "rows",
|
|
||||||
selectedModes: ["rows"],
|
|
||||||
name: i18n("Stacked"),
|
|
||||||
summary: i18n("2 rows"),
|
|
||||||
zones: linearLayoutZones(count, "horizontal")
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
return [
|
|
||||||
{
|
|
||||||
mode: "master",
|
|
||||||
selectedModes: ["master"],
|
|
||||||
name: i18n("Master Stack"),
|
|
||||||
summary: i18n("1 + %1 stack", count - 1),
|
|
||||||
zones: masterLayoutZones(count)
|
|
||||||
},
|
|
||||||
{
|
|
||||||
mode: "columns",
|
|
||||||
selectedModes: ["columns"],
|
|
||||||
name: i18n("Columns"),
|
|
||||||
summary: i18n("%1 columns", count),
|
|
||||||
zones: linearLayoutZones(count, "vertical")
|
|
||||||
},
|
|
||||||
{
|
|
||||||
mode: "rows",
|
|
||||||
selectedModes: ["rows"],
|
|
||||||
name: i18n("Rows"),
|
|
||||||
summary: i18n("%1 rows", count),
|
|
||||||
zones: linearLayoutZones(count, "horizontal")
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
function emptyLayoutSummary() {
|
|
||||||
return clampedWindowCount === 1 ? i18n("1 window") : i18n("0 windows")
|
|
||||||
}
|
|
||||||
|
|
||||||
Behavior on opacity {
|
|
||||||
MobileShell.MotionNumberAnimation {
|
|
||||||
type: MobileShell.Motion.EffectsFast
|
|
||||||
duration: root.animationDuration
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Shape {
|
|
||||||
anchors.fill: parent
|
|
||||||
|
|
||||||
ShapePath {
|
|
||||||
fillColor: root.surfaceColor
|
|
||||||
strokeWidth: 0
|
|
||||||
|
|
||||||
startX: root.width
|
|
||||||
startY: 0
|
|
||||||
PathLine { x: root.cornerRadius; y: 0 }
|
|
||||||
PathArc {
|
|
||||||
x: 0
|
|
||||||
y: root.cornerRadius
|
|
||||||
radiusX: root.cornerRadius
|
|
||||||
radiusY: root.cornerRadius
|
|
||||||
direction: PathArc.Counterclockwise
|
|
||||||
}
|
|
||||||
PathLine { x: 0; y: root.height - root.cornerRadius }
|
|
||||||
PathArc {
|
|
||||||
x: root.cornerRadius
|
|
||||||
y: root.height
|
|
||||||
radiusX: root.cornerRadius
|
|
||||||
radiusY: root.cornerRadius
|
|
||||||
direction: PathArc.Counterclockwise
|
|
||||||
}
|
|
||||||
PathLine { x: root.width; y: root.height }
|
|
||||||
PathLine { x: root.width; y: 0 }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
MouseArea {
|
|
||||||
anchors.fill: parent
|
|
||||||
hoverEnabled: true
|
|
||||||
}
|
|
||||||
|
|
||||||
ColumnLayout {
|
|
||||||
anchors.fill: parent
|
|
||||||
anchors.margins: Kirigami.Units.smallSpacing
|
|
||||||
spacing: Kirigami.Units.smallSpacing
|
|
||||||
|
|
||||||
PlasmaComponents.Label {
|
|
||||||
Layout.fillWidth: true
|
|
||||||
text: i18n("Tiling Layout")
|
|
||||||
font.weight: Font.Medium
|
|
||||||
elide: Text.ElideRight
|
|
||||||
maximumLineCount: 1
|
|
||||||
}
|
|
||||||
|
|
||||||
Repeater {
|
|
||||||
model: root.layoutOptions
|
|
||||||
|
|
||||||
delegate: MouseArea {
|
|
||||||
id: optionButton
|
|
||||||
|
|
||||||
required property var modelData
|
|
||||||
|
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.preferredHeight: root.rowHeight
|
|
||||||
hoverEnabled: true
|
|
||||||
cursorShape: Qt.PointingHandCursor
|
|
||||||
|
|
||||||
readonly property bool selected: modelData.selectedModes.indexOf(root.currentMode) >= 0
|
|
||||||
|
|
||||||
onClicked: {
|
|
||||||
if (!selected) {
|
|
||||||
root.layoutModeRequested(modelData.mode)
|
|
||||||
}
|
|
||||||
root.dismissRequested()
|
|
||||||
}
|
|
||||||
|
|
||||||
Rectangle {
|
|
||||||
anchors.fill: parent
|
|
||||||
radius: Kirigami.Units.cornerRadius
|
|
||||||
color: optionButton.selected
|
|
||||||
? Qt.rgba(Kirigami.Theme.highlightColor.r, Kirigami.Theme.highlightColor.g, Kirigami.Theme.highlightColor.b, 0.24)
|
|
||||||
: optionButton.containsMouse
|
|
||||||
? Qt.rgba(Kirigami.Theme.textColor.r, Kirigami.Theme.textColor.g, Kirigami.Theme.textColor.b, 0.08)
|
|
||||||
: "transparent"
|
|
||||||
border.width: optionButton.selected ? 1 : 0
|
|
||||||
border.color: Qt.rgba(Kirigami.Theme.highlightColor.r, Kirigami.Theme.highlightColor.g, Kirigami.Theme.highlightColor.b, 0.5)
|
|
||||||
}
|
|
||||||
|
|
||||||
RowLayout {
|
|
||||||
anchors.fill: parent
|
|
||||||
anchors.leftMargin: Kirigami.Units.smallSpacing
|
|
||||||
anchors.rightMargin: Kirigami.Units.smallSpacing
|
|
||||||
spacing: Kirigami.Units.smallSpacing
|
|
||||||
|
|
||||||
Rectangle {
|
|
||||||
id: layoutPreviewFrame
|
|
||||||
|
|
||||||
Layout.preferredWidth: Kirigami.Units.gridUnit * 2.5
|
|
||||||
Layout.preferredHeight: Kirigami.Units.gridUnit * 1.65
|
|
||||||
radius: Kirigami.Units.cornerRadius
|
|
||||||
color: Qt.rgba(Kirigami.Theme.textColor.r, Kirigami.Theme.textColor.g, Kirigami.Theme.textColor.b, 0.06)
|
|
||||||
border.width: 1
|
|
||||||
border.color: Qt.rgba(Kirigami.Theme.textColor.r, Kirigami.Theme.textColor.g, Kirigami.Theme.textColor.b, 0.18)
|
|
||||||
|
|
||||||
Repeater {
|
|
||||||
model: optionButton.modelData.zones
|
|
||||||
|
|
||||||
delegate: Rectangle {
|
|
||||||
required property var modelData
|
|
||||||
|
|
||||||
x: Math.round(layoutPreviewFrame.width * modelData.x) + Kirigami.Units.smallSpacing / 2
|
|
||||||
y: Math.round(layoutPreviewFrame.height * modelData.y) + Kirigami.Units.smallSpacing / 2
|
|
||||||
width: Math.max(1, Math.round(layoutPreviewFrame.width * modelData.w) - Kirigami.Units.smallSpacing)
|
|
||||||
height: Math.max(1, Math.round(layoutPreviewFrame.height * modelData.h) - Kirigami.Units.smallSpacing)
|
|
||||||
radius: Math.max(1, Kirigami.Units.cornerRadius - 1)
|
|
||||||
color: Qt.rgba(Kirigami.Theme.highlightColor.r, Kirigami.Theme.highlightColor.g, Kirigami.Theme.highlightColor.b, 0.58)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ColumnLayout {
|
|
||||||
Layout.fillWidth: true
|
|
||||||
spacing: 0
|
|
||||||
|
|
||||||
PlasmaComponents.Label {
|
|
||||||
Layout.fillWidth: true
|
|
||||||
text: optionButton.modelData.name
|
|
||||||
elide: Text.ElideRight
|
|
||||||
maximumLineCount: 1
|
|
||||||
}
|
|
||||||
|
|
||||||
PlasmaComponents.Label {
|
|
||||||
Layout.fillWidth: true
|
|
||||||
text: optionButton.modelData.summary
|
|
||||||
opacity: 0.62
|
|
||||||
font: Kirigami.Theme.smallFont
|
|
||||||
elide: Text.ElideRight
|
|
||||||
maximumLineCount: 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ColumnLayout {
|
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.fillHeight: true
|
|
||||||
visible: root.optionCount === 0
|
|
||||||
spacing: Kirigami.Units.smallSpacing
|
|
||||||
|
|
||||||
Item { Layout.fillHeight: true }
|
|
||||||
|
|
||||||
PlasmaComponents.Label {
|
|
||||||
Layout.fillWidth: true
|
|
||||||
horizontalAlignment: Text.AlignHCenter
|
|
||||||
text: i18n("No Alternatives")
|
|
||||||
font.weight: Font.Medium
|
|
||||||
elide: Text.ElideRight
|
|
||||||
maximumLineCount: 1
|
|
||||||
}
|
|
||||||
|
|
||||||
PlasmaComponents.Label {
|
|
||||||
Layout.fillWidth: true
|
|
||||||
horizontalAlignment: Text.AlignHCenter
|
|
||||||
text: root.emptyLayoutSummary()
|
|
||||||
opacity: 0.62
|
|
||||||
font: Kirigami.Theme.smallFont
|
|
||||||
elide: Text.ElideRight
|
|
||||||
maximumLineCount: 1
|
|
||||||
}
|
|
||||||
|
|
||||||
Item { Layout.fillHeight: true }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -94,8 +94,6 @@ MouseArea {
|
||||||
// Virtual desktop pager (convergence mode, 2+ desktops)
|
// Virtual desktop pager (convergence mode, 2+ desktops)
|
||||||
readonly property bool showPager: convergenceMode && virtualDesktopInfo.numberOfDesktops > 1
|
readonly property bool showPager: convergenceMode && virtualDesktopInfo.numberOfDesktops > 1
|
||||||
property real pagerButtonWidth: showPager ? Math.min(root.height, Kirigami.Units.gridUnit * 2.5) : 0
|
property real pagerButtonWidth: showPager ? Math.min(root.height, Kirigami.Units.gridUnit * 2.5) : 0
|
||||||
property int pagerWheelDelta: 0
|
|
||||||
property bool pagerWheelLocked: false
|
|
||||||
readonly property int pagerLeftCount: showPager ? Math.ceil(virtualDesktopInfo.numberOfDesktops / 2) : 0
|
readonly property int pagerLeftCount: showPager ? Math.ceil(virtualDesktopInfo.numberOfDesktops / 2) : 0
|
||||||
readonly property int pagerRightCount: showPager ? virtualDesktopInfo.numberOfDesktops - pagerLeftCount : 0
|
readonly property int pagerRightCount: showPager ? virtualDesktopInfo.numberOfDesktops - pagerLeftCount : 0
|
||||||
property real desktopButtonWidth: convergenceMode ? root.height : 0
|
property real desktopButtonWidth: convergenceMode ? root.height : 0
|
||||||
|
|
@ -130,15 +128,6 @@ MouseArea {
|
||||||
onTriggered: root.hideDockToolTip(root.activeDockToolTipItem)
|
onTriggered: root.hideDockToolTip(root.activeDockToolTipItem)
|
||||||
}
|
}
|
||||||
|
|
||||||
Timer {
|
|
||||||
id: pagerWheelEndTimer
|
|
||||||
interval: 160
|
|
||||||
onTriggered: {
|
|
||||||
root.pagerWheelDelta = 0
|
|
||||||
root.pagerWheelLocked = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function requestDockToolTip(item) {
|
function requestDockToolTip(item) {
|
||||||
activeDockToolTipItem = null
|
activeDockToolTipItem = null
|
||||||
pendingDockToolTipItem = item
|
pendingDockToolTipItem = item
|
||||||
|
|
@ -203,50 +192,6 @@ MouseArea {
|
||||||
return -1
|
return -1
|
||||||
}
|
}
|
||||||
|
|
||||||
function activateAdjacentDesktop(direction) {
|
|
||||||
let ids = virtualDesktopInfo.desktopIds
|
|
||||||
if (!ids || ids.length <= 1) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
let currentIndex = root.desktopIndexForId(virtualDesktopInfo.currentDesktop)
|
|
||||||
if (currentIndex < 0) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
let targetIndex = Math.max(0, Math.min(ids.length - 1, currentIndex + direction))
|
|
||||||
if (targetIndex !== currentIndex) {
|
|
||||||
root.folio.activateVirtualDesktop(String(ids[targetIndex]))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function handlePagerWheel(wheel) {
|
|
||||||
if (!root.showPager) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
const axisDelta = wheel.angleDelta.y || -wheel.angleDelta.x
|
|
||||||
if (axisDelta === 0) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
pagerWheelEndTimer.restart()
|
|
||||||
if (root.pagerWheelLocked) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
root.pagerWheelDelta += axisDelta * (wheel.inverted ? -1 : 1)
|
|
||||||
if (root.pagerWheelDelta >= 120) {
|
|
||||||
root.pagerWheelLocked = true
|
|
||||||
root.pagerWheelDelta = 0
|
|
||||||
root.activateAdjacentDesktop(-1)
|
|
||||||
} else if (root.pagerWheelDelta <= -120) {
|
|
||||||
root.pagerWheelLocked = true
|
|
||||||
root.pagerWheelDelta = 0
|
|
||||||
root.activateAdjacentDesktop(1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function dynamicTilingMoveToDesktopAction(desktopId) {
|
function dynamicTilingMoveToDesktopAction(desktopId) {
|
||||||
let index = root.desktopIndexForId(desktopId)
|
let index = root.desktopIndexForId(desktopId)
|
||||||
if (index < 0) {
|
if (index < 0) {
|
||||||
|
|
@ -740,7 +685,6 @@ MouseArea {
|
||||||
hoverEnabled: true
|
hoverEnabled: true
|
||||||
acceptedButtons: Qt.LeftButton | Qt.RightButton
|
acceptedButtons: Qt.LeftButton | Qt.RightButton
|
||||||
cursorShape: Qt.PointingHandCursor
|
cursorShape: Qt.PointingHandCursor
|
||||||
onWheel: (wheel) => root.handlePagerWheel(wheel)
|
|
||||||
onClicked: (mouse) => {
|
onClicked: (mouse) => {
|
||||||
root.hideDockToolTip(leftDesktopBtn)
|
root.hideDockToolTip(leftDesktopBtn)
|
||||||
if (mouse.button === Qt.RightButton) {
|
if (mouse.button === Qt.RightButton) {
|
||||||
|
|
@ -850,7 +794,6 @@ MouseArea {
|
||||||
hoverEnabled: true
|
hoverEnabled: true
|
||||||
acceptedButtons: Qt.LeftButton | Qt.RightButton
|
acceptedButtons: Qt.LeftButton | Qt.RightButton
|
||||||
cursorShape: Qt.PointingHandCursor
|
cursorShape: Qt.PointingHandCursor
|
||||||
onWheel: (wheel) => root.handlePagerWheel(wheel)
|
|
||||||
onClicked: (mouse) => {
|
onClicked: (mouse) => {
|
||||||
root.hideDockToolTip(rightDesktopBtn)
|
root.hideDockToolTip(rightDesktopBtn)
|
||||||
if (mouse.button === Qt.RightButton) {
|
if (mouse.button === Qt.RightButton) {
|
||||||
|
|
|
||||||
|
|
@ -188,21 +188,9 @@ Item {
|
||||||
homeScreenState.swipeMoved(totalDeltaX, totalDeltaY, deltaX, deltaY);
|
homeScreenState.swipeMoved(totalDeltaX, totalDeltaY, deltaX, deltaY);
|
||||||
}
|
}
|
||||||
|
|
||||||
onTouchpadScrollStarted: {
|
onTouchpadScrollStarted: homeScreenState.swipeStarted(0, 0);
|
||||||
if (!ShellSettings.Settings.convergenceModeEnabled) {
|
onTouchpadScrollEnded: homeScreenState.swipeEnded();
|
||||||
root.homeScreenState.swipeStarted(0, 0);
|
onTouchpadScrollMove: (totalDeltaX, totalDeltaY, deltaX, deltaY) => homeScreenState.swipeMoved(totalDeltaX, totalDeltaY, deltaX, deltaY);
|
||||||
}
|
|
||||||
}
|
|
||||||
onTouchpadScrollEnded: {
|
|
||||||
if (!ShellSettings.Settings.convergenceModeEnabled) {
|
|
||||||
root.homeScreenState.swipeEnded();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
onTouchpadScrollMove: (totalDeltaX, totalDeltaY, deltaX, deltaY) => {
|
|
||||||
if (!ShellSettings.Settings.convergenceModeEnabled) {
|
|
||||||
root.homeScreenState.swipeMoved(totalDeltaX, totalDeltaY, deltaX, deltaY);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
onPressedChanged: {
|
onPressedChanged: {
|
||||||
if (pressed) {
|
if (pressed) {
|
||||||
|
|
|
||||||
|
|
@ -305,43 +305,6 @@ ContainmentItem {
|
||||||
readonly property real workAreaY: topBarHitHeight
|
readonly property real workAreaY: topBarHitHeight
|
||||||
readonly property real workAreaWidth: Math.max(0, width - frameThickness * 2)
|
readonly property real workAreaWidth: Math.max(0, width - frameThickness * 2)
|
||||||
readonly property real workAreaHeight: Math.max(0, height - topBarHeight - dockHeight - frameThickness * 2)
|
readonly property real workAreaHeight: Math.max(0, height - topBarHeight - dockHeight - frameThickness * 2)
|
||||||
readonly property real leftEdgeHotzoneWidth: Math.max(frameThickness, Math.round(Kirigami.Units.gridUnit * 0.7))
|
|
||||||
readonly property real rightEdgeHotzoneWidth: leftEdgeHotzoneWidth
|
|
||||||
readonly property real leftLauncherWidth: Math.min(Kirigami.Units.gridUnit * 22, width * 0.42)
|
|
||||||
readonly property real leftLauncherHeight: Math.min(Kirigami.Units.gridUnit * 16, workAreaHeight * 0.66)
|
|
||||||
readonly property bool leftLauncherEnabled: root.folio.HomeScreenState.appDrawerOpenProgress <= 0
|
|
||||||
readonly property real layoutMenuWidth: Math.min(Kirigami.Units.gridUnit * 16, width * 0.34)
|
|
||||||
readonly property int layoutMenuWindowCount: Math.max(0, ShellSettings.Settings.dynamicTilingLayoutWindowCount)
|
|
||||||
readonly property bool layoutMenuEnabled: ShellSettings.Settings.dynamicTilingEnabled
|
|
||||||
&& layoutMenuWindowCount >= 2
|
|
||||||
&& root.folio.HomeScreenState.appDrawerOpenProgress <= 0
|
|
||||||
readonly property real leftFrameBulgeIdleDepth: Math.max(frameThickness * 0.45, Kirigami.Units.gridUnit * 0.16)
|
|
||||||
readonly property real leftFrameBulgeHoverDepth: 0
|
|
||||||
property real leftFrameBulgeDepth: !leftLauncherEnabled || leftLauncherOpen || leftEdgeHovered
|
|
||||||
? leftFrameBulgeHoverDepth
|
|
||||||
: leftFrameBulgeIdleDepth
|
|
||||||
property real rightFrameBulgeDepth: !layoutMenuEnabled || layoutMenuOpen || rightEdgeHovered
|
|
||||||
? leftFrameBulgeHoverDepth
|
|
||||||
: leftFrameBulgeIdleDepth
|
|
||||||
// Long, thin thickening of the lower-left workspace wall. Vertical
|
|
||||||
// tangents at all three anchors keep the curve smooth as it blends
|
|
||||||
// into the straight wall above and below.
|
|
||||||
readonly property real leftFrameBulgeEffectiveDepth: Math.max(leftFrameBulgeDepth, 0.01)
|
|
||||||
readonly property real leftFrameBulgeApexX: workAreaX + leftFrameBulgeEffectiveDepth
|
|
||||||
readonly property real leftFrameBulgeHalfLength: Kirigami.Units.gridUnit * 7.5
|
|
||||||
readonly property real leftFrameBulgeApexY: workAreaY + workAreaHeight * 0.7
|
|
||||||
readonly property real leftFrameBulgeEdgeTopY: leftFrameBulgeApexY - leftFrameBulgeHalfLength
|
|
||||||
readonly property real leftFrameBulgeEdgeBottomY: leftFrameBulgeApexY + leftFrameBulgeHalfLength
|
|
||||||
// Bezier control-handle length along the vertical tangent at each
|
|
||||||
// anchor. ~0.55 of the half-length gives a clean, taut oval profile.
|
|
||||||
readonly property real leftFrameBulgeTangent: leftFrameBulgeHalfLength * 0.55
|
|
||||||
readonly property real rightFrameBulgeEffectiveDepth: Math.max(rightFrameBulgeDepth, 0.01)
|
|
||||||
readonly property real rightFrameBulgeApexX: workAreaX + workAreaWidth - rightFrameBulgeEffectiveDepth
|
|
||||||
readonly property real rightFrameBulgeHalfLength: leftFrameBulgeHalfLength
|
|
||||||
readonly property real rightFrameBulgeApexY: leftFrameBulgeApexY
|
|
||||||
readonly property real rightFrameBulgeEdgeTopY: rightFrameBulgeApexY - rightFrameBulgeHalfLength
|
|
||||||
readonly property real rightFrameBulgeEdgeBottomY: rightFrameBulgeApexY + rightFrameBulgeHalfLength
|
|
||||||
readonly property real rightFrameBulgeTangent: rightFrameBulgeHalfLength * 0.55
|
|
||||||
readonly property color chromeColor: Kirigami.Theme.backgroundColor
|
readonly property color chromeColor: Kirigami.Theme.backgroundColor
|
||||||
readonly property color edgeColor: Qt.rgba(Kirigami.Theme.textColor.r, Kirigami.Theme.textColor.g, Kirigami.Theme.textColor.b, 0.1)
|
readonly property color edgeColor: Qt.rgba(Kirigami.Theme.textColor.r, Kirigami.Theme.textColor.g, Kirigami.Theme.textColor.b, 0.1)
|
||||||
readonly property int dockAnimationDuration: MobileShell.Motion.duration(MobileShell.Motion.SpatialDefault)
|
readonly property int dockAnimationDuration: MobileShell.Motion.duration(MobileShell.Motion.SpatialDefault)
|
||||||
|
|
@ -352,12 +315,6 @@ ContainmentItem {
|
||||||
|
|
||||||
// True once the hover-reveal timer fires; cleared on hover-exit.
|
// True once the hover-reveal timer fires; cleared on hover-exit.
|
||||||
property bool hoverRevealing: false
|
property bool hoverRevealing: false
|
||||||
property bool leftEdgeHovered: false
|
|
||||||
property bool leftLauncherHovered: false
|
|
||||||
property bool leftLauncherOpen: false
|
|
||||||
property bool rightEdgeHovered: false
|
|
||||||
property bool layoutMenuHovered: false
|
|
||||||
property bool layoutMenuOpen: false
|
|
||||||
|
|
||||||
readonly property bool shouldHide: ShellSettings.Settings.autoHidePanelsEnabled
|
readonly property bool shouldHide: ShellSettings.Settings.autoHidePanelsEnabled
|
||||||
&& windowMaximizedTracker.showingWindow && !hoverRevealing
|
&& windowMaximizedTracker.showingWindow && !hoverRevealing
|
||||||
|
|
@ -367,87 +324,17 @@ ContainmentItem {
|
||||||
|
|
||||||
function updateInputRegion() {
|
function updateInputRegion() {
|
||||||
const topBarRegion = Qt.rect(0, 0, width, topBarHitHeight)
|
const topBarRegion = Qt.rect(0, 0, width, topBarHitHeight)
|
||||||
const leftEdgeRegion = Qt.rect(0, topBarHitHeight, leftEdgeHotzoneWidth, Math.max(0, height - topBarHitHeight - dockHeight))
|
|
||||||
const rightEdgeRegion = Qt.rect(width - rightEdgeHotzoneWidth, topBarHitHeight, rightEdgeHotzoneWidth, Math.max(0, height - topBarHitHeight - dockHeight))
|
|
||||||
const leftLauncherRegion = Qt.rect(0,
|
|
||||||
Math.max(0, height - dockHeight - leftLauncherHeight),
|
|
||||||
leftLauncherWidth,
|
|
||||||
leftLauncherHeight)
|
|
||||||
const layoutMenuRegion = Qt.rect(rightLayoutMenu.x,
|
|
||||||
rightLayoutMenu.y,
|
|
||||||
rightLayoutMenu.width,
|
|
||||||
rightLayoutMenu.height)
|
|
||||||
let regions = [topBarRegion, leftEdgeRegion]
|
|
||||||
|
|
||||||
if (layoutMenuEnabled) {
|
|
||||||
regions.push(rightEdgeRegion)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (shouldHide && dockOffset >= dockHeight) {
|
if (shouldHide && dockOffset >= dockHeight) {
|
||||||
regions.push(Qt.rect(0, height - revealStripHeight, width, revealStripHeight))
|
MobileShell.ShellUtil.setInputRegions(convergenceChrome, [
|
||||||
|
topBarRegion,
|
||||||
|
Qt.rect(0, height - revealStripHeight, width, revealStripHeight)
|
||||||
|
])
|
||||||
} else {
|
} else {
|
||||||
regions.push(Qt.rect(0, height - dockHeight, width, dockHeight))
|
MobileShell.ShellUtil.setInputRegions(convergenceChrome, [
|
||||||
|
topBarRegion,
|
||||||
|
Qt.rect(0, height - dockHeight, width, dockHeight)
|
||||||
|
])
|
||||||
}
|
}
|
||||||
|
|
||||||
if (leftLauncherOpen) {
|
|
||||||
regions.push(leftLauncherRegion)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (layoutMenuEnabled && layoutMenuOpen) {
|
|
||||||
regions.push(layoutMenuRegion)
|
|
||||||
}
|
|
||||||
|
|
||||||
MobileShell.ShellUtil.setInputRegions(convergenceChrome, regions)
|
|
||||||
}
|
|
||||||
|
|
||||||
function launchStorageId(storageId) {
|
|
||||||
if (!storageId || String(storageId).length === 0) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
var normalizedId = String(storageId)
|
|
||||||
if (!normalizedId.endsWith(".desktop")) {
|
|
||||||
normalizedId += ".desktop"
|
|
||||||
}
|
|
||||||
MobileShell.AppLaunch.launchOrActivateApp(normalizedId)
|
|
||||||
}
|
|
||||||
|
|
||||||
function refreshLeftLauncherVisibility() {
|
|
||||||
if (!leftLauncherEnabled) {
|
|
||||||
leftLauncherCloseTimer.stop()
|
|
||||||
leftEdgeHovered = false
|
|
||||||
leftLauncherHovered = false
|
|
||||||
leftLauncherOpen = false
|
|
||||||
inputRegionTimer.restart()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if (leftEdgeHovered || leftLauncherHovered) {
|
|
||||||
leftLauncherCloseTimer.stop()
|
|
||||||
leftLauncherOpen = true
|
|
||||||
} else {
|
|
||||||
leftLauncherCloseTimer.restart()
|
|
||||||
}
|
|
||||||
inputRegionTimer.restart()
|
|
||||||
}
|
|
||||||
|
|
||||||
function refreshLayoutMenuVisibility() {
|
|
||||||
if (!layoutMenuEnabled) {
|
|
||||||
layoutMenuCloseTimer.stop()
|
|
||||||
rightEdgeHovered = false
|
|
||||||
layoutMenuHovered = false
|
|
||||||
layoutMenuOpen = false
|
|
||||||
inputRegionTimer.restart()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if (rightEdgeHovered || layoutMenuHovered) {
|
|
||||||
layoutMenuCloseTimer.stop()
|
|
||||||
layoutMenuOpen = true
|
|
||||||
} else {
|
|
||||||
layoutMenuCloseTimer.restart()
|
|
||||||
}
|
|
||||||
inputRegionTimer.restart()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onActiveChanged: {
|
onActiveChanged: {
|
||||||
|
|
@ -466,8 +353,6 @@ ContainmentItem {
|
||||||
}
|
}
|
||||||
inputRegionTimer.restart()
|
inputRegionTimer.restart()
|
||||||
}
|
}
|
||||||
onLeftLauncherEnabledChanged: refreshLeftLauncherVisibility()
|
|
||||||
onLayoutMenuEnabledChanged: refreshLayoutMenuVisibility()
|
|
||||||
|
|
||||||
// Narrow the input region to a strip at the screen edge when hidden
|
// Narrow the input region to a strip at the screen edge when hidden
|
||||||
// so that app controls near the bottom edge are not accidentally
|
// so that app controls near the bottom edge are not accidentally
|
||||||
|
|
@ -500,34 +385,6 @@ ContainmentItem {
|
||||||
onTriggered: convergenceChrome.hoverRevealing = true
|
onTriggered: convergenceChrome.hoverRevealing = true
|
||||||
}
|
}
|
||||||
|
|
||||||
Timer {
|
|
||||||
id: leftLauncherCloseTimer
|
|
||||||
interval: Kirigami.Units.shortDuration
|
|
||||||
repeat: false
|
|
||||||
onTriggered: {
|
|
||||||
if (!convergenceChrome.leftEdgeHovered
|
|
||||||
&& !convergenceChrome.leftLauncherHovered
|
|
||||||
&& convergenceChrome.leftLauncherOpen) {
|
|
||||||
convergenceChrome.leftLauncherOpen = false
|
|
||||||
inputRegionTimer.restart()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Timer {
|
|
||||||
id: layoutMenuCloseTimer
|
|
||||||
interval: Kirigami.Units.shortDuration
|
|
||||||
repeat: false
|
|
||||||
onTriggered: {
|
|
||||||
if (!convergenceChrome.rightEdgeHovered
|
|
||||||
&& !convergenceChrome.layoutMenuHovered
|
|
||||||
&& convergenceChrome.layoutMenuOpen) {
|
|
||||||
convergenceChrome.layoutMenuOpen = false
|
|
||||||
inputRegionTimer.restart()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Behavior on dockOffset {
|
Behavior on dockOffset {
|
||||||
MobileShell.MotionNumberAnimation {
|
MobileShell.MotionNumberAnimation {
|
||||||
type: MobileShell.Motion.SpatialDefault
|
type: MobileShell.Motion.SpatialDefault
|
||||||
|
|
@ -535,20 +392,6 @@ ContainmentItem {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Behavior on leftFrameBulgeDepth {
|
|
||||||
MobileShell.MotionNumberAnimation {
|
|
||||||
type: MobileShell.Motion.SpatialDefault
|
|
||||||
duration: root.shortAnimationDuration
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Behavior on rightFrameBulgeDepth {
|
|
||||||
MobileShell.MotionNumberAnimation {
|
|
||||||
type: MobileShell.Motion.SpatialDefault
|
|
||||||
duration: root.shortAnimationDuration
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
id: topBarSurface
|
id: topBarSurface
|
||||||
anchors.top: parent.top
|
anchors.top: parent.top
|
||||||
|
|
@ -568,7 +411,6 @@ ContainmentItem {
|
||||||
Shape {
|
Shape {
|
||||||
id: workspaceFrame
|
id: workspaceFrame
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
preferredRendererType: Shape.CurveRenderer
|
|
||||||
|
|
||||||
ShapePath {
|
ShapePath {
|
||||||
fillColor: convergenceChrome.chromeColor
|
fillColor: convergenceChrome.chromeColor
|
||||||
|
|
@ -585,125 +427,24 @@ ContainmentItem {
|
||||||
PathMove { x: convergenceChrome.workAreaX + convergenceChrome.frameRadius; y: convergenceChrome.workAreaY }
|
PathMove { x: convergenceChrome.workAreaX + convergenceChrome.frameRadius; y: convergenceChrome.workAreaY }
|
||||||
PathLine { x: convergenceChrome.workAreaX + convergenceChrome.workAreaWidth - convergenceChrome.frameRadius; y: convergenceChrome.workAreaY }
|
PathLine { x: convergenceChrome.workAreaX + convergenceChrome.workAreaWidth - convergenceChrome.frameRadius; y: convergenceChrome.workAreaY }
|
||||||
PathArc { x: convergenceChrome.workAreaX + convergenceChrome.workAreaWidth; y: convergenceChrome.workAreaY + convergenceChrome.frameRadius; radiusX: convergenceChrome.frameRadius; radiusY: convergenceChrome.frameRadius }
|
PathArc { x: convergenceChrome.workAreaX + convergenceChrome.workAreaWidth; y: convergenceChrome.workAreaY + convergenceChrome.frameRadius; radiusX: convergenceChrome.frameRadius; radiusY: convergenceChrome.frameRadius }
|
||||||
PathLine { x: convergenceChrome.workAreaX + convergenceChrome.workAreaWidth; y: convergenceChrome.rightFrameBulgeEdgeTopY }
|
|
||||||
PathCubic {
|
|
||||||
x: convergenceChrome.rightFrameBulgeApexX
|
|
||||||
y: convergenceChrome.rightFrameBulgeApexY
|
|
||||||
control1X: convergenceChrome.workAreaX + convergenceChrome.workAreaWidth
|
|
||||||
control1Y: convergenceChrome.rightFrameBulgeEdgeTopY + convergenceChrome.rightFrameBulgeTangent
|
|
||||||
control2X: convergenceChrome.rightFrameBulgeApexX
|
|
||||||
control2Y: convergenceChrome.rightFrameBulgeApexY - convergenceChrome.rightFrameBulgeTangent
|
|
||||||
}
|
|
||||||
PathCubic {
|
|
||||||
x: convergenceChrome.workAreaX + convergenceChrome.workAreaWidth
|
|
||||||
y: convergenceChrome.rightFrameBulgeEdgeBottomY
|
|
||||||
control1X: convergenceChrome.rightFrameBulgeApexX
|
|
||||||
control1Y: convergenceChrome.rightFrameBulgeApexY + convergenceChrome.rightFrameBulgeTangent
|
|
||||||
control2X: convergenceChrome.workAreaX + convergenceChrome.workAreaWidth
|
|
||||||
control2Y: convergenceChrome.rightFrameBulgeEdgeBottomY - convergenceChrome.rightFrameBulgeTangent
|
|
||||||
}
|
|
||||||
PathLine { x: convergenceChrome.workAreaX + convergenceChrome.workAreaWidth; y: convergenceChrome.workAreaY + convergenceChrome.workAreaHeight - convergenceChrome.frameRadius }
|
PathLine { x: convergenceChrome.workAreaX + convergenceChrome.workAreaWidth; y: convergenceChrome.workAreaY + convergenceChrome.workAreaHeight - convergenceChrome.frameRadius }
|
||||||
PathArc { x: convergenceChrome.workAreaX + convergenceChrome.workAreaWidth - convergenceChrome.frameRadius; y: convergenceChrome.workAreaY + convergenceChrome.workAreaHeight; radiusX: convergenceChrome.frameRadius; radiusY: convergenceChrome.frameRadius }
|
PathArc { x: convergenceChrome.workAreaX + convergenceChrome.workAreaWidth - convergenceChrome.frameRadius; y: convergenceChrome.workAreaY + convergenceChrome.workAreaHeight; radiusX: convergenceChrome.frameRadius; radiusY: convergenceChrome.frameRadius }
|
||||||
PathLine { x: convergenceChrome.workAreaX + convergenceChrome.frameRadius; y: convergenceChrome.workAreaY + convergenceChrome.workAreaHeight }
|
PathLine { x: convergenceChrome.workAreaX + convergenceChrome.frameRadius; y: convergenceChrome.workAreaY + convergenceChrome.workAreaHeight }
|
||||||
PathArc { x: convergenceChrome.workAreaX; y: convergenceChrome.workAreaY + convergenceChrome.workAreaHeight - convergenceChrome.frameRadius; radiusX: convergenceChrome.frameRadius; radiusY: convergenceChrome.frameRadius }
|
PathArc { x: convergenceChrome.workAreaX; y: convergenceChrome.workAreaY + convergenceChrome.workAreaHeight - convergenceChrome.frameRadius; radiusX: convergenceChrome.frameRadius; radiusY: convergenceChrome.frameRadius }
|
||||||
PathLine { x: convergenceChrome.workAreaX; y: convergenceChrome.leftFrameBulgeEdgeBottomY }
|
|
||||||
PathCubic {
|
|
||||||
x: convergenceChrome.leftFrameBulgeApexX
|
|
||||||
y: convergenceChrome.leftFrameBulgeApexY
|
|
||||||
control1X: convergenceChrome.workAreaX
|
|
||||||
control1Y: convergenceChrome.leftFrameBulgeEdgeBottomY - convergenceChrome.leftFrameBulgeTangent
|
|
||||||
control2X: convergenceChrome.leftFrameBulgeApexX
|
|
||||||
control2Y: convergenceChrome.leftFrameBulgeApexY + convergenceChrome.leftFrameBulgeTangent
|
|
||||||
}
|
|
||||||
PathCubic {
|
|
||||||
x: convergenceChrome.workAreaX
|
|
||||||
y: convergenceChrome.leftFrameBulgeEdgeTopY
|
|
||||||
control1X: convergenceChrome.leftFrameBulgeApexX
|
|
||||||
control1Y: convergenceChrome.leftFrameBulgeApexY - convergenceChrome.leftFrameBulgeTangent
|
|
||||||
control2X: convergenceChrome.workAreaX
|
|
||||||
control2Y: convergenceChrome.leftFrameBulgeEdgeTopY + convergenceChrome.leftFrameBulgeTangent
|
|
||||||
}
|
|
||||||
PathLine { x: convergenceChrome.workAreaX; y: convergenceChrome.workAreaY + convergenceChrome.frameRadius }
|
PathLine { x: convergenceChrome.workAreaX; y: convergenceChrome.workAreaY + convergenceChrome.frameRadius }
|
||||||
PathArc { x: convergenceChrome.workAreaX + convergenceChrome.frameRadius; y: convergenceChrome.workAreaY; radiusX: convergenceChrome.frameRadius; radiusY: convergenceChrome.frameRadius }
|
PathArc { x: convergenceChrome.workAreaX + convergenceChrome.frameRadius; y: convergenceChrome.workAreaY; radiusX: convergenceChrome.frameRadius; radiusY: convergenceChrome.frameRadius }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Shape {
|
Rectangle {
|
||||||
id: workspaceFrameBorder
|
|
||||||
anchors.fill: parent
|
|
||||||
preferredRendererType: Shape.CurveRenderer
|
|
||||||
|
|
||||||
ShapePath {
|
|
||||||
fillColor: "transparent"
|
|
||||||
strokeColor: convergenceChrome.edgeColor
|
|
||||||
strokeWidth: 0.85
|
|
||||||
joinStyle: ShapePath.RoundJoin
|
|
||||||
|
|
||||||
startX: convergenceChrome.workAreaX + convergenceChrome.frameRadius
|
|
||||||
startY: convergenceChrome.workAreaY
|
|
||||||
PathLine { x: convergenceChrome.workAreaX + convergenceChrome.workAreaWidth - convergenceChrome.frameRadius; y: convergenceChrome.workAreaY }
|
|
||||||
PathQuad {
|
|
||||||
x: convergenceChrome.workAreaX + convergenceChrome.workAreaWidth
|
|
||||||
y: convergenceChrome.workAreaY + convergenceChrome.frameRadius
|
|
||||||
controlX: convergenceChrome.workAreaX + convergenceChrome.workAreaWidth
|
|
||||||
controlY: convergenceChrome.workAreaY
|
|
||||||
}
|
|
||||||
PathLine { x: convergenceChrome.workAreaX + convergenceChrome.workAreaWidth; y: convergenceChrome.rightFrameBulgeEdgeTopY }
|
|
||||||
PathCubic {
|
|
||||||
x: convergenceChrome.rightFrameBulgeApexX
|
|
||||||
y: convergenceChrome.rightFrameBulgeApexY
|
|
||||||
control1X: convergenceChrome.workAreaX + convergenceChrome.workAreaWidth
|
|
||||||
control1Y: convergenceChrome.rightFrameBulgeEdgeTopY + convergenceChrome.rightFrameBulgeTangent
|
|
||||||
control2X: convergenceChrome.rightFrameBulgeApexX
|
|
||||||
control2Y: convergenceChrome.rightFrameBulgeApexY - convergenceChrome.rightFrameBulgeTangent
|
|
||||||
}
|
|
||||||
PathCubic {
|
|
||||||
x: convergenceChrome.workAreaX + convergenceChrome.workAreaWidth
|
|
||||||
y: convergenceChrome.rightFrameBulgeEdgeBottomY
|
|
||||||
control1X: convergenceChrome.rightFrameBulgeApexX
|
|
||||||
control1Y: convergenceChrome.rightFrameBulgeApexY + convergenceChrome.rightFrameBulgeTangent
|
|
||||||
control2X: convergenceChrome.workAreaX + convergenceChrome.workAreaWidth
|
|
||||||
control2Y: convergenceChrome.rightFrameBulgeEdgeBottomY - convergenceChrome.rightFrameBulgeTangent
|
|
||||||
}
|
|
||||||
PathLine { x: convergenceChrome.workAreaX + convergenceChrome.workAreaWidth; y: convergenceChrome.workAreaY + convergenceChrome.workAreaHeight - convergenceChrome.frameRadius }
|
|
||||||
PathQuad {
|
|
||||||
x: convergenceChrome.workAreaX + convergenceChrome.workAreaWidth - convergenceChrome.frameRadius
|
|
||||||
y: convergenceChrome.workAreaY + convergenceChrome.workAreaHeight
|
|
||||||
controlX: convergenceChrome.workAreaX + convergenceChrome.workAreaWidth
|
|
||||||
controlY: convergenceChrome.workAreaY + convergenceChrome.workAreaHeight
|
|
||||||
}
|
|
||||||
PathLine { x: convergenceChrome.workAreaX + convergenceChrome.frameRadius; y: convergenceChrome.workAreaY + convergenceChrome.workAreaHeight }
|
|
||||||
PathQuad {
|
|
||||||
x: convergenceChrome.workAreaX
|
x: convergenceChrome.workAreaX
|
||||||
y: convergenceChrome.workAreaY + convergenceChrome.workAreaHeight - convergenceChrome.frameRadius
|
|
||||||
controlX: convergenceChrome.workAreaX
|
|
||||||
controlY: convergenceChrome.workAreaY + convergenceChrome.workAreaHeight
|
|
||||||
}
|
|
||||||
PathLine { x: convergenceChrome.workAreaX; y: convergenceChrome.leftFrameBulgeEdgeBottomY }
|
|
||||||
PathCubic {
|
|
||||||
x: convergenceChrome.leftFrameBulgeApexX
|
|
||||||
y: convergenceChrome.leftFrameBulgeApexY
|
|
||||||
control1X: convergenceChrome.workAreaX
|
|
||||||
control1Y: convergenceChrome.leftFrameBulgeEdgeBottomY - convergenceChrome.leftFrameBulgeTangent
|
|
||||||
control2X: convergenceChrome.leftFrameBulgeApexX
|
|
||||||
control2Y: convergenceChrome.leftFrameBulgeApexY + convergenceChrome.leftFrameBulgeTangent
|
|
||||||
}
|
|
||||||
PathCubic {
|
|
||||||
x: convergenceChrome.workAreaX
|
|
||||||
y: convergenceChrome.leftFrameBulgeEdgeTopY
|
|
||||||
control1X: convergenceChrome.leftFrameBulgeApexX
|
|
||||||
control1Y: convergenceChrome.leftFrameBulgeApexY - convergenceChrome.leftFrameBulgeTangent
|
|
||||||
control2X: convergenceChrome.workAreaX
|
|
||||||
control2Y: convergenceChrome.leftFrameBulgeEdgeTopY + convergenceChrome.leftFrameBulgeTangent
|
|
||||||
}
|
|
||||||
PathLine { x: convergenceChrome.workAreaX; y: convergenceChrome.workAreaY + convergenceChrome.frameRadius }
|
|
||||||
PathQuad {
|
|
||||||
x: convergenceChrome.workAreaX + convergenceChrome.frameRadius
|
|
||||||
y: convergenceChrome.workAreaY
|
y: convergenceChrome.workAreaY
|
||||||
controlX: convergenceChrome.workAreaX
|
width: convergenceChrome.workAreaWidth
|
||||||
controlY: convergenceChrome.workAreaY
|
height: convergenceChrome.workAreaHeight
|
||||||
}
|
radius: convergenceChrome.frameRadius
|
||||||
}
|
color: "transparent"
|
||||||
|
border.width: 1
|
||||||
|
border.color: convergenceChrome.edgeColor
|
||||||
}
|
}
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
|
|
@ -747,307 +488,6 @@ ContainmentItem {
|
||||||
Kirigami.Theme.colorSet: Kirigami.Theme.Window
|
Kirigami.Theme.colorSet: Kirigami.Theme.Window
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Item {
|
|
||||||
id: leftEdgeStrip
|
|
||||||
|
|
||||||
anchors.left: parent.left
|
|
||||||
anchors.top: topBarSurface.bottom
|
|
||||||
anchors.bottom: dockSurface.top
|
|
||||||
width: convergenceChrome.leftEdgeHotzoneWidth
|
|
||||||
|
|
||||||
MouseArea {
|
|
||||||
id: leftEdgeHoverArea
|
|
||||||
anchors.fill: parent
|
|
||||||
acceptedButtons: Qt.NoButton
|
|
||||||
enabled: convergenceChrome.leftLauncherEnabled
|
|
||||||
hoverEnabled: enabled
|
|
||||||
cursorShape: enabled ? Qt.PointingHandCursor : Qt.ArrowCursor
|
|
||||||
|
|
||||||
onContainsMouseChanged: {
|
|
||||||
convergenceChrome.leftEdgeHovered = containsMouse
|
|
||||||
convergenceChrome.refreshLeftLauncherVisibility()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Item {
|
|
||||||
id: rightEdgeStrip
|
|
||||||
|
|
||||||
anchors.right: parent.right
|
|
||||||
anchors.top: topBarSurface.bottom
|
|
||||||
anchors.bottom: dockSurface.top
|
|
||||||
width: convergenceChrome.layoutMenuEnabled ? convergenceChrome.rightEdgeHotzoneWidth : 0
|
|
||||||
|
|
||||||
MouseArea {
|
|
||||||
id: rightEdgeHoverArea
|
|
||||||
anchors.fill: parent
|
|
||||||
acceptedButtons: Qt.NoButton
|
|
||||||
enabled: convergenceChrome.layoutMenuEnabled
|
|
||||||
hoverEnabled: enabled
|
|
||||||
cursorShape: enabled ? Qt.PointingHandCursor : Qt.ArrowCursor
|
|
||||||
|
|
||||||
onContainsMouseChanged: {
|
|
||||||
convergenceChrome.rightEdgeHovered = containsMouse
|
|
||||||
convergenceChrome.refreshLayoutMenuVisibility()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
DynamicTilingLayoutMenu {
|
|
||||||
id: rightLayoutMenu
|
|
||||||
|
|
||||||
width: convergenceChrome.layoutMenuWidth
|
|
||||||
height: preferredHeight
|
|
||||||
x: convergenceChrome.width - width
|
|
||||||
y: convergenceChrome.height - convergenceChrome.dockHeight - height
|
|
||||||
visible: convergenceChrome.layoutMenuOpen
|
|
||||||
opacity: convergenceChrome.layoutMenuOpen ? 1 : 0
|
|
||||||
maxHeight: convergenceChrome.workAreaHeight * 0.5
|
|
||||||
windowCount: convergenceChrome.layoutMenuWindowCount
|
|
||||||
currentMode: ShellSettings.Settings.dynamicTilingLayoutMode
|
|
||||||
surfaceColor: convergenceChrome.chromeColor
|
|
||||||
animationDuration: root.shortAnimationDuration
|
|
||||||
|
|
||||||
HoverHandler {
|
|
||||||
enabled: convergenceChrome.layoutMenuOpen
|
|
||||||
|
|
||||||
onHoveredChanged: {
|
|
||||||
convergenceChrome.layoutMenuHovered = hovered
|
|
||||||
convergenceChrome.refreshLayoutMenuVisibility()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
transform: Translate {
|
|
||||||
y: convergenceChrome.layoutMenuOpen ? 0 : Kirigami.Units.gridUnit
|
|
||||||
x: convergenceChrome.layoutMenuOpen ? 0 : rightLayoutMenu.width - convergenceChrome.rightEdgeHotzoneWidth
|
|
||||||
}
|
|
||||||
|
|
||||||
onLayoutModeRequested: (mode) => {
|
|
||||||
if (ShellSettings.Settings.requestDynamicTilingLayoutMode !== undefined) {
|
|
||||||
ShellSettings.Settings.requestDynamicTilingLayoutMode(mode)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
onDismissRequested: {
|
|
||||||
convergenceChrome.layoutMenuOpen = false
|
|
||||||
inputRegionTimer.restart()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Item {
|
|
||||||
id: leftEdgeLauncher
|
|
||||||
|
|
||||||
width: convergenceChrome.leftLauncherWidth
|
|
||||||
height: convergenceChrome.leftLauncherHeight
|
|
||||||
x: 0
|
|
||||||
y: convergenceChrome.height - convergenceChrome.dockHeight - height
|
|
||||||
visible: convergenceChrome.leftLauncherOpen
|
|
||||||
opacity: convergenceChrome.leftLauncherOpen ? 1 : 0
|
|
||||||
clip: true
|
|
||||||
|
|
||||||
transform: Translate {
|
|
||||||
y: convergenceChrome.leftLauncherOpen ? 0 : Kirigami.Units.gridUnit
|
|
||||||
x: convergenceChrome.leftLauncherOpen ? 0 : -leftEdgeLauncher.width + convergenceChrome.leftEdgeHotzoneWidth
|
|
||||||
}
|
|
||||||
|
|
||||||
Behavior on opacity {
|
|
||||||
MobileShell.MotionNumberAnimation {
|
|
||||||
type: MobileShell.Motion.EffectsFast
|
|
||||||
duration: root.shortAnimationDuration
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
readonly property real cornerRadius: Math.min(MobileShell.Constants.convergenceWorkspaceFrameRadius, height * 0.24)
|
|
||||||
|
|
||||||
HoverHandler {
|
|
||||||
enabled: convergenceChrome.leftLauncherOpen
|
|
||||||
|
|
||||||
onHoveredChanged: {
|
|
||||||
convergenceChrome.leftLauncherHovered = hovered
|
|
||||||
convergenceChrome.refreshLeftLauncherVisibility()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Shape {
|
|
||||||
id: leftLauncherSurface
|
|
||||||
anchors.fill: parent
|
|
||||||
|
|
||||||
ShapePath {
|
|
||||||
fillColor: convergenceChrome.chromeColor
|
|
||||||
strokeWidth: 0
|
|
||||||
|
|
||||||
startX: 0
|
|
||||||
startY: 0
|
|
||||||
PathLine { x: leftEdgeLauncher.width - leftEdgeLauncher.cornerRadius; y: 0 }
|
|
||||||
PathArc {
|
|
||||||
x: leftEdgeLauncher.width
|
|
||||||
y: leftEdgeLauncher.cornerRadius
|
|
||||||
radiusX: leftEdgeLauncher.cornerRadius
|
|
||||||
radiusY: leftEdgeLauncher.cornerRadius
|
|
||||||
}
|
|
||||||
PathLine { x: leftEdgeLauncher.width; y: leftEdgeLauncher.height }
|
|
||||||
PathLine { x: 0; y: leftEdgeLauncher.height }
|
|
||||||
PathLine { x: 0; y: 0 }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
MouseArea {
|
|
||||||
anchors.fill: parent
|
|
||||||
hoverEnabled: true
|
|
||||||
}
|
|
||||||
|
|
||||||
ColumnLayout {
|
|
||||||
anchors.fill: parent
|
|
||||||
anchors.margins: Kirigami.Units.smallSpacing
|
|
||||||
spacing: Kirigami.Units.gridUnit * 0.65
|
|
||||||
|
|
||||||
ColumnLayout {
|
|
||||||
Layout.fillWidth: true
|
|
||||||
spacing: Kirigami.Units.smallSpacing
|
|
||||||
|
|
||||||
PlasmaComponents.Label {
|
|
||||||
Layout.fillWidth: true
|
|
||||||
text: i18n("Recently Used")
|
|
||||||
font.weight: Font.Medium
|
|
||||||
elide: Text.ElideRight
|
|
||||||
}
|
|
||||||
|
|
||||||
ListView {
|
|
||||||
id: recentAppsList
|
|
||||||
|
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.preferredHeight: Kirigami.Units.gridUnit * 6.8
|
|
||||||
clip: true
|
|
||||||
interactive: false
|
|
||||||
boundsBehavior: Flickable.StopAtBounds
|
|
||||||
model: folio.RecentApplicationsModel
|
|
||||||
|
|
||||||
delegate: MouseArea {
|
|
||||||
required property int index
|
|
||||||
required property var model
|
|
||||||
|
|
||||||
readonly property var delegateObject: model.delegate
|
|
||||||
readonly property var application: delegateObject ? delegateObject.application : null
|
|
||||||
readonly property bool validEntry: index < 5 && application !== null
|
|
||||||
|
|
||||||
width: recentAppsList.width
|
|
||||||
height: validEntry ? Kirigami.Units.gridUnit * 1.35 : 0
|
|
||||||
enabled: validEntry
|
|
||||||
hoverEnabled: validEntry
|
|
||||||
cursorShape: validEntry ? Qt.PointingHandCursor : Qt.ArrowCursor
|
|
||||||
|
|
||||||
onClicked: {
|
|
||||||
if (application) {
|
|
||||||
convergenceChrome.launchStorageId(application.storageId)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Rectangle {
|
|
||||||
anchors.fill: parent
|
|
||||||
radius: Kirigami.Units.cornerRadius
|
|
||||||
color: parent.containsMouse
|
|
||||||
? Qt.rgba(Kirigami.Theme.textColor.r, Kirigami.Theme.textColor.g, Kirigami.Theme.textColor.b, 0.08)
|
|
||||||
: "transparent"
|
|
||||||
}
|
|
||||||
|
|
||||||
RowLayout {
|
|
||||||
anchors.fill: parent
|
|
||||||
anchors.leftMargin: Kirigami.Units.smallSpacing
|
|
||||||
anchors.rightMargin: Kirigami.Units.smallSpacing
|
|
||||||
spacing: Kirigami.Units.smallSpacing
|
|
||||||
|
|
||||||
Kirigami.Icon {
|
|
||||||
Layout.preferredWidth: Kirigami.Units.iconSizes.smallMedium
|
|
||||||
Layout.preferredHeight: Layout.preferredWidth
|
|
||||||
source: application ? application.icon : ""
|
|
||||||
}
|
|
||||||
|
|
||||||
PlasmaComponents.Label {
|
|
||||||
Layout.fillWidth: true
|
|
||||||
text: application ? application.name : ""
|
|
||||||
elide: Text.ElideRight
|
|
||||||
maximumLineCount: 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ColumnLayout {
|
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.fillHeight: true
|
|
||||||
spacing: Kirigami.Units.smallSpacing
|
|
||||||
|
|
||||||
PlasmaComponents.Label {
|
|
||||||
Layout.fillWidth: true
|
|
||||||
text: i18n("Most Used")
|
|
||||||
font.weight: Font.Medium
|
|
||||||
elide: Text.ElideRight
|
|
||||||
}
|
|
||||||
|
|
||||||
ListView {
|
|
||||||
id: favouritesQuickList
|
|
||||||
|
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.fillHeight: true
|
|
||||||
clip: true
|
|
||||||
interactive: false
|
|
||||||
boundsBehavior: Flickable.StopAtBounds
|
|
||||||
model: folio.MostUsedApplicationsModel
|
|
||||||
|
|
||||||
delegate: MouseArea {
|
|
||||||
required property int index
|
|
||||||
required property var model
|
|
||||||
|
|
||||||
readonly property var delegateObject: model.delegate
|
|
||||||
readonly property var application: delegateObject ? delegateObject.application : null
|
|
||||||
readonly property bool validEntry: index < 6 && application !== null
|
|
||||||
|
|
||||||
width: favouritesQuickList.width
|
|
||||||
height: validEntry ? Kirigami.Units.gridUnit * 1.35 : 0
|
|
||||||
enabled: validEntry
|
|
||||||
hoverEnabled: validEntry
|
|
||||||
cursorShape: validEntry ? Qt.PointingHandCursor : Qt.ArrowCursor
|
|
||||||
|
|
||||||
onClicked: {
|
|
||||||
if (application) {
|
|
||||||
convergenceChrome.launchStorageId(application.storageId)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Rectangle {
|
|
||||||
anchors.fill: parent
|
|
||||||
radius: Kirigami.Units.cornerRadius
|
|
||||||
color: parent.containsMouse
|
|
||||||
? Qt.rgba(Kirigami.Theme.textColor.r, Kirigami.Theme.textColor.g, Kirigami.Theme.textColor.b, 0.08)
|
|
||||||
: "transparent"
|
|
||||||
}
|
|
||||||
|
|
||||||
RowLayout {
|
|
||||||
anchors.fill: parent
|
|
||||||
anchors.leftMargin: Kirigami.Units.smallSpacing
|
|
||||||
anchors.rightMargin: Kirigami.Units.smallSpacing
|
|
||||||
spacing: Kirigami.Units.smallSpacing
|
|
||||||
|
|
||||||
Kirigami.Icon {
|
|
||||||
Layout.preferredWidth: Kirigami.Units.iconSizes.smallMedium
|
|
||||||
Layout.preferredHeight: Layout.preferredWidth
|
|
||||||
source: application ? application.icon : ""
|
|
||||||
}
|
|
||||||
|
|
||||||
PlasmaComponents.Label {
|
|
||||||
Layout.fillWidth: true
|
|
||||||
text: application ? application.name : ""
|
|
||||||
elide: Text.ElideRight
|
|
||||||
maximumLineCount: 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// App-drawer overlay — renders the popup drawer above application
|
// App-drawer overlay — renders the popup drawer above application
|
||||||
|
|
|
||||||
|
|
@ -51,10 +51,6 @@ Item {
|
||||||
value: drawer.visible
|
value: drawer.visible
|
||||||
}
|
}
|
||||||
|
|
||||||
TaskManager.VirtualDesktopInfo {
|
|
||||||
id: virtualDesktopInfo
|
|
||||||
}
|
|
||||||
|
|
||||||
//END API implementation
|
//END API implementation
|
||||||
|
|
||||||
// Startup feedback fill animation
|
// Startup feedback fill animation
|
||||||
|
|
@ -159,7 +155,6 @@ Item {
|
||||||
MobileShell.ActionDrawerOpenSurface {
|
MobileShell.ActionDrawerOpenSurface {
|
||||||
id: swipeArea
|
id: swipeArea
|
||||||
actionDrawer: drawer.actionDrawer
|
actionDrawer: drawer.actionDrawer
|
||||||
virtualDesktopInfo: virtualDesktopInfo
|
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
|
|
||||||
readonly property alias drawerVisible: drawer.visible
|
readonly property alias drawerVisible: drawer.visible
|
||||||
|
|
|
||||||
|
|
@ -96,7 +96,7 @@ ContainmentItem {
|
||||||
root.panel.thickness = root.panelHeight;
|
root.panel.thickness = root.panelHeight;
|
||||||
root.panel.thickness = root.panelHeight;
|
root.panel.thickness = root.panelHeight;
|
||||||
|
|
||||||
root.panel.visibilityMode = (ShellSettings.Settings.convergenceModeEnabled || ShellSettings.Settings.autoHidePanelsEnabled) ? 3 : 0;
|
root.panel.visibilityMode = (!ShellSettings.Settings.convergenceModeEnabled && ShellSettings.Settings.autoHidePanelsEnabled) ? 3 : 0;
|
||||||
MobileShell.ShellUtil.setWindowLayer(root.panel, LayerShell.Window.LayerOverlay)
|
MobileShell.ShellUtil.setWindowLayer(root.panel, LayerShell.Window.LayerOverlay)
|
||||||
root.updateTouchArea();
|
root.updateTouchArea();
|
||||||
}
|
}
|
||||||
|
|
@ -152,8 +152,9 @@ ContainmentItem {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Invisible layer-shell surface that reserves screen space for the
|
// Invisible layer-shell surface that reserves screen space for the
|
||||||
// convergence status bar and one frame inset. The panel window itself
|
// status bar in convergence mode. The visible convergence top bar is
|
||||||
// stays non-reserving so this is the only top strut.
|
// rendered by Folio's unified chrome surface; this window only shrinks
|
||||||
|
// KWin's MaximizeArea.
|
||||||
Window {
|
Window {
|
||||||
id: topBarSpaceReserver
|
id: topBarSpaceReserver
|
||||||
visible: ShellSettings.Settings.convergenceModeEnabled && !ShellSettings.Settings.gamingModeEnabled
|
visible: ShellSettings.Settings.convergenceModeEnabled && !ShellSettings.Settings.gamingModeEnabled
|
||||||
|
|
|
||||||
|
|
@ -54,14 +54,15 @@ QMap<QString, QMap<QString, QVariant>> getKwinrcSettings(KSharedConfig::Ptr m_mo
|
||||||
{"ElectricBorderTiling", convergenceModeEnabled} // drag to left/right edges to tile half-screen in convergence mode
|
{"ElectricBorderTiling", convergenceModeEnabled} // drag to left/right edges to tile half-screen in convergence mode
|
||||||
}},
|
}},
|
||||||
{"Plugins",
|
{"Plugins",
|
||||||
{{"blurEnabled", false}, // disable blur for performance reasons, we could reconsider in the future for more powerful devices
|
{
|
||||||
|
{"blurEnabled", false}, // disable blur for performance reasons, we could reconsider in the future for more powerful devices
|
||||||
{"convergentwindowsEnabled", true}, // enable our convergent window plugin
|
{"convergentwindowsEnabled", true}, // enable our convergent window plugin
|
||||||
{"mobiletaskswitcherEnabled", !convergenceModeEnabled}, // mobile task switcher on phone only; convergence uses standard Alt-Tab tabbox
|
{"mobiletaskswitcherEnabled", !convergenceModeEnabled}, // mobile task switcher on phone only; convergence uses standard Alt-Tab tabbox
|
||||||
{"overviewEnabled", convergenceModeEnabled}, // enable KWin Overview effect in convergence mode for desktop-style task switching
|
{"overviewEnabled", convergenceModeEnabled}, // enable KWin Overview effect in convergence mode for desktop-style task switching
|
||||||
{"screenedgeEnabled", convergenceModeEnabled}, // enable screen edge visual feedback in convergence mode (mouse hot corners)
|
{"screenedgeEnabled", convergenceModeEnabled}, // enable screen edge visual feedback in convergence mode (mouse hot corners)
|
||||||
{"shift-tile-animationsEnabled", convergenceModeEnabled},
|
|
||||||
{"shift-tilingEnabled", convergenceModeEnabled},
|
{"shift-tilingEnabled", convergenceModeEnabled},
|
||||||
{"shift-tile-previewEnabled", convergenceModeEnabled}}},
|
{"shift-tile-previewEnabled", convergenceModeEnabled}
|
||||||
|
}},
|
||||||
{"Wayland",
|
{"Wayland",
|
||||||
{
|
{
|
||||||
{"VirtualKeyboardEnabled", true} // enable vkbd
|
{"VirtualKeyboardEnabled", true} // enable vkbd
|
||||||
|
|
@ -79,7 +80,7 @@ QMap<QString, QMap<QString, QVariant>> getKwinrcSettings(KSharedConfig::Ptr m_mo
|
||||||
|
|
||||||
// Have a separate list here because we need to trigger DBus calls to load/unload each effect/script.
|
// Have a separate list here because we need to trigger DBus calls to load/unload each effect/script.
|
||||||
// Make sure that the effect/script is added to the kwinrc "Plugins" section above!
|
// Make sure that the effect/script is added to the kwinrc "Plugins" section above!
|
||||||
const QList<QString> KWIN_EFFECTS = {"blur", "mobiletaskswitcher", "overview", "screenedge", "shift-tile-animations", "shift-tile-preview"};
|
const QList<QString> KWIN_EFFECTS = {"blur", "mobiletaskswitcher", "overview", "screenedge", "shift-tile-preview"};
|
||||||
const QList<QString> KWIN_SCRIPTS = {"convergentwindows", "shift-tiling"};
|
const QList<QString> KWIN_SCRIPTS = {"convergentwindows", "shift-tiling"};
|
||||||
|
|
||||||
// .config/plasma-mobile/ksmserver - immutable settings:
|
// .config/plasma-mobile/ksmserver - immutable settings:
|
||||||
|
|
|
||||||
|
|
@ -8,5 +8,4 @@ function(add_kwin_effect name source)
|
||||||
endfunction()
|
endfunction()
|
||||||
|
|
||||||
add_kwin_effect(shift-snap-assist shift-snap-assist)
|
add_kwin_effect(shift-snap-assist shift-snap-assist)
|
||||||
add_kwin_effect(shift-tile-animations shift-tile-animations)
|
|
||||||
add_kwin_effect(shift-tile-preview shift-tile-preview)
|
add_kwin_effect(shift-tile-preview shift-tile-preview)
|
||||||
|
|
|
||||||
|
|
@ -1,155 +0,0 @@
|
||||||
// SPDX-FileCopyrightText: 2026 Marco Allegretti
|
|
||||||
// SPDX-License-Identifier: EUPL-1.2
|
|
||||||
/*global effect, effects, animate, animationTime, cancel, Effect, QEasingCurve */
|
|
||||||
|
|
||||||
"use strict";
|
|
||||||
|
|
||||||
class ShiftTileAnimationsEffect {
|
|
||||||
constructor() {
|
|
||||||
effect.configChanged.connect(this.loadConfig.bind(this));
|
|
||||||
effect.animationEnded.connect(this.cleanupWindow.bind(this));
|
|
||||||
effects.windowAdded.connect(this.manage.bind(this));
|
|
||||||
effects.windowClosed.connect(this.cleanupWindow.bind(this));
|
|
||||||
|
|
||||||
this.loadConfig();
|
|
||||||
|
|
||||||
for (const window of effects.stackingOrder) {
|
|
||||||
this.manage(window);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
loadConfig() {
|
|
||||||
this.baseDuration = effect.readConfig("Duration", 185) || 185;
|
|
||||||
this.minimumDelta = effect.readConfig("MinimumDelta", 3) || 3;
|
|
||||||
}
|
|
||||||
|
|
||||||
manage(window) {
|
|
||||||
if (!window || window.shiftTileAnimationsManaged) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
window.shiftTileAnimationsManaged = true;
|
|
||||||
window.shiftTileUserMoveResize = false;
|
|
||||||
window.windowFrameGeometryChanged.connect(this.onWindowFrameGeometryChanged.bind(this));
|
|
||||||
window.windowStartUserMovedResized.connect(this.onWindowStartUserMovedResized.bind(this));
|
|
||||||
window.windowFinishUserMovedResized.connect(this.onWindowFinishUserMovedResized.bind(this));
|
|
||||||
}
|
|
||||||
|
|
||||||
eligibleWindow(window) {
|
|
||||||
return window
|
|
||||||
&& !effects.hasActiveFullScreenEffect
|
|
||||||
&& window.visible
|
|
||||||
&& !window.deleted
|
|
||||||
&& window.managed
|
|
||||||
&& window.normalWindow
|
|
||||||
&& !window.fullScreen
|
|
||||||
&& !window.desktopWindow
|
|
||||||
&& !window.dock
|
|
||||||
&& !window.popup
|
|
||||||
&& !window.popupWindow
|
|
||||||
&& !window.outline;
|
|
||||||
}
|
|
||||||
|
|
||||||
validGeometry(geometry) {
|
|
||||||
return geometry && geometry.width > 0 && geometry.height > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
movedEnough(oldGeometry, newGeometry) {
|
|
||||||
return Math.abs(oldGeometry.x - newGeometry.x) >= this.minimumDelta
|
|
||||||
|| Math.abs(oldGeometry.y - newGeometry.y) >= this.minimumDelta
|
|
||||||
|| Math.abs(oldGeometry.width - newGeometry.width) >= this.minimumDelta
|
|
||||||
|| Math.abs(oldGeometry.height - newGeometry.height) >= this.minimumDelta;
|
|
||||||
}
|
|
||||||
|
|
||||||
durationFor(oldGeometry, newGeometry) {
|
|
||||||
const oldCenterX = oldGeometry.x + oldGeometry.width / 2;
|
|
||||||
const oldCenterY = oldGeometry.y + oldGeometry.height / 2;
|
|
||||||
const newCenterX = newGeometry.x + newGeometry.width / 2;
|
|
||||||
const newCenterY = newGeometry.y + newGeometry.height / 2;
|
|
||||||
const distanceX = newCenterX - oldCenterX;
|
|
||||||
const distanceY = newCenterY - oldCenterY;
|
|
||||||
const distance = Math.sqrt(distanceX * distanceX + distanceY * distanceY);
|
|
||||||
const resize = Math.abs(newGeometry.width - oldGeometry.width) + Math.abs(newGeometry.height - oldGeometry.height);
|
|
||||||
const travelAllowance = Math.min(80, Math.round(Math.max(distance / 12, resize / 18)));
|
|
||||||
|
|
||||||
return animationTime(Math.max(135, Math.min(260, this.baseDuration + travelAllowance)));
|
|
||||||
}
|
|
||||||
|
|
||||||
cancelWindowAnimation(window) {
|
|
||||||
if (!window || window.shiftTileMoveAnimation === undefined) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
cancel(window.shiftTileMoveAnimation);
|
|
||||||
window.shiftTileMoveAnimation = undefined;
|
|
||||||
window.setData(Effect.WindowForceBlurRole, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
cleanupWindow(window) {
|
|
||||||
if (!window) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
window.shiftTileMoveAnimation = undefined;
|
|
||||||
window.setData(Effect.WindowForceBlurRole, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
onWindowStartUserMovedResized(window) {
|
|
||||||
if (!window) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
window.shiftTileUserMoveResize = true;
|
|
||||||
this.cancelWindowAnimation(window);
|
|
||||||
}
|
|
||||||
|
|
||||||
onWindowFinishUserMovedResized(window) {
|
|
||||||
if (window) {
|
|
||||||
window.shiftTileUserMoveResize = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
onWindowFrameGeometryChanged(window, oldGeometry) {
|
|
||||||
if (!this.eligibleWindow(window) || window.shiftTileUserMoveResize) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const newGeometry = window.geometry;
|
|
||||||
if (!this.validGeometry(oldGeometry) || !this.validGeometry(newGeometry) || !this.movedEnough(oldGeometry, newGeometry)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.cancelWindowAnimation(window);
|
|
||||||
window.setData(Effect.WindowForceBlurRole, true);
|
|
||||||
window.shiftTileMoveAnimation = animate({
|
|
||||||
window: window,
|
|
||||||
duration: this.durationFor(oldGeometry, newGeometry),
|
|
||||||
keepAlive: false,
|
|
||||||
animations: [{
|
|
||||||
type: Effect.Size,
|
|
||||||
from: {
|
|
||||||
value1: oldGeometry.width,
|
|
||||||
value2: oldGeometry.height
|
|
||||||
},
|
|
||||||
to: {
|
|
||||||
value1: newGeometry.width,
|
|
||||||
value2: newGeometry.height
|
|
||||||
},
|
|
||||||
curve: QEasingCurve.OutCubic
|
|
||||||
}, {
|
|
||||||
type: Effect.Translation,
|
|
||||||
from: {
|
|
||||||
value1: oldGeometry.x - newGeometry.x - (newGeometry.width / 2 - oldGeometry.width / 2),
|
|
||||||
value2: oldGeometry.y - newGeometry.y - (newGeometry.height / 2 - oldGeometry.height / 2)
|
|
||||||
},
|
|
||||||
to: {
|
|
||||||
value1: 0,
|
|
||||||
value2: 0
|
|
||||||
},
|
|
||||||
curve: QEasingCurve.OutCubic
|
|
||||||
}]
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
new ShiftTileAnimationsEffect();
|
|
||||||
|
|
@ -1,20 +0,0 @@
|
||||||
{
|
|
||||||
"KPackageStructure": "KWin/Effect",
|
|
||||||
"KPlugin": {
|
|
||||||
"Authors": [
|
|
||||||
{
|
|
||||||
"Email": "marcoa@example.com",
|
|
||||||
"Name": "Marco Allegretti"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"Category": "Appearance",
|
|
||||||
"Description": "Animates SHIFT convergence window layout moves.",
|
|
||||||
"EnabledByDefault": false,
|
|
||||||
"Id": "shift-tile-animations",
|
|
||||||
"License": "EUPL-1.2",
|
|
||||||
"Name": "SHIFT Tile Animations",
|
|
||||||
"Version": "1.0"
|
|
||||||
},
|
|
||||||
"X-KDE-Ordering": 62,
|
|
||||||
"X-Plasma-API": "javascript"
|
|
||||||
}
|
|
||||||
|
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
import QtQuick
|
import QtQuick
|
||||||
import org.kde.kwin as KWinComponents
|
import org.kde.kwin as KWinComponents
|
||||||
|
import org.kde.plasma.private.mobileshell as MobileShell
|
||||||
import org.kde.plasma.private.mobileshell.shellsettingsplugin as ShellSettings
|
import org.kde.plasma.private.mobileshell.shellsettingsplugin as ShellSettings
|
||||||
|
|
||||||
KWinComponents.SceneEffect {
|
KWinComponents.SceneEffect {
|
||||||
|
|
@ -12,11 +13,14 @@ KWinComponents.SceneEffect {
|
||||||
|
|
||||||
readonly property int outerGap: 8
|
readonly property int outerGap: 8
|
||||||
readonly property int floatEscapeMargin: 32
|
readonly property int floatEscapeMargin: 32
|
||||||
|
readonly property int previewAnimationDuration: MobileShell.Motion.duration(MobileShell.Motion.SpatialDefault)
|
||||||
|
readonly property int previewFadeDuration: MobileShell.Motion.duration(MobileShell.Motion.EffectsFast)
|
||||||
|
|
||||||
property var dragConnectedWindows: ({})
|
property var dragConnectedWindows: ({})
|
||||||
property var draggingWindow: null
|
property var draggingWindow: null
|
||||||
property rect dragSourceGeometry: Qt.rect(0, 0, 0, 0)
|
property rect dragSourceGeometry: Qt.rect(0, 0, 0, 0)
|
||||||
|
|
||||||
|
property bool animatePreview: false
|
||||||
property bool previewVisible: false
|
property bool previewVisible: false
|
||||||
property string previewMode: ""
|
property string previewMode: ""
|
||||||
property string previewScreenName: ""
|
property string previewScreenName: ""
|
||||||
|
|
@ -122,26 +126,14 @@ KWinComponents.SceneEffect {
|
||||||
}
|
}
|
||||||
|
|
||||||
function showPreview(mode, geometry, screenName) {
|
function showPreview(mode, geometry, screenName) {
|
||||||
if (!isActive() || !validRect(geometry)) {
|
|
||||||
hidePreview();
|
hidePreview();
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
previewMode = mode;
|
|
||||||
previewScreenName = screenName;
|
|
||||||
previewGeometry = insetPreviewGeometry(geometry);
|
|
||||||
previewVisible = true;
|
|
||||||
KWinComponents.Workspace.showOutline(previewGeometry);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function hidePreview() {
|
function hidePreview() {
|
||||||
previewVisible = false;
|
previewVisible = false;
|
||||||
draggingWindow = null;
|
draggingWindow = null;
|
||||||
dragSourceGeometry = Qt.rect(0, 0, 0, 0);
|
dragSourceGeometry = Qt.rect(0, 0, 0, 0);
|
||||||
previewMode = "";
|
disableEffectTimer.restart();
|
||||||
previewScreenName = "";
|
|
||||||
previewGeometry = Qt.rect(0, 0, 0, 0);
|
|
||||||
KWinComponents.Workspace.hideOutline();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function updatePreview(window, dragGeometry) {
|
function updatePreview(window, dragGeometry) {
|
||||||
|
|
@ -197,6 +189,44 @@ KWinComponents.SceneEffect {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function previewFillColor(mode) {
|
||||||
|
if (mode === "float") {
|
||||||
|
return Qt.rgba(1.0, 0.62, 0.24, 0.18);
|
||||||
|
}
|
||||||
|
if (mode === "restore") {
|
||||||
|
return Qt.rgba(1.0, 1.0, 1.0, 0.10);
|
||||||
|
}
|
||||||
|
return Qt.rgba(0.18, 0.72, 0.66, 0.22);
|
||||||
|
}
|
||||||
|
|
||||||
|
function previewBorderColor(mode) {
|
||||||
|
if (mode === "float") {
|
||||||
|
return Qt.rgba(1.0, 0.72, 0.36, 0.72);
|
||||||
|
}
|
||||||
|
if (mode === "restore") {
|
||||||
|
return Qt.rgba(1.0, 1.0, 1.0, 0.36);
|
||||||
|
}
|
||||||
|
return Qt.rgba(0.64, 0.90, 0.86, 0.82);
|
||||||
|
}
|
||||||
|
|
||||||
|
Timer {
|
||||||
|
id: enableAnimationTimer
|
||||||
|
interval: 1
|
||||||
|
repeat: false
|
||||||
|
onTriggered: effect.animatePreview = true
|
||||||
|
}
|
||||||
|
|
||||||
|
Timer {
|
||||||
|
id: disableEffectTimer
|
||||||
|
interval: effect.previewFadeDuration
|
||||||
|
repeat: false
|
||||||
|
onTriggered: {
|
||||||
|
if (!effect.previewVisible) {
|
||||||
|
effect.visible = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Connections {
|
Connections {
|
||||||
target: KWinComponents.Workspace
|
target: KWinComponents.Workspace
|
||||||
|
|
||||||
|
|
@ -237,5 +267,65 @@ KWinComponents.SceneEffect {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
delegate: Rectangle {
|
||||||
|
id: screenDelegate
|
||||||
|
|
||||||
|
readonly property var targetScreen: KWinComponents.SceneView.screen
|
||||||
|
readonly property bool previewOnScreen: effect.previewScreenName === targetScreen.name
|
||||||
|
|
||||||
|
color: "transparent"
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: previewSurface
|
||||||
|
|
||||||
|
visible: opacity > 0
|
||||||
|
x: effect.previewGeometry.x - screenDelegate.targetScreen.geometry.x
|
||||||
|
y: effect.previewGeometry.y - screenDelegate.targetScreen.geometry.y
|
||||||
|
width: effect.previewGeometry.width
|
||||||
|
height: effect.previewGeometry.height
|
||||||
|
radius: 14
|
||||||
|
opacity: effect.previewVisible && screenDelegate.previewOnScreen ? 1 : 0
|
||||||
|
color: effect.previewFillColor(effect.previewMode)
|
||||||
|
border.width: 2
|
||||||
|
border.color: effect.previewBorderColor(effect.previewMode)
|
||||||
|
|
||||||
|
Behavior on x {
|
||||||
|
enabled: effect.animatePreview
|
||||||
|
MobileShell.MotionNumberAnimation { type: MobileShell.Motion.SpatialDefault; duration: effect.previewAnimationDuration }
|
||||||
|
}
|
||||||
|
Behavior on y {
|
||||||
|
enabled: effect.animatePreview
|
||||||
|
MobileShell.MotionNumberAnimation { type: MobileShell.Motion.SpatialDefault; duration: effect.previewAnimationDuration }
|
||||||
|
}
|
||||||
|
Behavior on width {
|
||||||
|
enabled: effect.animatePreview
|
||||||
|
MobileShell.MotionNumberAnimation { type: MobileShell.Motion.SpatialDefault; duration: effect.previewAnimationDuration }
|
||||||
|
}
|
||||||
|
Behavior on height {
|
||||||
|
enabled: effect.animatePreview
|
||||||
|
MobileShell.MotionNumberAnimation { type: MobileShell.Motion.SpatialDefault; duration: effect.previewAnimationDuration }
|
||||||
|
}
|
||||||
|
Behavior on opacity {
|
||||||
|
MobileShell.MotionNumberAnimation { type: MobileShell.Motion.EffectsFast; duration: effect.previewFadeDuration }
|
||||||
|
}
|
||||||
|
Behavior on color {
|
||||||
|
MobileShell.MotionColorAnimation { type: MobileShell.Motion.EffectsFast; duration: effect.previewFadeDuration }
|
||||||
|
}
|
||||||
|
Behavior on border.color {
|
||||||
|
MobileShell.MotionColorAnimation { type: MobileShell.Motion.EffectsFast; duration: effect.previewFadeDuration }
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.margins: 5
|
||||||
|
radius: Math.max(0, parent.radius - anchors.margins)
|
||||||
|
color: "transparent"
|
||||||
|
border.width: 1
|
||||||
|
border.color: Qt.rgba(1, 1, 1, 0.14)
|
||||||
|
opacity: effect.previewMode === "insert" ? 1 : 0.45
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Component.onCompleted: connectExistingWindows()
|
Component.onCompleted: connectExistingWindows()
|
||||||
}
|
}
|
||||||
|
|
@ -71,10 +71,8 @@ Item {
|
||||||
// Values keep callback references so KWin script reloads can disconnect them.
|
// Values keep callback references so KWin script reloads can disconnect them.
|
||||||
property var dragConnectedWindows: ({})
|
property var dragConnectedWindows: ({})
|
||||||
|
|
||||||
property int lastWindowRequestSerial: -1
|
property int lastWindowRequestSerial: ShellSettings.Settings.dynamicTilingWindowRequestSerial
|
||||||
property string lastPublishedMaximizedWindowIds: "__unpublished__"
|
property string lastPublishedMaximizedWindowIds: "__unpublished__"
|
||||||
property int lastLayoutRequestSerial: -1
|
|
||||||
property string lastPublishedLayoutState: "__unpublished__"
|
|
||||||
|
|
||||||
// Drag state.
|
// Drag state.
|
||||||
//
|
//
|
||||||
|
|
@ -506,7 +504,6 @@ Item {
|
||||||
const focused = Object.assign({}, lastFocusedWindowKeys);
|
const focused = Object.assign({}, lastFocusedWindowKeys);
|
||||||
delete focused[outputName];
|
delete focused[outputName];
|
||||||
lastFocusedWindowKeys = focused;
|
lastFocusedWindowKeys = focused;
|
||||||
publishDynamicTilingLayoutState();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function clearDisplacedWindowOwnersForLayout(outputName) {
|
function clearDisplacedWindowOwnersForLayout(outputName) {
|
||||||
|
|
@ -657,8 +654,6 @@ Item {
|
||||||
for (let i = 0; i < cleanupLayouts.length; i++) {
|
for (let i = 0; i < cleanupLayouts.length; i++) {
|
||||||
cleanupEmptyLayout(cleanupLayouts[i]);
|
cleanupEmptyLayout(cleanupLayouts[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
publishDynamicTilingLayoutState();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function makeLeaf(win) {
|
function makeLeaf(win) {
|
||||||
|
|
@ -847,15 +842,6 @@ Item {
|
||||||
const win = KWinComponents.Workspace.activeWindow;
|
const win = KWinComponents.Workspace.activeWindow;
|
||||||
const activeName = layoutKeyForWindow(win);
|
const activeName = layoutKeyForWindow(win);
|
||||||
if (activeName !== "") return activeName;
|
if (activeName !== "") return activeName;
|
||||||
const desktop = KWinComponents.Workspace.currentDesktop;
|
|
||||||
const screens = KWinComponents.Workspace.screens;
|
|
||||||
if (desktop && screens && screens.length > 0) {
|
|
||||||
for (let i = 0; i < screens.length; i++) {
|
|
||||||
const currentDesktopName = layoutKeyFor(screens[i].name, desktop);
|
|
||||||
if (screenLayouts[currentDesktopName]) return currentDesktopName;
|
|
||||||
}
|
|
||||||
return layoutKeyFor(screens[0].name, desktop);
|
|
||||||
}
|
|
||||||
for (const name in screenLayouts) {
|
for (const name in screenLayouts) {
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
@ -877,21 +863,6 @@ Item {
|
||||||
markLayoutChanged(transaction, outputName);
|
markLayoutChanged(transaction, outputName);
|
||||||
applyLayoutTransaction(transaction);
|
applyLayoutTransaction(transaction);
|
||||||
}
|
}
|
||||||
publishDynamicTilingLayoutState();
|
|
||||||
}
|
|
||||||
|
|
||||||
function setLayoutMode(outputName, mode) {
|
|
||||||
if (!outputName || layoutModes.indexOf(mode) < 0) return;
|
|
||||||
setLayoutModeForScreen(outputName, mode);
|
|
||||||
|
|
||||||
const windows = orderedWindowsForScreen(outputName);
|
|
||||||
if (windows.length > 0) {
|
|
||||||
setStableLayout(outputName, windows);
|
|
||||||
const transaction = createLayoutTransaction();
|
|
||||||
markLayoutChanged(transaction, outputName);
|
|
||||||
applyLayoutTransaction(transaction);
|
|
||||||
}
|
|
||||||
publishDynamicTilingLayoutState();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function containsLeaf(node, key) {
|
function containsLeaf(node, key) {
|
||||||
|
|
@ -1310,37 +1281,6 @@ Item {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function publishDynamicTilingLayoutState() {
|
|
||||||
if (!isConvergence()) {
|
|
||||||
const disabledState = "|0";
|
|
||||||
if (disabledState === lastPublishedLayoutState) return;
|
|
||||||
|
|
||||||
lastPublishedLayoutState = disabledState;
|
|
||||||
if (ShellSettings.Settings.reportDynamicTilingLayoutState !== undefined) {
|
|
||||||
ShellSettings.Settings.reportDynamicTilingLayoutState("", 0);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const outputName = outputNameForActiveWindow();
|
|
||||||
const mode = outputName !== "" ? layoutModeForScreen(outputName) : "";
|
|
||||||
const windowCount = outputName !== "" ? windowCountForLayout(outputName) : 0;
|
|
||||||
const serialized = mode + "|" + windowCount;
|
|
||||||
if (serialized === lastPublishedLayoutState) return;
|
|
||||||
|
|
||||||
lastPublishedLayoutState = serialized;
|
|
||||||
if (ShellSettings.Settings.reportDynamicTilingLayoutState !== undefined) {
|
|
||||||
ShellSettings.Settings.reportDynamicTilingLayoutState(mode, windowCount);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function clearDynamicTilingLayoutState() {
|
|
||||||
lastPublishedLayoutState = "__unpublished__";
|
|
||||||
if (ShellSettings.Settings.reportDynamicTilingLayoutState !== undefined) {
|
|
||||||
ShellSettings.Settings.reportDynamicTilingLayoutState("", 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function maximizedLayoutNameForWindow(win) {
|
function maximizedLayoutNameForWindow(win) {
|
||||||
const key = windowKey(win);
|
const key = windowKey(win);
|
||||||
if (!key) return "";
|
if (!key) return "";
|
||||||
|
|
@ -1742,19 +1682,6 @@ Item {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleLayoutModeRequest() {
|
|
||||||
const serial = ShellSettings.Settings.dynamicTilingLayoutRequestSerial;
|
|
||||||
if (serial === lastLayoutRequestSerial) return;
|
|
||||||
lastLayoutRequestSerial = serial;
|
|
||||||
|
|
||||||
if (!isConvergence()) return;
|
|
||||||
|
|
||||||
const mode = ShellSettings.Settings.dynamicTilingLayoutRequestMode;
|
|
||||||
if (layoutModes.indexOf(mode) < 0) return;
|
|
||||||
|
|
||||||
setLayoutMode(outputNameForActiveWindow(), mode);
|
|
||||||
}
|
|
||||||
|
|
||||||
function promoteWindow(win) {
|
function promoteWindow(win) {
|
||||||
if (!isTileable(win)) return;
|
if (!isTileable(win)) return;
|
||||||
|
|
||||||
|
|
@ -1844,12 +1771,10 @@ Item {
|
||||||
|
|
||||||
function onActiveWindowChanged() {
|
function onActiveWindowChanged() {
|
||||||
root.rememberFocusedWindow(KWinComponents.Workspace.activeWindow);
|
root.rememberFocusedWindow(KWinComponents.Workspace.activeWindow);
|
||||||
root.publishDynamicTilingLayoutState();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function onCurrentDesktopChanged() {
|
function onCurrentDesktopChanged() {
|
||||||
root.retileCurrentDesktopLayouts();
|
root.retileCurrentDesktopLayouts();
|
||||||
root.publishDynamicTilingLayoutState();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function onScreensChanged() {
|
function onScreensChanged() {
|
||||||
|
|
@ -1863,7 +1788,6 @@ Item {
|
||||||
}
|
}
|
||||||
|
|
||||||
root.scheduleRetileAll();
|
root.scheduleRetileAll();
|
||||||
root.publishDynamicTilingLayoutState();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1877,7 +1801,6 @@ Item {
|
||||||
for (let i = 0; i < wins.length; i++) {
|
for (let i = 0; i < wins.length; i++) {
|
||||||
adoptWindow(wins[i]);
|
adoptWindow(wins[i]);
|
||||||
}
|
}
|
||||||
publishDynamicTilingLayoutState();
|
|
||||||
} else {
|
} else {
|
||||||
// Clear all tiles — the convergentwindows script will re-maximize
|
// Clear all tiles — the convergentwindows script will re-maximize
|
||||||
restoreAllMaximizedLayouts();
|
restoreAllMaximizedLayouts();
|
||||||
|
|
@ -1886,7 +1809,6 @@ Item {
|
||||||
screenLayoutModes = {};
|
screenLayoutModes = {};
|
||||||
lastFocusedWindowKeys = {};
|
lastFocusedWindowKeys = {};
|
||||||
maximizedLayouts = {};
|
maximizedLayouts = {};
|
||||||
clearDynamicTilingLayoutState();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1898,13 +1820,11 @@ Item {
|
||||||
screenLayoutModes = {};
|
screenLayoutModes = {};
|
||||||
lastFocusedWindowKeys = {};
|
lastFocusedWindowKeys = {};
|
||||||
maximizedLayouts = {};
|
maximizedLayouts = {};
|
||||||
clearDynamicTilingLayoutState();
|
|
||||||
} else if (isConvergence()) {
|
} else if (isConvergence()) {
|
||||||
const wins = KWinComponents.Workspace.windows;
|
const wins = KWinComponents.Workspace.windows;
|
||||||
for (let i = 0; i < wins.length; i++) {
|
for (let i = 0; i < wins.length; i++) {
|
||||||
adoptWindow(wins[i]);
|
adoptWindow(wins[i]);
|
||||||
}
|
}
|
||||||
publishDynamicTilingLayoutState();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1914,7 +1834,6 @@ Item {
|
||||||
for (let i = 0; i < wins.length; i++) {
|
for (let i = 0; i < wins.length; i++) {
|
||||||
adoptWindow(wins[i]);
|
adoptWindow(wins[i]);
|
||||||
}
|
}
|
||||||
publishDynamicTilingLayoutState();
|
|
||||||
} else {
|
} else {
|
||||||
// Tiling turned off — leave windows where they are.
|
// Tiling turned off — leave windows where they are.
|
||||||
restoreAllMaximizedLayouts();
|
restoreAllMaximizedLayouts();
|
||||||
|
|
@ -1923,17 +1842,12 @@ Item {
|
||||||
screenLayoutModes = {};
|
screenLayoutModes = {};
|
||||||
lastFocusedWindowKeys = {};
|
lastFocusedWindowKeys = {};
|
||||||
maximizedLayouts = {};
|
maximizedLayouts = {};
|
||||||
clearDynamicTilingLayoutState();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function onDynamicTilingWindowRequestChanged() {
|
function onDynamicTilingWindowRequestChanged() {
|
||||||
root.handleWindowTilingRequest();
|
root.handleWindowTilingRequest();
|
||||||
}
|
}
|
||||||
|
|
||||||
function onDynamicTilingLayoutRequestChanged() {
|
|
||||||
root.handleLayoutModeRequest();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ── Drag handlers ─────────────────────────────────────────────────────
|
// ── Drag handlers ─────────────────────────────────────────────────────
|
||||||
|
|
@ -2251,9 +2165,6 @@ Item {
|
||||||
// ── Component setup ───────────────────────────────────────────────────
|
// ── Component setup ───────────────────────────────────────────────────
|
||||||
|
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
lastWindowRequestSerial = ShellSettings.Settings.dynamicTilingWindowRequestSerial;
|
|
||||||
lastLayoutRequestSerial = ShellSettings.Settings.dynamicTilingLayoutRequestSerial;
|
|
||||||
|
|
||||||
// Connect to existing windows
|
// Connect to existing windows
|
||||||
const wins = KWinComponents.Workspace.windows;
|
const wins = KWinComponents.Workspace.windows;
|
||||||
for (let i = 0; i < wins.length; i++) {
|
for (let i = 0; i < wins.length; i++) {
|
||||||
|
|
@ -2261,12 +2172,10 @@ Item {
|
||||||
}
|
}
|
||||||
rememberFocusedWindow(KWinComponents.Workspace.activeWindow);
|
rememberFocusedWindow(KWinComponents.Workspace.activeWindow);
|
||||||
publishDynamicTilingWindowState();
|
publishDynamicTilingWindowState();
|
||||||
publishDynamicTilingLayoutState();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Component.onDestruction: {
|
Component.onDestruction: {
|
||||||
disconnectDragHandlers();
|
disconnectDragHandlers();
|
||||||
clearDynamicTilingWindowState();
|
clearDynamicTilingWindowState();
|
||||||
clearDynamicTilingLayoutState();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,10 +14,7 @@ taskpanel="$repo_root/containments/taskpanel/qml/main.qml"
|
||||||
folio_main="$repo_root/containments/homescreens/folio/qml/main.qml"
|
folio_main="$repo_root/containments/homescreens/folio/qml/main.qml"
|
||||||
shellutil_header="$repo_root/components/mobileshell/shellutil.h"
|
shellutil_header="$repo_root/components/mobileshell/shellutil.h"
|
||||||
shellutil_cpp="$repo_root/components/mobileshell/shellutil.cpp"
|
shellutil_cpp="$repo_root/components/mobileshell/shellutil.cpp"
|
||||||
swipearea_header="$repo_root/components/mobileshell/components/swipearea.h"
|
|
||||||
swipearea_cpp="$repo_root/components/mobileshell/components/swipearea.cpp"
|
|
||||||
folio_home="$repo_root/containments/homescreens/folio/qml/FolioHomeScreen.qml"
|
folio_home="$repo_root/containments/homescreens/folio/qml/FolioHomeScreen.qml"
|
||||||
favourites_bar="$repo_root/containments/homescreens/folio/qml/FavouritesBar.qml"
|
|
||||||
folio_backend="$repo_root/containments/homescreens/folio/homescreen.h"
|
folio_backend="$repo_root/containments/homescreens/folio/homescreen.h"
|
||||||
folio_backend_cpp="$repo_root/containments/homescreens/folio/homescreen.cpp"
|
folio_backend_cpp="$repo_root/containments/homescreens/folio/homescreen.cpp"
|
||||||
action_content="$repo_root/components/mobileshell/qml/actiondrawer/private/ContentContainer.qml"
|
action_content="$repo_root/components/mobileshell/qml/actiondrawer/private/ContentContainer.qml"
|
||||||
|
|
@ -51,7 +48,7 @@ require_line "$constants" "readonly property real convergenceWorkspaceFrameRadiu
|
||||||
require_line "$panel" "readonly property real convergenceWorkspaceFrameThickness:"
|
require_line "$panel" "readonly property real convergenceWorkspaceFrameThickness:"
|
||||||
require_line "$panel" "root.panel.location = PlasmaCore.Types.TopEdge"
|
require_line "$panel" "root.panel.location = PlasmaCore.Types.TopEdge"
|
||||||
require_line "$panel" "root.panel.offset = 0"
|
require_line "$panel" "root.panel.offset = 0"
|
||||||
require_line "$panel" "root.panel.visibilityMode = (ShellSettings.Settings.convergenceModeEnabled || ShellSettings.Settings.autoHidePanelsEnabled) ? 3 : 0"
|
require_line "$panel" "root.panel.visibilityMode = (!ShellSettings.Settings.convergenceModeEnabled && ShellSettings.Settings.autoHidePanelsEnabled) ? 3 : 0"
|
||||||
require_line "$panel" "readonly property real topBarHeight: gamingMode ? 0 : MobileShell.Constants.topPanelHeight"
|
require_line "$panel" "readonly property real topBarHeight: gamingMode ? 0 : MobileShell.Constants.topPanelHeight"
|
||||||
require_line "$panel" "readonly property real topBarInputHeight: topBarHeight + convergenceWorkspaceFrameThickness"
|
require_line "$panel" "readonly property real topBarInputHeight: topBarHeight + convergenceWorkspaceFrameThickness"
|
||||||
require_line "$panel" "? 0"
|
require_line "$panel" "? 0"
|
||||||
|
|
@ -63,34 +60,11 @@ require_line "$panel" "visible: !ShellSettings.Settings.gamingModeEnabled"
|
||||||
|
|
||||||
require_line "$status_panel" "&& !ShellSettings.Settings.convergenceModeEnabled"
|
require_line "$status_panel" "&& !ShellSettings.Settings.convergenceModeEnabled"
|
||||||
require_line "$status_panel" "visible: !ShellSettings.Settings.convergenceModeEnabled"
|
require_line "$status_panel" "visible: !ShellSettings.Settings.convergenceModeEnabled"
|
||||||
require_line "$status_panel" "TaskManager.VirtualDesktopInfo {"
|
|
||||||
require_line "$status_panel" "MobileShell.ActionDrawerOpenSurface {"
|
require_line "$status_panel" "MobileShell.ActionDrawerOpenSurface {"
|
||||||
require_line "$status_panel" "virtualDesktopInfo: virtualDesktopInfo"
|
|
||||||
require_line "$action_open_surface" "property var virtualDesktopInfo: null"
|
|
||||||
require_line "$action_open_surface" "touchpadWorkspaceSwitchThreshold"
|
|
||||||
require_line "$action_open_surface" "function activateAdjacentWorkspace(direction)"
|
|
||||||
require_line "$action_open_surface" "virtualDesktopInfo.requestActivate(virtualDesktopInfo.desktopIds[targetIndex]);"
|
|
||||||
require_line "$action_open_surface" "absY >= touchpadDirectionLockThreshold && absY > absX * touchpadAxisDominance"
|
|
||||||
require_line "$action_open_surface" "workspaceScrollAvailable() && absX >= touchpadDirectionLockThreshold && absX > absY * touchpadAxisDominance"
|
|
||||||
require_line "$action_open_surface" "MouseArea {"
|
require_line "$action_open_surface" "MouseArea {"
|
||||||
require_line "$action_open_surface" "acceptedButtons: Qt.NoButton"
|
require_line "$action_open_surface" "acceptedButtons: Qt.NoButton"
|
||||||
require_line "$action_open_surface" "hoverEnabled: true"
|
require_line "$action_open_surface" "hoverEnabled: true"
|
||||||
require_line "$action_open_surface" "scrollGestureEnabled: false"
|
|
||||||
require_line "$action_open_surface" "cursorShape: ShellSettings.Settings.convergenceModeEnabled ? Qt.PointingHandCursor : Qt.ArrowCursor"
|
require_line "$action_open_surface" "cursorShape: ShellSettings.Settings.convergenceModeEnabled ? Qt.PointingHandCursor : Qt.ArrowCursor"
|
||||||
require_line "$swipearea_cpp" "const qreal WHEEL_STEP_PIXEL_DELTA = 48.0;"
|
|
||||||
require_line "$swipearea_cpp" "const int TOUCHPAD_SCROLL_END_TIMEOUT = 160;"
|
|
||||||
require_line "$swipearea_cpp" "const bool isTouchpad = event->deviceType() == QInputDevice::DeviceType::TouchPad;"
|
|
||||||
require_line "$swipearea_cpp" "startTouchpadScroll(event->points().first().position());"
|
|
||||||
require_line "$swipearea_cpp" "m_touchpadScrollEndTimer.start();"
|
|
||||||
require_line "$swipearea_cpp" "if (scrollDelta.isNull() && !event->angleDelta().isNull())"
|
|
||||||
require_line "$swipearea_cpp" "QWheelEvent::DefaultDeltasPerStep * WHEEL_STEP_PIXEL_DELTA"
|
|
||||||
require_line "$swipearea_header" "QTimer m_touchpadScrollEndTimer;"
|
|
||||||
require_line "$favourites_bar" "function handlePagerWheel(wheel)"
|
|
||||||
require_line "$favourites_bar" "onWheel: (wheel) => root.handlePagerWheel(wheel)"
|
|
||||||
require_line "$favourites_bar" "root.activateAdjacentDesktop(1)"
|
|
||||||
require_line "$folio_home" "onTouchpadScrollStarted: {"
|
|
||||||
require_line "$folio_home" "onTouchpadScrollMove: (totalDeltaX, totalDeltaY, deltaX, deltaY) => {"
|
|
||||||
require_line "$folio_home" "if (!ShellSettings.Settings.convergenceModeEnabled) {"
|
|
||||||
|
|
||||||
require_line "$status_bar_template" "panel.location = \"top\";"
|
require_line "$status_bar_template" "panel.location = \"top\";"
|
||||||
|
|
||||||
|
|
@ -105,7 +79,8 @@ require_line "$folio_main" "id: convergenceChrome"
|
||||||
require_line "$folio_main" "LayerShell.Window.scope: \"convergence-chrome\""
|
require_line "$folio_main" "LayerShell.Window.scope: \"convergence-chrome\""
|
||||||
require_line "$folio_main" "height: Screen.height"
|
require_line "$folio_main" "height: Screen.height"
|
||||||
require_line "$folio_main" "MobileShell.StatusBar {"
|
require_line "$folio_main" "MobileShell.StatusBar {"
|
||||||
require_line "$folio_main" "MobileShell.ShellUtil.setInputRegions(convergenceChrome, regions)"
|
require_line "$folio_main" "MobileShell.ShellUtil.setInputRegions(convergenceChrome, ["
|
||||||
|
require_line "$folio_main" "readonly property real topBarHitHeight: topBarHeight + frameThickness"
|
||||||
require_line "$folio_main" "const topBarRegion = Qt.rect(0, 0, width, topBarHitHeight)"
|
require_line "$folio_main" "const topBarRegion = Qt.rect(0, 0, width, topBarHitHeight)"
|
||||||
require_line "$folio_main" "readonly property real dockHeight: MobileShell.Constants.convergenceDockHeight"
|
require_line "$folio_main" "readonly property real dockHeight: MobileShell.Constants.convergenceDockHeight"
|
||||||
require_line "$folio_main" "readonly property real revealStripHeight: MobileShell.Constants.convergenceDockRevealHeight"
|
require_line "$folio_main" "readonly property real revealStripHeight: MobileShell.Constants.convergenceDockRevealHeight"
|
||||||
|
|
@ -114,29 +89,10 @@ require_line "$folio_main" "id: workspaceFrame"
|
||||||
require_line "$folio_main" "readonly property real frameThickness: MobileShell.Constants.convergenceWorkspaceFrameThickness"
|
require_line "$folio_main" "readonly property real frameThickness: MobileShell.Constants.convergenceWorkspaceFrameThickness"
|
||||||
require_line "$folio_main" "readonly property real frameRadius:"
|
require_line "$folio_main" "readonly property real frameRadius:"
|
||||||
require_line "$folio_main" "readonly property real workAreaX: frameThickness"
|
require_line "$folio_main" "readonly property real workAreaX: frameThickness"
|
||||||
require_line "$folio_main" "readonly property real topBarHitHeight: topBarHeight + frameThickness"
|
|
||||||
require_line "$folio_main" "readonly property real workAreaY: topBarHitHeight"
|
require_line "$folio_main" "readonly property real workAreaY: topBarHitHeight"
|
||||||
require_line "$folio_main" "readonly property real workAreaWidth: Math.max(0, width - frameThickness * 2)"
|
require_line "$folio_main" "readonly property real workAreaWidth: Math.max(0, width - frameThickness * 2)"
|
||||||
require_line "$folio_main" "readonly property real workAreaHeight: Math.max(0, height - topBarHeight - dockHeight - frameThickness * 2)"
|
require_line "$folio_main" "readonly property real workAreaHeight: Math.max(0, height - topBarHeight - dockHeight - frameThickness * 2)"
|
||||||
require_line "$folio_main" "fillRule: ShapePath.OddEvenFill"
|
require_line "$folio_main" "fillRule: ShapePath.OddEvenFill"
|
||||||
require_line "$folio_main" "id: leftEdgeHoverArea"
|
|
||||||
require_line "$folio_main" "id: rightEdgeHoverArea"
|
|
||||||
require_line "$folio_main" "cursorShape: enabled ? Qt.PointingHandCursor : Qt.ArrowCursor"
|
|
||||||
require_line "$folio_main" "convergenceChrome.leftEdgeHovered = containsMouse"
|
|
||||||
require_line "$folio_main" "convergenceChrome.rightEdgeHovered = containsMouse"
|
|
||||||
require_line "$folio_main" "convergenceChrome.leftLauncherHovered = hovered"
|
|
||||||
require_line "$folio_main" "convergenceChrome.layoutMenuHovered = hovered"
|
|
||||||
|
|
||||||
if grep -Fq "root.panel.visibilityMode = (!ShellSettings.Settings.convergenceModeEnabled && ShellSettings.Settings.autoHidePanelsEnabled) ? 3 : 0" "$panel"; then
|
|
||||||
echo "Convergence panel hit area must not reserve extra top space" >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
if grep -Fq "id: leftLauncherPointerTracker" "$folio_main"; then
|
|
||||||
echo "Folio convergence chrome must not cover the dock with a fullscreen hover tracker" >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
require_line "$folio_main" "PathLine { x: convergenceChrome.width; y: convergenceChrome.height - convergenceChrome.dockHeight }"
|
require_line "$folio_main" "PathLine { x: convergenceChrome.width; y: convergenceChrome.height - convergenceChrome.dockHeight }"
|
||||||
require_line "$folio_main" "PathLine { x: 0; y: convergenceChrome.height - convergenceChrome.dockHeight }"
|
require_line "$folio_main" "PathLine { x: 0; y: convergenceChrome.height - convergenceChrome.dockHeight }"
|
||||||
require_line "$folio_main" "PathArc { x: convergenceChrome.workAreaX + convergenceChrome.workAreaWidth - convergenceChrome.frameRadius; y: convergenceChrome.workAreaY + convergenceChrome.workAreaHeight; radiusX: convergenceChrome.frameRadius; radiusY: convergenceChrome.frameRadius }"
|
require_line "$folio_main" "PathArc { x: convergenceChrome.workAreaX + convergenceChrome.workAreaWidth - convergenceChrome.frameRadius; y: convergenceChrome.workAreaY + convergenceChrome.workAreaHeight; radiusX: convergenceChrome.frameRadius; radiusY: convergenceChrome.frameRadius }"
|
||||||
|
|
|
||||||
|
|
@ -8,13 +8,10 @@ repo_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||||
|
|
||||||
effect_qml="$repo_root/kwin/effects/shift-tile-preview/contents/ui/main.qml"
|
effect_qml="$repo_root/kwin/effects/shift-tile-preview/contents/ui/main.qml"
|
||||||
effect_metadata="$repo_root/kwin/effects/shift-tile-preview/metadata.json"
|
effect_metadata="$repo_root/kwin/effects/shift-tile-preview/metadata.json"
|
||||||
animation_effect_js="$repo_root/kwin/effects/shift-tile-animations/contents/code/main.js"
|
|
||||||
animation_effect_metadata="$repo_root/kwin/effects/shift-tile-animations/metadata.json"
|
|
||||||
effects_cmake="$repo_root/kwin/effects/CMakeLists.txt"
|
effects_cmake="$repo_root/kwin/effects/CMakeLists.txt"
|
||||||
tiling_script="$repo_root/kwin/scripts/shift-tiling/contents/ui/main.qml"
|
tiling_script="$repo_root/kwin/scripts/shift-tiling/contents/ui/main.qml"
|
||||||
decoration_qml="$repo_root/kwin/decorations/org.shift.decoration/contents/ui/main.qml"
|
decoration_qml="$repo_root/kwin/decorations/org.shift.decoration/contents/ui/main.qml"
|
||||||
running_apps_panel="$repo_root/containments/homescreens/folio/qml/RunningAppsPanel.qml"
|
running_apps_panel="$repo_root/containments/homescreens/folio/qml/RunningAppsPanel.qml"
|
||||||
folio_main="$repo_root/containments/homescreens/folio/qml/main.qml"
|
|
||||||
env_config="$repo_root/envmanager/config.h"
|
env_config="$repo_root/envmanager/config.h"
|
||||||
|
|
||||||
require_line() {
|
require_line() {
|
||||||
|
|
@ -38,17 +35,12 @@ reject_line() {
|
||||||
}
|
}
|
||||||
|
|
||||||
require_line "$effects_cmake" "add_kwin_effect(shift-tile-preview shift-tile-preview)"
|
require_line "$effects_cmake" "add_kwin_effect(shift-tile-preview shift-tile-preview)"
|
||||||
require_line "$effects_cmake" "add_kwin_effect(shift-tile-animations shift-tile-animations)"
|
|
||||||
require_line "$effect_metadata" '"Id": "shift-tile-preview"'
|
require_line "$effect_metadata" '"Id": "shift-tile-preview"'
|
||||||
require_line "$effect_metadata" '"X-Plasma-API": "declarativescript"'
|
require_line "$effect_metadata" '"X-Plasma-API": "declarativescript"'
|
||||||
require_line "$animation_effect_metadata" '"Id": "shift-tile-animations"'
|
|
||||||
require_line "$animation_effect_metadata" '"X-Plasma-API": "javascript"'
|
|
||||||
|
|
||||||
require_line "$env_config" '{"shift-tilingEnabled", convergenceModeEnabled}'
|
require_line "$env_config" '{"shift-tilingEnabled", convergenceModeEnabled}'
|
||||||
require_line "$env_config" '{"shift-tile-previewEnabled", convergenceModeEnabled}'
|
require_line "$env_config" '{"shift-tile-previewEnabled", convergenceModeEnabled}'
|
||||||
require_line "$env_config" '{"shift-tile-animationsEnabled", convergenceModeEnabled}'
|
|
||||||
require_line "$env_config" '"shift-tile-preview"'
|
require_line "$env_config" '"shift-tile-preview"'
|
||||||
require_line "$env_config" '"shift-tile-animations"'
|
|
||||||
require_line "$env_config" '"shift-tiling"'
|
require_line "$env_config" '"shift-tiling"'
|
||||||
|
|
||||||
require_line "$effect_qml" "KWinComponents.SceneEffect"
|
require_line "$effect_qml" "KWinComponents.SceneEffect"
|
||||||
|
|
@ -57,32 +49,17 @@ require_line "$effect_qml" "ShellSettings.Settings.dynamicTilingEnabled"
|
||||||
require_line "$effect_qml" "interactiveMoveResizeStarted.connect"
|
require_line "$effect_qml" "interactiveMoveResizeStarted.connect"
|
||||||
require_line "$effect_qml" "interactiveMoveResizeStepped.connect"
|
require_line "$effect_qml" "interactiveMoveResizeStepped.connect"
|
||||||
require_line "$effect_qml" "interactiveMoveResizeFinished.connect"
|
require_line "$effect_qml" "interactiveMoveResizeFinished.connect"
|
||||||
|
require_line "$effect_qml" "Behavior on x"
|
||||||
|
require_line "$effect_qml" "Behavior on y"
|
||||||
|
require_line "$effect_qml" "Behavior on width"
|
||||||
|
require_line "$effect_qml" "Behavior on height"
|
||||||
require_line "$effect_qml" "showPreview(\"swap\""
|
require_line "$effect_qml" "showPreview(\"swap\""
|
||||||
require_line "$effect_qml" "showPreview(\"float\""
|
require_line "$effect_qml" "showPreview(\"float\""
|
||||||
require_line "$effect_qml" "showPreview(\"restore\""
|
require_line "$effect_qml" "showPreview(\"restore\""
|
||||||
require_line "$effect_qml" "KWinComponents.Workspace.showOutline(previewGeometry)"
|
|
||||||
require_line "$effect_qml" "KWinComponents.Workspace.hideOutline()"
|
|
||||||
reject_line "$effect_qml" "MobileShell.MotionNumberAnimation"
|
|
||||||
reject_line "$effect_qml" "MobileShell.MotionColorAnimation"
|
|
||||||
reject_line "$effect_qml" "disableEffectTimer"
|
|
||||||
|
|
||||||
require_line "$animation_effect_js" "class ShiftTileAnimationsEffect"
|
|
||||||
require_line "$animation_effect_js" "window.windowFrameGeometryChanged.connect"
|
|
||||||
require_line "$animation_effect_js" "window.windowStartUserMovedResized.connect"
|
|
||||||
require_line "$animation_effect_js" "window.windowFinishUserMovedResized.connect"
|
|
||||||
require_line "$animation_effect_js" "animationTime("
|
|
||||||
require_line "$animation_effect_js" "type: Effect.Size"
|
|
||||||
require_line "$animation_effect_js" "type: Effect.Translation"
|
|
||||||
require_line "$animation_effect_js" "curve: QEasingCurve.OutCubic"
|
|
||||||
require_line "$animation_effect_js" "window.shiftTileUserMoveResize"
|
|
||||||
|
|
||||||
require_line "$tiling_script" "readonly property int maxWindowsPerPage: 4"
|
require_line "$tiling_script" "readonly property int maxWindowsPerPage: 4"
|
||||||
require_line "$tiling_script" "readonly property real stablePrimaryRatio: 0.58"
|
require_line "$tiling_script" "readonly property real stablePrimaryRatio: 0.58"
|
||||||
require_line "$tiling_script" "readonly property var layoutModes: [\"master\", \"columns\", \"rows\"]"
|
require_line "$tiling_script" "readonly property var layoutModes: [\"master\", \"columns\", \"rows\"]"
|
||||||
require_line "$tiling_script" "property int lastWindowRequestSerial: -1"
|
|
||||||
require_line "$tiling_script" "property int lastLayoutRequestSerial: -1"
|
|
||||||
require_line "$tiling_script" "lastWindowRequestSerial = ShellSettings.Settings.dynamicTilingWindowRequestSerial"
|
|
||||||
require_line "$tiling_script" "lastLayoutRequestSerial = ShellSettings.Settings.dynamicTilingLayoutRequestSerial"
|
|
||||||
require_line "$tiling_script" "function desktopKey(desktop)"
|
require_line "$tiling_script" "function desktopKey(desktop)"
|
||||||
require_line "$tiling_script" "function desktopForWindow(win)"
|
require_line "$tiling_script" "function desktopForWindow(win)"
|
||||||
require_line "$tiling_script" "function normalizeWindowDesktopScope(win)"
|
require_line "$tiling_script" "function normalizeWindowDesktopScope(win)"
|
||||||
|
|
@ -149,17 +126,6 @@ require_line "$decoration_qml" "borders.bottom = normalCornerRadius;"
|
||||||
require_line "$decoration_qml" "PathArc { x: root.width - root.cornerRadius; y: root.height; radiusX: root.cornerRadius; radiusY: root.cornerRadius }"
|
require_line "$decoration_qml" "PathArc { x: root.width - root.cornerRadius; y: root.height; radiusX: root.cornerRadius; radiusY: root.cornerRadius }"
|
||||||
require_line "$decoration_qml" "PathArc { x: 0; y: root.height - root.cornerRadius; radiusX: root.cornerRadius; radiusY: root.cornerRadius }"
|
require_line "$decoration_qml" "PathArc { x: 0; y: root.height - root.cornerRadius; radiusX: root.cornerRadius; radiusY: root.cornerRadius }"
|
||||||
|
|
||||||
require_line "$folio_main" "readonly property int layoutMenuWindowCount: Math.max(0, ShellSettings.Settings.dynamicTilingLayoutWindowCount)"
|
|
||||||
require_line "$folio_main" "&& layoutMenuWindowCount >= 2"
|
|
||||||
require_line "$folio_main" "if (layoutMenuEnabled) {"
|
|
||||||
require_line "$folio_main" "regions.push(rightEdgeRegion)"
|
|
||||||
require_line "$folio_main" "if (layoutMenuEnabled && layoutMenuOpen)"
|
|
||||||
require_line "$folio_main" "rightEdgeHovered = false"
|
|
||||||
require_line "$folio_main" "layoutMenuHovered = false"
|
|
||||||
require_line "$folio_main" "id: rightEdgeHoverArea"
|
|
||||||
require_line "$folio_main" "convergenceChrome.rightEdgeHovered = containsMouse"
|
|
||||||
require_line "$folio_main" "width: convergenceChrome.layoutMenuEnabled ? convergenceChrome.rightEdgeHotzoneWidth : 0"
|
|
||||||
|
|
||||||
running_panel_group_disabled_count="$(grep -F "groupMode: TaskManager.TasksModel.GroupDisabled" "$running_apps_panel" | wc -l)"
|
running_panel_group_disabled_count="$(grep -F "groupMode: TaskManager.TasksModel.GroupDisabled" "$running_apps_panel" | wc -l)"
|
||||||
if [[ "$running_panel_group_disabled_count" -ne 2 ]]; then
|
if [[ "$running_panel_group_disabled_count" -ne 2 ]]; then
|
||||||
echo "Expected the Folio Running panel to disable grouping for both task models; found $running_panel_group_disabled_count" >&2
|
echo "Expected the Folio Running panel to disable grouping for both task models; found $running_panel_group_disabled_count" >&2
|
||||||
|
|
@ -189,8 +155,6 @@ reject_line "$tiling_script" "function tileInsertDirection(cursor, rect)"
|
||||||
reject_line "$tiling_script" "showDragOutline(\"insert\""
|
reject_line "$tiling_script" "showDragOutline(\"insert\""
|
||||||
reject_line "$tiling_script" "KWinComponents.Workspace.showOutline(dragOutlineRect)"
|
reject_line "$tiling_script" "KWinComponents.Workspace.showOutline(dragOutlineRect)"
|
||||||
reject_line "$tiling_script" "KWinComponents.Workspace.hideOutline()"
|
reject_line "$tiling_script" "KWinComponents.Workspace.hideOutline()"
|
||||||
reject_line "$tiling_script" "property int lastWindowRequestSerial: ShellSettings.Settings.dynamicTilingWindowRequestSerial"
|
|
||||||
reject_line "$tiling_script" "property int lastLayoutRequestSerial: ShellSettings.Settings.dynamicTilingLayoutRequestSerial"
|
|
||||||
reject_line "$effect_qml" "effect.visible = true"
|
reject_line "$effect_qml" "effect.visible = true"
|
||||||
|
|
||||||
printf '%s\n' 'dynamic-tiles-motion-ok'
|
printf '%s\n' 'dynamic-tiles-motion-ok'
|
||||||
Loading…
Reference in a new issue