From 880db578e03c49f997481c4eb45e006cc51d01b8 Mon Sep 17 00:00:00 2001 From: "Antoine C." Date: Fri, 24 Jan 2025 18:06:27 +0000 Subject: [PATCH] WIP --- src/main.cpp | 31 +++----------------- src/qml/qmlapplication.cpp | 45 ++++++++++++++++++++++++++---- src/qml/qmlapplication.h | 10 +++++-- src/qml/qmldlgpreferencesproxy.cpp | 4 +-- src/qml/qmldlgpreferencesproxy.h | 2 +- src/soundio/soundmanager.cpp | 2 +- 6 files changed, 55 insertions(+), 39 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 74c5f6c07bf..e11e038ab5c 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -57,39 +57,16 @@ constexpr int kPixmapCacheLimitAt100PercentZoom = 32 * 1024; // 32 MByte int runMixxx(MixxxApplication* pApp, const CmdlineArgs& args) { CmdlineArgs::Instance().parseForUserFeedback(); - auto pCoreServices = std::make_shared(args, pApp); - int exitCode; #ifdef MIXXX_USE_QML if (args.isQml()) { - auto pTick = std::make_unique(); - auto pVisuals = std::make_unique(); - WaveformWidgetFactory::createInstance(); // takes a long time - WaveformWidgetFactory::instance()->setConfig(pCoreServices->getSettings()); - WaveformWidgetFactory::instance()->startVSync(pTick.get(), pVisuals.get(), true); - { - mixxx::qml::QmlApplication qmlApplication(pApp, pCoreServices); - const QStringList visualGroups = - pCoreServices->getPlayerManager()->getVisualPlayerGroups(); - for (const QString& group : visualGroups) { - pVisuals->addDeck(group); - } - pCoreServices->getPlayerManager()->connect(pCoreServices->getPlayerManager().get(), - &PlayerManager::numberOfDecksChanged, - &qmlApplication, - [&pVisuals](int decks) { - for (int i = 0; i < decks; ++i) { - QString group = PlayerManager::groupForDeck(i); - pVisuals->addDeckIfNotExist(group); - } - }); - exitCode = pApp->exec(); - } - pCoreServices.reset(); - WaveformWidgetFactory::destroy(); + mixxx::qml::QmlApplication qmlApplication(pApp, args); + exitCode = pApp->exec(); } else #endif { + auto pCoreServices = std::make_shared(args, pApp); + // This scope ensures that `MixxxMainWindow` is destroyed *before* // CoreServices is shut down. Otherwise a debug assertion complaining about // leaked COs may be triggered. diff --git a/src/qml/qmlapplication.cpp b/src/qml/qmlapplication.cpp index 5ead34eb30d..ceea63ea9e5 100644 --- a/src/qml/qmlapplication.cpp +++ b/src/qml/qmlapplication.cpp @@ -20,6 +20,9 @@ #include "qml/qmlvisibleeffectsmodel.h" #include "qml/qmlwaveformoverview.h" #include "soundio/soundmanager.h" +#include "waveform/guitick.h" +#include "waveform/visualsmanager.h" +#include "waveform/waveformwidgetfactory.h" Q_IMPORT_QML_PLUGIN(MixxxPlugin) Q_IMPORT_QML_PLUGIN(Mixxx_ControlsPlugin) @@ -42,13 +45,19 @@ namespace qml { QmlApplication::QmlApplication( QApplication* app, - std::shared_ptr pCoreServices) - : m_pCoreServices(pCoreServices), - m_mainFilePath(pCoreServices->getSettings()->getResourcePath() + kMainQmlFileName), + const CmdlineArgs& args) + : m_pCoreServices(std::make_unique(args, app)), + m_guiTick(std::make_unique()), + m_visualsManager(std::make_unique()), + m_mainFilePath(m_pCoreServices->getSettings()->getResourcePath() + kMainQmlFileName), m_pAppEngine(nullptr), m_autoReload() { QQuickStyle::setStyle("Basic"); + WaveformWidgetFactory::createInstance(); // takes a long time + WaveformWidgetFactory::instance()->setConfig(m_pCoreServices->getSettings()); + WaveformWidgetFactory::instance()->startVSync(m_guiTick.get(), m_visualsManager.get(), true); + m_pCoreServices->initialize(app); SoundDeviceStatus result = m_pCoreServices->getSoundManager()->setupDevices(); if (result != SoundDeviceStatus::Ok) { @@ -67,10 +76,11 @@ QmlApplication::QmlApplication( // Since DlgPreferences is only meant to be used in the main QML engine, it // follows a strict singleton pattern design - QmlDlgPreferencesProxy::s_pInstance = new QmlDlgPreferencesProxy(pDlgPreferences, this); + QmlDlgPreferencesProxy::s_pInstance = + std::make_unique(pDlgPreferences, this); loadQml(m_mainFilePath); - pCoreServices->getControllerManager()->setUpDevices(); + m_pCoreServices->getControllerManager()->setUpDevices(); connect(&m_autoReload, &QmlAutoReload::triggered, @@ -78,11 +88,34 @@ QmlApplication::QmlApplication( [this]() { loadQml(m_mainFilePath); }); + + const QStringList visualGroups = + m_pCoreServices->getPlayerManager()->getVisualPlayerGroups(); + for (const QString& group : visualGroups) { + m_visualsManager->addDeck(group); + } + + m_pCoreServices->getPlayerManager()->connect( + m_pCoreServices->getPlayerManager().get(), + &PlayerManager::numberOfDecksChanged, + this, + [this](int decks) { + for (int i = 0; i < decks; ++i) { + QString group = PlayerManager::groupForDeck(i); + m_visualsManager->addDeckIfNotExist(group); + } + }); } QmlApplication::~QmlApplication() { // Delete all the QML singletons in order to prevent leak detection in CoreService - QmlDlgPreferencesProxy::s_pInstance->deleteLater(); + QmlDlgPreferencesProxy::s_pInstance.reset(); + + WaveformWidgetFactory::destroy(); + m_guiTick.reset(); + m_visualsManager.reset(); + m_pAppEngine.reset(); + m_pCoreServices.reset(); } void QmlApplication::loadQml(const QString& path) { diff --git a/src/qml/qmlapplication.h b/src/qml/qmlapplication.h index b13e8a0ed83..435208e0fc5 100644 --- a/src/qml/qmlapplication.h +++ b/src/qml/qmlapplication.h @@ -6,6 +6,9 @@ #include "coreservices.h" #include "qmlautoreload.h" +class GuiTick; +class VisualsManager; + namespace mixxx { namespace qml { @@ -14,14 +17,17 @@ class QmlApplication : public QObject { public: QmlApplication( QApplication* app, - std::shared_ptr pCoreServices); + const CmdlineArgs& args); ~QmlApplication() override; public slots: void loadQml(const QString& path); private: - std::shared_ptr m_pCoreServices; + std::unique_ptr m_pCoreServices; + + std::unique_ptr<::GuiTick> m_guiTick; + std::unique_ptr<::VisualsManager> m_visualsManager; QString m_mainFilePath; diff --git a/src/qml/qmldlgpreferencesproxy.cpp b/src/qml/qmldlgpreferencesproxy.cpp index fbaf4a2eeae..7c67872866e 100644 --- a/src/qml/qmldlgpreferencesproxy.cpp +++ b/src/qml/qmldlgpreferencesproxy.cpp @@ -43,8 +43,8 @@ QmlDlgPreferencesProxy* QmlDlgPreferencesProxy::create( // Explicitly specify C++ ownership so that the engine doesn't delete // the instance. - QJSEngine::setObjectOwnership(s_pInstance, QJSEngine::CppOwnership); - return s_pInstance; + QJSEngine::setObjectOwnership(s_pInstance.get(), QJSEngine::CppOwnership); + return s_pInstance.get(); } } // namespace qml diff --git a/src/qml/qmldlgpreferencesproxy.h b/src/qml/qmldlgpreferencesproxy.h index 40e73ea300a..b41ed44ebec 100644 --- a/src/qml/qmldlgpreferencesproxy.h +++ b/src/qml/qmldlgpreferencesproxy.h @@ -20,7 +20,7 @@ class QmlDlgPreferencesProxy : public QObject { Q_INVOKABLE void show(); static QmlDlgPreferencesProxy* create(QQmlEngine* pQmlEngine, QJSEngine* pJsEngine); - static inline QmlDlgPreferencesProxy* s_pInstance = nullptr; + static inline std::unique_ptr s_pInstance; private: static inline QJSEngine* s_pJsEngine = nullptr; diff --git a/src/soundio/soundmanager.cpp b/src/soundio/soundmanager.cpp index 273211831ca..5e3bd6f639d 100644 --- a/src/soundio/soundmanager.cpp +++ b/src/soundio/soundmanager.cpp @@ -162,7 +162,7 @@ void SoundManager::closeDevices(bool sleepAfterClosing) { #ifdef __LINUX__ // Sleep for 5 sec to allow asynchronously sound APIs like "pulse" to free // its resources as well - QThread::sleep(kSleepSecondsAfterClosingDevice); + // QThread::sleep(kSleepSecondsAfterClosingDevice); #endif }