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.
This commit is contained in:
Błażej Szczygieł 2026-11-01 01:04:13 +01:00 committed by Akseli Lahtinen
parent dc7b9473f7
commit 8cf95a7eaf
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);
}
}
}
@ -1328,7 +1329,11 @@ void Positioner::onListingCompleted(const QList<QUrl> &urls)
m_positions = newPositions;
savePositionsConfig();
if (m_skipSaveOnListingCompleted) {
m_skipSaveOnListingCompleted = false;
} else {
savePositionsConfig();
}
}
void Positioner::connectSignals(FolderModel *model)

View file

@ -178,6 +178,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;