From a3943400d59145327b294042f292d8e96b330b11 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niccol=C3=B2=20Venerandi?= Date: Thu, 5 May 2022 00:31:42 +0000 Subject: [PATCH] Implement floating panel support Please refer to https://invent.kde.org/plasma/plasma-desktop/-/merge_requests/714 for explanation and discussion. --- shell/panelview.cpp | 121 +++++++++++++++++++++++++++++++++++------- shell/panelview.h | 18 +++++++ shell/shellcorona.cpp | 10 ++-- 3 files changed, 124 insertions(+), 25 deletions(-) diff --git a/shell/panelview.cpp b/shell/panelview.cpp index 091444cdc..b846a5bb9 100644 --- a/shell/panelview.cpp +++ b/shell/panelview.cpp @@ -57,6 +57,7 @@ PanelView::PanelView(ShellCorona *corona, QScreen *targetScreen, QWindow *parent , m_distance(0) , m_thickness(30) , m_initCompleted(false) + , m_floating(false) , m_alignment(Qt::AlignLeft) , m_corona(corona) , m_visibilityMode(NormalPanel) @@ -104,6 +105,7 @@ PanelView::PanelView(ShellCorona *corona, QScreen *targetScreen, QWindow *parent rootContext()->setContextProperty(QStringLiteral("panel"), this); setSource(m_corona->kPackage().fileUrl("views", QStringLiteral("Panel.qml"))); updatePadding(); + updateFloating(); } PanelView::~PanelView() @@ -228,6 +230,21 @@ int PanelView::thickness() const return m_thickness; } +int PanelView::totalThickness() const { + switch (containment()->location()) { + case Plasma::Types::TopEdge: + return thickness() + m_topFloatingPadding + m_bottomFloatingPadding; + case Plasma::Types::LeftEdge: + return thickness() + m_leftFloatingPadding + m_rightFloatingPadding; + case Plasma::Types::RightEdge: + return thickness() + m_rightFloatingPadding + m_leftFloatingPadding; + case Plasma::Types::BottomEdge: + return thickness() + m_bottomFloatingPadding + m_topFloatingPadding; + default: + return thickness(); + } +} + void PanelView::setThickness(int value) { if (value == thickness()) { @@ -323,6 +340,29 @@ void PanelView::setDistance(int dist) positionPanel(); } +bool PanelView::floating() const +{ + return m_floating; +} + +void PanelView::setFloating(bool floating) +{ + if (m_floating == floating) { + return; + } + + m_floating = floating; + if (config().isValid() && config().parent().isValid()) { + config().parent().writeEntry("floating", (int)floating); + m_corona->requestApplicationConfigSync(); + } + Q_EMIT floatingChanged(); + + updateFloating(); + updateEnabledBorders(); + updateMask(); +} + Plasma::Types::BackgroundHints PanelView::backgroundHints() const { return m_backgroundHints; @@ -516,17 +556,17 @@ QRect PanelView::geometryByDistance(int distance) const switch (m_alignment) { case Qt::AlignCenter: // Never use rect.right(); for historical reasons it returns left() + width() - 1; see https://doc.qt.io/qt-5/qrect.html#right - position = QPoint(QPoint(screenGeometry.x() + screenGeometry.width(), screenGeometry.center().y()) - QPoint(thickness() + distance, 0) + position = QPoint(QPoint(screenGeometry.x() + screenGeometry.width(), screenGeometry.center().y()) - QPoint(totalThickness() + distance, 0) + QPoint(0, m_offset - height() / 2)); break; case Qt::AlignRight: position = QPoint(QPoint(screenGeometry.x() + screenGeometry.width(), screenGeometry.y() + screenGeometry.height()) - - QPoint(thickness() + distance, 0) - QPoint(0, m_offset + height())); + - QPoint(totalThickness() + distance, 0) - QPoint(0, m_offset + height())); break; case Qt::AlignLeft: default: position = - QPoint(QPoint(screenGeometry.x() + screenGeometry.width(), screenGeometry.y()) - QPoint(thickness() + distance, 0) + QPoint(0, m_offset)); + QPoint(QPoint(screenGeometry.x() + screenGeometry.width(), screenGeometry.y()) - QPoint(totalThickness() + distance, 0) + QPoint(0, m_offset)); } break; @@ -534,17 +574,17 @@ QRect PanelView::geometryByDistance(int distance) const default: switch (m_alignment) { case Qt::AlignCenter: - position = QPoint(QPoint(screenGeometry.center().x(), screenGeometry.bottom() - thickness() - distance) + QPoint(m_offset - width() / 2, 1)); + position = QPoint(QPoint(screenGeometry.center().x(), screenGeometry.bottom() - totalThickness() - distance) + QPoint(m_offset - width() / 2, 1)); break; case Qt::AlignRight: - position = QPoint(screenGeometry.bottomRight() - QPoint(0, thickness() + distance) - QPoint(m_offset + width(), -1)); + position = QPoint(screenGeometry.bottomRight() - QPoint(0, totalThickness() + distance) - QPoint(m_offset + width(), -1)); break; case Qt::AlignLeft: default: - position = QPoint(screenGeometry.bottomLeft() - QPoint(0, thickness() + distance) + QPoint(m_offset, 1)); + position = QPoint(screenGeometry.bottomLeft() - QPoint(0, totalThickness() + distance) + QPoint(m_offset, 1)); } } - QRect ret = formFactor() == Plasma::Types::Vertical ? QRect(position, QSize(thickness(), height())) : QRect(position, QSize(width(), thickness())); + QRect ret = formFactor() == Plasma::Types::Vertical ? QRect(position, QSize(totalThickness(), height())) : QRect(position, QSize(width(), totalThickness())); ret = ret.intersected(screenGeometry); return ret; } @@ -569,15 +609,15 @@ void PanelView::resizePanel() if (formFactor() == Plasma::Types::Vertical) { const int minSize = qMax(MINSIZE, m_minLength); const int maxSize = qMin(m_maxLength, m_screenToFollow->size().height() - m_offset); - targetMinSize = QSize(thickness(), minSize); - targetMaxSize = QSize(thickness(), maxSize); - targetSize = QSize(thickness(), qBound(minSize, m_contentLength, maxSize)); + targetMinSize = QSize(totalThickness(), minSize); + targetMaxSize = QSize(totalThickness(), maxSize); + targetSize = QSize(totalThickness(), qBound(minSize, m_contentLength, maxSize)); } else { const int minSize = qMax(MINSIZE, m_minLength); const int maxSize = qMin(m_maxLength, m_screenToFollow->size().width() - m_offset); - targetMinSize = QSize(minSize, thickness()); - targetMaxSize = QSize(maxSize, thickness()); - targetSize = QSize(qBound(minSize, m_contentLength, maxSize), thickness()); + targetMinSize = QSize(minSize, totalThickness()); + targetMaxSize = QSize(maxSize, totalThickness()); + targetSize = QSize(std::clamp(m_contentLength, minSize, maxSize), totalThickness()); } if (minimumSize() != targetMinSize) { setMinimumSize(targetMinSize); @@ -617,6 +657,7 @@ void PanelView::restore() m_offset = qMax(0, m_offset); } + setFloating((bool)config().parent().readEntry("floating", configDefaults().parent().readEntry("floating", false))); setThickness(readConfigValueWithFallBack("thickness", m_thickness)); const QSize screenSize = m_screenToFollow->size(); @@ -1049,6 +1090,7 @@ bool PanelView::event(QEvent *e) case QPlatformSurfaceEvent::SurfaceCreated: setupWaylandIntegration(); PanelShadows::self()->addWindow(this, enabledBorders()); + updateEnabledBorders(); break; case QPlatformSurfaceEvent::SurfaceAboutToBeDestroyed: delete m_shellSurface; @@ -1108,9 +1150,10 @@ void PanelView::updateMask() const QVariant maskProperty = rootObject->property("panelMask"); if (static_cast(maskProperty.type()) == QMetaType::QRegion) { mask = maskProperty.value(); + mask.translate(rootObject->property("maskOffsetX").toInt(), + rootObject->property("maskOffsetY").toInt()); } } - KWindowEffects::enableBlurBehind(this, m_theme.blurBehindEnabled(), mask); KWindowEffects::enableBackgroundContrast(this, m_theme.backgroundContrastEnabled(), @@ -1217,28 +1260,28 @@ void PanelView::updateStruts() switch (location()) { case Plasma::Types::TopEdge: - strut.top_width = thickness() + topOffset; + strut.top_width = totalThickness() + topOffset; strut.top_start = x(); strut.top_end = x() + width() - 1; // qDebug() << "setting top edge to" << strut.top_width << strut.top_start << strut.top_end; break; case Plasma::Types::BottomEdge: - strut.bottom_width = thickness() + bottomOffset; + strut.bottom_width = totalThickness() + bottomOffset; strut.bottom_start = x(); strut.bottom_end = x() + width() - 1; // qDebug() << "setting bottom edge to" << strut.bottom_width << strut.bottom_start << strut.bottom_end; break; case Plasma::Types::RightEdge: - strut.right_width = thickness() + rightOffset; + strut.right_width = totalThickness() + rightOffset; strut.right_start = y(); strut.right_end = y() + height() - 1; // qDebug() << "setting right edge to" << strut.right_width << strut.right_start << strut.right_end; break; case Plasma::Types::LeftEdge: - strut.left_width = thickness() + leftOffset; + strut.left_width = totalThickness() + leftOffset; strut.left_start = y(); strut.left_end = y() + height() - 1; // qDebug() << "setting left edge to" << strut.left_width << strut.left_start << strut.left_end; @@ -1305,13 +1348,24 @@ void PanelView::handleQmlStatusChange(QQmlComponent::Status status) disconnect(this, &QuickViewSharedEngine::statusChanged, this, &PanelView::handleQmlStatusChange); updatePadding(); - int paddingSignal = rootObject->metaObject()->indexOfSignal(SIGNAL(bottomPaddingChanged())); + updateFloating(); + int paddingSignal = rootObject->metaObject()->indexOfSignal("bottomPaddingChanged()"); if (paddingSignal >= 0) { connect(rootObject, SIGNAL(bottomPaddingChanged()), this, SLOT(updatePadding())); connect(rootObject, SIGNAL(topPaddingChanged()), this, SLOT(updatePadding())); connect(rootObject, SIGNAL(rightPaddingChanged()), this, SLOT(updatePadding())); connect(rootObject, SIGNAL(leftPaddingChanged()), this, SLOT(updatePadding())); } + const int floatingSignal = rootObject->metaObject()->indexOfSignal("bottomFloatingPaddingChanged()"); + if (floatingSignal >= 0) { + connect(rootObject, SIGNAL(bottomFloatingPaddingChanged()), this, SLOT(updateFloating())); + connect(rootObject, SIGNAL(topFloatingPaddingChanged()), this, SLOT(updateFloating())); + connect(rootObject, SIGNAL(rightFloatingPaddingChanged()), this, SLOT(updateFloating())); + connect(rootObject, SIGNAL(leftFloatingPaddingChanged()), this, SLOT(updateFloating())); + connect(rootObject, SIGNAL(hasShadowsChanged()), this, SLOT(updateShadows())); + connect(rootObject, SIGNAL(maskOffsetXChanged()), this, SLOT(updateMask())); + connect(rootObject, SIGNAL(maskOffsetYChanged()), this, SLOT(updateMask())); + } const QVariant maskProperty = rootObject->property("panelMask"); if (static_cast(maskProperty.type()) == QMetaType::QRegion) { @@ -1394,7 +1448,6 @@ bool PanelView::edgeActivated() const void PanelView::updateEnabledBorders() { Plasma::FrameSvg::EnabledBorders borders = Plasma::FrameSvg::AllBorders; - if (m_backgroundHints == Plasma::Types::NoBackground) { borders = Plasma::FrameSvg::NoBorder; } else { @@ -1448,4 +1501,32 @@ void PanelView::updatePadding() m_bottomPadding = rootObject()->property("bottomPadding").toInt(); } +void PanelView::updateShadows() +{ + if (!rootObject()) { + return; + } + bool hasShadows = rootObject()->property("hasShadows").toBool(); + if (hasShadows) { + PanelShadows::self()->addWindow(this, enabledBorders()); + } else { + PanelShadows::self()->removeWindow(this); + } +} + +void PanelView::updateFloating() +{ + if (!rootObject()) { + return; + } + m_leftFloatingPadding = rootObject()->property("leftFloatingPadding").toInt(); + m_rightFloatingPadding = rootObject()->property("rightFloatingPadding").toInt(); + m_topFloatingPadding = rootObject()->property("topFloatingPadding").toInt(); + m_bottomFloatingPadding = rootObject()->property("bottomFloatingPadding").toInt(); + + positionPanel(); + resizePanel(); + updateMask(); +} + #include "moc_panelview.cpp" diff --git a/shell/panelview.h b/shell/panelview.h index ee056121e..d5072a06b 100644 --- a/shell/panelview.h +++ b/shell/panelview.h @@ -99,6 +99,12 @@ class PanelView : public PlasmaQuick::ContainmentView */ Q_PROPERTY(bool adaptiveOpacityEnabled READ adaptiveOpacityEnabled NOTIFY adaptiveOpacityEnabledChanged) + /** + * Property that determines whether the panel is currently floating or not + * @since 5.25 + */ + Q_PROPERTY(int floating READ floating WRITE setFloating NOTIFY floatingChanged) + public: enum VisibilityMode { NormalPanel = 0, /** default, always visible panel, the windowmanager reserves a places for it */ @@ -133,6 +139,7 @@ public: int thickness() const; void setThickness(int thickness); + int totalThickness() const; int length() const; void setLength(int value); @@ -146,6 +153,9 @@ public: int distance() const; void setDistance(int dist); + bool floating() const; + void setFloating(bool floating); + Plasma::Types::BackgroundHints backgroundHints() const; void setBackgroundHints(Plasma::Types::BackgroundHints hint); @@ -194,6 +204,7 @@ Q_SIGNALS: void distanceChanged(); void backgroundHintsChanged(); void enabledBordersChanged(); + void floatingChanged(); // QWindow does not have a property for screen. Adding this property requires re-implementing the signal void screenToFollowChanged(QScreen *screen); @@ -221,6 +232,8 @@ private Q_SLOTS: void updateMask(); void updateEnabledBorders(); void updatePadding(); + void updateFloating(); + void updateShadows(); private: int readConfigValueWithFallBack(const QString &key, int defaultValue); @@ -243,7 +256,12 @@ private: int m_topPadding; int m_leftPadding; int m_rightPadding; + int m_bottomFloatingPadding; + int m_topFloatingPadding; + int m_leftFloatingPadding; + int m_rightFloatingPadding; bool m_initCompleted; + bool m_floating; bool m_containsMouse = false; bool m_fakeEventPending = false; Qt::Alignment m_alignment; diff --git a/shell/shellcorona.cpp b/shell/shellcorona.cpp index 9d03612e1..acc86e6f0 100644 --- a/shell/shellcorona.cpp +++ b/shell/shellcorona.cpp @@ -478,7 +478,7 @@ QByteArray ShellCorona::dumpCurrentLayoutJS() const const qreal height = // If we do not have a panel, fallback to 4 units - !view ? 4 : (qreal)view->thickness() / gridUnit; + !view ? 4 : (qreal)view->totalThickness() / gridUnit; panelJson.insert("height", height); if (view) { @@ -1064,16 +1064,16 @@ QRect ShellCorona::_availableScreenRect(int id) const if (v->isVisible() && v->screen() == view->screen() && v->visibilityMode() != PanelView::AutoHide) { switch (v->location()) { case Plasma::Types::LeftEdge: - r.setLeft(r.left() + v->thickness()); + r.setLeft(r.left() + v->totalThickness()); break; case Plasma::Types::RightEdge: - r.setRight(r.right() - v->thickness()); + r.setRight(r.right() - v->totalThickness()); break; case Plasma::Types::TopEdge: - r.setTop(r.top() + v->thickness()); + r.setTop(r.top() + v->totalThickness()); break; case Plasma::Types::BottomEdge: - r.setBottom(r.bottom() - v->thickness()); + r.setBottom(r.bottom() - v->totalThickness()); default: break; }