diff --git a/src/windowsystem/windoweffects.cpp b/src/windowsystem/windoweffects.cpp index 49d5278..ef54f09 100644 --- a/src/windowsystem/windoweffects.cpp +++ b/src/windowsystem/windoweffects.cpp @@ -1,179 +1,284 @@ /* * Copyright 2014 Martin Gräßlin * Copyright 2015 Marco Martin * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) version 3, or any * later version accepted by the membership of KDE e.V. (or its * successor approved by the membership of KDE e.V.), which shall * act as a proxy defined in Section 6 of version 3 of the license. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see . */ #include "windoweffects.h" #include "waylandintegration.h" #include #include +#include +#include #include #include #include #include #include #include #include #include #include #include WindowEffects::WindowEffects() : QObject(), KWindowEffectsPrivate() { } WindowEffects::~WindowEffects() {} +QWindow *WindowEffects::windowForId(WId wid) +{ + QWindow *window = nullptr; + + for (auto win : qApp->allWindows()) { + if (win->winId() == wid) { + window = win; + break; + } + } + return window; +} + +void WindowEffects::trackWindow(QWindow *window) +{ + if (!m_windowWatchers.contains(window)) { + window->installEventFilter(this); + auto conn = connect(window, &QObject::destroyed, this, [this, window]() { + m_blurRegions.remove(window); + m_backgroundConstrastRegions.remove(window); + m_windowWatchers.remove(window); + }); + m_windowWatchers[window] = conn; + } +} + +void WindowEffects::releaseWindow(QWindow *window) +{ + if (!m_blurRegions.contains(window) && !m_backgroundConstrastRegions.contains(window)) { + disconnect(m_windowWatchers[window]); + window->removeEventFilter(this); + m_windowWatchers.remove(window); + } +} + +bool WindowEffects::eventFilter(QObject *watched, QEvent *event) +{ + if (event->type() == QEvent::Expose) { + auto ee = static_cast(event); + + if ((ee->region().isNull())) { + return false; + } + + auto window = qobject_cast(watched); + if (!window) { + return false; + } + + { + auto it = m_blurRegions.constFind(window); + if (it != m_blurRegions.constEnd()) { + enableBlurBehind(window, true, *it); + } + } + { + auto it = m_backgroundConstrastRegions.constFind(window); + if (it != m_backgroundConstrastRegions.constEnd()) { + enableBackgroundContrast(window, true, it->contrast, it->intensity, it->saturation, it->region); + } + } + } + return false; +} + bool WindowEffects::isEffectAvailable(KWindowEffects::Effect effect) { switch (effect) { case KWindowEffects::BackgroundContrast: return WaylandIntegration::self()->waylandContrastManager() != nullptr; case KWindowEffects::BlurBehind: return WaylandIntegration::self()->waylandBlurManager() != nullptr; case KWindowEffects::Slide: return WaylandIntegration::self()->waylandSlideManager() != nullptr; default: return false; } } void WindowEffects::slideWindow(WId id, KWindowEffects::SlideFromLocation location, int offset) { if (!WaylandIntegration::self()->waylandSlideManager()) { return; } KWayland::Client::Surface *surface = KWayland::Client::Surface::fromQtWinId(id); if (surface) { if (location != KWindowEffects::SlideFromLocation::NoEdge) { auto slide = WaylandIntegration::self()->waylandSlideManager()->createSlide(surface, surface); KWayland::Client::Slide::Location convertedLoc; switch (location) { case KWindowEffects::SlideFromLocation::TopEdge: convertedLoc = KWayland::Client::Slide::Location::Top; break; case KWindowEffects::SlideFromLocation::LeftEdge: convertedLoc = KWayland::Client::Slide::Location::Left; break; case KWindowEffects::SlideFromLocation::RightEdge: convertedLoc = KWayland::Client::Slide::Location::Right; break; case KWindowEffects::SlideFromLocation::BottomEdge: default: convertedLoc = KWayland::Client::Slide::Location::Bottom; break; } slide->setLocation(convertedLoc); slide->setOffset(offset); slide->commit(); } else { WaylandIntegration::self()->waylandSlideManager()->removeSlide(surface); } surface->commit(KWayland::Client::Surface::CommitFlag::None); WaylandIntegration::self()->waylandConnection()->flush(); } } void WindowEffects::slideWindow(QWidget *widget, KWindowEffects::SlideFromLocation location) { slideWindow(widget->winId(), location, 0); } QList WindowEffects::windowSizes(const QList &ids) { Q_UNUSED(ids) QList sizes; return sizes; } void WindowEffects::presentWindows(WId controller, const QList &ids) { Q_UNUSED(controller) Q_UNUSED(ids) } void WindowEffects::presentWindows(WId controller, int desktop) { Q_UNUSED(controller) Q_UNUSED(desktop) } void WindowEffects::highlightWindows(WId controller, const QList &ids) { Q_UNUSED(controller) Q_UNUSED(ids) } -void WindowEffects::enableBlurBehind(WId window, bool enable, const QRegion ®ion) +void WindowEffects::enableBlurBehind(WId winId, bool enable, const QRegion ®ion) +{ + auto window = windowForId(winId); + if (!window) { + return; + } + if (enable) { + trackWindow(window); + m_blurRegions[window] = region; + } else { + m_blurRegions.remove(window); + releaseWindow(window); + } + + enableBlurBehind(window, enable, region); +} + +void WindowEffects::enableBlurBehind(QWindow *window, bool enable, const QRegion ®ion) { if (!WaylandIntegration::self()->waylandBlurManager()) { return; } - KWayland::Client::Surface *surface = KWayland::Client::Surface::fromQtWinId(window); + KWayland::Client::Surface *surface = KWayland::Client::Surface::fromWindow(window); + if (surface) { if (enable) { auto blur = WaylandIntegration::self()->waylandBlurManager()->createBlur(surface, surface); blur->setRegion(WaylandIntegration::self()->waylandCompositor()->createRegion(region, nullptr)); blur->commit(); } else { WaylandIntegration::self()->waylandBlurManager()->removeBlur(surface); } surface->commit(KWayland::Client::Surface::CommitFlag::None); WaylandIntegration::self()->waylandConnection()->flush(); } } -void WindowEffects::enableBackgroundContrast(WId window, bool enable, qreal contrast, qreal intensity, qreal saturation, const QRegion ®ion) +void WindowEffects::enableBackgroundContrast(WId winId, bool enable, qreal contrast, qreal intensity, qreal saturation, const QRegion ®ion) +{ + auto window = windowForId(winId); + if (!window) { + return; + } + if (enable) { + trackWindow(window); + m_backgroundConstrastRegions[window].contrast = contrast; + m_backgroundConstrastRegions[window].intensity = intensity; + m_backgroundConstrastRegions[window].saturation = saturation; + m_backgroundConstrastRegions[window].region = region; + } else { + m_backgroundConstrastRegions.remove(window); + releaseWindow(window); + } + + enableBackgroundContrast(window, enable, contrast, intensity, saturation, region); +} + +void WindowEffects::enableBackgroundContrast(QWindow *window, bool enable, qreal contrast, qreal intensity, qreal saturation, const QRegion ®ion) { if (!WaylandIntegration::self()->waylandContrastManager()) { return; } - KWayland::Client::Surface *surface = KWayland::Client::Surface::fromQtWinId(window); + KWayland::Client::Surface *surface = KWayland::Client::Surface::fromWindow(window); if (surface) { if (enable) { auto backgroundContrast = WaylandIntegration::self()->waylandContrastManager()->createContrast(surface, surface); backgroundContrast->setRegion(WaylandIntegration::self()->waylandCompositor()->createRegion(region, nullptr)); backgroundContrast->setContrast(contrast); backgroundContrast->setIntensity(intensity); backgroundContrast->setSaturation(saturation); backgroundContrast->commit(); } else { WaylandIntegration::self()->waylandContrastManager()->removeContrast(surface); } surface->commit(KWayland::Client::Surface::CommitFlag::None); WaylandIntegration::self()->waylandConnection()->flush(); } } void WindowEffects::markAsDashboard(WId window) { Q_UNUSED(window) } diff --git a/src/windowsystem/windoweffects.h b/src/windowsystem/windoweffects.h index a206f25..2814111 100644 --- a/src/windowsystem/windoweffects.h +++ b/src/windowsystem/windoweffects.h @@ -1,55 +1,75 @@ /* * Copyright 2014 Martin Gräßlin * Copyright 2015 Marco Martin * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) version 3, or any * later version accepted by the membership of KDE e.V. (or its * successor approved by the membership of KDE e.V.), which shall * act as a proxy defined in Section 6 of version 3 of the license. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see . */ #ifndef WINDOWEFFECTS_H #define WINDOWEFFECTS_H #include namespace KWayland { namespace Client { class BlurManager; class ContrastManager; class Compositor; class ConnectionThread; } } class WindowEffects : public QObject, public KWindowEffectsPrivate { + Q_OBJECT public: WindowEffects(); ~WindowEffects() override; + static QWindow *windowForId(WId); + + bool eventFilter(QObject *watched, QEvent *event) override; + void trackWindow(QWindow *window); + void releaseWindow(QWindow *window); + bool isEffectAvailable(KWindowEffects::Effect effect) override; void slideWindow(WId id, KWindowEffects::SlideFromLocation location, int offset) override; void slideWindow(QWidget *widget, KWindowEffects::SlideFromLocation location) override; QList windowSizes(const QList &ids) override; void presentWindows(WId controller, const QList &ids) override; void presentWindows(WId controller, int desktop = NET::OnAllDesktops) override; void highlightWindows(WId controller, const QList &ids) override; - void enableBlurBehind(WId window, bool enable = true, const QRegion ®ion = QRegion()) override; - void enableBackgroundContrast(WId window, bool enable = true, qreal contrast = 1, qreal intensity = 1, qreal saturation = 1, const QRegion ®ion = QRegion()) override; + void enableBlurBehind(WId winId, bool enable = true, const QRegion ®ion = QRegion()) override; + void enableBlurBehind(QWindow *window, bool enable, const QRegion ®ion); + void enableBackgroundContrast(WId winId, bool enable = true, qreal contrast = 1, qreal intensity = 1, qreal saturation = 1, const QRegion ®ion = QRegion()) override; + void enableBackgroundContrast(QWindow *window, bool enable = true, qreal contrast = 1, qreal intensity = 1, qreal saturation = 1, const QRegion ®ion = QRegion()); void markAsDashboard(WId window) override; +private: + QHash m_windowWatchers; + QHash m_blurRegions; + struct BackgroundContrastData { + qreal contrast = 1; + qreal intensity = 1; + qreal saturation = 1; + QRegion region; + }; + QHash m_backgroundConstrastRegions; + }; #endif