Index: /tests/process/process-async/process-async.cpp
===================================================================
--- /tests/process/process-async/process-async.cpp	(revision 903)
+++ /tests/process/process-async/process-async.cpp	(revision 903)
@@ -0,0 +1,398 @@
+#include <QtCore>
+
+//#include <QtGui>
+#include <QApplication>
+#include <QWidget>
+#include <QTextEdit>
+#include <QLineEdit>
+#include <QLabel>
+#include <QTabWidget>
+#include <QLayout>
+
+#include <QDebug>
+
+#define STR(expr) #expr
+#define DBG(expr) STR(expr) << "=" << (expr)
+
+class MyWidget : public QWidget
+{
+    Q_OBJECT
+
+public:
+
+    MyWidget(QWidget *aParent)
+        : QWidget(aParent), mOtherProcess(0), mRedirectedToOtherProcess(false)
+    {
+        // children
+
+        mProcess = new QProcess(this);
+
+        mEditor = new QTextEdit();
+        mEditor->setReadOnly(true);
+
+        mLineEdit = new QLineEdit();
+        mStatusLabel = new QLabel();
+
+        // connections
+
+        connect(mProcess, SIGNAL(stateChanged(QProcess::ProcessState)),
+                this, SLOT(process_stateChanged(QProcess::ProcessState)));
+        connect(mProcess, SIGNAL(error(QProcess::ProcessError)),
+                this, SLOT(process_error(QProcess::ProcessError)));
+        connect(mProcess, SIGNAL(started()),
+                this, SLOT(process_started()));
+        connect(mProcess, SIGNAL(finished(int, QProcess::ExitStatus)),
+                this, SLOT(process_finished(int, QProcess::ExitStatus)));
+        connect(mProcess, SIGNAL(readyReadStandardOutput()),
+                this, SLOT(process_readyReadStandardOutput()));
+        connect(mProcess, SIGNAL(readyReadStandardError()),
+                this, SLOT(process_readyReadStandardError()));
+
+        connect(mLineEdit, SIGNAL(returnPressed()),
+                this, SLOT(lineEdit_returnPressed()));
+
+        // layout
+
+        QVBoxLayout *l1 = new QVBoxLayout();
+        l1->addWidget(mEditor);
+        l1->addWidget(mLineEdit);
+        l1->addWidget(mStatusLabel);
+
+        QHBoxLayout *mainLayout = new QHBoxLayout();
+        mainLayout->addLayout(l1);
+
+        setLayout(mainLayout);
+
+        mLineEdit->setFocus();
+
+        // initial values
+
+        mLineEdit->setText("D:\\Coding\\qt\\smplayer_test\\mplayer.ex");
+
+        process_stateChanged(mProcess->state());
+
+        // other
+    }
+
+    QProcess *process() const { return mProcess; }
+    void setOtherProcess(QProcess *aOtherProcess) { mOtherProcess = aOtherProcess; }
+
+private slots:
+
+    void lineEdit_returnPressed()
+    {
+        QString text = mLineEdit->text();
+        if (text.isEmpty())
+            return;
+
+        mLineEdit->clear();
+
+        text = text.trimmed();
+
+        QString cmd;
+        if (text.startsWith('>'))
+        {
+            int ws = text.indexOf(' ');
+            if (ws < 0)
+                ws = text.length();
+            cmd = text.mid(1, ws - 1);
+
+            text = text.mid(ws);
+            text = text.trimmed();
+        }
+
+        // @todo support for quoted strings
+        QStringList words = text.split(' ');
+
+        if (cmd.isNull() && mProcess->state() == QProcess::NotRunning)
+            cmd = "s";
+
+        if (cmd.isNull())
+        {
+            Q_ASSERT(mProcess->state() != QProcess::NotRunning);
+
+            /* send the line to standard input */
+            QByteArray data = (text + "\n").toLocal8Bit();
+            mProcess->write(data);
+        }
+        else if (cmd == "s" || cmd == "ss" || cmd == "scd" || cmd == "sscd")
+        {
+            /* start process (..cd changes to its directory) */
+
+            if (words.count() < 1)
+            {
+                mEditor->append(tr("> ERROR: '%1' requires one argument").arg(cmd));
+                return;
+            }
+            if (mProcess->state() != QProcess::NotRunning)
+            {
+                mEditor->append(tr("> ERROR: Process is already running"));
+                return;
+            }
+
+            QString workDir;
+            if (cmd.endsWith("cd"))
+            {
+                QDir dir = QDir(QFileInfo(words[0]).path());
+                workDir = dir.absolutePath();
+                mProcess->setWorkingDirectory(workDir);
+            }
+            else
+            {
+                workDir = QDir::currentPath();
+                mProcess->setWorkingDirectory(QString());
+            }
+            mEditor->append(tr("> Working directory: '%1'").arg(workDir));
+
+            mEditor->append(tr("> Starting: '%1'").arg(text));
+            mProcess->start(text);
+        }
+        else if (cmd == "rso" || cmd == "rse")
+        {
+            /* redirect stdout & stderr */
+
+            if (mProcess->state() != QProcess::NotRunning)
+            {
+                mEditor->append(tr("> ERROR: Process is already running"));
+                return;
+            }
+
+            bool output = cmd == "rso";
+            output ? mProcess->setStandardOutputFile(text)
+                   : mProcess->setStandardErrorFile(text);
+
+            if (!text.isEmpty())
+                mEditor->append(tr("> Redirected standard %1 stream to: '%2'")
+                                .arg(output ? "output" : "error").arg(text));
+            else
+                mEditor->append(tr("> Canceled redirection of standard %1")
+                                .arg(output ? "output" : "error"));
+        }
+        else if (cmd == "term")
+        {
+            /* terminate */
+
+            if (mProcess->state() == QProcess::NotRunning)
+            {
+                mEditor->append(tr("> ERROR: No process is running"));
+                return;
+            }
+
+            mEditor->append(tr("> Sent terminate process request"));
+            mProcess->terminate();
+        }
+        else if (cmd == "kill")
+        {
+            /* kill */
+
+            if (mProcess->state() == QProcess::NotRunning)
+            {
+                mEditor->append(tr("> ERROR: No process is running"));
+                return;
+            }
+
+            mEditor->append(tr("> Sent kill process request"));
+            mProcess->kill();
+        }
+        else if (cmd == "rtp")
+        {
+            /* redirect stdout to stdin of the other process */
+
+            if (mProcess->state() != QProcess::NotRunning)
+            {
+                mEditor->append(tr("> ERROR: Process is already running"));
+                return;
+            }
+
+            if (!mRedirectedToOtherProcess)
+            {
+                mRedirectedToOtherProcess = true;
+                mProcess->setStandardOutputProcess(mOtherProcess);
+                mEditor->append(tr("> Redirected standard output to standard "
+                                   "input of another process"));
+            }
+            else
+            {
+                mRedirectedToOtherProcess = false;
+                mProcess->setStandardErrorFile(QString::null);
+                mEditor->append(tr("> Canceled redirection of standard output"));
+            }
+        }
+        else if (cmd == "d" || cmd == "dcd")
+        {
+            QString workDir;
+            if (cmd.endsWith("cd"))
+            {
+                QDir dir = QDir(QFileInfo(words[0]).path());
+                workDir = dir.absolutePath();
+            }
+            else
+            {
+                workDir = QDir::currentPath();
+            }
+            mEditor->append(tr("> Working directory: '%1'").arg(workDir));
+
+            mEditor->append(tr("> Detaching: '%1'").arg(text));
+            QStringList args = words;
+            QString prg = args.takeFirst();
+            qint64 pid;
+            if (QProcess::startDetached(prg, args, workDir, &pid))
+                mEditor->append(tr("> Detached successfully (pid '%1')").arg(pid));
+            else
+                mEditor->append(tr("> Detach failed"));
+        }
+        else
+        {
+            mEditor->append(tr("> ERROR: '%1' command is unknown").arg(cmd));
+            return;
+        }
+    }
+
+    void process_stateChanged(QProcess::ProcessState aState)
+    {
+        QString state;
+        switch (aState)
+        {
+            case QProcess::NotRunning: state = tr("NotRunning"); break;
+            case QProcess::Starting: state = tr("Starting"); break;
+            case QProcess::Running: state = tr("Running"); break;
+        }
+        mStatusLabel->setText(tr("%1 (PID: %2)").arg(state).arg((ulong)mProcess->pid()));
+    }
+
+    void process_error(QProcess::ProcessError aError)
+    {
+        QString error;
+        switch (aError)
+        {
+            case QProcess::FailedToStart: error = tr("FailedToStart"); break;
+            case QProcess::Crashed: error = tr("Crashed"); break;
+            case QProcess::Timedout: error = tr("Timedout"); break;
+            case QProcess::WriteError: error = tr("WriteError"); break;
+            case QProcess::ReadError: error = tr("ReadError"); break;
+            case QProcess::UnknownError: error = tr("UnknownError"); break;
+        }
+        mEditor->append(tr("> ERROR: %1: %2").arg(error).arg(mProcess->errorString()));
+    }
+
+    void process_started()
+    {
+        mEditor->append(tr("> Started: PID is %1").arg((ulong)mProcess->pid()));
+    }
+
+    void process_finished(int aExitCode, QProcess::ExitStatus aExitStatus)
+    {
+        QString exitStatus;
+        switch (aExitStatus)
+        {
+            case QProcess::NormalExit: exitStatus = tr("NormalExit"); break;
+            case QProcess::CrashExit: exitStatus = tr("CrashExit"); break;
+        }
+        mEditor->append(tr("> Finished: %1 with code %2").arg(exitStatus).arg(aExitCode));
+    }
+
+    void process_readyReadStandardOutput()
+    {
+        QByteArray data = mProcess->readAllStandardOutput();
+        mEditor->append(QString::fromLocal8Bit(data));
+    }
+
+    void process_readyReadStandardError()
+    {
+        QByteArray data = mProcess->readAllStandardError();
+        mEditor->append(QString::fromLocal8Bit(data));
+    }
+
+private:
+
+    QProcess *mProcess;
+    QProcess *mOtherProcess;
+    bool mRedirectedToOtherProcess;
+
+    QTextEdit *mEditor;
+    QLineEdit *mLineEdit;
+    QLabel *mStatusLabel;
+};
+
+////////////////////////////////////////////////////////////////////////////////
+
+class MyDialog : public QWidget
+{
+    Q_OBJECT
+
+public:
+
+    MyDialog() : QWidget(0, Qt::Window)
+    {
+        // children
+
+        QTabWidget *tabs = new QTabWidget();
+
+        mWidget1 = new MyWidget(tabs);
+        mWidget2 = new MyWidget(tabs);
+
+        mWidget1->setOtherProcess(mWidget2->process());
+        mWidget2->setOtherProcess(mWidget1->process());
+
+        tabs->addTab(mWidget1, QLatin1String("Process 1"));
+        tabs->addTab(mWidget2, QLatin1String("Process 2"));
+
+        // connections
+
+        // layout
+
+        QHBoxLayout *mainLayout = new QHBoxLayout();
+        mainLayout->addWidget(tabs);
+
+        setLayout(mainLayout);
+
+        // initial values
+
+        tabs->currentWidget()->setFocus();
+
+        // other
+    }
+
+private:
+
+    MyWidget *mWidget1;
+    MyWidget *mWidget2;
+};
+
+////////////////////////////////////////////////////////////////////////////////
+
+int main(int argc, char *argv[])
+{
+#if 1
+
+    QApplication app(argc, argv);
+
+    MyDialog dialog;
+    dialog.resize(800, 400);
+    dialog.show();
+
+	return app.exec();
+
+#else
+
+    qDebug() << "Starting...";
+
+    QProcess proc;
+#if defined(Q_OS_OS2)
+    //proc.start("cmd.exe /c dir >bbb");
+    //proc.start("cmd /c start /n newview.exe");
+    proc.start("test");
+#elif defined(Q_OS_WIN)
+    proc.start("notepad.exe");
+#endif
+
+    qDebug() << "Waiting for finished...";
+    proc.waitForFinished();
+
+    qDebug() << "DONE";
+
+#endif
+}
+
+#include "process-async.moc"
+
Index: /tests/process/process-async/process-async.pro
===================================================================
--- /tests/process/process-async/process-async.pro	(revision 903)
+++ /tests/process/process-async/process-async.pro	(revision 903)
@@ -0,0 +1,8 @@
+DEPTH = ..
+include($$DEPTH/../common.pri)
+else:error("Cannot include $$DEPTH/../common.pri!")
+
+QT = core gui
+CONFIG += console
+
+SOURCES += process-async.cpp
Index: /tests/process/process.pro
===================================================================
--- /tests/process/process.pro	(revision 902)
+++ /tests/process/process.pro	(revision 903)
@@ -3,3 +3,3 @@
 
 TEMPLATE = subdirs
-SUBDIRS = process test
+SUBDIRS = process-async test
