diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/commandline.cpp | 118 | ||||
| -rw-r--r-- | src/commandline.h | 37 | ||||
| -rw-r--r-- | src/main.cpp | 34 | ||||
| -rw-r--r-- | src/messagedialog.cpp | 22 | ||||
| -rw-r--r-- | src/moapplication.cpp | 49 | ||||
| -rw-r--r-- | src/moapplication.h | 4 | ||||
| -rw-r--r-- | src/organizercore.cpp | 19 | ||||
| -rw-r--r-- | src/organizercore.h | 1 |
8 files changed, 213 insertions, 71 deletions
diff --git a/src/commandline.cpp b/src/commandline.cpp index fd0f6cb5..b6210463 100644 --- a/src/commandline.cpp +++ b/src/commandline.cpp @@ -2,8 +2,10 @@ #include "env.h" #include "organizercore.h" #include "instancemanager.h" +#include "multiprocess.h" #include "shared/util.h" #include "shared/error_report.h" +#include "shared/appconfig.h" #include <log.h> #include <report.h> @@ -54,9 +56,12 @@ CommandLine::CommandLine() : m_command(nullptr) { createOptions(); - m_commands.push_back(std::make_unique<RunCommand>()); - m_commands.push_back(std::make_unique<CrashDumpCommand>()); - m_commands.push_back(std::make_unique<LaunchCommand>()); + + add< + RunCommand, + ReloadPluginCommand, + CrashDumpCommand, + LaunchCommand>(); } std::optional<int> CommandLine::process(const std::wstring& line) @@ -130,7 +135,7 @@ std::optional<int> CommandLine::process(const std::wstring& line) c->process(line, m_vm, opts); m_command = c.get(); - return m_command->runPreOrganizer(); + return m_command->runEarly(); } catch(po::error& e) { @@ -170,7 +175,7 @@ std::optional<int> CommandLine::process(const std::wstring& line) return 1; } - // try as an moshorcut:// + // try as an moshortcut:// m_shortcut = qs; if (!m_shortcut.isValid()) { @@ -205,14 +210,34 @@ std::optional<int> CommandLine::process(const std::wstring& line) } } -std::optional<int> CommandLine::run(OrganizerCore& organizer) const +bool CommandLine::forwardToPrimary(MOMultiProcess& multiProcess) +{ + if (m_shortcut.isValid()) { + multiProcess.sendMessage(m_shortcut.toString()); + } else if (m_nxmLink) { + multiProcess.sendMessage(*m_nxmLink); + } else if (m_command && m_command->canForwardToPrimary()) { + multiProcess.sendMessage(QString::fromWCharArray(GetCommandLineW())); + } else { + return false; + } + + return true; +} + +std::optional<int> CommandLine::runPostMultiProcess(MOMultiProcess& mp) +{ + return {}; +} + +std::optional<int> CommandLine::runPostOrganizer(OrganizerCore& core) { if (m_shortcut.isValid()) { if (m_shortcut.hasExecutable()) { try { // make sure MO doesn't exit even if locking is disabled, ForceWait and // PreventExit will do that - organizer.processRunner() + core.processRunner() .setFromShortcut(m_shortcut) .setWaitForCompletion(ProcessRunner::ForceWait, UILocker::PreventExit) .run(); @@ -227,7 +252,7 @@ std::optional<int> CommandLine::run(OrganizerCore& organizer) const } } else if (m_nxmLink) { log::debug("starting download from command line: {}", *m_nxmLink); - organizer.externalMessage(*m_nxmLink); + core.downloadRequestedNXM(*m_nxmLink); } else if (m_executable) { const QString exeName = *m_executable; log::debug("starting {} from command line", exeName); @@ -238,7 +263,7 @@ std::optional<int> CommandLine::run(OrganizerCore& organizer) const // // make sure MO doesn't exit even if locking is disabled, ForceWait and // PreventExit will do that - organizer.processRunner() + core.processRunner() .setFromFileOrExecutable(exeName, m_untouched) .setWaitForCompletion(ProcessRunner::ForceWait, UILocker::PreventExit) .run(); @@ -252,7 +277,7 @@ std::optional<int> CommandLine::run(OrganizerCore& organizer) const return 1; } } else if (m_command) { - return m_command->runPostOrganizer(organizer); + return m_command->runPostOrganizer(core); } return {}; @@ -479,7 +504,17 @@ void Command::process( m_untouched = untouched; } -std::optional<int> Command::runPreOrganizer() +std::optional<int> Command::runEarly() +{ + return {}; +} + +bool Command::canForwardToPrimary() const +{ + return false; +} + +std::optional<int> Command::runPostMultiProcess(MOMultiProcess&) { return {}; } @@ -520,7 +555,7 @@ Command::Meta CrashDumpCommand::meta() const return {"crashdump", "writes a crashdump for a running process of MO"}; } -std::optional<int> CrashDumpCommand::runPreOrganizer() +std::optional<int> CrashDumpCommand::runEarly() { env::Console console; @@ -550,7 +585,7 @@ bool LaunchCommand::legacy() const return true; } -std::optional<int> LaunchCommand::runPreOrganizer() +std::optional<int> LaunchCommand::runEarly() { // needs at least the working directory and process name if (untouched().size() < 2) { @@ -657,7 +692,7 @@ Command::Meta RunCommand::meta() const return {"run", "runs a program, file or a configured executable"}; } -std::optional<int> RunCommand::runPostOrganizer(OrganizerCore& organizer) +std::optional<int> RunCommand::runPostOrganizer(OrganizerCore& core) { const auto program = QString::fromStdString(vm()["program"].as<std::string>()); @@ -665,10 +700,10 @@ std::optional<int> RunCommand::runPostOrganizer(OrganizerCore& organizer) { // make sure MO doesn't exit even if locking is disabled, ForceWait and // PreventExit will do that - auto p = organizer.processRunner(); + auto p = core.processRunner(); if (vm()["executable"].as<bool>()) { - const auto& exes = *organizer.executablesList(); + const auto& exes = *core.executablesList(); auto itor = exes.find(program); if (itor == exes.end()) { @@ -714,4 +749,55 @@ std::optional<int> RunCommand::runPostOrganizer(OrganizerCore& organizer) } } + + +std::string ReloadPluginCommand::getUsageLine() const +{ + return "plugin-name"; +} + +po::options_description ReloadPluginCommand::getInternalOptions() const +{ + po::options_description d; + + d.add_options() + ("plugin-name", po::value<std::string>()->required(), "plugin name"); + + return d; +} + +po::positional_options_description ReloadPluginCommand::getPositional() const +{ + po::positional_options_description d; + + d.add("plugin-name", 1); + + return d; +} + +Command::Meta ReloadPluginCommand::meta() const +{ + return {"reload-plugin", "reloads the given plugin"}; +} + +bool ReloadPluginCommand::canForwardToPrimary() const +{ + return true; +} + +std::optional<int> ReloadPluginCommand::runPostOrganizer(OrganizerCore& core) +{ + const QString name = QString::fromStdString(vm()["plugin-name"].as<std::string>()); + + QString filepath = QDir( + qApp->applicationDirPath() + "/" + + ToQString(AppConfig::pluginPath())) + .absoluteFilePath(name); + + log::debug("reloading plugin from {}", filepath); + core.pluginContainer().reloadPlugin(filepath); + + return {}; +} + } // namespace diff --git a/src/commandline.h b/src/commandline.h index d0d62a72..6f96d724 100644 --- a/src/commandline.h +++ b/src/commandline.h @@ -5,6 +5,7 @@ #include <memory> class OrganizerCore; +class MOMultiProcess; namespace cl { @@ -59,8 +60,10 @@ public: // // - virtual std::optional<int> runPreOrganizer(); - virtual std::optional<int> runPostOrganizer(OrganizerCore& organizer); + virtual std::optional<int> runEarly(); + virtual bool canForwardToPrimary() const; + virtual std::optional<int> runPostMultiProcess(MOMultiProcess& mp); + virtual std::optional<int> runPostOrganizer(OrganizerCore& core); protected: // meta information about this command, returned by derived classes @@ -118,7 +121,7 @@ class CrashDumpCommand : public Command protected: po::options_description getVisibleOptions() const override; Meta meta() const override; - std::optional<int> runPreOrganizer() override; + std::optional<int> runEarly() override; }; @@ -141,7 +144,7 @@ public: protected: Meta meta() const override; - std::optional<int> runPreOrganizer() override; + std::optional<int> runEarly() override; int SpawnWaitProcess(LPCWSTR workingDirectory, LPCWSTR commandLine); @@ -160,7 +163,21 @@ protected: po::options_description getInternalOptions() const override; po::positional_options_description getPositional() const override; Meta meta() const override; - std::optional<int> runPostOrganizer(OrganizerCore& organizer) override; + std::optional<int> runPostOrganizer(OrganizerCore& core) override; +}; + + +// reloads the given plugin +// +class ReloadPluginCommand : public Command +{ +protected: + std::string getUsageLine() const override; + po::options_description getInternalOptions() const override; + po::positional_options_description getPositional() const override; + Meta meta() const override; + bool canForwardToPrimary() const override; + std::optional<int> runPostOrganizer(OrganizerCore& core) override; }; @@ -215,7 +232,9 @@ public: // returns an empty optional if execution should continue, or a return code // if MO must quit // - std::optional<int> run(OrganizerCore& organizer) const; + bool forwardToPrimary(MOMultiProcess& multiProcess); + std::optional<int> runPostMultiProcess(MOMultiProcess& mp); + std::optional<int> runPostOrganizer(OrganizerCore& core); // clears parsed options, used when MO is "restarted" so the options aren't @@ -269,6 +288,12 @@ private: void createOptions(); std::string more() const; + + template <class... Ts> + void add() + { + (m_commands.push_back(std::make_unique<Ts>()), ...); + } }; } // namespace diff --git a/src/main.cpp b/src/main.cpp index f85e13f3..adb33d91 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -37,12 +37,27 @@ int main(int argc, char *argv[]) MOMultiProcess multiProcess(cl.multiple()); if (multiProcess.ephemeral()) { - return forwardToPrimary(multiProcess, cl); + if (cl.forwardToPrimary(multiProcess)) { + return 0; + } else { + QMessageBox::information( + nullptr, QObject::tr("Mod Organizer"), + QObject::tr("An instance of Mod Organizer is already running")); + } + + return 0; + } + + if (auto r=cl.runPostMultiProcess(multiProcess)) { + return *r; } tt.stop(); + app.firstTimeSetup(multiProcess); + + // MO runs in a loop because it can be restarted in several ways, such as // when switching instances or changing some settings for (;;) @@ -73,7 +88,7 @@ int main(int argc, char *argv[]) } } - if (auto r=cl.run(app.core())) { + if (auto r=cl.runPostOrganizer(app.core())) { return *r; } @@ -99,21 +114,6 @@ int main(int argc, char *argv[]) } } -int forwardToPrimary(MOMultiProcess& multiProcess, const cl::CommandLine& cl) -{ - if (cl.shortcut().isValid()) { - multiProcess.sendMessage(cl.shortcut().toString()); - } else if (cl.nxmLink()) { - multiProcess.sendMessage(*cl.nxmLink()); - } else { - QMessageBox::information( - nullptr, QObject::tr("Mod Organizer"), - QObject::tr("An instance of Mod Organizer is already running")); - } - - return 0; -} - LONG WINAPI onUnhandledException(_EXCEPTION_POINTERS* ptrs) { const auto path = OrganizerCore::getGlobalCoreDumpPath(); diff --git a/src/messagedialog.cpp b/src/messagedialog.cpp index 78a5dd4d..1244e8c6 100644 --- a/src/messagedialog.cpp +++ b/src/messagedialog.cpp @@ -86,11 +86,23 @@ void MessageDialog::showMessage(const QString &text, QWidget *reference, bool br {
log::debug("{}", text);
- if (reference != nullptr) {
- if (bringToFront || (qApp->activeWindow() != nullptr)) {
- MessageDialog *dialog = new MessageDialog(text, reference);
- dialog->show();
- reference->activateWindow();
+ if (!reference) {
+ for (QWidget* w : qApp->topLevelWidgets()) {
+ if (dynamic_cast<QMainWindow*>(w)) {
+ reference = w;
+ break;
+ }
}
}
+
+ if (!reference) {
+ return;
+ }
+
+ MessageDialog *dialog = new MessageDialog(text, reference);
+ dialog->show();
+
+ if (bringToFront) {
+ reference->activateWindow();
+ }
}
diff --git a/src/moapplication.cpp b/src/moapplication.cpp index d1622d59..01d75ad1 100644 --- a/src/moapplication.cpp +++ b/src/moapplication.cpp @@ -31,6 +31,7 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. #include "tutorialmanager.h"
#include "sanitychecks.h"
#include "mainwindow.h"
+#include "messagedialog.h"
#include "shared/error_report.h"
#include "shared/util.h"
#include <iplugingame.h>
@@ -175,6 +176,14 @@ OrganizerCore& MOApplication::core() return *m_core;
}
+void MOApplication::firstTimeSetup(MOMultiProcess& multiProcess)
+{
+ connect(
+ &multiProcess, &MOMultiProcess::messageSent, this,
+ [this](auto&& s){ externalMessage(s); },
+ Qt::QueuedConnection);
+}
+
int MOApplication::setup(MOMultiProcess& multiProcess)
{
TimeThis tt("MOApplication setup()");
@@ -350,11 +359,10 @@ int MOApplication::run(MOMultiProcess& multiProcess) // main window
m_nexus->getAccessManager()->setTopLevelWidget(&mainWindow);
- QObject::connect(&mainWindow, SIGNAL(styleChanged(QString)), this,
- SLOT(setStyleFile(QString)));
-
- QObject::connect(&multiProcess, SIGNAL(messageSent(QString)), m_core.get(),
- SLOT(externalMessage(QString)));
+ connect(
+ &mainWindow, &MainWindow::styleChanged, this,
+ [this](auto&& file){ setStyleFile(file); },
+ Qt::QueuedConnection);
log::debug("displaying main window");
@@ -377,6 +385,37 @@ int MOApplication::run(MOMultiProcess& multiProcess) return res;
}
+void MOApplication::externalMessage(const QString& message)
+{
+ log::debug("received external message '{}'", message);
+
+ MOShortcut moshortcut(message);
+
+ if (moshortcut.isValid()) {
+ if(moshortcut.hasExecutable()) {
+ m_core->processRunner()
+ .setFromShortcut(moshortcut)
+ .setWaitForCompletion(ProcessRunner::Refresh)
+ .run();
+ }
+ } else if (isNxmLink(message)) {
+ MessageDialog::showMessage(tr("Download started"), qApp->activeWindow());
+ m_core->downloadRequestedNXM(message);
+ } else {
+ cl::CommandLine cl;
+
+ if (auto r=cl.process(message.toStdWString())) {
+ log::debug(
+ "while processing external message, command line wants to "
+ "exit; ignoring");
+
+ return;
+ }
+
+ cl.runPostOrganizer(*m_core);
+ }
+}
+
std::unique_ptr<Instance> MOApplication::getCurrentInstance()
{
auto& m = InstanceManager::singleton();
diff --git a/src/moapplication.h b/src/moapplication.h index 7e427ca8..2fe3409b 100644 --- a/src/moapplication.h +++ b/src/moapplication.h @@ -40,6 +40,7 @@ class MOApplication : public QApplication public:
MOApplication(int& argc, char** argv);
+ void firstTimeSetup(MOMultiProcess& multiProcess);
int setup(MOMultiProcess& multiProcess);
int run(MOMultiProcess& multiProcess);
void resetForRestart();
@@ -65,8 +66,7 @@ private: std::unique_ptr<PluginContainer> m_plugins;
std::unique_ptr<OrganizerCore> m_core;
- int doOneRun(MOMultiProcess& multiProcess);
-
+ void externalMessage(const QString& message);
std::unique_ptr<Instance> getCurrentInstance();
std::optional<int> setupInstanceLoop(Instance& currentInstance, PluginContainer& pc);
void purgeOldFiles();
diff --git a/src/organizercore.cpp b/src/organizercore.cpp index 5d079f89..fe17ee9a 100644 --- a/src/organizercore.cpp +++ b/src/organizercore.cpp @@ -347,25 +347,6 @@ void OrganizerCore::profileRemoved(QString const& profileName) m_ProfileRemoved(profileName); } - -void OrganizerCore::externalMessage(const QString &message) -{ - MOShortcut moshortcut(message); - - if (moshortcut.isValid()) { - if(moshortcut.hasExecutable()) { - processRunner() - .setFromShortcut(moshortcut) - .setWaitForCompletion(ProcessRunner::Refresh) - .run(); - } - } - else if (isNxmLink(message)) { - MessageDialog::showMessage(tr("Download started"), qApp->activeWindow()); - downloadRequestedNXM(message); - } -} - void OrganizerCore::downloadRequested(QNetworkReply *reply, QString gameName, int modID, const QString &fileName) { diff --git a/src/organizercore.h b/src/organizercore.h index 8add5542..39a2c3cb 100644 --- a/src/organizercore.h +++ b/src/organizercore.h @@ -351,7 +351,6 @@ public: // IPluginDiagnose interface public slots:
void profileRefresh();
- void externalMessage(const QString &message);
void syncOverwrite();
|
