Commit e3bceff3 authored by Erik Verbruggen's avatar Erik Verbruggen

Separated child-process stdout/stderr, and seperated "our" output/errors.

So now the "Applciation Output" can distinguish between these four, and
handle them appropriately.
parent 53425816
......@@ -56,7 +56,7 @@ public:
virtual int exitCode() const = 0;
//signals:
virtual void processError(const QString &error) = 0;
virtual void processMessage(const QString &error, bool isError) = 0;
#ifdef Q_OS_WIN
// Add PATH and SystemRoot environment variables in case they are missing
......
......@@ -81,7 +81,7 @@ public:
#endif
signals:
void processError(const QString &error);
void processMessage(const QString &message, bool isError);
// These reflect the state of the actual client process
void processStarted();
void processStopped();
......
......@@ -70,7 +70,7 @@ bool ConsoleProcess::start(const QString &program, const QStringList &args)
const QString err = stubServerListen();
if (!err.isEmpty()) {
emit processError(msgCommChannelFailed(err));
emit processMessage(msgCommChannelFailed(err), true);
return false;
}
......@@ -78,7 +78,7 @@ bool ConsoleProcess::start(const QString &program, const QStringList &args)
m_tempFile = new QTemporaryFile();
if (!m_tempFile->open()) {
stubServerShutdown();
emit processError(msgCannotCreateTempFile(m_tempFile->errorString()));
emit processMessage(msgCannotCreateTempFile(m_tempFile->errorString()), true);
delete m_tempFile;
m_tempFile = 0;
return false;
......@@ -108,7 +108,7 @@ bool ConsoleProcess::start(const QString &program, const QStringList &args)
m_process.start(xterm, xtermArgs);
if (!m_process.waitForStarted()) {
stubServerShutdown();
emit processError(tr("Cannot start the terminal emulator '%1'.").arg(xterm));
emit processMessage(tr("Cannot start the terminal emulator '%1'.").arg(xterm), true);
delete m_tempFile;
m_tempFile = 0;
return false;
......@@ -189,9 +189,9 @@ void ConsoleProcess::readStubOutput()
QByteArray out = m_stubSocket->readLine();
out.chop(1); // \n
if (out.startsWith("err:chdir ")) {
emit processError(msgCannotChangeToWorkDir(workingDirectory(), errorMsg(out.mid(10).toInt())));
emit processMessage(msgCannotChangeToWorkDir(workingDirectory(), errorMsg(out.mid(10).toInt())), true);
} else if (out.startsWith("err:exec ")) {
emit processError(msgCannotExecute(m_executable, errorMsg(out.mid(9).toInt())));
emit processMessage(msgCannotExecute(m_executable, errorMsg(out.mid(9).toInt())), true);
} else if (out.startsWith("pid ")) {
// Will not need it any more
delete m_tempFile;
......@@ -210,7 +210,7 @@ void ConsoleProcess::readStubOutput()
m_appPid = 0;
emit processStopped();
} else {
emit processError(msgUnexpectedOutput());
emit processMessage(msgUnexpectedOutput(), true);
m_process.terminate();
break;
}
......
......@@ -68,7 +68,7 @@ bool ConsoleProcess::start(const QString &program, const QStringList &args)
const QString err = stubServerListen();
if (!err.isEmpty()) {
emit processError(msgCommChannelFailed(err));
emit processMessage(msgCommChannelFailed(err), true);
return false;
}
......@@ -76,7 +76,7 @@ bool ConsoleProcess::start(const QString &program, const QStringList &args)
m_tempFile = new QTemporaryFile();
if (!m_tempFile->open()) {
stubServerShutdown();
emit processError(msgCannotCreateTempFile(m_tempFile->errorString()));
emit processMessage(msgCannotCreateTempFile(m_tempFile->errorString()), true);
delete m_tempFile;
m_tempFile = 0;
return false;
......@@ -122,7 +122,7 @@ bool ConsoleProcess::start(const QString &program, const QStringList &args)
delete m_tempFile;
m_tempFile = 0;
stubServerShutdown();
emit processError(tr("The process '%1' could not be started: %2").arg(cmdLine, winErrorMessage(GetLastError())));
emit processMessage(tr("The process '%1' could not be started: %2").arg(cmdLine, winErrorMessage(GetLastError())), true);
return false;
}
......@@ -179,9 +179,9 @@ void ConsoleProcess::readStubOutput()
QByteArray out = m_stubSocket->readLine();
out.chop(2); // \r\n
if (out.startsWith("err:chdir ")) {
emit processError(msgCannotChangeToWorkDir(workingDirectory(), winErrorMessage(out.mid(10).toInt())));
emit processMessage(msgCannotChangeToWorkDir(workingDirectory(), winErrorMessage(out.mid(10).toInt())), true);
} else if (out.startsWith("err:exec ")) {
emit processError(msgCannotExecute(m_executable, winErrorMessage(out.mid(9).toInt())));
emit processMessage(msgCannotExecute(m_executable, winErrorMessage(out.mid(9).toInt())), processMessage);
} else if (out.startsWith("pid ")) {
// Wil not need it any more
delete m_tempFile;
......@@ -192,8 +192,8 @@ void ConsoleProcess::readStubOutput()
SYNCHRONIZE | PROCESS_QUERY_INFORMATION | PROCESS_TERMINATE,
FALSE, m_appPid);
if (m_hInferior == NULL) {
emit processError(tr("Cannot obtain a handle to the inferior: %1")
.arg(winErrorMessage(GetLastError())));
emit processMessage(tr("Cannot obtain a handle to the inferior: %1")
.arg(winErrorMessage(GetLastError())), true);
// Uhm, and now what?
continue;
}
......@@ -201,7 +201,7 @@ void ConsoleProcess::readStubOutput()
connect(inferiorFinishedNotifier, SIGNAL(activated(HANDLE)), SLOT(inferiorExited()));
emit processStarted();
} else {
emit processError(msgUnexpectedOutput());
emit processMessage(msgUnexpectedOutput(), true);
TerminateProcess(m_pid->hProcess, (unsigned)-1);
break;
}
......@@ -222,8 +222,8 @@ void ConsoleProcess::inferiorExited()
DWORD chldStatus;
if (!GetExitCodeProcess(m_hInferior, &chldStatus))
emit processError(tr("Cannot obtain exit status from inferior: %1")
.arg(winErrorMessage(GetLastError())));
emit processMessage(tr("Cannot obtain exit status from inferior: %1")
.arg(winErrorMessage(GetLastError())), true);
cleanupInferior();
m_appStatus = QProcess::NormalExit;
m_appCode = chldStatus;
......
......@@ -221,8 +221,8 @@ CdbDebugEngine::CdbDebugEngine(DebuggerManager *manager, const QSharedPointer<Cd
m_d(new CdbDebugEnginePrivate(manager, options, this))
{
m_d->m_consoleStubProc.setMode(Utils::ConsoleProcess::Suspend);
connect(&m_d->m_consoleStubProc, SIGNAL(processError(QString)),
this, SLOT(slotConsoleStubError(QString)));
connect(&m_d->m_consoleStubProc, SIGNAL(processMessage(QString,bool)),
this, SLOT(slotConsoleStubMessage(QString, bool)));
connect(&m_d->m_consoleStubProc, SIGNAL(processStarted()),
this, SLOT(slotConsoleStubStarted()));
connect(&m_d->m_consoleStubProc, SIGNAL(wrapperStopped()),
......@@ -1232,7 +1232,7 @@ void CdbDebugEngine::slotConsoleStubStarted()
}
}
void CdbDebugEngine::slotConsoleStubError(const QString &msg)
void CdbDebugEngine::slotConsoleStubMessage(const QString &msg, bool)
{
QMessageBox::critical(DebuggerUISwitcher::instance()->mainWindow(), tr("Debugger Error"), msg);
}
......
......@@ -106,7 +106,7 @@ public slots:
private slots:
void slotConsoleStubStarted();
void slotConsoleStubError(const QString &msg);
void slotConsoleStubMessage(const QString &msg, bool);
void slotConsoleStubTerminated();
void slotBreakAttachToCrashed();
void warning(const QString &w);
......
......@@ -821,9 +821,9 @@ void DebuggerManager::notifyInferiorPidChanged(qint64 pid)
}
}
void DebuggerManager::showApplicationOutput(const QString &str)
void DebuggerManager::showApplicationOutput(const QString &str, bool onStdErr)
{
emit applicationOutputAvailable(str);
emit applicationOutputAvailable(str, onStdErr);
}
void DebuggerManager::shutdown()
......
......@@ -264,7 +264,7 @@ public slots: // FIXME
//private slots: // FIXME
void showDebuggerOutput(int channel, const QString &msg);
void showDebuggerInput(int channel, const QString &msg);
void showApplicationOutput(const QString &data);
void showApplicationOutput(const QString &data, bool onStdErr);
void reloadSourceFiles();
void sourceFilesDockToggled(bool on);
......@@ -329,7 +329,8 @@ signals:
void inferiorPidChanged(qint64 pid);
void stateChanged(int newstatus);
void statusMessageRequested(const QString &msg, int timeout); // -1 for 'forever'
void applicationOutputAvailable(const QString &output);
void applicationOutputAvailable(const QString &output, bool onStdErr);
void messageAvailable(const QString &output, bool isError);
void emitShowOutput(int channel, const QString &output);
void emitShowInput(int channel, const QString &input);
......
......@@ -179,9 +179,11 @@ void DebuggerRunControl::init()
connect(m_manager, SIGNAL(debuggingFinished()),
this, SLOT(debuggingFinished()),
Qt::QueuedConnection);
connect(m_manager, SIGNAL(applicationOutputAvailable(QString)),
this, SLOT(slotAddToOutputWindowInline(QString)),
connect(m_manager, SIGNAL(applicationOutputAvailable(QString, bool)),
this, SLOT(slotAddToOutputWindowInline(QString, bool)),
Qt::QueuedConnection);
connect(m_manager, SIGNAL(messageAvailable(QString, bool)),
this, SLOT(slotMessageAvailable(QString, bool)));
connect(m_manager, SIGNAL(inferiorPidChanged(qint64)),
this, SLOT(bringApplicationToForeground(qint64)),
Qt::QueuedConnection);
......@@ -200,7 +202,7 @@ void DebuggerRunControl::start()
m_manager->startNewDebugger(m_startParameters);
emit started();
} else {
error(this, errorMessage);
appendMessage(this, errorMessage, true);
emit finished();
Core::ICore::instance()->showWarningWithOptions(tr("Debugger"), errorMessage,
QString(),
......@@ -208,9 +210,15 @@ void DebuggerRunControl::start()
}
}
void DebuggerRunControl::slotAddToOutputWindowInline(const QString &data)
void DebuggerRunControl::slotAddToOutputWindowInline(const QString &data,
bool onStdErr)
{
emit addToOutputWindowInline(this, data);
emit addToOutputWindowInline(this, data, onStdErr);
}
void DebuggerRunControl::slotMessageAvailable(const QString &data, bool isError)
{
emit appendMessage(this, data, isError);
}
void DebuggerRunControl::stop()
......
......@@ -87,7 +87,8 @@ signals:
void stopRequested();
private slots:
void slotAddToOutputWindowInline(const QString &output);
void slotAddToOutputWindowInline(const QString &output, bool onStdErr);
void slotMessageAvailable(const QString &data, bool isError);
private:
void init();
......
......@@ -329,8 +329,8 @@ static void dump(const char *first, const char *middle, const QString & to)
void GdbEngine::readDebugeeOutput(const QByteArray &data)
{
m_manager->showApplicationOutput(m_outputCodec->toUnicode(
data.constData(), data.length(), &m_outputCodecState));
m_manager->messageAvailable(m_outputCodec->toUnicode(
data.constData(), data.length(), &m_outputCodecState), true);
}
void GdbEngine::debugMessage(const QString &msg)
......@@ -541,7 +541,7 @@ void GdbEngine::handleResponse(const QByteArray &buff)
// On Windows, the contents seem to depend on the debugger
// version and/or OS version used.
if (data.startsWith("warning:"))
manager()->showApplicationOutput(_(data.mid(9))); // cut "warning: "
manager()->messageAvailable(_(data.mid(9)), true); // cut "warning: "
break;
}
......
......@@ -59,7 +59,7 @@ TermGdbAdapter::TermGdbAdapter(GdbEngine *engine, QObject *parent)
m_stubProc.setSettings(Core::ICore::instance()->settings());
#endif
connect(&m_stubProc, SIGNAL(processError(QString)), SLOT(stubError(QString)));
connect(&m_stubProc, SIGNAL(processMessage(QString, bool)), SLOT(stubMessage(QString, bool)));
connect(&m_stubProc, SIGNAL(processStarted()), SLOT(handleInferiorStarted()));
connect(&m_stubProc, SIGNAL(wrapperStopped()), SLOT(stubExited()));
}
......@@ -165,7 +165,7 @@ void TermGdbAdapter::interruptInferior()
debugMessage(_("CANNOT INTERRUPT %1").arg(attachedPID));
}
void TermGdbAdapter::stubError(const QString &msg)
void TermGdbAdapter::stubMessage(const QString &msg, bool)
{
showMessageBox(QMessageBox::Critical, tr("Debugger Error"), msg);
}
......
......@@ -66,7 +66,7 @@ private:
Q_SLOT void handleInferiorStarted();
Q_SLOT void stubExited();
Q_SLOT void stubError(const QString &msg);
Q_SLOT void stubMessage(const QString &msg, bool isError);
Utils::ConsoleProcess m_stubProc;
};
......
......@@ -70,19 +70,20 @@ public:
qint64 applicationPID() const;
signals:
void applicationError(const QString &error);
void appendOutput(const QString &line);
void appendMessage(const QString &message, bool isError);
void appendOutput(const QString &line, bool onStdErr);
void processExited(int exitCode);
void bringToForegroundRequested(qint64 pid);
private slots:
void processStopped();
#ifdef Q_OS_WIN
void readWinDebugOutput(const QString &output);
void readWinDebugOutput(const QString &output, bool onStdErr);
void processFinished(int exitCode);
#else
void guiProcessError();
void readStandardOutput();
void readStandardError();
void processDone(int, QProcess::ExitStatus);
#endif
......
......@@ -43,16 +43,16 @@ ApplicationLauncher::ApplicationLauncher(QObject *parent)
m_currentMode = Gui;
m_consoleProcess = new ConsoleProcess(this);
connect(m_consoleProcess, SIGNAL(processError(const QString&)),
this, SIGNAL(applicationError(const QString&)));
connect(m_consoleProcess, SIGNAL(processMessage(const QString&, bool)),
this, SIGNAL(appendMessage(QString,bool)));
connect(m_consoleProcess, SIGNAL(processStopped()),
this, SLOT(processStopped()));
m_winGuiProcess = new WinGuiProcess(this);
connect(m_winGuiProcess, SIGNAL(processError(const QString&)),
this, SIGNAL(applicationError(const QString&)));
connect(m_winGuiProcess, SIGNAL(receivedDebugOutput(const QString&)),
this, SLOT(readWinDebugOutput(const QString&)));
connect(m_winGuiProcess, SIGNAL(processMessage(const QString &, bool)),
this, SIGNAL(appendMessage(QString,bool)));
connect(m_winGuiProcess, SIGNAL(receivedDebugOutput(const QString&, bool)),
this, SLOT(readWinDebugOutput(const QString&, bool)));
connect(m_winGuiProcess, SIGNAL(processFinished(int)),
this, SLOT(processFinished(int)));
......@@ -111,9 +111,10 @@ qint64 ApplicationLauncher::applicationPID() const
return result;
}
void ApplicationLauncher::readWinDebugOutput(const QString &output)
void ApplicationLauncher::readWinDebugOutput(const QString &output,
bool onStdErr)
{
emit appendOutput(output);
emit appendOutput(output, onStdErr);
}
void ApplicationLauncher::processStopped()
......
......@@ -43,11 +43,13 @@ ApplicationLauncher::ApplicationLauncher(QObject *parent)
m_outputCodec = QTextCodec::codecForLocale();
m_currentMode = Gui;
m_guiProcess = new QProcess(this);
m_guiProcess->setReadChannelMode(QProcess::MergedChannels);
m_guiProcess->setReadChannelMode(QProcess::SeparateChannels);
connect(m_guiProcess, SIGNAL(error(QProcess::ProcessError)),
this, SLOT(guiProcessError()));
connect(m_guiProcess, SIGNAL(readyReadStandardOutput()),
this, SLOT(readStandardOutput()));
connect(m_guiProcess, SIGNAL(readyReadStandardError()),
this, SLOT(readStandardError()));
connect(m_guiProcess, SIGNAL(finished(int, QProcess::ExitStatus)),
this, SLOT(processDone(int, QProcess::ExitStatus)));
connect(m_guiProcess, SIGNAL(started()),
......@@ -55,8 +57,8 @@ ApplicationLauncher::ApplicationLauncher(QObject *parent)
m_consoleProcess = new ConsoleProcess(this);
m_consoleProcess->setSettings(Core::ICore::instance()->settings());
connect(m_consoleProcess, SIGNAL(processError(const QString&)),
this, SIGNAL(applicationError(const QString&)));
connect(m_consoleProcess, SIGNAL(processMessage(QString,bool)),
this, SIGNAL(appendMessage(QString,bool)));
connect(m_consoleProcess, SIGNAL(processStopped()),
this, SLOT(processStopped()));
}
......@@ -131,14 +133,23 @@ void ApplicationLauncher::guiProcessError()
default:
error = tr("Some error has occurred while running the program.");
}
emit applicationError(error);
emit appendMessage(error, true);
}
void ApplicationLauncher::readStandardOutput()
{
QByteArray data = m_guiProcess->readAllStandardOutput();
emit appendOutput(m_outputCodec->toUnicode(
data.constData(), data.length(), &m_outputCodecState));
data.constData(), data.length(), &m_outputCodecState),
false);
}
void ApplicationLauncher::readStandardError()
{
QByteArray data = m_guiProcess->readAllStandardError();
emit appendOutput(m_outputCodec->toUnicode(
data.constData(), data.length(), &m_outputCodecState),
true);
}
void ApplicationLauncher::processStopped()
......
......@@ -101,10 +101,10 @@ LocalApplicationRunControl::LocalApplicationRunControl(LocalApplicationRunConfig
m_runMode = static_cast<ApplicationLauncher::Mode>(runConfiguration->runMode());
m_commandLineArguments = runConfiguration->commandLineArguments();
connect(&m_applicationLauncher, SIGNAL(applicationError(QString)),
this, SLOT(slotError(QString)));
connect(&m_applicationLauncher, SIGNAL(appendOutput(QString)),
this, SLOT(slotAddToOutputWindow(QString)));
connect(&m_applicationLauncher, SIGNAL(appendMessage(QString,bool)),
this, SLOT(slotAppendMessage(QString,bool)));
connect(&m_applicationLauncher, SIGNAL(appendOutput(QString, bool)),
this, SLOT(slotAddToOutputWindow(QString, bool)));
connect(&m_applicationLauncher, SIGNAL(processExited(int)),
this, SLOT(processExited(int)));
connect(&m_applicationLauncher, SIGNAL(bringToForegroundRequested(qint64)),
......@@ -120,7 +120,7 @@ void LocalApplicationRunControl::start()
m_applicationLauncher.start(m_runMode, m_executable, m_commandLineArguments);
emit started();
emit addToOutputWindow(this, tr("Starting %1...").arg(QDir::toNativeSeparators(m_executable)));
emit appendMessage(this, tr("Starting %1...").arg(QDir::toNativeSeparators(m_executable)), false);
}
void LocalApplicationRunControl::stop()
......@@ -133,20 +133,22 @@ bool LocalApplicationRunControl::isRunning() const
return m_applicationLauncher.isRunning();
}
void LocalApplicationRunControl::slotError(const QString & err)
void LocalApplicationRunControl::slotAppendMessage(const QString &err,
bool isError)
{
emit error(this, err);
emit appendMessage(this, err, isError);
emit finished();
}
void LocalApplicationRunControl::slotAddToOutputWindow(const QString &line)
void LocalApplicationRunControl::slotAddToOutputWindow(const QString &line,
bool stderr)
{
emit addToOutputWindowInline(this, line);
emit addToOutputWindowInline(this, line, stderr);
}
void LocalApplicationRunControl::processExited(int exitCode)
{
emit addToOutputWindow(this, tr("%1 exited with code %2").arg(QDir::toNativeSeparators(m_executable)).arg(exitCode));
emit appendMessage(this, tr("%1 exited with code %2").arg(QDir::toNativeSeparators(m_executable)).arg(exitCode), false);
emit finished();
}
......@@ -88,8 +88,8 @@ public:
virtual bool isRunning() const;
private slots:
void processExited(int exitCode);
void slotAddToOutputWindow(const QString &line);
void slotError(const QString & error);
void slotAddToOutputWindow(const QString &line, bool stderr);
void slotAppendMessage(const QString &err, bool isError);
private:
ProjectExplorer::ApplicationLauncher m_applicationLauncher;
QString m_executable;
......
......@@ -49,7 +49,7 @@ void OutputFormatter::setPlainTextEdit(QPlainTextEdit *plainText)
setParent(m_plainTextEdit);
}
void OutputFormatter::appendOutput(const QString &text)
void OutputFormatter::appendApplicationOutput(const QString &text, bool /*onStdErr*/)
{
QTextCharFormat format;
format.setForeground(plainTextEdit()->palette().text().color());
......@@ -57,9 +57,9 @@ void OutputFormatter::appendOutput(const QString &text)
plainTextEdit()->insertPlainText(text);
}
void OutputFormatter::appendError(const QString &text)
void OutputFormatter::appendMessage(const QString &text, bool isError)
{
appendOutput(text);
appendApplicationOutput(text, isError);
}
void OutputFormatter::mousePressEvent(QMouseEvent * /*e*/)
......
......@@ -50,8 +50,8 @@ public:
QPlainTextEdit *plainTextEdit() const;
void setPlainTextEdit(QPlainTextEdit *plainText);
virtual void appendOutput(const QString &text);
virtual void appendError(const QString &text);
virtual void appendApplicationOutput(const QString &text, bool onStdErr);
virtual void appendMessage(const QString &text, bool isError);
virtual void mousePressEvent(QMouseEvent *e);
virtual void mouseReleaseEvent(QMouseEvent *e);
......
......@@ -210,22 +210,25 @@ void OutputPane::createNewOutputWindow(RunControl *rc)
}
}
void OutputPane::appendOutput(RunControl *rc, const QString &out)
void OutputPane::appendApplicationOutput(RunControl *rc, const QString &out,
bool onStdErr)
{
OutputWindow *ow = m_outputWindows.value(rc);
ow->appendOutput(out);
ow->appendApplicationOutput(out, onStdErr);
}
void OutputPane::appendOutputInline(RunControl *rc, const QString &out)
void OutputPane::appendApplicationOutputInline(RunControl *rc,
const QString &out,
bool onStdErr)
{
OutputWindow *ow = m_outputWindows.value(rc);
ow->appendOutputInline(out);
ow->appendApplicationOutputInline(out, onStdErr);
}
void OutputPane::appendError(RunControl *rc, const QString &out)
void OutputPane::appendMessage(RunControl *rc, const QString &out, bool isError)
{
OutputWindow *ow = m_outputWindows.value(rc);
ow->appendError(out);
ow->appendMessage(out, isError);
}
void OutputPane::showTabFor(RunControl *rc)
......@@ -424,7 +427,7 @@ void OutputWindow::showEvent(QShowEvent *e)
m_scrollToBottom = false;
}
QString OutputWindow::doNewlineMagic(const QString &out)
QString OutputWindow::doNewlineEnfocement(const QString &out)
{
m_scrollToBottom = true;
QString s = out;
......@@ -439,17 +442,17 @@ QString OutputWindow::doNewlineMagic(const QString &out)
return s;
}
void OutputWindow::appendOutput(const QString &out)
void OutputWindow::appendApplicationOutput(const QString &out, bool onStdErr)
{
setMaximumBlockCount(MaxBlockCount);
const bool atBottom = isScrollbarAtBottom();
m_formatter->appendOutput(doNewlineMagic(out));
m_formatter->appendApplicationOutput(doNewlineEnfocement(out), onStdErr);
if (atBottom)
scrollToBottom();
enableUndoRedo();
}
void OutputWindow::appendOutputInline(const QString &out)
void OutputWindow::appendApplicationOutputInline(const QString &out, bool onStdErr)
{
m_scrollToBottom = true;
setMaximumBlockCount(MaxBlockCount);
......@@ -462,7 +465,7 @@ void OutputWindow::appendOutputInline(const QString &out)
if (!enforceNewline) {
newline = out.indexOf(QLatin1Char('\n'));
moveCursor(QTextCursor::End);
m_formatter->appendOutput(newline < 0 ? out : out.left(newline)); // doesn't enforce new paragraph like appendPlainText