diff options
Diffstat (limited to 'logic')
| -rw-r--r-- | logic/BaseInstance.h | 4 | ||||
| -rw-r--r-- | logic/BaseLauncher.cpp | 311 | ||||
| -rw-r--r-- | logic/BaseLauncher.h (renamed from logic/BaseProcess.h) | 63 | ||||
| -rw-r--r-- | logic/BaseProcess.cpp | 420 | ||||
| -rw-r--r-- | logic/CMakeLists.txt | 12 | ||||
| -rw-r--r-- | logic/LoggedProcess.cpp | 147 | ||||
| -rw-r--r-- | logic/LoggedProcess.h | 60 | ||||
| -rw-r--r-- | logic/MessageLevel.cpp | 36 | ||||
| -rw-r--r-- | logic/MessageLevel.h | 28 | ||||
| -rw-r--r-- | logic/NullInstance.h | 2 | ||||
| -rw-r--r-- | logic/minecraft/LegacyInstance.cpp | 6 | ||||
| -rw-r--r-- | logic/minecraft/LegacyInstance.h | 2 | ||||
| -rw-r--r-- | logic/minecraft/MinecraftLauncher.cpp (renamed from logic/minecraft/MinecraftProcess.cpp) | 154 | ||||
| -rw-r--r-- | logic/minecraft/MinecraftLauncher.h (renamed from logic/minecraft/MinecraftProcess.h) | 15 | ||||
| -rw-r--r-- | logic/minecraft/OneSixInstance.cpp | 6 | ||||
| -rw-r--r-- | logic/minecraft/OneSixInstance.h | 2 | ||||
| -rw-r--r-- | logic/tools/BaseExternalTool.cpp | 10 | ||||
| -rw-r--r-- | logic/tools/BaseExternalTool.h | 1 | ||||
| -rw-r--r-- | logic/tools/BaseProfiler.cpp | 2 | ||||
| -rw-r--r-- | logic/tools/BaseProfiler.h | 6 | ||||
| -rw-r--r-- | logic/tools/JProfiler.cpp | 8 | ||||
| -rw-r--r-- | logic/tools/JVisualVM.cpp | 8 |
22 files changed, 724 insertions, 579 deletions
diff --git a/logic/BaseInstance.h b/logic/BaseInstance.h index 4c547a77..91d46df1 100644 --- a/logic/BaseInstance.h +++ b/logic/BaseInstance.h @@ -27,7 +27,7 @@ class QDir; class Task; -class BaseProcess; +class BaseLauncher; class BaseInstance; // pointer for lazy people @@ -138,7 +138,7 @@ public: virtual std::shared_ptr<Task> doUpdate() = 0; /// returns a valid process, ready for launch with the given account. - virtual BaseProcess *prepareForLaunch(AuthSessionPtr account) = 0; + virtual BaseLauncher *prepareForLaunch(AuthSessionPtr account) = 0; /// do any necessary cleanups after the instance finishes. also runs before /// 'prepareForLaunch' diff --git a/logic/BaseLauncher.cpp b/logic/BaseLauncher.cpp new file mode 100644 index 00000000..96cb2b93 --- /dev/null +++ b/logic/BaseLauncher.cpp @@ -0,0 +1,311 @@ +/* Copyright 2013-2015 MultiMC Contributors + * + * Authors: Orochimarufan <orochimarufan.x3@gmail.com> + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "BaseLauncher.h" +#include "MessageLevel.h" +#include <QDebug> +#include <QDir> +#include <QEventLoop> + +BaseLauncher::BaseLauncher(InstancePtr instance): m_instance(instance) +{ +} + +void BaseLauncher::initializeEnvironment() +{ + // prepare the process environment + QProcessEnvironment rawenv = QProcessEnvironment::systemEnvironment(); + + QStringList ignored = + { + "JAVA_ARGS", + "CLASSPATH", + "CONFIGPATH", + "JAVA_HOME", + "JRE_HOME", + "_JAVA_OPTIONS", + "JAVA_OPTIONS", + "JAVA_TOOL_OPTIONS" + }; + for(auto key: rawenv.keys()) + { + auto value = rawenv.value(key); + // filter out dangerous java crap + if(ignored.contains(key)) + { + qDebug() << "Env: ignoring" << key << value; + continue; + } + // filter MultiMC-related things + if(key.startsWith("QT_")) + { + qDebug() << "Env: ignoring" << key << value; + continue; + } +#ifdef LINUX + // Do not pass LD_* variables to java. They were intended for MultiMC + if(key.startsWith("LD_")) + { + qDebug() << "Env: ignoring" << key << value; + continue; + } + // Strip IBus + // IBus is a Linux IME framework. For some reason, it breaks MC? + if (key == "XMODIFIERS" && value.contains(IBUS)) + { + QString save = value; + value.replace(IBUS, ""); + qDebug() << "Env: stripped" << IBUS << "from" << save << ":" << value; + } +#endif + qDebug() << "Env: " << key << value; + m_env.insert(key, value); + } +#ifdef LINUX + // HACK: Workaround for QTBUG-42500 + m_env.insert("LD_LIBRARY_PATH", ""); +#endif + + // export some infos + auto variables = getVariables(); + for (auto it = variables.begin(); it != variables.end(); ++it) + { + m_env.insert(it.key(), it.value()); + } +} + +void BaseLauncher::init() +{ + initializeEnvironment(); + + m_process.setProcessEnvironment(m_env); + connect(&m_process, &LoggedProcess::log, this, &BaseLauncher::on_log); + connect(&m_process, &LoggedProcess::stateChanged, this, &BaseLauncher::on_state); + + m_prelaunchprocess.setProcessEnvironment(m_env); + connect(&m_prelaunchprocess, &LoggedProcess::log, this, &BaseLauncher::on_log); + connect(&m_prelaunchprocess, &LoggedProcess::stateChanged, this, &BaseLauncher::on_pre_state); + + m_postlaunchprocess.setProcessEnvironment(m_env); + connect(&m_postlaunchprocess, &LoggedProcess::log, this, &BaseLauncher::on_log); + connect(&m_postlaunchprocess, &LoggedProcess::stateChanged, this, &BaseLauncher::on_post_state); + + // a process has been constructed for the instance. It is running from MultiMC POV + m_instance->setRunning(true); +} + + +void BaseLauncher::setWorkdir(QString path) +{ + QDir mcDir(path); + m_process.setWorkingDirectory(mcDir.absolutePath()); + m_prelaunchprocess.setWorkingDirectory(mcDir.absolutePath()); + m_postlaunchprocess.setWorkingDirectory(mcDir.absolutePath()); +} + +void BaseLauncher::printHeader() +{ + emit log(m_header); +} + +void BaseLauncher::on_log(QStringList lines, MessageLevel::Enum level) +{ + logOutput(lines, level); +} + +void BaseLauncher::logOutput(const QStringList &lines, MessageLevel::Enum defaultLevel) +{ + for (auto & line: lines) + { + logOutput(line, defaultLevel); + } +} + +void BaseLauncher::logOutput(QString line, MessageLevel::Enum level) +{ + // if the launcher part set a log level, use it + auto innerLevel = MessageLevel::fromLine(line); + if(innerLevel != MessageLevel::Unknown) + { + level = innerLevel; + } + + // If the level is still undetermined, guess level + if (level == MessageLevel::StdErr || level == MessageLevel::StdOut || level == MessageLevel::Unknown) + { + level = this->guessLevel(line, level); + } + + // censor private user info + line = censorPrivateInfo(line); + + emit log(line, level); +} + +void BaseLauncher::preLaunch() +{ + QString prelaunch_cmd = m_instance->settings()->get("PreLaunchCommand").toString(); + if (!prelaunch_cmd.isEmpty()) + { + prelaunch_cmd = substituteVariables(prelaunch_cmd); + // Launch + emit log(tr("Running Pre-Launch command: %1").arg(prelaunch_cmd)); + m_prelaunchprocess.start(prelaunch_cmd); + } + else + { + on_pre_state(LoggedProcess::Skipped); + } +} + +void BaseLauncher::on_pre_state(LoggedProcess::State state) +{ + switch(state) + { + case LoggedProcess::Aborted: + case LoggedProcess::Crashed: + case LoggedProcess::FailedToStart: + { + emit log(tr("Pre-Launch command failed with code %1.\n\n") + .arg(m_prelaunchprocess.exitCode()), + MessageLevel::Fatal); + m_instance->cleanupAfterRun(); + emit prelaunch_failed(m_instance, m_prelaunchprocess.exitCode(), m_prelaunchprocess.exitStatus()); + // not running, failed + m_instance->setRunning(false); + } + case LoggedProcess::Finished: + { + emit log(tr("Pre-Launch command ran successfully.\n\n")); + m_instance->reload(); + } + case LoggedProcess::Skipped: + default: + break; + } +} + +void BaseLauncher::on_state(LoggedProcess::State state) +{ + QProcess::ExitStatus estat = QProcess::NormalExit; + switch(state) + { + case LoggedProcess::Aborted: + case LoggedProcess::Crashed: + case LoggedProcess::FailedToStart: + estat = QProcess::CrashExit; + case LoggedProcess::Finished: + { + auto exitCode = m_process.exitCode(); + m_postlaunchprocess.processEnvironment().insert("INST_EXITCODE", QString(exitCode)); + + // run post-exit + postLaunch(); + m_instance->cleanupAfterRun(); + // no longer running... + m_instance->setRunning(false); + emit ended(m_instance, exitCode, estat); + } + case LoggedProcess::Skipped: + qWarning() << "Illegal game state: Skipped"; + default: + break; + } +} + +void BaseLauncher::on_post_state(LoggedProcess::State state) +{ + switch(state) + { + case LoggedProcess::Aborted: + case LoggedProcess::Crashed: + case LoggedProcess::FailedToStart: + case LoggedProcess::Finished: + case LoggedProcess::Skipped: + { + + } + default: + break; + } +} + +void BaseLauncher::killProcess() +{ + killed = true; + if (m_prelaunchprocess.state() == LoggedProcess::Running) + { + m_prelaunchprocess.kill(); + } + else if(m_process.state() == LoggedProcess::Running) + { + m_process.kill(); + } + else if(m_postlaunchprocess.state() == LoggedProcess::Running) + { + m_postlaunchprocess.kill(); + } +} + +void BaseLauncher::postLaunch() +{ + QString postlaunch_cmd = m_instance->settings()->get("PostExitCommand").toString(); + if (!postlaunch_cmd.isEmpty()) + { + postlaunch_cmd = substituteVariables(postlaunch_cmd); + emit log(tr("Running Post-Launch command: %1").arg(postlaunch_cmd)); + m_postlaunchprocess.start(postlaunch_cmd); + if (m_postlaunchprocess.exitStatus() != QProcess::NormalExit) + { + emit log(tr("Post-Launch command failed with code %1.\n\n") + .arg(m_postlaunchprocess.exitCode()), + MessageLevel::Error); + emit postlaunch_failed(m_instance, m_postlaunchprocess.exitCode(), + m_postlaunchprocess.exitStatus()); + // not running, failed + m_instance->setRunning(false); + } + else + emit log(tr("Post-Launch command ran successfully.\n\n")); + } +} + +QString BaseLauncher::substituteVariables(const QString &cmd) const +{ + QString out = cmd; + auto variables = getVariables(); + for (auto it = variables.begin(); it != variables.end(); ++it) + { + out.replace("$" + it.key(), it.value()); + } + auto env = QProcessEnvironment::systemEnvironment(); + for (auto var : env.keys()) + { + out.replace("$" + var, env.value(var)); + } + return out; +} + +qint64 BaseLauncher::pid() +{ +#ifdef Q_OS_WIN + struct _PROCESS_INFORMATION *procinfo = m_process.pid(); + return procinfo->dwProcessId; +#else + return m_process.pid(); +#endif +} diff --git a/logic/BaseProcess.h b/logic/BaseLauncher.h index 75bf0217..f47d3351 100644 --- a/logic/BaseProcess.h +++ b/logic/BaseLauncher.h @@ -18,36 +18,18 @@ #pragma once #include <QProcess> #include "BaseInstance.h" +#include "MessageLevel.h" +#include "LoggedProcess.h" -/** - * @brief the MessageLevel Enum - * defines what level a message is - */ -namespace MessageLevel -{ -enum Enum -{ - MultiMC, /**< MultiMC Messages */ - Debug, /**< Debug Messages */ - Info, /**< Info Messages */ - Message, /**< Standard Messages */ - Warning, /**< Warnings */ - Error, /**< Errors */ - Fatal, /**< Fatal Errors */ - PrePost, /**< Pre/Post Launch command output */ -}; -MessageLevel::Enum getLevel(const QString &levelName); -} - -class BaseProcess: public QProcess +class BaseLauncher: public QObject { Q_OBJECT protected: - explicit BaseProcess(InstancePtr instance); + explicit BaseLauncher(InstancePtr instance); void init(); public: /* methods */ - virtual ~BaseProcess() {}; + virtual ~BaseLauncher() {}; InstancePtr instance() { @@ -64,6 +46,8 @@ public: /* methods */ void killProcess(); + qint64 pid(); + /** * @brief prepare the process for launch (for multi-stage launch) */ @@ -80,10 +64,10 @@ public: /* methods */ virtual void abort() = 0; protected: /* methods */ - bool preLaunch(); - bool postLaunch(); - bool waitForPrePost(); + void preLaunch(); + void postLaunch(); QString substituteVariables(const QString &cmd) const; + void initializeEnvironment(); void printHeader(); @@ -120,23 +104,22 @@ signals: void log(QString text, MessageLevel::Enum level = MessageLevel::MultiMC); protected slots: - void finish(int, QProcess::ExitStatus status); - void on_stdErr(); - void on_stdOut(); - void on_prepost_stdOut(); - void on_prepost_stdErr(); - void logOutput(const QStringList &lines, - MessageLevel::Enum defaultLevel = MessageLevel::Message, - bool guessLevel = true, bool censor = true); - void logOutput(QString line, - MessageLevel::Enum defaultLevel = MessageLevel::Message, - bool guessLevel = true, bool censor = true); + void on_log(QStringList lines, MessageLevel::Enum level); + void logOutput(const QStringList& lines, MessageLevel::Enum defaultLevel = MessageLevel::Message); + void logOutput(QString line, MessageLevel::Enum defaultLevel = MessageLevel::Message); + + void on_pre_state(LoggedProcess::State state); + void on_state(LoggedProcess::State state); + void on_post_state(LoggedProcess::State state); protected: InstancePtr m_instance; - QString m_err_leftover; - QString m_out_leftover; - QProcess m_prepostlaunchprocess; + + LoggedProcess m_prelaunchprocess; + LoggedProcess m_postlaunchprocess; + LoggedProcess m_process; + QProcessEnvironment m_env; + bool killed = false; QString m_header; }; diff --git a/logic/BaseProcess.cpp b/logic/BaseProcess.cpp deleted file mode 100644 index 852bec4c..00000000 --- a/logic/BaseProcess.cpp +++ /dev/null @@ -1,420 +0,0 @@ -/* Copyright 2013-2015 MultiMC Contributors - * - * Authors: Orochimarufan <orochimarufan.x3@gmail.com> - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "BaseProcess.h" -#include <QDebug> -#include <QDir> -#include <QEventLoop> - -#define IBUS "@im=ibus" - -MessageLevel::Enum MessageLevel::getLevel(const QString& levelName) -{ - if (levelName == "MultiMC") - return MessageLevel::MultiMC; - else if (levelName == "Debug") - return MessageLevel::Debug; - else if (levelName == "Info") - return MessageLevel::Info; - else if (levelName == "Message") - return MessageLevel::Message; - else if (levelName == "Warning") - return MessageLevel::Warning; - else if (levelName == "Error") - return MessageLevel::Error; - else if (levelName == "Fatal") - return MessageLevel::Fatal; - // Skip PrePost, it's not exposed to !![]! - else - return MessageLevel::Message; -} - -BaseProcess::BaseProcess(InstancePtr instance): QProcess(), m_instance(instance) -{ -} - -void BaseProcess::init() -{ - connect(this, SIGNAL(finished(int, QProcess::ExitStatus)), - SLOT(finish(int, QProcess::ExitStatus))); - - // prepare the process environment - QProcessEnvironment rawenv = QProcessEnvironment::systemEnvironment(); - - QProcessEnvironment env; - - QStringList ignored = - { - "JAVA_ARGS", - "CLASSPATH", - "CONFIGPATH", - "JAVA_HOME", - "JRE_HOME", - "_JAVA_OPTIONS", - "JAVA_OPTIONS", - "JAVA_TOOL_OPTIONS", - "CDPATH" - }; - for(auto key: rawenv.keys()) - { - auto value = rawenv.value(key); - // filter out dangerous java crap - if(ignored.contains(key)) - { - qDebug() << "Env: ignoring" << key << value; - continue; - } - // filter MultiMC-related things - if(key.startsWith("QT_")) - { - qDebug() << "Env: ignoring" << key << value; - continue; - } -#ifdef Q_OS_LINUX - // Do not pass LD_* variables to java. They were intended for MultiMC - if(key.startsWith("LD_")) - { - qDebug() << "Env: ignoring" << key << value; - continue; - } - // Strip IBus - // IBus is a Linux IME framework. For some reason, it breaks MC? - if (key == "XMODIFIERS" && value.contains(IBUS)) - { - QString save = value; - value.replace(IBUS, ""); - qDebug() << "Env: stripped" << IBUS << "from" << save << ":" << value; - } -#endif - if(key == "GAME_PRELOAD") - { - env.insert("LD_PRELOAD", value); - continue; - } - if(key == "GAME_LIBRARY_PATH") - { - env.insert("LD_LIBRARY_PATH", value); - continue; - } - qDebug() << "Env: " << key << value; - env.insert(key, value); - } -#ifdef Q_OS_LINUX - // HACK: Workaround for QTBUG-42500 - if(!env.contains("LD_LIBRARY_PATH")) - { - env.insert("LD_LIBRARY_PATH", ""); - } -#endif - - // export some infos - auto variables = getVariables(); - for (auto it = variables.begin(); it != variables.end(); ++it) - { - env.insert(it.key(), it.value()); - } - - this->setProcessEnvironment(env); - m_prepostlaunchprocess.setProcessEnvironment(env); - - // std channels - connect(this, SIGNAL(readyReadStandardError()), SLOT(on_stdErr())); - connect(this, SIGNAL(readyReadStandardOutput()), SLOT(on_stdOut())); - - // Log prepost launch command output (can be disabled.) - if (m_instance->settings()->get("LogPrePostOutput").toBool()) - { - connect(&m_prepostlaunchprocess, &QProcess::readyReadStandardError, this, - &BaseProcess::on_prepost_stdErr); - connect(&m_prepostlaunchprocess, &QProcess::readyReadStandardOutput, this, - &BaseProcess::on_prepost_stdOut); - } - - // a process has been constructed for the instance. It is running from MultiMC POV - m_instance->setRunning(true); -} - - -void BaseProcess::setWorkdir(QString path) -{ - QDir mcDir(path); - this->setWorkingDirectory(mcDir.absolutePath()); - m_prepostlaunchprocess.setWorkingDirectory(mcDir.absolutePath()); -} - -void BaseProcess::printHeader() -{ - emit log(m_header); -} - - -void BaseProcess::logOutput(const QStringList &lines, MessageLevel::Enum defaultLevel, - bool guessLevel, bool censor) -{ - for (int i = 0; i < lines.size(); ++i) - logOutput(lines[i], defaultLevel, guessLevel, censor); -} - -void BaseProcess::logOutput(QString line, MessageLevel::Enum defaultLevel, bool guessLevel, - bool censor) -{ - MessageLevel::Enum level = defaultLevel; - - // Level prefix - int endmark = line.indexOf("]!"); - if (line.startsWith("! - { - if (state == QProcess::NotRunning) - { - eventLoop.quit(); - } - }; - auto connection = connect(&m_prepostlaunchprocess, &QProcess::stateChanged, finisher); - int ret = eventLoop.exec(); - disconnect(connection); - return ret == 0; -} - -QString BaseProcess::substituteVariables(const QString &cmd) const -{ - QString out = cmd; - auto variables = getVariables(); - for (auto it = variables.begin(); it != variables.end(); ++it) - { - out.replace("$" + it.key(), it.value()); - } - auto env = QProcessEnvironment::systemEnvironment(); - for (auto var : env.keys()) - { - out.replace("$" + var, env.value(var)); - } - return out; -} diff --git a/logic/CMakeLists.txt b/logic/CMakeLists.txt index e6e36225..19686aa0 100644 --- a/logic/CMakeLists.txt +++ b/logic/CMakeLists.txt @@ -8,9 +8,13 @@ set(LOGIC_SOURCES BaseVersionList.cpp InstanceList.h InstanceList.cpp + LoggedProcess.h + LoggedProcess.cpp + MessageLevel.cpp + MessageLevel.h BaseVersion.h - BaseProcess.h - BaseProcess.cpp + BaseLauncher.h + BaseLauncher.cpp BaseInstance.h BaseInstance.cpp NullInstance.h @@ -136,8 +140,8 @@ set(LOGIC_SOURCES minecraft/JarMod.h minecraft/MinecraftInstance.cpp minecraft/MinecraftInstance.h - minecraft/MinecraftProcess.cpp - minecraft/MinecraftProcess.h + minecraft/MinecraftLauncher.cpp + minecraft/MinecraftLauncher.h minecraft/MinecraftVersion.cpp minecraft/MinecraftVersion.h minecraft/MinecraftVersionList.cpp diff --git a/logic/LoggedProcess.cpp b/logic/LoggedProcess.cpp new file mode 100644 index 00000000..53840621 --- /dev/null +++ b/logic/LoggedProcess.cpp @@ -0,0 +1,147 @@ +#include "LoggedProcess.h" +#include "MessageLevel.h" +#include <QDebug> + +LoggedProcess::LoggedProcess(QObject *parent) : QProcess(parent) +{ + // QProcess has a strange interface... let's map a lot of those into a few. + connect(this, &QProcess::readyReadStandardOutput, this, &LoggedProcess::on_stdOut); + connect(this, &QProcess::readyReadStandardError, this, &LoggedProcess::on_stdErr); + connect(this, SIGNAL(finished(int,QProcess::ExitStatus)), SLOT(on_exit(int,QProcess::ExitStatus))); + connect(this, SIGNAL(error(QProcess::ProcessError)), this, SLOT(on_error(QProcess::ProcessError))); + connect(this, &QProcess::stateChanged, this, &LoggedProcess::on_stateChange); +} + +QStringList reprocess(const QByteArray & data, QString & leftover) +{ + QString str = leftover + QString::fromLocal8Bit(data); + + str.remove('\r'); + QStringList lines = str.split("\n"); + leftover = lines.takeLast(); + return lines; +} + +void LoggedProcess::on_stdErr() +{ + auto lines = reprocess(readAllStandardError(), m_err_leftover); + emit log(lines, MessageLevel::StdErr); +} + +void LoggedProcess::on_stdOut() +{ + auto lines = reprocess(readAllStandardOutput(), m_out_leftover); + emit log(lines, MessageLevel::StdOut); +} + +void LoggedProcess::on_exit(int exit_code, QProcess::ExitStatus status) +{ + // Flush console window + if (!m_err_leftover.isEmpty()) + { + emit log({m_err_leftover}, MessageLevel::StdErr); + m_err_leftover.clear(); + } + if (!m_out_leftover.isEmpty()) + { + emit log({m_err_leftover}, MessageLevel::StdOut); + m_out_leftover.clear(); + } + + // based on state, send signals + if (!m_is_aborting) + { + if (status == QProcess::NormalExit) + { + //: Message displayed on instance exit + emit log({tr("Process exited with code %1.").arg(exit_code)}, MessageLevel::MultiMC); + changeState(LoggedProcess::Finished); + } + else + { + //: Message displayed on instance crashed + if(exit_code == -1) + emit log({tr("Process crashed.").arg(exit_code)}, MessageLevel::MultiMC); + else + emit log({tr("Process crashed with exitcode %1.").arg(exit_code)}, MessageLevel::MultiMC); + changeState(LoggedProcess::Crashed); + } + } + else + { + //: Message displayed after the instance exits due to kill request + emit log({tr("Process was killed by user.")}, MessageLevel::Error); + changeState(LoggedProcess::Aborted); + } +} + +void LoggedProcess::on_error(QProcess::ProcessError error) +{ + switch(error) + { + case QProcess::FailedToStart: + { + emit log({tr("The process failed to start.")}, MessageLevel::Fatal); + changeState(LoggedProcess::FailedToStart); + break; + } + // we'll just ignore those... never needed them + case QProcess::Crashed: + case QProcess::ReadError: + case QProcess::Timedout: + case QProcess::UnknownError: + case QProcess::WriteError: + break; + } +} + +void LoggedProcess::kill() +{ + m_is_aborting = true; + QProcess::kill(); +} + +int LoggedProcess::exitCode() const +{ + return m_exit_code; +} + +void LoggedProcess::changeState(LoggedProcess::State state) +{ + if(state == m_state) + return; + m_state = state; + emit stateChanged(m_state); +} + +LoggedProcess::State LoggedProcess::state() const +{ + return m_state; +} + +void LoggedProcess::on_stateChange(QProcess::ProcessState state) +{ + switch(state) + { + case QProcess::NotRunning: |
