File indexing completed on 2025-04-20 10:59:45
0001 /* 0002 SPDX-FileCopyrightText: 2018 Michail Vourlakos <mvourlakos@gmail.com> 0003 SPDX-License-Identifier: GPL-2.0-or-later 0004 */ 0005 0006 #include "secondaryconfigview.h" 0007 0008 // local 0009 #include <config-latte.h> 0010 #include "primaryconfigview.h" 0011 #include "../panelshadows_p.h" 0012 #include "../view.h" 0013 #include "../../lattecorona.h" 0014 #include "../../wm/abstractwindowinterface.h" 0015 0016 // Qt 0017 #include <QQuickItem> 0018 #include <QQmlContext> 0019 #include <QQmlEngine> 0020 #include <QScreen> 0021 0022 // KDE 0023 #include <KLocalizedContext> 0024 #include <KDeclarative/KDeclarative> 0025 #include <KWayland/Client/plasmashell.h> 0026 #include <KWayland/Client/surface.h> 0027 #include <KWindowEffects> 0028 #include <KWindowSystem> 0029 0030 // Plasma 0031 #include <Plasma/Package> 0032 0033 namespace Latte { 0034 namespace ViewPart { 0035 0036 SecondaryConfigView::SecondaryConfigView(Latte::View *view, PrimaryConfigView *parent) 0037 : SubConfigView(view, QString("#secondaryconfigview#")), 0038 m_parent(parent) 0039 { 0040 connect(this, &QQuickView::widthChanged, this, &SecondaryConfigView::updateEffects); 0041 connect(this, &QQuickView::heightChanged, this, &SecondaryConfigView::updateEffects); 0042 0043 connect(this, &QQuickView::statusChanged, [&](QQuickView::Status status) { 0044 if (status == QQuickView::Ready) { 0045 updateEffects(); 0046 } 0047 }); 0048 0049 connections << connect(m_parent, &PrimaryConfigView::availableScreenGeometryChanged, this, &SecondaryConfigView::syncGeometry); 0050 0051 setParentView(view); 0052 init(); 0053 } 0054 0055 void SecondaryConfigView::init() 0056 { 0057 SubConfigView::init(); 0058 0059 QByteArray tempFilePath = "lattedocksecondaryconfigurationui"; 0060 0061 updateEnabledBorders(); 0062 0063 auto source = QUrl::fromLocalFile(m_latteView->containment()->corona()->kPackage().filePath(tempFilePath)); 0064 setSource(source); 0065 syncGeometry(); 0066 0067 if (m_parent && KWindowSystem::isPlatformX11()) { 0068 m_parent->requestActivate(); 0069 } 0070 } 0071 0072 QRect SecondaryConfigView::geometryWhenVisible() const 0073 { 0074 return m_geometryWhenVisible; 0075 } 0076 0077 void SecondaryConfigView::initParentView(Latte::View *view) 0078 { 0079 SubConfigView::initParentView(view); 0080 0081 rootContext()->setContextProperty(QStringLiteral("primaryConfigView"), m_parent); 0082 0083 updateEnabledBorders(); 0084 syncGeometry(); 0085 } 0086 0087 void SecondaryConfigView::syncGeometry() 0088 { 0089 if (!m_latteView || !m_latteView->layout() || !m_latteView->containment() || !m_parent || !rootObject()) { 0090 return; 0091 } 0092 0093 const QSize size(rootObject()->width(), rootObject()->height()); 0094 const auto location = m_latteView->containment()->location(); 0095 const auto scrGeometry = m_latteView->screenGeometry(); 0096 const auto availGeometry = m_parent->availableScreenGeometry(); 0097 const auto canvasGeometry = m_latteView->positioner()->canvasGeometry(); 0098 0099 int canvasThickness = m_latteView->formFactor() == Plasma::Types::Vertical ? canvasGeometry.width() : canvasGeometry.height(); 0100 0101 int secondaryConfigSpacing = 2 * m_latteView->fontPixelSize(); 0102 0103 QPoint position{0, 0}; 0104 0105 int xPos{0}; 0106 int yPos{0}; 0107 0108 switch (m_latteView->containment()->formFactor()) { 0109 case Plasma::Types::Horizontal: { 0110 if (qApp->isLeftToRight()) { 0111 xPos = availGeometry.x() + secondaryConfigSpacing; 0112 } else { 0113 xPos = availGeometry.x() + availGeometry.width() - size.width() - secondaryConfigSpacing; 0114 } 0115 0116 if (location == Plasma::Types::TopEdge) { 0117 yPos = scrGeometry.y() + canvasThickness; 0118 } else if (location == Plasma::Types::BottomEdge) { 0119 yPos = scrGeometry.y() + scrGeometry.height() - canvasThickness - size.height(); 0120 } 0121 } 0122 break; 0123 0124 case Plasma::Types::Vertical: { 0125 yPos = availGeometry.y() + secondaryConfigSpacing; 0126 0127 if (location == Plasma::Types::LeftEdge) { 0128 xPos = scrGeometry.x() + canvasThickness; 0129 } else if (location == Plasma::Types::RightEdge) { 0130 xPos = scrGeometry.x() + scrGeometry.width() - canvasThickness - size.width(); 0131 } 0132 } 0133 break; 0134 0135 default: 0136 qWarning() << "no sync geometry, wrong formFactor"; 0137 break; 0138 } 0139 0140 position = {xPos, yPos}; 0141 0142 updateEnabledBorders(); 0143 0144 auto geometry = QRect(position.x(), position.y(), size.width(), size.height()); 0145 0146 if (m_geometryWhenVisible == geometry) { 0147 return; 0148 } 0149 0150 m_geometryWhenVisible = geometry; 0151 0152 setPosition(position); 0153 0154 if (m_shellSurface) { 0155 m_shellSurface->setPosition(position); 0156 } 0157 0158 setMaximumSize(size); 0159 setMinimumSize(size); 0160 resize(size); 0161 0162 //! after placement request to activate the main config window in order to avoid 0163 //! rare cases of closing settings window from secondaryConfigView->focusOutEvent 0164 if (m_parent && KWindowSystem::isPlatformX11()) { 0165 m_parent->requestActivate(); 0166 } 0167 } 0168 0169 void SecondaryConfigView::showEvent(QShowEvent *ev) 0170 { 0171 if (m_shellSurface) { 0172 //! under wayland it needs to be set again after its hiding 0173 m_shellSurface->setPosition(m_geometryWhenVisible.topLeft()); 0174 } 0175 0176 SubConfigView::showEvent(ev); 0177 0178 if (!m_latteView) { 0179 return; 0180 } 0181 0182 setFlags(wFlags()); 0183 m_corona->wm()->setViewExtraFlags(this, false, Latte::Types::NormalWindow); 0184 0185 syncGeometry(); 0186 0187 m_screenSyncTimer.start(); 0188 QTimer::singleShot(400, this, &SecondaryConfigView::syncGeometry); 0189 0190 emit showSignal(); 0191 } 0192 0193 void SecondaryConfigView::focusOutEvent(QFocusEvent *ev) 0194 { 0195 Q_UNUSED(ev); 0196 0197 if (!m_latteView) { 0198 return; 0199 } 0200 0201 const auto *focusWindow = qGuiApp->focusWindow(); 0202 0203 if (focusWindow && (focusWindow->flags().testFlag(Qt::Popup) 0204 || focusWindow->flags().testFlag(Qt::ToolTip))) { 0205 return; 0206 } 0207 0208 const auto parent = qobject_cast<PrimaryConfigView *>(m_parent); 0209 0210 if (!parent->hasFocus()) { 0211 parent->hideConfigWindow(); 0212 } 0213 } 0214 0215 void SecondaryConfigView::hideConfigWindow() 0216 { 0217 if (m_shellSurface) { 0218 //!NOTE: Avoid crash in wayland environment with qt5.9 0219 close(); 0220 } else { 0221 hide(); 0222 } 0223 } 0224 0225 void SecondaryConfigView::updateEffects() 0226 { 0227 //! Don't apply any effect before the wayland surface is created under wayland 0228 //! https://bugs.kde.org/show_bug.cgi?id=392890 0229 if (KWindowSystem::isPlatformWayland() && !m_shellSurface) { 0230 return; 0231 } 0232 0233 //! Don't apply any effect before the wayland surface is created under wayland 0234 //! https://bugs.kde.org/show_bug.cgi?id=392890 0235 if (KWindowSystem::isPlatformWayland() && !m_shellSurface) { 0236 return; 0237 } 0238 0239 if (!m_background) { 0240 m_background = new Plasma::FrameSvg(this); 0241 } 0242 0243 if (m_background->imagePath() != "dialogs/background") { 0244 m_background->setImagePath(QStringLiteral("dialogs/background")); 0245 } 0246 0247 m_background->setEnabledBorders(m_enabledBorders); 0248 m_background->resizeFrame(size()); 0249 0250 QRegion mask = m_background->mask(); 0251 0252 QRegion fixedMask = mask.isNull() ? QRegion(QRect(0,0,width(),height())) : mask; 0253 0254 if (!fixedMask.isEmpty()) { 0255 setMask(fixedMask); 0256 } else { 0257 setMask(QRegion()); 0258 } 0259 0260 if (KWindowSystem::compositingActive()) { 0261 KWindowEffects::enableBlurBehind(winId(), true, fixedMask); 0262 } else { 0263 KWindowEffects::enableBlurBehind(winId(), false); 0264 } 0265 } 0266 0267 //!BEGIN borders 0268 void SecondaryConfigView::updateEnabledBorders() 0269 { 0270 if (!this->screen()) { 0271 return; 0272 } 0273 0274 Plasma::FrameSvg::EnabledBorders borders = Plasma::FrameSvg::AllBorders; 0275 0276 switch (m_latteView->location()) { 0277 case Plasma::Types::TopEdge: 0278 borders &= ~Plasma::FrameSvg::TopBorder; 0279 break; 0280 0281 case Plasma::Types::LeftEdge: 0282 borders &= ~Plasma::FrameSvg::LeftBorder; 0283 break; 0284 0285 case Plasma::Types::RightEdge: 0286 borders &= ~Plasma::FrameSvg::RightBorder; 0287 break; 0288 0289 case Plasma::Types::BottomEdge: 0290 borders &= ~Plasma::FrameSvg::BottomBorder; 0291 break; 0292 0293 default: 0294 break; 0295 } 0296 0297 if (m_enabledBorders != borders) { 0298 m_enabledBorders = borders; 0299 0300 m_corona->dialogShadows()->addWindow(this, m_enabledBorders); 0301 0302 emit enabledBordersChanged(); 0303 } 0304 } 0305 0306 //!END borders 0307 0308 } 0309 } 0310