diff --git a/autotests/test_window_paint_data.cpp b/autotests/test_window_paint_data.cpp index d218bed0b2..6b2addc02f 100644 --- a/autotests/test_window_paint_data.cpp +++ b/autotests/test_window_paint_data.cpp @@ -27,8 +27,8 @@ public: QVariant data(int role) const override; QRect decorationInnerRect() const override; void deleteProperty(long int atom) const override; - void disablePainting(int reason) override; - void enablePainting(int reason) override; + void refVisible(int reason) override; + void unrefVisible(int reason) override; void addRepaint(const QRect &r) override; void addRepaint(int x, int y, int w, int h) override; void addRepaintFull() override; @@ -37,7 +37,6 @@ public: EffectWindow *findModal() override; EffectWindow *transientFor() override; const EffectWindowGroup *group() const override; - bool isPaintingEnabled() override; EffectWindowList mainWindows() const override; QByteArray readProperty(long int atom, long int type, int format) const override; void refWindow() override; @@ -366,12 +365,12 @@ void MockEffectWindow::deleteProperty(long int atom) const Q_UNUSED(atom) } -void MockEffectWindow::disablePainting(int reason) +void MockEffectWindow::refVisible(int reason) { Q_UNUSED(reason) } -void MockEffectWindow::enablePainting(int reason) +void MockEffectWindow::unrefVisible(int reason) { Q_UNUSED(reason) } @@ -421,11 +420,6 @@ const EffectWindowGroup *MockEffectWindow::group() const return nullptr; } -bool MockEffectWindow::isPaintingEnabled() -{ - return true; -} - EffectWindowList MockEffectWindow::mainWindows() const { return EffectWindowList(); diff --git a/src/effects.cpp b/src/effects.cpp index c08cffdc31..d5afff6e48 100644 --- a/src/effects.cpp +++ b/src/effects.cpp @@ -49,6 +49,7 @@ #include "wayland_server.h" #include "waylandwindow.h" #include "window_property_notify_x11_filter.h" +#include "windowitem.h" #include "workspace.h" #include @@ -1915,19 +1916,14 @@ EffectWindowImpl::~EffectWindowImpl() } } -bool EffectWindowImpl::isPaintingEnabled() +void EffectWindowImpl::refVisible(int reason) { - return sceneWindow()->isPaintingEnabled(); + m_sceneWindow->windowItem()->refVisible(reason); } -void EffectWindowImpl::enablePainting(int reason) +void EffectWindowImpl::unrefVisible(int reason) { - sceneWindow()->enablePainting(reason); -} - -void EffectWindowImpl::disablePainting(int reason) -{ - sceneWindow()->disablePainting(reason); + m_sceneWindow->windowItem()->unrefVisible(reason); } void EffectWindowImpl::addRepaint(const QRect &r) diff --git a/src/effects.h b/src/effects.h index 2eb4019bf3..c407fbd9c2 100644 --- a/src/effects.h +++ b/src/effects.h @@ -384,9 +384,8 @@ public: explicit EffectWindowImpl(Window *window); ~EffectWindowImpl() override; - void enablePainting(int reason) override; - void disablePainting(int reason) override; - bool isPaintingEnabled() override; + void refVisible(int reason) override; + void unrefVisible(int reason) override; void addRepaint(const QRect &r) override; void addRepaint(int x, int y, int w, int h) override; diff --git a/src/effects/blur/blur.cpp b/src/effects/blur/blur.cpp index ed0c39dab4..2fefd8485f 100644 --- a/src/effects/blur/blur.cpp +++ b/src/effects/blur/blur.cpp @@ -535,9 +535,6 @@ void BlurEffect::prePaintWindow(EffectWindow *w, WindowPrePaintData &data, std:: effects->prePaintWindow(w, data, presentTime); - if (!w->isPaintingEnabled()) { - return; - } if (!m_shader || !m_shader->isValid()) { return; } diff --git a/src/effects/desktopgrid/desktopgrid.cpp b/src/effects/desktopgrid/desktopgrid.cpp index 217e7b4b88..61e5e53062 100644 --- a/src/effects/desktopgrid/desktopgrid.cpp +++ b/src/effects/desktopgrid/desktopgrid.cpp @@ -257,11 +257,6 @@ void DesktopGridEffect::prePaintScreen(ScreenPrePaintData &data, std::chrono::mi // so with normal screen painting second screen paint would erase parts of the first paint data.mask |= PAINT_SCREEN_TRANSFORMED | PAINT_SCREEN_BACKGROUND_FIRST; - const EffectWindowList windows = effects->stackingOrder(); - for (auto *w : windows) { - w->setData(WindowForceBlurRole, QVariant(true)); - } - effects->prePaintScreen(data, presentTime); } @@ -360,10 +355,6 @@ void DesktopGridEffect::postPaintScreen() lastPresentTime = std::chrono::milliseconds::zero(); } - for (auto &w : effects->stackingOrder()) { - w->setData(WindowForceBlurRole, QVariant()); - } - effects->postPaintScreen(); } @@ -372,19 +363,18 @@ void DesktopGridEffect::postPaintScreen() void DesktopGridEffect::prePaintWindow(EffectWindow *w, WindowPrePaintData &data, std::chrono::milliseconds presentTime) { - w->enablePainting(EffectWindow::PAINT_DISABLED_BY_DESKTOP); - if (w->isMinimized() && isUsingPresentWindows()) { - w->enablePainting(EffectWindow::PAINT_DISABLED_BY_MINIMIZE); - } - if (windowMove && wasWindowMove && windowMove->findModal() == w) { - w->disablePainting(EffectWindow::PAINT_DISABLED_BY_DESKTOP); - } data.setTransformed(); effects->prePaintWindow(w, data, presentTime); } void DesktopGridEffect::paintWindow(EffectWindow *w, int mask, QRegion region, WindowPaintData &data) { + if (w->isMinimized() && !isUsingPresentWindows()) { + return; + } + if (windowMove && wasWindowMove && windowMove->findModal() == w) { + return; + } if (!w->isOnDesktop(paintingDesktop)) { return; } @@ -1152,6 +1142,12 @@ void DesktopGridEffect::setup() } setHighlightedDesktop(effects->currentDesktop()); + const EffectWindowList windows = effects->stackingOrder(); + for (auto *w : windows) { + w->refVisible(EffectWindow::PAINT_DISABLED_BY_MINIMIZE | EffectWindow::PAINT_DISABLED_BY_DESKTOP); + w->setData(WindowForceBlurRole, QVariant(true)); + } + // Soft highlighting qDeleteAll(hoverTimeline); hoverTimeline.clear(); @@ -1350,6 +1346,11 @@ void DesktopGridEffect::finish() m_proxy = nullptr; } + for (auto &w : effects->stackingOrder()) { + w->unrefVisible(EffectWindow::PAINT_DISABLED_BY_MINIMIZE | EffectWindow::PAINT_DISABLED_BY_DESKTOP); + w->setData(WindowForceBlurRole, QVariant()); + } + effects->addRepaintFull(); } diff --git a/src/effects/fallapart/fallapart.cpp b/src/effects/fallapart/fallapart.cpp index 5626b2b50d..3a994f3298 100644 --- a/src/effects/fallapart/fallapart.cpp +++ b/src/effects/fallapart/fallapart.cpp @@ -59,7 +59,6 @@ void FallApartEffect::prePaintWindow(EffectWindow *w, WindowPrePaintData &data, animationIt->progress += time / animationTime(1000.); data.setTransformed(); - w->enablePainting(EffectWindow::PAINT_DISABLED_BY_DELETE); } else { unredirect(w); windows.remove(w); @@ -181,6 +180,7 @@ void FallApartEffect::slotWindowClosed(EffectWindow *c) FallApartAnimation &animation = windows[c]; animation.progress = 0; animation.deletedRef = EffectWindowDeletedRef(c); + animation.visibleRef = EffectWindowVisibleRef(c, EffectWindow::PAINT_DISABLED_BY_DELETE); redirect(c); } diff --git a/src/effects/fallapart/fallapart.h b/src/effects/fallapart/fallapart.h index 53d71c43c9..b26fb2ee95 100644 --- a/src/effects/fallapart/fallapart.h +++ b/src/effects/fallapart/fallapart.h @@ -18,6 +18,7 @@ namespace KWin struct FallApartAnimation { EffectWindowDeletedRef deletedRef; + EffectWindowVisibleRef visibleRef; std::chrono::milliseconds lastPresentTime = std::chrono::milliseconds::zero(); qreal progress = 0; }; diff --git a/src/effects/glide/glide.cpp b/src/effects/glide/glide.cpp index 2336ba6538..e3655fb0a2 100644 --- a/src/effects/glide/glide.cpp +++ b/src/effects/glide/glide.cpp @@ -89,7 +89,6 @@ void GlideEffect::prePaintWindow(EffectWindow *w, WindowPrePaintData &data, std: { if (m_animations.contains(w)) { data.setTransformed(); - w->enablePainting(EffectWindow::PAINT_DISABLED_BY_DELETE); } effects->prePaintWindow(w, data, presentTime); @@ -245,6 +244,7 @@ void GlideEffect::windowClosed(EffectWindow *w) GlideAnimation &animation = m_animations[w]; animation.deletedRef = EffectWindowDeletedRef(w); + animation.visibleRef = EffectWindowVisibleRef(w, EffectWindow::PAINT_DISABLED_BY_DELETE); animation.timeLine.reset(); animation.timeLine.setDirection(TimeLine::Forward); animation.timeLine.setDuration(m_duration); diff --git a/src/effects/glide/glide.h b/src/effects/glide/glide.h index c1b6ca105c..c25fcece9b 100644 --- a/src/effects/glide/glide.h +++ b/src/effects/glide/glide.h @@ -22,6 +22,7 @@ namespace KWin struct GlideAnimation { EffectWindowDeletedRef deletedRef; + EffectWindowVisibleRef visibleRef; TimeLine timeLine; std::chrono::milliseconds lastPresentTime = std::chrono::milliseconds::zero(); }; diff --git a/src/effects/magiclamp/magiclamp.cpp b/src/effects/magiclamp/magiclamp.cpp index 3394dd6c41..ed15f72b75 100644 --- a/src/effects/magiclamp/magiclamp.cpp +++ b/src/effects/magiclamp/magiclamp.cpp @@ -70,7 +70,6 @@ void MagicLampEffect::prePaintWindow(EffectWindow *w, WindowPrePaintData &data, if (m_animations.contains(w)) { // We'll transform this window data.setTransformed(); - w->enablePainting(EffectWindow::PAINT_DISABLED_BY_MINIMIZE); } effects->prePaintWindow(w, data, presentTime); @@ -342,6 +341,7 @@ void MagicLampEffect::slotWindowMinimized(EffectWindow *w) if (animation.timeLine.running()) { animation.timeLine.toggleDirection(); } else { + animation.visibleRef = EffectWindowVisibleRef(w, EffectWindow::PAINT_DISABLED_BY_MINIMIZE); animation.timeLine.setDirection(TimeLine::Forward); animation.timeLine.setDuration(m_duration); animation.timeLine.setEasingCurve(QEasingCurve::Linear); diff --git a/src/effects/magiclamp/magiclamp.h b/src/effects/magiclamp/magiclamp.h index fc65564718..812bde63cc 100644 --- a/src/effects/magiclamp/magiclamp.h +++ b/src/effects/magiclamp/magiclamp.h @@ -17,6 +17,7 @@ namespace KWin struct MagicLampAnimation { + EffectWindowVisibleRef visibleRef; TimeLine timeLine; std::chrono::milliseconds lastPresentTime = std::chrono::milliseconds::zero(); }; diff --git a/src/effects/presentwindows/presentwindows.cpp b/src/effects/presentwindows/presentwindows.cpp index cb83dce3d8..f2c9c078fd 100644 --- a/src/effects/presentwindows/presentwindows.cpp +++ b/src/effects/presentwindows/presentwindows.cpp @@ -332,8 +332,6 @@ void PresentWindowsEffect::prePaintWindow(EffectWindow *w, WindowPrePaintData &d effects->prePaintWindow(w, data, presentTime); return; } - w->enablePainting(EffectWindow::PAINT_DISABLED_BY_MINIMIZE); // Display always - w->enablePainting(EffectWindow::PAINT_DISABLED_BY_DESKTOP); // The animation code assumes that the time diff cannot be 0, let's work around it. int time; @@ -357,15 +355,6 @@ void PresentWindowsEffect::prePaintWindow(EffectWindow *w, WindowPrePaintData &d winData->opacity = qMax(0.0, winData->opacity - time / m_fadeDuration); } - if (winData->opacity <= 0.0) { - // don't disable painting for panels if show panel is set - if (!(m_showPanel && w->isDock())) { - w->disablePainting(EffectWindow::PAINT_DISABLED); - } - } else if (winData->opacity != 1.0) { - data.setTranslucent(); - } - const bool isInMotion = m_motionManager.isManaging(w); // Calculate window's brightness if (w == m_highlightedWindow || !m_activated) { @@ -383,19 +372,15 @@ void PresentWindowsEffect::prePaintWindow(EffectWindow *w, WindowPrePaintData &d // it's possible that another effect has referenced the window // we have to keep the window in the list to prevent flickering winData->deletedRef = EffectWindowDeletedRef{}; - } else { - w->enablePainting(EffectWindow::PAINT_DISABLED_BY_DELETE); } } - // desktop windows on other desktops (Plasma activity per desktop) should not be painted - if (w->isDesktop() && !w->isOnCurrentDesktop()) { - w->disablePainting(EffectWindow::PAINT_DISABLED_BY_DESKTOP); - } - if (isInMotion) { data.setTransformed(); // We will be moving this window } + if (winData->opacity != 1.0) { + data.setTranslucent(); + } } effects->prePaintWindow(w, data, presentTime); } @@ -403,6 +388,11 @@ void PresentWindowsEffect::prePaintWindow(EffectWindow *w, WindowPrePaintData &d void PresentWindowsEffect::paintWindow(EffectWindow *w, int mask, QRegion region, WindowPaintData &data) { if (m_activated || m_motionManager.areWindowsMoving()) { + // desktop windows on other desktops (Plasma activity per desktop) should not be painted + if (w->isDesktop() && !w->isOnCurrentDesktop()) { + return; + } + DataHash::const_iterator winData = m_windowData.constFind(w); if (winData == m_windowData.constEnd() || (w->isDock() && m_showPanel)) { // we are darkening the panel to communicate that it's not interactive @@ -1702,6 +1692,8 @@ void PresentWindowsEffect::setActive(bool active) winData->opacity = 1.0; } + winData->visibleRef = EffectWindowVisibleRef(w, EffectWindow::PAINT_DISABLED_BY_DESKTOP | EffectWindow::PAINT_DISABLED_BY_MINIMIZE); + winData->highlight = 1.0; winData->textFrame = effects->effectFrame(EffectFrameUnstyled, false); diff --git a/src/effects/presentwindows/presentwindows.h b/src/effects/presentwindows/presentwindows.h index b9fcb2d724..d1c33aab62 100644 --- a/src/effects/presentwindows/presentwindows.h +++ b/src/effects/presentwindows/presentwindows.h @@ -67,6 +67,7 @@ private: struct WindowData { EffectWindowDeletedRef deletedRef; + EffectWindowVisibleRef visibleRef; std::chrono::milliseconds lastPresentTime = std::chrono::milliseconds::zero(); bool visible; bool deleted; diff --git a/src/effects/sheet/sheet.cpp b/src/effects/sheet/sheet.cpp index ec9aff9029..a5143fee2b 100644 --- a/src/effects/sheet/sheet.cpp +++ b/src/effects/sheet/sheet.cpp @@ -67,7 +67,6 @@ void SheetEffect::prePaintWindow(EffectWindow *w, WindowPrePaintData &data, std: { if (m_animations.contains(w)) { data.setTransformed(); - w->enablePainting(EffectWindow::PAINT_DISABLED_BY_DELETE); } effects->prePaintWindow(w, data, presentTime); @@ -185,6 +184,7 @@ void SheetEffect::slotWindowClosed(EffectWindow *w) Animation &animation = m_animations[w]; animation.deletedRef = EffectWindowDeletedRef(w); + animation.visibleRef = EffectWindowVisibleRef(w, EffectWindow::PAINT_DISABLED_BY_DELETE); animation.timeLine.reset(); animation.parentY = 0; animation.timeLine.setDuration(m_duration); diff --git a/src/effects/sheet/sheet.h b/src/effects/sheet/sheet.h index 76bda02292..f16a357acb 100644 --- a/src/effects/sheet/sheet.h +++ b/src/effects/sheet/sheet.h @@ -54,6 +54,7 @@ private: struct Animation { EffectWindowDeletedRef deletedRef; + EffectWindowVisibleRef visibleRef; TimeLine timeLine; int parentY; std::chrono::milliseconds lastPresentTime = std::chrono::milliseconds::zero(); diff --git a/src/effects/slide/slide.cpp b/src/effects/slide/slide.cpp index 07448081f2..86b2348436 100644 --- a/src/effects/slide/slide.cpp +++ b/src/effects/slide/slide.cpp @@ -271,14 +271,7 @@ bool SlideEffect::isPainted(const EffectWindow *w) const void SlideEffect::prePaintWindow(EffectWindow *w, WindowPrePaintData &data, std::chrono::milliseconds presentTime) { - for (const auto &desktop : std::as_const(m_paintCtx.visibleDesktops)) { - if (w->isOnDesktop(desktop)) { - w->enablePainting(EffectWindow::PAINT_DISABLED_BY_DESKTOP); - data.setTransformed(); - break; - } - } - + data.setTransformed(); effects->prePaintWindow(w, data, presentTime); } @@ -380,6 +373,7 @@ void SlideEffect::prepareSwitching() effects->setElevatedWindow(w, true); m_elevatedWindows << w; } + w->refVisible(EffectWindow::PAINT_DISABLED_BY_DESKTOP); w->setData(WindowForceBackgroundContrastRole, QVariant(true)); w->setData(WindowForceBlurRole, QVariant(true)); } @@ -392,6 +386,7 @@ void SlideEffect::finishedSwitching() } const EffectWindowList windows = effects->stackingOrder(); for (EffectWindow *w : windows) { + w->unrefVisible(EffectWindow::PAINT_DISABLED_BY_DESKTOP); w->setData(WindowForceBackgroundContrastRole, QVariant()); w->setData(WindowForceBlurRole, QVariant()); } @@ -482,6 +477,7 @@ void SlideEffect::windowAdded(EffectWindow *w) effects->setElevatedWindow(w, true); m_elevatedWindows << w; } + w->refVisible(EffectWindow::PAINT_DISABLED_BY_DESKTOP); w->setData(WindowForceBackgroundContrastRole, QVariant(true)); w->setData(WindowForceBlurRole, QVariant(true)); } diff --git a/src/effects/slideback/slideback.cpp b/src/effects/slideback/slideback.cpp index 2d2d247996..52a988b255 100644 --- a/src/effects/slideback/slideback.cpp +++ b/src/effects/slideback/slideback.cpp @@ -296,8 +296,7 @@ void SlideBackEffect::slotTabBoxClosed() bool SlideBackEffect::isWindowUsable(EffectWindow *w) { - return w && (w->isNormalWindow() || w->isDialog()) && !w->keepAbove() && !w->isDeleted() && !w->isMinimized() - && w->isPaintingEnabled(); + return w && (w->isNormalWindow() || w->isDialog()) && !w->keepAbove() && !w->isDeleted() && !w->isMinimized(); } bool SlideBackEffect::intersects(EffectWindow *windowUnder, const QRect &windowOverGeometry) diff --git a/src/effects/slidingpopups/slidingpopups.cpp b/src/effects/slidingpopups/slidingpopups.cpp index 7c267b6ddc..129b896350 100644 --- a/src/effects/slidingpopups/slidingpopups.cpp +++ b/src/effects/slidingpopups/slidingpopups.cpp @@ -131,7 +131,6 @@ void SlidingPopupsEffect::prePaintWindow(EffectWindow *w, WindowPrePaintData &da (*animationIt).timeLine.update(delta); data.setTransformed(); - w->enablePainting(EffectWindow::PAINT_DISABLED | EffectWindow::PAINT_DISABLED_BY_DELETE); effects->prePaintWindow(w, data, presentTime); } @@ -544,7 +543,10 @@ void SlidingPopupsEffect::slideOut(EffectWindow *w) } Animation &animation = m_animations[w]; - animation.deletedRef = EffectWindowDeletedRef(w); + if (w->isDeleted()) { + animation.deletedRef = EffectWindowDeletedRef(w); + } + animation.visibleRef = EffectWindowVisibleRef(w, EffectWindow::PAINT_DISABLED | EffectWindow::PAINT_DISABLED_BY_DELETE); animation.kind = AnimationKind::Out; animation.timeLine.setDirection(TimeLine::Backward); animation.timeLine.setDuration((*dataIt).slideOutDuration); diff --git a/src/effects/slidingpopups/slidingpopups.h b/src/effects/slidingpopups/slidingpopups.h index 673bca109a..11a9277601 100644 --- a/src/effects/slidingpopups/slidingpopups.h +++ b/src/effects/slidingpopups/slidingpopups.h @@ -83,6 +83,7 @@ private: struct Animation { EffectWindowDeletedRef deletedRef; + EffectWindowVisibleRef visibleRef; AnimationKind kind; TimeLine timeLine; std::chrono::milliseconds lastPresentTime = std::chrono::milliseconds::zero(); diff --git a/src/events.cpp b/src/events.cpp index 352a678eaf..828bba9f5e 100644 --- a/src/events.cpp +++ b/src/events.cpp @@ -1281,8 +1281,6 @@ bool Unmanaged::windowEvent(xcb_generic_event_t *e) default: { if (eventType == Xcb::Extensions::self()->shapeNotifyEvent()) { detectShape(window()); - addRepaintFull(); - addWorkspaceRepaint(frameGeometry()); // in case shape change removes part of this window Q_EMIT geometryShapeChanged(this, frameGeometry()); } if (eventType == Xcb::Extensions::self()->damageNotifyEvent()) { diff --git a/src/libkwineffects/anidata_p.h b/src/libkwineffects/anidata_p.h index 46d45e50cf..945586b2ce 100644 --- a/src/libkwineffects/anidata_p.h +++ b/src/libkwineffects/anidata_p.h @@ -76,6 +76,7 @@ public: bool waitAtSource; bool keepAlive; EffectWindowDeletedRef deletedRef; + EffectWindowVisibleRef visibleRef; PreviousWindowPixmapLockPtr previousWindowPixmapLock; AnimationEffect::TerminationFlags terminationFlags; std::chrono::milliseconds lastPresentTime; diff --git a/src/libkwineffects/kwinanimationeffect.cpp b/src/libkwineffects/kwinanimationeffect.cpp index 63ace9c31b..de078e6061 100644 --- a/src/libkwineffects/kwinanimationeffect.cpp +++ b/src/libkwineffects/kwinanimationeffect.cpp @@ -258,6 +258,7 @@ quint64 AnimationEffect::p_animate(EffectWindow *w, Attribute a, uint meta, int AniData &animation = it->first.last(); animation.id = ret_id; + animation.visibleRef = EffectWindowVisibleRef(w, EffectWindow::PAINT_DISABLED_BY_MINIMIZE | EffectWindow::PAINT_DISABLED_BY_DESKTOP | EffectWindow::PAINT_DISABLED_BY_DELETE); animation.timeLine.setDirection(TimeLine::Forward); animation.timeLine.setDuration(std::chrono::milliseconds(ms)); animation.timeLine.setEasingCurve(curve); @@ -504,32 +505,16 @@ void AnimationEffect::prePaintWindow(EffectWindow *w, WindowPrePaintData &data, Q_D(AnimationEffect); AniMap::const_iterator entry = d->m_animations.constFind(w); if (entry != d->m_animations.constEnd()) { - bool isUsed = false; - bool paintDeleted = false; for (QList::const_iterator anim = entry->first.constBegin(); anim != entry->first.constEnd(); ++anim) { if (anim->startTime > clock() && !anim->waitAtSource) { continue; } - isUsed = true; if (anim->attribute == Opacity || anim->attribute == CrossFadePrevious) { data.setTranslucent(); } else if (!(anim->attribute == Brightness || anim->attribute == Saturation)) { data.setTransformed(); } - - paintDeleted |= anim->keepAlive; - } - if (isUsed) { - if (w->isMinimized()) { - w->enablePainting(EffectWindow::PAINT_DISABLED_BY_MINIMIZE); - } else if (w->isDeleted() && paintDeleted) { - w->enablePainting(EffectWindow::PAINT_DISABLED_BY_DELETE); - } else if (!w->isOnCurrentDesktop()) { - w->enablePainting(EffectWindow::PAINT_DISABLED_BY_DESKTOP); - } - // if( !w->isPaintingEnabled() && !effects->activeFullScreenEffect() ) - // effects->addLayerRepaint(w->expandedGeometry()); } } effects->prePaintWindow(w, data, presentTime); diff --git a/src/libkwineffects/kwineffects.h b/src/libkwineffects/kwineffects.h index f67248811d..e7c4b0dbda 100644 --- a/src/libkwineffects/kwineffects.h +++ b/src/libkwineffects/kwineffects.h @@ -2354,9 +2354,6 @@ public: explicit EffectWindow(QObject *parent = nullptr); ~EffectWindow() override; - virtual void enablePainting(int reason) = 0; - virtual void disablePainting(int reason) = 0; - virtual bool isPaintingEnabled() = 0; Q_SCRIPTABLE virtual void addRepaint(const QRect &r) = 0; Q_SCRIPTABLE virtual void addRepaint(int x, int y, int w, int h) = 0; Q_SCRIPTABLE virtual void addRepaintFull() = 0; @@ -2366,6 +2363,9 @@ public: virtual void refWindow() = 0; virtual void unrefWindow() = 0; + virtual void refVisible(int reason) = 0; + virtual void unrefVisible(int reason) = 0; + virtual bool isDeleted() const = 0; virtual bool isMinimized() const = 0; @@ -2774,6 +2774,64 @@ private: EffectWindow *m_window; }; +/** + * The EffectWindowVisibleRef provides a convenient way to force the visible status of a + * window until an effect is finished animating it. + */ +class KWINEFFECTS_EXPORT EffectWindowVisibleRef +{ +public: + EffectWindowVisibleRef() + : m_window(nullptr) + { + } + + explicit EffectWindowVisibleRef(EffectWindow *window, int reason) + : m_window(window) + , m_reason(reason) + { + m_window->refVisible(reason); + } + + EffectWindowVisibleRef(const EffectWindowVisibleRef &other) + : m_window(other.m_window) + , m_reason(other.m_reason) + { + if (m_window) { + m_window->refVisible(m_reason); + } + } + + ~EffectWindowVisibleRef() + { + if (m_window) { + m_window->unrefVisible(m_reason); + } + } + + EffectWindowVisibleRef &operator=(const EffectWindowVisibleRef &other) + { + if (other.m_window) { + other.m_window->refVisible(other.m_reason); + } + if (m_window) { + m_window->unrefVisible(m_reason); + } + m_window = other.m_window; + m_reason = other.m_reason; + return *this; + } + + bool isNull() const + { + return m_window == nullptr; + } + +private: + EffectWindow *m_window; + int m_reason; +}; + class KWINEFFECTS_EXPORT EffectWindowGroup { public: diff --git a/src/scene.cpp b/src/scene.cpp index a30515c9f0..c67beccff3 100644 --- a/src/scene.cpp +++ b/src/scene.cpp @@ -232,7 +232,7 @@ SurfaceItem *Scene::scanoutCandidate() const for (int i = stacking_order.count() - 1; i >= 0; i--) { SceneWindow *sceneWindow = stacking_order[i]; Window *window = sceneWindow->window(); - if (window->isOnOutput(painted_screen) && sceneWindow->isVisible() && window->opacity() > 0) { + if (window->isOnOutput(painted_screen) && window->opacity() > 0) { if (!window->isClient() || !window->isFullScreen() || window->opacity() != 1.0) { break; } @@ -338,16 +338,13 @@ void Scene::preparePaintGenericScreen() data.mask = m_paintContext.mask; data.paint = infiniteRegion(); // no clipping, so doesn't really matter - sceneWindow->resetPaintingEnabled(); effects->prePaintWindow(effectWindow(sceneWindow), data, m_expectedPresentTimestamp); - if (sceneWindow->isPaintingEnabled()) { - m_paintContext.phase2Data.append(Phase2Data{ - .window = sceneWindow, - .region = infiniteRegion(), - .opaque = data.opaque, - .mask = data.mask, - }); - } + m_paintContext.phase2Data.append(Phase2Data{ + .window = sceneWindow, + .region = infiniteRegion(), + .opaque = data.opaque, + .mask = data.mask, + }); } m_paintContext.damage = renderTargetRect(); @@ -373,16 +370,13 @@ void Scene::preparePaintSimpleScreen() } } - sceneWindow->resetPaintingEnabled(); effects->prePaintWindow(effectWindow(sceneWindow), data, m_expectedPresentTimestamp); - if (sceneWindow->isPaintingEnabled()) { - m_paintContext.phase2Data.append(Phase2Data{ - .window = sceneWindow, - .region = data.paint, - .opaque = data.opaque, - .mask = data.mask, - }); - } + m_paintContext.phase2Data.append(Phase2Data{ + .window = sceneWindow, + .region = data.paint, + .opaque = data.opaque, + .mask = data.mask, + }); } // Perform an occlusion cull pass, remove surface damage occluded by opaque windows. @@ -664,7 +658,6 @@ SurfaceTexture *Scene::createSurfaceTextureWayland(SurfacePixmapWayland *pixmap) SceneWindow::SceneWindow(Window *client, QObject *parent) : QObject(parent) , m_window(client) - , disable_painting(0) { if (qobject_cast(client)) { m_windowItem.reset(new WindowItemWayland(m_window)); @@ -729,60 +722,6 @@ QRegion SceneWindow::decorationShape() const return QRegion(m_window->rect()) - decorationInnerRect; } -bool SceneWindow::isVisible() const -{ - if (m_window->isDeleted()) { - return false; - } - if (!m_window->isOnCurrentDesktop()) { - return false; - } - if (!m_window->isOnCurrentActivity()) { - return false; - } - if (m_window->isClient()) { - return m_window->isShown(); - } - return true; // Unmanaged is always visible -} - -bool SceneWindow::isPaintingEnabled() const -{ - return !disable_painting; -} - -void SceneWindow::resetPaintingEnabled() -{ - disable_painting = 0; - if (m_window->isDeleted()) { - disable_painting |= PAINT_DISABLED_BY_DELETE; - } - if (!m_window->isOnCurrentDesktop()) { - disable_painting |= PAINT_DISABLED_BY_DESKTOP; - } - if (!m_window->isOnCurrentActivity()) { - disable_painting |= PAINT_DISABLED_BY_ACTIVITY; - } - if (m_window->isClient()) { - if (m_window->isMinimized()) { - disable_painting |= PAINT_DISABLED_BY_MINIMIZE; - } - if (m_window->isHiddenInternal()) { - disable_painting |= PAINT_DISABLED; - } - } -} - -void SceneWindow::enablePainting(int reason) -{ - disable_painting &= ~reason; -} - -void SceneWindow::disablePainting(int reason) -{ - disable_painting |= reason; -} - WindowItem *SceneWindow::windowItem() const { return m_windowItem.data(); diff --git a/src/scene.h b/src/scene.h index f50e703474..6f1af9cd7a 100644 --- a/src/scene.h +++ b/src/scene.h @@ -295,26 +295,6 @@ public: // access to the internal window class // TODO eventually get rid of this Window *window() const; - // should the window be painted - bool isPaintingEnabled() const; - void resetPaintingEnabled(); - // Flags explaining why painting should be disabled - enum { - // SceneWindow will not be painted - PAINT_DISABLED = 1 << 0, - // SceneWindow will not be painted because it is deleted - PAINT_DISABLED_BY_DELETE = 1 << 1, - // SceneWindow will not be painted because of which desktop it's on - PAINT_DISABLED_BY_DESKTOP = 1 << 2, - // SceneWindow will not be painted because it is minimized - PAINT_DISABLED_BY_MINIMIZE = 1 << 3, - // SceneWindow will not be painted because it's not on the current activity - PAINT_DISABLED_BY_ACTIVITY = 1 << 5 - }; - void enablePainting(int reason); - void disablePainting(int reason); - // is the window visible at all - bool isVisible() const; QRegion decorationShape() const; void setWindow(Window *window); void referencePreviousPixmap(); @@ -332,7 +312,6 @@ private: void updateWindowPosition(); - int disable_painting; QScopedPointer m_windowItem; Q_DISABLE_COPY(SceneWindow) }; diff --git a/src/waylandwindow.cpp b/src/waylandwindow.cpp index 0c944301ea..3e66c22381 100644 --- a/src/waylandwindow.cpp +++ b/src/waylandwindow.cpp @@ -259,7 +259,6 @@ void WaylandWindow::showClient() return; } m_isHidden = false; - addRepaintFull(); Q_EMIT windowShown(this); } @@ -272,7 +271,6 @@ void WaylandWindow::hideClient() leaveInteractiveMoveResize(); } m_isHidden = true; - addWorkspaceRepaint(visibleGeometry()); workspace()->windowHidden(this); Q_EMIT windowHidden(this); } diff --git a/src/window.cpp b/src/window.cpp index 9ea2de9d57..d4c8302ce6 100644 --- a/src/window.cpp +++ b/src/window.cpp @@ -432,7 +432,6 @@ void Window::setReadyForPainting() if (!ready_for_painting) { ready_for_painting = true; if (Compositor::compositing()) { - addRepaintFull(); Q_EMIT windowShown(this); } } @@ -1200,7 +1199,6 @@ void Window::setDesktops(QVector desktops) Q_EMIT desktopChanged(); if (wasOnCurrentDesktop != isOnCurrentDesktop()) { - addWorkspaceRepaint(visibleGeometry()); Q_EMIT desktopPresenceChanged(this, was_desk); } Q_EMIT x11DesktopIdsChanged(); @@ -1443,7 +1441,6 @@ void Window::minimize(bool avoid_animation) } // TODO: merge signal with s_minimized - addWorkspaceRepaint(visibleGeometry()); Q_EMIT clientMinimized(this, !avoid_animation); Q_EMIT minimizedChanged(); } diff --git a/src/windowitem.cpp b/src/windowitem.cpp index 274f00ca12..2673614e1b 100644 --- a/src/windowitem.cpp +++ b/src/windowitem.cpp @@ -13,6 +13,7 @@ #include "surfaceitem_wayland.h" #include "surfaceitem_x11.h" #include "window.h" +#include "workspace.h" namespace KWin { @@ -27,6 +28,14 @@ WindowItem::WindowItem(Window *window, Item *parent) connect(window, &Window::shadowChanged, this, &WindowItem::updateShadowItem); updateShadowItem(); + connect(window, &Window::minimizedChanged, this, &WindowItem::updateVisibility); + connect(window, &Window::hiddenChanged, this, &WindowItem::updateVisibility); + connect(window, &Window::activitiesChanged, this, &WindowItem::updateVisibility); + connect(window, &Window::desktopChanged, this, &WindowItem::updateVisibility); + connect(workspace(), &Workspace::currentActivityChanged, this, &WindowItem::updateVisibility); + connect(workspace(), &Workspace::currentDesktopChanged, this, &WindowItem::updateVisibility); + updateVisibility(); + connect(window, &Window::windowClosed, this, &WindowItem::handleWindowClosed); } @@ -50,12 +59,92 @@ Window *WindowItem::window() const return m_window; } +void WindowItem::refVisible(int reason) +{ + if (reason & PAINT_DISABLED_BY_HIDDEN) { + m_forceVisibleByHiddenCount++; + } + if (reason & PAINT_DISABLED_BY_DELETE) { + m_forceVisibleByDeleteCount++; + } + if (reason & PAINT_DISABLED_BY_DESKTOP) { + m_forceVisibleByDesktopCount++; + } + if (reason & PAINT_DISABLED_BY_MINIMIZE) { + m_forceVisibleByMinimizeCount++; + } + if (reason & PAINT_DISABLED_BY_ACTIVITY) { + m_forceVisibleByActivityCount++; + } + updateVisibility(); +} + +void WindowItem::unrefVisible(int reason) +{ + if (reason & PAINT_DISABLED_BY_HIDDEN) { + Q_ASSERT(m_forceVisibleByHiddenCount > 0); + m_forceVisibleByHiddenCount--; + } + if (reason & PAINT_DISABLED_BY_DELETE) { + Q_ASSERT(m_forceVisibleByDeleteCount > 0); + m_forceVisibleByDeleteCount--; + } + if (reason & PAINT_DISABLED_BY_DESKTOP) { + Q_ASSERT(m_forceVisibleByDesktopCount > 0); + m_forceVisibleByDesktopCount--; + } + if (reason & PAINT_DISABLED_BY_MINIMIZE) { + Q_ASSERT(m_forceVisibleByMinimizeCount > 0); + m_forceVisibleByMinimizeCount--; + } + if (reason & PAINT_DISABLED_BY_ACTIVITY) { + Q_ASSERT(m_forceVisibleByActivityCount > 0); + m_forceVisibleByActivityCount--; + } + updateVisibility(); +} + void WindowItem::handleWindowClosed(Window *original, Deleted *deleted) { Q_UNUSED(original) m_window = deleted; } +bool WindowItem::computeVisibility() const +{ + if (m_window->isDeleted()) { + if (m_forceVisibleByDeleteCount == 0) { + return false; + } + } + if (!m_window->isOnCurrentDesktop()) { + if (m_forceVisibleByDesktopCount == 0) { + return false; + } + } + if (!m_window->isOnCurrentActivity()) { + if (m_forceVisibleByActivityCount == 0) { + return false; + } + } + if (m_window->isMinimized()) { + if (m_forceVisibleByMinimizeCount == 0) { + return false; + } + } + if (m_window->isHiddenInternal()) { + if (m_forceVisibleByHiddenCount == 0) { + return false; + } + } + return true; +} + +void WindowItem::updateVisibility() +{ + setVisible(computeVisibility()); +} + void WindowItem::updateSurfaceItem(SurfaceItem *surfaceItem) { m_surfaceItem.reset(surfaceItem); diff --git a/src/windowitem.h b/src/windowitem.h index c17144a7ff..225a21c9a8 100644 --- a/src/windowitem.h +++ b/src/windowitem.h @@ -34,11 +34,22 @@ class KWIN_EXPORT WindowItem : public Item Q_OBJECT public: + enum { + PAINT_DISABLED_BY_HIDDEN = 1 << 0, + PAINT_DISABLED_BY_DELETE = 1 << 1, + PAINT_DISABLED_BY_DESKTOP = 1 << 2, + PAINT_DISABLED_BY_MINIMIZE = 1 << 3, + PAINT_DISABLED_BY_ACTIVITY = 1 << 5 + }; + SurfaceItem *surfaceItem() const; DecorationItem *decorationItem() const; ShadowItem *shadowItem() const; Window *window() const; + void refVisible(int reason); + void unrefVisible(int reason); + protected: explicit WindowItem(Window *window, Item *parent = nullptr); void updateSurfaceItem(SurfaceItem *surfaceItem); @@ -51,10 +62,18 @@ private Q_SLOTS: void updateSurfaceVisibility(); private: + bool computeVisibility() const; + void updateVisibility(); + Window *m_window; QScopedPointer m_surfaceItem; QScopedPointer m_decorationItem; QScopedPointer m_shadowItem; + int m_forceVisibleByHiddenCount = 0; + int m_forceVisibleByDeleteCount = 0; + int m_forceVisibleByDesktopCount = 0; + int m_forceVisibleByMinimizeCount = 0; + int m_forceVisibleByActivityCount = 0; }; /** diff --git a/src/x11window.cpp b/src/x11window.cpp index 7c6d7b8994..b5ba228dc6 100644 --- a/src/x11window.cpp +++ b/src/x11window.cpp @@ -1351,10 +1351,6 @@ void X11Window::updateShape() // Decoration mask (i.e. 'else' here) setting is done in setMask() // when the decoration calls it or when the decoration is created/destroyed updateInputShape(); - if (Compositor::compositing()) { - addRepaintFull(); - addWorkspaceRepaint(visibleGeometry()); // In case shape change removes part of this window - } Q_EMIT geometryShapeChanged(this, frameGeometry()); } @@ -1518,9 +1514,6 @@ void X11Window::doSetShade(ShadeMode previousShadeMode) { // TODO: All this unmapping, resizing etc. feels too much duplicated from elsewhere if (isShade()) { - // shade_mode == ShadeNormal - addWorkspaceRepaint(visibleGeometry()); - // Shade shade_geometry_change = true; QSize s(implicitSize()); s.setHeight(borderTop() + borderBottom()); @@ -1679,7 +1672,6 @@ void X11Window::internalHide() if (old == Kept) { updateHiddenPreview(); } - addWorkspaceRepaint(visibleGeometry()); workspace()->windowHidden(this); Q_EMIT windowHidden(this); } @@ -1700,7 +1692,6 @@ void X11Window::internalKeep() workspace()->focusToNull(); // get rid of input focus, bug #317484 } updateHiddenPreview(); - addWorkspaceRepaint(visibleGeometry()); workspace()->windowHidden(this); } @@ -1726,7 +1717,6 @@ void X11Window::map() } else { exportMappingState(XCB_ICCCM_WM_STATE_ICONIC); } - addLayerRepaint(visibleGeometry()); } /**