From 1b7384f7cb3dc32063e588c174265b8c46cfa629 Mon Sep 17 00:00:00 2001 From: isanae <14251494+isanae@users.noreply.github.com> Date: Sat, 7 Nov 2020 17:55:25 -0500 Subject: moved most of the stuff from main.cpp into MOApplication --- src/main.cpp | 288 +---------------------------------------------- src/moapplication.cpp | 303 ++++++++++++++++++++++++++++++++++++++++++++++++-- src/moapplication.h | 20 +++- 3 files changed, 315 insertions(+), 296 deletions(-) (limited to 'src') diff --git a/src/main.cpp b/src/main.cpp index 40512006..72d598a8 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -45,21 +45,6 @@ along with Mod Organizer. If not, see . using namespace MOBase; using namespace MOShared; -void purgeOldFiles() -{ - // remove the temporary backup directory in case we're restarting after an - // update - QString backupDirectory = qApp->applicationDirPath() + "/update_backup"; - if (QDir(backupDirectory).exists()) { - shellDelete(QStringList(backupDirectory)); - } - - // cycle log file - removeOldFiles( - qApp->property("dataPath").toString() + "/" + QString::fromStdWString(AppConfig::logPath()), - "usvfs*.log", 5, QDir::Name); -} - thread_local LPTOP_LEVEL_EXCEPTION_FILTER g_prevExceptionFilter = nullptr; thread_local std::terminate_handler g_prevTerminateHandler = nullptr; @@ -111,180 +96,6 @@ void setExceptionHandlers() g_prevTerminateHandler = std::set_terminate(onTerminate); } -int runApplication( - MOApplication &application, const cl::CommandLine& cl, - SingleInstance &instance, const QString &dataPath, - Instance& currentInstance) -{ - TimeThis tt("runApplication() to exec()"); - - log::info( - "starting Mod Organizer version {} revision {} in {}, usvfs: {}", - createVersionInfo().displayString(3), GITID, - QCoreApplication::applicationDirPath(), MOShared::getUsvfsVersionString()); - - log::info("data path: {}", dataPath); - - log::info("working directory: {}", QDir::currentPath()); - - if (!instance.secondary()) { - purgeOldFiles(); - } - - QWindowsWindowFunctions::setWindowActivationBehavior( - QWindowsWindowFunctions::AlwaysActivateWindow); - - try - { - Settings settings( - dataPath + "/" + QString::fromStdWString(AppConfig::iniFileName()), - true); - - log::getDefault().setLevel(settings.diagnostics().logLevel()); - - log::debug("using ini at '{}'", settings.filename()); - - if (instance.secondary()) { - log::debug("another instance of MO is running but --multiple was given"); - } - - // global crashDumpType sits in OrganizerCore to make a bit less ugly to - // update it when the settings are changed during runtime - OrganizerCore::setGlobalCrashDumpsType(settings.diagnostics().crashDumpsType()); - - env::Environment env; - env.dump(settings); - settings.dump(); - sanity::checkEnvironment(env); - - const auto moduleNotification = env.onModuleLoaded(qApp, [](auto&& m) { - log::debug("loaded module {}", m.toString()); - sanity::checkIncompatibleModule(m); - }); - - // this must outlive `organizer` - std::unique_ptr pluginContainer; - - log::debug("initializing nexus interface"); - NexusInterface ni(&settings); - - log::debug("initializing core"); - OrganizerCore organizer(settings); - if (!organizer.bootstrap()) { - reportError("failed to set up data paths"); - InstanceManager::singleton().clearCurrentInstance(); - return 1; - } - - log::debug("initializing plugins"); - pluginContainer = std::make_unique(&organizer); - pluginContainer->loadPlugins(); - - for (;;) - { - const auto setupResult = setupInstance(currentInstance, *pluginContainer); - - if (setupResult == SetupInstanceResults::Okay) { - break; - } else if (setupResult == SetupInstanceResults::TryAgain) { - continue; - } else if (setupResult == SetupInstanceResults::SelectAnother) { - InstanceManager::singleton().clearCurrentInstance(); - return RestartExitCode; - } else { - return 1; - } - } - - if (currentInstance.isPortable()) { - log::debug("this is a portable instance"); - } - - sanity::checkPaths(*currentInstance.gamePlugin(), settings); - - organizer.setManagedGame(currentInstance.gamePlugin()); - organizer.createDefaultProfile(); - - log::info( - "using game plugin '{}' ('{}', variant {}, steam id '{}') at {}", - currentInstance.gamePlugin()->gameName(), - currentInstance.gamePlugin()->gameShortName(), - (settings.game().edition().value_or("").isEmpty() ? - "(none)" : *settings.game().edition()), - currentInstance.gamePlugin()->steamAPPId(), - currentInstance.gamePlugin()->gameDirectory().absolutePath()); - - - CategoryFactory::instance().loadCategories(); - organizer.updateExecutablesList(); - organizer.updateModInfoFromDisc(); - - organizer.setCurrentProfile(currentInstance.profileName()); - - if (auto r=cl.setupCore(organizer)) { - return *r; - } - - MOSplash splash(settings, dataPath, currentInstance.gamePlugin()); - - QString apiKey; - if (GlobalSettings::nexusApiKey(apiKey)) { - ni.getAccessManager()->apiCheck(apiKey); - } - - log::debug("initializing tutorials"); - TutorialManager::init( - qApp->applicationDirPath() + "/" - + QString::fromStdWString(AppConfig::tutorialsPath()) + "/", - &organizer); - - if (!application.setStyleFile(settings.interface().styleName().value_or(""))) { - // disable invalid stylesheet - settings.interface().setStyleName(""); - } - - int res = 1; - - { - // scope to control lifetime of mainwindow - // set up main window and its data structures - MainWindow mainWindow(settings, organizer, *pluginContainer); - - // qt resets the thread name somewhere when creating the main window - MOShared::SetThisThreadName("main"); - - ni.getAccessManager()->setTopLevelWidget(&mainWindow); - - QObject::connect(&mainWindow, SIGNAL(styleChanged(QString)), &application, - SLOT(setStyleFile(QString))); - QObject::connect(&instance, SIGNAL(messageSent(QString)), &organizer, - SLOT(externalMessage(QString))); - - log::debug("displaying main window"); - mainWindow.show(); - mainWindow.activateWindow(); - - splash.close(); - - tt.stop(); - - res = application.exec(); - mainWindow.close(); - - ni.getAccessManager()->setTopLevelWidget(nullptr); - } - - settings.geometry().resetIfNeeded(); - return res; - } - catch (const std::exception &e) - { - reportError(e.what()); - } - - return 1; -} - int forwardToPrimary(SingleInstance& instance, const cl::CommandLine& cl) { if (cl.shortcut().isValid()) { @@ -300,118 +111,25 @@ int forwardToPrimary(SingleInstance& instance, const cl::CommandLine& cl) return 0; } -void resetForRestart(cl::CommandLine& cl) -{ - LogModel::instance().clear(); - ResetExitFlag(); - - // make sure the log file isn't locked in case MO was restarted and - // the previous instance gets deleted - log::getDefault().setFile({}); - - // don't reprocess command line - cl.clear(); -} - -int doOneRun( - cl::CommandLine& cl, MOApplication& application, SingleInstance& instance) -{ - TimeThis tt("doOneRun() to runApplication()"); - - // resets things when MO is "restarted" - resetForRestart(cl); - - auto& m = InstanceManager::singleton(); - auto currentInstance = m.currentInstance(); - - if (!currentInstance) - { - currentInstance = selectInstance(); - if (!currentInstance) { - return 1; - } - } - else - { - if (!QDir(currentInstance->directory()).exists()) { - // the previously used instance doesn't exist anymore - - if (m.hasAnyInstances()) { - MOShared::criticalOnTop(QObject::tr( - "Instance at '%1' not found. Select another instance.") - .arg(currentInstance->directory())); - } else { - MOShared::criticalOnTop(QObject::tr( - "Instance at '%1' not found. You must create a new instance") - .arg(currentInstance->directory())); - } - - currentInstance = selectInstance(); - if (!currentInstance) { - return 1; - } - } - } - - const QString dataPath = currentInstance->directory(); - application.setProperty("dataPath", dataPath); - - setExceptionHandlers(); - - if (!setLogDirectory(dataPath)) { - reportError("Failed to create log folder"); - InstanceManager::singleton().clearCurrentInstance(); - return 1; - } - - log::debug("command line: '{}'", QString::fromWCharArray(GetCommandLineW())); - - tt.stop(); - - return runApplication(application, cl, instance, dataPath, *currentInstance); -} int main(int argc, char *argv[]) { MOShared::SetThisThreadName("main"); cl::CommandLine cl; - if (auto r=cl.run(GetCommandLineW())) { return *r; } - TimeThis tt("main() to doOneRun()"); - initLogging(); - auto application = MOApplication::create(argc, argv); + QApplication::setAttribute(Qt::AA_EnableHighDpiScaling); + MOApplication app(cl, argc, argv); SingleInstance instance(cl.multiple()); if (instance.ephemeral()) { return forwardToPrimary(instance, cl); } - tt.stop(); - - if (cl.instance()) - InstanceManager::singleton().overrideInstance(*cl.instance()); - - if (cl.profile()) { - InstanceManager::singleton().overrideProfile(*cl.profile()); - } - - // makes plugin data path available to plugins, see - // IOrganizer::getPluginDataPath() - MOBase::details::setPluginDataPath(OrganizerCore::pluginDataPath()); - - for (;;) - { - const auto r = doOneRun(cl, application, instance); - if (r == RestartExitCode) { - continue; - } - - return r; - } + return app.run(instance); } diff --git a/src/moapplication.cpp b/src/moapplication.cpp index 43d787f5..b4ba7da6 100644 --- a/src/moapplication.cpp +++ b/src/moapplication.cpp @@ -20,6 +20,18 @@ along with Mod Organizer. If not, see . #include "moapplication.h" #include "settings.h" #include "env.h" +#include "commandline.h" +#include "instancemanager.h" +#include "organizercore.h" +#include "thread_utils.h" +#include "loglist.h" +#include "singleinstance.h" +#include "nexusinterface.h" +#include "nxmaccessmanager.h" +#include "tutorialmanager.h" +#include "sanitychecks.h" +#include "mainwindow.h" +#include "shared/error_report.h" #include "shared/util.h" #include #include @@ -42,7 +54,7 @@ along with Mod Organizer. If not, see . "type='win32' \"") using namespace MOBase; - +using namespace MOShared; class ProxyStyle : public QProxyStyle { public: @@ -120,8 +132,8 @@ void addDllsToPath() } -MOApplication::MOApplication(int& argc, char** argv) - : QApplication(argc, argv) +MOApplication::MOApplication(cl::CommandLine& cl, int& argc, char** argv) + : QApplication(argc, argv), m_cl(cl) { connect(&m_StyleWatcher, &QFileSystemWatcher::fileChanged, [&](auto&& file){ log::debug("style file '{}' changed, reloading", file); @@ -133,11 +145,288 @@ MOApplication::MOApplication(int& argc, char** argv) addDllsToPath(); } -MOApplication MOApplication::create(int& argc, char** argv) +int MOApplication::run(SingleInstance& singleInstance) +{ + auto& m = InstanceManager::singleton(); + + if (m_cl.instance()) + m.overrideInstance(*m_cl.instance()); + + if (m_cl.profile()) { + m.overrideProfile(*m_cl.profile()); + } + + // makes plugin data path available to plugins, see + // IOrganizer::getPluginDataPath() + MOBase::details::setPluginDataPath(OrganizerCore::pluginDataPath()); + + for (;;) + { + const auto r = doOneRun(singleInstance); + if (r == RestartExitCode) { + continue; + } + + return r; + } +} + +int MOApplication::doOneRun(SingleInstance& singleInstance) { - QApplication::setAttribute(Qt::AA_EnableHighDpiScaling); + TimeThis tt("doOneRun() to runApplication()"); + + // resets things when MO is "restarted" + resetForRestart(); + + auto& m = InstanceManager::singleton(); + auto currentInstance = m.currentInstance(); + + if (!currentInstance) + { + currentInstance = selectInstance(); + if (!currentInstance) { + return 1; + } + } + else + { + if (!QDir(currentInstance->directory()).exists()) { + // the previously used instance doesn't exist anymore + + if (m.hasAnyInstances()) { + MOShared::criticalOnTop(QObject::tr( + "Instance at '%1' not found. Select another instance.") + .arg(currentInstance->directory())); + } else { + MOShared::criticalOnTop(QObject::tr( + "Instance at '%1' not found. You must create a new instance") + .arg(currentInstance->directory())); + } + + currentInstance = selectInstance(); + if (!currentInstance) { + return 1; + } + } + } + + const QString dataPath = currentInstance->directory(); + setProperty("dataPath", dataPath); + + setExceptionHandlers(); + + if (!setLogDirectory(dataPath)) { + reportError("Failed to create log folder"); + InstanceManager::singleton().clearCurrentInstance(); + return 1; + } + + log::debug("command line: '{}'", QString::fromWCharArray(GetCommandLineW())); + + tt.stop(); - return MOApplication(argc, argv); + return runApplication(singleInstance, dataPath, *currentInstance); +} + +int MOApplication::runApplication( + SingleInstance& singleInstance, + const QString &dataPath, Instance& currentInstance) +{ + TimeThis tt("runApplication() to exec()"); + + log::info( + "starting Mod Organizer version {} revision {} in {}, usvfs: {}", + createVersionInfo().displayString(3), GITID, + QCoreApplication::applicationDirPath(), MOShared::getUsvfsVersionString()); + + log::info("data path: {}", dataPath); + + log::info("working directory: {}", QDir::currentPath()); + + if (!singleInstance.secondary()) { + purgeOldFiles(); + } + + QWindowsWindowFunctions::setWindowActivationBehavior( + QWindowsWindowFunctions::AlwaysActivateWindow); + + try + { + Settings settings( + dataPath + "/" + QString::fromStdWString(AppConfig::iniFileName()), + true); + + log::getDefault().setLevel(settings.diagnostics().logLevel()); + + log::debug("using ini at '{}'", settings.filename()); + + if (singleInstance.secondary()) { + log::debug("another instance of MO is running but --multiple was given"); + } + + // global crashDumpType sits in OrganizerCore to make a bit less ugly to + // update it when the settings are changed during runtime + OrganizerCore::setGlobalCrashDumpsType(settings.diagnostics().crashDumpsType()); + + env::Environment env; + env.dump(settings); + settings.dump(); + sanity::checkEnvironment(env); + + const auto moduleNotification = env.onModuleLoaded(qApp, [](auto&& m) { + log::debug("loaded module {}", m.toString()); + sanity::checkIncompatibleModule(m); + }); + + // this must outlive `organizer` + std::unique_ptr pluginContainer; + + log::debug("initializing nexus interface"); + NexusInterface ni(&settings); + + log::debug("initializing core"); + OrganizerCore organizer(settings); + if (!organizer.bootstrap()) { + reportError("failed to set up data paths"); + InstanceManager::singleton().clearCurrentInstance(); + return 1; + } + + log::debug("initializing plugins"); + pluginContainer = std::make_unique(&organizer); + pluginContainer->loadPlugins(); + + for (;;) + { + const auto setupResult = setupInstance(currentInstance, *pluginContainer); + + if (setupResult == SetupInstanceResults::Okay) { + break; + } else if (setupResult == SetupInstanceResults::TryAgain) { + continue; + } else if (setupResult == SetupInstanceResults::SelectAnother) { + InstanceManager::singleton().clearCurrentInstance(); + return RestartExitCode; + } else { + return 1; + } + } + + if (currentInstance.isPortable()) { + log::debug("this is a portable instance"); + } + + sanity::checkPaths(*currentInstance.gamePlugin(), settings); + + organizer.setManagedGame(currentInstance.gamePlugin()); + organizer.createDefaultProfile(); + + log::info( + "using game plugin '{}' ('{}', variant {}, steam id '{}') at {}", + currentInstance.gamePlugin()->gameName(), + currentInstance.gamePlugin()->gameShortName(), + (settings.game().edition().value_or("").isEmpty() ? + "(none)" : *settings.game().edition()), + currentInstance.gamePlugin()->steamAPPId(), + currentInstance.gamePlugin()->gameDirectory().absolutePath()); + + + CategoryFactory::instance().loadCategories(); + organizer.updateExecutablesList(); + organizer.updateModInfoFromDisc(); + + organizer.setCurrentProfile(currentInstance.profileName()); + + if (auto r=m_cl.setupCore(organizer)) { + return *r; + } + + MOSplash splash(settings, dataPath, currentInstance.gamePlugin()); + + QString apiKey; + if (GlobalSettings::nexusApiKey(apiKey)) { + ni.getAccessManager()->apiCheck(apiKey); + } + + log::debug("initializing tutorials"); + TutorialManager::init( + qApp->applicationDirPath() + "/" + + QString::fromStdWString(AppConfig::tutorialsPath()) + "/", + &organizer); + + if (!setStyleFile(settings.interface().styleName().value_or(""))) { + // disable invalid stylesheet + settings.interface().setStyleName(""); + } + + int res = 1; + + { + // scope to control lifetime of mainwindow + // set up main window and its data structures + MainWindow mainWindow(settings, organizer, *pluginContainer); + + // qt resets the thread name somewhere when creating the main window + MOShared::SetThisThreadName("main"); + + ni.getAccessManager()->setTopLevelWidget(&mainWindow); + + QObject::connect(&mainWindow, SIGNAL(styleChanged(QString)), this, + SLOT(setStyleFile(QString))); + QObject::connect(&singleInstance, SIGNAL(messageSent(QString)), &organizer, + SLOT(externalMessage(QString))); + + log::debug("displaying main window"); + mainWindow.show(); + mainWindow.activateWindow(); + + splash.close(); + + tt.stop(); + + res = exec(); + mainWindow.close(); + + ni.getAccessManager()->setTopLevelWidget(nullptr); + } + + settings.geometry().resetIfNeeded(); + return res; + } + catch (const std::exception &e) + { + reportError(e.what()); + } + + return 1; +} + +void MOApplication::purgeOldFiles() +{ + // remove the temporary backup directory in case we're restarting after an + // update + QString backupDirectory = qApp->applicationDirPath() + "/update_backup"; + if (QDir(backupDirectory).exists()) { + shellDelete(QStringList(backupDirectory)); + } + + // cycle log file + removeOldFiles( + qApp->property("dataPath").toString() + "/" + QString::fromStdWString(AppConfig::logPath()), + "usvfs*.log", 5, QDir::Name); +} + +void MOApplication::resetForRestart() +{ + LogModel::instance().clear(); + ResetExitFlag(); + + // make sure the log file isn't locked in case MO was restarted and + // the previous instance gets deleted + log::getDefault().setFile({}); + + // don't reprocess command line + m_cl.clear(); } bool MOApplication::setStyleFile(const QString& styleName) @@ -163,7 +452,6 @@ bool MOApplication::setStyleFile(const QString& styleName) return true; } - bool MOApplication::notify(QObject* receiver, QEvent* event) { try { @@ -183,7 +471,6 @@ bool MOApplication::notify(QObject* receiver, QEvent* event) } } - void MOApplication::updateStyle(const QString& fileName) { if (QStyleFactory::keys().contains(fileName)) { diff --git a/src/moapplication.h b/src/moapplication.h index 0ee04492..c1512d9b 100644 --- a/src/moapplication.h +++ b/src/moapplication.h @@ -24,15 +24,21 @@ along with Mod Organizer. If not, see . #include class Settings; +class SingleInstance; +class Instance; + namespace MOBase { class IPluginGame; } +namespace cl { class CommandLine; } class MOApplication : public QApplication { Q_OBJECT public: - static MOApplication create(int& argc, char** argv); - virtual bool notify (QObject* receiver, QEvent* event); + MOApplication(cl::CommandLine& cl, int& argc, char** argv); + + int run(SingleInstance& si); + virtual bool notify(QObject* receiver, QEvent* event); public slots: bool setStyleFile(const QString& style); @@ -43,8 +49,16 @@ private slots: private: QFileSystemWatcher m_StyleWatcher; QString m_DefaultStyle; + cl::CommandLine& m_cl; + + int doOneRun(SingleInstance& singleInstance); + + int runApplication( + SingleInstance& singleInstance, + const QString &dataPath, Instance& currentInstance); - MOApplication(int& argc, char** argv); + void purgeOldFiles(); + void resetForRestart(); }; -- cgit v1.3.1