summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/main.cpp47
-rw-r--r--src/singleinstance.cpp23
-rw-r--r--src/singleinstance.h62
3 files changed, 85 insertions, 47 deletions
diff --git a/src/main.cpp b/src/main.cpp
index a81ae962..7130d15c 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -112,19 +112,19 @@ bool createAndMakeWritable(const std::wstring &subPath) {
}
}
-bool bootstrap()
+void purgeOldFiles()
{
- // remove the temporary backup directory in case we're restarting after an update
+ // 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);
-
- return true;
+ removeOldFiles(
+ qApp->property("dataPath").toString() + "/" + QString::fromStdWString(AppConfig::logPath()),
+ "usvfs*.log", 5, QDir::Name);
}
thread_local LPTOP_LEVEL_EXCEPTION_FILTER prevUnhandledExceptionFilter = nullptr;
@@ -533,8 +533,9 @@ static QString getVersionDisplayString()
}
-int runApplication(MOApplication &application, SingleInstance &instance,
- const QString &splashPath)
+int runApplication(
+ MOApplication &application, QStringList& arguments,
+ SingleInstance &instance, const QString &splashPath)
{
TimeThis tt("runApplication() to exec()");
@@ -555,17 +556,13 @@ int runApplication(MOApplication &application, SingleInstance &instance,
log::debug("this is a portable instance");
}
- if (!bootstrap()) {
- reportError("failed to set up data paths");
- InstanceManager::instance().clearCurrentInstance();
- return 1;
+ if (!instance.secondary()) {
+ purgeOldFiles();
}
QWindowsWindowFunctions::setWindowActivationBehavior(
QWindowsWindowFunctions::AlwaysActivateWindow);
- QStringList arguments = application.arguments();
-
try {
log::info("working directory: {}", QDir::currentPath());
@@ -574,6 +571,11 @@ int runApplication(MOApplication &application, SingleInstance &instance,
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());
@@ -929,16 +931,23 @@ int main(int argc, char *argv[])
setupPath();
- bool forcePrimary = false;
+
+ SingleInstance::Flags siFlags = SingleInstance::NoFlags;
+
if (arguments.contains("update")) {
arguments.removeAll("update");
- forcePrimary = true;
+ siFlags |= SingleInstance::ForcePrimary;
+ }
+
+ if (arguments.contains("--multiple")) {
+ arguments.removeAll("--multiple");
+ siFlags |= SingleInstance::AllowMultiple;
}
MOShortcut moshortcut{ arguments.size() > 1 ? arguments.at(1) : "" };
- SingleInstance instance(forcePrimary);
- if (!instance.primaryInstance()) {
+ SingleInstance instance(siFlags);
+ if (instance.ephemeral()) {
if (moshortcut ||
arguments.size() > 1 && OrganizerCore::isNxmLink(arguments.at(1)))
{
@@ -998,7 +1007,7 @@ int main(int argc, char *argv[])
tt.stop();
- const int result = runApplication(application, instance, splash);
+ const int result = runApplication(application, arguments, instance, splash);
if (result != RestartExitCode) {
return result;
}
diff --git a/src/singleinstance.cpp b/src/singleinstance.cpp
index aa62d40a..d38095df 100644
--- a/src/singleinstance.cpp
+++ b/src/singleinstance.cpp
@@ -28,33 +28,38 @@ static const int s_Timeout = 5000;
using MOBase::reportError;
-SingleInstance::SingleInstance(bool forcePrimary, QObject *parent) :
- QObject(parent), m_PrimaryInstance(false)
+SingleInstance::SingleInstance(Flags flags, QObject *parent) :
+ QObject(parent), m_Ephemeral(false), m_OwnsSM(false)
{
m_SharedMem.setKey(s_Key);
+
if (!m_SharedMem.create(1)) {
- if (forcePrimary) {
+ if (flags.testFlag(ForcePrimary)) {
while (m_SharedMem.error() == QSharedMemory::AlreadyExists) {
Sleep(500);
if (m_SharedMem.create(1)) {
- m_PrimaryInstance = true;
+ m_OwnsSM = true;
break;
}
}
}
if (m_SharedMem.error() == QSharedMemory::AlreadyExists) {
- m_SharedMem.attach();
- m_PrimaryInstance = false;
+ if (!flags.testFlag(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_PrimaryInstance = true;
+ m_OwnsSM = true;
}
- if (m_PrimaryInstance) {
+
+ if (m_OwnsSM) {
connect(&m_Server, SIGNAL(newConnection()), this, SLOT(receiveMessage()), Qt::QueuedConnection);
// has to be called before listen
m_Server.setSocketOptions(QLocalServer::WorldAccessOption);
@@ -65,7 +70,7 @@ SingleInstance::SingleInstance(bool forcePrimary, QObject *parent) :
void SingleInstance::sendMessage(const QString &message)
{
- if (m_PrimaryInstance) {
+ if (m_OwnsSM) {
// nobody there to receive the message
return;
}
diff --git a/src/singleinstance.h b/src/singleinstance.h
index 14d49d6d..5c7cdf85 100644
--- a/src/singleinstance.h
+++ b/src/singleinstance.h
@@ -27,8 +27,8 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
/**
* used to ensure only a single instance of Mod Organizer is started and to
- * allow secondary instances to send messages to the primary (visible) one. This way,
- * secondary instances can start a download in the primary one
+ * allow ephemeral instances to send messages to the primary (visible) one.
+ * This way, other instances can start a download in the primary one
**/
class SingleInstance : public QObject
{
@@ -36,24 +36,46 @@ class SingleInstance : public QObject
Q_OBJECT
public:
+ enum Flag
+ {
+ NoFlags = 0x00,
- /**
- * @brief constructor
- *
- * @param forcePrimary if true, this will be treated as the primary instance even
- * if another instance is running. This is used after an update since
- * the other instance is assumed to be in the process of quitting
- * @param parent parent object
- * @todo the forcePrimary parameter makes no sense. The second instance after an update
- * needs to delete the files from before the update so the first instance needs to quit
- * first anyway
- **/
- explicit SingleInstance(bool forcePrimary, QObject *parent = 0);
+
+ // when set, this will be treated as the primary instance even if
+ // another instance is running. This is used after an update since the
+ // other instance is assumed to be in the process of quitting
+ //
+ // todo: this makes no sense. The second instance after an update needs
+ // to delete the files from before the update so the first instance
+ // needs to quit first anyway
+ ForcePrimary = 0x01,
+
+ // if another instance is running, run this one disconnected from the
+ // shared memory
+ AllowMultiple = 0x02
+ };
+
+ using Flags = QFlags<Flag>;
+
+
+ explicit SingleInstance(Flags flags, QObject *parent = 0);
/**
- * @return true if this is the primary instance (the one that gets to display a UI)
+ * @return true if this instance's job is to forward data to the primary
+ * instance through shared memory
**/
- bool primaryInstance() const { return m_PrimaryInstance; }
+ bool ephemeral() const
+ {
+ return m_Ephemeral;
+ }
+
+ // returns true if this is not the primary instance, but was allowed because
+ // of the AllowMultiple flag
+ //
+ bool secondary() const
+ {
+ return !m_Ephemeral && !m_OwnsSM;
+ }
/**
* send a message to the primary instance. This can be used to transmit download urls
@@ -65,7 +87,7 @@ public:
signals:
/**
- * @brief emitted when a secondary instance has sent a message (to us)
+ * @brief emitted when an ephemeral instance has sent a message (to us)
*
* @param message the message we received
**/
@@ -78,11 +100,13 @@ private slots:
void receiveMessage();
private:
-
- bool m_PrimaryInstance;
+ bool m_Ephemeral;
+ bool m_OwnsSM;
QSharedMemory m_SharedMem;
QLocalServer m_Server;
};
+Q_DECLARE_OPERATORS_FOR_FLAGS(SingleInstance::Flags);
+
#endif // SINGLEINSTANCE_H