From f754682adf2874041e0eddff708cfd396c805e72 Mon Sep 17 00:00:00 2001
From: Be
Date: Mon, 14 Dec 2020 12:45:04 -0600
Subject: [PATCH 01/11] introduce CoreServices to decouple backend from
QWidgets
---
CMakeLists.txt | 1 +
src/coreservices.cpp | 588 +++++++++++++++++++++++
src/coreservices.h | 143 ++++++
src/main.cpp | 15 +-
src/mixer/basetrackplayer.cpp | 3 -
src/mixer/basetrackplayer.h | 1 -
src/mixer/deck.cpp | 2 -
src/mixer/deck.h | 1 -
src/mixer/playermanager.cpp | 19 +-
src/mixer/playermanager.h | 4 +-
src/mixer/previewdeck.cpp | 2 -
src/mixer/previewdeck.h | 1 -
src/mixer/sampler.cpp | 2 -
src/mixer/sampler.h | 1 -
src/mixxx.cpp | 855 ++++++----------------------------
src/mixxx.h | 58 +--
src/skin/launchimage.cpp | 6 +-
src/skin/launchimage.h | 3 +-
src/test/signalpathtest.h | 8 -
19 files changed, 922 insertions(+), 791 deletions(-)
create mode 100644 src/coreservices.cpp
create mode 100644 src/coreservices.h
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 591fd6ba64f..00a70264bf2 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -636,6 +636,7 @@ add_library(mixxx-lib STATIC EXCLUDE_FROM_ALL
src/mixer/previewdeck.cpp
src/mixer/sampler.cpp
src/mixer/samplerbank.cpp
+ src/coreservices.cpp
src/mixxx.cpp
src/mixxxapplication.cpp
src/musicbrainz/chromaprinter.cpp
diff --git a/src/coreservices.cpp b/src/coreservices.cpp
new file mode 100644
index 00000000000..228d5df5300
--- /dev/null
+++ b/src/coreservices.cpp
@@ -0,0 +1,588 @@
+#include "coreservices.h"
+
+#include
+#include
+#include
+
+#ifdef __BROADCAST__
+#include "broadcast/broadcastmanager.h"
+#endif
+#include "controllers/controllermanager.h"
+#include "controllers/keyboard/keyboardeventfilter.h"
+#include "database/mixxxdb.h"
+#include "effects/builtin/builtinbackend.h"
+#include "effects/effectsmanager.h"
+#include "effects/lv2/lv2backend.h"
+#include "engine/enginemaster.h"
+#include "library/coverartcache.h"
+#include "library/library.h"
+#include "library/trackcollectionmanager.h"
+#include "mixer/playerinfo.h"
+#include "mixer/playermanager.h"
+#include "preferences/settingsmanager.h"
+#include "soundio/soundmanager.h"
+#include "sources/soundsourceproxy.h"
+#include "util/db/dbconnectionpooled.h"
+#include "util/font.h"
+#include "util/logger.h"
+#include "util/screensaver.h"
+#include "util/statsmanager.h"
+#include "util/time.h"
+#include "util/translations.h"
+#include "util/version.h"
+#include "vinylcontrol/vinylcontrolmanager.h"
+
+#ifdef __APPLE__
+#include "util/sandbox.h"
+#endif
+
+#if defined(Q_OS_LINUX)
+#include
+#include
+
+#include
+
+#include "engine/channelhandle.h"
+// Xlibint.h predates C++ and defines macros which conflict
+// with references to std::max and std::min
+#undef max
+#undef min
+#endif
+
+namespace {
+const mixxx::Logger kLogger("CoreServices");
+
+#define CLEAR_AND_CHECK_DELETED(x) clearHelper(x, #x);
+
+template
+void clearHelper(std::shared_ptr& ref_ptr, const char* name) {
+ std::weak_ptr weak(ref_ptr);
+ ref_ptr.reset();
+ if (auto shared = weak.lock()) {
+ qWarning() << name << "was leaked! Use count:" << shared.use_count();
+ DEBUG_ASSERT(false);
+ }
+}
+
+// hack around https://gitlab.freedesktop.org/xorg/lib/libx11/issues/25
+// https://bugs.launchpad.net/mixxx/+bug/1805559
+#if defined(Q_OS_LINUX)
+typedef Bool (*WireToErrorType)(Display*, XErrorEvent*, xError*);
+
+const int NUM_HANDLERS = 256;
+WireToErrorType __oldHandlers[NUM_HANDLERS] = {0};
+
+Bool __xErrorHandler(Display* display, XErrorEvent* event, xError* error) {
+ // Call any previous handler first in case it needs to do real work.
+ auto code = static_cast(event->error_code);
+ if (__oldHandlers[code] != NULL) {
+ __oldHandlers[code](display, event, error);
+ }
+
+ // Always return false so the error does not get passed to the normal
+ // application defined handler.
+ return False;
+}
+
+#endif
+
+inline QLocale inputLocale() {
+ // Use the default config for local keyboard
+ QInputMethod* pInputMethod = QGuiApplication::inputMethod();
+ return pInputMethod ? pInputMethod->locale() : QLocale(QLocale::English);
+}
+} // anonymous namespace
+
+namespace mixxx {
+
+// static
+const int CoreServices::kMicrophoneCount = 4;
+// static
+const int CoreServices::kAuxiliaryCount = 4;
+
+CoreServices::CoreServices(const CmdlineArgs& args)
+ : m_runtime_timer(QLatin1String("CoreServices::runtime")),
+ m_cmdlineArgs(args) {
+}
+
+void CoreServices::initializeSettings() {
+ QString settingsPath = m_cmdlineArgs.getSettingsPath();
+#ifdef __APPLE__
+ if (!m_cmdlineArgs.getSettingsPathSet()) {
+ settingsPath = Sandbox::migrateOldSettings();
+ }
+#endif
+ m_pSettingsManager = std::make_unique(settingsPath);
+}
+
+void CoreServices::initialize(QApplication* pApp) {
+ m_runtime_timer.start();
+ mixxx::Time::start();
+ ScopedTimer t("CoreServices::initialize");
+
+ mixxx::Logging::initialize(
+ m_pSettingsManager->settings()->getSettingsPath(),
+ m_cmdlineArgs.getLogLevel(),
+ m_cmdlineArgs.getLogFlushLevel(),
+ m_cmdlineArgs.getDebugAssertBreak());
+
+ VERIFY_OR_DEBUG_ASSERT(SoundSourceProxy::registerProviders()) {
+ qCritical() << "Failed to register any SoundSource providers";
+ return;
+ }
+
+ Version::logBuildDetails();
+
+ // Only record stats in developer mode.
+ if (m_cmdlineArgs.getDeveloper()) {
+ StatsManager::createInstance();
+ }
+
+ initializeKeyboard();
+
+ mixxx::Translations::initializeTranslations(
+ m_pSettingsManager->settings(), pApp, m_cmdlineArgs.getLocale());
+
+#if defined(Q_OS_LINUX)
+ // XESetWireToError will segfault if running as a Wayland client
+ if (pApp->platformName() == QLatin1String("xcb")) {
+ for (auto i = 0; i < NUM_HANDLERS; ++i) {
+ XESetWireToError(QX11Info::display(), i, &__xErrorHandler);
+ }
+ }
+#endif
+
+ UserSettingsPointer pConfig = m_pSettingsManager->settings();
+
+ Sandbox::initialize(QDir(pConfig->getSettingsPath()).filePath("sandbox.cfg"));
+
+ QString resourcePath = pConfig->getResourcePath();
+
+ emit initializationProgressUpdate(0, tr("fonts"));
+
+ FontUtils::initializeFonts(resourcePath); // takes a long time
+
+ // Set the visibility of tooltips, default "1" = ON
+ m_toolTipsCfg = static_cast(
+ pConfig->getValue(ConfigKey("[Controls]", "Tooltips"),
+ static_cast(mixxx::TooltipsPreference::TOOLTIPS_ON)));
+
+ emit initializationProgressUpdate(10, tr("database"));
+ m_pDbConnectionPool = MixxxDb(pConfig).connectionPool();
+ if (!m_pDbConnectionPool) {
+ exit(-1);
+ }
+ // Create a connection for the main thread
+ m_pDbConnectionPool->createThreadLocalConnection();
+ if (!initializeDatabase()) {
+ exit(-1);
+ }
+
+ auto pChannelHandleFactory = std::make_shared();
+
+ emit initializationProgressUpdate(20, tr("effects"));
+ m_pEffectsManager = std::make_shared(this, pConfig, pChannelHandleFactory);
+
+ m_pEngine = std::make_shared(
+ pConfig,
+ "[Master]",
+ m_pEffectsManager.get(),
+ pChannelHandleFactory,
+ true);
+
+ // Create effect backends. We do this after creating EngineMaster to allow
+ // effect backends to refer to controls that are produced by the engine.
+ BuiltInBackend* pBuiltInBackend = new BuiltInBackend(m_pEffectsManager.get());
+ m_pEffectsManager->addEffectsBackend(pBuiltInBackend);
+#ifdef __LILV__
+ m_pLV2Backend = new LV2Backend(m_pEffectsManager.get());
+ // EffectsManager takes ownership
+ m_pEffectsManager->addEffectsBackend(m_pLV2Backend);
+#else
+ m_pLV2Backend = nullptr;
+#endif
+
+ m_pEffectsManager->setup();
+
+ emit initializationProgressUpdate(30, tr("audio interface"));
+ // Although m_pSoundManager is created here, m_pSoundManager->setupDevices()
+ // needs to be called after m_pPlayerManager registers sound IO for each EngineChannel.
+ m_pSoundManager = std::make_shared(pConfig, m_pEngine.get());
+ m_pEngine->registerNonEngineChannelSoundIO(m_pSoundManager.get());
+
+ m_pRecordingManager = std::make_shared(pConfig, m_pEngine.get());
+
+#ifdef __BROADCAST__
+ m_pBroadcastManager = std::make_shared(
+ m_pSettingsManager.get(),
+ m_pSoundManager.get());
+#endif
+
+#ifdef __VINYLCONTROL__
+ m_pVCManager = std::make_shared(this, pConfig, m_pSoundManager.get());
+#else
+ m_pVCManager = nullptr;
+#endif
+
+ emit initializationProgressUpdate(40, tr("decks"));
+ // Create the player manager. (long)
+ m_pPlayerManager = std::make_shared(
+ pConfig,
+ m_pSoundManager.get(),
+ m_pEffectsManager.get(),
+ m_pEngine.get());
+ // TODO: connect input not configured error dialog slots
+ PlayerInfo::create();
+
+ for (int i = 0; i < kMicrophoneCount; ++i) {
+ m_pPlayerManager->addMicrophone();
+ }
+
+ for (int i = 0; i < kAuxiliaryCount; ++i) {
+ m_pPlayerManager->addAuxiliary();
+ }
+
+ m_pPlayerManager->addConfiguredDecks();
+ m_pPlayerManager->addSampler();
+ m_pPlayerManager->addSampler();
+ m_pPlayerManager->addSampler();
+ m_pPlayerManager->addSampler();
+ m_pPlayerManager->addPreviewDeck();
+
+ m_pEffectsManager->loadEffectChains();
+
+#ifdef __VINYLCONTROL__
+ m_pVCManager->init();
+#endif
+
+ emit initializationProgressUpdate(50, tr("library"));
+ CoverArtCache::createInstance();
+
+ m_pTrackCollectionManager = std::make_shared(
+ this,
+ pConfig,
+ m_pDbConnectionPool);
+
+ m_pLibrary = std::make_shared(
+ this,
+ pConfig,
+ m_pDbConnectionPool,
+ m_pTrackCollectionManager.get(),
+ m_pPlayerManager.get(),
+ m_pRecordingManager.get());
+
+ // Binding the PlayManager to the Library may already trigger
+ // loading of tracks which requires that the GlobalTrackCache has
+ // been created. Otherwise Mixxx might hang when accessing
+ // the uninitialized singleton instance!
+ m_pPlayerManager->bindToLibrary(m_pLibrary.get());
+
+ bool hasChanged_MusicDir = false;
+
+ QStringList dirs = m_pLibrary->getDirs();
+ if (dirs.size() < 1) {
+ // TODO(XXX) this needs to be smarter, we can't distinguish between an empty
+ // path return value (not sure if this is normally possible, but it is
+ // possible with the Windows 7 "Music" library, which is what
+ // QStandardPaths::writableLocation(QStandardPaths::MusicLocation)
+ // resolves to) and a user hitting 'cancel'. If we get a blank return
+ // but the user didn't hit cancel, we need to know this and let the
+ // user take some course of action -- bkgood
+ QString fd = QFileDialog::getExistingDirectory(nullptr,
+ tr("Choose music library directory"),
+ QStandardPaths::writableLocation(
+ QStandardPaths::MusicLocation));
+ if (!fd.isEmpty()) {
+ // adds Folder to database.
+ m_pLibrary->slotRequestAddDir(fd);
+ hasChanged_MusicDir = true;
+ }
+ }
+
+ emit initializationProgressUpdate(60, tr("controllers"));
+ // Initialize controller sub-system,
+ // but do not set up controllers until the end of the application startup
+ // (long)
+ qDebug() << "Creating ControllerManager";
+ m_pControllerManager = std::make_shared(pConfig);
+
+ // Inhibit the screensaver if the option is set. (Do it before creating the preferences dialog)
+ int inhibit = pConfig->getValue(ConfigKey("[Config]", "InhibitScreensaver"), -1);
+ if (inhibit == -1) {
+ inhibit = static_cast(mixxx::ScreenSaverPreference::PREVENT_ON);
+ pConfig->setValue(ConfigKey("[Config]", "InhibitScreensaver"), inhibit);
+ }
+ m_inhibitScreensaver = static_cast(inhibit);
+ if (m_inhibitScreensaver == mixxx::ScreenSaverPreference::PREVENT_ON) {
+ mixxx::ScreenSaverHelper::inhibit();
+ }
+
+ // Wait until all other ControlObjects are set up before initializing
+ // controllers
+ m_pControllerManager->setUpDevices();
+
+ // Scan the library for new files and directories
+ bool rescan = pConfig->getValue(
+ ConfigKey("[Library]", "RescanOnStartup"));
+ // rescan the library if we get a new plugin
+ QList prev_plugins_list =
+ pConfig->getValueString(
+ ConfigKey("[Library]", "SupportedFileExtensions"))
+ .split(',',
+#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
+ Qt::SkipEmptyParts);
+#else
+ QString::SkipEmptyParts);
+#endif
+
+ // TODO: QSet::fromList(const QList&) is deprecated and should be
+ // replaced with QSet(list.begin(), list.end()).
+ // However, the proposed alternative has just been introduced in Qt
+ // 5.14. Until the minimum required Qt version of Mixxx is increased,
+ // we need a version check here
+ QSet prev_plugins =
+#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
+ QSet(prev_plugins_list.begin(), prev_plugins_list.end());
+#else
+ QSet::fromList(prev_plugins_list);
+#endif
+
+ const QList curr_plugins_list = SoundSourceProxy::getSupportedFileExtensions();
+ QSet curr_plugins =
+#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
+ QSet(curr_plugins_list.begin(), curr_plugins_list.end());
+#else
+ QSet::fromList(curr_plugins_list);
+#endif
+
+ rescan = rescan || (prev_plugins != curr_plugins);
+ pConfig->set(ConfigKey("[Library]", "SupportedFileExtensions"), curr_plugins_list.join(","));
+
+ // Scan the library directory. Do this after the skinloader has
+ // loaded a skin, see Bug #1047435
+ if (rescan || hasChanged_MusicDir || m_pSettingsManager->shouldRescanLibrary()) {
+ m_pTrackCollectionManager->startLibraryScan();
+ }
+
+ // This has to be done before m_pSoundManager->setupDevices()
+ // https://bugs.launchpad.net/mixxx/+bug/1758189
+ m_pPlayerManager->loadSamplers();
+
+ // Load tracks in args.qlMusicFiles (command line arguments) into player
+ // 1 and 2:
+ const QList& musicFiles = m_cmdlineArgs.getMusicFiles();
+ for (int i = 0; i < (int)m_pPlayerManager->numDecks() && i < musicFiles.count(); ++i) {
+ if (SoundSourceProxy::isFileNameSupported(musicFiles.at(i))) {
+ m_pPlayerManager->slotLoadToDeck(musicFiles.at(i), i + 1);
+ }
+ }
+}
+
+void CoreServices::initializeKeyboard() {
+ UserSettingsPointer pConfig = m_pSettingsManager->settings();
+ QString resourcePath = pConfig->getResourcePath();
+
+ // Set the default value in settings file
+ if (pConfig->getValueString(ConfigKey("[Keyboard]", "Enabled")).length() == 0)
+ pConfig->set(ConfigKey("[Keyboard]", "Enabled"), ConfigValue(1));
+
+ // Read keyboard configuration and set kdbConfig object in WWidget
+ // Check first in user's Mixxx directory
+ QString userKeyboard = QDir(pConfig->getSettingsPath()).filePath("Custom.kbd.cfg");
+
+ // Empty keyboard configuration
+ m_pKbdConfigEmpty = std::make_shared>(QString());
+
+ if (QFile::exists(userKeyboard)) {
+ qDebug() << "Found and will use custom keyboard preset" << userKeyboard;
+ m_pKbdConfig = std::make_shared>(userKeyboard);
+ } else {
+ // Default to the locale for the main input method (e.g. keyboard).
+ QLocale locale = inputLocale();
+
+ // check if a default keyboard exists
+ QString defaultKeyboard = QString(resourcePath).append("keyboard/");
+ defaultKeyboard += locale.name();
+ defaultKeyboard += ".kbd.cfg";
+ qDebug() << "Found and will use default keyboard preset" << defaultKeyboard;
+
+ if (!QFile::exists(defaultKeyboard)) {
+ qDebug() << defaultKeyboard << " not found, using en_US.kbd.cfg";
+ defaultKeyboard = QString(resourcePath).append("keyboard/").append("en_US.kbd.cfg");
+ if (!QFile::exists(defaultKeyboard)) {
+ qDebug() << defaultKeyboard << " not found, starting without shortcuts";
+ defaultKeyboard = "";
+ }
+ }
+ m_pKbdConfig = std::make_shared>(defaultKeyboard);
+ }
+
+ // TODO(XXX) leak pKbdConfig, KeyboardEventFilter owns it? Maybe roll all keyboard
+ // initialization into KeyboardEventFilter
+ // Workaround for today: KeyboardEventFilter calls delete
+ bool keyboardShortcutsEnabled = pConfig->getValue(
+ ConfigKey("[Keyboard]", "Enabled"));
+ m_pKeyboardEventFilter = std::make_shared(
+ keyboardShortcutsEnabled ? m_pKbdConfig.get() : m_pKbdConfigEmpty.get());
+}
+
+void CoreServices::slotOptionsKeyboard(bool toggle) {
+ UserSettingsPointer pConfig = m_pSettingsManager->settings();
+ if (toggle) {
+ //qDebug() << "Enable keyboard shortcuts/mappings";
+ m_pKeyboardEventFilter->setKeyboardConfig(m_pKbdConfig.get());
+ pConfig->set(ConfigKey("[Keyboard]", "Enabled"), ConfigValue(1));
+ } else {
+ //qDebug() << "Disable keyboard shortcuts/mappings";
+ m_pKeyboardEventFilter->setKeyboardConfig(m_pKbdConfigEmpty.get());
+ pConfig->set(ConfigKey("[Keyboard]", "Enabled"), ConfigValue(0));
+ }
+}
+
+bool CoreServices::initializeDatabase() {
+ kLogger.info() << "Connecting to database";
+ QSqlDatabase dbConnection = mixxx::DbConnectionPooled(m_pDbConnectionPool);
+ if (!dbConnection.isOpen()) {
+ QMessageBox::critical(0,
+ tr("Cannot open database"),
+ tr("Unable to establish a database connection.\n"
+ "Mixxx requires QT with SQLite support. Please read "
+ "the Qt SQL driver documentation for information on how "
+ "to build it.\n\n"
+ "Click OK to exit."),
+ QMessageBox::Ok);
+ return false;
+ }
+
+ kLogger.info() << "Initializing or upgrading database schema";
+ return MixxxDb::initDatabaseSchema(dbConnection);
+}
+
+void CoreServices::shutdown() {
+ Timer t("CoreServices::shutdown");
+ t.start();
+
+ if (m_inhibitScreensaver != mixxx::ScreenSaverPreference::PREVENT_OFF) {
+ mixxx::ScreenSaverHelper::uninhibit();
+ }
+
+ // Stop all pending library operations
+ qDebug() << t.elapsed(false).debugMillisWithUnit() << "stopping pending Library tasks";
+ m_pTrackCollectionManager->stopLibraryScan();
+ m_pLibrary->stopPendingTasks();
+
+ qDebug() << t.elapsed(false).debugMillisWithUnit() << "saving configuration";
+ m_pSettingsManager->save();
+
+ // SoundManager depend on Engine and Config
+ qDebug() << t.elapsed(false).debugMillisWithUnit() << "deleting SoundManager";
+ CLEAR_AND_CHECK_DELETED(m_pSoundManager);
+
+ // ControllerManager depends on Config
+ qDebug() << t.elapsed(false).debugMillisWithUnit() << "deleting ControllerManager";
+ CLEAR_AND_CHECK_DELETED(m_pControllerManager);
+
+#ifdef __VINYLCONTROL__
+ // VinylControlManager depends on a CO the engine owns
+ // (vinylcontrol_enabled in VinylControlControl)
+ qDebug() << t.elapsed(false).debugMillisWithUnit() << "deleting VinylControlManager";
+ CLEAR_AND_CHECK_DELETED(m_pVCManager);
+#endif
+
+ // CoverArtCache is fairly independent of everything else.
+ CoverArtCache::destroy();
+
+ // PlayerManager depends on Engine, SoundManager, VinylControlManager, and Config
+ // The player manager has to be deleted before the library to ensure
+ // that all modified track metadata of loaded tracks is saved.
+ qDebug() << t.elapsed(false).debugMillisWithUnit() << "deleting PlayerManager";
+ CLEAR_AND_CHECK_DELETED(m_pPlayerManager);
+
+ // Destroy PlayerInfo explicitly to release the track
+ // pointers of tracks that were still loaded in decks
+ // or samplers when PlayerManager was destroyed!
+ PlayerInfo::destroy();
+
+ // Delete the library after the view so there are no dangling pointers to
+ // the data models.
+ // Depends on RecordingManager and PlayerManager
+ qDebug() << t.elapsed(false).debugMillisWithUnit() << "deleting Library";
+ CLEAR_AND_CHECK_DELETED(m_pLibrary);
+
+ // RecordingManager depends on config, engine
+ qDebug() << t.elapsed(false).debugMillisWithUnit() << "deleting RecordingManager";
+ CLEAR_AND_CHECK_DELETED(m_pRecordingManager);
+
+#ifdef __BROADCAST__
+ // BroadcastManager depends on config, engine
+ qDebug() << t.elapsed(false).debugMillisWithUnit() << "deleting BroadcastManager";
+ CLEAR_AND_CHECK_DELETED(m_pBroadcastManager);
+#endif
+
+ // EngineMaster depends on Config and m_pEffectsManager.
+ qDebug() << t.elapsed(false).debugMillisWithUnit() << "deleting EngineMaster";
+ CLEAR_AND_CHECK_DELETED(m_pEngine);
+
+ qDebug() << t.elapsed(false).debugMillisWithUnit() << "deleting EffectsManager";
+ CLEAR_AND_CHECK_DELETED(m_pEffectsManager);
+
+ // Delete the track collections after all internal track pointers
+ // in other components have been released by deleting those components
+ // beforehand!
+ qDebug() << t.elapsed(false).debugMillisWithUnit() << "detaching all track collections";
+ CLEAR_AND_CHECK_DELETED(m_pTrackCollectionManager);
+
+ qDebug() << t.elapsed(false).debugMillisWithUnit() << "closing database connection(s)";
+ m_pDbConnectionPool->destroyThreadLocalConnection();
+ m_pDbConnectionPool.reset(); // should drop the last reference
+
+ // HACK: Save config again. We saved it once before doing some dangerous
+ // stuff. We only really want to save it here, but the first one was just
+ // a precaution. The earlier one can be removed when stuff is more stable
+ // at exit.
+ m_pSettingsManager->save();
+
+ // Check for leaked ControlObjects and give warnings.
+ {
+ const QList> leakedControls =
+ ControlDoublePrivate::takeAllInstances();
+ if (!leakedControls.isEmpty()) {
+ qWarning()
+ << "The following"
+ << leakedControls.size()
+ << "controls were leaked:";
+ for (auto pCDP : leakedControls) {
+ ConfigKey key = pCDP->getKey();
+ qWarning() << key.group << key.item << pCDP->getCreatorCO();
+ // Deleting leaked objects helps to satisfy valgrind.
+ // These delete calls could cause crashes if a destructor for a control
+ // we thought was leaked is triggered after this one exits.
+ // So, only delete so if developer mode is on.
+ if (CmdlineArgs::Instance().getDeveloper()) {
+ pCDP->deleteCreatorCO();
+ }
+ }
+ DEBUG_ASSERT(!"Controls were leaked!");
+ }
+ // Finally drop all shared pointers by exiting this scope
+ }
+
+ Sandbox::shutdown();
+
+ qDebug() << t.elapsed(false).debugMillisWithUnit() << "deleting SettingsManager";
+ m_pSettingsManager.reset();
+
+ CLEAR_AND_CHECK_DELETED(m_pKeyboardEventFilter);
+ CLEAR_AND_CHECK_DELETED(m_pKbdConfig);
+ CLEAR_AND_CHECK_DELETED(m_pKbdConfigEmpty);
+
+ t.elapsed(true);
+ // Report the total time we have been running.
+ m_runtime_timer.elapsed(true);
+
+ if (m_cmdlineArgs.getDeveloper()) {
+ StatsManager::destroy();
+ }
+}
+
+} // namespace mixxx
diff --git a/src/coreservices.h b/src/coreservices.h
new file mode 100644
index 00000000000..33125edfcf7
--- /dev/null
+++ b/src/coreservices.h
@@ -0,0 +1,143 @@
+#pragma once
+
+class QApplication;
+class CmdlineArgs;
+class KeyboardEventFilter;
+class EffectsManager;
+class EngineMaster;
+class SoundManager;
+class PlayerManager;
+class RecordingManager;
+class BroadcastManager;
+class ControllerManager;
+class VinylControlManager;
+class TrackCollectionManager;
+class Library;
+class LV2Backend;
+
+#include "preferences/configobject.h"
+#include "preferences/constants.h"
+#include "preferences/settingsmanager.h"
+#include "soundio/sounddeviceerror.h"
+#include "util/cmdlineargs.h"
+#include "util/timer.h"
+
+namespace mixxx {
+
+class DbConnectionPool;
+
+class CoreServices : public QObject {
+ Q_OBJECT
+
+ public:
+ CoreServices(const CmdlineArgs& args);
+ ~CoreServices() = default;
+
+ void initializeSettings();
+ // FIXME: should be private, but WMainMenuBar needs it initialized early
+ void initializeKeyboard();
+ void initialize(QApplication* pApp);
+ void shutdown();
+
+ std::shared_ptr getKeyboardEventFilter() const {
+ return m_pKeyboardEventFilter;
+ }
+
+ std::shared_ptr> getKeyboardConfig() const {
+ return m_pKbdConfig;
+ }
+
+ std::shared_ptr getSoundManager() const {
+ return m_pSoundManager;
+ }
+
+ std::shared_ptr getPlayerManager() const {
+ return m_pPlayerManager;
+ }
+
+ std::shared_ptr getRecordingManager() const {
+ return m_pRecordingManager;
+ }
+
+ std::shared_ptr getBroadcastManager() const {
+ return m_pBroadcastManager;
+ }
+
+ std::shared_ptr getControllerManager() const {
+ return m_pControllerManager;
+ }
+
+ std::shared_ptr getVinylControlManager() const {
+ return m_pVCManager;
+ }
+
+ LV2Backend* getLV2Backend() const {
+ return m_pLV2Backend;
+ }
+
+ std::shared_ptr getEffectsManager() const {
+ return m_pEffectsManager;
+ }
+
+ std::shared_ptr getLibrary() const {
+ return m_pLibrary;
+ }
+
+ std::shared_ptr getTrackCollectionManager() const {
+ return m_pTrackCollectionManager;
+ }
+
+ std::shared_ptr getSettingsManager() const {
+ return m_pSettingsManager;
+ }
+
+ UserSettingsPointer getSettings() const {
+ return m_pSettingsManager->settings();
+ }
+
+ signals:
+ void initializationProgressUpdate(int progress, const QString& serviceName);
+
+ public slots:
+ void slotOptionsKeyboard(bool toggle);
+
+ private:
+ bool initializeDatabase();
+
+ std::shared_ptr m_pSettingsManager;
+ std::shared_ptr m_pEffectsManager;
+ // owned by EffectsManager
+ LV2Backend* m_pLV2Backend;
+ std::shared_ptr m_pEngine;
+ std::shared_ptr m_pSoundManager;
+ std::shared_ptr m_pPlayerManager;
+ std::shared_ptr m_pRecordingManager;
+#ifdef __BROADCAST__
+ std::shared_ptr m_pBroadcastManager;
+#endif
+ std::shared_ptr m_pControllerManager;
+
+ std::shared_ptr m_pVCManager;
+
+ std::shared_ptr m_pDbConnectionPool;
+ std::shared_ptr m_pTrackCollectionManager;
+ std::shared_ptr m_pLibrary;
+
+ std::shared_ptr m_pKeyboardEventFilter;
+ std::shared_ptr> m_pKbdConfig;
+ std::shared_ptr> m_pKbdConfigEmpty;
+
+ TooltipsPreference m_toolTipsCfg;
+
+ Timer m_runtime_timer;
+ const CmdlineArgs& m_cmdlineArgs;
+
+ ScreenSaverPreference m_inhibitScreensaver;
+
+ QSet m_skinCreatedControls;
+
+ static const int kMicrophoneCount;
+ static const int kAuxiliaryCount;
+};
+
+} // namespace mixxx
diff --git a/src/main.cpp b/src/main.cpp
index 4cf913ed125..12aa7f1e0eb 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -1,15 +1,16 @@
-#include
-#include
-#include
#include
-#include
+#include
#include
+#include
#include
+#include
+#include
+#include "coreservices.h"
+#include "errordialoghandler.h"
#include "mixxx.h"
#include "mixxxapplication.h"
#include "sources/soundsourceproxy.h"
-#include "errordialoghandler.h"
#include "util/cmdlineargs.h"
#include "util/console.h"
#include "util/logging.h"
@@ -26,11 +27,11 @@ constexpr int kFatalErrorOnStartupExitCode = 1;
constexpr int kParseCmdlineArgsErrorExitCode = 2;
int runMixxx(MixxxApplication* app, const CmdlineArgs& args) {
- MixxxMainWindow mainWindow(app, args);
+ auto coreServices = std::make_shared(args);
+ MixxxMainWindow mainWindow(app, coreServices);
// If startup produced a fatal error, then don't even start the
// Qt event loop.
if (ErrorDialogHandler::instance()->checkError()) {
- mainWindow.finalize();
return kFatalErrorOnStartupExitCode;
} else {
qDebug() << "Displaying main window";
diff --git a/src/mixer/basetrackplayer.cpp b/src/mixer/basetrackplayer.cpp
index 92e43b53ebb..9b336d9b161 100644
--- a/src/mixer/basetrackplayer.cpp
+++ b/src/mixer/basetrackplayer.cpp
@@ -40,7 +40,6 @@ BaseTrackPlayerImpl::BaseTrackPlayerImpl(
UserSettingsPointer pConfig,
EngineMaster* pMixingEngine,
EffectsManager* pEffectsManager,
- VisualsManager* pVisualsManager,
EngineChannel::ChannelOrientation defaultOrientation,
const ChannelHandleAndGroup& handleGroup,
bool defaultMaster,
@@ -193,8 +192,6 @@ BaseTrackPlayerImpl::BaseTrackPlayerImpl(
m_pRateRatio = make_parented(getGroup(), "rate_ratio", this);
m_pPitchAdjust = make_parented(getGroup(), "pitch_adjust", this);
-
- pVisualsManager->addDeck(getGroup());
}
BaseTrackPlayerImpl::~BaseTrackPlayerImpl() {
diff --git a/src/mixer/basetrackplayer.h b/src/mixer/basetrackplayer.h
index 8e6186d99f2..87bceec0b74 100644
--- a/src/mixer/basetrackplayer.h
+++ b/src/mixer/basetrackplayer.h
@@ -57,7 +57,6 @@ class BaseTrackPlayerImpl : public BaseTrackPlayer {
UserSettingsPointer pConfig,
EngineMaster* pMixingEngine,
EffectsManager* pEffectsManager,
- VisualsManager* pVisualsManager,
EngineChannel::ChannelOrientation defaultOrientation,
const ChannelHandleAndGroup& handleGroup,
bool defaultMaster,
diff --git a/src/mixer/deck.cpp b/src/mixer/deck.cpp
index 06be4a5bbf1..b3a1effe9c8 100644
--- a/src/mixer/deck.cpp
+++ b/src/mixer/deck.cpp
@@ -6,14 +6,12 @@ Deck::Deck(QObject* pParent,
UserSettingsPointer pConfig,
EngineMaster* pMixingEngine,
EffectsManager* pEffectsManager,
- VisualsManager* pVisualsManager,
EngineChannel::ChannelOrientation defaultOrientation,
const ChannelHandleAndGroup& handleGroup)
: BaseTrackPlayerImpl(pParent,
pConfig,
pMixingEngine,
pEffectsManager,
- pVisualsManager,
defaultOrientation,
handleGroup,
/*defaultMaster*/ true,
diff --git a/src/mixer/deck.h b/src/mixer/deck.h
index f53dcd3893c..f6c47a1ebb3 100644
--- a/src/mixer/deck.h
+++ b/src/mixer/deck.h
@@ -11,7 +11,6 @@ class Deck : public BaseTrackPlayerImpl {
UserSettingsPointer pConfig,
EngineMaster* pMixingEngine,
EffectsManager* pEffectsManager,
- VisualsManager* pVisualsManager,
EngineChannel::ChannelOrientation defaultOrientation,
const ChannelHandleAndGroup& handleGroup);
~Deck() override = default;
diff --git a/src/mixer/playermanager.cpp b/src/mixer/playermanager.cpp
index 75bb78ca42f..f608c544059 100644
--- a/src/mixer/playermanager.cpp
+++ b/src/mixer/playermanager.cpp
@@ -42,13 +42,11 @@ QAtomicPointer PlayerManager::m_pCOPNumPreviewDecks;
PlayerManager::PlayerManager(UserSettingsPointer pConfig,
SoundManager* pSoundManager,
EffectsManager* pEffectsManager,
- VisualsManager* pVisualsManager,
EngineMaster* pEngine)
: m_mutex(QMutex::Recursive),
m_pConfig(pConfig),
m_pSoundManager(pSoundManager),
m_pEffectsManager(pEffectsManager),
- m_pVisualsManager(pVisualsManager),
m_pEngine(pEngine),
// NOTE(XXX) LegacySkinParser relies on these controls being Controls
// and not ControlProxies.
@@ -157,6 +155,20 @@ void PlayerManager::bindToLibrary(Library* pLibrary) {
}
}
+QStringList PlayerManager::getVisualPlayerGroups() {
+ QStringList groups;
+ for (const auto& pDeck : std::as_const(m_decks)) {
+ groups.append(pDeck->getGroup());
+ }
+ for (const auto& pPreview : std::as_const(m_previewDecks)) {
+ groups.append(pPreview->getGroup());
+ }
+ for (const auto& pSampler : std::as_const(m_samplers)) {
+ groups.append(pSampler->getGroup());
+ }
+ return groups;
+}
+
// static
bool PlayerManager::isDeckGroup(const QString& group, int* number) {
if (!group.startsWith("[Channel")) {
@@ -374,7 +386,6 @@ void PlayerManager::addDeckInner() {
m_pConfig,
m_pEngine,
m_pEffectsManager,
- m_pVisualsManager,
deckIndex % 2 == 1 ? EngineChannel::RIGHT : EngineChannel::LEFT,
handleGroup);
connect(pDeck->getEngineDeck(),
@@ -452,7 +463,6 @@ void PlayerManager::addSamplerInner() {
m_pConfig,
m_pEngine,
m_pEffectsManager,
- m_pVisualsManager,
orientation,
handleGroup);
if (m_pTrackAnalysisScheduler) {
@@ -486,7 +496,6 @@ void PlayerManager::addPreviewDeckInner() {
m_pConfig,
m_pEngine,
m_pEffectsManager,
- m_pVisualsManager,
orientation,
handleGroup);
if (m_pTrackAnalysisScheduler) {
diff --git a/src/mixer/playermanager.h b/src/mixer/playermanager.h
index eaab5d5c128..2a6ddce2c4c 100644
--- a/src/mixer/playermanager.h
+++ b/src/mixer/playermanager.h
@@ -58,7 +58,6 @@ class PlayerManager : public QObject, public PlayerManagerInterface {
PlayerManager(UserSettingsPointer pConfig,
SoundManager* pSoundManager,
EffectsManager* pEffectsManager,
- VisualsManager* pVisualsManager,
EngineMaster* pEngine);
~PlayerManager() override;
@@ -135,6 +134,8 @@ class PlayerManager : public QObject, public PlayerManagerInterface {
// must exist at least for the lifetime of this instance.
void bindToLibrary(Library* pLibrary);
+ QStringList getVisualPlayerGroups();
+
// Returns the group for the ith sampler where i is zero indexed
static QString groupForSampler(int i) {
DEBUG_ASSERT(i >= 0);
@@ -258,7 +259,6 @@ class PlayerManager : public QObject, public PlayerManagerInterface {
UserSettingsPointer m_pConfig;
SoundManager* m_pSoundManager;
EffectsManager* m_pEffectsManager;
- VisualsManager* m_pVisualsManager;
EngineMaster* m_pEngine;
SamplerBank* m_pSamplerBank;
ControlObject* m_pCONumDecks;
diff --git a/src/mixer/previewdeck.cpp b/src/mixer/previewdeck.cpp
index dee63bfb584..cd44e0aa1f6 100644
--- a/src/mixer/previewdeck.cpp
+++ b/src/mixer/previewdeck.cpp
@@ -6,14 +6,12 @@ PreviewDeck::PreviewDeck(QObject* pParent,
UserSettingsPointer pConfig,
EngineMaster* pMixingEngine,
EffectsManager* pEffectsManager,
- VisualsManager* pVisualsManager,
EngineChannel::ChannelOrientation defaultOrientation,
const ChannelHandleAndGroup& handleGroup)
: BaseTrackPlayerImpl(pParent,
pConfig,
pMixingEngine,
pEffectsManager,
- pVisualsManager,
defaultOrientation,
handleGroup,
/*defaultMaster*/ false,
diff --git a/src/mixer/previewdeck.h b/src/mixer/previewdeck.h
index 2da64603c49..ceca7f6ae2d 100644
--- a/src/mixer/previewdeck.h
+++ b/src/mixer/previewdeck.h
@@ -9,7 +9,6 @@ class PreviewDeck : public BaseTrackPlayerImpl {
UserSettingsPointer pConfig,
EngineMaster* pMixingEngine,
EffectsManager* pEffectsManager,
- VisualsManager* pVisualsManager,
EngineChannel::ChannelOrientation defaultOrientation,
const ChannelHandleAndGroup& handleGroup);
~PreviewDeck() override = default;
diff --git a/src/mixer/sampler.cpp b/src/mixer/sampler.cpp
index 1ee1aef8c6c..697fd8687d5 100644
--- a/src/mixer/sampler.cpp
+++ b/src/mixer/sampler.cpp
@@ -7,14 +7,12 @@ Sampler::Sampler(QObject* pParent,
UserSettingsPointer pConfig,
EngineMaster* pMixingEngine,
EffectsManager* pEffectsManager,
- VisualsManager* pVisualsManager,
EngineChannel::ChannelOrientation defaultOrientation,
const ChannelHandleAndGroup& handleGroup)
: BaseTrackPlayerImpl(pParent,
pConfig,
pMixingEngine,
pEffectsManager,
- pVisualsManager,
defaultOrientation,
handleGroup,
/*defaultMaster*/ true,
diff --git a/src/mixer/sampler.h b/src/mixer/sampler.h
index f17cbc4ccab..213b2063798 100644
--- a/src/mixer/sampler.h
+++ b/src/mixer/sampler.h
@@ -9,7 +9,6 @@ class Sampler : public BaseTrackPlayerImpl {
UserSettingsPointer pConfig,
EngineMaster* pMixingEngine,
EffectsManager* pEffectsManager,
- VisualsManager* pVisualsManager,
EngineChannel::ChannelOrientation defaultOrientation,
const ChannelHandleAndGroup& handleGroup);
~Sampler() override = default;
diff --git a/src/mixxx.cpp b/src/mixxx.cpp
index 3add3279d9f..8b56ac1d5a2 100644
--- a/src/mixxx.cpp
+++ b/src/mixxx.cpp
@@ -82,116 +82,23 @@
#undef min
#endif
-namespace {
-
-const mixxx::Logger kLogger("MixxxMainWindow");
-
-// hack around https://gitlab.freedesktop.org/xorg/lib/libx11/issues/25
-// https://bugs.launchpad.net/mixxx/+bug/1805559
-#if defined(Q_OS_LINUX)
-typedef Bool (*WireToErrorType)(Display*, XErrorEvent*, xError*);
-
-const int NUM_HANDLERS = 256;
-WireToErrorType __oldHandlers[NUM_HANDLERS] = {0};
-
-Bool __xErrorHandler(Display* display, XErrorEvent* event, xError* error) {
- // Call any previous handler first in case it needs to do real work.
- auto code = static_cast(event->error_code);
- if (__oldHandlers[code] != NULL) {
- __oldHandlers[code](display, event, error);
- }
-
- // Always return false so the error does not get passed to the normal
- // application defined handler.
- return False;
-}
-
-#endif
-
-inline QLocale inputLocale() {
- // Use the default config for local keyboard
- QInputMethod* pInputMethod = QGuiApplication::inputMethod();
- return pInputMethod ? pInputMethod->locale() :
- QLocale(QLocale::English);
-}
-
-} // anonymous namespace
-
-// static
-const int MixxxMainWindow::kMicrophoneCount = 4;
-// static
-const int MixxxMainWindow::kAuxiliaryCount = 4;
-
-MixxxMainWindow::MixxxMainWindow(QApplication* pApp, const CmdlineArgs& args)
- : m_pCentralWidget(nullptr),
+MixxxMainWindow::MixxxMainWindow(
+ QApplication* pApp, std::shared_ptr pCoreServices)
+ : m_pCoreServices(pCoreServices),
+ m_pCentralWidget(nullptr),
m_pLaunchImage(nullptr),
- m_pEffectsManager(nullptr),
- m_pEngine(nullptr),
- m_pSkinLoader(nullptr),
- m_pSoundManager(nullptr),
- m_pPlayerManager(nullptr),
- m_pRecordingManager(nullptr),
-#ifdef __BROADCAST__
- m_pBroadcastManager(nullptr),
-#endif
- m_pControllerManager(nullptr),
m_pGuiTick(nullptr),
-#ifdef __VINYLCONTROL__
- m_pVCManager(nullptr),
-#endif
- m_pKeyboard(nullptr),
- m_pLibrary(nullptr),
m_pDeveloperToolsDlg(nullptr),
- m_pPrefDlg(nullptr),
- m_pKbdConfig(nullptr),
- m_pKbdConfigEmpty(nullptr),
m_toolTipsCfg(mixxx::TooltipsPreference::TOOLTIPS_ON),
- m_runtime_timer("MixxxMainWindow::runtime"),
- m_cmdLineArgs(args),
m_pTouchShift(nullptr) {
- m_runtime_timer.start();
- mixxx::Time::start();
-
- QString settingsPath = args.getSettingsPath();
-#ifdef __APPLE__
- if (!args.getSettingsPathSet()) {
- settingsPath = Sandbox::migrateOldSettings();
- }
-#endif
-
- mixxx::Logging::initialize(
- settingsPath,
- args.getLogLevel(),
- args.getLogFlushLevel(),
- args.getDebugAssertBreak());
-
- VERIFY_OR_DEBUG_ASSERT(SoundSourceProxy::registerProviders()) {
- qCritical() << "Failed to register any SoundSource providers";
- return;
- }
-
- Version::logBuildDetails();
-
- // Only record stats in developer mode.
- if (m_cmdLineArgs.getDeveloper()) {
- StatsManager::createInstance();
- }
-
- m_pSettingsManager = std::make_unique(args.getSettingsPath());
-
- initializeKeyboard();
- installEventFilter(m_pKeyboard);
-
- // Menubar depends on translations.
- mixxx::Translations::initializeTranslations(
- m_pSettingsManager->settings(), pApp, args.getLocale());
-
+ m_pCoreServices->initializeSettings();
+ m_pCoreServices->initializeKeyboard();
+ // These depend on the settings
createMenuBar();
-
initializeWindow();
- // First load launch image to show a the user a quick responds
- m_pSkinLoader = new SkinLoader(m_pSettingsManager->settings());
+ // Show launch image immediately so the user knows Mixxx is starting
+ m_pSkinLoader = std::make_unique(m_pCoreServices->getSettings());
m_pLaunchImage = m_pSkinLoader->loadLaunchImage(this);
m_pCentralWidget = (QWidget*)m_pLaunchImage;
setCentralWidget(m_pCentralWidget);
@@ -199,221 +106,24 @@ MixxxMainWindow::MixxxMainWindow(QApplication* pApp, const CmdlineArgs& args)
show();
pApp->processEvents();
- initialize(pApp, args);
-}
-
-MixxxMainWindow::~MixxxMainWindow() {
- finalize();
- // SkinLoader depends on Config;
- delete m_pSkinLoader;
-}
-
-void MixxxMainWindow::initialize(QApplication* pApp, const CmdlineArgs& args) {
- ScopedTimer t("MixxxMainWindow::initialize");
-
-#if defined(Q_OS_LINUX)
- // XESetWireToError will segfault if running as a Wayland client
- if (pApp->platformName() == QLatin1String("xcb")) {
- for (auto i = 0; i < NUM_HANDLERS; ++i) {
- XESetWireToError(QX11Info::display(), i, &__xErrorHandler);
- }
- }
-#endif
-
- UserSettingsPointer pConfig = m_pSettingsManager->settings();
-
- Sandbox::initialize(QDir(pConfig->getSettingsPath()).filePath("sandbox.cfg"));
-
- QString resourcePath = pConfig->getResourcePath();
-
- FontUtils::initializeFonts(resourcePath); // takes a long time
-
- launchProgress(2);
-
- // Set the visibility of tooltips, default "1" = ON
- m_toolTipsCfg = static_cast(
- pConfig->getValue(ConfigKey("[Controls]", "Tooltips"),
- static_cast(mixxx::TooltipsPreference::TOOLTIPS_ON)));
-
- m_pTouchShift = new ControlPushButton(ConfigKey("[Controls]", "touch_shift"));
-
- m_pDbConnectionPool = MixxxDb(pConfig).connectionPool();
- if (!m_pDbConnectionPool) {
- // TODO(XXX) something a little more elegant
- exit(-1);
- }
- // Create a connection for the main thread
- m_pDbConnectionPool->createThreadLocalConnection();
- if (!initializeDatabase()) {
- // TODO(XXX) something a little more elegant
- exit(-1);
- }
-
- auto pChannelHandleFactory = std::make_shared();
-
- // Create the Effects subsystem.
- m_pEffectsManager = new EffectsManager(this, pConfig, pChannelHandleFactory);
-
- // Starting the master (mixing of the channels and effects):
- m_pEngine = new EngineMaster(
- pConfig,
- "[Master]",
- m_pEffectsManager,
- pChannelHandleFactory,
- true);
-
- // Create effect backends. We do this after creating EngineMaster to allow
- // effect backends to refer to controls that are produced by the engine.
- BuiltInBackend* pBuiltInBackend = new BuiltInBackend(m_pEffectsManager);
- m_pEffectsManager->addEffectsBackend(pBuiltInBackend);
-#ifdef __LILV__
- LV2Backend* pLV2Backend = new LV2Backend(m_pEffectsManager);
- m_pEffectsManager->addEffectsBackend(pLV2Backend);
-#else
- LV2Backend* pLV2Backend = nullptr;
-#endif
-
- // Sets up the EffectChains and EffectRacks (long)
- m_pEffectsManager->setup();
-
- launchProgress(8);
+ connect(
+ m_pCoreServices.get(),
+ &mixxx::CoreServices::initializationProgressUpdate,
+ this,
+ &MixxxMainWindow::initializationProgressUpdate);
- // Although m_pSoundManager is created here, m_pSoundManager->setupDevices()
- // needs to be called after m_pPlayerManager registers sound IO for each EngineChannel.
- m_pSoundManager = new SoundManager(pConfig, m_pEngine);
- m_pEngine->registerNonEngineChannelSoundIO(m_pSoundManager);
+ m_pCoreServices->initialize(pApp);
- m_pRecordingManager = new RecordingManager(pConfig, m_pEngine);
+ initializationProgressUpdate(65, tr("skin"));
-#ifdef __BROADCAST__
- m_pBroadcastManager = new BroadcastManager(
- m_pSettingsManager.get(),
- m_pSoundManager);
-#endif
+ installEventFilter(m_pCoreServices->getKeyboardEventFilter().get());
- launchProgress(11);
-
- // Needs to be created before CueControl (decks) and WTrackTableView.
m_pGuiTick = new GuiTick();
m_pVisualsManager = new VisualsManager();
-
-#ifdef __VINYLCONTROL__
- m_pVCManager = new VinylControlManager(this, pConfig, m_pSoundManager);
-#else
- m_pVCManager = NULL;
-#endif
-
- // Create the player manager. (long)
- m_pPlayerManager = new PlayerManager(pConfig, m_pSoundManager,
- m_pEffectsManager, m_pVisualsManager, m_pEngine);
- connect(m_pPlayerManager,
- &PlayerManager::noMicrophoneInputConfigured,
- this,
- &MixxxMainWindow::slotNoMicrophoneInputConfigured);
- connect(m_pPlayerManager,
- &PlayerManager::noAuxiliaryInputConfigured,
- this,
- &MixxxMainWindow::slotNoAuxiliaryInputConfigured);
- connect(m_pPlayerManager,
- &PlayerManager::noDeckPassthroughInputConfigured,
- this,
- &MixxxMainWindow::slotNoDeckPassthroughInputConfigured);
- connect(m_pPlayerManager,
- &PlayerManager::noVinylControlInputConfigured,
- this,
- &MixxxMainWindow::slotNoVinylControlInputConfigured);
- PlayerInfo::create();
-
- for (int i = 0; i < kMicrophoneCount; ++i) {
- m_pPlayerManager->addMicrophone();
- }
-
- for (int i = 0; i < kAuxiliaryCount; ++i) {
- m_pPlayerManager->addAuxiliary();
+ for (const auto& group : m_pCoreServices->getPlayerManager()->getVisualPlayerGroups()) {
+ m_pVisualsManager->addDeck(group);
}
- m_pPlayerManager->addConfiguredDecks();
- m_pPlayerManager->addSampler();
- m_pPlayerManager->addSampler();
- m_pPlayerManager->addSampler();
- m_pPlayerManager->addSampler();
- m_pPlayerManager->addPreviewDeck();
-
- launchProgress(30);
-
- m_pEffectsManager->loadEffectChains();
-
-#ifdef __VINYLCONTROL__
- m_pVCManager->init();
-#endif
-
-#ifdef __MODPLUG__
- // restore the configuration for the modplug library before trying to load a module
- DlgPrefModplug* pModplugPrefs = new DlgPrefModplug(0, pConfig);
- pModplugPrefs->loadSettings();
- pModplugPrefs->applySettings();
- delete pModplugPrefs; // not needed anymore
-#endif
-
- CoverArtCache::createInstance();
-
- launchProgress(30);
-
- m_pTrackCollectionManager = new TrackCollectionManager(
- this,
- pConfig,
- m_pDbConnectionPool);
-
- launchProgress(35);
-
- m_pLibrary = new Library(
- this,
- pConfig,
- m_pDbConnectionPool,
- m_pTrackCollectionManager,
- m_pPlayerManager,
- m_pRecordingManager);
-
- // Binding the PlayManager to the Library may already trigger
- // loading of tracks which requires that the GlobalTrackCache has
- // been created. Otherwise Mixxx might hang when accessing
- // the uninitialized singleton instance!
- m_pPlayerManager->bindToLibrary(m_pLibrary);
-
- launchProgress(40);
-
- // Get Music dir
- bool hasChanged_MusicDir = false;
-
- QStringList dirs = m_pLibrary->getDirs();
- if (dirs.size() < 1) {
- // TODO(XXX) this needs to be smarter, we can't distinguish between an empty
- // path return value (not sure if this is normally possible, but it is
- // possible with the Windows 7 "Music" library, which is what
- // QStandardPaths::writableLocation(QStandardPaths::MusicLocation)
- // resolves to) and a user hitting 'cancel'. If we get a blank return
- // but the user didn't hit cancel, we need to know this and let the
- // user take some course of action -- bkgood
- QString fd = QFileDialog::getExistingDirectory(
- this, tr("Choose music library directory"),
- QStandardPaths::writableLocation(QStandardPaths::MusicLocation));
- if (!fd.isEmpty()) {
- // adds Folder to database.
- m_pLibrary->slotRequestAddDir(fd);
- hasChanged_MusicDir = true;
- }
- }
-
- // Call inits to invoke all other construction parts
-
- // Initialize controller sub-system,
- // but do not set up controllers until the end of the application startup
- // (long)
- qDebug() << "Creating ControllerManager";
- m_pControllerManager = new ControllerManager(pConfig);
-
- launchProgress(47);
-
// Before creating the first skin we need to create a QGLWidget so that all
// the QGLWidget's we create can use it as a shared QGLContext.
if (!CmdlineArgs::Instance().getSafeMode() && QGLFormat::hasOpenGL()) {
@@ -445,14 +155,12 @@ void MixxxMainWindow::initialize(QApplication* pApp, const CmdlineArgs& args) {
}
WaveformWidgetFactory::createInstance(); // takes a long time
- WaveformWidgetFactory::instance()->setConfig(pConfig);
+ WaveformWidgetFactory::instance()->setConfig(m_pCoreServices->getSettings());
WaveformWidgetFactory::instance()->startVSync(m_pGuiTick, m_pVisualsManager);
- launchProgress(52);
-
connect(this,
&MixxxMainWindow::skinLoaded,
- m_pLibrary,
+ m_pCoreServices->getLibrary().get(),
&Library::onSkinLoadFinished);
connect(this,
@@ -460,40 +168,23 @@ void MixxxMainWindow::initialize(QApplication* pApp, const CmdlineArgs& args) {
WaveformWidgetFactory::instance(),
&WaveformWidgetFactory::slotSkinLoaded);
- // Inhibit the screensaver if the option is set. (Do it before creating the preferences dialog)
- int inhibit = pConfig->getValue(ConfigKey("[Config]","InhibitScreensaver"),-1);
- if (inhibit == -1) {
- inhibit = static_cast(mixxx::ScreenSaverPreference::PREVENT_ON);
- pConfig->setValue(ConfigKey("[Config]","InhibitScreensaver"), inhibit);
- }
- m_inhibitScreensaver = static_cast(inhibit);
- if (m_inhibitScreensaver == mixxx::ScreenSaverPreference::PREVENT_ON) {
- mixxx::ScreenSaverHelper::inhibit();
- }
-
// Initialize preference dialog
m_pPrefDlg = new DlgPreferences(
this,
- m_pSkinLoader,
- m_pSoundManager,
- m_pPlayerManager,
- m_pControllerManager,
- m_pVCManager,
- pLV2Backend,
- m_pEffectsManager,
- m_pSettingsManager.get(),
- m_pLibrary);
+ m_pSkinLoader.get(),
+ m_pCoreServices->getSoundManager().get(),
+ m_pCoreServices->getPlayerManager().get(),
+ m_pCoreServices->getControllerManager().get(),
+ m_pCoreServices->getVinylControlManager().get(),
+ m_pCoreServices->getLV2Backend(),
+ m_pCoreServices->getEffectsManager().get(),
+ m_pCoreServices->getSettingsManager().get(),
+ m_pCoreServices->getLibrary().get());
m_pPrefDlg->setWindowIcon(QIcon(":/images/mixxx_icon.svg"));
m_pPrefDlg->setHidden(true);
- launchProgress(60);
-
- // Connect signals to the menubar. Should be done before we go fullscreen
- // and emit newSkinLoaded.
connectMenuBar();
- launchProgress(63);
-
QWidget* oldWidget = m_pCentralWidget;
// Load default styles that can be overridden by skins
@@ -516,11 +207,6 @@ void MixxxMainWindow::initialize(QApplication* pApp, const CmdlineArgs& args) {
m_pMenuBar->setStyleSheet(m_pCentralWidget->styleSheet());
}
- // Fake a 100 % progress here.
- // At a later place it will newer shown up, since it is
- // immediately replaced by the real widget.
- launchProgress(100);
-
// Check direct rendering and warn user if they don't have it
if (!CmdlineArgs::Instance().getSafeMode()) {
checkDirectRendering();
@@ -534,70 +220,18 @@ void MixxxMainWindow::initialize(QApplication* pApp, const CmdlineArgs& args) {
// If we were told to start in fullscreen mode on the command-line or if
// user chose always starts in fullscreen mode, then turn on fullscreen
// mode.
- bool fullscreenPref = pConfig->getValue(
+ bool fullscreenPref = m_pCoreServices->getSettings()->getValue(
ConfigKey("[Config]", "StartInFullscreen"));
- if (args.getStartInFullscreen() || fullscreenPref) {
+ if (CmdlineArgs::Instance().getStartInFullscreen() || fullscreenPref) {
slotViewFullScreen(true);
}
emit skinLoaded();
-
- // Wait until all other ControlObjects are set up before initializing
- // controllers
- m_pControllerManager->setUpDevices();
-
- // Scan the library for new files and directories
- bool rescan = pConfig->getValue(
- ConfigKey("[Library]","RescanOnStartup"));
- // rescan the library if we get a new plugin
- QList prev_plugins_list =
- pConfig->getValueString(
- ConfigKey("[Library]", "SupportedFileExtensions"))
- .split(',',
-#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
- Qt::SkipEmptyParts);
-#else
- QString::SkipEmptyParts);
-#endif
-
- // TODO: QSet::fromList(const QList&) is deprecated and should be
- // replaced with QSet(list.begin(), list.end()).
- // However, the proposed alternative has just been introduced in Qt
- // 5.14. Until the minimum required Qt version of Mixxx is increased,
- // we need a version check here
- QSet prev_plugins =
-#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
- QSet(prev_plugins_list.begin(), prev_plugins_list.end());
-#else
- QSet::fromList(prev_plugins_list);
-#endif
-
- const QList curr_plugins_list = SoundSourceProxy::getSupportedFileExtensions();
- QSet curr_plugins =
-#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
- QSet(curr_plugins_list.begin(), curr_plugins_list.end());
-#else
- QSet::fromList(curr_plugins_list);
-#endif
-
- rescan = rescan || (prev_plugins != curr_plugins);
- pConfig->set(ConfigKey("[Library]", "SupportedFileExtensions"), curr_plugins_list.join(","));
-
- // Scan the library directory. Do this after the skinloader has
- // loaded a skin, see Bug #1047435
- if (rescan || hasChanged_MusicDir || m_pSettingsManager->shouldRescanLibrary()) {
- m_pTrackCollectionManager->startLibraryScan();
- }
-
- // This has to be done before m_pSoundManager->setupDevices()
- // https://bugs.launchpad.net/mixxx/+bug/1758189
- m_pPlayerManager->loadSamplers();
-
// Try open player device If that fails, the preference panel is opened.
bool retryClicked;
do {
retryClicked = false;
- SoundDeviceError result = m_pSoundManager->setupDevices();
+ SoundDeviceError result = m_pCoreServices->getSoundManager()->setupDevices();
if (result == SOUNDDEVICE_ERROR_DEVICE_COUNT ||
result == SOUNDDEVICE_ERROR_EXCESSIVE_OUTPUT_CHANNEL) {
if (soundDeviceBusyDlg(&retryClicked) != QDialog::Accepted) {
@@ -616,7 +250,7 @@ void MixxxMainWindow::initialize(QApplication* pApp, const CmdlineArgs& args) {
// In case persisting errors, the user has already received a message
// box from the preferences dialog above. So we can watch here just the
// output count.
- while (m_pSoundManager->getConfig().getOutputs().count() == 0) {
+ while (m_pCoreServices->getSoundManager()->getConfig().getOutputs().count() == 0) {
// Exit when we press the Exit button in the noSoundDlg dialog
// only call it if result != OK
bool continueClicked = false;
@@ -624,61 +258,51 @@ void MixxxMainWindow::initialize(QApplication* pApp, const CmdlineArgs& args) {
exit(0);
}
if (continueClicked) break;
- }
-
- // Load tracks in args.qlMusicFiles (command line arguments) into player
- // 1 and 2:
- const QList& musicFiles = args.getMusicFiles();
- for (int i = 0; i < (int)m_pPlayerManager->numDecks()
- && i < musicFiles.count(); ++i) {
- if (SoundSourceProxy::isFileNameSupported(musicFiles.at(i))) {
- m_pPlayerManager->slotLoadToDeck(musicFiles.at(i), i+1);
- }
}
+ // this has to be after the OpenGL widgets are created or depending on a
+ // million different variables the first waveform may be horribly
+ // corrupted. See bug 521509 -- bkgood ?? -- vrince
+ setCentralWidget(m_pCentralWidget);
+ // The launch image widget is automatically disposed, but we still have a
+ // pointer to it.
+ m_pLaunchImage = nullptr;
+
+ connect(m_pCoreServices->getPlayerManager().get(),
+ &PlayerManager::noMicrophoneInputConfigured,
+ this,
+ &MixxxMainWindow::slotNoMicrophoneInputConfigured);
+ connect(m_pCoreServices->getPlayerManager().get(),
+ &PlayerManager::noAuxiliaryInputConfigured,
+ this,
+ &MixxxMainWindow::slotNoAuxiliaryInputConfigured);
+ connect(m_pCoreServices->getPlayerManager().get(),
+ &PlayerManager::noDeckPassthroughInputConfigured,
+ this,
+ &MixxxMainWindow::slotNoDeckPassthroughInputConfigured);
+ connect(m_pCoreServices->getPlayerManager().get(),
+ &PlayerManager::noVinylControlInputConfigured,
+ this,
+ &MixxxMainWindow::slotNoVinylControlInputConfigured);
+
connect(&PlayerInfo::instance(),
&PlayerInfo::currentPlayingTrackChanged,
this,
&MixxxMainWindow::slotUpdateWindowTitle);
-
connect(&PlayerInfo::instance(),
&PlayerInfo::currentPlayingDeckChanged,
this,
&MixxxMainWindow::slotChangedPlayingDeck);
-
- // this has to be after the OpenGL widgets are created or depending on a
- // million different variables the first waveform may be horribly
- // corrupted. See bug 521509 -- bkgood ?? -- vrince
- setCentralWidget(m_pCentralWidget);
- // The launch image widget is automatically disposed, but we still have a
- // pointer to it.
- m_pLaunchImage = nullptr;
}
-void MixxxMainWindow::finalize() {
- Timer t("MixxxMainWindow::~finalize");
+MixxxMainWindow::~MixxxMainWindow() {
+ Timer t("~MixxxMainWindow");
t.start();
if (m_inhibitScreensaver != mixxx::ScreenSaverPreference::PREVENT_OFF) {
mixxx::ScreenSaverHelper::uninhibit();
}
- // Stop all pending library operations
- qDebug() << t.elapsed(false).debugMillisWithUnit() << "stopping pending Library tasks";
- m_pTrackCollectionManager->stopLibraryScan();
- m_pLibrary->stopPendingTasks();
-
- // Save the current window state (position, maximized, etc)
- m_pSettingsManager->settings()->set(ConfigKey("[MainWindow]", "geometry"),
- QString(saveGeometry().toBase64()));
- m_pSettingsManager->settings()->set(ConfigKey("[MainWindow]", "state"),
- QString(saveState().toBase64()));
-
- qDebug() << "Destroying MixxxMainWindow";
-
- qDebug() << t.elapsed(false).debugMillisWithUnit() << "saving configuration";
- m_pSettingsManager->save();
-
// GUI depends on KeyboardEventFilter, PlayerManager, Library
qDebug() << t.elapsed(false).debugMillisWithUnit() << "deleting skin";
m_pCentralWidget = nullptr;
@@ -719,62 +343,9 @@ void MixxxMainWindow::finalize() {
qWarning() << "WMainMenuBar was not deleted by our sendPostedEvents trick.";
}
- // SoundManager depend on Engine and Config
- qDebug() << t.elapsed(false).debugMillisWithUnit() << "deleting SoundManager";
- delete m_pSoundManager;
-
- // ControllerManager depends on Config
- qDebug() << t.elapsed(false).debugMillisWithUnit() << "deleting ControllerManager";
- delete m_pControllerManager;
-
-#ifdef __VINYLCONTROL__
- // VinylControlManager depends on a CO the engine owns
- // (vinylcontrol_enabled in VinylControlControl)
- qDebug() << t.elapsed(false).debugMillisWithUnit() << "deleting VinylControlManager";
- delete m_pVCManager;
-#endif
-
- // CoverArtCache is fairly independent of everything else.
- CoverArtCache::destroy();
-
- // PlayerManager depends on Engine, SoundManager, VinylControlManager, and Config
- // The player manager has to be deleted before the library to ensure
- // that all modified track metadata of loaded tracks is saved.
- qDebug() << t.elapsed(false).debugMillisWithUnit() << "deleting PlayerManager";
- delete m_pPlayerManager;
-
- // Destroy PlayerInfo explicitly to release the track
- // pointers of tracks that were still loaded in decks
- // or samplers when PlayerManager was destroyed!
- PlayerInfo::destroy();
-
- // Delete the library after the view so there are no dangling pointers to
- // the data models.
- // Depends on RecordingManager and PlayerManager
- qDebug() << t.elapsed(false).debugMillisWithUnit() << "deleting Library";
- delete m_pLibrary;
-
- // RecordingManager depends on config, engine
- qDebug() << t.elapsed(false).debugMillisWithUnit() << "deleting RecordingManager";
- delete m_pRecordingManager;
-
-#ifdef __BROADCAST__
- // BroadcastManager depends on config, engine
- qDebug() << t.elapsed(false).debugMillisWithUnit() << "deleting BroadcastManager";
- delete m_pBroadcastManager;
-#endif
-
- // EngineMaster depends on Config and m_pEffectsManager.
- qDebug() << t.elapsed(false).debugMillisWithUnit() << "deleting EngineMaster";
- delete m_pEngine;
-
qDebug() << t.elapsed(false).debugMillisWithUnit() << "deleting DlgPreferences";
delete m_pPrefDlg;
- // Must delete after EngineMaster and DlgPrefEq.
- qDebug() << t.elapsed(false).debugMillisWithUnit() << "deleting EffectsManager";
- delete m_pEffectsManager;
-
delete m_pTouchShift;
WaveformWidgetFactory::destroy();
@@ -782,80 +353,7 @@ void MixxxMainWindow::finalize() {
delete m_pGuiTick;
delete m_pVisualsManager;
- // Delete the track collections after all internal track pointers
- // in other components have been released by deleting those components
- // beforehand!
- qDebug() << t.elapsed(false).debugMillisWithUnit() << "detaching all track collections";
- delete m_pTrackCollectionManager;
-
- qDebug() << t.elapsed(false).debugMillisWithUnit() << "closing database connection(s)";
- m_pDbConnectionPool->destroyThreadLocalConnection();
- m_pDbConnectionPool.reset(); // should drop the last reference
-
- // HACK: Save config again. We saved it once before doing some dangerous
- // stuff. We only really want to save it here, but the first one was just
- // a precaution. The earlier one can be removed when stuff is more stable
- // at exit.
- m_pSettingsManager->save();
-
- // Check for leaked ControlObjects and give warnings.
- {
- const QList> leakedControls =
- ControlDoublePrivate::takeAllInstances();
- if (!leakedControls.isEmpty()) {
- qWarning()
- << "The following"
- << leakedControls.size()
- << "controls were leaked:";
- for (auto pCDP : leakedControls) {
- ConfigKey key = pCDP->getKey();
- qWarning() << key.group << key.item << pCDP->getCreatorCO();
- // Deleting leaked objects helps to satisfy valgrind.
- // These delete calls could cause crashes if a destructor for a control
- // we thought was leaked is triggered after this one exits.
- // So, only delete so if developer mode is on.
- if (CmdlineArgs::Instance().getDeveloper()) {
- pCDP->deleteCreatorCO();
- }
- }
- DEBUG_ASSERT(!"Controls were leaked!");
- }
- // Finally drop all shared pointers by exiting this scope
- }
-
- Sandbox::shutdown();
-
- qDebug() << t.elapsed(false).debugMillisWithUnit() << "deleting SettingsManager";
- m_pSettingsManager.reset();
-
- delete m_pKeyboard;
- delete m_pKbdConfig;
- delete m_pKbdConfigEmpty;
-
- t.elapsed(true);
- // Report the total time we have been running.
- m_runtime_timer.elapsed(true);
-
- if (m_cmdLineArgs.getDeveloper()) {
- StatsManager::destroy();
- }
-}
-
-bool MixxxMainWindow::initializeDatabase() {
- kLogger.info() << "Connecting to database";
- QSqlDatabase dbConnection = mixxx::DbConnectionPooled(m_pDbConnectionPool);
- if (!dbConnection.isOpen()) {
- QMessageBox::critical(0, tr("Cannot open database"),
- tr("Unable to establish a database connection.\n"
- "Mixxx requires QT with SQLite support. Please read "
- "the Qt SQL driver documentation for information on how "
- "to build it.\n\n"
- "Click OK to exit."), QMessageBox::Ok);
- return false;
- }
-
- kLogger.info() << "Initializing or upgrading database schema";
- return MixxxDb::initDatabaseSchema(dbConnection);
+ m_pCoreServices->shutdown();
}
void MixxxMainWindow::initializeWindow() {
@@ -873,62 +371,19 @@ void MixxxMainWindow::initializeWindow() {
m_pMenuBar->setPalette(Pal);
// Restore the current window state (position, maximized, etc)
- restoreGeometry(QByteArray::fromBase64(m_pSettingsManager->settings()->getValueString(
- ConfigKey("[MainWindow]", "geometry")).toUtf8()));
- restoreState(QByteArray::fromBase64(m_pSettingsManager->settings()->getValueString(
- ConfigKey("[MainWindow]", "state")).toUtf8()));
+ restoreGeometry(QByteArray::fromBase64(
+ m_pCoreServices->getSettings()
+ ->getValueString(ConfigKey("[MainWindow]", "geometry"))
+ .toUtf8()));
+ restoreState(QByteArray::fromBase64(
+ m_pCoreServices->getSettings()
+ ->getValueString(ConfigKey("[MainWindow]", "state"))
+ .toUtf8()));
setWindowIcon(QIcon(":/images/mixxx_icon.svg"));
slotUpdateWindowTitle(TrackPointer());
}
-void MixxxMainWindow::initializeKeyboard() {
- UserSettingsPointer pConfig = m_pSettingsManager->settings();
- QString resourcePath = pConfig->getResourcePath();
-
- // Set the default value in settings file
- if (pConfig->getValueString(ConfigKey("[Keyboard]","Enabled")).length() == 0)
- pConfig->set(ConfigKey("[Keyboard]","Enabled"), ConfigValue(1));
-
- // Read keyboard configuration and set kdbConfig object in WWidget
- // Check first in user's Mixxx directory
- QString userKeyboard = QDir(pConfig->getSettingsPath()).filePath("Custom.kbd.cfg");
-
- // Empty keyboard configuration
- m_pKbdConfigEmpty = new ConfigObject(QString());
-
- if (QFile::exists(userKeyboard)) {
- qDebug() << "Found and will use custom keyboard preset" << userKeyboard;
- m_pKbdConfig = new ConfigObject(userKeyboard);
- } else {
- // Default to the locale for the main input method (e.g. keyboard).
- QLocale locale = inputLocale();
-
- // check if a default keyboard exists
- QString defaultKeyboard = QString(resourcePath).append("keyboard/");
- defaultKeyboard += locale.name();
- defaultKeyboard += ".kbd.cfg";
- qDebug() << "Found and will use default keyboard preset" << defaultKeyboard;
-
- if (!QFile::exists(defaultKeyboard)) {
- qDebug() << defaultKeyboard << " not found, using en_US.kbd.cfg";
- defaultKeyboard = QString(resourcePath).append("keyboard/").append("en_US.kbd.cfg");
- if (!QFile::exists(defaultKeyboard)) {
- qDebug() << defaultKeyboard << " not found, starting without shortcuts";
- defaultKeyboard = "";
- }
- }
- m_pKbdConfig = new ConfigObject(defaultKeyboard);
- }
-
- // TODO(XXX) leak pKbdConfig, KeyboardEventFilter owns it? Maybe roll all keyboard
- // initialization into KeyboardEventFilter
- // Workaround for today: KeyboardEventFilter calls delete
- bool keyboardShortcutsEnabled = pConfig->getValue(
- ConfigKey("[Keyboard]", "Enabled"));
- m_pKeyboard = new KeyboardEventFilter(keyboardShortcutsEnabled ? m_pKbdConfig : m_pKbdConfigEmpty);
-}
-
QDialog::DialogCode MixxxMainWindow::soundDeviceErrorDlg(
const QString &title, const QString &text, bool* retryClicked) {
QMessageBox msgBox;
@@ -950,7 +405,7 @@ QDialog::DialogCode MixxxMainWindow::soundDeviceErrorDlg(
msgBox.exec();
if (msgBox.clickedButton() == retryButton) {
- m_pSoundManager->clearAndQueryDevices();
+ m_pCoreServices->getSoundManager()->clearAndQueryDevices();
*retryClicked = true;
return QDialog::Accepted;
} else if (msgBox.clickedButton() == wikiButton) {
@@ -961,7 +416,7 @@ QDialog::DialogCode MixxxMainWindow::soundDeviceErrorDlg(
} else if (msgBox.clickedButton() == reconfigureButton) {
msgBox.hide();
- m_pSoundManager->clearAndQueryDevices();
+ m_pCoreServices->getSoundManager()->clearAndQueryDevices();
// This way of opening the dialog allows us to use it synchronously
m_pPrefDlg->setWindowModality(Qt::ApplicationModal);
m_pPrefDlg->exec();
@@ -981,26 +436,25 @@ QDialog::DialogCode MixxxMainWindow::soundDeviceBusyDlg(bool* retryClicked) {
QString title(tr("Sound Device Busy"));
QString text(
" " %
- tr("Mixxx was unable to open all the configured sound devices.") +
+ tr("Mixxx was unable to open all the configured sound devices.") +
"
" %
- m_pSoundManager->getErrorDeviceName() %
- " is used by another application or not plugged in."
- "
"
- "- " %
+ m_pCoreServices->getSoundManager()->getErrorDeviceName() %
+ " is used by another application or not plugged in."
+ "
"
+ "- " %
tr("Retry after closing the other application "
- "or reconnecting a sound device") %
- "
"
- "- " %
+ "or reconnecting a sound device") %
+ "
"
+ "- " %
tr("Reconfigure Mixxx's sound device settings.") %
- "
"
- "- " %
+ "
"
+ "- " %
tr("Get Help from the Mixxx Wiki.") %
- "
"
- "- " %
+ "
"
+ "- " %
tr("Exit Mixxx.") %
- "
"
- "
"
- );
+ ""
+ "