From df8ddb609b8a5278c42a62e5bc685fe9304e7e5d Mon Sep 17 00:00:00 2001 From: Vlad Zahorodnii Date: Tue, 12 Sep 2023 13:30:19 +0300 Subject: [PATCH] wayland: Keep transaction entries for deleted surfaces If a transaction entry is removed, the graphics buffer reference will be dropped and it's possible that the TransactionDmaBufLocker is going to be destroyed as well. If that happens, the transaction may remain in the locked state. --- src/wayland/surface_interface.cpp | 4 ---- src/wayland/transaction.cpp | 32 ++++++++++++++++--------------- src/wayland/transaction.h | 13 ++++++------- 3 files changed, 23 insertions(+), 26 deletions(-) diff --git a/src/wayland/surface_interface.cpp b/src/wayland/surface_interface.cpp index c707c4aad8..b5918f2702 100644 --- a/src/wayland/surface_interface.cpp +++ b/src/wayland/surface_interface.cpp @@ -407,10 +407,6 @@ SurfaceInterface::~SurfaceInterface() { delete d->subsurface.transaction; d->subsurface.transaction = nullptr; - - for (auto transaction = d->firstTransaction; transaction; transaction = transaction->next(this)) { - transaction->remove(this); - } } SurfaceRole *SurfaceInterface::role() const diff --git a/src/wayland/transaction.cpp b/src/wayland/transaction.cpp index 1d207da3d6..a564c1ce09 100644 --- a/src/wayland/transaction.cpp +++ b/src/wayland/transaction.cpp @@ -103,6 +103,9 @@ bool Transaction::isReady() const } for (const TransactionEntry &entry : m_entries) { + if (!entry.surface) { + continue; + } if (entry.surface->firstTransaction() != this) { return false; } @@ -145,13 +148,6 @@ void Transaction::add(SurfaceInterface *surface) }); } -void Transaction::remove(SurfaceInterface *surface) -{ - std::erase_if(m_entries, [surface](const TransactionEntry &entry) { - return entry.surface == surface; - }); -} - void Transaction::amend(SurfaceInterface *surface, std::function mutator) { for (TransactionEntry &entry : m_entries) { @@ -211,17 +207,23 @@ void Transaction::apply() }); for (TransactionEntry &entry : m_entries) { - SurfaceInterfacePrivate::get(entry.surface)->applyState(entry.state.get()); + if (entry.surface) { + SurfaceInterfacePrivate::get(entry.surface)->applyState(entry.state.get()); + } } for (TransactionEntry &entry : m_entries) { - if (entry.surface->lastTransaction() == this) { - entry.surface->setFirstTransaction(nullptr); - entry.surface->setLastTransaction(nullptr); - } else { - Transaction *nextTransaction = entry.nextTransaction; - entry.surface->setFirstTransaction(nextTransaction); - nextTransaction->tryApply(); + if (entry.surface) { + if (entry.surface->lastTransaction() == this) { + entry.surface->setFirstTransaction(nullptr); + entry.surface->setLastTransaction(nullptr); + } else { + entry.surface->setFirstTransaction(entry.nextTransaction); + } + } + + if (entry.nextTransaction) { + entry.nextTransaction->tryApply(); } } diff --git a/src/wayland/transaction.h b/src/wayland/transaction.h index 82140c4d22..06e58fc440 100644 --- a/src/wayland/transaction.h +++ b/src/wayland/transaction.h @@ -8,6 +8,8 @@ #include "core/graphicsbuffer.h" +#include + #include #include #include @@ -25,9 +27,11 @@ class Transaction; struct TransactionEntry { /** - * The surface that is going to be affected by the transaction. + * The surface that is going to be affected by the transaction. Might be + * \c null if the surface has been destroyed while the transaction is still + * not ready. */ - SurfaceInterface *surface = nullptr; + QPointer surface; /** * Next transaction that is going to affect the surface. @@ -81,11 +85,6 @@ public: */ void add(SurfaceInterface *surface); - /** - * Removes the specified \a surface from this transaction. - */ - void remove(SurfaceInterface *surface); - /** * Amends already committed state. */