wayland: Fix transaction cleanup with destroyed surfaces
When sorting surfaces in the ancestor order we need to ignore null surfaces. In addition to that, we also need to properly handle the case where a transaction with dependencies is unlocked and it contains null surfaces. For example, if there are three transactions A -> B -> C, and the B transaction is unlocked, we cannot apply it until transaction A is applied. The readiness check is based on checking the first pending transaction of the surface. But if the surface is null, the check will be skipped, which is not ideal as transaction B can be applied before transaction A now. To address that, this change makes every transaction entry remember the previous transaction. With that, the readiness check can be performed even if the surface has been destroyed. BUG: 475648
This commit is contained in:
parent
816d2866c7
commit
d52ba8c3fe
2 changed files with 22 additions and 10 deletions
|
@ -100,16 +100,9 @@ bool Transaction::isReady() const
|
|||
return false;
|
||||
}
|
||||
|
||||
for (const TransactionEntry &entry : m_entries) {
|
||||
if (!entry.surface) {
|
||||
continue;
|
||||
}
|
||||
if (entry.surface->firstTransaction() != this) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
return std::none_of(m_entries.cbegin(), m_entries.cend(), [](const TransactionEntry &entry) {
|
||||
return entry.previousTransaction;
|
||||
});
|
||||
}
|
||||
|
||||
Transaction *Transaction::next(SurfaceInterface *surface) const
|
||||
|
@ -195,6 +188,13 @@ void Transaction::apply()
|
|||
{
|
||||
// Sort surfaces so descendants come first, then their ancestors.
|
||||
std::sort(m_entries.begin(), m_entries.end(), [](const TransactionEntry &a, const TransactionEntry &b) {
|
||||
if (!a.surface) {
|
||||
return false;
|
||||
}
|
||||
if (!b.surface) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (isAncestor(a.surface, b.surface)) {
|
||||
return true;
|
||||
}
|
||||
|
@ -221,6 +221,12 @@ void Transaction::apply()
|
|||
}
|
||||
|
||||
if (entry.nextTransaction) {
|
||||
for (TransactionEntry &otherEntry : entry.nextTransaction->m_entries) {
|
||||
if (otherEntry.previousTransaction == this) {
|
||||
otherEntry.previousTransaction = nullptr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
entry.nextTransaction->tryApply();
|
||||
}
|
||||
}
|
||||
|
@ -258,6 +264,7 @@ void Transaction::commit()
|
|||
entry.surface->setFirstTransaction(this);
|
||||
}
|
||||
|
||||
entry.previousTransaction = entry.surface->lastTransaction();
|
||||
entry.surface->setLastTransaction(this);
|
||||
}
|
||||
|
||||
|
|
|
@ -33,6 +33,11 @@ struct TransactionEntry
|
|||
*/
|
||||
QPointer<SurfaceInterface> surface;
|
||||
|
||||
/**
|
||||
* The previous transaction that this transaction depends on.
|
||||
*/
|
||||
Transaction *previousTransaction = nullptr;
|
||||
|
||||
/**
|
||||
* Next transaction that is going to affect the surface.
|
||||
*/
|
||||
|
|
Loading…
Reference in a new issue