Positioner: Conditionally skip saving positions after listing completes

Prevent saving incorrect icon positions while the desktop is still
setting up its screen geometry.

This fixes the following scenario:
- 'setPerStripe()' is called from QtQuick with a lower 'perStripe'
  value (because the desktop geometry is not yet correct) while the
  directory is being listed
- directory listing finishes (we skip saving the icon positions)
- 'setPerStripe()' is called again (from QtQuick) with the correct value

This can occasionally happen when turning off one monitor and turning on
another, depending on the hardware.

Behavior change: Saving is skipped when Plasma loads or the desktop
reappears on the screen. There is no need to save when the desktop
loads or reappears.

(cherry picked from commit 8cf95a7eaf)
This commit is contained in:
Błażej Szczygieł 2026-11-01 01:04:13 +01:00
parent adfb19dfd5
commit 891840c2d1
4 changed files with 46 additions and 1 deletions

View file

@ -418,6 +418,44 @@ void PositionerTest::tst_dontSaveWithoutScreen()
QCOMPARE(baselineConfig, getCurrentConfig());
}
void PositionerTest::tst_mixedSetPerStripeListingAndReady()
{
QString firstUrl;
for (auto [url, gridPos] : std::as_const(m_positioner->m_positions).asKeyValueRange()) {
if (gridPos.pos == 0 && gridPos.stripe == 0) {
firstUrl = url;
break;
}
}
QVERIFY(!firstUrl.isEmpty());
auto getFirstGridPos = [firstUrl, this] {
return m_positioner->m_positions.value(firstUrl, {-1, -1});
};
const auto perStripe = m_positioner->perStripe();
QCOMPARE_GT(perStripe, 1);
const int newPos = m_positioner->m_positions.size() + perStripe + 1;
m_positioner->move({0, newPos});
auto newGridPos = getFirstGridPos();
QCOMPARE(newGridPos.stripe, newPos / perStripe);
QCOMPARE(newGridPos.pos, newPos % perStripe);
m_folderModel->refresh();
QTRY_COMPARE(m_folderModel->status(), FolderModel::Listing);
m_positioner->setPerStripe(1);
QVERIFY(m_positioner->m_deferApplyPositions);
ensureFolderModelReady();
m_positioner->setPerStripe(perStripe);
auto gridPos = getFirstGridPos();
QCOMPARE(gridPos.stripe, newGridPos.stripe);
QCOMPARE(gridPos.pos, newGridPos.pos);
}
// Test utilities
QJsonDocument PositionerTest::getCurrentConfig()

View file

@ -48,6 +48,7 @@ private Q_SLOTS:
void tst_renameFile();
void tst_insertFile();
void tst_dontSaveWithoutScreen();
void tst_mixedSetPerStripeListingAndReady();
private:
void checkDefaultPositions(int perStripe);

View file

@ -570,6 +570,7 @@ void Positioner::sourceStatusChanged()
updatePositionsList();
if (m_deferRestoreChangedPositions) {
maybeRestoreAndApplyChangedPositions(false);
m_skipSaveOnListingCompleted = (m_folderModel->status() == FolderModel::Ready);
}
}
}
@ -1305,7 +1306,11 @@ void Positioner::onItemRenamed(const QString &filename, const QString &newFilena
// geometry changes
void Positioner::onListingCompleted()
{
savePositionsConfig();
if (m_skipSaveOnListingCompleted) {
m_skipSaveOnListingCompleted = false;
} else {
savePositionsConfig();
}
}
void Positioner::connectSignals(FolderModel *model)

View file

@ -177,6 +177,7 @@ private:
QHash<QString, GridPosition> m_positions;
bool m_deferApplyPositions;
bool m_deferRestoreChangedPositions = false;
bool m_skipSaveOnListingCompleted = false;
QVariantList m_deferMovePositions;
QHash<QString, std::optional<ChangedPosition>> m_changedPositions;