File indexing completed on 2024-11-10 04:56:42

0001 /*
0002     SPDX-FileCopyrightText: 2006 Lubos Lunak <l.lunak@kde.org>
0003     SPDX-FileCopyrightText: 2010, 2011 Martin Gräßlin <mgraesslin@kde.org>
0004 
0005     SPDX-License-Identifier: GPL-2.0-or-later
0006 */
0007 
0008 #include "effect/effectframe.h"
0009 #include "effect/effecthandler.h"
0010 
0011 #include <QQuickItem>
0012 #include <QStandardPaths>
0013 
0014 namespace KWin
0015 {
0016 
0017 EffectFrameQuickScene::EffectFrameQuickScene(EffectFrameStyle style, bool staticSize, QPoint position, Qt::Alignment alignment)
0018     : m_style(style)
0019     , m_static(staticSize)
0020     , m_point(position)
0021     , m_alignment(alignment)
0022 {
0023 
0024     QString name;
0025     switch (style) {
0026     case EffectFrameNone:
0027         name = QStringLiteral("none");
0028         break;
0029     case EffectFrameUnstyled:
0030         name = QStringLiteral("unstyled");
0031         break;
0032     case EffectFrameStyled:
0033         name = QStringLiteral("styled");
0034         break;
0035     }
0036 
0037     const QString defaultPath = QStringLiteral("kwin/frames/plasma/frame_%1.qml").arg(name);
0038     // TODO read from kwinApp()->config() "QmlPath" like Outline/OnScreenNotification
0039     // *if* someone really needs this to be configurable.
0040     const QString path = QStandardPaths::locate(QStandardPaths::GenericDataLocation, defaultPath);
0041 
0042     setSource(QUrl::fromLocalFile(path), QVariantMap{{QStringLiteral("effectFrame"), QVariant::fromValue(this)}});
0043 
0044     if (rootItem()) {
0045         connect(rootItem(), &QQuickItem::implicitWidthChanged, this, &EffectFrameQuickScene::reposition);
0046         connect(rootItem(), &QQuickItem::implicitHeightChanged, this, &EffectFrameQuickScene::reposition);
0047     }
0048 }
0049 
0050 EffectFrameQuickScene::~EffectFrameQuickScene() = default;
0051 
0052 EffectFrameStyle EffectFrameQuickScene::style() const
0053 {
0054     return m_style;
0055 }
0056 
0057 bool EffectFrameQuickScene::isStatic() const
0058 {
0059     return m_static;
0060 }
0061 
0062 QFont EffectFrameQuickScene::font() const
0063 {
0064     return m_font;
0065 }
0066 
0067 void EffectFrameQuickScene::setFont(const QFont &font)
0068 {
0069     if (m_font == font) {
0070         return;
0071     }
0072 
0073     m_font = font;
0074     Q_EMIT fontChanged(font);
0075     reposition();
0076 }
0077 
0078 QIcon EffectFrameQuickScene::icon() const
0079 {
0080     return m_icon;
0081 }
0082 
0083 void EffectFrameQuickScene::setIcon(const QIcon &icon)
0084 {
0085     m_icon = icon;
0086     Q_EMIT iconChanged(icon);
0087     reposition();
0088 }
0089 
0090 QSize EffectFrameQuickScene::iconSize() const
0091 {
0092     return m_iconSize;
0093 }
0094 
0095 void EffectFrameQuickScene::setIconSize(const QSize &iconSize)
0096 {
0097     if (m_iconSize == iconSize) {
0098         return;
0099     }
0100 
0101     m_iconSize = iconSize;
0102     Q_EMIT iconSizeChanged(iconSize);
0103     reposition();
0104 }
0105 
0106 QString EffectFrameQuickScene::text() const
0107 {
0108     return m_text;
0109 }
0110 
0111 void EffectFrameQuickScene::setText(const QString &text)
0112 {
0113     if (m_text == text) {
0114         return;
0115     }
0116 
0117     m_text = text;
0118     Q_EMIT textChanged(text);
0119     reposition();
0120 }
0121 
0122 qreal EffectFrameQuickScene::frameOpacity() const
0123 {
0124     return m_frameOpacity;
0125 }
0126 
0127 void EffectFrameQuickScene::setFrameOpacity(qreal frameOpacity)
0128 {
0129     if (m_frameOpacity != frameOpacity) {
0130         m_frameOpacity = frameOpacity;
0131         Q_EMIT frameOpacityChanged(frameOpacity);
0132     }
0133 }
0134 
0135 bool EffectFrameQuickScene::crossFadeEnabled() const
0136 {
0137     return m_crossFadeEnabled;
0138 }
0139 
0140 void EffectFrameQuickScene::setCrossFadeEnabled(bool enabled)
0141 {
0142     if (m_crossFadeEnabled != enabled) {
0143         m_crossFadeEnabled = enabled;
0144         Q_EMIT crossFadeEnabledChanged(enabled);
0145     }
0146 }
0147 
0148 qreal EffectFrameQuickScene::crossFadeProgress() const
0149 {
0150     return m_crossFadeProgress;
0151 }
0152 
0153 void EffectFrameQuickScene::setCrossFadeProgress(qreal progress)
0154 {
0155     if (m_crossFadeProgress != progress) {
0156         m_crossFadeProgress = progress;
0157         Q_EMIT crossFadeProgressChanged(progress);
0158     }
0159 }
0160 
0161 Qt::Alignment EffectFrameQuickScene::alignment() const
0162 {
0163     return m_alignment;
0164 }
0165 
0166 void EffectFrameQuickScene::setAlignment(Qt::Alignment alignment)
0167 {
0168     if (m_alignment == alignment) {
0169         return;
0170     }
0171 
0172     m_alignment = alignment;
0173     reposition();
0174 }
0175 
0176 QPoint EffectFrameQuickScene::position() const
0177 {
0178     return m_point;
0179 }
0180 
0181 void EffectFrameQuickScene::setPosition(const QPoint &point)
0182 {
0183     if (m_point == point) {
0184         return;
0185     }
0186 
0187     m_point = point;
0188     reposition();
0189 }
0190 
0191 void EffectFrameQuickScene::reposition()
0192 {
0193     if (!rootItem() || m_point.x() < 0 || m_point.y() < 0) {
0194         return;
0195     }
0196 
0197     QSizeF size;
0198     if (m_static) {
0199         size = rootItem()->size();
0200     } else {
0201         size = QSizeF(rootItem()->implicitWidth(), rootItem()->implicitHeight());
0202     }
0203 
0204     QRect geometry(QPoint(), size.toSize());
0205 
0206     if (m_alignment & Qt::AlignLeft)
0207         geometry.moveLeft(m_point.x());
0208     else if (m_alignment & Qt::AlignRight)
0209         geometry.moveLeft(m_point.x() - geometry.width());
0210     else
0211         geometry.moveLeft(m_point.x() - geometry.width() / 2);
0212     if (m_alignment & Qt::AlignTop)
0213         geometry.moveTop(m_point.y());
0214     else if (m_alignment & Qt::AlignBottom)
0215         geometry.moveTop(m_point.y() - geometry.height());
0216     else
0217         geometry.moveTop(m_point.y() - geometry.height() / 2);
0218 
0219     if (geometry == this->geometry()) {
0220         return;
0221     }
0222 
0223     setGeometry(geometry);
0224 }
0225 
0226 EffectFrame::EffectFrame(EffectFrameStyle style, bool staticSize, QPoint position, Qt::Alignment alignment)
0227     : m_view(new EffectFrameQuickScene(style, staticSize, position, alignment))
0228 {
0229     connect(m_view, &OffscreenQuickScene::repaintNeeded, this, [this] {
0230         effects->addRepaint(geometry());
0231     });
0232     connect(m_view, &OffscreenQuickScene::geometryChanged, this, [](const QRect &oldGeometry, const QRect &newGeometry) {
0233         effects->addRepaint(oldGeometry);
0234         effects->addRepaint(newGeometry);
0235     });
0236 }
0237 
0238 EffectFrame::~EffectFrame()
0239 {
0240     // Effects often destroy their cached TextFrames in pre/postPaintScreen.
0241     // Destroying an OffscreenQuickView changes GL context, which we
0242     // must not do during effect rendering.
0243     // Delay destruction of the view until after the rendering.
0244     m_view->deleteLater();
0245 }
0246 
0247 Qt::Alignment EffectFrame::alignment() const
0248 {
0249     return m_view->alignment();
0250 }
0251 
0252 void EffectFrame::setAlignment(Qt::Alignment alignment)
0253 {
0254     m_view->setAlignment(alignment);
0255 }
0256 
0257 QFont EffectFrame::font() const
0258 {
0259     return m_view->font();
0260 }
0261 
0262 void EffectFrame::setFont(const QFont &font)
0263 {
0264     m_view->setFont(font);
0265 }
0266 
0267 void EffectFrame::free()
0268 {
0269     m_view->hide();
0270 }
0271 
0272 QRect EffectFrame::geometry() const
0273 {
0274     return m_view->geometry();
0275 }
0276 
0277 void EffectFrame::setGeometry(const QRect &geometry, bool force)
0278 {
0279     m_view->setGeometry(geometry);
0280 }
0281 
0282 QIcon EffectFrame::icon() const
0283 {
0284     return m_view->icon();
0285 }
0286 
0287 void EffectFrame::setIcon(const QIcon &icon)
0288 {
0289     m_view->setIcon(icon);
0290 
0291     if (m_view->iconSize().isEmpty() && !icon.availableSizes().isEmpty()) { // Set a size if we don't already have one
0292         setIconSize(icon.availableSizes().constFirst());
0293     }
0294 }
0295 
0296 QSize EffectFrame::iconSize() const
0297 {
0298     return m_view->iconSize();
0299 }
0300 
0301 void EffectFrame::setIconSize(const QSize &size)
0302 {
0303     m_view->setIconSize(size);
0304 }
0305 
0306 void EffectFrame::setPosition(const QPoint &point)
0307 {
0308     m_view->setPosition(point);
0309 }
0310 
0311 void EffectFrame::render(const RenderTarget &renderTarget, const RenderViewport &viewport, const QRegion &region, double opacity, double frameOpacity)
0312 {
0313     if (!m_view->rootItem()) {
0314         return;
0315     }
0316 
0317     m_view->show();
0318 
0319     m_view->setOpacity(opacity);
0320     m_view->setFrameOpacity(frameOpacity);
0321 
0322     effects->renderOffscreenQuickView(renderTarget, viewport, m_view);
0323 }
0324 
0325 QString EffectFrame::text() const
0326 {
0327     return m_view->text();
0328 }
0329 
0330 void EffectFrame::setText(const QString &text)
0331 {
0332     m_view->setText(text);
0333 }
0334 
0335 EffectFrameStyle EffectFrame::style() const
0336 {
0337     return m_view->style();
0338 }
0339 
0340 bool EffectFrame::isCrossFade() const
0341 {
0342     return m_view->crossFadeEnabled();
0343 }
0344 
0345 void EffectFrame::enableCrossFade(bool enable)
0346 {
0347     m_view->setCrossFadeEnabled(enable);
0348 }
0349 
0350 qreal EffectFrame::crossFadeProgress() const
0351 {
0352     return m_view->crossFadeProgress();
0353 }
0354 
0355 void EffectFrame::setCrossFadeProgress(qreal progress)
0356 {
0357     m_view->setCrossFadeProgress(progress);
0358 }
0359 
0360 } // namespace KWin
0361 
0362 #include "moc_effectframe.cpp"