From 90ea45328d72f9664ace3cfbdce700dbe7a1d016 Mon Sep 17 00:00:00 2001
From: isanae <14251494+isanae@users.noreply.github.com>
Date: Sat, 7 Nov 2020 16:16:47 -0500
Subject: moved splash stuff to MOSplash comments
---
src/moapplication.cpp | 73 +++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 73 insertions(+)
(limited to 'src/moapplication.cpp')
diff --git a/src/moapplication.cpp b/src/moapplication.cpp
index 290666af..659b5a12 100644
--- a/src/moapplication.cpp
+++ b/src/moapplication.cpp
@@ -18,6 +18,8 @@ along with Mod Organizer. If not, see .
*/
#include "moapplication.h"
+#include "settings.h"
+#include
#include
#include
#include
@@ -147,3 +149,74 @@ void MOApplication::updateStyle(const QString& fileName)
}
}
}
+
+
+MOSplash::MOSplash(
+ const Settings& settings, const QString& dataPath,
+ const MOBase::IPluginGame* game)
+{
+ const auto splashPath = getSplashPath(settings, dataPath, game);
+ if (splashPath.isEmpty()) {
+ return;
+ }
+
+ QPixmap image(splashPath);
+ if (image.isNull()) {
+ log::error("failed to load splash from {}", splashPath);
+ return;
+ }
+
+ ss_.reset(new QSplashScreen(image));
+ settings.geometry().centerOnMainWindowMonitor(ss_.get());
+
+ ss_->show();
+ ss_->activateWindow();
+}
+
+void MOSplash::close()
+{
+ if (ss_) {
+ // don't pass mainwindow as it just waits half a second for it
+ // instead of proceding
+ ss_->finish(nullptr);
+ }
+}
+
+QString MOSplash::getSplashPath(
+ const Settings& settings, const QString& dataPath,
+ const MOBase::IPluginGame* game) const
+{
+ if (!settings.useSplash()) {
+ return {};
+ }
+
+ // try splash from instance directory
+ const QString splashPath = dataPath + "/splash.png";
+ if (QFile::exists(dataPath + "/splash.png")) {
+ QImage image(splashPath);
+ if (!image.isNull()) {
+ return splashPath;
+ }
+ }
+
+ // try splash from plugin
+ QString pluginSplash = QString(":/%1/splash").arg(game->gameShortName());
+ if (QFile::exists(pluginSplash)) {
+ QImage image(pluginSplash);
+ if (!image.isNull()) {
+ image.save(splashPath);
+ return pluginSplash;
+ }
+ }
+
+ // try default splash from resource
+ QString defaultSplash = ":/MO/gui/splash";
+ if (QFile::exists(defaultSplash)) {
+ QImage image(defaultSplash);
+ if (!image.isNull()) {
+ return defaultSplash;
+ }
+ }
+
+ return splashPath;
+}
--
cgit v1.3.1
From a8187e7dc47cd344fd309a2be3675e4687f95aaa Mon Sep 17 00:00:00 2001
From: isanae <14251494+isanae@users.noreply.github.com>
Date: Sat, 7 Nov 2020 16:31:35 -0500
Subject: moved dlls stuff to MOApplication
---
src/main.cpp | 40 +---------------------------------------
src/moapplication.cpp | 48 ++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 49 insertions(+), 39 deletions(-)
(limited to 'src/moapplication.cpp')
diff --git a/src/main.cpp b/src/main.cpp
index 9d6ed7b0..a8ea2601 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -122,44 +122,6 @@ void setExceptionHandlers()
g_prevTerminateHandler = std::set_terminate(onTerminate);
}
-// This adds the `dlls` directory to the path so the dlls can be found. How
-// MO is able to find dlls in there is a bit convoluted:
-//
-// Dependencies on DLLs can be baked into an executable by passing a
-// `manifestdependency` option to the linker. This can be done on the command
-// line or with a pragma. Typically, the dependency will not be a hardcoded
-// filename, but an assembly name, such as Microsoft.Windows.Common-Controls.
-//
-// When Windows loads the exe, it will look for this assembly in a variety of
-// places, such as in the WinSxS folder, but also in the program's folder. It
-// will look for `assemblyname.dll` or `assemblyname/assemblyname.dll` and try
-// to load that.
-//
-// If these files don't exist, then the loader gets creative and looks for
-// `assemblyname.manifest` and `assemblyname/assemblyname.manifest`. A manifest
-// file is just an XML file that can contain a list of DLLs to load for this
-// assembly.
-//
-// In MO's case, there's a `pragma` at the beginning of this file which adds
-// `dlls` as an "assembly" dependency. This is a bit of a hack to just force
-// the loader to eventually find `dlls/dlls.manifest`, which contains the list
-// of all the DLLs MO requires to load.
-//
-// This file was handwritten in `modorganizer/src/dlls.manifest.qt5` and
-// is copied and renamed in CMakeLists.txt into `bin/dlls/dlls.manifest`. Note
-// that the useless and incorrect .qt5 extension is removed.
-//
-void addDllsToPath()
-{
- const auto dllsPath = QDir::toNativeSeparators(
- QCoreApplication::applicationDirPath() + "/dlls");
-
- QCoreApplication::setLibraryPaths(
- QStringList(dllsPath) + QCoreApplication::libraryPaths());
-
- env::prependToPath(dllsPath);
-}
-
std::optional handleCommandLine(
const cl::CommandLine& cl, OrganizerCore& organizer)
{
@@ -646,8 +608,8 @@ int main(int argc, char *argv[])
SetThisThreadName("main");
initLogging();
+
auto application = MOApplication::create(argc, argv);
- addDllsToPath();
SingleInstance instance(cl.multiple());
if (instance.ephemeral()) {
diff --git a/src/moapplication.cpp b/src/moapplication.cpp
index 659b5a12..f514050f 100644
--- a/src/moapplication.cpp
+++ b/src/moapplication.cpp
@@ -19,6 +19,7 @@ along with Mod Organizer. If not, see .
#include "moapplication.h"
#include "settings.h"
+#include "env.h"
#include
#include
#include
@@ -32,6 +33,12 @@ along with Mod Organizer. If not, see .
#include
#include
+// see addDllsToPath() below
+#pragma comment(linker, "/manifestDependency:\"" \
+ "name='dlls' " \
+ "processorArchitecture='x86' " \
+ "version='1.0.0.0' " \
+ "type='win32' \"")
using namespace MOBase;
@@ -73,6 +80,45 @@ public:
};
+// This adds the `dlls` directory to the path so the dlls can be found. How
+// MO is able to find dlls in there is a bit convoluted:
+//
+// Dependencies on DLLs can be baked into an executable by passing a
+// `manifestdependency` option to the linker. This can be done on the command
+// line or with a pragma. Typically, the dependency will not be a hardcoded
+// filename, but an assembly name, such as Microsoft.Windows.Common-Controls.
+//
+// When Windows loads the exe, it will look for this assembly in a variety of
+// places, such as in the WinSxS folder, but also in the program's folder. It
+// will look for `assemblyname.dll` or `assemblyname/assemblyname.dll` and try
+// to load that.
+//
+// If these files don't exist, then the loader gets creative and looks for
+// `assemblyname.manifest` and `assemblyname/assemblyname.manifest`. A manifest
+// file is just an XML file that can contain a list of DLLs to load for this
+// assembly.
+//
+// In MO's case, there's a `pragma` at the beginning of this file which adds
+// `dlls` as an "assembly" dependency. This is a bit of a hack to just force
+// the loader to eventually find `dlls/dlls.manifest`, which contains the list
+// of all the DLLs MO requires to load.
+//
+// This file was handwritten in `modorganizer/src/dlls.manifest.qt5` and
+// is copied and renamed in CMakeLists.txt into `bin/dlls/dlls.manifest`. Note
+// that the useless and incorrect .qt5 extension is removed.
+//
+void addDllsToPath()
+{
+ const auto dllsPath = QDir::toNativeSeparators(
+ QCoreApplication::applicationDirPath() + "/dlls");
+
+ QCoreApplication::setLibraryPaths(
+ QStringList(dllsPath) + QCoreApplication::libraryPaths());
+
+ env::prependToPath(dllsPath);
+}
+
+
MOApplication::MOApplication(int& argc, char** argv)
: QApplication(argc, argv)
{
@@ -83,11 +129,13 @@ MOApplication::MOApplication(int& argc, char** argv)
m_DefaultStyle = style()->objectName();
setStyle(new ProxyStyle(style()));
+ addDllsToPath();
}
MOApplication MOApplication::create(int& argc, char** argv)
{
QApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
+
return MOApplication(argc, argv);
}
--
cgit v1.3.1
From 079fd33cf18cc901d1a6a4463d8a8ccd1d730786 Mon Sep 17 00:00:00 2001
From: isanae <14251494+isanae@users.noreply.github.com>
Date: Sat, 7 Nov 2020 17:32:30 -0500
Subject: added sanitychecks.h, moved to namespace sanity added a set
SetThisThreadName() after creating the main window, Qt resets it
---
src/main.cpp | 22 +++++++++++-----------
src/moapplication.cpp | 1 +
src/sanitychecks.cpp | 10 ++++++++--
src/sanitychecks.h | 27 +++++++++++++++++++++++++++
4 files changed, 47 insertions(+), 13 deletions(-)
create mode 100644 src/sanitychecks.h
(limited to 'src/moapplication.cpp')
diff --git a/src/main.cpp b/src/main.cpp
index 55fedc7a..40512006 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -32,6 +32,7 @@ along with Mod Organizer. If not, see .
#include "env.h"
#include "envmodule.h"
#include "commandline.h"
+#include "sanitychecks.h"
#include "shared/util.h"
#include "shared/appconfig.h"
#include "shared/error_report.h"
@@ -41,14 +42,9 @@ along with Mod Organizer. If not, see .
#include
#include
-
using namespace MOBase;
using namespace MOShared;
-void sanityChecks(const env::Environment& env);
-int checkIncompatibleModule(const env::Module& m);
-int checkPathsForSanity(MOBase::IPluginGame& game, const Settings& s);
-
void purgeOldFiles()
{
// remove the temporary backup directory in case we're restarting after an
@@ -159,11 +155,11 @@ int runApplication(
env::Environment env;
env.dump(settings);
settings.dump();
- sanityChecks(env);
+ sanity::checkEnvironment(env);
const auto moduleNotification = env.onModuleLoaded(qApp, [](auto&& m) {
log::debug("loaded module {}", m.toString());
- checkIncompatibleModule(m);
+ sanity::checkIncompatibleModule(m);
});
// this must outlive `organizer`
@@ -204,7 +200,7 @@ int runApplication(
log::debug("this is a portable instance");
}
- checkPathsForSanity(*currentInstance.gamePlugin(), settings);
+ sanity::checkPaths(*currentInstance.gamePlugin(), settings);
organizer.setManagedGame(currentInstance.gamePlugin());
organizer.createDefaultProfile();
@@ -249,10 +245,14 @@ int runApplication(
int res = 1;
- { // scope to control lifetime of mainwindow
+ {
+ // 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,
@@ -373,6 +373,8 @@ int doOneRun(
int main(int argc, char *argv[])
{
+ MOShared::SetThisThreadName("main");
+
cl::CommandLine cl;
if (auto r=cl.run(GetCommandLineW())) {
@@ -381,8 +383,6 @@ int main(int argc, char *argv[])
TimeThis tt("main() to doOneRun()");
- SetThisThreadName("main");
-
initLogging();
auto application = MOApplication::create(argc, argv);
diff --git a/src/moapplication.cpp b/src/moapplication.cpp
index f514050f..43d787f5 100644
--- a/src/moapplication.cpp
+++ b/src/moapplication.cpp
@@ -20,6 +20,7 @@ along with Mod Organizer. If not, see .
#include "moapplication.h"
#include "settings.h"
#include "env.h"
+#include "shared/util.h"
#include
#include
#include
diff --git a/src/sanitychecks.cpp b/src/sanitychecks.cpp
index 7afce7bd..613e4b26 100644
--- a/src/sanitychecks.cpp
+++ b/src/sanitychecks.cpp
@@ -1,3 +1,4 @@
+#include "sanitychecks.h"
#include "env.h"
#include "envmodule.h"
#include "settings.h"
@@ -5,6 +6,9 @@
#include
#include
+namespace sanity
+{
+
using namespace MOBase;
enum class SecurityZone
@@ -368,7 +372,7 @@ int checkProtected(const QDir& d, const QString& what)
return 0;
}
-int checkPathsForSanity(IPluginGame& game, const Settings& s)
+int checkPaths(IPluginGame& game, const Settings& s)
{
log::debug("checking paths");
@@ -390,7 +394,7 @@ int checkPathsForSanity(IPluginGame& game, const Settings& s)
return n;
}
-void sanityChecks(const env::Environment& e)
+void checkEnvironment(const env::Environment& e)
{
log::debug("running sanity checks...");
@@ -404,3 +408,5 @@ void sanityChecks(const env::Environment& e)
"sanity checks done, {}",
(n > 0 ? "problems were found" : "everything looks okay"));
}
+
+} // namespace
diff --git a/src/sanitychecks.h b/src/sanitychecks.h
new file mode 100644
index 00000000..8786ee78
--- /dev/null
+++ b/src/sanitychecks.h
@@ -0,0 +1,27 @@
+#ifndef MODORGANIZER_SANITYCHECKS_INCLUDED
+#define MODORGANIZER_SANITYCHECKS_INCLUDED
+
+namespace env
+{
+ class Environment;
+ class Module;
+}
+
+namespace MOBase
+{
+ class IPluginGame;
+}
+
+class Settings;
+
+
+namespace sanity
+{
+
+void checkEnvironment(const env::Environment& env);
+int checkIncompatibleModule(const env::Module& m);
+int checkPaths(MOBase::IPluginGame& game, const Settings& s);
+
+} // namespace
+
+#endif // MODORGANIZER_SANITYCHECKS_INCLUDED
--
cgit v1.3.1
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/moapplication.cpp')
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
From b4f6275c3ef888551e14e5d64739e1c32978b8e8 Mon Sep 17 00:00:00 2001
From: isanae <14251494+isanae@users.noreply.github.com>
Date: Sat, 7 Nov 2020 18:14:24 -0500
Subject: split getCurrentInstance()
---
src/moapplication.cpp | 54 ++++++++++++++++++++++++++++-----------------------
src/moapplication.h | 5 +++++
2 files changed, 35 insertions(+), 24 deletions(-)
(limited to 'src/moapplication.cpp')
diff --git a/src/moapplication.cpp b/src/moapplication.cpp
index b4ba7da6..24cafd05 100644
--- a/src/moapplication.cpp
+++ b/src/moapplication.cpp
@@ -160,8 +160,13 @@ int MOApplication::run(SingleInstance& singleInstance)
// IOrganizer::getPluginDataPath()
MOBase::details::setPluginDataPath(OrganizerCore::pluginDataPath());
+ // MO runs in a loop because it can be restarted in several ways, such as
+ // when switching instances or changing some settings
for (;;)
{
+ // resets things when MO is "restarted"
+ resetForRestart();
+
const auto r = doOneRun(singleInstance);
if (r == RestartExitCode) {
continue;
@@ -175,18 +180,37 @@ int MOApplication::doOneRun(SingleInstance& singleInstance)
{
TimeThis tt("doOneRun() to runApplication()");
- // resets things when MO is "restarted"
- resetForRestart();
+ auto currentInstance = getCurrentInstance();
+ 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 runApplication(singleInstance, dataPath, *currentInstance);
+}
+std::optional MOApplication::getCurrentInstance()
+{
auto& m = InstanceManager::singleton();
auto currentInstance = m.currentInstance();
if (!currentInstance)
{
currentInstance = selectInstance();
- if (!currentInstance) {
- return 1;
- }
}
else
{
@@ -204,28 +228,10 @@ int MOApplication::doOneRun(SingleInstance& singleInstance)
}
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 runApplication(singleInstance, dataPath, *currentInstance);
+ return currentInstance;
}
int MOApplication::runApplication(
diff --git a/src/moapplication.h b/src/moapplication.h
index c1512d9b..8cbb5f28 100644
--- a/src/moapplication.h
+++ b/src/moapplication.h
@@ -37,7 +37,10 @@ class MOApplication : public QApplication
public:
MOApplication(cl::CommandLine& cl, int& argc, char** argv);
+ // sets up everything, creates the main window and runs it
+ //
int run(SingleInstance& si);
+
virtual bool notify(QObject* receiver, QEvent* event);
public slots:
@@ -53,6 +56,8 @@ private:
int doOneRun(SingleInstance& singleInstance);
+ std::optional getCurrentInstance();
+
int runApplication(
SingleInstance& singleInstance,
const QString &dataPath, Instance& currentInstance);
--
cgit v1.3.1
From 08c952e53a4efcd5b50c0ec947bf216101c027ef Mon Sep 17 00:00:00 2001
From: isanae <14251494+isanae@users.noreply.github.com>
Date: Sat, 7 Nov 2020 19:05:15 -0500
Subject: stopped using core dump stuff from usvfs, mo has its own set
exception handler at the start, it can handle not having qt or data paths
hopefully fixed infinite crash dumps
---
src/CMakeLists.txt | 1 +
src/env.cpp | 27 ++++++++++++++--------
src/env.h | 21 -----------------
src/envdump.h | 30 ++++++++++++++++++++++++
src/main.cpp | 27 ++++++++++++++--------
src/mainwindow.cpp | 4 ++--
src/moapplication.cpp | 4 +---
src/organizercore.cpp | 48 +++++++++++++++++++++++----------------
src/organizercore.h | 13 +++++------
src/settings.cpp | 12 +++++-----
src/settings.h | 9 ++++----
src/settingsdialogdiagnostics.cpp | 20 ++++++++--------
src/usvfsconnector.cpp | 33 +++++++++++++++------------
src/usvfsconnector.h | 3 ++-
14 files changed, 146 insertions(+), 106 deletions(-)
create mode 100644 src/envdump.h
(limited to 'src/moapplication.cpp')
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index eec33460..30614e59 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -70,6 +70,7 @@ add_filter(NAME src/downloads GROUPS
add_filter(NAME src/env GROUPS
env
+ envdump
envfs
envmetrics
envmodule
diff --git a/src/env.cpp b/src/env.cpp
index 5bed84c1..98d2e6ea 100644
--- a/src/env.cpp
+++ b/src/env.cpp
@@ -4,6 +4,7 @@
#include "envsecurity.h"
#include "envshortcut.h"
#include "envwindows.h"
+#include "envdump.h"
#include "settings.h"
#include
#include
@@ -1182,8 +1183,16 @@ HandlePtr tempFile(const std::wstring dir)
return {};
}
-HandlePtr dumpFile()
+HandlePtr dumpFile(const wchar_t* dir)
{
+ // try the given directory, if any
+ if (dir) {
+ HandlePtr h = tempFile(dir);
+ if (h.get() != INVALID_HANDLE_VALUE) {
+ return h;
+ }
+ }
+
// try the current directory
HandlePtr h = tempFile(L".");
if (h.get() != INVALID_HANDLE_VALUE) {
@@ -1193,10 +1202,10 @@ HandlePtr dumpFile()
std::wclog << L"cannot write dump file in current directory\n";
// try the temp directory
- const auto dir = tempDir();
+ const auto temp = tempDir();
- if (!dir.empty()) {
- h = tempFile(dir.c_str());
+ if (!temp.empty()) {
+ h = tempFile(temp.c_str());
if (h.get() != INVALID_HANDLE_VALUE) {
return h;
}
@@ -1235,11 +1244,11 @@ std::string toString(CoreDumpTypes type)
}
-bool createMiniDump(HANDLE process, CoreDumpTypes type)
+bool createMiniDump(const wchar_t* dir, HANDLE process, CoreDumpTypes type)
{
const DWORD pid = GetProcessId(process);
- const HandlePtr file = dumpFile();
+ const HandlePtr file = dumpFile(dir);
if (!file) {
std::wcerr << L"nowhere to write the dump file\n";
return false;
@@ -1278,10 +1287,10 @@ bool createMiniDump(HANDLE process, CoreDumpTypes type)
}
-bool coredump(CoreDumpTypes type)
+bool coredump(const wchar_t* dir, CoreDumpTypes type)
{
std::wclog << L"creating minidump for the current process\n";
- return createMiniDump(GetCurrentProcess(), type);
+ return createMiniDump(dir, GetCurrentProcess(), type);
}
bool coredumpOther(CoreDumpTypes type)
@@ -1309,7 +1318,7 @@ bool coredumpOther(CoreDumpTypes type)
return false;
}
- return createMiniDump(handle.get(), type);
+ return createMiniDump(nullptr, handle.get(), type);
}
} // namespace
diff --git a/src/env.h b/src/env.h
index dbbd5cf4..e9cb7a36 100644
--- a/src/env.h
+++ b/src/env.h
@@ -309,27 +309,6 @@ bool registryValueExists(const QString& key, const QString& value);
//
void deleteRegistryKeyIfEmpty(const QString& name);
-
-enum class CoreDumpTypes
-{
- Mini = 1,
- Data,
- Full
-};
-
-
-CoreDumpTypes coreDumpTypeFromString(const std::string& s);
-std::string toString(CoreDumpTypes type);
-
-// creates a minidump file for this process
-//
-bool coredump(CoreDumpTypes type);
-
-// finds another process with the same name as this one and creates a minidump
-// file for it
-//
-bool coredumpOther(CoreDumpTypes type);
-
} // namespace env
#endif // ENV_ENV_H
diff --git a/src/envdump.h b/src/envdump.h
new file mode 100644
index 00000000..355df783
--- /dev/null
+++ b/src/envdump.h
@@ -0,0 +1,30 @@
+#ifndef MODORGANIZER_ENVDUMP_INCLUDED
+#define MODORGANIZER_ENVDUMP_INCLUDED
+
+namespace env
+{
+
+enum class CoreDumpTypes
+{
+ None,
+ Mini,
+ Data,
+ Full
+};
+
+
+CoreDumpTypes coreDumpTypeFromString(const std::string& s);
+std::string toString(CoreDumpTypes type);
+
+// creates a minidump file for this process
+//
+bool coredump(const wchar_t* dir, CoreDumpTypes type);
+
+// finds another process with the same name as this one and creates a minidump
+// file for it
+//
+bool coredumpOther(CoreDumpTypes type);
+
+} // namespace
+
+#endif // MODORGANIZER_ENVDUMP_INCLUDED
diff --git a/src/main.cpp b/src/main.cpp
index a2e16cc0..ad074501 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -3,8 +3,9 @@
#include "moapplication.h"
#include "organizercore.h"
#include "commandline.h"
+#include "env.h"
+#include "thread_utils.h"
#include "shared/util.h"
-#include
#include
using namespace MOBase;
@@ -17,6 +18,7 @@ int forwardToPrimary(SingleInstance& instance, const cl::CommandLine& cl);
int main(int argc, char *argv[])
{
MOShared::SetThisThreadName("main");
+ setExceptionHandlers();
cl::CommandLine cl;
if (auto r=cl.run(GetCommandLineW())) {
@@ -53,20 +55,20 @@ int forwardToPrimary(SingleInstance& instance, const cl::CommandLine& cl)
LONG WINAPI onUnhandledException(_EXCEPTION_POINTERS* ptrs)
{
- const std::wstring& dumpPath = OrganizerCore::crashDumpsPath();
+ const auto path = OrganizerCore::getGlobalCoreDumpPath();
+ const auto type = OrganizerCore::getGlobalCoreDumpType();
- const int r = CreateMiniDump(
- ptrs, OrganizerCore::getGlobalCrashDumpsType(), dumpPath.c_str());
+ const auto r = env::coredump(path.empty() ? nullptr : path.c_str(), type);
- if (r == 0) {
- log::error("ModOrganizer has crashed, crash dump created.");
+ if (r) {
+ log::error("ModOrganizer has crashed, core dump created.");
} else {
- log::error(
- "ModOrganizer has crashed, CreateMiniDump failed ({}, error {}).",
- r, GetLastError());
+ log::error("ModOrganizer has crashed, core dump failed");
}
- if (g_prevExceptionFilter && ptrs)
+ // g_prevExceptionFilter somehow sometimes point to this function, making this
+ // recurse and create hundreds of core dump, not sure why
+ if (g_prevExceptionFilter && ptrs && g_prevExceptionFilter != onUnhandledException)
return g_prevExceptionFilter(ptrs);
else
return EXCEPTION_CONTINUE_SEARCH;
@@ -95,6 +97,11 @@ void onTerminate() noexcept
void setExceptionHandlers()
{
+ if (g_prevExceptionFilter) {
+ // already called
+ return;
+ }
+
g_prevExceptionFilter = SetUnhandledExceptionFilter(onUnhandledException);
g_prevTerminateHandler = std::set_terminate(onTerminate);
}
diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp
index ea8a0efe..41958b80 100644
--- a/src/mainwindow.cpp
+++ b/src/mainwindow.cpp
@@ -5084,7 +5084,7 @@ void MainWindow::on_actionSettings_triggered()
bool proxy = settings.network().useProxy();
DownloadManager *dlManager = m_OrganizerCore.downloadManager();
const bool oldCheckForUpdates = settings.checkForUpdates();
- const int oldMaxDumps = settings.diagnostics().crashDumpsMax();
+ const int oldMaxDumps = settings.diagnostics().maxCoreDumps();
SettingsDialog dialog(&m_PluginContainer, settings, this);
@@ -5171,7 +5171,7 @@ void MainWindow::on_actionSettings_triggered()
m_OrganizerCore.setLogLevel(settings.diagnostics().logLevel());
- if (settings.diagnostics().crashDumpsMax() != oldMaxDumps) {
+ if (settings.diagnostics().maxCoreDumps() != oldMaxDumps) {
m_OrganizerCore.cycleDiagnostics();
}
diff --git a/src/moapplication.cpp b/src/moapplication.cpp
index 24cafd05..bb7b4922 100644
--- a/src/moapplication.cpp
+++ b/src/moapplication.cpp
@@ -188,8 +188,6 @@ int MOApplication::doOneRun(SingleInstance& singleInstance)
const QString dataPath = currentInstance->directory();
setProperty("dataPath", dataPath);
- setExceptionHandlers();
-
if (!setLogDirectory(dataPath)) {
reportError("Failed to create log folder");
InstanceManager::singleton().clearCurrentInstance();
@@ -272,7 +270,7 @@ int MOApplication::runApplication(
// 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());
+ OrganizerCore::setGlobalCoreDumpType(settings.diagnostics().coreDumpType());
env::Environment env;
env.dump(settings);
diff --git a/src/organizercore.cpp b/src/organizercore.cpp
index d01aab96..f57903e2 100644
--- a/src/organizercore.cpp
+++ b/src/organizercore.cpp
@@ -76,8 +76,7 @@
using namespace MOShared;
using namespace MOBase;
-//static
-CrashDumpsType OrganizerCore::m_globalCrashDumpsType = CrashDumpsType::None;
+static env::CoreDumpTypes g_coreDumpType = env::CoreDumpTypes::Mini;
template
QStringList toStringList(InputIterator current, InputIterator end)
@@ -478,7 +477,7 @@ bool OrganizerCore::bootstrap()
m_Settings.paths().mods(),
m_Settings.paths().downloads(),
m_Settings.paths().overwrite(),
- QString::fromStdWString(crashDumpsPath())
+ QString::fromStdWString(getGlobalCoreDumpPath())
};
for (auto&& dir : dirs) {
@@ -497,14 +496,14 @@ bool OrganizerCore::bootstrap()
// log if there are any dmp files
const auto hasCrashDumps =
- !QDir(QString::fromStdWString(crashDumpsPath()))
+ !QDir(QString::fromStdWString(getGlobalCoreDumpPath()))
.entryList({"*.dmp"}, QDir::Files)
.empty();
if (hasCrashDumps) {
log::debug(
"there are crash dumps in '{}'",
- QString::fromStdWString(crashDumpsPath()));
+ QString::fromStdWString(getGlobalCoreDumpPath()));
}
return true;
@@ -528,13 +527,14 @@ void OrganizerCore::prepareVFS()
}
void OrganizerCore::updateVFSParams(
- log::Levels logLevel, CrashDumpsType crashDumpsType,
+ log::Levels logLevel, env::CoreDumpTypes coreDumpType,
const QString& crashDumpsPath,
std::chrono::seconds spawnDelay, QString executableBlacklist)
{
- setGlobalCrashDumpsType(crashDumpsType);
+ setGlobalCoreDumpType(coreDumpType);
+
m_USVFS.updateParams(
- logLevel, crashDumpsType, crashDumpsPath, spawnDelay, executableBlacklist);
+ logLevel, coreDumpType, crashDumpsPath, spawnDelay, executableBlacklist);
}
void OrganizerCore::setLogLevel(log::Levels level)
@@ -543,8 +543,8 @@ void OrganizerCore::setLogLevel(log::Levels level)
updateVFSParams(
m_Settings.diagnostics().logLevel(),
- m_Settings.diagnostics().crashDumpsType(),
- QString::fromStdWString(crashDumpsPath()),
+ m_Settings.diagnostics().coreDumpType(),
+ QString::fromStdWString(getGlobalCoreDumpPath()),
m_Settings.diagnostics().spawnDelay(),
m_Settings.executablesBlacklist());
@@ -553,8 +553,8 @@ void OrganizerCore::setLogLevel(log::Levels level)
bool OrganizerCore::cycleDiagnostics()
{
- const auto maxDumps = settings().diagnostics().crashDumpsMax();
- const auto path = QString::fromStdWString(crashDumpsPath());
+ const auto maxDumps = settings().diagnostics().maxCoreDumps();
+ const auto path = QString::fromStdWString(getGlobalCoreDumpPath());
if (maxDumps > 0) {
removeOldFiles(path, "*.dmp", maxDumps, QDir::Time|QDir::Reversed);
@@ -563,16 +563,26 @@ bool OrganizerCore::cycleDiagnostics()
return true;
}
-void OrganizerCore::setGlobalCrashDumpsType(CrashDumpsType type)
+env::CoreDumpTypes OrganizerCore::getGlobalCoreDumpType()
+{
+ return g_coreDumpType;
+}
+
+void OrganizerCore::setGlobalCoreDumpType(env::CoreDumpTypes type)
{
- m_globalCrashDumpsType = type;
+ g_coreDumpType = type;
}
-std::wstring OrganizerCore::crashDumpsPath() {
- return (
- qApp->property("dataPath").toString() + "/"
- + QString::fromStdWString(AppConfig::dumpsDir())
- ).toStdWString();
+std::wstring OrganizerCore::getGlobalCoreDumpPath()
+{
+ if (qApp) {
+ const auto dp = qApp->property("dataPath");
+ if (!dp.isNull()) {
+ return dp.toString().toStdWString() + L"/" + AppConfig::dumpsDir();
+ }
+ }
+
+ return {};
}
void OrganizerCore::setCurrentProfile(const QString &profileName)
diff --git a/src/organizercore.h b/src/organizercore.h
index 80b89a43..b566e626 100644
--- a/src/organizercore.h
+++ b/src/organizercore.h
@@ -13,6 +13,7 @@
#include "moshortcut.h"
#include "processrunner.h"
#include "uilocker.h"
+#include "envdump.h"
#include
#include
#include
@@ -277,17 +278,17 @@ public:
void prepareVFS();
void updateVFSParams(
- MOBase::log::Levels logLevel, CrashDumpsType crashDumpsType,
- const QString& crashDumpsPath, std::chrono::seconds spawnDelay,
+ MOBase::log::Levels logLevel, env::CoreDumpTypes coreDumpType,
+ const QString& coreDumpsPath, std::chrono::seconds spawnDelay,
QString executableBlacklist);
void setLogLevel(MOBase::log::Levels level);
bool cycleDiagnostics();
- static CrashDumpsType getGlobalCrashDumpsType() { return m_globalCrashDumpsType; }
- static void setGlobalCrashDumpsType(CrashDumpsType crashDumpsType);
- static std::wstring crashDumpsPath();
+ static env::CoreDumpTypes getGlobalCoreDumpType();
+ static void setGlobalCoreDumpType(env::CoreDumpTypes type);
+ static std::wstring getGlobalCoreDumpPath();
/**
* @brief Returns the name of all the mods in the priority order of the given profile.
@@ -487,8 +488,6 @@ private:
UsvfsConnector m_USVFS;
UILocker m_UILocker;
-
- static CrashDumpsType m_globalCrashDumpsType;
};
#endif // ORGANIZERCORE_H
diff --git a/src/settings.cpp b/src/settings.cpp
index 99b41e1f..a8ada6ba 100644
--- a/src/settings.cpp
+++ b/src/settings.cpp
@@ -2110,23 +2110,23 @@ void DiagnosticsSettings::setLootLogLevel(lootcli::LogLevels level)
set(m_Settings, "Settings", "loot_log_level", level);
}
-CrashDumpsType DiagnosticsSettings::crashDumpsType() const
+env::CoreDumpTypes DiagnosticsSettings::coreDumpType() const
{
- return get(m_Settings,
- "Settings", "crash_dumps_type", CrashDumpsType::Mini);
+ return get(m_Settings,
+ "Settings", "crash_dumps_type", env::CoreDumpTypes::Mini);
}
-void DiagnosticsSettings::setCrashDumpsType(CrashDumpsType type)
+void DiagnosticsSettings::setCoreDumpType(env::CoreDumpTypes type)
{
set(m_Settings, "Settings", "crash_dumps_type", type);
}
-int DiagnosticsSettings::crashDumpsMax() const
+int DiagnosticsSettings::maxCoreDumps() const
{
return get(m_Settings, "Settings", "crash_dumps_max", 5);
}
-void DiagnosticsSettings::setCrashDumpsMax(int n)
+void DiagnosticsSettings::setMaxCoreDumps(int n)
{
set(m_Settings, "Settings", "crash_dumps_max", n);
}
diff --git a/src/settings.h b/src/settings.h
index fc7789f0..df081c5c 100644
--- a/src/settings.h
+++ b/src/settings.h
@@ -21,6 +21,7 @@ along with Mod Organizer. If not, see .
#define SETTINGS_H
#include "loadmechanism.h"
+#include "envdump.h"
#include
#include
#include
@@ -651,13 +652,13 @@ public:
// crash dump type for both MO and usvfs
//
- CrashDumpsType crashDumpsType() const;
- void setCrashDumpsType(CrashDumpsType type);
+ env::CoreDumpTypes coreDumpType() const;
+ void setCoreDumpType(env::CoreDumpTypes type);
// maximum number of dump files keps, for both MO and usvfs
//
- int crashDumpsMax() const;
- void setCrashDumpsMax(int n);
+ int maxCoreDumps() const;
+ void setMaxCoreDumps(int n);
std::chrono::seconds spawnDelay() const;
void setSpawnDelay(std::chrono::seconds t);
diff --git a/src/settingsdialogdiagnostics.cpp b/src/settingsdialogdiagnostics.cpp
index 4ade6900..33175a66 100644
--- a/src/settingsdialogdiagnostics.cpp
+++ b/src/settingsdialogdiagnostics.cpp
@@ -13,7 +13,7 @@ DiagnosticsSettingsTab::DiagnosticsSettingsTab(Settings& s, SettingsDialog& d)
setLootLogLevel();
setCrashDumpTypesBox();
- ui->dumpsMaxEdit->setValue(settings().diagnostics().crashDumpsMax());
+ ui->dumpsMaxEdit->setValue(settings().diagnostics().maxCoreDumps());
QString logsPath = qApp->property("dataPath").toString()
+ "/" + QString::fromStdWString(AppConfig::logPath());
@@ -22,7 +22,7 @@ DiagnosticsSettingsTab::DiagnosticsSettingsTab(Settings& s, SettingsDialog& d)
ui->diagnosticsExplainedLabel->text()
.replace("LOGS_FULL_PATH", logsPath)
.replace("LOGS_DIR", QString::fromStdWString(AppConfig::logPath()))
- .replace("DUMPS_FULL_PATH", QString::fromStdWString(OrganizerCore::crashDumpsPath()))
+ .replace("DUMPS_FULL_PATH", QString::fromStdWString(OrganizerCore::getGlobalCoreDumpPath()))
.replace("DUMPS_DIR", QString::fromStdWString(AppConfig::dumpsDir()))
);
}
@@ -78,13 +78,13 @@ void DiagnosticsSettingsTab::setCrashDumpTypesBox()
ui->dumpsTypeBox->addItem(text, static_cast(type));
};
- add(QObject::tr("None"), CrashDumpsType::None);
- add(QObject::tr("Mini (recommended)"), CrashDumpsType::Mini);
- add(QObject::tr("Data"), CrashDumpsType::Data);
- add(QObject::tr("Full"), CrashDumpsType::Full);
+ add(QObject::tr("None"), env::CoreDumpTypes::None);
+ add(QObject::tr("Mini (recommended)"), env::CoreDumpTypes::Mini);
+ add(QObject::tr("Data"), env::CoreDumpTypes::Data);
+ add(QObject::tr("Full"), env::CoreDumpTypes::Full);
const auto current = static_cast(
- settings().diagnostics().crashDumpsType());
+ settings().diagnostics().coreDumpType());
for (int i=0; idumpsTypeBox->count(); ++i) {
if (ui->dumpsTypeBox->itemData(i) == current) {
@@ -99,10 +99,10 @@ void DiagnosticsSettingsTab::update()
settings().diagnostics().setLogLevel(
static_cast(ui->logLevelBox->currentData().toInt()));
- settings().diagnostics().setCrashDumpsType(
- static_cast(ui->dumpsTypeBox->currentData().toInt()));
+ settings().diagnostics().setCoreDumpType(
+ static_cast(ui->dumpsTypeBox->currentData().toInt()));
- settings().diagnostics().setCrashDumpsMax(ui->dumpsMaxEdit->value());
+ settings().diagnostics().setMaxCoreDumps(ui->dumpsMaxEdit->value());
settings().diagnostics().setLootLogLevel(
static_cast(ui->lootLogLevel->currentData().toInt()));
diff --git a/src/usvfsconnector.cpp b/src/usvfsconnector.cpp
index ed6e31ce..c8f2f1c4 100644
--- a/src/usvfsconnector.cpp
+++ b/src/usvfsconnector.cpp
@@ -107,17 +107,22 @@ LogLevel toUsvfsLogLevel(log::Levels level)
}
}
-CrashDumpsType crashDumpsType(int type)
+CrashDumpsType toUsvfsCrashDumpsType(env::CoreDumpTypes type)
{
- switch (static_cast(type)) {
- case CrashDumpsType::Mini:
- return CrashDumpsType::Mini;
- case CrashDumpsType::Data:
- return CrashDumpsType::Data;
- case CrashDumpsType::Full:
- return CrashDumpsType::Full;
- default:
- return CrashDumpsType::None;
+ switch (type)
+ {
+ case env::CoreDumpTypes::None:
+ return CrashDumpsType::None;
+
+ case env::CoreDumpTypes::Data:
+ return CrashDumpsType::Data;
+
+ case env::CoreDumpTypes::Full:
+ return CrashDumpsType::Full;
+
+ case env::CoreDumpTypes::Mini:
+ default:
+ return CrashDumpsType::Mini;
}
}
@@ -128,9 +133,9 @@ UsvfsConnector::UsvfsConnector()
const auto& s = Settings::instance();
const LogLevel logLevel = toUsvfsLogLevel(s.diagnostics().logLevel());
- const CrashDumpsType dumpType = s.diagnostics().crashDumpsType();
+ const auto dumpType = toUsvfsCrashDumpsType(s.diagnostics().coreDumpType());
const auto delay = duration_cast(s.diagnostics().spawnDelay());
- std::string dumpPath = MOShared::ToString(OrganizerCore::crashDumpsPath(), true);
+ std::string dumpPath = MOShared::ToString(OrganizerCore::getGlobalCoreDumpPath(), true);
usvfsParameters* params = usvfsCreateParameters();
@@ -224,7 +229,7 @@ void UsvfsConnector::updateMapping(const MappingType &mapping)
}
void UsvfsConnector::updateParams(
- MOBase::log::Levels logLevel, CrashDumpsType crashDumpsType,
+ MOBase::log::Levels logLevel, env::CoreDumpTypes coreDumpType,
const QString& crashDumpsPath, std::chrono::seconds spawnDelay,
QString executableBlacklist)
{
@@ -234,7 +239,7 @@ void UsvfsConnector::updateParams(
usvfsSetDebugMode(p, FALSE);
usvfsSetLogLevel(p, toUsvfsLogLevel(logLevel));
- usvfsSetCrashDumpType(p, crashDumpsType);
+ usvfsSetCrashDumpType(p, toUsvfsCrashDumpsType(coreDumpType));
usvfsSetCrashDumpPath(p, crashDumpsPath.toStdString().c_str());
usvfsSetProcessDelay(p, duration_cast(spawnDelay).count());
diff --git a/src/usvfsconnector.h b/src/usvfsconnector.h
index 5982778b..bf5d49ce 100644
--- a/src/usvfsconnector.h
+++ b/src/usvfsconnector.h
@@ -31,6 +31,7 @@ along with Mod Organizer. If not, see .
#include
#include
#include "executableinfo.h"
+#include "envdump.h"
class LogWorker : public QThread {
@@ -87,7 +88,7 @@ public:
void updateMapping(const MappingType &mapping);
void updateParams(
- MOBase::log::Levels logLevel, CrashDumpsType crashDumpsType,
+ MOBase::log::Levels logLevel, env::CoreDumpTypes coreDumpType,
const QString& crashDumpsPath, std::chrono::seconds spawnDelay,
QString executableBlacklist);
--
cgit v1.3.1
From dd5367f488de7cd312e53705ffc970a723951ca2 Mon Sep 17 00:00:00 2001
From: isanae <14251494+isanae@users.noreply.github.com>
Date: Sat, 7 Nov 2020 19:30:54 -0500
Subject: fixed AppConfig::logFileName so it can be used refactored
MOApplication so everything is in doOneRun()
---
src/loglist.cpp | 5 +-
src/moapplication.cpp | 335 ++++++++++++++++++++++++-----------------------
src/moapplication.h | 7 +-
src/shared/appconfig.inc | 2 +-
4 files changed, 179 insertions(+), 170 deletions(-)
(limited to 'src/moapplication.cpp')
diff --git a/src/loglist.cpp b/src/loglist.cpp
index fad4678c..8df21111 100644
--- a/src/loglist.cpp
+++ b/src/loglist.cpp
@@ -345,7 +345,10 @@ bool createAndMakeWritable(const std::wstring &subPath) {
bool setLogDirectory(const QString& dir)
{
- const auto logFile = dir + "/logs/mo_interface.log";
+ const auto logFile =
+ dir + "/" +
+ QString::fromStdWString(AppConfig::logPath()) + "/" +
+ QString::fromStdWString(AppConfig::logFileName());
if (!createAndMakeWritable(AppConfig::logPath())) {
return false;
diff --git a/src/moapplication.cpp b/src/moapplication.cpp
index bb7b4922..885abc37 100644
--- a/src/moapplication.cpp
+++ b/src/moapplication.cpp
@@ -164,27 +164,36 @@ int MOApplication::run(SingleInstance& singleInstance)
// when switching instances or changing some settings
for (;;)
{
- // resets things when MO is "restarted"
- resetForRestart();
+ try
+ {
+ // resets things when MO is "restarted"
+ resetForRestart();
- const auto r = doOneRun(singleInstance);
- if (r == RestartExitCode) {
- continue;
- }
+ const auto r = doOneRun(singleInstance);
+ if (r == RestartExitCode) {
+ continue;
+ }
- return r;
+ return r;
+ }
+ catch (const std::exception &e)
+ {
+ reportError(e.what());
+ return 1;
+ }
}
}
int MOApplication::doOneRun(SingleInstance& singleInstance)
{
- TimeThis tt("doOneRun() to runApplication()");
-
+ // figuring out the current instance
auto currentInstance = getCurrentInstance();
if (!currentInstance) {
return 1;
}
+ // first time the data path is available, set the global property and log
+ // directory, then log a bunch of debug stuff
const QString dataPath = currentInstance->directory();
setProperty("dataPath", dataPath);
@@ -196,57 +205,20 @@ int MOApplication::doOneRun(SingleInstance& singleInstance)
log::debug("command line: '{}'", QString::fromWCharArray(GetCommandLineW()));
- tt.stop();
-
- return runApplication(singleInstance, dataPath, *currentInstance);
-}
-
-std::optional MOApplication::getCurrentInstance()
-{
- auto& m = InstanceManager::singleton();
- auto currentInstance = m.currentInstance();
-
- if (!currentInstance)
- {
- currentInstance = selectInstance();
- }
- 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();
- }
- }
-
- return 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);
+ if (singleInstance.secondary()) {
+ log::debug("another instance of MO is running but --multiple was given");
+ }
+ log::info("data path: {}", currentInstance->directory());
log::info("working directory: {}", QDir::currentPath());
+
+ // deleting old files, only for the main instance
if (!singleInstance.secondary()) {
purgeOldFiles();
}
@@ -254,155 +226,192 @@ int MOApplication::runApplication(
QWindowsWindowFunctions::setWindowActivationBehavior(
QWindowsWindowFunctions::AlwaysActivateWindow);
- try
- {
- Settings settings(
- dataPath + "/" + QString::fromStdWString(AppConfig::iniFileName()),
- true);
- log::getDefault().setLevel(settings.diagnostics().logLevel());
+ // loading settings
+ Settings settings(currentInstance->iniPath(), true);
+ log::getDefault().setLevel(settings.diagnostics().logLevel());
+ log::debug("using ini at '{}'", settings.filename());
- log::debug("using ini at '{}'", settings.filename());
+ OrganizerCore::setGlobalCoreDumpType(settings.diagnostics().coreDumpType());
- 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::setGlobalCoreDumpType(settings.diagnostics().coreDumpType());
+ // logging and checking
+ env::Environment env;
+ env.dump(settings);
+ settings.dump();
+ sanity::checkEnvironment(env);
- 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);
+ });
- 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;
+ // this must outlive `organizer`
+ std::unique_ptr pluginContainer;
- log::debug("initializing nexus interface");
- NexusInterface ni(&settings);
+ // nexus interface
+ 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;
- }
+ // organizer core
+ 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();
+ // plugins
+ log::debug("initializing plugins");
+ pluginContainer = std::make_unique(&organizer);
+ pluginContainer->loadPlugins();
- for (;;)
- {
- const auto setupResult = setupInstance(currentInstance, *pluginContainer);
+ // instance
+ if (auto r=setupInstanceLoop(*currentInstance, *pluginContainer)) {
+ return *r;
+ }
- 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");
+ }
- if (currentInstance.isPortable()) {
- log::debug("this is a portable instance");
- }
+ sanity::checkPaths(*currentInstance->gamePlugin(), settings);
- sanity::checkPaths(*currentInstance.gamePlugin(), settings);
+ // setting up organizer core
+ organizer.setManagedGame(currentInstance->gamePlugin());
+ organizer.createDefaultProfile();
- 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());
+
+ // checking command line
+ if (auto r=m_cl.setupCore(organizer)) {
+ return *r;
+ }
- 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());
+ // show splash
+ MOSplash splash(
+ settings, currentInstance->directory(), currentInstance->gamePlugin());
+ // start an api check
+ QString apiKey;
+ if (GlobalSettings::nexusApiKey(apiKey)) {
+ ni.getAccessManager()->apiCheck(apiKey);
+ }
- CategoryFactory::instance().loadCategories();
- organizer.updateExecutablesList();
- organizer.updateModInfoFromDisc();
+ // tutorials
+ log::debug("initializing tutorials");
+ TutorialManager::init(
+ qApp->applicationDirPath() + "/"
+ + QString::fromStdWString(AppConfig::tutorialsPath()) + "/",
+ &organizer);
+
+ // styling
+ if (!setStyleFile(settings.interface().styleName().value_or(""))) {
+ // disable invalid stylesheet
+ settings.interface().setStyleName("");
+ }
- organizer.setCurrentProfile(currentInstance.profileName());
- if (auto r=m_cl.setupCore(organizer)) {
- return *r;
- }
+ int res = 1;
+
+ {
+ MainWindow mainWindow(settings, organizer, *pluginContainer);
- MOSplash splash(settings, dataPath, currentInstance.gamePlugin());
+ // qt resets the thread name somewhere when creating the main window
+ MOShared::SetThisThreadName("main");
- QString apiKey;
- if (GlobalSettings::nexusApiKey(apiKey)) {
- ni.getAccessManager()->apiCheck(apiKey);
- }
+ // the nexus interface can show dialogs, make sure they're parented to the
+ // main window
+ ni.getAccessManager()->setTopLevelWidget(&mainWindow);
- log::debug("initializing tutorials");
- TutorialManager::init(
- qApp->applicationDirPath() + "/"
- + QString::fromStdWString(AppConfig::tutorialsPath()) + "/",
- &organizer);
+ QObject::connect(&mainWindow, SIGNAL(styleChanged(QString)), this,
+ SLOT(setStyleFile(QString)));
- if (!setStyleFile(settings.interface().styleName().value_or(""))) {
- // disable invalid stylesheet
- settings.interface().setStyleName("");
- }
+ QObject::connect(&singleInstance, SIGNAL(messageSent(QString)), &organizer,
+ SLOT(externalMessage(QString)));
- int res = 1;
- {
- // scope to control lifetime of mainwindow
- // set up main window and its data structures
- MainWindow mainWindow(settings, organizer, *pluginContainer);
+ log::debug("displaying main window");
+ mainWindow.show();
+ mainWindow.activateWindow();
+ splash.close();
- // qt resets the thread name somewhere when creating the main window
- MOShared::SetThisThreadName("main");
+ res = exec();
+ mainWindow.close();
- ni.getAccessManager()->setTopLevelWidget(&mainWindow);
+ // main window is about to be destroyed
+ ni.getAccessManager()->setTopLevelWidget(nullptr);
+ }
- QObject::connect(&mainWindow, SIGNAL(styleChanged(QString)), this,
- SLOT(setStyleFile(QString)));
- QObject::connect(&singleInstance, SIGNAL(messageSent(QString)), &organizer,
- SLOT(externalMessage(QString)));
+ // reset geometry if the flag was set from the settings dialog
+ settings.geometry().resetIfNeeded();
- log::debug("displaying main window");
- mainWindow.show();
- mainWindow.activateWindow();
+ return res;
+}
- splash.close();
+std::optional MOApplication::getCurrentInstance()
+{
+ auto& m = InstanceManager::singleton();
+ auto currentInstance = m.currentInstance();
- tt.stop();
+ if (!currentInstance)
+ {
+ currentInstance = selectInstance();
+ }
+ else
+ {
+ if (!QDir(currentInstance->directory()).exists()) {
+ // the previously used instance doesn't exist anymore
- res = exec();
- mainWindow.close();
+ 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()));
+ }
- ni.getAccessManager()->setTopLevelWidget(nullptr);
+ currentInstance = selectInstance();
}
-
- settings.geometry().resetIfNeeded();
- return res;
}
- catch (const std::exception &e)
+
+ return currentInstance;
+}
+
+std::optional MOApplication::setupInstanceLoop(
+ Instance& currentInstance, PluginContainer& pc)
+{
+ for (;;)
{
- reportError(e.what());
- }
+ const auto setupResult = setupInstance(currentInstance, pc);
- return 1;
+ if (setupResult == SetupInstanceResults::Okay) {
+ return {};
+ } else if (setupResult == SetupInstanceResults::TryAgain) {
+ continue;
+ } else if (setupResult == SetupInstanceResults::SelectAnother) {
+ InstanceManager::singleton().clearCurrentInstance();
+ return RestartExitCode;
+ } else {
+ return 1;
+ }
+ }
}
void MOApplication::purgeOldFiles()
diff --git a/src/moapplication.h b/src/moapplication.h
index 8cbb5f28..7423c897 100644
--- a/src/moapplication.h
+++ b/src/moapplication.h
@@ -26,6 +26,7 @@ along with Mod Organizer. If not, see .
class Settings;
class SingleInstance;
class Instance;
+class PluginContainer;
namespace MOBase { class IPluginGame; }
namespace cl { class CommandLine; }
@@ -57,11 +58,7 @@ private:
int doOneRun(SingleInstance& singleInstance);
std::optional getCurrentInstance();
-
- int runApplication(
- SingleInstance& singleInstance,
- const QString &dataPath, Instance& currentInstance);
-
+ std::optional setupInstanceLoop(Instance& currentInstance, PluginContainer& pc);
void purgeOldFiles();
void resetForRestart();
};
diff --git a/src/shared/appconfig.inc b/src/shared/appconfig.inc
index 807f1d69..5839c2f4 100644
--- a/src/shared/appconfig.inc
+++ b/src/shared/appconfig.inc
@@ -11,7 +11,7 @@ APPPARAM(std::wstring, logPath, L"logs")
APPPARAM(std::wstring, dumpsDir, L"crashDumps")
APPPARAM(std::wstring, defaultProfileName, L"Default")
APPPARAM(std::wstring, profileTweakIni, L"profile_tweaks.ini")
-APPPARAM(std::wstring, logFileName, L"ModOrganizer.log")
+APPPARAM(std::wstring, logFileName, L"mo_interface.log")
APPPARAM(std::wstring, iniFileName, L"ModOrganizer.ini")
APPPARAM(std::wstring, proxyDLLTarget, L"steam_api.dll")
APPPARAM(std::wstring, proxyDLLOrig, L"steam_api_orig.dll") // needs to be identical to the value used in proxydll-project
--
cgit v1.3.1
From 54bf7e1fa230c78e98f429559b51a6be42f29e4a Mon Sep 17 00:00:00 2001
From: isanae <14251494+isanae@users.noreply.github.com>
Date: Sun, 8 Nov 2020 21:58:02 -0500
Subject: timings
---
src/main.cpp | 4 ++++
src/moapplication.cpp | 26 ++++++++++++++++++++++++++
2 files changed, 30 insertions(+)
(limited to 'src/moapplication.cpp')
diff --git a/src/main.cpp b/src/main.cpp
index ad074501..8f99cf1d 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -17,6 +17,8 @@ int forwardToPrimary(SingleInstance& instance, const cl::CommandLine& cl);
int main(int argc, char *argv[])
{
+ TimeThis tt("main()");
+
MOShared::SetThisThreadName("main");
setExceptionHandlers();
@@ -35,6 +37,8 @@ int main(int argc, char *argv[])
return forwardToPrimary(instance, cl);
}
+ tt.stop();
+
return app.run(instance);
}
diff --git a/src/moapplication.cpp b/src/moapplication.cpp
index 885abc37..3f17e436 100644
--- a/src/moapplication.cpp
+++ b/src/moapplication.cpp
@@ -135,6 +135,8 @@ void addDllsToPath()
MOApplication::MOApplication(cl::CommandLine& cl, int& argc, char** argv)
: QApplication(argc, argv), m_cl(cl)
{
+ TimeThis tt("MOApplication()");
+
connect(&m_StyleWatcher, &QFileSystemWatcher::fileChanged, [&](auto&& file){
log::debug("style file '{}' changed, reloading", file);
updateStyle(file);
@@ -147,6 +149,8 @@ MOApplication::MOApplication(cl::CommandLine& cl, int& argc, char** argv)
int MOApplication::run(SingleInstance& singleInstance)
{
+ TimeThis tt("MOApplication run() to doOneRun()");
+
auto& m = InstanceManager::singleton();
if (m_cl.instance())
@@ -169,6 +173,7 @@ int MOApplication::run(SingleInstance& singleInstance)
// resets things when MO is "restarted"
resetForRestart();
+ tt.stop();
const auto r = doOneRun(singleInstance);
if (r == RestartExitCode) {
continue;
@@ -186,6 +191,8 @@ int MOApplication::run(SingleInstance& singleInstance)
int MOApplication::doOneRun(SingleInstance& singleInstance)
{
+ TimeThis tt("MOApplication::doOneRun() instances");
+
// figuring out the current instance
auto currentInstance = getCurrentInstance();
if (!currentInstance) {
@@ -218,6 +225,8 @@ int MOApplication::doOneRun(SingleInstance& singleInstance)
log::info("working directory: {}", QDir::currentPath());
+ tt.start("MOApplication::doOneRun() settings");
+
// deleting old files, only for the main instance
if (!singleInstance.secondary()) {
purgeOldFiles();
@@ -235,6 +244,8 @@ int MOApplication::doOneRun(SingleInstance& singleInstance)
OrganizerCore::setGlobalCoreDumpType(settings.diagnostics().coreDumpType());
+ tt.start("MOApplication::doOneRun() log and checks");
+
// logging and checking
env::Environment env;
env.dump(settings);
@@ -251,11 +262,14 @@ int MOApplication::doOneRun(SingleInstance& singleInstance)
std::unique_ptr pluginContainer;
// nexus interface
+ tt.start("MOApplication::doOneRun() NexusInterface");
log::debug("initializing nexus interface");
NexusInterface ni(&settings);
// organizer core
+ tt.start("MOApplication::doOneRun() OrganizerCore");
log::debug("initializing core");
+
OrganizerCore organizer(settings);
if (!organizer.bootstrap()) {
reportError("failed to set up data paths");
@@ -264,7 +278,9 @@ int MOApplication::doOneRun(SingleInstance& singleInstance)
}
// plugins
+ tt.start("MOApplication::doOneRun() plugins");
log::debug("initializing plugins");
+
pluginContainer = std::make_unique(&organizer);
pluginContainer->loadPlugins();
@@ -277,6 +293,8 @@ int MOApplication::doOneRun(SingleInstance& singleInstance)
log::debug("this is a portable instance");
}
+ tt.start("MOApplication::doOneRun() OrganizerCore setup");
+
sanity::checkPaths(*currentInstance->gamePlugin(), settings);
// setting up organizer core
@@ -298,14 +316,19 @@ int MOApplication::doOneRun(SingleInstance& singleInstance)
organizer.setCurrentProfile(currentInstance->profileName());
// checking command line
+ tt.start("MOApplication::doOneRun() command line");
if (auto r=m_cl.setupCore(organizer)) {
return *r;
}
// show splash
+ tt.start("MOApplication::doOneRun() splash");
+
MOSplash splash(
settings, currentInstance->directory(), currentInstance->gamePlugin());
+ tt.start("MOApplication::doOneRun() finishing");
+
// start an api check
QString apiKey;
if (GlobalSettings::nexusApiKey(apiKey)) {
@@ -329,6 +352,7 @@ int MOApplication::doOneRun(SingleInstance& singleInstance)
int res = 1;
{
+ tt.start("MOApplication::doOneRun() MainWindow setup");
MainWindow mainWindow(settings, organizer, *pluginContainer);
// qt resets the thread name somewhere when creating the main window
@@ -350,6 +374,8 @@ int MOApplication::doOneRun(SingleInstance& singleInstance)
mainWindow.activateWindow();
splash.close();
+ tt.stop();
+
res = exec();
mainWindow.close();
--
cgit v1.3.1
From a5469ae4e0668c36e4bf36bf7395fa25073b0bc6 Mon Sep 17 00:00:00 2001
From: isanae <14251494+isanae@users.noreply.github.com>
Date: Sun, 8 Nov 2020 22:07:15 -0500
Subject: renamed SingleInstance to MOMultiProcess rewrote some comments to
avoid using "instance"
---
src/commandline.cpp | 5 ++---
src/main.cpp | 16 ++++++++--------
src/moapplication.cpp | 12 ++++++------
src/moapplication.h | 6 +++---
src/singleinstance.cpp | 36 ++++++++----------------------------
src/singleinstance.h | 48 ++++++++++++++----------------------------------
6 files changed, 41 insertions(+), 82 deletions(-)
(limited to 'src/moapplication.cpp')
diff --git a/src/commandline.cpp b/src/commandline.cpp
index 3d0e901d..fd2fcb51 100644
--- a/src/commandline.cpp
+++ b/src/commandline.cpp
@@ -144,7 +144,8 @@ std::optional CommandLine::run(const std::wstring& line)
// the first word on the command line is not a valid command, try the other
- // stuff; this is handled in main.cpp
+ // stuff; this is used in setupCore() below when called from
+ // MOApplication::doOneRun()
// look for help
if (m_vm.count("help")) {
@@ -202,8 +203,6 @@ std::optional CommandLine::run(const std::wstring& line)
std::optional CommandLine::setupCore(OrganizerCore& organizer) const
{
- // if we have a command line parameter, it is either a nxm link or
- // a binary to start
if (m_shortcut.isValid()) {
if (m_shortcut.hasExecutable()) {
try {
diff --git a/src/main.cpp b/src/main.cpp
index 8f99cf1d..440489d3 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -13,7 +13,7 @@ using namespace MOBase;
thread_local LPTOP_LEVEL_EXCEPTION_FILTER g_prevExceptionFilter = nullptr;
thread_local std::terminate_handler g_prevTerminateHandler = nullptr;
-int forwardToPrimary(SingleInstance& instance, const cl::CommandLine& cl);
+int forwardToPrimary(MOMultiProcess& multiProcess, const cl::CommandLine& cl);
int main(int argc, char *argv[])
{
@@ -32,22 +32,22 @@ int main(int argc, char *argv[])
QApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
MOApplication app(cl, argc, argv);
- SingleInstance instance(cl.multiple());
- if (instance.ephemeral()) {
- return forwardToPrimary(instance, cl);
+ MOMultiProcess multiProcess(cl.multiple());
+ if (multiProcess.ephemeral()) {
+ return forwardToPrimary(multiProcess, cl);
}
tt.stop();
- return app.run(instance);
+ return app.run(multiProcess);
}
-int forwardToPrimary(SingleInstance& instance, const cl::CommandLine& cl)
+int forwardToPrimary(MOMultiProcess& multiProcess, const cl::CommandLine& cl)
{
if (cl.shortcut().isValid()) {
- instance.sendMessage(cl.shortcut().toString());
+ multiProcess.sendMessage(cl.shortcut().toString());
} else if (cl.nxmLink()) {
- instance.sendMessage(*cl.nxmLink());
+ multiProcess.sendMessage(*cl.nxmLink());
} else {
QMessageBox::information(
nullptr, QObject::tr("Mod Organizer"),
diff --git a/src/moapplication.cpp b/src/moapplication.cpp
index 3f17e436..db559421 100644
--- a/src/moapplication.cpp
+++ b/src/moapplication.cpp
@@ -147,7 +147,7 @@ MOApplication::MOApplication(cl::CommandLine& cl, int& argc, char** argv)
addDllsToPath();
}
-int MOApplication::run(SingleInstance& singleInstance)
+int MOApplication::run(MOMultiProcess& multiProcess)
{
TimeThis tt("MOApplication run() to doOneRun()");
@@ -174,7 +174,7 @@ int MOApplication::run(SingleInstance& singleInstance)
resetForRestart();
tt.stop();
- const auto r = doOneRun(singleInstance);
+ const auto r = doOneRun(multiProcess);
if (r == RestartExitCode) {
continue;
}
@@ -189,7 +189,7 @@ int MOApplication::run(SingleInstance& singleInstance)
}
}
-int MOApplication::doOneRun(SingleInstance& singleInstance)
+int MOApplication::doOneRun(MOMultiProcess& multiProcess)
{
TimeThis tt("MOApplication::doOneRun() instances");
@@ -217,7 +217,7 @@ int MOApplication::doOneRun(SingleInstance& singleInstance)
createVersionInfo().displayString(3), GITID,
QCoreApplication::applicationDirPath(), MOShared::getUsvfsVersionString());
- if (singleInstance.secondary()) {
+ if (multiProcess.secondary()) {
log::debug("another instance of MO is running but --multiple was given");
}
@@ -228,7 +228,7 @@ int MOApplication::doOneRun(SingleInstance& singleInstance)
tt.start("MOApplication::doOneRun() settings");
// deleting old files, only for the main instance
- if (!singleInstance.secondary()) {
+ if (!multiProcess.secondary()) {
purgeOldFiles();
}
@@ -365,7 +365,7 @@ int MOApplication::doOneRun(SingleInstance& singleInstance)
QObject::connect(&mainWindow, SIGNAL(styleChanged(QString)), this,
SLOT(setStyleFile(QString)));
- QObject::connect(&singleInstance, SIGNAL(messageSent(QString)), &organizer,
+ QObject::connect(&multiProcess, SIGNAL(messageSent(QString)), &organizer,
SLOT(externalMessage(QString)));
diff --git a/src/moapplication.h b/src/moapplication.h
index 7423c897..91b8023a 100644
--- a/src/moapplication.h
+++ b/src/moapplication.h
@@ -24,7 +24,7 @@ along with Mod Organizer. If not, see .
#include
class Settings;
-class SingleInstance;
+class MOMultiProcess;
class Instance;
class PluginContainer;
@@ -40,7 +40,7 @@ public:
// sets up everything, creates the main window and runs it
//
- int run(SingleInstance& si);
+ int run(MOMultiProcess& multiProcess);
virtual bool notify(QObject* receiver, QEvent* event);
@@ -55,7 +55,7 @@ private:
QString m_DefaultStyle;
cl::CommandLine& m_cl;
- int doOneRun(SingleInstance& singleInstance);
+ int doOneRun(MOMultiProcess& multiProcess);
std::optional getCurrentInstance();
std::optional setupInstanceLoop(Instance& currentInstance, PluginContainer& pc);
diff --git a/src/singleinstance.cpp b/src/singleinstance.cpp
index bd7ccc43..401381fd 100644
--- a/src/singleinstance.cpp
+++ b/src/singleinstance.cpp
@@ -1,22 +1,3 @@
-/*
-Copyright (C) 2012 Sebastian Herbord. All rights reserved.
-
-This file is part of Mod Organizer.
-
-Mod Organizer is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-Mod Organizer is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with Mod Organizer. If not, see .
-*/
-
#include "singleinstance.h"
#include "utility.h"
#include
@@ -28,7 +9,7 @@ static const int s_Timeout = 5000;
using MOBase::reportError;
-SingleInstance::SingleInstance(bool allowMultiple, QObject *parent) :
+MOMultiProcess::MOMultiProcess(bool allowMultiple, QObject *parent) :
QObject(parent), m_Ephemeral(false), m_OwnsSM(false)
{
m_SharedMem.setKey(s_Key);
@@ -58,7 +39,7 @@ SingleInstance::SingleInstance(bool allowMultiple, QObject *parent) :
}
-void SingleInstance::sendMessage(const QString &message)
+void MOMultiProcess::sendMessage(const QString &message)
{
if (m_OwnsSM) {
// nobody there to receive the message
@@ -72,19 +53,19 @@ void SingleInstance::sendMessage(const QString &message)
Sleep(250);
}
- // other instance may be just starting up
+ // other process may be just starting up
socket.connectToServer(s_Key, QIODevice::WriteOnly);
connected = socket.waitForConnected(s_Timeout);
}
if (!connected) {
- reportError(tr("failed to connect to running instance: %1").arg(socket.errorString()));
+ reportError(tr("failed to connect to running process: %1").arg(socket.errorString()));
return;
}
socket.write(message.toUtf8());
if (!socket.waitForBytesWritten(s_Timeout)) {
- reportError(tr("failed to communicate with running instance: %1").arg(socket.errorString()));
+ reportError(tr("failed to communicate with running process: %1").arg(socket.errorString()));
return;
}
@@ -92,8 +73,7 @@ void SingleInstance::sendMessage(const QString &message)
socket.waitForDisconnected();
}
-
-void SingleInstance::receiveMessage()
+void MOMultiProcess::receiveMessage()
{
QLocalSocket *socket = m_Server.nextPendingConnection();
if (!socket) {
@@ -108,10 +88,10 @@ void SingleInstance::receiveMessage()
if (av <= 0) {
MOBase::log::error(
- "failed to receive data from secondary instance: {}",
+ "failed to receive data from secondary process: {}",
socket->errorString());
- reportError(tr("failed to receive data from secondary instance: %1").arg(socket->errorString()));
+ reportError(tr("failed to receive data from secondary process: %1").arg(socket->errorString()));
return;
}
}
diff --git a/src/singleinstance.h b/src/singleinstance.h
index 5f6c3633..810e63d2 100644
--- a/src/singleinstance.h
+++ b/src/singleinstance.h
@@ -1,24 +1,5 @@
-/*
-Copyright (C) 2012 Sebastian Herbord. All rights reserved.
-
-This file is part of Mod Organizer.
-
-Mod Organizer is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-Mod Organizer is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with Mod Organizer. If not, see .
-*/
-
-#ifndef SINGLEINSTANCE_H
-#define SINGLEINSTANCE_H
+#ifndef MODORGANIZER_MOMULTIPROCESS_INCLUDED
+#define MODORGANIZER_MOMULTIPROCESS_INCLUDED
#include
#include
@@ -26,30 +7,29 @@ along with Mod Organizer. If not, see .
/**
- * used to ensure only a single instance of Mod Organizer is started and to
- * allow ephemeral instances to send messages to the primary (visible) one.
- * This way, other instances can start a download in the primary one
+ * used to ensure only a single process of Mod Organizer is started and to
+ * allow ephemeral processes to send messages to the primary (visible) one.
+ * This way, other processes can start a download in the primary one
**/
-class SingleInstance : public QObject
+class MOMultiProcess : public QObject
{
-
Q_OBJECT
public:
- // `allowMultiple`: if another instance is running, run this one
+ // `allowMultiple`: if another process is running, run this one
// disconnected from the shared memory
- explicit SingleInstance(bool allowMultiple, QObject *parent = 0);
+ explicit MOMultiProcess(bool allowMultiple, QObject *parent = 0);
/**
- * @return true if this instance's job is to forward data to the primary
- * instance through shared memory
+ * @return true if this process's job is to forward data to the primary
+ * process through shared memory
**/
bool ephemeral() const
{
return m_Ephemeral;
}
- // returns true if this is not the primary instance, but was allowed because
+ // returns true if this is not the primary process, but was allowed because
// of the AllowMultiple flag
//
bool secondary() const
@@ -58,7 +38,7 @@ public:
}
/**
- * send a message to the primary instance. This can be used to transmit download urls
+ * send a message to the primary process. This can be used to transmit download urls
*
* @param message message to send
**/
@@ -67,7 +47,7 @@ public:
signals:
/**
- * @brief emitted when an ephemeral instance has sent a message (to us)
+ * @brief emitted when an ephemeral process has sent a message (to us)
*
* @param message the message we received
**/
@@ -87,4 +67,4 @@ private:
};
-#endif // SINGLEINSTANCE_H
+#endif // MODORGANIZER_MOMULTIPROCESS_INCLUDED
--
cgit v1.3.1
From d7ae42d3775f88d5cd63fa2f8860bd31e18f981e Mon Sep 17 00:00:00 2001
From: isanae <14251494+isanae@users.noreply.github.com>
Date: Sun, 8 Nov 2020 22:09:42 -0500
Subject: renamed singleinstance.h/cpp to multiprocess.h/cpp
---
src/CMakeLists.txt | 2 +-
src/main.cpp | 2 +-
src/moapplication.cpp | 2 +-
src/multiprocess.cpp | 102 +++++++++++++++++++++++++++++++++++++++++++++++++
src/multiprocess.h | 70 +++++++++++++++++++++++++++++++++
src/singleinstance.cpp | 102 -------------------------------------------------
src/singleinstance.h | 70 ---------------------------------
7 files changed, 175 insertions(+), 175 deletions(-)
create mode 100644 src/multiprocess.cpp
create mode 100644 src/multiprocess.h
delete mode 100644 src/singleinstance.cpp
delete mode 100644 src/singleinstance.h
(limited to 'src/moapplication.cpp')
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 30614e59..bb4b151f 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -15,9 +15,9 @@ add_filter(NAME src/application GROUPS
main
moapplication
moshortcut
+ multiprocess
sanitychecks
selfupdater
- singleinstance
)
add_filter(NAME src/browser GROUPS
diff --git a/src/main.cpp b/src/main.cpp
index 440489d3..554ed006 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -1,4 +1,4 @@
-#include "singleinstance.h"
+#include "multiprocess.h"
#include "loglist.h"
#include "moapplication.h"
#include "organizercore.h"
diff --git a/src/moapplication.cpp b/src/moapplication.cpp
index db559421..9139acbb 100644
--- a/src/moapplication.cpp
+++ b/src/moapplication.cpp
@@ -25,7 +25,7 @@ along with Mod Organizer. If not, see .
#include "organizercore.h"
#include "thread_utils.h"
#include "loglist.h"
-#include "singleinstance.h"
+#include "multiprocess.h"
#include "nexusinterface.h"
#include "nxmaccessmanager.h"
#include "tutorialmanager.h"
diff --git a/src/multiprocess.cpp b/src/multiprocess.cpp
new file mode 100644
index 00000000..4ce58718
--- /dev/null
+++ b/src/multiprocess.cpp
@@ -0,0 +1,102 @@
+#include "multiprocess.h"
+#include "utility.h"
+#include
+#include
+#include
+
+static const char s_Key[] = "mo-43d1a3ad-eeb0-4818-97c9-eda5216c29b5";
+static const int s_Timeout = 5000;
+
+using MOBase::reportError;
+
+MOMultiProcess::MOMultiProcess(bool allowMultiple, QObject *parent) :
+ QObject(parent), m_Ephemeral(false), m_OwnsSM(false)
+{
+ m_SharedMem.setKey(s_Key);
+
+ if (!m_SharedMem.create(1)) {
+ if (m_SharedMem.error() == QSharedMemory::AlreadyExists) {
+ if (!allowMultiple) {
+ m_SharedMem.attach();
+ m_Ephemeral = true;
+ }
+ }
+
+ if ((m_SharedMem.error() != QSharedMemory::NoError) &&
+ (m_SharedMem.error() != QSharedMemory::AlreadyExists)) {
+ throw MOBase::MyException(tr("SHM error: %1").arg(m_SharedMem.errorString()));
+ }
+ } else {
+ m_OwnsSM = true;
+ }
+
+ if (m_OwnsSM) {
+ connect(&m_Server, SIGNAL(newConnection()), this, SLOT(receiveMessage()), Qt::QueuedConnection);
+ // has to be called before listen
+ m_Server.setSocketOptions(QLocalServer::WorldAccessOption);
+ m_Server.listen(s_Key);
+ }
+}
+
+
+void MOMultiProcess::sendMessage(const QString &message)
+{
+ if (m_OwnsSM) {
+ // nobody there to receive the message
+ return;
+ }
+ QLocalSocket socket(this);
+
+ bool connected = false;
+ for(int i = 0; i < 2 && !connected; ++i) {
+ if (i > 0) {
+ Sleep(250);
+ }
+
+ // other process may be just starting up
+ socket.connectToServer(s_Key, QIODevice::WriteOnly);
+ connected = socket.waitForConnected(s_Timeout);
+ }
+
+ if (!connected) {
+ reportError(tr("failed to connect to running process: %1").arg(socket.errorString()));
+ return;
+ }
+
+ socket.write(message.toUtf8());
+ if (!socket.waitForBytesWritten(s_Timeout)) {
+ reportError(tr("failed to communicate with running process: %1").arg(socket.errorString()));
+ return;
+ }
+
+ socket.disconnectFromServer();
+ socket.waitForDisconnected();
+}
+
+void MOMultiProcess::receiveMessage()
+{
+ QLocalSocket *socket = m_Server.nextPendingConnection();
+ if (!socket) {
+ return;
+ }
+
+ if (!socket->waitForReadyRead(s_Timeout)) {
+ // check if there are bytes available; if so, it probably means the data was
+ // already received by the time waitForReadyRead() was called and the
+ // connection has been closed
+ const auto av = socket->bytesAvailable();
+
+ if (av <= 0) {
+ MOBase::log::error(
+ "failed to receive data from secondary process: {}",
+ socket->errorString());
+
+ reportError(tr("failed to receive data from secondary process: %1").arg(socket->errorString()));
+ return;
+ }
+ }
+
+ QString message = QString::fromUtf8(socket->readAll().constData());
+ emit messageSent(message);
+ socket->disconnectFromServer();
+}
diff --git a/src/multiprocess.h b/src/multiprocess.h
new file mode 100644
index 00000000..810e63d2
--- /dev/null
+++ b/src/multiprocess.h
@@ -0,0 +1,70 @@
+#ifndef MODORGANIZER_MOMULTIPROCESS_INCLUDED
+#define MODORGANIZER_MOMULTIPROCESS_INCLUDED
+
+#include
+#include
+#include
+
+
+/**
+ * used to ensure only a single process of Mod Organizer is started and to
+ * allow ephemeral processes to send messages to the primary (visible) one.
+ * This way, other processes can start a download in the primary one
+ **/
+class MOMultiProcess : public QObject
+{
+ Q_OBJECT
+
+public:
+ // `allowMultiple`: if another process is running, run this one
+ // disconnected from the shared memory
+ explicit MOMultiProcess(bool allowMultiple, QObject *parent = 0);
+
+ /**
+ * @return true if this process's job is to forward data to the primary
+ * process through shared memory
+ **/
+ bool ephemeral() const
+ {
+ return m_Ephemeral;
+ }
+
+ // returns true if this is not the primary process, but was allowed because
+ // of the AllowMultiple flag
+ //
+ bool secondary() const
+ {
+ return !m_Ephemeral && !m_OwnsSM;
+ }
+
+ /**
+ * send a message to the primary process. This can be used to transmit download urls
+ *
+ * @param message message to send
+ **/
+ void sendMessage(const QString &message);
+
+signals:
+
+ /**
+ * @brief emitted when an ephemeral process has sent a message (to us)
+ *
+ * @param message the message we received
+ **/
+ void messageSent(const QString &message);
+
+public slots:
+
+private slots:
+
+ void receiveMessage();
+
+private:
+ bool m_Ephemeral;
+ bool m_OwnsSM;
+ QSharedMemory m_SharedMem;
+ QLocalServer m_Server;
+
+};
+
+#endif // MODORGANIZER_MOMULTIPROCESS_INCLUDED
diff --git a/src/singleinstance.cpp b/src/singleinstance.cpp
deleted file mode 100644
index 401381fd..00000000
--- a/src/singleinstance.cpp
+++ /dev/null
@@ -1,102 +0,0 @@
-#include "singleinstance.h"
-#include "utility.h"
-#include
-#include
-#include
-
-static const char s_Key[] = "mo-43d1a3ad-eeb0-4818-97c9-eda5216c29b5";
-static const int s_Timeout = 5000;
-
-using MOBase::reportError;
-
-MOMultiProcess::MOMultiProcess(bool allowMultiple, QObject *parent) :
- QObject(parent), m_Ephemeral(false), m_OwnsSM(false)
-{
- m_SharedMem.setKey(s_Key);
-
- if (!m_SharedMem.create(1)) {
- if (m_SharedMem.error() == QSharedMemory::AlreadyExists) {
- if (!allowMultiple) {
- m_SharedMem.attach();
- m_Ephemeral = true;
- }
- }
-
- if ((m_SharedMem.error() != QSharedMemory::NoError) &&
- (m_SharedMem.error() != QSharedMemory::AlreadyExists)) {
- throw MOBase::MyException(tr("SHM error: %1").arg(m_SharedMem.errorString()));
- }
- } else {
- m_OwnsSM = true;
- }
-
- if (m_OwnsSM) {
- connect(&m_Server, SIGNAL(newConnection()), this, SLOT(receiveMessage()), Qt::QueuedConnection);
- // has to be called before listen
- m_Server.setSocketOptions(QLocalServer::WorldAccessOption);
- m_Server.listen(s_Key);
- }
-}
-
-
-void MOMultiProcess::sendMessage(const QString &message)
-{
- if (m_OwnsSM) {
- // nobody there to receive the message
- return;
- }
- QLocalSocket socket(this);
-
- bool connected = false;
- for(int i = 0; i < 2 && !connected; ++i) {
- if (i > 0) {
- Sleep(250);
- }
-
- // other process may be just starting up
- socket.connectToServer(s_Key, QIODevice::WriteOnly);
- connected = socket.waitForConnected(s_Timeout);
- }
-
- if (!connected) {
- reportError(tr("failed to connect to running process: %1").arg(socket.errorString()));
- return;
- }
-
- socket.write(message.toUtf8());
- if (!socket.waitForBytesWritten(s_Timeout)) {
- reportError(tr("failed to communicate with running process: %1").arg(socket.errorString()));
- return;
- }
-
- socket.disconnectFromServer();
- socket.waitForDisconnected();
-}
-
-void MOMultiProcess::receiveMessage()
-{
- QLocalSocket *socket = m_Server.nextPendingConnection();
- if (!socket) {
- return;
- }
-
- if (!socket->waitForReadyRead(s_Timeout)) {
- // check if there are bytes available; if so, it probably means the data was
- // already received by the time waitForReadyRead() was called and the
- // connection has been closed
- const auto av = socket->bytesAvailable();
-
- if (av <= 0) {
- MOBase::log::error(
- "failed to receive data from secondary process: {}",
- socket->errorString());
-
- reportError(tr("failed to receive data from secondary process: %1").arg(socket->errorString()));
- return;
- }
- }
-
- QString message = QString::fromUtf8(socket->readAll().constData());
- emit messageSent(message);
- socket->disconnectFromServer();
-}
diff --git a/src/singleinstance.h b/src/singleinstance.h
deleted file mode 100644
index 810e63d2..00000000
--- a/src/singleinstance.h
+++ /dev/null
@@ -1,70 +0,0 @@
-#ifndef MODORGANIZER_MOMULTIPROCESS_INCLUDED
-#define MODORGANIZER_MOMULTIPROCESS_INCLUDED
-
-#include
-#include
-#include
-
-
-/**
- * used to ensure only a single process of Mod Organizer is started and to
- * allow ephemeral processes to send messages to the primary (visible) one.
- * This way, other processes can start a download in the primary one
- **/
-class MOMultiProcess : public QObject
-{
- Q_OBJECT
-
-public:
- // `allowMultiple`: if another process is running, run this one
- // disconnected from the shared memory
- explicit MOMultiProcess(bool allowMultiple, QObject *parent = 0);
-
- /**
- * @return true if this process's job is to forward data to the primary
- * process through shared memory
- **/
- bool ephemeral() const
- {
- return m_Ephemeral;
- }
-
- // returns true if this is not the primary process, but was allowed because
- // of the AllowMultiple flag
- //
- bool secondary() const
- {
- return !m_Ephemeral && !m_OwnsSM;
- }
-
- /**
- * send a message to the primary process. This can be used to transmit download urls
- *
- * @param message message to send
- **/
- void sendMessage(const QString &message);
-
-signals:
-
- /**
- * @brief emitted when an ephemeral process has sent a message (to us)
- *
- * @param message the message we received
- **/
- void messageSent(const QString &message);
-
-public slots:
-
-private slots:
-
- void receiveMessage();
-
-private:
- bool m_Ephemeral;
- bool m_OwnsSM;
- QSharedMemory m_SharedMem;
- QLocalServer m_Server;
-
-};
-
-#endif // MODORGANIZER_MOMULTIPROCESS_INCLUDED
--
cgit v1.3.1