diff --git a/src/lib/core/presenter/DocumentManager.cpp b/src/lib/core/presenter/DocumentManager.cpp index f22aab74f7..2d27de53f9 100644 --- a/src/lib/core/presenter/DocumentManager.cpp +++ b/src/lib/core/presenter/DocumentManager.cpp @@ -156,6 +156,17 @@ DocumentManager::~DocumentManager() // The documents have to be deleted before the application context plug-ins. // This is because the Local device has to be deleted last in // ApplicationPlugin. + for(auto document : m_documents) + { + // Reverse creation order, to match ~DocumentModel (e.g. the execution + // plugin must be torn down before the device explorer plugin). + auto& plugs = document->model().pluginModels(); + for(auto it = plugs.rbegin(); it != plugs.rend(); ++it) + { + (*it)->on_documentClosing(); + } + } + for(auto document : m_documents) { document->deleteLater(); diff --git a/src/lib/score/gfx/Vulkan.cpp b/src/lib/score/gfx/Vulkan.cpp index 98a5baceeb..309daca8c3 100644 --- a/src/lib/score/gfx/Vulkan.cpp +++ b/src/lib/score/gfx/Vulkan.cpp @@ -60,6 +60,8 @@ QVulkanInstance* staticVulkanInstance(bool create) if(!instance.create()) { g_staticVulkanInstanceInvalid = true; + delete g_staticVulkanInstance; + g_staticVulkanInstance = nullptr; } }); diff --git a/src/lib/score/model/path/ObjectPath.cpp b/src/lib/score/model/path/ObjectPath.cpp index 6fd28de16a..e9e19e2e2f 100644 --- a/src/lib/score/model/path/ObjectPath.cpp +++ b/src/lib/score/model/path/ObjectPath.cpp @@ -147,6 +147,30 @@ QString ObjectPath::toString() const noexcept return s; } +ObjectPath ObjectPath::fromString(const QString& str) noexcept +{ + std::vector v; + for(const auto& seg : QStringView{str}.split(QLatin1Char('/'), Qt::SkipEmptyParts)) + { + const auto dot = seg.lastIndexOf(QLatin1Char('.')); + if(dot <= 0) + return {}; + bool ok{}; + const int32_t id = seg.mid(dot + 1).toInt(&ok); + if(!ok) + return {}; + v.emplace_back(seg.left(dot).toString(), id); + } + return ObjectPath{std::move(v)}; +} + +QObject* ObjectPath::findObject(const score::DocumentContext& ctx) const noexcept +{ + if(m_objectIdentifiers.empty()) + return nullptr; + return find_impl_unsafe(ctx); +} + QObject* ObjectPath::find_impl(const score::DocumentContext& ctx) const { using namespace score; diff --git a/src/lib/score/model/path/ObjectPath.hpp b/src/lib/score/model/path/ObjectPath.hpp index 963c39efe6..7b8e45a782 100644 --- a/src/lib/score/model/path/ObjectPath.hpp +++ b/src/lib/score/model/path/ObjectPath.hpp @@ -59,6 +59,8 @@ class SCORE_LIB_BASE_EXPORT ObjectPath ObjectPath() noexcept { } ~ObjectPath() noexcept = default; QString toString() const noexcept; + static ObjectPath fromString(const QString& str) noexcept; + QObject* findObject(const score::DocumentContext& ctx) const noexcept; explicit ObjectPath(std::vector vec) noexcept : m_objectIdentifiers{std::move(vec)} diff --git a/src/plugins/score-plugin-avnd/Crousti/ProcessModel.hpp b/src/plugins/score-plugin-avnd/Crousti/ProcessModel.hpp index 5a1cd5be99..16761d473f 100644 --- a/src/plugins/score-plugin-avnd/Crousti/ProcessModel.hpp +++ b/src/plugins/score-plugin-avnd/Crousti/ProcessModel.hpp @@ -38,6 +38,12 @@ namespace oscr { +// The condition under which a process needs the port-callback storage (a +// model-side Info instance). The storage member and its init guard below must +// both use it — keep them in sync. +template +concept needs_ports_callback_storage = has_dynamic_ports; + template struct MessageBusWrapperToUi { @@ -92,7 +98,8 @@ class ProcessModel final oscr::dynamic_ports_storage dynamic_ports; [[no_unique_address]] - ossia::type_if> object_storage_for_ports_callbacks; + ossia::type_if> + object_storage_for_ports_callbacks; ProcessModel( const TimeVal& duration, const Id& id, @@ -202,9 +209,7 @@ class ProcessModel final void init_controller_ports() { - if constexpr( - avnd::dynamic_ports_input_introspection::size > 0 - || avnd::dynamic_ports_output_introspection::size > 0) + if constexpr(oscr::needs_ports_callback_storage) { avnd::control_input_introspection::for_all_n2( avnd::get_inputs((Info&)this->object_storage_for_ports_callbacks), diff --git a/src/plugins/score-plugin-deviceexplorer/Explorer/DocumentPlugin/DeviceDocumentPlugin.cpp b/src/plugins/score-plugin-deviceexplorer/Explorer/DocumentPlugin/DeviceDocumentPlugin.cpp index eb1f5bae19..a2aee645d6 100644 --- a/src/plugins/score-plugin-deviceexplorer/Explorer/DocumentPlugin/DeviceDocumentPlugin.cpp +++ b/src/plugins/score-plugin-deviceexplorer/Explorer/DocumentPlugin/DeviceDocumentPlugin.cpp @@ -59,6 +59,14 @@ DeviceDocumentPlugin::DeviceDocumentPlugin( m_explorer = new DeviceExplorerModel{*this, this}; } +void DeviceDocumentPlugin::on_documentClosing() +{ + for(auto dev : this->m_list.devices()) + { + dev->disconnect(); + } +} + DeviceDocumentPlugin::~DeviceDocumentPlugin() { for(auto dev : this->m_list.devices()) diff --git a/src/plugins/score-plugin-deviceexplorer/Explorer/DocumentPlugin/DeviceDocumentPlugin.hpp b/src/plugins/score-plugin-deviceexplorer/Explorer/DocumentPlugin/DeviceDocumentPlugin.hpp index 0a42415044..c2b85985fb 100644 --- a/src/plugins/score-plugin-deviceexplorer/Explorer/DocumentPlugin/DeviceDocumentPlugin.hpp +++ b/src/plugins/score-plugin-deviceexplorer/Explorer/DocumentPlugin/DeviceDocumentPlugin.hpp @@ -49,6 +49,8 @@ class SCORE_PLUGIN_DEVICEEXPLORER_EXPORT DeviceDocumentPlugin final void init(); + void on_documentClosing() override; + Device::Node& rootNode() { return m_rootNode; } const Device::Node& rootNode() const { return m_rootNode; } diff --git a/src/plugins/score-plugin-gfx/Gfx/GStreamer/GStreamerDevice.cpp b/src/plugins/score-plugin-gfx/Gfx/GStreamer/GStreamerDevice.cpp index 1df3e8e69e..94e5bd9f8d 100644 --- a/src/plugins/score-plugin-gfx/Gfx/GStreamer/GStreamerDevice.cpp +++ b/src/plugins/score-plugin-gfx/Gfx/GStreamer/GStreamerDevice.cpp @@ -35,8 +35,10 @@ extern "C" { #include #include