From 50177a8406ada5a52f3d85a985ce03a5d1f92364 Mon Sep 17 00:00:00 2001 From: Michail Vourlakos Date: Sun, 12 Dec 2021 03:13:35 +0200 Subject: [PATCH] improve smoothness of animations during startup --This new approach paints all docks and panels during starup offscreen. This way especially under x11 not a lot of visual glitches are appearing all over the place. After startup time has ended docks and panels are moved at their original and valid placement and slide in animations are triggered. --- app/view/positioner.cpp | 29 +++++++++++++- app/view/positioner.h | 6 ++- app/view/view.cpp | 4 -- app/view/view.h | 1 - app/view/visibilitymanager.cpp | 38 +++++++++---------- app/view/visibilitymanager.h | 2 + .../package/contents/ui/VisibilityManager.qml | 20 +++++++++- containment/package/contents/ui/main.qml | 32 +++++++++++++++- 8 files changed, 102 insertions(+), 30 deletions(-) diff --git a/app/view/positioner.cpp b/app/view/positioner.cpp index ad3ccbc65..75dd5681e 100644 --- a/app/view/positioner.cpp +++ b/app/view/positioner.cpp @@ -107,6 +107,7 @@ void Positioner::init() connect(this, &Positioner::hidingForRelocationStarted, this, &Positioner::updateInRelocationAnimation); connect(this, &Positioner::showingAfterRelocationFinished, this, &Positioner::updateInRelocationAnimation); connect(this, &Positioner::showingAfterRelocationFinished, this, &Positioner::syncLatteViews); + connect(this, &Positioner::startupFinished, this, &Positioner::onStartupFinished); connect(m_view, &Latte::View::onPrimaryChanged, this, &Positioner::syncLatteViews); @@ -336,6 +337,14 @@ void Positioner::slideInDuringStartup() m_corona->wm()->slideWindow(*m_view, slideLocation(m_view->containment()->location())); } +void Positioner::onStartupFinished() +{ + if (m_inStartup) { + m_inStartup = false; + syncGeometry(); + } +} + void Positioner::onCurrentLayoutIsSwitching(const QString &layoutName) { if (!m_view || !m_view->layout() || m_view->layout()->name() != layoutName || !m_view->isVisible()) { @@ -509,7 +518,14 @@ void Positioner::immediateSyncGeometry() //! instead of two times (both inside the resizeWindow and the updatePosition) QRegion freeRegion;; QRect maximumRect; - QRect availableScreenRect{m_view->screen()->geometry()}; + QRect availableScreenRect = m_view->screen()->geometry(); + + if (m_inStartup) { + //! paint out-of-screen + availableScreenRect = QRect(-9999, -9999, m_view->screen()->geometry().width(), m_view->screen()->geometry().height()); + } + + qDebug() << " ------------>> " << m_view->location() << " ___ " << availableScreenRect; if (m_view->formFactor() == Plasma::Types::Vertical) { QString layoutName = m_view->layout() ? m_view->layout()->name() : QString(); @@ -538,7 +554,12 @@ void Positioner::immediateSyncGeometry() } QString activityid = m_view->layout() ? m_view->layout()->lastUsedActivity() : QString(); - freeRegion = latteCorona->availableScreenRegionWithCriteria(fixedScreen, activityid, ignoreModes, ignoreEdges); + if (m_inStartup) { + //! paint out-of-screen + freeRegion = availableScreenRect; + } else { + freeRegion = latteCorona->availableScreenRegionWithCriteria(fixedScreen, activityid, ignoreModes, ignoreEdges); + } maximumRect = maximumNormalGeometry(); QRegion availableRegion = freeRegion.intersected(maximumRect); @@ -871,6 +892,10 @@ void Positioner::resizeWindow(QRect availableScreenRect) } } + //! protect from invalid window size under wayland + size.setWidth(qMax(1, size.width())); + size.setHeight(qMax(1, size.height())); + m_validGeometry.setSize(size); m_view->setMinimumSize(size); diff --git a/app/view/positioner.h b/app/view/positioner.h index 481b3afa7..78400efc7 100644 --- a/app/view/positioner.h +++ b/app/view/positioner.h @@ -89,6 +89,7 @@ public: public slots: Q_INVOKABLE void setNextLocation(const QString layoutName, const QString screenId, int edge, int alignment); + Q_INVOKABLE void slideInDuringStartup(); void syncGeometry(); @@ -96,7 +97,6 @@ public slots: //! that might prevent them. It must be called with care. void immediateSyncGeometry(); - void slideInDuringStartup(); void slideOutDuringExit(Plasma::Types::Location location = Plasma::Types::Floating); void initDelayedSignals(); @@ -118,6 +118,8 @@ signals: void hidingForRelocationFinished(); void showingAfterRelocationFinished(); + void startupFinished(); //called from containment qml end of startup sequence + void onHideWindowsForSlidingOut(); void inRelocationAnimationChanged(); void inRelocationShowingChanged(); @@ -129,6 +131,7 @@ private slots: void onScreenChanged(QScreen *screen); void onCurrentLayoutIsSwitching(const QString &layoutName); void onLastRepositionApplyEvent(); + void onStartupFinished(); void validateDockGeometry(); void updateInRelocationAnimation(); @@ -160,6 +163,7 @@ private: bool m_inRelocationAnimation{false}; bool m_inRelocationShowing{false}; bool m_inSlideAnimation{false}; + bool m_inStartup{true}; bool m_isStickedOnTopEdge{false}; bool m_isStickedOnBottomEdge{false}; diff --git a/app/view/view.cpp b/app/view/view.cpp index 3b6c9c96f..178f10864 100644 --- a/app/view/view.cpp +++ b/app/view/view.cpp @@ -172,10 +172,6 @@ View::View(Plasma::Corona *corona, QScreen *targetScreen, bool byPassX11WM) if (m_positioner) { //! immediateSyncGeometry helps avoiding binding loops from containment qml side m_positioner->immediateSyncGeometry(); - if (m_inStartup) { - m_inStartup = false; - m_positioner->slideInDuringStartup(); - } } connect(this->containment(), SIGNAL(statusChanged(Plasma::Types::ItemStatus)), SLOT(statusChanged(Plasma::Types::ItemStatus))); diff --git a/app/view/view.h b/app/view/view.h index 4525a4017..c24488ff7 100644 --- a/app/view/view.h +++ b/app/view/view.h @@ -391,7 +391,6 @@ private: bool m_containsDrag{false}; bool m_containsMouse{false}; bool m_inDelete{false}; - bool m_inStartup{true}; bool m_isPreferredForShortcuts{false}; bool m_onPrimary{true}; bool m_screenEdgeMarginEnabled{false}; diff --git a/app/view/visibilitymanager.cpp b/app/view/visibilitymanager.cpp index a77aede20..d34d88368 100644 --- a/app/view/visibilitymanager.cpp +++ b/app/view/visibilitymanager.cpp @@ -79,16 +79,6 @@ VisibilityManager::VisibilityManager(PlasmaQuick::ContainmentView *view) connect(m_latteView, &Latte::View::inEditModeChanged, this, &VisibilityManager::initViewFlags); - // disabling this call because it was creating too many struts calls and - // could create reduced responsiveness for DynamicStruts Scenario(for example - // when dragging active window from a floating dock/panel) - /* - connect(m_latteView, &Latte::View::absoluteGeometryChanged, this, [&]() { - if (m_mode == Types::AlwaysVisible) { - updateStrutsBasedOnLayoutsAndActivities(); - } - });*/ - //! Frame Extents connect(m_latteView, &Latte::View::headThicknessGapChanged, this, &VisibilityManager::onHeadThicknessChanged); connect(m_latteView, &Latte::View::locationChanged, this, [&]() { @@ -267,23 +257,20 @@ void VisibilityManager::setMode(Latte::Types::Visibility mode) updateStrutsBasedOnLayoutsAndActivities(); } - m_connections[base] = connect(this, &VisibilityManager::strutsThicknessChanged, this, [&]() { - bool execute = !m_timerBlockStrutsUpdate.isActive(); - - m_timerBlockStrutsUpdate.start(); + m_connections[base] = connect(this, &VisibilityManager::strutsThicknessChanged, &VisibilityManager::updateStrutsAfterTimer); - if (execute) { - updateStrutsBasedOnLayoutsAndActivities(); - } - }); + // disabling this call because it was creating too many struts calls and ??? + // could create reduced responsiveness for DynamicStruts Scenario(for example ?? + // when dragging active window from a floating dock/panel) ??? + m_connections[base+1] = connect(m_latteView, &Latte::View::absoluteGeometryChanged, this, &VisibilityManager::updateStrutsAfterTimer); - m_connections[base+1] = connect(m_corona->activitiesConsumer(), &KActivities::Consumer::currentActivityChanged, this, [&]() { + m_connections[base+2] = connect(m_corona->activitiesConsumer(), &KActivities::Consumer::currentActivityChanged, this, [&]() { if (m_corona && m_corona->layoutsManager()->memoryUsage() == MemoryUsage::MultipleLayouts) { updateStrutsBasedOnLayoutsAndActivities(true); } }); - m_connections[base+2] = connect(m_latteView, &Latte::View::activitiesChanged, this, [&]() { + m_connections[base+3] = connect(m_latteView, &Latte::View::activitiesChanged, this, [&]() { updateStrutsBasedOnLayoutsAndActivities(true); }); @@ -382,6 +369,17 @@ void VisibilityManager::setMode(Latte::Types::Visibility mode) emit modeChanged(); } +void VisibilityManager::updateStrutsAfterTimer() +{ + bool execute = !m_timerBlockStrutsUpdate.isActive(); + + m_timerBlockStrutsUpdate.start(); + + if (execute) { + updateStrutsBasedOnLayoutsAndActivities(); + } +} + void VisibilityManager::updateSidebarState() { bool cursidebarstate = ((m_mode == Types::SidebarOnDemand) diff --git a/app/view/visibilitymanager.h b/app/view/visibilitymanager.h index 92e240a34..1d9da2a7a 100644 --- a/app/view/visibilitymanager.h +++ b/app/view/visibilitymanager.h @@ -204,6 +204,8 @@ private slots: void dodgeMaximized(); void updateHiddenState(); + void updateStrutsAfterTimer(); + bool isValidMode() const; private: diff --git a/containment/package/contents/ui/VisibilityManager.qml b/containment/package/contents/ui/VisibilityManager.qml index 6f1f41826..42b28b04f 100644 --- a/containment/package/contents/ui/VisibilityManager.qml +++ b/containment/package/contents/ui/VisibilityManager.qml @@ -166,6 +166,11 @@ Item{ } function slotMustBeShown() { + if (root.inStartup) { + slidingAnimationAutoHiddenIn.init(); + return; + } + //! WindowsCanCover case if (latteView && latteView.visibility.mode === LatteCore.Types.WindowsCanCover) { latteView.visibility.setViewOnFrontLayer(); @@ -190,6 +195,11 @@ Item{ } function slotMustBeHide() { + if (root.inStartup) { + slidingAnimationAutoHiddenOut.init(); + return; + } + if (inSlidingIn && !inRelocationHiding) { /*consider hiding after sliding in has finished*/ return; @@ -468,10 +478,18 @@ Item{ latteView.visibility.slideOutFinished(); manager.updateInputGeometry(); + + if (root.inStartup) { + //! when view is first created slide-outs when that animation ends then + //! it flags that startup has ended and first slide-in can be started + //! this is important because if it is removed then some views + //! wont slide-in after startup. + root.inStartup = false; + } } function init() { - if (manager.inRelocationAnimation || !latteView.visibility.blockHiding) { + if (manager.inRelocationAnimation || root.inStartup/*used from recreating views*/ || !latteView.visibility.blockHiding) { start(); } } diff --git a/containment/package/contents/ui/main.qml b/containment/package/contents/ui/main.qml index 26775fa77..98238a1c5 100644 --- a/containment/package/contents/ui/main.qml +++ b/containment/package/contents/ui/main.qml @@ -180,7 +180,7 @@ Item { property bool dragActiveWindowEnabled: plasmoid.configuration.dragActiveWindowEnabled property bool immutable: plasmoid.immutable property bool inFullJustify: (plasmoid.configuration.alignment === LatteCore.Types.Justify) && (maxLengthPerCentage===100) - property bool inStartup: !fastLayoutManager.hasRestoredApplets + property bool inStartup: true property bool isHorizontal: plasmoid.formFactor === PlasmaCore.Types.Horizontal property bool isVertical: !isHorizontal @@ -1045,6 +1045,12 @@ Item { onViewChanged: { if (view) { view.interfacesGraphicObj = _interfaces; + + if (!root.inStartup) { + //! used from recreating views + root.inStartup = true; + startupDelayer.start(); + } } } } @@ -1056,10 +1062,34 @@ Item { //! It is used in order to slide-in the latteView on startup onInStartupChanged: { if (!inStartup) { + latteView.positioner.startupFinished(); + latteView.positioner.slideInDuringStartup(); visibilityManager.slotMustBeShown(); } } + Connections { + target:fastLayoutManager + onHasRestoredAppletsChanged: { + if (fastLayoutManager.hasRestoredApplets) { + startupDelayer.start(); + } + } + } + + Timer { + //! Give a little more time to layouter and applets to load and be positioned properly during startup when + //! the view is drawn out-of-screen and afterwards trigger the startup animation sequence: + //! 1.slide-out when out-of-screen //slotMustBeHide() + //! 2.be positioned properly at correct screen //slideInDuringStartup(), triggers Positioner::syncGeometry() + //! 3.slide-in properly in correct screen //slotMustBeShown(); + id: startupDelayer + interval: 1000 + onTriggered: { + visibilityManager.slotMustBeHide(); + } + } + ///////////////END TIMER elements Loader{