From 91dcb41d2216be6b11955c59b54637bff6c2f296 Mon Sep 17 00:00:00 2001 From: outfoxxed Date: Thu, 17 Jul 2025 00:06:32 -0700 Subject: [PATCH] services/pipewire: destroy qml ifaces early to avoid user callbacks Consumers of defaultAudio*Changed signals can run code between safeDestroy being called and PwObjectIface destruction due to signal connection order. This change destroys ifaces earlier so they are nulled by the time a changed signal is fired from destruction, preventing access between ~PwNode() and ~QObject() completion. Fixes #116 #122 #124 --- src/services/pipewire/qml.cpp | 10 ++++++++++ src/services/pipewire/qml.hpp | 5 ++++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src/services/pipewire/qml.cpp b/src/services/pipewire/qml.cpp index 5d8c45e7..9efb17eb 100644 --- a/src/services/pipewire/qml.cpp +++ b/src/services/pipewire/qml.cpp @@ -18,6 +18,16 @@ namespace qs::service::pipewire { +PwObjectIface::PwObjectIface(PwBindableObject* object): QObject(object), object(object) { + // We want to destroy the interface before QObject::destroyed is fired, as handlers + // connected before PwObjectIface will run first and emit signals that hit user code, + // which can then try to reference the iface again after ~PwNode() has been called but + // before ~QObject() has finished. + QObject::connect(object, &PwBindableObject::destroying, this, &PwObjectIface::onObjectDestroying); +} + +void PwObjectIface::onObjectDestroying() { delete this; } + void PwObjectIface::ref() { this->refcount++; diff --git a/src/services/pipewire/qml.hpp b/src/services/pipewire/qml.hpp index 5bcc70d4..e3489a1c 100644 --- a/src/services/pipewire/qml.hpp +++ b/src/services/pipewire/qml.hpp @@ -36,7 +36,7 @@ class PwObjectIface Q_OBJECT; public: - explicit PwObjectIface(PwBindableObject* object): QObject(object), object(object) {}; + explicit PwObjectIface(PwBindableObject* object); // destructor should ONLY be called by the pw object destructor, making an unref unnecessary ~PwObjectIface() override = default; Q_DISABLE_COPY_MOVE(PwObjectIface); @@ -44,6 +44,9 @@ public: void ref() override; void unref() override; +private slots: + void onObjectDestroying(); + private: quint32 refcount = 0; PwBindableObject* object;