From 9f2cb0ae1b6fa6a79158006714907abfac12929a Mon Sep 17 00:00:00 2001 From: Vlad Zahorodnii Date: Fri, 20 Nov 2020 17:44:04 +0200 Subject: [PATCH] Provide expected presentation time to effects Effects are given the interval between two consecutive frames. The main flaw of this approach is that if the Compositor transitions from the idle state to "active" state, i.e. when there is something to repaint, effects may see a very large interval between the last painted frame and the current. In order to address this issue, the Scene invalidates the timer that is used to measure time between consecutive frames before the Compositor is about to become idle. While this works perfectly fine with Xinerama-style rendering, with per screen rendering, determining whether the compositor is about to idle is rather a tedious task mostly because a single output can't be used for the test. Furthermore, since the Compositor schedules pointless repaints just to ensure that it's idle, it might take several attempts to figure out whether the scene timer must be invalidated if you use (true) per screen rendering. Ideally, all effects should use a timeline helper that is aware of the underlying render loop and its timings. However, this option is off the table because it will involve a lot of work to implement it. Alternative and much simpler option is to pass the expected presentation time to effects rather than time between consecutive frames. This means that effects are responsible for determining how much animation timelines have to be advanced. Typically, an effect would have to store the presentation timestamp provided in either prePaint{Screen,Window} and use it in the subsequent prePaint{Screen,Window} call to estimate the amount of time passed between the next and the last frames. Unfortunately, this is an API incompatible change. However, it shouldn't take a lot of work to port third-party binary effects, which don't use the AnimationEffect class, to the new API. On the bright side, we no longer need to be concerned about the Compositor getting idle. We do still try to determine whether the Compositor is about to idle, primarily, because the OpenGL render backend swaps buffers on present, but that will change with the ongoing compositing timing rework. --- autotests/mock_effectshandler.h | 4 +- composite.cpp | 8 +- effects.cpp | 8 +- effects.h | 4 +- effects/backgroundcontrast/contrast.cpp | 8 +- effects/backgroundcontrast/contrast.h | 4 +- effects/blur/blur.cpp | 8 +- effects/blur/blur.h | 4 +- effects/coverswitch/coverswitch.cpp | 16 +++- effects/coverswitch/coverswitch.h | 3 +- effects/cube/cube.cpp | 26 ++++-- effects/cube/cube.h | 5 +- effects/cubeslide/cubeslide.cpp | 22 +++-- effects/cubeslide/cubeslide.h | 5 +- effects/desktopgrid/desktopgrid.cpp | 34 +++++-- effects/desktopgrid/desktopgrid.h | 5 +- effects/diminactive/diminactive.cpp | 14 ++- effects/diminactive/diminactive.h | 3 +- effects/fallapart/fallapart.cpp | 30 ++++--- effects/fallapart/fallapart.h | 12 ++- effects/flipswitch/flipswitch.cpp | 16 +++- effects/flipswitch/flipswitch.h | 5 +- effects/glide/glide.cpp | 42 +++++---- effects/glide/glide.h | 12 ++- effects/highlightwindow/highlightwindow.cpp | 85 +++++++++++------- effects/highlightwindow/highlightwindow.h | 10 ++- effects/kscreen/kscreen.cpp | 23 +++-- effects/kscreen/kscreen.h | 5 +- effects/lookingglass/lookingglass.cpp | 11 ++- effects/lookingglass/lookingglass.h | 3 +- effects/magiclamp/magiclamp.cpp | 46 +++++----- effects/magiclamp/magiclamp.h | 12 ++- effects/magnifier/magnifier.cpp | 14 ++- effects/magnifier/magnifier.h | 3 +- effects/mouseclick/mouseclick.cpp | 12 ++- effects/mouseclick/mouseclick.h | 3 +- effects/presentwindows/presentwindows.cpp | 98 ++++++++++++++------- effects/presentwindows/presentwindows.h | 8 +- effects/resize/resize.cpp | 8 +- effects/resize/resize.h | 4 +- effects/screenedge/screenedgeeffect.cpp | 4 +- effects/screenedge/screenedgeeffect.h | 2 +- effects/sheet/sheet.cpp | 16 ++-- effects/sheet/sheet.h | 5 +- effects/showfps/showfps.cpp | 4 +- effects/showfps/showfps.h | 2 +- effects/slide/slide.cpp | 17 ++-- effects/slide/slide.h | 5 +- effects/slideback/slideback.cpp | 17 +++- effects/slideback/slideback.h | 5 +- effects/slidingpopups/slidingpopups.cpp | 14 ++- effects/slidingpopups/slidingpopups.h | 3 +- effects/snaphelper/snaphelper.cpp | 13 ++- effects/snaphelper/snaphelper.h | 3 +- effects/startupfeedback/startupfeedback.cpp | 13 ++- effects/startupfeedback/startupfeedback.h | 3 +- effects/touchpoints/touchpoints.cpp | 15 +++- effects/touchpoints/touchpoints.h | 3 +- effects/trackmouse/trackmouse.cpp | 4 +- effects/trackmouse/trackmouse.h | 2 +- effects/wobblywindows/wobblywindows.cpp | 19 ++-- effects/wobblywindows/wobblywindows.h | 6 +- effects/zoom/zoom.cpp | 12 ++- effects/zoom/zoom.h | 3 +- libkwineffects/anidata.cpp | 2 + libkwineffects/anidata_p.h | 1 + libkwineffects/kwinanimationeffect.cpp | 15 ++-- libkwineffects/kwinanimationeffect.h | 4 +- libkwineffects/kwineffects.cpp | 8 +- libkwineffects/kwineffects.h | 16 +++- plugins/scenes/opengl/scene_opengl.cpp | 6 +- plugins/scenes/opengl/scene_opengl.h | 3 +- plugins/scenes/qpainter/scene_qpainter.cpp | 6 +- plugins/scenes/qpainter/scene_qpainter.h | 3 +- plugins/scenes/xrender/scene_xrender.cpp | 5 +- plugins/scenes/xrender/scene_xrender.h | 3 +- scene.cpp | 40 +++------ scene.h | 14 +-- 78 files changed, 631 insertions(+), 328 deletions(-) diff --git a/autotests/mock_effectshandler.h b/autotests/mock_effectshandler.h index 9a0f6a6fb2..28f30ce3a8 100644 --- a/autotests/mock_effectshandler.h +++ b/autotests/mock_effectshandler.h @@ -167,8 +167,8 @@ public: void paintWindow(KWin::EffectWindow *, int, const QRegion &, KWin::WindowPaintData &) override {} void postPaintScreen() override {} void postPaintWindow(KWin::EffectWindow *) override {} - void prePaintScreen(KWin::ScreenPrePaintData &, int) override {} - void prePaintWindow(KWin::EffectWindow *, KWin::WindowPrePaintData &, int) override {} + void prePaintScreen(KWin::ScreenPrePaintData &, std::chrono::milliseconds) override {} + void prePaintWindow(KWin::EffectWindow *, KWin::WindowPrePaintData &, std::chrono::milliseconds) override {} QByteArray readRootProperty(long int, long int, int) const override { return QByteArray(); } diff --git a/composite.cpp b/composite.cpp index 1bf598545c..0bae7ef4fd 100644 --- a/composite.cpp +++ b/composite.cpp @@ -681,16 +681,20 @@ void Compositor::performCompositing() // clear all repaints, so that post-pass can add repaints for the next repaint repaints_region = QRegion(); + const std::chrono::nanoseconds now = std::chrono::steady_clock::now().time_since_epoch(); + const std::chrono::milliseconds presentTime = + std::chrono::duration_cast(now); + if (m_framesToTestForSafety > 0 && (m_scene->compositingType() & OpenGLCompositing)) { kwinApp()->platform()->createOpenGLSafePoint(Platform::OpenGLSafePoint::PreFrame); } m_renderTimer.start(); if (kwinApp()->platform()->isPerScreenRenderingEnabled()) { for (int screenId = 0; screenId < screens()->count(); ++screenId) { - m_scene->paint(screenId, repaints, windows); + m_scene->paint(screenId, repaints, windows, presentTime); } } else { - m_scene->paint(-1, repaints, windows); + m_scene->paint(-1, repaints, windows, presentTime); } m_timeSinceLastVBlank = m_renderTimer.elapsed(); if (m_framesToTestForSafety > 0) { diff --git a/effects.cpp b/effects.cpp index 967d7170b2..58c8eebe50 100644 --- a/effects.cpp +++ b/effects.cpp @@ -363,10 +363,10 @@ void EffectsHandlerImpl::reconfigure() } // the idea is that effects call this function again which calls the next one -void EffectsHandlerImpl::prePaintScreen(ScreenPrePaintData& data, int time) +void EffectsHandlerImpl::prePaintScreen(ScreenPrePaintData& data, std::chrono::milliseconds presentTime) { if (m_currentPaintScreenIterator != m_activeEffects.constEnd()) { - (*m_currentPaintScreenIterator++)->prePaintScreen(data, time); + (*m_currentPaintScreenIterator++)->prePaintScreen(data, presentTime); --m_currentPaintScreenIterator; } // no special final code @@ -406,10 +406,10 @@ void EffectsHandlerImpl::postPaintScreen() // no special final code } -void EffectsHandlerImpl::prePaintWindow(EffectWindow* w, WindowPrePaintData& data, int time) +void EffectsHandlerImpl::prePaintWindow(EffectWindow* w, WindowPrePaintData& data, std::chrono::milliseconds presentTime) { if (m_currentPaintWindowIterator != m_activeEffects.constEnd()) { - (*m_currentPaintWindowIterator++)->prePaintWindow(w, data, time); + (*m_currentPaintWindowIterator++)->prePaintWindow(w, data, presentTime); --m_currentPaintWindowIterator; } // no special final code diff --git a/effects.h b/effects.h index dd02767bfa..e069886d0b 100644 --- a/effects.h +++ b/effects.h @@ -59,14 +59,14 @@ class KWIN_EXPORT EffectsHandlerImpl : public EffectsHandler public: EffectsHandlerImpl(Compositor *compositor, Scene *scene); ~EffectsHandlerImpl() override; - void prePaintScreen(ScreenPrePaintData& data, int time) override; + void prePaintScreen(ScreenPrePaintData& data, std::chrono::milliseconds presentTime) override; void paintScreen(int mask, const QRegion ®ion, ScreenPaintData& data) override; /** * Special hook to perform a paintScreen but just with the windows on @p desktop. */ void paintDesktop(int desktop, int mask, QRegion region, ScreenPaintData& data); void postPaintScreen() override; - void prePaintWindow(EffectWindow* w, WindowPrePaintData& data, int time) override; + void prePaintWindow(EffectWindow* w, WindowPrePaintData& data, std::chrono::milliseconds presentTime) override; void paintWindow(EffectWindow* w, int mask, const QRegion ®ion, WindowPaintData& data) override; void postPaintWindow(EffectWindow* w) override; void paintEffectFrame(EffectFrame* frame, const QRegion ®ion, double opacity, double frameOpacity) override; diff --git a/effects/backgroundcontrast/contrast.cpp b/effects/backgroundcontrast/contrast.cpp index 2c20a200aa..6e548eec47 100644 --- a/effects/backgroundcontrast/contrast.cpp +++ b/effects/backgroundcontrast/contrast.cpp @@ -336,19 +336,19 @@ void ContrastEffect::uploadGeometry(GLVertexBuffer *vbo, const QRegion ®ion) vbo->setAttribLayout(layout, 2, sizeof(QVector2D)); } -void ContrastEffect::prePaintScreen(ScreenPrePaintData &data, int time) +void ContrastEffect::prePaintScreen(ScreenPrePaintData &data, std::chrono::milliseconds presentTime) { m_paintedArea = QRegion(); m_currentContrast = QRegion(); - effects->prePaintScreen(data, time); + effects->prePaintScreen(data, presentTime); } -void ContrastEffect::prePaintWindow(EffectWindow* w, WindowPrePaintData& data, int time) +void ContrastEffect::prePaintWindow(EffectWindow* w, WindowPrePaintData& data, std::chrono::milliseconds presentTime) { // this effect relies on prePaintWindow being called in the bottom to top order - effects->prePaintWindow(w, data, time); + effects->prePaintWindow(w, data, presentTime); if (!w->isPaintingEnabled()) { return; diff --git a/effects/backgroundcontrast/contrast.h b/effects/backgroundcontrast/contrast.h index c4ca3e21ab..a2ea3eb10e 100644 --- a/effects/backgroundcontrast/contrast.h +++ b/effects/backgroundcontrast/contrast.h @@ -37,8 +37,8 @@ public: static QMatrix4x4 colorMatrix(qreal contrast, qreal intensity, qreal saturation); void reconfigure(ReconfigureFlags flags) override; - void prePaintScreen(ScreenPrePaintData &data, int time) override; - void prePaintWindow(EffectWindow *w, WindowPrePaintData &data, int time) override; + void prePaintScreen(ScreenPrePaintData &data, std::chrono::milliseconds presentTime) override; + void prePaintWindow(EffectWindow *w, WindowPrePaintData &data, std::chrono::milliseconds presentTime) override; void drawWindow(EffectWindow *w, int mask, const QRegion ®ion, WindowPaintData &data) override; void paintEffectFrame(EffectFrame *frame, const QRegion ®ion, double opacity, double frameOpacity) override; diff --git a/effects/blur/blur.cpp b/effects/blur/blur.cpp index 201383aa70..63eae7ec1c 100644 --- a/effects/blur/blur.cpp +++ b/effects/blur/blur.cpp @@ -469,19 +469,19 @@ void BlurEffect::uploadGeometry(GLVertexBuffer *vbo, const QRegion &blurRegion, vbo->setAttribLayout(layout, 2, sizeof(QVector2D)); } -void BlurEffect::prePaintScreen(ScreenPrePaintData &data, int time) +void BlurEffect::prePaintScreen(ScreenPrePaintData &data, std::chrono::milliseconds presentTime) { m_paintedArea = QRegion(); m_currentBlur = QRegion(); - effects->prePaintScreen(data, time); + effects->prePaintScreen(data, presentTime); } -void BlurEffect::prePaintWindow(EffectWindow* w, WindowPrePaintData& data, int time) +void BlurEffect::prePaintWindow(EffectWindow* w, WindowPrePaintData& data, std::chrono::milliseconds presentTime) { // this effect relies on prePaintWindow being called in the bottom to top order - effects->prePaintWindow(w, data, time); + effects->prePaintWindow(w, data, presentTime); if (!w->isPaintingEnabled()) { return; diff --git a/effects/blur/blur.h b/effects/blur/blur.h index fdf5f135b2..8638abfe8f 100644 --- a/effects/blur/blur.h +++ b/effects/blur/blur.h @@ -40,8 +40,8 @@ public: static bool enabledByDefault(); void reconfigure(ReconfigureFlags flags) override; - void prePaintScreen(ScreenPrePaintData &data, int time) override; - void prePaintWindow(EffectWindow* w, WindowPrePaintData& data, int time) override; + void prePaintScreen(ScreenPrePaintData &data, std::chrono::milliseconds presentTime) override; + void prePaintWindow(EffectWindow* w, WindowPrePaintData& data, std::chrono::milliseconds presentTime) override; void drawWindow(EffectWindow *w, int mask, const QRegion ®ion, WindowPaintData &data) override; void paintEffectFrame(EffectFrame *frame, const QRegion ®ion, double opacity, double frameOpacity) override; diff --git a/effects/coverswitch/coverswitch.cpp b/effects/coverswitch/coverswitch.cpp index db8f6d12d4..a42ffa95c2 100644 --- a/effects/coverswitch/coverswitch.cpp +++ b/effects/coverswitch/coverswitch.cpp @@ -34,6 +34,7 @@ CoverSwitchEffect::CoverSwitchEffect() , stop(false) , stopRequested(false) , startRequested(false) + , lastPresentTime(std::chrono::milliseconds::zero()) , zPosition(900.0) , scaleFactor(0.0) , direction(Left) @@ -103,17 +104,23 @@ void CoverSwitchEffect::reconfigure(ReconfigureFlags) } -void CoverSwitchEffect::prePaintScreen(ScreenPrePaintData& data, int time) +void CoverSwitchEffect::prePaintScreen(ScreenPrePaintData& data, std::chrono::milliseconds presentTime) { + std::chrono::milliseconds delta = std::chrono::milliseconds::zero(); + if (lastPresentTime.count()) { + delta = presentTime - lastPresentTime; + } + lastPresentTime = presentTime; + if (mActivated || stop || stopRequested) { data.mask |= Effect::PAINT_SCREEN_WITH_TRANSFORMED_WINDOWS; if (animation || start || stop) { - timeLine.update(std::chrono::milliseconds(time)); + timeLine.update(delta); } if (selected_window == nullptr) abort(); } - effects->prePaintScreen(data, time); + effects->prePaintScreen(data, presentTime); } void CoverSwitchEffect::paintScreen(int mask, const QRegion ®ion, ScreenPaintData& data) @@ -285,6 +292,7 @@ void CoverSwitchEffect::postPaintScreen() } referrencedWindows.clear(); currentWindowList.clear(); + lastPresentTime = std::chrono::milliseconds::zero(); if (startRequested) { startRequested = false; mActivated = true; @@ -538,6 +546,7 @@ void CoverSwitchEffect::slotTabBoxClosed() start = false; animation = false; timeLine.reset(); + lastPresentTime = std::chrono::milliseconds::zero(); } mActivated = false; effects->unrefTabBox(); @@ -907,6 +916,7 @@ void CoverSwitchEffect::abort() } effects->setActiveFullScreenEffect(nullptr); timeLine.reset(); + lastPresentTime = std::chrono::milliseconds::zero(); mActivated = false; stop = false; stopRequested = false; diff --git a/effects/coverswitch/coverswitch.h b/effects/coverswitch/coverswitch.h index d48b39b9e2..a3202f0f2d 100644 --- a/effects/coverswitch/coverswitch.h +++ b/effects/coverswitch/coverswitch.h @@ -42,7 +42,7 @@ public: ~CoverSwitchEffect() override; void reconfigure(ReconfigureFlags) override; - void prePaintScreen(ScreenPrePaintData &data, int time) override; + void prePaintScreen(ScreenPrePaintData &data, std::chrono::milliseconds presentTime) override; void paintScreen(int mask, const QRegion ®ion, ScreenPaintData &data) override; void postPaintScreen() override; void paintWindow(EffectWindow *w, int mask, QRegion region, WindowPaintData &data) override; @@ -123,6 +123,7 @@ private: bool stopRequested; bool startRequested; TimeLine timeLine; + std::chrono::milliseconds lastPresentTime; QRect area; float zPosition; float scaleFactor; diff --git a/effects/cube/cube.cpp b/effects/cube/cube.cpp index 9aa45f8a8c..9d8d643895 100644 --- a/effects/cube/cube.cpp +++ b/effects/cube/cube.cpp @@ -50,6 +50,7 @@ CubeEffect::CubeEffect() , wallpaper(nullptr) , texturedCaps(true) , capTexture(nullptr) + , lastPresentTime(std::chrono::milliseconds::zero()) , reflectionPainting(false) , activeScreen(0) , bottomCap(false) @@ -360,8 +361,14 @@ void CubeEffect::startVerticalAnimation(VerticalAnimationState state) verticalAnimationState = state; } -void CubeEffect::prePaintScreen(ScreenPrePaintData& data, int time) +void CubeEffect::prePaintScreen(ScreenPrePaintData& data, std::chrono::milliseconds presentTime) { + std::chrono::milliseconds delta = std::chrono::milliseconds::zero(); + if (lastPresentTime.count()) { + delta = presentTime - lastPresentTime; + } + lastPresentTime = presentTime; + if (activated) { data.mask |= PAINT_SCREEN_TRANSFORMED | Effect::PAINT_SCREEN_WITH_TRANSFORMED_WINDOWS | PAINT_SCREEN_BACKGROUND_FIRST; if (animationState == AnimationState::None && !animations.empty()) { @@ -373,15 +380,15 @@ void CubeEffect::prePaintScreen(ScreenPrePaintData& data, int time) if (animationState != AnimationState::None || verticalAnimationState != VerticalAnimationState::None) { if (animationState != AnimationState::None) { - timeLine.update(std::chrono::milliseconds(time)); + timeLine.update(delta); } if (verticalAnimationState != VerticalAnimationState::None) { - verticalTimeLine.update(std::chrono::milliseconds(time)); + verticalTimeLine.update(delta); } rotateCube(); } } - effects->prePaintScreen(data, time); + effects->prePaintScreen(data, presentTime); } void CubeEffect::paintScreen(int mask, const QRegion ®ion, ScreenPaintData& data) @@ -973,6 +980,7 @@ void CubeEffect::postPaintScreen() animations.clear(); verticalAnimationState = VerticalAnimationState::None; verticalAnimations.clear(); + lastPresentTime = std::chrono::milliseconds::zero(); } else { if (!animations.empty()) startAnimation(animations.dequeue()); @@ -991,10 +999,12 @@ void CubeEffect::postPaintScreen() /* Repaint if there is any animation */ if (animation) { effects->addRepaintFull(); + } else { + lastPresentTime = std::chrono::milliseconds::zero(); } } -void CubeEffect::prePaintWindow(EffectWindow* w, WindowPrePaintData& data, int time) +void CubeEffect::prePaintWindow(EffectWindow* w, WindowPrePaintData& data, std::chrono::milliseconds presentTime) { if (activated) { if (cube_painting) { @@ -1046,7 +1056,7 @@ void CubeEffect::prePaintWindow(EffectWindow* w, WindowPrePaintData& data, int t data.quads = data.quads.splitAtY(rect.height() - w->y()); } data.setTransformed(); - effects->prePaintWindow(w, data, time); + effects->prePaintWindow(w, data, presentTime); return; } } @@ -1066,7 +1076,7 @@ void CubeEffect::prePaintWindow(EffectWindow* w, WindowPrePaintData& data, int t data.quads = data.quads.splitAtY(rect.height() - w->y()); } data.setTransformed(); - effects->prePaintWindow(w, data, time); + effects->prePaintWindow(w, data, presentTime); return; } } @@ -1074,7 +1084,7 @@ void CubeEffect::prePaintWindow(EffectWindow* w, WindowPrePaintData& data, int t } } } - effects->prePaintWindow(w, data, time); + effects->prePaintWindow(w, data, presentTime); } void CubeEffect::paintWindow(EffectWindow* w, int mask, QRegion region, WindowPaintData& data) diff --git a/effects/cube/cube.h b/effects/cube/cube.h index 026f08c494..5388bc3d3b 100644 --- a/effects/cube/cube.h +++ b/effects/cube/cube.h @@ -47,10 +47,10 @@ public: CubeEffect(); ~CubeEffect() override; void reconfigure(ReconfigureFlags) override; - void prePaintScreen(ScreenPrePaintData& data, int time) override; + void prePaintScreen(ScreenPrePaintData& data, std::chrono::milliseconds presentTime) override; void paintScreen(int mask, const QRegion ®ion, ScreenPaintData& data) override; void postPaintScreen() override; - void prePaintWindow(EffectWindow* w, WindowPrePaintData& data, int time) override; + void prePaintWindow(EffectWindow* w, WindowPrePaintData& data, std::chrono::milliseconds presentTime) override; void paintWindow(EffectWindow* w, int mask, QRegion region, WindowPaintData& data) override; bool borderActivated(ElectricBorder border) override; void grabbedKeyboardEvent(QKeyEvent* e) override; @@ -200,6 +200,7 @@ private: VerticalAnimationState verticalAnimationState; TimeLine verticalTimeLine; QQueue verticalAnimations; + std::chrono::milliseconds lastPresentTime; bool reflectionPainting; std::chrono::milliseconds rotationDuration; diff --git a/effects/cubeslide/cubeslide.cpp b/effects/cubeslide/cubeslide.cpp index a32714a33f..3ed7c46618 100644 --- a/effects/cubeslide/cubeslide.cpp +++ b/effects/cubeslide/cubeslide.cpp @@ -22,6 +22,7 @@ namespace KWin CubeSlideEffect::CubeSlideEffect() : stickyPainting(false) + , lastPresentTime(std::chrono::milliseconds::zero()) , windowMoving(false) , desktopChangedWhileMoving(false) , progressRestriction(0.0f) @@ -64,15 +65,21 @@ void CubeSlideEffect::reconfigure(ReconfigureFlags) useWindowMoving = CubeSlideConfig::useWindowMoving(); } -void CubeSlideEffect::prePaintScreen(ScreenPrePaintData& data, int time) +void CubeSlideEffect::prePaintScreen(ScreenPrePaintData& data, std::chrono::milliseconds presentTime) { + std::chrono::milliseconds delta = std::chrono::milliseconds::zero(); + if (lastPresentTime.count()) { + delta = presentTime - lastPresentTime; + } + lastPresentTime = presentTime; + if (isActive()) { data.mask |= PAINT_SCREEN_TRANSFORMED | PAINT_SCREEN_WITH_TRANSFORMED_WINDOWS | PAINT_SCREEN_BACKGROUND_FIRST; - timeLine.setCurrentTime(timeLine.currentTime() + time); + timeLine.setCurrentTime(timeLine.currentTime() + delta.count()); if (windowMoving && timeLine.currentTime() > progressRestriction * (qreal)timeLine.duration()) timeLine.setCurrentTime(progressRestriction * (qreal)timeLine.duration()); } - effects->prePaintScreen(data, time); + effects->prePaintScreen(data, presentTime); } void CubeSlideEffect::paintScreen(int mask, const QRegion ®ion, ScreenPaintData& data) @@ -169,7 +176,7 @@ void CubeSlideEffect::paintSlideCube(int mask, QRegion region, ScreenPaintData& painting_desktop = effects->currentDesktop(); } -void CubeSlideEffect::prePaintWindow(EffectWindow* w, WindowPrePaintData& data, int time) +void CubeSlideEffect::prePaintWindow(EffectWindow* w, WindowPrePaintData& data, std::chrono::milliseconds presentTime) { if (stickyPainting) { if (staticWindows.contains(w)) { @@ -180,7 +187,7 @@ void CubeSlideEffect::prePaintWindow(EffectWindow* w, WindowPrePaintData& data, } else if (isActive() && cube_painting) { if (staticWindows.contains(w)) { w->disablePainting(EffectWindow::PAINT_DISABLED_BY_DESKTOP); - effects->prePaintWindow(w, data, time); + effects->prePaintWindow(w, data, presentTime); return; } QRect rect = effects->clientArea(FullArea, effects->activeScreen(), painting_desktop); @@ -230,7 +237,7 @@ void CubeSlideEffect::prePaintWindow(EffectWindow* w, WindowPrePaintData& data, } else w->disablePainting(EffectWindow::PAINT_DISABLED_BY_DESKTOP); } - effects->prePaintWindow(w, data, time); + effects->prePaintWindow(w, data, presentTime); } void CubeSlideEffect::paintWindow(EffectWindow* w, int mask, QRegion region, WindowPaintData& data) @@ -375,6 +382,7 @@ void CubeSlideEffect::postPaintScreen() w->setData(WindowForceBackgroundContrastRole, QVariant()); } staticWindows.clear(); + lastPresentTime = std::chrono::milliseconds::zero(); effects->setActiveFullScreenEffect(nullptr); } } @@ -572,6 +580,7 @@ void CubeSlideEffect::slotWindowStepUserMovedResized(EffectWindow* w) windowMoving = false; desktopChangedWhileMoving = false; timeLine.setCurrentTime(0); + lastPresentTime = std::chrono::milliseconds::zero(); if (!slideRotations.isEmpty()) slideRotations.clear(); effects->setActiveFullScreenEffect(nullptr); @@ -652,6 +661,7 @@ void CubeSlideEffect::slotNumberDesktopsChanged() slideRotations.clear(); staticWindows.clear(); + lastPresentTime = std::chrono::milliseconds::zero(); effects->setActiveFullScreenEffect(nullptr); } diff --git a/effects/cubeslide/cubeslide.h b/effects/cubeslide/cubeslide.h index 5625f2fa5f..e4f38ca757 100644 --- a/effects/cubeslide/cubeslide.h +++ b/effects/cubeslide/cubeslide.h @@ -31,10 +31,10 @@ public: CubeSlideEffect(); ~CubeSlideEffect() override; void reconfigure(ReconfigureFlags) override; - void prePaintScreen(ScreenPrePaintData& data, int time) override; + void prePaintScreen(ScreenPrePaintData& data, std::chrono::milliseconds presentTime) override; void paintScreen(int mask, const QRegion ®ion, ScreenPaintData& data) override; void postPaintScreen() override; - void prePaintWindow(EffectWindow* w, WindowPrePaintData& data, int time) override; + void prePaintWindow(EffectWindow* w, WindowPrePaintData& data, std::chrono::milliseconds presentTime) override; void paintWindow(EffectWindow* w, int mask, QRegion region, WindowPaintData& data) override; bool isActive() const override; @@ -90,6 +90,7 @@ private: bool stickyPainting; QSet staticWindows; QTimeLine timeLine; + std::chrono::milliseconds lastPresentTime; QQueue slideRotations; bool dontSlidePanels; bool dontSlideStickyWindows; diff --git a/effects/desktopgrid/desktopgrid.cpp b/effects/desktopgrid/desktopgrid.cpp index 58f9204c89..e454622ecc 100644 --- a/effects/desktopgrid/desktopgrid.cpp +++ b/effects/desktopgrid/desktopgrid.cpp @@ -49,6 +49,7 @@ DesktopGridEffect::DesktopGridEffect() , windowMove(nullptr) , windowMoveDiff() , windowMoveElevateTimer(new QTimer(this)) + , lastPresentTime(std::chrono::milliseconds::zero()) , gridSize() , orientation(Qt::Horizontal) , activeCell(1, 1) @@ -143,8 +144,17 @@ void DesktopGridEffect::reconfigure(ReconfigureFlags) //----------------------------------------------------------------------------- // Screen painting -void DesktopGridEffect::prePaintScreen(ScreenPrePaintData& data, int time) +void DesktopGridEffect::prePaintScreen(ScreenPrePaintData& data, std::chrono::milliseconds presentTime) { + // The animation code assumes that the time diff cannot be 0, let's work around it. + int time; + if (lastPresentTime.count()) { + time = std::max(1, int((presentTime - lastPresentTime).count())); + } else { + time = 1; + } + lastPresentTime = presentTime; + if (timeline.currentValue() != 0 || activated || (isUsingPresentWindows() && isMotionManagerMovingWindows())) { if (activated) timeline.setCurrentTime(timeline.currentTime() + time); @@ -173,7 +183,7 @@ void DesktopGridEffect::prePaintScreen(ScreenPrePaintData& data, int time) w->setData(WindowForceBlurRole, QVariant(true)); } - effects->prePaintScreen(data, time); + effects->prePaintScreen(data, presentTime); } void DesktopGridEffect::paintScreen(int mask, const QRegion ®ion, ScreenPaintData& data) @@ -237,20 +247,31 @@ void DesktopGridEffect::paintScreen(int mask, const QRegion ®ion, ScreenPaint void DesktopGridEffect::postPaintScreen() { - if (activated ? timeline.currentValue() != 1 : timeline.currentValue() != 0) + bool resetLastPresentTime = true; + + if (activated ? timeline.currentValue() != 1 : timeline.currentValue() != 0) { effects->addRepaintFull(); // Repaint during zoom - if (isUsingPresentWindows() && isMotionManagerMovingWindows()) + resetLastPresentTime = false; + } + if (isUsingPresentWindows() && isMotionManagerMovingWindows()) { effects->addRepaintFull(); + resetLastPresentTime = false; + } if (activated) { for (int i = 0; i < effects->numberOfDesktops(); i++) { if (hoverTimeline[i]->currentValue() != 0.0 && hoverTimeline[i]->currentValue() != 1.0) { // Repaint during soft highlighting effects->addRepaintFull(); + resetLastPresentTime = false; break; } } } + if (resetLastPresentTime) { + lastPresentTime = std::chrono::milliseconds::zero(); + } + for (auto &w : effects->stackingOrder()) { w->setData(WindowForceBlurRole, QVariant()); } @@ -261,7 +282,7 @@ void DesktopGridEffect::postPaintScreen() //----------------------------------------------------------------------------- // Window painting -void DesktopGridEffect::prePaintWindow(EffectWindow* w, WindowPrePaintData& data, int time) +void DesktopGridEffect::prePaintWindow(EffectWindow* w, WindowPrePaintData& data, std::chrono::milliseconds presentTime) { if (timeline.currentValue() != 0 || (isUsingPresentWindows() && isMotionManagerMovingWindows())) { if (w->isOnDesktop(paintingDesktop)) { @@ -287,7 +308,7 @@ void DesktopGridEffect::prePaintWindow(EffectWindow* w, WindowPrePaintData& data } else w->disablePainting(EffectWindow::PAINT_DISABLED_BY_DESKTOP); } - effects->prePaintWindow(w, data, time); + effects->prePaintWindow(w, data, presentTime); } void DesktopGridEffect::paintWindow(EffectWindow* w, int mask, QRegion region, WindowPaintData& data) @@ -1218,6 +1239,7 @@ void DesktopGridEffect::finish() if (keyboardGrab) effects->ungrabKeyboard(); keyboardGrab = false; + lastPresentTime = std::chrono::milliseconds::zero(); effects->stopMouseInterception(this); effects->setActiveFullScreenEffect(nullptr); if (isUsingPresentWindows()) { diff --git a/effects/desktopgrid/desktopgrid.h b/effects/desktopgrid/desktopgrid.h index ec1aa4799f..321d06fe53 100644 --- a/effects/desktopgrid/desktopgrid.h +++ b/effects/desktopgrid/desktopgrid.h @@ -39,10 +39,10 @@ public: DesktopGridEffect(); ~DesktopGridEffect() override; void reconfigure(ReconfigureFlags) override; - void prePaintScreen(ScreenPrePaintData& data, int time) override; + void prePaintScreen(ScreenPrePaintData& data, std::chrono::milliseconds presentTime) override; void paintScreen(int mask, const QRegion ®ion, ScreenPaintData& data) override; void postPaintScreen() override; - void prePaintWindow(EffectWindow* w, WindowPrePaintData& data, int time) override; + void prePaintWindow(EffectWindow* w, WindowPrePaintData& data, std::chrono::milliseconds presentTime) override; void paintWindow(EffectWindow* w, int mask, QRegion region, WindowPaintData& data) override; void windowInputMouseEvent(QEvent* e) override; void grabbedKeyboardEvent(QKeyEvent* e) override; @@ -131,6 +131,7 @@ private: QPoint windowMoveDiff; QPoint dragStartPos; QTimer *windowMoveElevateTimer; + std::chrono::milliseconds lastPresentTime; // Soft highlighting QList hoverTimeline; diff --git a/effects/diminactive/diminactive.cpp b/effects/diminactive/diminactive.cpp index 837421f10b..71e8c22e0c 100644 --- a/effects/diminactive/diminactive.cpp +++ b/effects/diminactive/diminactive.cpp @@ -82,9 +82,13 @@ void DimInactiveEffect::reconfigure(ReconfigureFlags flags) effects->addRepaintFull(); } -void DimInactiveEffect::prePaintScreen(ScreenPrePaintData &data, int time) +void DimInactiveEffect::prePaintScreen(ScreenPrePaintData &data, std::chrono::milliseconds presentTime) { - const std::chrono::milliseconds delta(time); + std::chrono::milliseconds delta(0); + if (m_lastPresentTime.count()) { + delta = presentTime - m_lastPresentTime; + } + m_lastPresentTime = presentTime; if (m_fullScreenTransition.active) { m_fullScreenTransition.timeLine.update(delta); @@ -96,7 +100,7 @@ void DimInactiveEffect::prePaintScreen(ScreenPrePaintData &data, int time) ++transitionIt; } - effects->prePaintScreen(data, time); + effects->prePaintScreen(data, presentTime); } void DimInactiveEffect::paintWindow(EffectWindow *w, int mask, QRegion region, WindowPaintData &data) @@ -144,6 +148,10 @@ void DimInactiveEffect::postPaintScreen() w->addRepaintFull(); } + if (m_transitions.isEmpty() && !m_fullScreenTransition.active) { + m_lastPresentTime = std::chrono::milliseconds::zero(); + } + effects->postPaintScreen(); } diff --git a/effects/diminactive/diminactive.h b/effects/diminactive/diminactive.h index 9c01f06093..18c90a10a0 100644 --- a/effects/diminactive/diminactive.h +++ b/effects/diminactive/diminactive.h @@ -34,7 +34,7 @@ public: void reconfigure(ReconfigureFlags flags) override; - void prePaintScreen(ScreenPrePaintData &data, int time) override; + void prePaintScreen(ScreenPrePaintData &data, std::chrono::milliseconds presentTime) override; void paintWindow(EffectWindow *w, int mask, QRegion region, WindowPaintData &data) override; void postPaintScreen() override; @@ -77,6 +77,7 @@ private: const EffectWindowGroup *m_activeWindowGroup; QHash m_transitions; QHash m_forceDim; + std::chrono::milliseconds m_lastPresentTime = std::chrono::milliseconds::zero(); struct { bool active = false; diff --git a/effects/fallapart/fallapart.cpp b/effects/fallapart/fallapart.cpp index d521180a90..2f4b4fe0f4 100644 --- a/effects/fallapart/fallapart.cpp +++ b/effects/fallapart/fallapart.cpp @@ -36,18 +36,25 @@ void FallApartEffect::reconfigure(ReconfigureFlags) blockSize = FallApartConfig::blockSize(); } -void FallApartEffect::prePaintScreen(ScreenPrePaintData& data, int time) +void FallApartEffect::prePaintScreen(ScreenPrePaintData& data, std::chrono::milliseconds presentTime) { if (!windows.isEmpty()) data.mask |= PAINT_SCREEN_WITH_TRANSFORMED_WINDOWS; - effects->prePaintScreen(data, time); + effects->prePaintScreen(data, presentTime); } -void FallApartEffect::prePaintWindow(EffectWindow* w, WindowPrePaintData& data, int time) +void FallApartEffect::prePaintWindow(EffectWindow* w, WindowPrePaintData& data, std::chrono::milliseconds presentTime) { - if (windows.contains(w) && isRealWindow(w)) { - if (windows[ w ] < 1) { - windows[ w ] += time / animationTime(1000.); + auto animationIt = windows.find(w); + if (animationIt != windows.end() && isRealWindow(w)) { + if (animationIt->progress < 1) { + int time = 0; + if (animationIt->lastPresentTime.count()) { + time = (presentTime - animationIt->lastPresentTime).count(); + } + animationIt->lastPresentTime = presentTime; + + animationIt->progress += time / animationTime(1000.); data.setTransformed(); w->enablePainting(EffectWindow::PAINT_DISABLED_BY_DELETE); // Request the window to be divided into cells @@ -57,13 +64,14 @@ void FallApartEffect::prePaintWindow(EffectWindow* w, WindowPrePaintData& data, w->unrefWindow(); } } - effects->prePaintWindow(w, data, time); + effects->prePaintWindow(w, data, presentTime); } void FallApartEffect::paintWindow(EffectWindow* w, int mask, QRegion region, WindowPaintData& data) { - if (windows.contains(w) && isRealWindow(w)) { - const qreal t = windows[w]; + auto animationIt = windows.constFind(w); + if (animationIt != windows.constEnd() && isRealWindow(w)) { + const qreal t = animationIt->progress; WindowQuadList new_quads; int cnt = 0; foreach (WindowQuad quad, data.quads) { // krazy:exclude=foreach @@ -99,7 +107,7 @@ void FallApartEffect::paintWindow(EffectWindow* w, int mask, QRegion region, Win double x = quad[ j ].x() - center.x(); double y = quad[ j ].y() - center.y(); double angle = atan2(y, x); - angle += windows[ w ] * adiff; + angle += animationIt->progress * adiff; double dist = sqrt(x * x + y * y); x = dist * cos(angle); y = dist * sin(angle); @@ -156,7 +164,7 @@ void FallApartEffect::slotWindowClosed(EffectWindow* c) if (e && e != this) return; c->setData(WindowClosedGrabRole, QVariant::fromValue(static_cast(this))); - windows[ c ] = 0; + windows[ c ].progress = 0; c->refWindow(); } diff --git a/effects/fallapart/fallapart.h b/effects/fallapart/fallapart.h index 9fed03b44a..526b1fba06 100644 --- a/effects/fallapart/fallapart.h +++ b/effects/fallapart/fallapart.h @@ -15,6 +15,12 @@ namespace KWin { +struct FallApartAnimation +{ + std::chrono::milliseconds lastPresentTime = std::chrono::milliseconds::zero(); + qreal progress = 0; +}; + class FallApartEffect : public Effect { @@ -23,8 +29,8 @@ class FallApartEffect public: FallApartEffect(); void reconfigure(ReconfigureFlags) override; - void prePaintScreen(ScreenPrePaintData& data, int time) override; - void prePaintWindow(EffectWindow* w, WindowPrePaintData& data, int time) override; + void prePaintScreen(ScreenPrePaintData& data, std::chrono::milliseconds presentTime) override; + void prePaintWindow(EffectWindow* w, WindowPrePaintData& data, std::chrono::milliseconds presentTime) override; void paintWindow(EffectWindow* w, int mask, QRegion region, WindowPaintData& data) override; void postPaintScreen() override; bool isActive() const override; @@ -46,7 +52,7 @@ public Q_SLOTS: void slotWindowDataChanged(KWin::EffectWindow *w, int role); private: - QHash< EffectWindow*, double > windows; + QHash< EffectWindow*, FallApartAnimation > windows; bool isRealWindow(EffectWindow* w); int blockSize; }; diff --git a/effects/flipswitch/flipswitch.cpp b/effects/flipswitch/flipswitch.cpp index bdc175f9ac..c149fa7f31 100644 --- a/effects/flipswitch/flipswitch.cpp +++ b/effects/flipswitch/flipswitch.cpp @@ -27,6 +27,7 @@ namespace KWin FlipSwitchEffect::FlipSwitchEffect() : m_selectedWindow(nullptr) , m_currentAnimationEasingCurve(QEasingCurve::InOutSine) + , m_lastPresentTime(std::chrono::milliseconds::zero()) , m_active(false) , m_start(false) , m_stop(false) @@ -93,8 +94,14 @@ void FlipSwitchEffect::reconfigure(ReconfigureFlags) m_windowTitle = FlipSwitchConfig::windowTitle(); } -void FlipSwitchEffect::prePaintScreen(ScreenPrePaintData& data, int time) +void FlipSwitchEffect::prePaintScreen(ScreenPrePaintData& data, std::chrono::milliseconds presentTime) { + int time = 0; + if (m_lastPresentTime.count()) { + time = (presentTime - m_lastPresentTime).count(); + } + m_lastPresentTime = presentTime; + if (m_active) { data.mask |= PAINT_SCREEN_WITH_TRANSFORMED_WINDOWS; if (m_start) @@ -104,7 +111,7 @@ void FlipSwitchEffect::prePaintScreen(ScreenPrePaintData& data, int time) if (m_animation) m_timeLine.setCurrentTime(m_timeLine.currentTime() + time); } - effects->prePaintScreen(data, time); + effects->prePaintScreen(data, presentTime); } void FlipSwitchEffect::paintScreen(int mask, const QRegion ®ion, ScreenPaintData& data) @@ -318,6 +325,7 @@ void FlipSwitchEffect::postPaintScreen() m_stop = false; m_active = false; m_captionFrame->free(); + m_lastPresentTime = std::chrono::milliseconds::zero(); effects->setActiveFullScreenEffect(nullptr); effects->addRepaintFull(); qDeleteAll(m_windows); @@ -347,7 +355,7 @@ void FlipSwitchEffect::postPaintScreen() effects->postPaintScreen(); } -void FlipSwitchEffect::prePaintWindow(EffectWindow* w, WindowPrePaintData& data, int time) +void FlipSwitchEffect::prePaintWindow(EffectWindow* w, WindowPrePaintData& data, std::chrono::milliseconds presentTime) { if (m_active) { if (m_windows.contains(w)) { @@ -364,7 +372,7 @@ void FlipSwitchEffect::prePaintWindow(EffectWindow* w, WindowPrePaintData& data, w->disablePainting(EffectWindow::PAINT_DISABLED_BY_DESKTOP); } } - effects->prePaintWindow(w, data, time); + effects->prePaintWindow(w, data, presentTime); } void FlipSwitchEffect::paintWindow(EffectWindow* w, int mask, QRegion region, WindowPaintData& data) diff --git a/effects/flipswitch/flipswitch.h b/effects/flipswitch/flipswitch.h index b45ec7ddad..cef9fb1661 100644 --- a/effects/flipswitch/flipswitch.h +++ b/effects/flipswitch/flipswitch.h @@ -35,10 +35,10 @@ public: ~FlipSwitchEffect() override; void reconfigure(ReconfigureFlags) override; - void prePaintScreen(ScreenPrePaintData& data, int time) override; + void prePaintScreen(ScreenPrePaintData& data, std::chrono::milliseconds presentTime) override; void paintScreen(int mask, const QRegion ®ion, ScreenPaintData& data) override; void postPaintScreen() override; - void prePaintWindow(EffectWindow *w, WindowPrePaintData &data, int time) override; + void prePaintWindow(EffectWindow *w, WindowPrePaintData &data, std::chrono::milliseconds presentTime) override; void paintWindow(EffectWindow* w, int mask, QRegion region, WindowPaintData& data) override; void grabbedKeyboardEvent(QKeyEvent* e) override; void windowInputMouseEvent(QEvent* e) override; @@ -112,6 +112,7 @@ private: QTimeLine m_timeLine; QTimeLine m_startStopTimeLine; QEasingCurve m_currentAnimationEasingCurve; + std::chrono::milliseconds m_lastPresentTime; QRect m_screenArea; int m_activeScreen; bool m_active; diff --git a/effects/glide/glide.cpp b/effects/glide/glide.cpp index 0b0c18d136..ea3d2be75d 100644 --- a/effects/glide/glide.cpp +++ b/effects/glide/glide.cpp @@ -68,29 +68,33 @@ void GlideEffect::reconfigure(ReconfigureFlags flags) m_outParams.opacity.to = GlideConfig::outOpacity(); } -void GlideEffect::prePaintScreen(ScreenPrePaintData &data, int time) +void GlideEffect::prePaintScreen(ScreenPrePaintData &data, std::chrono::milliseconds presentTime) { - const std::chrono::milliseconds delta(time); - auto animationIt = m_animations.begin(); while (animationIt != m_animations.end()) { - (*animationIt).update(delta); + std::chrono::milliseconds delta = std::chrono::milliseconds::zero(); + if (animationIt->lastPresentTime.count()) { + delta = presentTime - animationIt->lastPresentTime; + } + animationIt->lastPresentTime = presentTime; + + (*animationIt).timeLine.update(delta); ++animationIt; } data.mask |= PAINT_SCREEN_WITH_TRANSFORMED_WINDOWS; - effects->prePaintScreen(data, time); + effects->prePaintScreen(data, presentTime); } -void GlideEffect::prePaintWindow(EffectWindow *w, WindowPrePaintData &data, int time) +void GlideEffect::prePaintWindow(EffectWindow *w, WindowPrePaintData &data, std::chrono::milliseconds presentTime) { if (m_animations.contains(w)) { data.setTransformed(); w->enablePainting(EffectWindow::PAINT_DISABLED_BY_DELETE); } - effects->prePaintWindow(w, data, time); + effects->prePaintWindow(w, data, presentTime); } void GlideEffect::paintWindow(EffectWindow *w, int mask, QRegion region, WindowPaintData &data) @@ -123,7 +127,7 @@ void GlideEffect::paintWindow(EffectWindow *w, int mask, QRegion region, WindowP data.translate(offset.x(), offset.y()); const GlideParams params = w->isDeleted() ? m_outParams : m_inParams; - const qreal t = (*animationIt).value(); + const qreal t = (*animationIt).timeLine.value(); switch (params.edge) { case RotationEdge::Top: @@ -168,7 +172,7 @@ void GlideEffect::postPaintScreen() { auto animationIt = m_animations.begin(); while (animationIt != m_animations.end()) { - if ((*animationIt).done()) { + if ((*animationIt).timeLine.done()) { EffectWindow *w = animationIt.key(); if (w->isDeleted()) { w->unrefWindow(); @@ -215,11 +219,11 @@ void GlideEffect::windowAdded(EffectWindow *w) w->setData(WindowAddedGrabRole, QVariant::fromValue(static_cast(this))); - TimeLine &timeLine = m_animations[w]; - timeLine.reset(); - timeLine.setDirection(TimeLine::Forward); - timeLine.setDuration(m_duration); - timeLine.setEasingCurve(QEasingCurve::InCurve); + GlideAnimation &animation = m_animations[w]; + animation.timeLine.reset(); + animation.timeLine.setDirection(TimeLine::Forward); + animation.timeLine.setDuration(m_duration); + animation.timeLine.setEasingCurve(QEasingCurve::InCurve); effects->addRepaintFull(); } @@ -246,11 +250,11 @@ void GlideEffect::windowClosed(EffectWindow *w) w->refWindow(); w->setData(WindowClosedGrabRole, QVariant::fromValue(static_cast(this))); - TimeLine &timeLine = m_animations[w]; - timeLine.reset(); - timeLine.setDirection(TimeLine::Forward); - timeLine.setDuration(m_duration); - timeLine.setEasingCurve(QEasingCurve::OutCurve); + GlideAnimation &animation = m_animations[w]; + animation.timeLine.reset(); + animation.timeLine.setDirection(TimeLine::Forward); + animation.timeLine.setDuration(m_duration); + animation.timeLine.setEasingCurve(QEasingCurve::OutCurve); effects->addRepaintFull(); } diff --git a/effects/glide/glide.h b/effects/glide/glide.h index d456eebe79..13b315fdab 100644 --- a/effects/glide/glide.h +++ b/effects/glide/glide.h @@ -19,6 +19,12 @@ namespace KWin { +struct GlideAnimation +{ + TimeLine timeLine; + std::chrono::milliseconds lastPresentTime = std::chrono::milliseconds::zero(); +}; + class GlideEffect : public Effect { Q_OBJECT @@ -38,8 +44,8 @@ public: void reconfigure(ReconfigureFlags flags) override; - void prePaintScreen(ScreenPrePaintData &data, int time) override; - void prePaintWindow(EffectWindow *w, WindowPrePaintData &data, int time) override; + void prePaintScreen(ScreenPrePaintData &data, std::chrono::milliseconds presentTime) override; + void prePaintWindow(EffectWindow *w, WindowPrePaintData &data, std::chrono::milliseconds presentTime) override; void paintWindow(EffectWindow *w, int mask, QRegion region, WindowPaintData &data) override; void postPaintScreen() override; @@ -76,7 +82,7 @@ private: bool isGlideWindow(EffectWindow *w) const; std::chrono::milliseconds m_duration; - QHash m_animations; + QHash m_animations; struct GlideParams { RotationEdge edge; diff --git a/effects/highlightwindow/highlightwindow.cpp b/effects/highlightwindow/highlightwindow.cpp index 28594c47fa..089c21e08d 100644 --- a/effects/highlightwindow/highlightwindow.cpp +++ b/effects/highlightwindow/highlightwindow.cpp @@ -43,59 +43,76 @@ static bool isInitiallyHidden(EffectWindow* w) return w->isMinimized() || !w->isOnCurrentDesktop(); } -void HighlightWindowEffect::prePaintWindow(EffectWindow* w, WindowPrePaintData& data, int time) +void HighlightWindowEffect::prePaintWindow(EffectWindow* w, WindowPrePaintData& data, std::chrono::milliseconds presentTime) { // Calculate window opacities - QHash::iterator opacity = m_windowOpacity.find(w); + QHash::iterator it = m_animations.find(w); if (!m_highlightedWindows.isEmpty()) { // Initial fade out and changing highlight animation - if (opacity == m_windowOpacity.end()) - opacity = m_windowOpacity.insert(w, 0.0f); - float oldOpacity = *opacity; + if (it == m_animations.end()) + it = m_animations.insert(w, HightlightWindowData()); + + int time = 1; + if (it->lastPresentTime.count()) { + time = std::max(1, int((presentTime - it->lastPresentTime).count())); + } + it->lastPresentTime = presentTime; + + float oldOpacity = it->opacity; if (m_highlightedWindows.contains(w)) - *opacity = qMin(1.0f, oldOpacity + time / m_fadeDuration); + it->opacity = qMin(1.0f, oldOpacity + time / m_fadeDuration); else if (w->isNormalWindow() || w->isDialog()) // Only fade out windows - *opacity = qMax(isInitiallyHidden(w) ? 0.0f : 0.15f, oldOpacity - time / m_fadeDuration); + it->opacity = qMax(isInitiallyHidden(w) ? 0.0f : 0.15f, oldOpacity - time / m_fadeDuration); - if (*opacity < 0.98f) + if (it->opacity < 0.98f) data.setTranslucent(); - if (oldOpacity != *opacity) + if (oldOpacity != it->opacity) effects->addRepaint(w->expandedGeometry()); - } else if (m_finishing && m_windowOpacity.contains(w)) { + } else if (m_finishing && m_animations.contains(w)) { // Final fading back in animation - if (opacity == m_windowOpacity.end()) - opacity = m_windowOpacity.insert(w, 0.0f); - float oldOpacity = *opacity; - if (isInitiallyHidden(w)) - *opacity = qMax(0.0f, oldOpacity - time / m_fadeDuration); - else - *opacity = qMin(1.0f, oldOpacity + time / m_fadeDuration); + if (it == m_animations.end()) + it = m_animations.insert(w, HightlightWindowData()); - if (*opacity < 0.98f) + int time = 1; + if (it->lastPresentTime.count()) { + time = std::max(1, int((presentTime - it->lastPresentTime).count())); + } + it->lastPresentTime = presentTime; + + float oldOpacity = it->opacity; + if (isInitiallyHidden(w)) + it->opacity = qMax(0.0f, oldOpacity - time / m_fadeDuration); + else + it->opacity = qMin(1.0f, oldOpacity + time / m_fadeDuration); + + if (it->opacity < 0.98f) data.setTranslucent(); - if (oldOpacity != *opacity) + if (oldOpacity != it->opacity) effects->addRepaint(w->expandedGeometry()); - if (*opacity > 0.98f || *opacity < 0.02f) { - m_windowOpacity.remove(w); // We default to 1.0 - opacity = m_windowOpacity.end(); + if (it->opacity > 0.98f || it->opacity < 0.02f) { + m_animations.remove(w); // We default to 1.0 + it = m_animations.end(); } } // Show tabbed windows and windows on other desktops if highlighted - if (opacity != m_windowOpacity.end() && *opacity > 0.01) { + if (it != m_animations.end() && it->opacity > 0.01) { if (w->isMinimized()) w->enablePainting(EffectWindow::PAINT_DISABLED_BY_MINIMIZE); if (!w->isOnCurrentDesktop()) w->enablePainting(EffectWindow::PAINT_DISABLED_BY_DESKTOP); } - effects->prePaintWindow(w, data, time); + effects->prePaintWindow(w, data, presentTime); } void HighlightWindowEffect::paintWindow(EffectWindow* w, int mask, QRegion region, WindowPaintData& data) { - data.multiplyOpacity(m_windowOpacity.value(w, 1.0f)); + auto it = m_animations.constFind(w); + if (it != m_animations.constEnd()) { + data.multiplyOpacity(it->opacity); + } effects->paintWindow(w, mask, region, data); } @@ -105,11 +122,11 @@ void HighlightWindowEffect::slotWindowAdded(EffectWindow* w) // The effect is activated thus we need to add it to the opacity hash foreach (const WId id, m_highlightedIds) { if (w == effects->findWindow(id)) { - m_windowOpacity[w] = 1.0; // this window was demanded to be highlighted before it appeared + m_animations[w].opacity = 1.0; // this window was demanded to be highlighted before it appeared return; } } - m_windowOpacity[w] = 0.15; // this window is not currently highlighted + m_animations[w].opacity = 0.15; // this window is not currently highlighted } slotPropertyNotify(w, m_atom, w); // Check initial value } @@ -122,7 +139,7 @@ void HighlightWindowEffect::slotWindowClosed(EffectWindow* w) void HighlightWindowEffect::slotWindowDeleted(EffectWindow* w) { - m_windowOpacity.remove(w); + m_animations.remove(w); } void HighlightWindowEffect::slotPropertyNotify(EffectWindow* w, long a, EffectWindow *addedWindow) @@ -172,7 +189,7 @@ void HighlightWindowEffect::slotPropertyNotify(EffectWindow* w, long a, EffectWi } prepareHighlighting(); if (w) - m_windowOpacity[w] = 1.0; // Because it's not in stackingOrder() yet + m_animations[w].opacity = 1.0; // Because it's not in stackingOrder() yet /* TODO: Finish thumbnails of offscreen windows, not sure if it's worth it though if ( !m_highlightedWindow->isOnCurrentDesktop() ) @@ -238,8 +255,8 @@ void HighlightWindowEffect::prepareHighlighting() // Create window data for every window. Just calling [w] creates it. m_finishing = false; foreach (EffectWindow * w, effects->stackingOrder()) { - if (!m_windowOpacity.contains(w)) // Just in case we are still finishing from last time - m_windowOpacity.insert(w, isInitiallyHidden(w) ? 0.0 : 1.0); + if (!m_animations.contains(w)) // Just in case we are still finishing from last time + m_animations[w].opacity = isInitiallyHidden(w) ? 0.0 : 1.0; if (!m_highlightedWindows.isEmpty()) m_highlightedWindows.at(0)->addRepaintFull(); } @@ -250,8 +267,8 @@ void HighlightWindowEffect::finishHighlighting() m_finishing = true; m_monitorWindow = nullptr; m_highlightedWindows.clear(); - if (!m_windowOpacity.isEmpty()) - m_windowOpacity.constBegin().key()->addRepaintFull(); + if (!m_animations.isEmpty()) + m_animations.constBegin().key()->addRepaintFull(); } void HighlightWindowEffect::highlightWindows(const QVector &windows) @@ -272,7 +289,7 @@ void HighlightWindowEffect::highlightWindows(const QVector bool HighlightWindowEffect::isActive() const { - return !(m_windowOpacity.isEmpty() || effects->isScreenLocked()); + return !(m_animations.isEmpty() || effects->isScreenLocked()); } bool HighlightWindowEffect::provides(Feature feature) diff --git a/effects/highlightwindow/highlightwindow.h b/effects/highlightwindow/highlightwindow.h index b8b80d3cfe..7b5ac17390 100644 --- a/effects/highlightwindow/highlightwindow.h +++ b/effects/highlightwindow/highlightwindow.h @@ -15,6 +15,12 @@ namespace KWin { +struct HightlightWindowData +{ + std::chrono::milliseconds lastPresentTime = std::chrono::milliseconds::zero(); + float opacity = 0; +}; + class HighlightWindowEffect : public Effect { @@ -23,7 +29,7 @@ public: HighlightWindowEffect(); ~HighlightWindowEffect() override; - void prePaintWindow(EffectWindow* w, WindowPrePaintData& data, int time) override; + void prePaintWindow(EffectWindow* w, WindowPrePaintData& data, std::chrono::milliseconds presentTime) override; void paintWindow(EffectWindow* w, int mask, QRegion region, WindowPaintData& data) override; bool isActive() const override; @@ -49,7 +55,7 @@ private: bool m_finishing; float m_fadeDuration; - QHash m_windowOpacity; + QHash m_animations; long m_atom; QList m_highlightedWindows; diff --git a/effects/kscreen/kscreen.cpp b/effects/kscreen/kscreen.cpp index affa73ddae..06c29aee54 100644 --- a/effects/kscreen/kscreen.cpp +++ b/effects/kscreen/kscreen.cpp @@ -41,6 +41,7 @@ namespace KWin KscreenEffect::KscreenEffect() : Effect() + , m_lastPresentTime(std::chrono::milliseconds::zero()) , m_state(StateNormal) , m_atom(effects->announceSupportProperty("_KDE_KWIN_KSCREEN_SUPPORT", this)) { @@ -67,15 +68,27 @@ void KscreenEffect::reconfigure(ReconfigureFlags flags) std::chrono::milliseconds(animationTime(250))); } -void KscreenEffect::prePaintScreen(ScreenPrePaintData &data, int time) +void KscreenEffect::prePaintScreen(ScreenPrePaintData &data, std::chrono::milliseconds presentTime) { + std::chrono::milliseconds delta = std::chrono::milliseconds::zero(); + if (m_lastPresentTime.count()) { + delta = presentTime - m_lastPresentTime; + } + if (m_state == StateFadingIn || m_state == StateFadingOut) { - m_timeLine.update(std::chrono::milliseconds(time)); + m_timeLine.update(delta); if (m_timeLine.done()) { switchState(); } } - effects->prePaintScreen(data, time); + + if (isActive()) { + m_lastPresentTime = presentTime; + } else { + m_lastPresentTime = std::chrono::milliseconds::zero(); + } + + effects->prePaintScreen(data, presentTime); } void KscreenEffect::postPaintScreen() @@ -85,12 +98,12 @@ void KscreenEffect::postPaintScreen() } } -void KscreenEffect::prePaintWindow(EffectWindow *w, WindowPrePaintData &data, int time) +void KscreenEffect::prePaintWindow(EffectWindow *w, WindowPrePaintData &data, std::chrono::milliseconds presentTime) { if (m_state != StateNormal) { data.setTranslucent(); } - effects->prePaintWindow(w, data, time); + effects->prePaintWindow(w, data, presentTime); } void KscreenEffect::paintWindow(EffectWindow *w, int mask, QRegion region, WindowPaintData &data) diff --git a/effects/kscreen/kscreen.h b/effects/kscreen/kscreen.h index 83074239a6..b01ef9f3ac 100644 --- a/effects/kscreen/kscreen.h +++ b/effects/kscreen/kscreen.h @@ -22,9 +22,9 @@ public: KscreenEffect(); ~KscreenEffect() override; - void prePaintScreen(ScreenPrePaintData &data, int time) override; + void prePaintScreen(ScreenPrePaintData &data, std::chrono::milliseconds presentTime) override; void postPaintScreen() override; - void prePaintWindow(EffectWindow *w, WindowPrePaintData &data, int time) override; + void prePaintWindow(EffectWindow *w, WindowPrePaintData &data, std::chrono::milliseconds presentTime) override; void paintWindow(EffectWindow *w, int mask, QRegion region, WindowPaintData &data) override; void reconfigure(ReconfigureFlags flags) override; @@ -46,6 +46,7 @@ private: StateFadingIn }; TimeLine m_timeLine; + std::chrono::milliseconds m_lastPresentTime; FadeOutState m_state; xcb_atom_t m_atom; }; diff --git a/effects/lookingglass/lookingglass.cpp b/effects/lookingglass/lookingglass.cpp index 283c89d328..dbc2c5d45b 100644 --- a/effects/lookingglass/lookingglass.cpp +++ b/effects/lookingglass/lookingglass.cpp @@ -38,6 +38,7 @@ LookingGlassEffect::LookingGlassEffect() , m_fbo(nullptr) , m_vbo(nullptr) , m_shader(nullptr) + , m_lastPresentTime(std::chrono::milliseconds::zero()) , m_enabled(false) , m_valid(false) { @@ -179,8 +180,9 @@ void LookingGlassEffect::zoomOut() effects->addRepaint(cursorPos().x() - radius, cursorPos().y() - radius, 2 * radius, 2 * radius); } -void LookingGlassEffect::prePaintScreen(ScreenPrePaintData& data, int time) +void LookingGlassEffect::prePaintScreen(ScreenPrePaintData& data, std::chrono::milliseconds presentTime) { + const int time = m_lastPresentTime.count() ? (presentTime - m_lastPresentTime).count() : 0; if (zoom != target_zoom) { double diff = time / animationTime(500.0); if (target_zoom > zoom) @@ -196,13 +198,18 @@ void LookingGlassEffect::prePaintScreen(ScreenPrePaintData& data, int time) effects->addRepaint(cursorPos().x() - radius, cursorPos().y() - radius, 2 * radius, 2 * radius); } + if (zoom != target_zoom) { + m_lastPresentTime = presentTime; + } else { + m_lastPresentTime = std::chrono::milliseconds::zero(); + } if (m_valid && m_enabled) { data.mask |= PAINT_SCREEN_WITH_TRANSFORMED_WINDOWS; // Start rendering to texture GLRenderTarget::pushRenderTarget(m_fbo); } - effects->prePaintScreen(data, time); + effects->prePaintScreen(data, presentTime); } void LookingGlassEffect::slotMouseChanged(const QPoint& pos, const QPoint& old, Qt::MouseButtons, diff --git a/effects/lookingglass/lookingglass.h b/effects/lookingglass/lookingglass.h index 463c3dc325..3394bf505b 100644 --- a/effects/lookingglass/lookingglass.h +++ b/effects/lookingglass/lookingglass.h @@ -34,7 +34,7 @@ public: void reconfigure(ReconfigureFlags) override; - void prePaintScreen(ScreenPrePaintData& data, int time) override; + void prePaintScreen(ScreenPrePaintData& data, std::chrono::milliseconds presentTime) override; void paintScreen(int mask, const QRegion ®ion, ScreenPaintData &data) override; bool isActive() const override; @@ -63,6 +63,7 @@ private: GLRenderTarget *m_fbo; GLVertexBuffer *m_vbo; GLShader *m_shader; + std::chrono::milliseconds m_lastPresentTime; bool m_enabled; bool m_valid; }; diff --git a/effects/magiclamp/magiclamp.cpp b/effects/magiclamp/magiclamp.cpp index 4c7c0fc50a..647f0055bc 100644 --- a/effects/magiclamp/magiclamp.cpp +++ b/effects/magiclamp/magiclamp.cpp @@ -42,13 +42,17 @@ void MagicLampEffect::reconfigure(ReconfigureFlags) m_duration = std::chrono::milliseconds(static_cast(animationTime(d))); } -void MagicLampEffect::prePaintScreen(ScreenPrePaintData& data, int time) +void MagicLampEffect::prePaintScreen(ScreenPrePaintData& data, std::chrono::milliseconds presentTime) { - const std::chrono::milliseconds delta(time); - auto animationIt = m_animations.begin(); while (animationIt != m_animations.end()) { - (*animationIt).update(delta); + std::chrono::milliseconds delta = std::chrono::milliseconds::zero(); + if (animationIt->lastPresentTime.count()) { + delta = presentTime - animationIt->lastPresentTime; + } + animationIt->lastPresentTime = presentTime; + + (*animationIt).timeLine.update(delta); ++animationIt; } @@ -56,10 +60,10 @@ void MagicLampEffect::prePaintScreen(ScreenPrePaintData& data, int time) // whole screen won't be repainted, resulting in artefacts. data.mask |= PAINT_SCREEN_WITH_TRANSFORMED_WINDOWS; - effects->prePaintScreen(data, time); + effects->prePaintScreen(data, presentTime); } -void MagicLampEffect::prePaintWindow(EffectWindow* w, WindowPrePaintData& data, int time) +void MagicLampEffect::prePaintWindow(EffectWindow* w, WindowPrePaintData& data, std::chrono::milliseconds presentTime) { // Schedule window for transformation if the animation is still in // progress @@ -70,7 +74,7 @@ void MagicLampEffect::prePaintWindow(EffectWindow* w, WindowPrePaintData& data, w->enablePainting(EffectWindow::PAINT_DISABLED_BY_MINIMIZE); } - effects->prePaintWindow(w, data, time); + effects->prePaintWindow(w, data, presentTime); } void MagicLampEffect::paintWindow(EffectWindow* w, int mask, QRegion region, WindowPaintData& data) @@ -78,7 +82,7 @@ void MagicLampEffect::paintWindow(EffectWindow* w, int mask, QRegion region, Win auto animationIt = m_animations.constFind(w); if (animationIt != m_animations.constEnd()) { // 0 = not minimized, 1 = fully minimized - const qreal progress = (*animationIt).value(); + const qreal progress = (*animationIt).timeLine.value(); QRect geo = w->geometry(); QRect icon = w->iconGeometry(); @@ -301,7 +305,7 @@ void MagicLampEffect::postPaintScreen() { auto animationIt = m_animations.begin(); while (animationIt != m_animations.end()) { - if ((*animationIt).done()) { + if ((*animationIt).timeLine.done()) { animationIt = m_animations.erase(animationIt); } else { ++animationIt; @@ -324,14 +328,14 @@ void MagicLampEffect::slotWindowMinimized(EffectWindow* w) if (effects->activeFullScreenEffect()) return; - TimeLine &timeLine = m_animations[w]; + MagicLampAnimation &animation = m_animations[w]; - if (timeLine.running()) { - timeLine.toggleDirection(); + if (animation.timeLine.running()) { + animation.timeLine.toggleDirection(); } else { - timeLine.setDirection(TimeLine::Forward); - timeLine.setDuration(m_duration); - timeLine.setEasingCurve(QEasingCurve::Linear); + animation.timeLine.setDirection(TimeLine::Forward); + animation.timeLine.setDuration(m_duration); + animation.timeLine.setEasingCurve(QEasingCurve::Linear); } effects->addRepaintFull(); @@ -342,14 +346,14 @@ void MagicLampEffect::slotWindowUnminimized(EffectWindow* w) if (effects->activeFullScreenEffect()) return; - TimeLine &timeLine = m_animations[w]; + MagicLampAnimation &animation = m_animations[w]; - if (timeLine.running()) { - timeLine.toggleDirection(); + if (animation.timeLine.running()) { + animation.timeLine.toggleDirection(); } else { - timeLine.setDirection(TimeLine::Backward); - timeLine.setDuration(m_duration); - timeLine.setEasingCurve(QEasingCurve::Linear); + animation.timeLine.setDirection(TimeLine::Backward); + animation.timeLine.setDuration(m_duration); + animation.timeLine.setEasingCurve(QEasingCurve::Linear); } effects->addRepaintFull(); diff --git a/effects/magiclamp/magiclamp.h b/effects/magiclamp/magiclamp.h index 408236b8b5..91ebdf962e 100644 --- a/effects/magiclamp/magiclamp.h +++ b/effects/magiclamp/magiclamp.h @@ -15,6 +15,12 @@ namespace KWin { +struct MagicLampAnimation +{ + TimeLine timeLine; + std::chrono::milliseconds lastPresentTime = std::chrono::milliseconds::zero(); +}; + class MagicLampEffect : public Effect { @@ -24,8 +30,8 @@ public: MagicLampEffect(); void reconfigure(ReconfigureFlags) override; - void prePaintScreen(ScreenPrePaintData& data, int time) override; - void prePaintWindow(EffectWindow* w, WindowPrePaintData& data, int time) override; + void prePaintScreen(ScreenPrePaintData& data, std::chrono::milliseconds presentTime) override; + void prePaintWindow(EffectWindow* w, WindowPrePaintData& data, std::chrono::milliseconds presentTime) override; void paintWindow(EffectWindow* w, int mask, QRegion region, WindowPaintData& data) override; void postPaintScreen() override; bool isActive() const override; @@ -43,7 +49,7 @@ public Q_SLOTS: private: std::chrono::milliseconds m_duration; - QHash m_animations; + QHash m_animations; enum IconPosition { Top, diff --git a/effects/magnifier/magnifier.cpp b/effects/magnifier/magnifier.cpp index 8c2176ef17..4aced41fb9 100644 --- a/effects/magnifier/magnifier.cpp +++ b/effects/magnifier/magnifier.cpp @@ -33,6 +33,7 @@ MagnifierEffect::MagnifierEffect() : zoom(1) , target_zoom(1) , polling(false) + , m_lastPresentTime(std::chrono::milliseconds::zero()) , m_texture(nullptr) , m_fbo(nullptr) #ifdef KWIN_HAVE_XRENDER_COMPOSITING @@ -104,8 +105,10 @@ void MagnifierEffect::reconfigure(ReconfigureFlags) toggle(); } -void MagnifierEffect::prePaintScreen(ScreenPrePaintData& data, int time) +void MagnifierEffect::prePaintScreen(ScreenPrePaintData& data, std::chrono::milliseconds presentTime) { + const int time = m_lastPresentTime.count() ? (presentTime - m_lastPresentTime).count() : 0; + if (zoom != target_zoom) { double diff = time / animationTime(500.0); if (target_zoom > zoom) @@ -122,7 +125,14 @@ void MagnifierEffect::prePaintScreen(ScreenPrePaintData& data, int time) } } } - effects->prePaintScreen(data, time); + + if (zoom != target_zoom) { + m_lastPresentTime = presentTime; + } else { + m_lastPresentTime = std::chrono::milliseconds::zero(); + } + + effects->prePaintScreen(data, presentTime); if (zoom != 1.0) data.paint |= magnifierArea().adjusted(-FRAME_WIDTH, -FRAME_WIDTH, FRAME_WIDTH, FRAME_WIDTH); } diff --git a/effects/magnifier/magnifier.h b/effects/magnifier/magnifier.h index 48b87fee41..28deb3499f 100644 --- a/effects/magnifier/magnifier.h +++ b/effects/magnifier/magnifier.h @@ -30,7 +30,7 @@ public: MagnifierEffect(); ~MagnifierEffect() override; void reconfigure(ReconfigureFlags) override; - void prePaintScreen(ScreenPrePaintData& data, int time) override; + void prePaintScreen(ScreenPrePaintData& data, std::chrono::milliseconds presentTime) override; void paintScreen(int mask, const QRegion ®ion, ScreenPaintData& data) override; void postPaintScreen() override; bool isActive() const override; @@ -56,6 +56,7 @@ private: double zoom; double target_zoom; bool polling; // Mouse polling + std::chrono::milliseconds m_lastPresentTime; QSize magnifier_size; GLTexture *m_texture; GLRenderTarget *m_fbo; diff --git a/effects/mouseclick/mouseclick.cpp b/effects/mouseclick/mouseclick.cpp index 01a335bdd3..f1d62b832b 100644 --- a/effects/mouseclick/mouseclick.cpp +++ b/effects/mouseclick/mouseclick.cpp @@ -74,8 +74,10 @@ void MouseClickEffect::reconfigure(ReconfigureFlags) m_font = MouseClickConfig::font(); } -void MouseClickEffect::prePaintScreen(ScreenPrePaintData& data, int time) +void MouseClickEffect::prePaintScreen(ScreenPrePaintData& data, std::chrono::milliseconds presentTime) { + const int time = m_lastPresentTime.count() ? (presentTime - m_lastPresentTime).count() : 0; + foreach (MouseEvent* click, m_clicks) { click->m_time += time; } @@ -95,7 +97,13 @@ void MouseClickEffect::prePaintScreen(ScreenPrePaintData& data, int time) delete first; } - effects->prePaintScreen(data, time); + if (isActive()) { + m_lastPresentTime = presentTime; + } else { + m_lastPresentTime = std::chrono::milliseconds::zero(); + } + + effects->prePaintScreen(data, presentTime); } void MouseClickEffect::paintScreen(int mask, const QRegion ®ion, ScreenPaintData& data) diff --git a/effects/mouseclick/mouseclick.h b/effects/mouseclick/mouseclick.h index ec9cd7af6e..b81a97d5af 100644 --- a/effects/mouseclick/mouseclick.h +++ b/effects/mouseclick/mouseclick.h @@ -92,7 +92,7 @@ public: MouseClickEffect(); ~MouseClickEffect() override; void reconfigure(ReconfigureFlags) override; - void prePaintScreen(ScreenPrePaintData& data, int time) override; + void prePaintScreen(ScreenPrePaintData& data, std::chrono::milliseconds presentTime) override; void paintScreen(int mask, const QRegion ®ion, ScreenPaintData& data) override; void postPaintScreen() override; bool isActive() const override; @@ -161,6 +161,7 @@ private: float m_ringMaxSize; bool m_showText; QFont m_font; + std::chrono::milliseconds m_lastPresentTime = std::chrono::milliseconds::zero(); QList m_clicks; MouseButton* m_buttons[BUTTON_COUNT]; diff --git a/effects/presentwindows/presentwindows.cpp b/effects/presentwindows/presentwindows.cpp index 15a4d132ca..99e3598e94 100644 --- a/effects/presentwindows/presentwindows.cpp +++ b/effects/presentwindows/presentwindows.cpp @@ -46,6 +46,7 @@ PresentWindowsEffect::PresentWindowsEffect() , m_managerWindow(nullptr) , m_needInitialSelection(false) , m_highlightedWindow(nullptr) + , m_lastPresentTime(std::chrono::milliseconds::zero()) , m_filterFrame(nullptr) , m_closeView(nullptr) , m_exposeAction(new QAction(this)) @@ -199,8 +200,17 @@ void PresentWindowsEffect::toggleActiveClass() //----------------------------------------------------------------------------- // Screen painting -void PresentWindowsEffect::prePaintScreen(ScreenPrePaintData &data, int time) +void PresentWindowsEffect::prePaintScreen(ScreenPrePaintData &data, std::chrono::milliseconds presentTime) { + // The animation code assumes that the time diff cannot be 0, let's work around it. + int time; + if (m_lastPresentTime.count()) { + time = std::max(1, int((presentTime - m_lastPresentTime).count())); + } else { + time = 1; + } + m_lastPresentTime = presentTime; + m_motionManager.calculate(time); // We need to mark the screen as having been transformed otherwise there will be no repainting @@ -212,7 +222,7 @@ void PresentWindowsEffect::prePaintScreen(ScreenPrePaintData &data, int time) else m_decalOpacity = qMax(0.0, m_decalOpacity - time / m_fadeDuration); - effects->prePaintScreen(data, time); + effects->prePaintScreen(data, presentTime); } void PresentWindowsEffect::paintScreen(int mask, const QRegion ®ion, ScreenPaintData &data) @@ -229,43 +239,58 @@ void PresentWindowsEffect::paintScreen(int mask, const QRegion ®ion, ScreenPa void PresentWindowsEffect::postPaintScreen() { - if (m_motionManager.areWindowsMoving()) + if (m_motionManager.areWindowsMoving()) { effects->addRepaintFull(); - else if (!m_activated && m_motionManager.managingWindows() && !(m_closeView && m_closeView->isVisible())) { - // We have finished moving them back, stop processing - m_motionManager.unmanageAll(); + } else { + m_lastPresentTime = std::chrono::milliseconds::zero(); - DataHash::iterator i = m_windowData.begin(); - while (i != m_windowData.end()) { - delete i.value().textFrame; - delete i.value().iconFrame; - ++i; - } - m_windowData.clear(); + if (!m_activated && m_motionManager.managingWindows() && !(m_closeView && m_closeView->isVisible())) { + // We have finished moving them back, stop processing + m_motionManager.unmanageAll(); - foreach (EffectWindow * w, effects->stackingOrder()) { - w->setData(WindowForceBlurRole, QVariant()); - w->setData(WindowForceBackgroundContrastRole, QVariant()); + DataHash::iterator i = m_windowData.begin(); + while (i != m_windowData.end()) { + delete i.value().textFrame; + delete i.value().iconFrame; + ++i; + } + m_windowData.clear(); + + foreach (EffectWindow * w, effects->stackingOrder()) { + w->setData(WindowForceBlurRole, QVariant()); + w->setData(WindowForceBackgroundContrastRole, QVariant()); + } + effects->setActiveFullScreenEffect(nullptr); + effects->addRepaintFull(); + } else if (m_activated && m_needInitialSelection) { + m_needInitialSelection = false; + QMouseEvent me(QEvent::MouseMove, cursorPos(), Qt::NoButton, Qt::NoButton, Qt::NoModifier); + windowInputMouseEvent(&me); } - effects->setActiveFullScreenEffect(nullptr); - effects->addRepaintFull(); - } else if (m_activated && m_needInitialSelection) { - m_needInitialSelection = false; - QMouseEvent me(QEvent::MouseMove, cursorPos(), Qt::NoButton, Qt::NoButton, Qt::NoModifier); - windowInputMouseEvent(&me); } // Update windows that are changing brightness or opacity - DataHash::const_iterator i; - for (i = m_windowData.constBegin(); i != m_windowData.constEnd(); ++i) { - if (i.value().opacity > 0.0 && i.value().opacity < 1.0) + for (auto i = m_windowData.begin(); i != m_windowData.end(); ++i) { + bool resetLastPresentTime = true; + + if (i.value().opacity > 0.0 && i.value().opacity < 1.0) { i.key()->addRepaintFull(); - if (i.key()->isDesktop() && !m_motionManager.isManaging(i.key())) { - if (i.value().highlight != 0.3) - i.key()->addRepaintFull(); + resetLastPresentTime = false; } - else if (i.value().highlight > 0.0 && i.value().highlight < 1.0) + if (i.key()->isDesktop() && !m_motionManager.isManaging(i.key())) { + if (i.value().highlight != 0.3) { + i.key()->addRepaintFull(); + resetLastPresentTime = false; + } + } + else if (i.value().highlight > 0.0 && i.value().highlight < 1.0) { i.key()->addRepaintFull(); + resetLastPresentTime = false; + } + + if (resetLastPresentTime) { + i->lastPresentTime = std::chrono::milliseconds::zero(); + } } effects->postPaintScreen(); @@ -274,19 +299,28 @@ void PresentWindowsEffect::postPaintScreen() //----------------------------------------------------------------------------- // Window painting -void PresentWindowsEffect::prePaintWindow(EffectWindow *w, WindowPrePaintData &data, int time) +void PresentWindowsEffect::prePaintWindow(EffectWindow *w, WindowPrePaintData &data, std::chrono::milliseconds presentTime) { // TODO: We should also check to see if any windows are fading just in case fading takes longer // than moving the windows when the effect is deactivated. if (m_activated || m_motionManager.areWindowsMoving() || m_closeView) { DataHash::iterator winData = m_windowData.find(w); if (winData == m_windowData.end()) { - effects->prePaintWindow(w, data, time); + 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; + if (winData->lastPresentTime.count()) { + time = std::max(1, int((presentTime - winData->lastPresentTime).count())); + } else { + time = 1; + } + winData->lastPresentTime = presentTime; + // Calculate window's opacity // TODO: Minimized windows or windows not on the current desktop are only 75% visible? if (winData->visible) { @@ -333,7 +367,7 @@ void PresentWindowsEffect::prePaintWindow(EffectWindow *w, WindowPrePaintData &d if (isInMotion) data.setTransformed(); // We will be moving this window } - effects->prePaintWindow(w, data, time); + effects->prePaintWindow(w, data, presentTime); } void PresentWindowsEffect::paintWindow(EffectWindow *w, int mask, QRegion region, WindowPaintData &data) diff --git a/effects/presentwindows/presentwindows.h b/effects/presentwindows/presentwindows.h index bd54144c87..8232a1aa94 100644 --- a/effects/presentwindows/presentwindows.h +++ b/effects/presentwindows/presentwindows.h @@ -64,6 +64,7 @@ class PresentWindowsEffect private: // Structures struct WindowData { + std::chrono::milliseconds lastPresentTime = std::chrono::milliseconds::zero(); bool visible; bool deleted; bool referenced; @@ -86,12 +87,12 @@ public: void* proxy() override; // Screen painting - void prePaintScreen(ScreenPrePaintData &data, int time) override; + void prePaintScreen(ScreenPrePaintData &data, std::chrono::milliseconds presentTime) override; void paintScreen(int mask, const QRegion ®ion, ScreenPaintData &data) override; void postPaintScreen() override; // Window painting - void prePaintWindow(EffectWindow *w, WindowPrePaintData &data, int time) override; + void prePaintWindow(EffectWindow *w, WindowPrePaintData &data, std::chrono::milliseconds presentTime) override; void paintWindow(EffectWindow *w, int mask, QRegion region, WindowPaintData &data) override; // User interaction @@ -279,6 +280,9 @@ private: DataHash m_windowData; EffectWindow *m_highlightedWindow; + // Timing + std::chrono::milliseconds m_lastPresentTime; + // Grid layout info QList m_gridSizes; diff --git a/effects/resize/resize.cpp b/effects/resize/resize.cpp index b3e32d2080..5063a5b133 100644 --- a/effects/resize/resize.cpp +++ b/effects/resize/resize.cpp @@ -40,19 +40,19 @@ ResizeEffect::~ResizeEffect() { } -void ResizeEffect::prePaintScreen(ScreenPrePaintData& data, int time) +void ResizeEffect::prePaintScreen(ScreenPrePaintData& data, std::chrono::milliseconds presentTime) { if (m_active) { data.mask |= PAINT_SCREEN_WITH_TRANSFORMED_WINDOWS; } - AnimationEffect::prePaintScreen(data, time); + AnimationEffect::prePaintScreen(data, presentTime); } -void ResizeEffect::prePaintWindow(EffectWindow* w, WindowPrePaintData& data, int time) +void ResizeEffect::prePaintWindow(EffectWindow* w, WindowPrePaintData& data, std::chrono::milliseconds presentTime) { if (m_active && w == m_resizeWindow) data.mask |= PAINT_WINDOW_TRANSFORMED; - AnimationEffect::prePaintWindow(w, data, time); + AnimationEffect::prePaintWindow(w, data, presentTime); } void ResizeEffect::paintWindow(EffectWindow* w, int mask, QRegion region, WindowPaintData& data) diff --git a/effects/resize/resize.h b/effects/resize/resize.h index a0150ee964..93f561a1dc 100644 --- a/effects/resize/resize.h +++ b/effects/resize/resize.h @@ -28,8 +28,8 @@ public: return ef == Effect::Resize; } inline bool isActive() const override { return m_active || AnimationEffect::isActive(); } - void prePaintScreen(ScreenPrePaintData& data, int time) override; - void prePaintWindow(EffectWindow* w, WindowPrePaintData& data, int time) override; + void prePaintScreen(ScreenPrePaintData& data, std::chrono::milliseconds presentTime) override; + void prePaintWindow(EffectWindow* w, WindowPrePaintData& data, std::chrono::milliseconds presentTime) override; void paintWindow(EffectWindow* w, int mask, QRegion region, WindowPaintData& data) override; void reconfigure(ReconfigureFlags) override; diff --git a/effects/screenedge/screenedgeeffect.cpp b/effects/screenedge/screenedgeeffect.cpp index 4058fa9d47..07662b7b16 100644 --- a/effects/screenedge/screenedgeeffect.cpp +++ b/effects/screenedge/screenedgeeffect.cpp @@ -65,9 +65,9 @@ void ScreenEdgeEffect::cleanup() m_borders.clear(); } -void ScreenEdgeEffect::prePaintScreen(ScreenPrePaintData &data, int time) +void ScreenEdgeEffect::prePaintScreen(ScreenPrePaintData &data, std::chrono::milliseconds presentTime) { - effects->prePaintScreen(data, time); + effects->prePaintScreen(data, presentTime); for (QHash::iterator it = m_borders.begin(); it != m_borders.end(); ++it) { diff --git a/effects/screenedge/screenedgeeffect.h b/effects/screenedge/screenedgeeffect.h index 14a4d5755f..56544a4f7e 100644 --- a/effects/screenedge/screenedgeeffect.h +++ b/effects/screenedge/screenedgeeffect.h @@ -25,7 +25,7 @@ class ScreenEdgeEffect : public Effect public: ScreenEdgeEffect(); ~ScreenEdgeEffect() override; - void prePaintScreen(ScreenPrePaintData &data, int time) override; + void prePaintScreen(ScreenPrePaintData &data, std::chrono::milliseconds presentTime) override; void paintScreen(int mask, const QRegion ®ion, ScreenPaintData &data) override; bool isActive() const override; diff --git a/effects/sheet/sheet.cpp b/effects/sheet/sheet.cpp index d2cb7ad2a1..acff5d38c9 100644 --- a/effects/sheet/sheet.cpp +++ b/effects/sheet/sheet.cpp @@ -44,29 +44,33 @@ void SheetEffect::reconfigure(ReconfigureFlags flags) m_duration = std::chrono::milliseconds(static_cast(d)); } -void SheetEffect::prePaintScreen(ScreenPrePaintData &data, int time) +void SheetEffect::prePaintScreen(ScreenPrePaintData &data, std::chrono::milliseconds presentTime) { - const std::chrono::milliseconds delta(time); - auto animationIt = m_animations.begin(); while (animationIt != m_animations.end()) { + std::chrono::milliseconds delta = std::chrono::milliseconds::zero(); + if (animationIt->lastPresentTime.count()) { + delta = presentTime - animationIt->lastPresentTime; + } + animationIt->lastPresentTime = presentTime; + (*animationIt).timeLine.update(delta); ++animationIt; } data.mask |= PAINT_SCREEN_WITH_TRANSFORMED_WINDOWS; - effects->prePaintScreen(data, time); + effects->prePaintScreen(data, presentTime); } -void SheetEffect::prePaintWindow(EffectWindow *w, WindowPrePaintData &data, int time) +void SheetEffect::prePaintWindow(EffectWindow *w, WindowPrePaintData &data, std::chrono::milliseconds presentTime) { if (m_animations.contains(w)) { data.setTransformed(); w->enablePainting(EffectWindow::PAINT_DISABLED_BY_DELETE); } - effects->prePaintWindow(w, data, time); + effects->prePaintWindow(w, data, presentTime); } void SheetEffect::paintWindow(EffectWindow *w, int mask, QRegion region, WindowPaintData &data) diff --git a/effects/sheet/sheet.h b/effects/sheet/sheet.h index 3a23657725..3665552fd8 100644 --- a/effects/sheet/sheet.h +++ b/effects/sheet/sheet.h @@ -28,8 +28,8 @@ public: void reconfigure(ReconfigureFlags flags) override; - void prePaintScreen(ScreenPrePaintData &data, int time) override; - void prePaintWindow(EffectWindow *w, WindowPrePaintData &data, int time) override; + void prePaintScreen(ScreenPrePaintData &data, std::chrono::milliseconds presentTime) override; + void prePaintWindow(EffectWindow *w, WindowPrePaintData &data, std::chrono::milliseconds presentTime) override; void paintWindow(EffectWindow *w, int mask, QRegion region, WindowPaintData &data) override; void postPaintWindow(EffectWindow *w) override; @@ -54,6 +54,7 @@ private: struct Animation { TimeLine timeLine; int parentY; + std::chrono::milliseconds lastPresentTime = std::chrono::milliseconds::zero(); }; QHash m_animations; diff --git a/effects/showfps/showfps.cpp b/effects/showfps/showfps.cpp index 05510350e9..9f1df61382 100644 --- a/effects/showfps/showfps.cpp +++ b/effects/showfps/showfps.cpp @@ -110,12 +110,12 @@ void ShowFpsEffect::reconfigure(ReconfigureFlags) } } -void ShowFpsEffect::prePaintScreen(ScreenPrePaintData& data, int time) +void ShowFpsEffect::prePaintScreen(ScreenPrePaintData& data, std::chrono::milliseconds presentTime) { frames[ frames_pos ] = QDateTime::currentMSecsSinceEpoch(); if (++frames_pos == MAX_FPS) frames_pos = 0; - effects->prePaintScreen(data, time); + effects->prePaintScreen(data, presentTime); data.paint += fps_rect; paint_size[ paints_pos ] = 0; diff --git a/effects/showfps/showfps.h b/effects/showfps/showfps.h index e82ec84447..ed7c19b3b9 100644 --- a/effects/showfps/showfps.h +++ b/effects/showfps/showfps.h @@ -34,7 +34,7 @@ class ShowFpsEffect public: ShowFpsEffect(); void reconfigure(ReconfigureFlags) override; - void prePaintScreen(ScreenPrePaintData& data, int time) override; + void prePaintScreen(ScreenPrePaintData& data, std::chrono::milliseconds presentTime) override; void paintScreen(int mask, const QRegion ®ion, ScreenPaintData& data) override; void paintWindow(EffectWindow* w, int mask, QRegion region, WindowPaintData& data) override; void postPaintScreen() override; diff --git a/effects/slide/slide.cpp b/effects/slide/slide.cpp index a73836eaac..c944f4c3fe 100644 --- a/effects/slide/slide.cpp +++ b/effects/slide/slide.cpp @@ -62,14 +62,20 @@ void SlideEffect::reconfigure(ReconfigureFlags) m_slideBackground = SlideConfig::slideBackground(); } -void SlideEffect::prePaintScreen(ScreenPrePaintData &data, int time) +void SlideEffect::prePaintScreen(ScreenPrePaintData &data, std::chrono::milliseconds presentTime) { - m_timeLine.update(std::chrono::milliseconds(time)); + std::chrono::milliseconds delta = std::chrono::milliseconds::zero(); + if (m_lastPresentTime.count()) { + delta = presentTime - m_lastPresentTime; + } + m_lastPresentTime = presentTime; + + m_timeLine.update(delta); data.mask |= PAINT_SCREEN_TRANSFORMED | PAINT_SCREEN_BACKGROUND_FIRST; - effects->prePaintScreen(data, time); + effects->prePaintScreen(data, presentTime); } /** @@ -249,7 +255,7 @@ bool SlideEffect::isPainted(const EffectWindow *w) const return false; } -void SlideEffect::prePaintWindow(EffectWindow *w, WindowPrePaintData &data, int time) +void SlideEffect::prePaintWindow(EffectWindow *w, WindowPrePaintData &data, std::chrono::milliseconds presentTime) { const bool painted = isPainted(w); if (painted) { @@ -260,7 +266,7 @@ void SlideEffect::prePaintWindow(EffectWindow *w, WindowPrePaintData &data, int if (painted && isTranslated(w)) { data.setTransformed(); } - effects->prePaintWindow(w, data, time); + effects->prePaintWindow(w, data, presentTime); } void SlideEffect::paintWindow(EffectWindow *w, int mask, QRegion region, WindowPaintData &data) @@ -392,6 +398,7 @@ void SlideEffect::stop() m_paintCtx.fullscreenWindows.clear(); m_movingWindow = nullptr; m_active = false; + m_lastPresentTime = std::chrono::milliseconds::zero(); effects->setActiveFullScreenEffect(nullptr); } diff --git a/effects/slide/slide.h b/effects/slide/slide.h index fc64803ef0..56ac539a68 100644 --- a/effects/slide/slide.h +++ b/effects/slide/slide.h @@ -33,11 +33,11 @@ public: void reconfigure(ReconfigureFlags) override; - void prePaintScreen(ScreenPrePaintData &data, int time) override; + void prePaintScreen(ScreenPrePaintData &data, std::chrono::milliseconds presentTime) override; void paintScreen(int mask, const QRegion ®ion, ScreenPaintData &data) override; void postPaintScreen() override; - void prePaintWindow(EffectWindow *w, WindowPrePaintData &data, int time) override; + void prePaintWindow(EffectWindow *w, WindowPrePaintData &data, std::chrono::milliseconds presentTime) override; void paintWindow(EffectWindow *w, int mask, QRegion region, WindowPaintData &data) override; bool isActive() const override { @@ -88,6 +88,7 @@ private: QPoint m_startPos; QPoint m_diff; EffectWindow *m_movingWindow = nullptr; + std::chrono::milliseconds m_lastPresentTime = std::chrono::milliseconds::zero(); struct { int desktop; diff --git a/effects/slideback/slideback.cpp b/effects/slideback/slideback.cpp index e6a891422d..4faabba262 100644 --- a/effects/slideback/slideback.cpp +++ b/effects/slideback/slideback.cpp @@ -126,8 +126,14 @@ QRect SlideBackEffect::getSlideDestination(const QRect &windowUnderGeometry, con return slideRect; } -void SlideBackEffect::prePaintScreen(ScreenPrePaintData &data, int time) +void SlideBackEffect::prePaintScreen(ScreenPrePaintData &data, std::chrono::milliseconds presentTime) { + int time = 0; + if (m_lastPresentTime.count()) { + time = (presentTime - m_lastPresentTime).count(); + } + m_lastPresentTime = presentTime; + if (motionManager.managingWindows()) { motionManager.calculate(time); data.mask |= Effect::PAINT_SCREEN_WITH_TRANSFORMED_WINDOWS; @@ -137,7 +143,7 @@ void SlideBackEffect::prePaintScreen(ScreenPrePaintData &data, int time) w->setData(WindowForceBlurRole, QVariant(true)); } - effects->prePaintScreen(data, time); + effects->prePaintScreen(data, presentTime); } void SlideBackEffect::postPaintScreen() @@ -153,13 +159,13 @@ void SlideBackEffect::postPaintScreen() effects->postPaintScreen(); } -void SlideBackEffect::prePaintWindow(EffectWindow *w, WindowPrePaintData &data, int time) +void SlideBackEffect::prePaintWindow(EffectWindow *w, WindowPrePaintData &data, std::chrono::milliseconds presentTime) { if (motionManager.isManaging(w)) { data.setTransformed(); } - effects->prePaintWindow(w, data, time); + effects->prePaintWindow(w, data, presentTime); } void SlideBackEffect::paintWindow(EffectWindow *w, int mask, QRegion region, WindowPaintData &data) @@ -242,6 +248,9 @@ void SlideBackEffect::postPaintWindow(EffectWindow* w) } } } + if (!isActive()) { + m_lastPresentTime = std::chrono::milliseconds::zero(); + } effects->postPaintWindow(w); } diff --git a/effects/slideback/slideback.h b/effects/slideback/slideback.h index c10b7e52ba..cf49a345eb 100644 --- a/effects/slideback/slideback.h +++ b/effects/slideback/slideback.h @@ -23,11 +23,11 @@ class SlideBackEffect public: SlideBackEffect(); - void prePaintWindow(EffectWindow *w, WindowPrePaintData &data, int time) override; + void prePaintWindow(EffectWindow *w, WindowPrePaintData &data, std::chrono::milliseconds presentTime) override; void paintWindow(EffectWindow* w, int mask, QRegion region, WindowPaintData& data) override; void postPaintWindow(EffectWindow* w) override; - void prePaintScreen(ScreenPrePaintData &data, int time) override; + void prePaintScreen(ScreenPrePaintData &data, std::chrono::milliseconds presentTime) override; void postPaintScreen() override; bool isActive() const override; @@ -54,6 +54,7 @@ private: QHash destinationList; int m_tabboxActive; QList clippedRegions; + std::chrono::milliseconds m_lastPresentTime = std::chrono::milliseconds::zero(); QRect getSlideDestination(const QRect &windowUnderGeometry, const QRect &windowOverGeometry); bool isWindowUsable(EffectWindow *w); diff --git a/effects/slidingpopups/slidingpopups.cpp b/effects/slidingpopups/slidingpopups.cpp index afb7ceceb1..837228d85c 100644 --- a/effects/slidingpopups/slidingpopups.cpp +++ b/effects/slidingpopups/slidingpopups.cpp @@ -91,19 +91,25 @@ void SlidingPopupsEffect::reconfigure(ReconfigureFlags flags) } } -void SlidingPopupsEffect::prePaintWindow(EffectWindow *w, WindowPrePaintData &data, int time) +void SlidingPopupsEffect::prePaintWindow(EffectWindow *w, WindowPrePaintData &data, std::chrono::milliseconds presentTime) { auto animationIt = m_animations.find(w); if (animationIt == m_animations.end()) { - effects->prePaintWindow(w, data, time); + effects->prePaintWindow(w, data, presentTime); return; } - (*animationIt).timeLine.update(std::chrono::milliseconds(time)); + std::chrono::milliseconds delta = std::chrono::milliseconds::zero(); + if (animationIt->lastPresentTime.count()) { + delta = presentTime - animationIt->lastPresentTime; + } + animationIt->lastPresentTime = presentTime; + + (*animationIt).timeLine.update(delta); data.setTransformed(); w->enablePainting(EffectWindow::PAINT_DISABLED | EffectWindow::PAINT_DISABLED_BY_DELETE); - effects->prePaintWindow(w, data, time); + effects->prePaintWindow(w, data, presentTime); } void SlidingPopupsEffect::paintWindow(EffectWindow *w, int mask, QRegion region, WindowPaintData &data) diff --git a/effects/slidingpopups/slidingpopups.h b/effects/slidingpopups/slidingpopups.h index c6c2c3e189..4480371d6d 100644 --- a/effects/slidingpopups/slidingpopups.h +++ b/effects/slidingpopups/slidingpopups.h @@ -27,7 +27,7 @@ public: SlidingPopupsEffect(); ~SlidingPopupsEffect() override; - void prePaintWindow(EffectWindow *w, WindowPrePaintData &data, int time) override; + void prePaintWindow(EffectWindow *w, WindowPrePaintData &data, std::chrono::milliseconds presentTime) override; void paintWindow(EffectWindow *w, int mask, QRegion region, WindowPaintData &data) override; void postPaintWindow(EffectWindow *w) override; void reconfigure(ReconfigureFlags flags) override; @@ -72,6 +72,7 @@ private: struct Animation { AnimationKind kind; TimeLine timeLine; + std::chrono::milliseconds lastPresentTime = std::chrono::milliseconds::zero(); }; QHash m_animations; diff --git a/effects/snaphelper/snaphelper.cpp b/effects/snaphelper/snaphelper.cpp index 0fd783c083..e6e1e82dd9 100644 --- a/effects/snaphelper/snaphelper.cpp +++ b/effects/snaphelper/snaphelper.cpp @@ -85,13 +85,19 @@ void SnapHelperEffect::reconfigure(ReconfigureFlags flags) std::chrono::milliseconds(static_cast(animationTime(250)))); } -void SnapHelperEffect::prePaintScreen(ScreenPrePaintData &data, int time) +void SnapHelperEffect::prePaintScreen(ScreenPrePaintData &data, std::chrono::milliseconds presentTime) { + std::chrono::milliseconds delta = std::chrono::milliseconds::zero(); + if (m_animation.lastPresentTime.count()) { + delta = (presentTime - m_animation.lastPresentTime); + } + m_animation.lastPresentTime = presentTime; + if (m_animation.active) { - m_animation.timeLine.update(std::chrono::milliseconds(time)); + m_animation.timeLine.update(delta); } - effects->prePaintScreen(data, time); + effects->prePaintScreen(data, presentTime); } void SnapHelperEffect::paintScreen(int mask, const QRegion ®ion, ScreenPaintData &data) @@ -244,6 +250,7 @@ void SnapHelperEffect::postPaintScreen() if (m_animation.timeLine.done()) { m_animation.active = false; + m_animation.lastPresentTime = std::chrono::milliseconds::zero(); } effects->postPaintScreen(); diff --git a/effects/snaphelper/snaphelper.h b/effects/snaphelper/snaphelper.h index 4e6c09bd9b..e965c049d8 100644 --- a/effects/snaphelper/snaphelper.h +++ b/effects/snaphelper/snaphelper.h @@ -26,7 +26,7 @@ public: void reconfigure(ReconfigureFlags flags) override; - void prePaintScreen(ScreenPrePaintData &data, int time) override; + void prePaintScreen(ScreenPrePaintData &data, std::chrono::milliseconds presentTime) override; void paintScreen(int mask, const QRegion ®ion, ScreenPaintData &data) override; void postPaintScreen() override; @@ -45,6 +45,7 @@ private: struct Animation { bool active = false; TimeLine timeLine; + std::chrono::milliseconds lastPresentTime = std::chrono::milliseconds::zero(); }; Animation m_animation; diff --git a/effects/startupfeedback/startupfeedback.cpp b/effects/startupfeedback/startupfeedback.cpp index e4b156a07f..e65beba2e3 100644 --- a/effects/startupfeedback/startupfeedback.cpp +++ b/effects/startupfeedback/startupfeedback.cpp @@ -68,6 +68,7 @@ StartupFeedbackEffect::StartupFeedbackEffect() , m_active(false) , m_frame(0) , m_progress(0) + , m_lastPresentTime(std::chrono::milliseconds::zero()) , m_type(BouncingFeedback) , m_cursorSize(24) , m_configWatcher(KConfigWatcher::create(KSharedConfig::openConfig("klaunchrc", KConfig::NoGlobals))) @@ -142,8 +143,14 @@ void StartupFeedbackEffect::reconfigure(Effect::ReconfigureFlags flags) } } -void StartupFeedbackEffect::prePaintScreen(ScreenPrePaintData& data, int time) +void StartupFeedbackEffect::prePaintScreen(ScreenPrePaintData& data, std::chrono::milliseconds presentTime) { + int time = 0; + if (m_lastPresentTime.count()) { + time = (presentTime - m_lastPresentTime).count(); + } + m_lastPresentTime = presentTime; + if (m_active) { // need the unclipped version switch(m_type) { @@ -161,7 +168,7 @@ void StartupFeedbackEffect::prePaintScreen(ScreenPrePaintData& data, int time) break; // nothing } } - effects->prePaintScreen(data, time); + effects->prePaintScreen(data, presentTime); } void StartupFeedbackEffect::paintScreen(int mask, const QRegion ®ion, ScreenPaintData& data) @@ -289,6 +296,7 @@ void StartupFeedbackEffect::stop() if (m_active) effects->stopMousePolling(); m_active = false; + m_lastPresentTime = std::chrono::milliseconds::zero(); effects->makeOpenGLContextCurrent(); switch(m_type) { case BouncingFeedback: @@ -324,6 +332,7 @@ void StartupFeedbackEffect::prepareTextures(const QPixmap& pix) default: // for safety m_active = false; + m_lastPresentTime = std::chrono::milliseconds::zero(); break; } } diff --git a/effects/startupfeedback/startupfeedback.h b/effects/startupfeedback/startupfeedback.h index 553fc53c68..aa36066031 100644 --- a/effects/startupfeedback/startupfeedback.h +++ b/effects/startupfeedback/startupfeedback.h @@ -29,7 +29,7 @@ public: ~StartupFeedbackEffect() override; void reconfigure(ReconfigureFlags flags) override; - void prePaintScreen(ScreenPrePaintData& data, int time) override; + void prePaintScreen(ScreenPrePaintData& data, std::chrono::milliseconds presentTime) override; void paintScreen(int mask, const QRegion ®ion, ScreenPaintData& data) override; void postPaintScreen() override; bool isActive() const override; @@ -71,6 +71,7 @@ private: bool m_active; int m_frame; int m_progress; + std::chrono::milliseconds m_lastPresentTime; QScopedPointer m_bouncingTextures[5]; QScopedPointer m_texture; // for passive and blinking FeedbackType m_type; diff --git a/effects/touchpoints/touchpoints.cpp b/effects/touchpoints/touchpoints.cpp index 9af04c9648..1673c2e192 100644 --- a/effects/touchpoints/touchpoints.cpp +++ b/effects/touchpoints/touchpoints.cpp @@ -101,8 +101,13 @@ bool TouchPointsEffect::touchUp(qint32 id, quint32 time) return false; } -void TouchPointsEffect::prePaintScreen(ScreenPrePaintData& data, int time) +void TouchPointsEffect::prePaintScreen(ScreenPrePaintData& data, std::chrono::milliseconds presentTime) { + int time = 0; + if (m_lastPresentTime.count()) { + time = (presentTime - m_lastPresentTime).count(); + } + auto it = m_points.begin(); while (it != m_points.end()) { it->time += time; @@ -113,7 +118,13 @@ void TouchPointsEffect::prePaintScreen(ScreenPrePaintData& data, int time) } } - effects->prePaintScreen(data, time); + if (m_points.isEmpty()) { + m_lastPresentTime = std::chrono::milliseconds::zero(); + } else { + m_lastPresentTime = presentTime; + } + + effects->prePaintScreen(data, presentTime); } void TouchPointsEffect::paintScreen(int mask, const QRegion ®ion, ScreenPaintData& data) diff --git a/effects/touchpoints/touchpoints.h b/effects/touchpoints/touchpoints.h index 2ff4626ea0..13117c6c99 100644 --- a/effects/touchpoints/touchpoints.h +++ b/effects/touchpoints/touchpoints.h @@ -27,7 +27,7 @@ class TouchPointsEffect public: TouchPointsEffect(); ~TouchPointsEffect() override; - void prePaintScreen(ScreenPrePaintData& data, int time) override; + void prePaintScreen(ScreenPrePaintData& data, std::chrono::milliseconds presentTime) override; void paintScreen(int mask, const QRegion ®ion, ScreenPaintData& data) override; void postPaintScreen() override; bool isActive() const override; @@ -80,6 +80,7 @@ private: QVector m_points; QHash m_latestPositions; QHash m_colors; + std::chrono::milliseconds m_lastPresentTime = std::chrono::milliseconds::zero(); }; diff --git a/effects/trackmouse/trackmouse.cpp b/effects/trackmouse/trackmouse.cpp index ea26120ec5..496528afc4 100644 --- a/effects/trackmouse/trackmouse.cpp +++ b/effects/trackmouse/trackmouse.cpp @@ -93,7 +93,7 @@ void TrackMouseEffect::reconfigure(ReconfigureFlags) } } -void TrackMouseEffect::prePaintScreen(ScreenPrePaintData& data, int time) +void TrackMouseEffect::prePaintScreen(ScreenPrePaintData& data, std::chrono::milliseconds presentTime) { QTime t = QTime::currentTime(); m_angle = ((t.second() % 4) * m_angleBase) + (t.msec() / 1000.0 * m_angleBase); @@ -101,7 +101,7 @@ void TrackMouseEffect::prePaintScreen(ScreenPrePaintData& data, int time) m_lastRect[1].moveCenter(cursorPos()); data.paint |= m_lastRect[0].adjusted(-1,-1,1,1); - effects->prePaintScreen(data, time); + effects->prePaintScreen(data, presentTime); } void TrackMouseEffect::paintScreen(int mask, const QRegion ®ion, ScreenPaintData& data) diff --git a/effects/trackmouse/trackmouse.h b/effects/trackmouse/trackmouse.h index d35b087666..386635a125 100644 --- a/effects/trackmouse/trackmouse.h +++ b/effects/trackmouse/trackmouse.h @@ -29,7 +29,7 @@ class TrackMouseEffect public: TrackMouseEffect(); ~TrackMouseEffect() override; - void prePaintScreen(ScreenPrePaintData& data, int time) override; + void prePaintScreen(ScreenPrePaintData& data, std::chrono::milliseconds presentTime) override; void paintScreen(int mask, const QRegion ®ion, ScreenPaintData& data) override; void postPaintScreen() override; void reconfigure(ReconfigureFlags) override; diff --git a/effects/wobblywindows/wobblywindows.cpp b/effects/wobblywindows/wobblywindows.cpp index 3113ed095f..2ece00547c 100644 --- a/effects/wobblywindows/wobblywindows.cpp +++ b/effects/wobblywindows/wobblywindows.cpp @@ -228,7 +228,7 @@ void WobblyWindowsEffect::setDrag(qreal drag) m_drag = drag; } -void WobblyWindowsEffect::prePaintScreen(ScreenPrePaintData& data, int time) +void WobblyWindowsEffect::prePaintScreen(ScreenPrePaintData& data, std::chrono::milliseconds presentTime) { // We need to mark the screen windows as transformed. Otherwise the whole // screen won't be repainted, resulting in artefacts. @@ -237,16 +237,22 @@ void WobblyWindowsEffect::prePaintScreen(ScreenPrePaintData& data, int time) m_updateRegion = QRegion(); } - effects->prePaintScreen(data, time); + effects->prePaintScreen(data, presentTime); } const qreal maxTime = 10.0; -void WobblyWindowsEffect::prePaintWindow(EffectWindow* w, WindowPrePaintData& data, int time) +void WobblyWindowsEffect::prePaintWindow(EffectWindow* w, WindowPrePaintData& data, std::chrono::milliseconds presentTime) { - if (windows.contains(w)) { + auto infoIt = windows.find(w); + if (infoIt != windows.end()) { data.setTransformed(); data.quads = data.quads.makeRegularGrid(m_xTesselation, m_yTesselation); bool stop = false; - qreal updateTime = time; + + qreal updateTime = 0; + if (infoIt->lastPresentTime.count()) { + updateTime = (presentTime - infoIt->lastPresentTime).count(); + } + infoIt->lastPresentTime = presentTime; // We have to reset the clip region in order to render clients below // opaque wobbly windows. @@ -264,7 +270,7 @@ void WobblyWindowsEffect::prePaintWindow(EffectWindow* w, WindowPrePaintData& da } } - effects->prePaintWindow(w, data, time); + effects->prePaintWindow(w, data, presentTime); } void WobblyWindowsEffect::paintWindow(EffectWindow* w, int mask, QRegion region, WindowPaintData& data) @@ -464,6 +470,7 @@ void WobblyWindowsEffect::initWobblyInfo(WindowWobblyInfos& wwi, QRect geometry) wwi.bezierSurface = new Pair[wwi.bezierCount]; wwi.status = Moving; + wwi.lastPresentTime = std::chrono::milliseconds::zero(); qreal x = geometry.x(), y = geometry.y(); qreal width = geometry.width(), height = geometry.height(); diff --git a/effects/wobblywindows/wobblywindows.h b/effects/wobblywindows/wobblywindows.h index c4848e3f98..9ebcdfa38f 100644 --- a/effects/wobblywindows/wobblywindows.h +++ b/effects/wobblywindows/wobblywindows.h @@ -43,8 +43,8 @@ public: ~WobblyWindowsEffect() override; void reconfigure(ReconfigureFlags) override; - void prePaintScreen(ScreenPrePaintData& data, int time) override; - void prePaintWindow(EffectWindow* w, WindowPrePaintData& data, int time) override; + void prePaintScreen(ScreenPrePaintData& data, std::chrono::milliseconds presentTime) override; + void prePaintWindow(EffectWindow* w, WindowPrePaintData& data, std::chrono::milliseconds presentTime) override; void paintWindow(EffectWindow* w, int mask, QRegion region, WindowPaintData& data) override; void postPaintScreen() override; bool isActive() const override; @@ -151,6 +151,8 @@ private: // for resizing. Only sides that have moved will wobble bool can_wobble_top, can_wobble_left, can_wobble_right, can_wobble_bottom; QRect resize_original_rect; + + std::chrono::milliseconds lastPresentTime; }; QHash< const EffectWindow*, WindowWobblyInfos > windows; diff --git a/effects/zoom/zoom.cpp b/effects/zoom/zoom.cpp index 7ef01327a8..3a8238cb75 100644 --- a/effects/zoom/zoom.cpp +++ b/effects/zoom/zoom.cpp @@ -49,6 +49,7 @@ ZoomEffect::ZoomEffect() , xMove(0) , yMove(0) , moveFactor(20.0) + , lastPresentTime(std::chrono::milliseconds::zero()) { initConfig(); QAction* a = nullptr; @@ -249,9 +250,14 @@ void ZoomEffect::reconfigure(ReconfigureFlags) } } -void ZoomEffect::prePaintScreen(ScreenPrePaintData& data, int time) +void ZoomEffect::prePaintScreen(ScreenPrePaintData& data, std::chrono::milliseconds presentTime) { if (zoom != target_zoom) { + int time = 0; + if (lastPresentTime.count()) + time = (presentTime - lastPresentTime).count(); + lastPresentTime = presentTime; + const float zoomDist = qAbs(target_zoom - source_zoom); if (target_zoom > zoom) zoom = qMin(zoom + ((zoomDist * time) / animationTime(150*zoomFactor)), target_zoom); @@ -266,7 +272,7 @@ void ZoomEffect::prePaintScreen(ScreenPrePaintData& data, int time) data.mask |= PAINT_SCREEN_TRANSFORMED; } - effects->prePaintScreen(data, time); + effects->prePaintScreen(data, presentTime); } void ZoomEffect::paintScreen(int mask, const QRegion ®ion, ScreenPaintData& data) @@ -389,6 +395,8 @@ void ZoomEffect::postPaintScreen() { if (zoom != target_zoom) effects->addRepaintFull(); + else + lastPresentTime = std::chrono::milliseconds::zero(); effects->postPaintScreen(); } diff --git a/effects/zoom/zoom.h b/effects/zoom/zoom.h index da754a94f7..6e4acc654a 100644 --- a/effects/zoom/zoom.h +++ b/effects/zoom/zoom.h @@ -43,7 +43,7 @@ public: ZoomEffect(); ~ZoomEffect() override; void reconfigure(ReconfigureFlags flags) override; - void prePaintScreen(ScreenPrePaintData& data, int time) override; + void prePaintScreen(ScreenPrePaintData& data, std::chrono::milliseconds presentTime) override; void paintScreen(int mask, const QRegion ®ion, ScreenPaintData& data) override; void postPaintScreen() override; bool isActive() const override; @@ -119,6 +119,7 @@ private: QTimeLine timeline; int xMove, yMove; double moveFactor; + std::chrono::milliseconds lastPresentTime; }; } // namespace diff --git a/libkwineffects/anidata.cpp b/libkwineffects/anidata.cpp index d2ee9d85b1..0b006ce591 100644 --- a/libkwineffects/anidata.cpp +++ b/libkwineffects/anidata.cpp @@ -64,6 +64,7 @@ AniData::AniData() , startTime(0) , waitAtSource(false) , keepAlive(true) + , lastPresentTime(std::chrono::milliseconds::zero()) { } @@ -80,6 +81,7 @@ AniData::AniData(AnimationEffect::Attribute a, int meta_, const FPx2 &to_, , waitAtSource(waitAtSource_) , keepAlive(keepAlive) , previousWindowPixmapLock(std::move(previousWindowPixmapLock_)) + , lastPresentTime(std::chrono::milliseconds::zero()) { } diff --git a/libkwineffects/anidata_p.h b/libkwineffects/anidata_p.h index c1bedafb4f..ed26e9a40b 100644 --- a/libkwineffects/anidata_p.h +++ b/libkwineffects/anidata_p.h @@ -88,6 +88,7 @@ public: KeepAliveLockPtr keepAliveLock; PreviousWindowPixmapLockPtr previousWindowPixmapLock; AnimationEffect::TerminationFlags terminationFlags; + std::chrono::milliseconds lastPresentTime; }; } // namespace diff --git a/libkwineffects/kwinanimationeffect.cpp b/libkwineffects/kwinanimationeffect.cpp index eb287aaee8..f0a741272f 100644 --- a/libkwineffects/kwinanimationeffect.cpp +++ b/libkwineffects/kwinanimationeffect.cpp @@ -391,11 +391,11 @@ bool AnimationEffect::cancel(quint64 animationId) return false; } -void AnimationEffect::prePaintScreen( ScreenPrePaintData& data, int time ) +void AnimationEffect::prePaintScreen( ScreenPrePaintData& data, std::chrono::milliseconds presentTime ) { Q_D(AnimationEffect); if (d->m_animations.isEmpty()) { - effects->prePaintScreen(data, time); + effects->prePaintScreen(data, presentTime); return; } @@ -415,7 +415,10 @@ void AnimationEffect::prePaintScreen( ScreenPrePaintData& data, int time ) continue; } } else { - anim->timeLine.update(std::chrono::milliseconds(time)); + if (anim->lastPresentTime.count()) { + anim->timeLine.update(presentTime - anim->lastPresentTime); + } + anim->lastPresentTime = presentTime; } if (anim->isActive()) { @@ -465,7 +468,7 @@ void AnimationEffect::prePaintScreen( ScreenPrePaintData& data, int time ) disconnectGeometryChanges(); } - effects->prePaintScreen(data, time); + effects->prePaintScreen(data, presentTime); } static int xCoord(const QRect &r, int flag) { @@ -561,7 +564,7 @@ void AnimationEffect::disconnectGeometryChanges() } -void AnimationEffect::prePaintWindow( EffectWindow* w, WindowPrePaintData& data, int time ) +void AnimationEffect::prePaintWindow( EffectWindow* w, WindowPrePaintData& data, std::chrono::milliseconds presentTime ) { Q_D(AnimationEffect); if ( d->m_animated ) { @@ -596,7 +599,7 @@ void AnimationEffect::prePaintWindow( EffectWindow* w, WindowPrePaintData& data, } } } - effects->prePaintWindow( w, data, time ); + effects->prePaintWindow(w, data, presentTime); } static inline float geometryCompensation(int flags, float v) diff --git a/libkwineffects/kwinanimationeffect.h b/libkwineffects/kwinanimationeffect.h index 94af2fcfc9..26179a8632 100644 --- a/libkwineffects/kwinanimationeffect.h +++ b/libkwineffects/kwinanimationeffect.h @@ -198,8 +198,8 @@ public: // Reimplemented from KWin::Effect. QString debug(const QString ¶meter) const override; - void prePaintScreen( ScreenPrePaintData& data, int time ) override; - void prePaintWindow( EffectWindow* w, WindowPrePaintData& data, int time ) override; + void prePaintScreen( ScreenPrePaintData& data, std::chrono::milliseconds presentTime ) override; + void prePaintWindow( EffectWindow* w, WindowPrePaintData& data, std::chrono::milliseconds presentTime ) override; void paintWindow( EffectWindow* w, int mask, QRegion region, WindowPaintData& data ) override; void postPaintScreen() override; diff --git a/libkwineffects/kwineffects.cpp b/libkwineffects/kwineffects.cpp index 7232143bab..0ed7c467bb 100644 --- a/libkwineffects/kwineffects.cpp +++ b/libkwineffects/kwineffects.cpp @@ -567,9 +567,9 @@ bool Effect::borderActivated(ElectricBorder) return false; } -void Effect::prePaintScreen(ScreenPrePaintData& data, int time) +void Effect::prePaintScreen(ScreenPrePaintData& data, std::chrono::milliseconds presentTime) { - effects->prePaintScreen(data, time); + effects->prePaintScreen(data, presentTime); } void Effect::paintScreen(int mask, const QRegion ®ion, ScreenPaintData& data) @@ -582,9 +582,9 @@ void Effect::postPaintScreen() effects->postPaintScreen(); } -void Effect::prePaintWindow(EffectWindow* w, WindowPrePaintData& data, int time) +void Effect::prePaintWindow(EffectWindow* w, WindowPrePaintData& data, std::chrono::milliseconds presentTime) { - effects->prePaintWindow(w, data, time); + effects->prePaintWindow(w, data, presentTime); } void Effect::paintWindow(EffectWindow* w, int mask, QRegion region, WindowPaintData& data) diff --git a/libkwineffects/kwineffects.h b/libkwineffects/kwineffects.h index bbc1c3deea..b5c165bb6d 100644 --- a/libkwineffects/kwineffects.h +++ b/libkwineffects/kwineffects.h @@ -402,8 +402,12 @@ public: * * In OpenGL based compositing, the frameworks ensures that the context is current * when this method is invoked. + * + * @a presentTime specifies the expected monotonic time when the rendered frame + * will be displayed on the screen. */ - virtual void prePaintScreen(ScreenPrePaintData& data, int time); + virtual void prePaintScreen(ScreenPrePaintData &data, + std::chrono::milliseconds presentTime); /** * In this method you can: * @li paint something on top of the windows (by painting after calling @@ -436,8 +440,12 @@ public: * * In OpenGL based compositing, the frameworks ensures that the context is current * when this method is invoked. + * + * @a presentTime specifies the expected monotonic time when the rendered frame + * will be displayed on the screen. */ - virtual void prePaintWindow(EffectWindow* w, WindowPrePaintData& data, int time); + virtual void prePaintWindow(EffectWindow *w, WindowPrePaintData &data, + std::chrono::milliseconds presentTime); /** * This is the main method for painting windows. * In this method you can: @@ -824,10 +832,10 @@ public: explicit EffectsHandler(CompositingType type); ~EffectsHandler() override; // for use by effects - virtual void prePaintScreen(ScreenPrePaintData& data, int time) = 0; + virtual void prePaintScreen(ScreenPrePaintData& data, std::chrono::milliseconds presentTime) = 0; virtual void paintScreen(int mask, const QRegion ®ion, ScreenPaintData& data) = 0; virtual void postPaintScreen() = 0; - virtual void prePaintWindow(EffectWindow* w, WindowPrePaintData& data, int time) = 0; + virtual void prePaintWindow(EffectWindow* w, WindowPrePaintData& data, std::chrono::milliseconds presentTime) = 0; virtual void paintWindow(EffectWindow* w, int mask, const QRegion ®ion, WindowPaintData& data) = 0; virtual void postPaintWindow(EffectWindow* w) = 0; virtual void paintEffectFrame(EffectFrame* frame, const QRegion ®ion, double opacity, double frameOpacity) = 0; diff --git a/plugins/scenes/opengl/scene_opengl.cpp b/plugins/scenes/opengl/scene_opengl.cpp index f90f00375d..e1f944b1c1 100644 --- a/plugins/scenes/opengl/scene_opengl.cpp +++ b/plugins/scenes/opengl/scene_opengl.cpp @@ -620,7 +620,8 @@ void SceneOpenGL::aboutToStartPainting(int screenId, const QRegion &damage) m_backend->aboutToStartPainting(screenId, damage); } -void SceneOpenGL::paint(int screenId, const QRegion &damage, const QList &toplevels) +void SceneOpenGL::paint(int screenId, const QRegion &damage, const QList &toplevels, + std::chrono::milliseconds presentTime) { if (m_resetOccurred) { return; // A graphics reset has occurred, do nothing. @@ -658,7 +659,8 @@ void SceneOpenGL::paint(int screenId, const QRegion &damage, const QListisGLES() && screenId == -1) { diff --git a/plugins/scenes/opengl/scene_opengl.h b/plugins/scenes/opengl/scene_opengl.h index 0e6c60c63e..93bcaa4fa9 100644 --- a/plugins/scenes/opengl/scene_opengl.h +++ b/plugins/scenes/opengl/scene_opengl.h @@ -35,7 +35,8 @@ public: ~SceneOpenGL() override; bool initFailed() const override; bool hasPendingFlush() const override; - void paint(int screenId, const QRegion &damage, const QList &windows) override; + void paint(int screenId, const QRegion &damage, const QList &windows, + std::chrono::milliseconds presentTime) override; Scene::EffectFrame *createEffectFrame(EffectFrameImpl *frame) override; Shadow *createShadow(Toplevel *toplevel) override; void screenGeometryChanged(const QSize &size) override; diff --git a/plugins/scenes/qpainter/scene_qpainter.cpp b/plugins/scenes/qpainter/scene_qpainter.cpp index 7a9b525254..a1de2f56ac 100644 --- a/plugins/scenes/qpainter/scene_qpainter.cpp +++ b/plugins/scenes/qpainter/scene_qpainter.cpp @@ -80,7 +80,8 @@ void SceneQPainter::paintGenericScreen(int mask, const ScreenPaintData &data) m_painter->restore(); } -void SceneQPainter::paint(int screenId, const QRegion &_damage, const QList &toplevels) +void SceneQPainter::paint(int screenId, const QRegion &_damage, const QList &toplevels, + std::chrono::milliseconds presentTime) { Q_ASSERT(kwinApp()->platform()->isPerScreenRenderingEnabled()); painted_screen = screenId; @@ -103,7 +104,8 @@ void SceneQPainter::paint(int screenId, const QRegion &_damage, const QListsetWindow(geometry); QRegion updateRegion, validRegion; - paintScreen(&mask, damage.intersected(geometry), QRegion(), &updateRegion, &validRegion); + paintScreen(&mask, damage.intersected(geometry), QRegion(), &updateRegion, &validRegion, + presentTime); paintCursor(updateRegion); m_painter->end(); diff --git a/plugins/scenes/qpainter/scene_qpainter.h b/plugins/scenes/qpainter/scene_qpainter.h index b47b1c18be..d9b304c383 100644 --- a/plugins/scenes/qpainter/scene_qpainter.h +++ b/plugins/scenes/qpainter/scene_qpainter.h @@ -25,7 +25,8 @@ public: ~SceneQPainter() override; bool usesOverlayWindow() const override; OverlayWindow* overlayWindow() const override; - void paint(int screenId, const QRegion &damage, const QList &windows) override; + void paint(int screenId, const QRegion &damage, const QList &windows, + std::chrono::milliseconds presentTime) override; void paintGenericScreen(int mask, const ScreenPaintData &data) override; CompositingType compositingType() const override; bool initFailed() const override; diff --git a/plugins/scenes/xrender/scene_xrender.cpp b/plugins/scenes/xrender/scene_xrender.cpp index b967fe7350..27766e8a71 100644 --- a/plugins/scenes/xrender/scene_xrender.cpp +++ b/plugins/scenes/xrender/scene_xrender.cpp @@ -75,7 +75,8 @@ bool SceneXrender::initFailed() const } // the entry point for painting -void SceneXrender::paint(int screenId, const QRegion &damage, const QList &toplevels) +void SceneXrender::paint(int screenId, const QRegion &damage, const QList &toplevels, + std::chrono::milliseconds presentTime) { painted_screen = screenId; @@ -83,7 +84,7 @@ void SceneXrender::paint(int screenId, const QRegion &damage, const QListshowOverlay(); diff --git a/plugins/scenes/xrender/scene_xrender.h b/plugins/scenes/xrender/scene_xrender.h index 0f31f46961..1816e35303 100644 --- a/plugins/scenes/xrender/scene_xrender.h +++ b/plugins/scenes/xrender/scene_xrender.h @@ -32,7 +32,8 @@ public: CompositingType compositingType() const override { return XRenderCompositing; } - void paint(int screenId, const QRegion &damage, const QList &windows) override; + void paint(int screenId, const QRegion &damage, const QList &windows, + std::chrono::milliseconds presentTime) override; Scene::EffectFrame *createEffectFrame(EffectFrameImpl *frame) override; Shadow *createShadow(Toplevel *toplevel) override; void screenGeometryChanged(const QSize &size) override; diff --git a/scene.cpp b/scene.cpp index 1c065f7787..30ee308d02 100644 --- a/scene.cpp +++ b/scene.cpp @@ -86,7 +86,6 @@ namespace KWin Scene::Scene(QObject *parent) : QObject(parent) { - last_time.invalidate(); // Initialize the timer } Scene::~Scene() @@ -96,13 +95,22 @@ Scene::~Scene() // returns mask and possibly modified region void Scene::paintScreen(int* mask, const QRegion &damage, const QRegion &repaint, - QRegion *updateRegion, QRegion *validRegion, const QMatrix4x4 &projection, const QRect &outputGeometry, const qreal screenScale) + QRegion *updateRegion, QRegion *validRegion, + std::chrono::milliseconds presentTime, + const QMatrix4x4 &projection, const QRect &outputGeometry, + qreal screenScale) { const QSize &screenSize = screens()->size(); const QRegion displayRegion(0, 0, screenSize.width(), screenSize.height()); *mask = (damage == displayRegion) ? 0 : PAINT_SCREEN_REGION; - updateTimeDiff(); + if (Q_UNLIKELY(presentTime < m_expectedPresentTimestamp)) { + qCDebug(KWIN_CORE, "Provided presentation timestamp is invalid: %ld (current: %ld)", + presentTime.count(), m_expectedPresentTimestamp.count()); + } else { + m_expectedPresentTimestamp = presentTime; + } + // preparation step static_cast(effects)->startPaint(); @@ -112,7 +120,7 @@ void Scene::paintScreen(int* mask, const QRegion &damage, const QRegion &repaint pdata.mask = *mask; pdata.paint = region; - effects->prePaintScreen(pdata, time_diff); + effects->prePaintScreen(pdata, m_expectedPresentTimestamp); *mask = pdata.mask; region = pdata.paint; @@ -154,29 +162,9 @@ void Scene::paintScreen(int* mask, const QRegion &damage, const QRegion &repaint Q_ASSERT(!PaintClipper::clip()); } -// Compute time since the last painting pass. -void Scene::updateTimeDiff() -{ - if (!last_time.isValid()) { - // Painting has been idle (optimized out) for some time, - // which means time_diff would be huge and would break animations. - // Simply set it to one (zero would mean no change at all and could - // cause problems). - time_diff = 1; - last_time.start(); - } else - - time_diff = last_time.restart(); - - if (time_diff < 0) // check time rollback - time_diff = 1; -} - // Painting pass is optimized away. void Scene::idle() { - // Don't break time since last paint for the next pass. - last_time.invalidate(); } // the function that'll be eventually called by paintScreen() above @@ -213,7 +201,7 @@ void Scene::paintGenericScreen(int orig_mask, const ScreenPaintData &) data.clip = QRegion(); data.quads = w->buildQuads(); // preparation step - effects->prePaintWindow(effectWindow(w), data, time_diff); + effects->prePaintWindow(effectWindow(w), data, m_expectedPresentTimestamp); #if !defined(QT_NO_DEBUG) if (data.quads.isTransformed()) { qFatal("Pre-paint calls are not allowed to transform quads!"); @@ -306,7 +294,7 @@ void Scene::paintSimpleScreen(int orig_mask, const QRegion ®ion) data.quads = window->buildQuads(); // preparation step - effects->prePaintWindow(effectWindow(window), data, time_diff); + effects->prePaintWindow(effectWindow(window), data, m_expectedPresentTimestamp); #if !defined(QT_NO_DEBUG) if (data.quads.isTransformed()) { qFatal("Pre-paint calls are not allowed to transform quads!"); diff --git a/scene.h b/scene.h index 1b8ea7c432..86506e71da 100644 --- a/scene.h +++ b/scene.h @@ -65,7 +65,8 @@ public: // The entry point for the main part of the painting pass. // returns the time since the last vblank signal - if there's one // ie. "what of this frame is lost to painting" - virtual void paint(int screenId, const QRegion &damage, const QList &windows) = 0; + virtual void paint(int screenId, const QRegion &damage, const QList &windows, + std::chrono::milliseconds presentTime) = 0; /** * Adds the Toplevel to the Scene. @@ -207,7 +208,10 @@ protected: void clearStackingOrder(); // shared implementation, starts painting the screen void paintScreen(int *mask, const QRegion &damage, const QRegion &repaint, - QRegion *updateRegion, QRegion *validRegion, const QMatrix4x4 &projection = QMatrix4x4(), const QRect &outputGeometry = QRect(), const qreal screenScale = 1.0); + QRegion *updateRegion, QRegion *validRegion, + std::chrono::milliseconds presentTime, + const QMatrix4x4 &projection = QMatrix4x4(), + const QRect &outputGeometry = QRect(), qreal screenScale = 1.0); // Render cursor texture in case hardware cursor is disabled/non-applicable virtual void paintCursor(const QRegion ®ion) = 0; friend class EffectsHandlerImpl; @@ -240,8 +244,6 @@ protected: virtual void paintEffectQuickView(EffectQuickView *w) = 0; - // compute time since the last repaint - void updateTimeDiff(); // saved data for 2nd pass of optimized screen painting struct Phase2Data { Window *window = nullptr; @@ -260,14 +262,12 @@ protected: QRegion repaint_region; // The dirty region before it was unioned with repaint_region QRegion damaged_region; - // time since last repaint - int time_diff; - QElapsedTimer last_time; // The screen that is being currently painted int painted_screen = -1; private: void paintWindowThumbnails(Scene::Window *w, const QRegion ®ion, qreal opacity, qreal brightness, qreal saturation); void paintDesktopThumbnails(Scene::Window *w); + std::chrono::milliseconds m_expectedPresentTimestamp = std::chrono::milliseconds::zero(); QHash< Toplevel*, Window* > m_windows; // windows in their stacking order QVector< Window* > stacking_order;