effects/overview: Layout window thumbnails in updatePolish()

Currently, ExpoLayout delays layout updates by using a singleshot timer
(primarily due to the author of the effect not being aware of
QQuickItem::polish() and QQuickItem::updatePolish()).

This change makes ExpoLayout schedule layout updates using QtQuick's
native item polish machinery, which gets triggered before rendering and
thus we can batch more geometry updates.

In addition to that, this change simplifies the initialization code in
ScreenView by making the fact that ExpoLayout is arranged right before
rendering internal to the WindowHeap type.
This commit is contained in:
Vlad Zahorodnii 2021-08-31 13:41:36 +03:00
parent 683bf20168
commit b0c26cc424
4 changed files with 42 additions and 36 deletions

View file

@ -45,7 +45,7 @@ void ExpoCell::setLayout(ExpoLayout *layout)
void ExpoCell::update() void ExpoCell::update()
{ {
if (m_layout) { if (m_layout) {
m_layout->scheduleUpdate(); m_layout->polish();
} }
} }
@ -199,8 +199,6 @@ void ExpoCell::setPersistentKey(const QString &key)
ExpoLayout::ExpoLayout(QQuickItem *parent) ExpoLayout::ExpoLayout(QQuickItem *parent)
: QQuickItem(parent) : QQuickItem(parent)
{ {
m_updateTimer.setSingleShot(true);
connect(&m_updateTimer, &QTimer::timeout, this, &ExpoLayout::update);
} }
ExpoLayout::LayoutMode ExpoLayout::mode() const ExpoLayout::LayoutMode ExpoLayout::mode() const
@ -212,7 +210,7 @@ void ExpoLayout::setMode(LayoutMode mode)
{ {
if (m_mode != mode) { if (m_mode != mode) {
m_mode = mode; m_mode = mode;
scheduleUpdate(); polish();
Q_EMIT modeChanged(); Q_EMIT modeChanged();
} }
} }
@ -226,7 +224,7 @@ void ExpoLayout::setFillGaps(bool fill)
{ {
if (m_fillGaps != fill) { if (m_fillGaps != fill) {
m_fillGaps = fill; m_fillGaps = fill;
scheduleUpdate(); polish();
Q_EMIT fillGapsChanged(); Q_EMIT fillGapsChanged();
} }
} }
@ -240,51 +238,60 @@ void ExpoLayout::setSpacing(int spacing)
{ {
if (m_spacing != spacing) { if (m_spacing != spacing) {
m_spacing = spacing; m_spacing = spacing;
scheduleUpdate(); polish();
Q_EMIT spacingChanged(); Q_EMIT spacingChanged();
} }
} }
void ExpoLayout::update() bool ExpoLayout::isReady() const
{ {
if (m_cells.isEmpty()) { return m_ready;
return; }
}
switch (m_mode) { void ExpoLayout::setReady()
case LayoutClosest: {
calculateWindowTransformationsClosest(); if (!m_ready) {
break; m_ready = true;
case LayoutKompose: Q_EMIT readyChanged();
calculateWindowTransformationsKompose();
break;
case LayoutNatural:
calculateWindowTransformationsNatural();
break;
} }
} }
void ExpoLayout::scheduleUpdate() void ExpoLayout::updatePolish()
{ {
m_updateTimer.start(); if (!m_cells.isEmpty()) {
switch (m_mode) {
case LayoutClosest:
calculateWindowTransformationsClosest();
break;
case LayoutKompose:
calculateWindowTransformationsKompose();
break;
case LayoutNatural:
calculateWindowTransformationsNatural();
break;
}
}
setReady();
} }
void ExpoLayout::addCell(ExpoCell *cell) void ExpoLayout::addCell(ExpoCell *cell)
{ {
Q_ASSERT(!m_cells.contains(cell)); Q_ASSERT(!m_cells.contains(cell));
m_cells.append(cell); m_cells.append(cell);
scheduleUpdate(); polish();
} }
void ExpoLayout::removeCell(ExpoCell *cell) void ExpoLayout::removeCell(ExpoCell *cell)
{ {
m_cells.removeOne(cell); m_cells.removeOne(cell);
scheduleUpdate(); polish();
} }
void ExpoLayout::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) void ExpoLayout::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry)
{ {
if (newGeometry.size() != oldGeometry.size()) { if (newGeometry.size() != oldGeometry.size()) {
scheduleUpdate(); polish();
} }
QQuickItem::geometryChanged(newGeometry, oldGeometry); QQuickItem::geometryChanged(newGeometry, oldGeometry);
} }

View file

@ -9,7 +9,6 @@
#include <QObject> #include <QObject>
#include <QQuickItem> #include <QQuickItem>
#include <QRect> #include <QRect>
#include <QTimer>
#include <optional> #include <optional>
@ -21,6 +20,7 @@ class ExpoLayout : public QQuickItem
Q_PROPERTY(LayoutMode mode READ mode WRITE setMode NOTIFY modeChanged) Q_PROPERTY(LayoutMode mode READ mode WRITE setMode NOTIFY modeChanged)
Q_PROPERTY(bool fillGaps READ fillGaps WRITE setFillGaps NOTIFY fillGapsChanged) Q_PROPERTY(bool fillGaps READ fillGaps WRITE setFillGaps NOTIFY fillGapsChanged)
Q_PROPERTY(int spacing READ spacing WRITE setSpacing NOTIFY spacingChanged) Q_PROPERTY(int spacing READ spacing WRITE setSpacing NOTIFY spacingChanged)
Q_PROPERTY(bool ready READ isReady NOTIFY readyChanged)
public: public:
enum LayoutMode : uint { enum LayoutMode : uint {
@ -44,17 +44,18 @@ public:
void addCell(ExpoCell *cell); void addCell(ExpoCell *cell);
void removeCell(ExpoCell *cell); void removeCell(ExpoCell *cell);
bool isReady() const;
void setReady();
protected: protected:
void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) override; void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) override;
void updatePolish() override;
public Q_SLOTS:
void update();
void scheduleUpdate();
Q_SIGNALS: Q_SIGNALS:
void modeChanged(); void modeChanged();
void fillGapsChanged(); void fillGapsChanged();
void spacingChanged(); void spacingChanged();
void readyChanged();
private: private:
void calculateWindowTransformationsClosest(); void calculateWindowTransformationsClosest();
@ -63,9 +64,9 @@ private:
QList<ExpoCell *> m_cells; QList<ExpoCell *> m_cells;
LayoutMode m_mode = LayoutNatural; LayoutMode m_mode = LayoutNatural;
QTimer m_updateTimer;
int m_accuracy = 20; int m_accuracy = 20;
int m_spacing = 10; int m_spacing = 10;
bool m_ready = false;
bool m_fillGaps = false; bool m_fillGaps = false;
}; };

View file

@ -125,8 +125,5 @@ FocusScope {
id: stackModel id: stackModel
} }
Component.onCompleted: { Component.onCompleted: start();
// Delay starting the effect to let the window heap arrange thumbnails.
Qt.callLater(container.start);
}
} }

View file

@ -27,6 +27,7 @@ FocusScope {
property real padding: 0 property real padding: 0
required property bool organized required property bool organized
readonly property bool effectiveOrganized: expoLayout.ready && organized
ExpoLayout { ExpoLayout {
id: expoLayout id: expoLayout
@ -50,7 +51,7 @@ FocusScope {
readonly property bool selected: heap.selectedIndex == index readonly property bool selected: heap.selectedIndex == index
state: { state: {
if (heap.organized) { if (heap.effectiveOrganized) {
return "active"; return "active";
} }
return client.minimized ? "initial-minimized" : "initial"; return client.minimized ? "initial-minimized" : "initial";