From def99b1a7c256d81b56487844c8680869dbe9360 Mon Sep 17 00:00:00 2001 From: Vlad Zahorodnii Date: Wed, 27 Apr 2022 12:22:23 +0300 Subject: [PATCH] Update WindowItem's visibility With this, the WindowItem will know whether it's actually visible. As the result, if a native wayland window has been minimized, kwin won't try to schedule a new frame if just a frame callback has been committed. EffectWindow::enablePainting() and EffectWindow::disablePainting() act as a stone in the shoe. They have the final say whether the given window is visible and they are invoked too late in the rendering process. WindowItem needs to know whether the window is visible in advance, before compositing starts. This change replaces EffectWindow::enablePainting() and EffectWindow::disablePainting() with EffectWindow::refVisible() and EffectWindow::unrefVisible(). If an effect calls the refVisible() function, the window will be kept visible regardless of its state. It should be called when a window is minimized or closed, etc. If an effect doesn't want to paint a window, it should not call effects->paintWindow(). EffectWindow::refVisible() doesn't replace EffectWindow::refWindow() but supplements it. refVisible() only ensures that a window will be kept visible while refWindow() ensures that the window won't be destroyed until the effect is done with it. --- autotests/test_window_paint_data.cpp | 14 +-- src/effects.cpp | 14 ++- src/effects.h | 5 +- src/effects/blur/blur.cpp | 3 - src/effects/desktopgrid/desktopgrid.cpp | 33 +++---- src/effects/fallapart/fallapart.cpp | 2 +- src/effects/fallapart/fallapart.h | 1 + src/effects/glide/glide.cpp | 2 +- src/effects/glide/glide.h | 1 + src/effects/magiclamp/magiclamp.cpp | 2 +- src/effects/magiclamp/magiclamp.h | 1 + src/effects/presentwindows/presentwindows.cpp | 28 +++--- src/effects/presentwindows/presentwindows.h | 1 + src/effects/sheet/sheet.cpp | 2 +- src/effects/sheet/sheet.h | 1 + src/effects/slide/slide.cpp | 12 +-- src/effects/slideback/slideback.cpp | 3 +- src/effects/slidingpopups/slidingpopups.cpp | 6 +- src/effects/slidingpopups/slidingpopups.h | 1 + src/events.cpp | 2 - src/libkwineffects/anidata_p.h | 1 + src/libkwineffects/kwinanimationeffect.cpp | 17 +--- src/libkwineffects/kwineffects.h | 64 ++++++++++++- src/scene.cpp | 87 +++--------------- src/scene.h | 21 ----- src/waylandwindow.cpp | 2 - src/window.cpp | 3 - src/windowitem.cpp | 89 +++++++++++++++++++ src/windowitem.h | 19 ++++ src/x11window.cpp | 10 --- 30 files changed, 241 insertions(+), 206 deletions(-) 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()); } /**