#include "launch_manager.hpp" #include "debug.hpp" LaunchManager::~LaunchManager(){ if(currentLaunch){ auto& p = currentLaunch->process; p.blockSignals(true); p.terminate(); p.waitForFinished(500); if(p.state() != QProcess::NotRunning){ p.kill(); p.waitForFinished(1000); } } queuedLaunch.reset(); } void LaunchManager::launch(std::unique_ptr&& ctx){ if(getCurrentStatus() == LaunchContext::Type::None){ doLaunch(std::move(ctx)); } else { if(queuedLaunch && queuedLaunch->type == LaunchContext::Type::Run){ return; } queuedLaunch = std::move(ctx); currentLaunch->terminate(); } } void LaunchManager::doLaunch(std::unique_ptr&& ctx){ currentLaunch = std::move(ctx); connect(¤tLaunch->process, QOverload::of(&QProcess::finished), this, &LaunchManager::processFinished, Qt::UniqueConnection); currentLaunch->process.start(currentLaunch->executablePath, currentLaunch->args); if(!currentLaunch->process.waitForStarted()){ //Shouldn't happen as we probe ug executability at startup abort_msgBox("Failed to launch process. Did the ug executable disappear?"); } } void LaunchManager::stop(){ if(!currentLaunch) return; currentLaunch->terminate(); } void LaunchManager::processFinished(){ currentLaunch.reset(); if(queuedLaunch) doLaunch(std::move(queuedLaunch)); } std::unique_ptr LaunchManager::extractCurrentCtx(){ auto ret = std::move(currentLaunch); return ret; } void LaunchManager::reLaunch(std::unique_ptr&& ctx){ queuedLaunch = std::move(ctx); } LaunchContext::Type LaunchManager::getCurrentStatus() const{ if(!currentLaunch) return LaunchContext::Type::None; return currentLaunch->type; } LaunchContext::LaunchContext(){ connect(&killTimer, &QTimer::timeout, [=](){ process.kill(); }); killTimer.setSingleShot(true); connect(&process, QOverload::of(&QProcess::finished), this, &LaunchContext::processTerminationHandler); process.setProcessChannelMode(QProcess::MergedChannels); connect(&process, &QProcess::readyReadStandardOutput, this, &LaunchContext::processOutput); connect(&process, &QProcess::readyReadStandardError, this, &LaunchContext::processOutput); } void LaunchContext::processTerminationHandler(int code, QProcess::ExitStatus es){ emit processTerminated(code, es, terminationRequested); } void LaunchContext::processOutput(){ QString str = process.isReadable() ? process.readAll() : QByteArray(); emit processOutputRead(str); lineBuf.write(str.toStdString()); while(lineBuf.hasLine()){ emit processOutputLine(lineBuf.peek()); lineBuf.pop(); } } void LaunchContext::terminate(){ terminationRequested = true; process.terminate(); killTimer.start(terminateTimeoutMs); }