92 lines
4.1 KiB
Diff
92 lines
4.1 KiB
Diff
diff --git a/src/plugins/platforms/wayland/qwaylanddisplay.cpp b/src/plugins/platforms/wayland/qwaylanddisplay.cpp
|
|
index 02169e77..42d2aa0f 100644
|
|
--- a/src/plugins/platforms/wayland/qwaylanddisplay.cpp
|
|
+++ b/src/plugins/platforms/wayland/qwaylanddisplay.cpp
|
|
@@ -603,6 +603,11 @@ QWaylandScreen *QWaylandDisplay::screenForOutput(struct wl_output *output) const
|
|
return nullptr;
|
|
}
|
|
|
|
+bool QWaylandDisplay::isScreenAlive(QWaylandScreen *screen) const
|
|
+{
|
|
+ return mScreens.contains(screen) || mWaitingScreens.contains(screen);
|
|
+}
|
|
+
|
|
void QWaylandDisplay::handleScreenInitialized(QWaylandScreen *screen)
|
|
{
|
|
if (!mWaitingScreens.removeOne(screen))
|
|
diff --git a/src/plugins/platforms/wayland/qwaylanddisplay_p.h b/src/plugins/platforms/wayland/qwaylanddisplay_p.h
|
|
index 29952886..379403ee 100644
|
|
--- a/src/plugins/platforms/wayland/qwaylanddisplay_p.h
|
|
+++ b/src/plugins/platforms/wayland/qwaylanddisplay_p.h
|
|
@@ -116,6 +116,7 @@ public:
|
|
QPlatformPlaceholderScreen *placeholderScreen() const { return mPlaceholderScreen; }
|
|
void ensureScreen();
|
|
|
|
+ bool isScreenAlive(QWaylandScreen *screen) const;
|
|
QWaylandScreen *screenForOutput(struct wl_output *output) const;
|
|
void handleScreenInitialized(QWaylandScreen *screen);
|
|
|
|
diff --git a/src/plugins/platforms/wayland/qwaylandsurface.cpp b/src/plugins/platforms/wayland/qwaylandsurface.cpp
|
|
index 274fdda8..f630cec3 100644
|
|
--- a/src/plugins/platforms/wayland/qwaylandsurface.cpp
|
|
+++ b/src/plugins/platforms/wayland/qwaylandsurface.cpp
|
|
@@ -13,6 +13,7 @@ namespace QtWaylandClient {
|
|
|
|
QWaylandSurface::QWaylandSurface(QWaylandDisplay *display)
|
|
: wl_surface(display->createSurface(this))
|
|
+ , m_display(display)
|
|
{
|
|
connect(qApp, &QGuiApplication::screenRemoved, this, &QWaylandSurface::handleScreenRemoved);
|
|
connect(qApp, &QGuiApplication::screenAdded, this, &QWaylandSurface::screensChanged);
|
|
@@ -25,6 +26,13 @@ QWaylandSurface::~QWaylandSurface()
|
|
|
|
QWaylandScreen *QWaylandSurface::oldestEnteredScreen()
|
|
{
|
|
+ // Prune stale screen pointers before iterating. Entries can go stale
|
|
+ // when a wl_output is removed while a waiting-state QWaylandScreen
|
|
+ // referencing it was in m_screens (direct deletion, no screenRemoved signal).
|
|
+ m_screens.removeIf([this](QWaylandScreen *s) {
|
|
+ return !m_display->isScreenAlive(s);
|
|
+ });
|
|
+
|
|
for (auto *screen : std::as_const(m_screens)) {
|
|
// only report valid screens
|
|
// we can have some ouptuts waiting for xdg output information
|
|
@@ -60,6 +68,14 @@ void QWaylandSurface::surface_enter(wl_output *output)
|
|
if (!addedScreen)
|
|
return;
|
|
|
|
+ // libwayland resolves wl_output proxy pointers at demarshal time. If a
|
|
+ // preceding event in the same dispatch batch destroyed the output's proxy
|
|
+ // (e.g. via wl_registry.global_remove), fromWlOutput may return a stale
|
|
+ // QWaylandScreen pointer from freed proxy memory. Validate against the
|
|
+ // display's live screen lists before dereferencing.
|
|
+ if (!m_display->isScreenAlive(addedScreen))
|
|
+ return;
|
|
+
|
|
if (m_screens.contains(addedScreen)) {
|
|
qCWarning(lcQpaWayland)
|
|
<< "Ignoring unexpected wl_surface.enter received for output with id:"
|
|
@@ -80,6 +96,10 @@ void QWaylandSurface::surface_leave(wl_output *output)
|
|
if (!removedScreen)
|
|
return;
|
|
|
|
+ // See comment in surface_enter: the proxy may reference a dead screen.
|
|
+ if (!m_display->isScreenAlive(removedScreen))
|
|
+ return;
|
|
+
|
|
bool wasRemoved = m_screens.removeOne(removedScreen);
|
|
if (!wasRemoved) {
|
|
qCWarning(lcQpaWayland)
|
|
diff --git a/src/plugins/platforms/wayland/qwaylandsurface_p.h b/src/plugins/platforms/wayland/qwaylandsurface_p.h
|
|
index 41860297..af59f0a3 100644
|
|
--- a/src/plugins/platforms/wayland/qwaylandsurface_p.h
|
|
+++ b/src/plugins/platforms/wayland/qwaylandsurface_p.h
|
|
@@ -57,6 +57,7 @@ protected:
|
|
|
|
QList<QWaylandScreen *> m_screens; //As seen by wl_surface.enter/leave events. Chronological order.
|
|
QWaylandWindow *m_window = nullptr;
|
|
+ QWaylandDisplay *m_display = nullptr;
|
|
std::optional<int32_t> m_preferredBufferScale;
|
|
std::optional<wl_output_transform> m_preferredBufferTransform;
|
|
|