File indexing completed on 2025-03-09 05:02:43
0001 /* 0002 SPDX-FileCopyrightText: 2023 David Edmundson <davidedmundson@kde.org> 0003 SPDX-License-Identifier: LGPL-2.0-or-later 0004 */ 0005 0006 #include "plasmawindow.h" 0007 0008 #include "dialogshadows_p.h" 0009 #include "private/dialogbackground_p.h" 0010 0011 #include <QMarginsF> 0012 #include <QQuickItem> 0013 0014 #include <KWindowEffects> 0015 #include <KWindowSystem> 0016 #include <KX11Extras> 0017 0018 #include <Plasma/Theme> 0019 0020 using namespace Plasma; 0021 0022 namespace PlasmaQuick 0023 { 0024 class PlasmaWindowPrivate 0025 { 0026 public: 0027 PlasmaWindowPrivate(PlasmaWindow *_q) 0028 : q(_q) 0029 { 0030 } 0031 void handleFrameChanged(); 0032 void updateMainItemGeometry(); 0033 PlasmaWindow *q; 0034 DialogShadows *shadows; 0035 QPointer<QQuickItem> mainItem; 0036 DialogBackground *dialogBackground; 0037 PlasmaWindow::BackgroundHints backgroundHints = PlasmaWindow::StandardBackground; 0038 }; 0039 0040 PlasmaWindow::PlasmaWindow(const QString &svgPrefix) 0041 : QQuickWindow() 0042 , d(new PlasmaWindowPrivate(this)) 0043 { 0044 setColor(QColor(Qt::transparent)); 0045 setFlags(Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint); 0046 0047 d->shadows = DialogShadows::instance(svgPrefix); 0048 d->dialogBackground = new DialogBackground(contentItem()); 0049 d->dialogBackground->setImagePath(svgPrefix); 0050 connect(d->dialogBackground, &DialogBackground::fixedMarginsChanged, this, [this]() { 0051 d->updateMainItemGeometry(); 0052 Q_EMIT paddingChanged(); 0053 }); 0054 connect(d->dialogBackground, &DialogBackground::maskChanged, this, [this]() { 0055 d->handleFrameChanged(); 0056 }); 0057 0058 d->shadows->addWindow(this, d->dialogBackground->enabledBorders()); 0059 } 0060 0061 PlasmaWindow::~PlasmaWindow() 0062 { 0063 } 0064 0065 void PlasmaWindow::setMainItem(QQuickItem *mainItem) 0066 { 0067 if (d->mainItem == mainItem) 0068 return; 0069 0070 if (d->mainItem) { 0071 d->mainItem->setParentItem(nullptr); 0072 } 0073 0074 d->mainItem = mainItem; 0075 Q_EMIT mainItemChanged(); 0076 0077 if (d->mainItem) { 0078 mainItem->setParentItem(contentItem()); 0079 d->updateMainItemGeometry(); 0080 } 0081 } 0082 0083 QQuickItem *PlasmaWindow::mainItem() const 0084 { 0085 return d->mainItem; 0086 } 0087 0088 static KSvg::FrameSvg::EnabledBorders edgeToBorder(Qt::Edges edges) 0089 { 0090 KSvg::FrameSvg::EnabledBorders borders = KSvg::FrameSvg::EnabledBorders(0); 0091 0092 if (edges & Qt::Edge::TopEdge) { 0093 borders |= KSvg::FrameSvg::EnabledBorder::TopBorder; 0094 } 0095 if (edges & Qt::Edge::BottomEdge) { 0096 borders |= KSvg::FrameSvg::EnabledBorder::BottomBorder; 0097 } 0098 if (edges & Qt::Edge::LeftEdge) { 0099 borders |= KSvg::FrameSvg::EnabledBorder::LeftBorder; 0100 } 0101 if (edges & Qt::Edge::RightEdge) { 0102 borders |= KSvg::FrameSvg::EnabledBorder::RightBorder; 0103 } 0104 0105 return borders; 0106 } 0107 0108 static Qt::Edges bordersToEdge(KSvg::FrameSvg::EnabledBorders borders) 0109 { 0110 Qt::Edges edges; 0111 if (borders & KSvg::FrameSvg::EnabledBorder::TopBorder) { 0112 edges |= Qt::Edge::TopEdge; 0113 } 0114 if (borders & KSvg::FrameSvg::EnabledBorder::BottomBorder) { 0115 edges |= Qt::Edge::BottomEdge; 0116 } 0117 if (borders & KSvg::FrameSvg::EnabledBorder::LeftBorder) { 0118 edges |= Qt::Edge::LeftEdge; 0119 } 0120 if (borders & KSvg::FrameSvg::EnabledBorder::RightBorder) { 0121 edges |= Qt::Edge::RightEdge; 0122 } 0123 return edges; 0124 } 0125 0126 void PlasmaWindow::setBorders(Qt::Edges bordersToShow) 0127 { 0128 d->dialogBackground->setEnabledBorders(edgeToBorder(bordersToShow)); 0129 d->shadows->setEnabledBorders(this, d->dialogBackground->enabledBorders()); 0130 Q_EMIT bordersChanged(); 0131 } 0132 0133 Qt::Edges PlasmaWindow::borders() 0134 { 0135 return bordersToEdge(d->dialogBackground->enabledBorders()); 0136 } 0137 0138 void PlasmaWindow::showEvent(QShowEvent *e) 0139 { 0140 // EWMH states that the state is reset every hide 0141 // Qt supports external factors setting state before the next show 0142 if (KWindowSystem::isPlatformX11()) { 0143 KX11Extras::setState(winId(), NET::SkipTaskbar | NET::SkipPager | NET::SkipSwitcher); 0144 } 0145 QQuickWindow::showEvent(e); 0146 } 0147 0148 void PlasmaWindow::resizeEvent(QResizeEvent *e) 0149 { 0150 QQuickWindow::resizeEvent(e); 0151 const QSize windowSize = e->size(); 0152 d->dialogBackground->setSize(windowSize); 0153 if (d->mainItem) { 0154 const QSize contentSize = windowSize.shrunkBy(padding()); 0155 d->mainItem->setSize(contentSize); 0156 } 0157 } 0158 0159 void PlasmaWindowPrivate::handleFrameChanged() 0160 { 0161 auto theme = Plasma::Theme(); 0162 const QRegion mask = dialogBackground->mask(); 0163 KWindowEffects::enableBlurBehind(q, theme.blurBehindEnabled(), mask); 0164 KWindowEffects::enableBackgroundContrast(q, 0165 theme.backgroundContrastEnabled(), 0166 theme.backgroundContrast(), 0167 theme.backgroundIntensity(), 0168 theme.backgroundSaturation(), 0169 mask); 0170 0171 if (!KWindowSystem::isPlatformX11() || KX11Extras::compositingActive()) { 0172 q->setMask(QRegion()); 0173 } else { 0174 q->setMask(mask); 0175 } 0176 } 0177 0178 void PlasmaWindowPrivate::updateMainItemGeometry() 0179 { 0180 if (!mainItem) { 0181 return; 0182 } 0183 const QMargins frameMargins = q->padding(); 0184 const QSize windowSize = q->size(); 0185 0186 mainItem->setX(frameMargins.left()); 0187 mainItem->setY(frameMargins.top()); 0188 0189 const QSize contentSize = windowSize.shrunkBy(frameMargins); 0190 mainItem->setSize(contentSize); 0191 } 0192 0193 QMargins PlasmaWindow::padding() const 0194 { 0195 return QMargins(d->dialogBackground->leftMargin(), 0196 d->dialogBackground->topMargin(), 0197 d->dialogBackground->rightMargin(), 0198 d->dialogBackground->bottomMargin()); 0199 } 0200 0201 PlasmaWindow::BackgroundHints PlasmaWindow::backgroundHints() const 0202 { 0203 return d->backgroundHints; 0204 } 0205 0206 void PlasmaWindow::setBackgroundHints(BackgroundHints hints) 0207 { 0208 if (d->backgroundHints == hints) { 0209 return; 0210 } 0211 d->backgroundHints = hints; 0212 0213 auto prefix = QStringLiteral(""); 0214 if (d->backgroundHints == PlasmaWindow::SolidBackground) { 0215 prefix = QStringLiteral("solid/"); 0216 } 0217 d->dialogBackground->setImagePath(prefix + QStringLiteral("dialogs/background")); 0218 0219 Q_EMIT backgroundHintsChanged(); 0220 } 0221 0222 qreal PlasmaWindow::topPadding() const 0223 { 0224 return d->dialogBackground->topMargin(); 0225 } 0226 0227 qreal PlasmaWindow::bottomPadding() const 0228 { 0229 return d->dialogBackground->bottomMargin(); 0230 } 0231 0232 qreal PlasmaWindow::leftPadding() const 0233 { 0234 return d->dialogBackground->leftMargin(); 0235 } 0236 0237 qreal PlasmaWindow::rightPadding() const 0238 { 0239 return d->dialogBackground->rightMargin(); 0240 } 0241 } 0242 0243 #include "moc_plasmawindow.cpp"