File indexing completed on 2024-04-21 05:31:05

0001 /*
0002     SPDX-FileCopyrightText: 2021 Michail Vourlakos <mvourlakos@gmail.com>
0003     SPDX-License-Identifier: GPL-2.0-or-later
0004 */
0005 
0006 #include "widgetexplorerview.h"
0007 
0008 // local
0009 #include "../panelshadows_p.h"
0010 #include "../view.h"
0011 #include "../../lattecorona.h"
0012 #include "../../wm/abstractwindowinterface.h"
0013 
0014 // Qt
0015 #include <QQuickItem>
0016 #include <QScreen>
0017 
0018 // KDE
0019 #include <KWindowEffects>
0020 #include <KWindowSystem>
0021 #include <KWayland/Client/plasmashell.h>
0022 
0023 // Plasma
0024 #include <Plasma/Package>
0025 
0026 namespace Latte {
0027 namespace ViewPart {
0028 
0029 WidgetExplorerView::WidgetExplorerView(Latte::View *view)
0030     : SubConfigView(view, QString("#widgetexplorerview#"), true)
0031 {
0032     setResizeMode(QQuickView::SizeRootObjectToView);
0033     //!set flags early in order for wayland to initialize properly
0034     setFlags(wFlags());
0035 
0036     connect(this, &QQuickView::widthChanged, this, &WidgetExplorerView::updateEffects);
0037     connect(this, &QQuickView::heightChanged, this, &WidgetExplorerView::updateEffects);
0038 
0039     connect(this, &QQuickView::statusChanged, [&](QQuickView::Status status) {
0040         if (status == QQuickView::Ready) {
0041             updateEffects();
0042         }
0043     });
0044 
0045     setParentView(view);
0046     init();
0047 }
0048 
0049 void WidgetExplorerView::init()
0050 {
0051     SubConfigView::init();
0052 
0053     QByteArray tempFilePath = "widgetexplorerui";
0054 
0055     updateEnabledBorders();
0056 
0057     auto source = QUrl::fromLocalFile(m_latteView->containment()->corona()->kPackage().filePath(tempFilePath));
0058     setSource(source);
0059     syncGeometry();
0060 }
0061 
0062 bool WidgetExplorerView::hideOnWindowDeactivate() const
0063 {
0064     return m_hideOnWindowDeactivate;
0065 }
0066 
0067 void WidgetExplorerView::setHideOnWindowDeactivate(bool hide)
0068 {
0069     if (m_hideOnWindowDeactivate == hide) {
0070         return;
0071     }
0072 
0073     m_hideOnWindowDeactivate = hide;
0074     emit hideOnWindowDeactivateChanged();
0075 }
0076 
0077 Qt::WindowFlags WidgetExplorerView::wFlags() const
0078 {
0079     return (flags() | Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint);
0080 }
0081 
0082 QRect WidgetExplorerView::geometryWhenVisible() const
0083 {
0084     return m_geometryWhenVisible;
0085 }
0086 
0087 void WidgetExplorerView::initParentView(Latte::View *view)
0088 {
0089     SubConfigView::initParentView(view);
0090 
0091     rootContext()->setContextProperty(QStringLiteral("containmentFromView"), m_latteView->containment());
0092     rootContext()->setContextProperty(QStringLiteral("latteView"), m_latteView);
0093 
0094     updateEnabledBorders();
0095     syncGeometry();
0096 }
0097 
0098 QRect WidgetExplorerView::availableScreenGeometry() const
0099 {
0100     int currentScrId = m_latteView->positioner()->currentScreenId();
0101 
0102     QList<Latte::Types::Visibility> ignoreModes{Latte::Types::SidebarOnDemand,Latte::Types::SidebarAutoHide};
0103 
0104     if (m_latteView->visibility() && m_latteView->visibility()->isSidebar()) {
0105         ignoreModes.removeAll(Latte::Types::SidebarOnDemand);
0106         ignoreModes.removeAll(Latte::Types::SidebarAutoHide);
0107     }
0108 
0109     QString activityid = m_latteView->layout()->lastUsedActivity();
0110 
0111     return m_corona->availableScreenRectWithCriteria(currentScrId, activityid, ignoreModes, {}, false, true);
0112 }
0113 
0114 void WidgetExplorerView::syncGeometry()
0115 {
0116     if (!m_latteView || !m_latteView->layout() || !m_latteView->containment() || !rootObject()) {
0117         return;
0118     }
0119     const QSize size(rootObject()->width(), rootObject()->height());
0120     auto availGeometry = availableScreenGeometry();
0121 
0122     int margin = availGeometry.height() == m_latteView->screenGeometry().height() ? 100 : 0;
0123     auto geometry = QRect(availGeometry.x(), availGeometry.y(), size.width(), availGeometry.height()-margin);
0124 
0125     updateEnabledBorders();
0126 
0127     if (m_geometryWhenVisible == geometry) {
0128         return;
0129     }
0130 
0131     m_geometryWhenVisible = geometry;
0132 
0133     setPosition(geometry.topLeft());
0134 
0135     if (m_shellSurface) {
0136         m_shellSurface->setPosition(geometry.topLeft());
0137     }
0138 
0139     setMaximumSize(geometry.size());
0140     setMinimumSize(geometry.size());
0141     resize(geometry.size());
0142 }
0143 
0144 void WidgetExplorerView::showEvent(QShowEvent *ev)
0145 {
0146     if (m_shellSurface) {
0147         //! under wayland it needs to be set again after its hiding
0148         m_shellSurface->setPosition(m_geometryWhenVisible.topLeft());
0149     }
0150 
0151     SubConfigView::showEvent(ev);
0152 
0153     if (!m_latteView) {
0154         return;
0155     }
0156 
0157     syncGeometry();
0158 
0159     requestActivate();
0160 
0161     m_screenSyncTimer.start();
0162     QTimer::singleShot(400, this, &WidgetExplorerView::syncGeometry);
0163 
0164     emit showSignal();
0165 }
0166 
0167 void WidgetExplorerView::focusOutEvent(QFocusEvent *ev)
0168 {
0169     Q_UNUSED(ev);
0170 
0171     if (!m_latteView) {
0172         return;
0173     }
0174 
0175     hideConfigWindow();
0176 }
0177 
0178 void WidgetExplorerView::updateEffects()
0179 {
0180     //! Don't apply any effect before the wayland surface is created under wayland
0181     //! https://bugs.kde.org/show_bug.cgi?id=392890
0182     if (KWindowSystem::isPlatformWayland() && !m_shellSurface) {
0183         return;
0184     }
0185 
0186     if (!m_background) {
0187         m_background = new Plasma::FrameSvg(this);
0188     }
0189 
0190     if (m_background->imagePath() != "dialogs/background") {
0191         m_background->setImagePath(QStringLiteral("dialogs/background"));
0192     }
0193 
0194     m_background->setEnabledBorders(m_enabledBorders);
0195     m_background->resizeFrame(size());
0196 
0197     QRegion mask = m_background->mask();
0198 
0199     QRegion fixedMask = mask.isNull() ? QRegion(QRect(0,0,width(),height())) : mask;
0200 
0201     if (!fixedMask.isEmpty()) {
0202         setMask(fixedMask);
0203     } else {
0204         setMask(QRegion());
0205     }
0206 
0207     if (KWindowSystem::compositingActive()) {
0208         KWindowEffects::enableBlurBehind(winId(), true, fixedMask);
0209     } else {
0210         KWindowEffects::enableBlurBehind(winId(), false);
0211     }
0212 }
0213 
0214 void WidgetExplorerView::hideConfigWindow()
0215 {
0216     if (!m_hideOnWindowDeactivate) {
0217         return;
0218     }
0219 
0220     deleteLater();
0221 
0222     /*QTimer::singleShot(100, [this]() {
0223         //! avoid crashes under wayland because some mouse events are sended after the surface is destroyed
0224 
0225         if (m_shellSurface) {
0226             //!NOTE: Avoid crash in wayland environment with qt5.9
0227             close();
0228         } else {
0229             hide();
0230         }
0231     });*/
0232 }
0233 
0234 void WidgetExplorerView::syncSlideEffect()
0235 {
0236     if (!m_latteView || !m_latteView->containment()) {
0237         return;
0238     }
0239 
0240     auto slideLocation = WindowSystem::AbstractWindowInterface::Slide::Left;
0241 
0242     m_corona->wm()->slideWindow(*this, slideLocation);
0243 }
0244 
0245 //!BEGIN borders
0246 void WidgetExplorerView::updateEnabledBorders()
0247 {
0248     if (!this->screen()) {
0249         return;
0250     }
0251 
0252     Plasma::FrameSvg::EnabledBorders borders = Plasma::FrameSvg::AllBorders;
0253 
0254     if (!m_geometryWhenVisible.isEmpty()) {
0255         if (m_geometryWhenVisible.x() == m_latteView->screenGeometry().x()) {
0256             borders &= ~Plasma::FrameSvg::LeftBorder;
0257         }
0258 
0259         if (m_geometryWhenVisible.y() == m_latteView->screenGeometry().y()) {
0260             borders &= ~Plasma::FrameSvg::TopBorder;
0261         }
0262 
0263         if (m_geometryWhenVisible.height() == m_latteView->screenGeometry().height()) {
0264             borders &= ~Plasma::FrameSvg::BottomBorder;
0265         }
0266     }
0267 
0268     if (m_enabledBorders != borders) {
0269         if (isVisible()) {
0270             m_enabledBorders = borders;
0271         }
0272         m_corona->dialogShadows()->addWindow(this, m_enabledBorders);
0273 
0274         emit enabledBordersChanged();
0275     }
0276 }
0277 
0278 //!END borders
0279 
0280 }
0281 }
0282