changeset 15635:a89e968265e8 draft

Intermediate commit.
author Jacob Dawid <jacob.dawid@googlemail.com>
date Mon, 23 Jan 2012 22:27:05 +0100
parents 3524352c7382
children 462e0f609d01
files libqterminal/Pty.cpp libqterminal/Pty.h libqterminal/QTerminal.cpp libqterminal/Session.cpp libqterminal/Session.h libqterminal/k3process.cpp libqterminal/k3process.h libqterminal/kpty.cpp libqterminal/kpty.h libqterminal/kpty_p.h qterminal/qterminal.pro
diffstat 11 files changed, 367 insertions(+), 291 deletions(-) [+]
line wrap: on
line diff
--- a/libqterminal/Pty.cpp
+++ b/libqterminal/Pty.cpp
@@ -152,8 +152,10 @@
                const QStringList& programArguments, 
                const QStringList& environment, 
                ulong winid, 
-               bool addToUtmp
-//               const QString& dbusService, 
+               bool addToUtmp,
+               int masterFd,
+               int slaveFd
+//               const QString& dbusService,
 //               const QString& dbusSession)
 		)
 {
@@ -188,7 +190,7 @@
   if (!environment.contains("LANGUAGE"))
       setEnvironment("LANGUAGE",QString());
 
-  setUsePty(All, addToUtmp);
+  setUsePty(All, addToUtmp, masterFd, slaveFd);
 
   pty()->open();
   
@@ -247,7 +249,26 @@
           this, SLOT(writeReady()));
   _pty = new KPty;
 
-  setUsePty(All, false); // utmp will be overridden later
+  setUsePty(All, false, -1, -1); // utmp will be overridden later
+}
+
+Pty::Pty(int masterFd, int slaveFd)
+    : _bufferFull(false),
+      _windowColumns(0),
+      _windowLines(0),
+      _eraseChar(0),
+      _xonXoff(true),
+      _utf8(true)
+{
+  connect(this, SIGNAL(receivedStdout(K3Process *, char *, int )),
+          this, SLOT(dataReceived(K3Process *,char *, int)));
+  connect(this, SIGNAL(processExited(K3Process *)),
+          this, SLOT(donePty()));
+  connect(this, SIGNAL(wroteStdin(K3Process *)),
+          this, SLOT(writeReady()));
+  _pty = new KPty(masterFd, slaveFd);
+
+  setUsePty(All, false, masterFd, slaveFd); // utmp will be overridden later
 }
 
 Pty::~Pty()
--- a/libqterminal/Pty.h
+++ b/libqterminal/Pty.h
@@ -66,6 +66,8 @@
      * name of the program to start and appropriate arguments.
      */
     Pty();
+    Pty(int masterFd, int slaveFd);
+
     ~Pty();
 
     /**
@@ -92,7 +94,9 @@
                const QStringList& arguments, 
                const QStringList& environment, 
                ulong winid, 
-               bool addToUtmp
+               bool addToUtmp,
+               int masterFd,
+               int slaveFd
 //               const QString& dbusService,
 //               const QString& dbusSession
              );
--- a/libqterminal/QTerminal.cpp
+++ b/libqterminal/QTerminal.cpp
@@ -18,6 +18,7 @@
 						
 
 #include "QTerminal.h"
+#include "pty.h"
 
 using namespace Konsole;
 
@@ -33,7 +34,15 @@
 
 void QTerminal::init()
 {
-    m_session = new Session();
+    int fdm;
+    int fds;
+    openpty (&fdm, &fds, 0, 0, 0);
+
+    dup2 (fds, 0);
+    dup2 (fds, 1);
+    dup2 (fds, 2);
+
+    m_session = new Session(fdm, fds);
 
     m_session->setTitle(Session::NameRole, "QTermWidget");
     m_session->setProgram("/bin/bash");
--- a/libqterminal/Session.cpp
+++ b/libqterminal/Session.cpp
@@ -47,49 +47,56 @@
 
 int Session::lastSessionId = 0;
 
-Session::Session() :
+Session::Session(int masterFd, int slaveFd) :
     _shellProcess(0)
-   , _emulation(0)
-   , _monitorActivity(false)
-   , _monitorSilence(false)
-   , _notifiedActivity(false)
-   , _autoClose(true)
-   , _wantedClose(false)
-   , _silenceSeconds(10)
-   , _addToUtmp(false)  // disabled by default because of a bug encountered on certain systems
-                        // which caused Konsole to hang when closing a tab and then opening a new
-                        // one.  A 'QProcess destroyed while still running' warning was being
-                        // printed to the terminal.  Likely a problem in KPty::logout() 
-                        // or KPty::login() which uses a QProcess to start /usr/bin/utempter 
-   , _flowControl(true)
-   , _fullScripting(false)
-   , _sessionId(0)
-//   , _zmodemBusy(false)
-//   , _zmodemProc(0)
-//   , _zmodemProgress(0)
-   , _hasDarkBackground(false)
+  , _emulation(0)
+  , _monitorActivity(false)
+  , _monitorSilence(false)
+  , _notifiedActivity(false)
+  , _autoClose(true)
+  , _wantedClose(false)
+  , _silenceSeconds(10)
+  , _addToUtmp(false)  // disabled by default because of a bug encountered on certain systems
+  // which caused Konsole to hang when closing a tab and then opening a new
+  // one.  A 'QProcess destroyed while still running' warning was being
+  // printed to the terminal.  Likely a problem in KPty::logout()
+  // or KPty::login() which uses a QProcess to start /usr/bin/utempter
+  , _flowControl(true)
+  , _fullScripting(false)
+  , _sessionId(0)
+  //   , _zmodemBusy(false)
+  //   , _zmodemProc(0)
+  //   , _zmodemProgress(0)
+  , _hasDarkBackground(false)
 {
+    _masterFd = masterFd;
+    _slaveFd = slaveFd;
+
     //prepare DBus communication
-//    new SessionAdaptor(this);
+    //    new SessionAdaptor(this);
     _sessionId = ++lastSessionId;
-//    QDBusConnection::sessionBus().registerObject(QLatin1String("/Sessions/")+QString::number(_sessionId), this);
+    //    QDBusConnection::sessionBus().registerObject(QLatin1String("/Sessions/")+QString::number(_sessionId), this);
 
     //create teletype for I/O with shell process
-    _shellProcess = new Pty();
+    if(_masterFd >= 0) {
+        _shellProcess = new Pty(_masterFd, _slaveFd);
+    } else {
+        _shellProcess = new Pty();
+    }
 
     //create emulation backend
     _emulation = new Vt102Emulation();
 
     connect( _emulation, SIGNAL( titleChanged( int, const QString & ) ),
-           this, SLOT( setUserTitle( int, const QString & ) ) );
+             this, SLOT( setUserTitle( int, const QString & ) ) );
     connect( _emulation, SIGNAL( stateSet(int) ),
-           this, SLOT( activityStateSet(int) ) );
-//    connect( _emulation, SIGNAL( zmodemDetected() ), this ,
-//            SLOT( fireZModemDetected() ) );
+             this, SLOT( activityStateSet(int) ) );
+    //    connect( _emulation, SIGNAL( zmodemDetected() ), this ,
+    //            SLOT( fireZModemDetected() ) );
     connect( _emulation, SIGNAL( changeTabTextColorRequest( int ) ),
-           this, SIGNAL( changeTabTextColorRequest( int ) ) );
+             this, SIGNAL( changeTabTextColorRequest( int ) ) );
     connect( _emulation, SIGNAL(profileChangeCommandReceived(const QString&)),
-           this, SIGNAL( profileChangeCommandReceived(const QString&)) );
+             this, SIGNAL( profileChangeCommandReceived(const QString&)) );
     // TODO
     // connect( _emulation,SIGNAL(imageSizeChanged(int,int)) , this ,
     //        SLOT(onEmulationSizeChange(int,int)) );
@@ -98,9 +105,9 @@
     _shellProcess->setUtf8Mode(_emulation->utf8());
 
     connect( _shellProcess,SIGNAL(receivedData(const char*,int)),this,
-            SLOT(onReceiveBlock(const char*,int)) );
+             SLOT(onReceiveBlock(const char*,int)) );
     connect( _emulation,SIGNAL(sendData(const char*,int)),_shellProcess,
-            SLOT(sendData(const char*,int)) );
+             SLOT(sendData(const char*,int)) );
     connect( _emulation,SIGNAL(lockPtyRequest(bool)),_shellProcess,SLOT(lockPty(bool)) );
     connect( _emulation,SIGNAL(useUtf8Request(bool)),_shellProcess,SLOT(setUtf8Mode(bool)) );
 
@@ -128,7 +135,7 @@
     // returned
 
     if ( _views.count() == 0 )
-       return 0;
+        return 0;
     else
     {
         QWidget* window = _views.first();
@@ -180,7 +187,7 @@
 
 void Session::addView(TerminalDisplay* widget)
 {
-     Q_ASSERT( !_views.contains(widget) );
+    Q_ASSERT( !_views.contains(widget) );
 
     _views.append(widget);
 
@@ -188,16 +195,16 @@
     {
         // connect emulation - view signals and slots
         connect( widget , SIGNAL(keyPressedSignal(QKeyEvent*)) , _emulation ,
-               SLOT(sendKeyEvent(QKeyEvent*)) );
+                 SLOT(sendKeyEvent(QKeyEvent*)) );
         connect( widget , SIGNAL(mouseSignal(int,int,int,int)) , _emulation ,
-               SLOT(sendMouseEvent(int,int,int,int)) );
+                 SLOT(sendMouseEvent(int,int,int,int)) );
         connect( widget , SIGNAL(sendStringToEmu(const char*)) , _emulation ,
-               SLOT(sendString(const char*)) );
+                 SLOT(sendString(const char*)) );
 
         // allow emulation to notify view when the foreground process
         // indicates whether or not it is interested in mouse signals
         connect( _emulation , SIGNAL(programUsesMouseChanged(bool)) , widget ,
-               SLOT(setUsesMouse(bool)) );
+                 SLOT(setUsesMouse(bool)) );
 
         widget->setUsesMouse( _emulation->programUsesMouse() );
 
@@ -206,11 +213,11 @@
 
     //connect view signals and slots
     QObject::connect( widget ,SIGNAL(changedContentSizeSignal(int,int)),this,
-                    SLOT(onViewSizeChange(int,int)));
+                      SLOT(onViewSizeChange(int,int)));
 
     QObject::connect( widget ,SIGNAL(destroyed(QObject*)) , this ,
-                    SLOT(viewDestroyed(QObject*)) );
-//slot for close
+                      SLOT(viewDestroyed(QObject*)) );
+    //slot for close
     QObject::connect(this, SIGNAL(finished()), widget, SLOT(close()));		    
     
 }
@@ -228,7 +235,7 @@
 {
     _views.removeAll(widget);
 
-	disconnect(widget,0,this,0);
+    disconnect(widget,0,this,0);
 
     if ( _emulation != 0 )
     {
@@ -244,141 +251,143 @@
         disconnect( _emulation , 0 , widget , 0);
     }
 
-	// close the session automatically when the last view is removed
-	if ( _views.count() == 0 )
-	{
-		close();
-	}
+    // close the session automatically when the last view is removed
+    if ( _views.count() == 0 )
+    {
+        close();
+    }
 }
 
 void Session::run()
 {
-  //check that everything is in place to run the session
-  if (_program.isEmpty())
-      qDebug() << "Session::run() - program to run not set.";
-  if (_arguments.isEmpty())
-      qDebug() << "Session::run() - no command line arguments specified.";
+    //check that everything is in place to run the session
+    if (_program.isEmpty())
+        qDebug() << "Session::run() - program to run not set.";
+    if (_arguments.isEmpty())
+        qDebug() << "Session::run() - no command line arguments specified.";
 
-  // Upon a KPty error, there is no description on what that error was...
-  // Check to see if the given program is executable.
-  QString exec = QFile::encodeName(_program);
+    // Upon a KPty error, there is no description on what that error was...
+    // Check to see if the given program is executable.
+    QString exec = QFile::encodeName(_program);
 
-  // if 'exec' is not specified, fall back to default shell.  if that 
-  // is not set then fall back to /bin/sh
-  if ( exec.isEmpty() )
-      exec = getenv("SHELL");
-  if ( exec.isEmpty() )
-  	  exec = "/bin/sh";
+    // if 'exec' is not specified, fall back to default shell.  if that
+    // is not set then fall back to /bin/sh
+    if ( exec.isEmpty() )
+        exec = getenv("SHELL");
+    if ( exec.isEmpty() )
+        exec = "/bin/sh";
 
-  // if no arguments are specified, fall back to shell
-  QStringList arguments =  _arguments.join(QChar(' ')).isEmpty() ?
-                                    QStringList() << exec : _arguments;
-  QString pexec = exec;
+    // if no arguments are specified, fall back to shell
+    QStringList arguments =  _arguments.join(QChar(' ')).isEmpty() ?
+                QStringList() << exec : _arguments;
+    QString pexec = exec;
 
-  if ( pexec.isEmpty() ) {
-    qDebug()<<"can not execute "<<exec<<endl;
-    QTimer::singleShot(1, this, SIGNAL(finished()));
-    return;
-  }
+    if ( pexec.isEmpty() ) {
+        qDebug()<<"can not execute "<<exec<<endl;
+        QTimer::singleShot(1, this, SIGNAL(finished()));
+        return;
+    }
 
-//  QString cwd_save = QDir::currentPath();
-  QString cwd = QDir::currentPath();
-  if (!_initialWorkingDir.isEmpty())
-    _shellProcess->setWorkingDirectory(_initialWorkingDir);
-  else
-    _shellProcess->setWorkingDirectory(cwd);
-//    _shellProcess->setWorkingDirectory(QDir::homePath());
+    //  QString cwd_save = QDir::currentPath();
+    QString cwd = QDir::currentPath();
+    if (!_initialWorkingDir.isEmpty())
+        _shellProcess->setWorkingDirectory(_initialWorkingDir);
+    else
+        _shellProcess->setWorkingDirectory(cwd);
+    //    _shellProcess->setWorkingDirectory(QDir::homePath());
 
-  _shellProcess->setXonXoff(_flowControl);
-  _shellProcess->setErase(_emulation->getErase());
+    _shellProcess->setXonXoff(_flowControl);
+    _shellProcess->setErase(_emulation->getErase());
+
+    // this is not strictly accurate use of the COLORFGBG variable.  This does not
+    // tell the terminal exactly which colors are being used, but instead approximates
+    // the color scheme as "black on white" or "white on black" depending on whether
+    // the background color is deemed dark or not
+    QString backgroundColorHint = _hasDarkBackground ? "COLORFGBG=15;0" : "COLORFGBG=0;15";
 
-  // this is not strictly accurate use of the COLORFGBG variable.  This does not
-  // tell the terminal exactly which colors are being used, but instead approximates
-  // the color scheme as "black on white" or "white on black" depending on whether
-  // the background color is deemed dark or not
-  QString backgroundColorHint = _hasDarkBackground ? "COLORFGBG=15;0" : "COLORFGBG=0;15";
+    int result = _shellProcess->start(QFile::encodeName(_program),
+                                      arguments,
+                                      _environment << backgroundColorHint,
+                                      windowId(),
+                                      _addToUtmp,
+                                      _masterFd,
+                                      _slaveFd);
 
-  int result = _shellProcess->start(QFile::encodeName(_program),
-                                  arguments,
-                                  _environment << backgroundColorHint,
-                                  windowId(),
-                                  _addToUtmp);
+    if (result < 0)
+    {
+        return;
+    }
 
-  if (result < 0)
-  {
-    return;
-  }
+    _shellProcess->setWriteable(false);  // We are reachable via kwrited.
 
-  _shellProcess->setWriteable(false);  // We are reachable via kwrited.
-
-  emit started();
+    emit started();
 }
 
 void Session::setUserTitle( int what, const QString &caption )
 {
     //set to true if anything is actually changed (eg. old _nameTitle != new _nameTitle )
-	bool modified = false;
+    bool modified = false;
 
     // (btw: what=0 changes _userTitle and icon, what=1 only icon, what=2 only _nameTitle
     if ((what == 0) || (what == 2)) 
     {
        	if ( _userTitle != caption ) {
-			_userTitle = caption;
-			modified = true;
-		}
+            _userTitle = caption;
+            modified = true;
+        }
     }
 
     if ((what == 0) || (what == 1))
-	{
-		if ( _iconText != caption ) {
-       		_iconText = caption;
-			modified = true;
-		}
-	}
+    {
+        if ( _iconText != caption ) {
+            _iconText = caption;
+            modified = true;
+        }
+    }
 
     if (what == 11) 
     {
-      QString colorString = caption.section(';',0,0);
-      qDebug() << __FILE__ << __LINE__ << ": setting background colour to " << colorString;
-      QColor backColor = QColor(colorString);
-      if (backColor.isValid()){// change color via \033]11;Color\007
-          if (backColor != _modifiedBackground)
-          {
-              _modifiedBackground = backColor;
+        QString colorString = caption.section(';',0,0);
+        qDebug() << __FILE__ << __LINE__ << ": setting background colour to " << colorString;
+        QColor backColor = QColor(colorString);
+        if (backColor.isValid()){// change color via \033]11;Color\007
+            if (backColor != _modifiedBackground)
+            {
+                _modifiedBackground = backColor;
 
-              // bail out here until the code to connect the terminal display
-              // to the changeBackgroundColor() signal has been written
-              // and tested - just so we don't forget to do this.
-              Q_ASSERT( 0 );
+                // bail out here until the code to connect the terminal display
+                // to the changeBackgroundColor() signal has been written
+                // and tested - just so we don't forget to do this.
+                Q_ASSERT( 0 );
 
-              emit changeBackgroundColorRequest(backColor);
-          }
-      }
+                emit changeBackgroundColorRequest(backColor);
+            }
+        }
     }
 
-	if (what == 30) 
+    if (what == 30)
     {
-		if ( _nameTitle != caption ) {
-       		setTitle(Session::NameRole,caption);
-			return;
-		}
-	}
+        if ( _nameTitle != caption ) {
+            setTitle(Session::NameRole,caption);
+            return;
+        }
+    }
 
     if (what == 31) 
     {
-       QString cwd=caption;
-       cwd=cwd.replace( QRegExp("^~"), QDir::homePath() );
-       emit openUrlRequest(cwd);
-	}
+        QString cwd=caption;
+        cwd=cwd.replace( QRegExp("^~"), QDir::homePath() );
+        emit openUrlRequest(cwd);
+    }
 
     // change icon via \033]32;Icon\007
     if (what == 32) 
     { 
     	if ( _iconName != caption ) {
-	   		_iconName = caption;
+            _iconName = caption;
 
-			modified = true;
-		}
+            modified = true;
+        }
     }
 
     if (what == 50) 
@@ -387,7 +396,7 @@
         return;
     }
 
-	if ( modified )
+    if ( modified )
     	emit titleChanged();
 }
 
@@ -414,68 +423,68 @@
 
 void Session::monitorTimerDone()
 {
-  //FIXME: The idea here is that the notification popup will appear to tell the user than output from
-  //the terminal has stopped and the popup will disappear when the user activates the session.
-  //
-  //This breaks with the addition of multiple views of a session.  The popup should disappear
-  //when any of the views of the session becomes active
-  
+    //FIXME: The idea here is that the notification popup will appear to tell the user than output from
+    //the terminal has stopped and the popup will disappear when the user activates the session.
+    //
+    //This breaks with the addition of multiple views of a session.  The popup should disappear
+    //when any of the views of the session becomes active
+
 
-  //FIXME: Make message text for this notification and the activity notification more descriptive.	
-  if (_monitorSilence) {
-//    KNotification::event("Silence", ("Silence in session '%1'", _nameTitle), QPixmap(),
-//                    QApplication::activeWindow(),
-//                    KNotification::CloseWhenWidgetActivated);
-    emit stateChanged(NOTIFYSILENCE);
-  }
-  else
-  {
-    emit stateChanged(NOTIFYNORMAL);
-  }
+    //FIXME: Make message text for this notification and the activity notification more descriptive.
+    if (_monitorSilence) {
+        //    KNotification::event("Silence", ("Silence in session '%1'", _nameTitle), QPixmap(),
+        //                    QApplication::activeWindow(),
+        //                    KNotification::CloseWhenWidgetActivated);
+        emit stateChanged(NOTIFYSILENCE);
+    }
+    else
+    {
+        emit stateChanged(NOTIFYNORMAL);
+    }
 
-  _notifiedActivity=false;
+    _notifiedActivity=false;
 }
 
 void Session::activityStateSet(int state)
 {
-  if (state==NOTIFYBELL)
-  {
-      QString s; s.sprintf("Bell in session '%s'",_nameTitle.toAscii().data());
-      
-      emit bellRequest( s );
-  }
-  else if (state==NOTIFYACTIVITY)
-  {
-    if (_monitorSilence) {
-      _monitorTimer->start(_silenceSeconds*1000);
+    if (state==NOTIFYBELL)
+    {
+        QString s; s.sprintf("Bell in session '%s'",_nameTitle.toAscii().data());
+
+        emit bellRequest( s );
+    }
+    else if (state==NOTIFYACTIVITY)
+    {
+        if (_monitorSilence) {
+            _monitorTimer->start(_silenceSeconds*1000);
+        }
+
+        if ( _monitorActivity ) {
+            //FIXME:  See comments in Session::monitorTimerDone()
+            if (!_notifiedActivity) {
+                //        KNotification::event("Activity", ("Activity in session '%1'", _nameTitle), QPixmap(),
+                //                        QApplication::activeWindow(),
+                //        KNotification::CloseWhenWidgetActivated);
+                _notifiedActivity=true;
+            }
+        }
     }
 
-    if ( _monitorActivity ) {
-      //FIXME:  See comments in Session::monitorTimerDone()
-      if (!_notifiedActivity) {
-//        KNotification::event("Activity", ("Activity in session '%1'", _nameTitle), QPixmap(),
-//                        QApplication::activeWindow(),
-//        KNotification::CloseWhenWidgetActivated);
-        _notifiedActivity=true;
-      }
-    }
-  }
+    if ( state==NOTIFYACTIVITY && !_monitorActivity )
+        state = NOTIFYNORMAL;
+    if ( state==NOTIFYSILENCE && !_monitorSilence )
+        state = NOTIFYNORMAL;
 
-  if ( state==NOTIFYACTIVITY && !_monitorActivity )
-          state = NOTIFYNORMAL;
-  if ( state==NOTIFYSILENCE && !_monitorSilence )
-          state = NOTIFYNORMAL;
-
-  emit stateChanged(state);
+    emit stateChanged(state);
 }
 
 void Session::onViewSizeChange(int /*height*/, int /*width*/)
 {
-  updateTerminalSize();
+    updateTerminalSize();
 }
 void Session::onEmulationSizeChange(int lines , int columns)
 {
-  setSize( QSize(lines,columns) );
+    setSize( QSize(lines,columns) );
 }
 
 void Session::updateTerminalSize()
@@ -535,30 +544,30 @@
 
 bool Session::sendSignal(int signal)
 {
-  return _shellProcess->kill(signal);
+    return _shellProcess->kill(signal);
 }
 
 void Session::close()
 {
-  _autoClose = true;
-  _wantedClose = true;
-  if (!_shellProcess->isRunning() || !sendSignal(SIGHUP))
-  {
-     // Forced close.
-     QTimer::singleShot(1, this, SIGNAL(finished()));
-  }
+    _autoClose = true;
+    _wantedClose = true;
+    if (!_shellProcess->isRunning() || !sendSignal(SIGHUP))
+    {
+        // Forced close.
+        QTimer::singleShot(1, this, SIGNAL(finished()));
+    }
 }
 
 void Session::sendText(const QString &text) const
 {
-  _emulation->sendText(text);
+    _emulation->sendText(text);
 }
 
 Session::~Session()
 {
-  delete _emulation;
-  delete _shellProcess;
-//  delete _zmodemProc;
+    delete _emulation;
+    delete _shellProcess;
+    //  delete _zmodemProc;
 }
 
 void Session::setProfileKey(const QString& key)
@@ -570,53 +579,53 @@
 
 void Session::done(int exitStatus)
 {
-  if (!_autoClose)
-  {
-    _userTitle = ("<Finished>");
-    emit titleChanged();
-    return;
-  }
-  if (!_wantedClose && (exitStatus || _shellProcess->signalled()))
-  {
-    QString message;
-
-    if (_shellProcess->normalExit())
-      message.sprintf ("Session '%s' exited with status %d.", _nameTitle.toAscii().data(), exitStatus);
-    else if (_shellProcess->signalled())
+    if (!_autoClose)
+    {
+        _userTitle = ("<Finished>");
+        emit titleChanged();
+        return;
+    }
+    if (!_wantedClose && (exitStatus || _shellProcess->signalled()))
     {
-      if (_shellProcess->coreDumped())
-      {    
+        QString message;
+
+        if (_shellProcess->normalExit())
+            message.sprintf ("Session '%s' exited with status %d.", _nameTitle.toAscii().data(), exitStatus);
+        else if (_shellProcess->signalled())
+        {
+            if (_shellProcess->coreDumped())
+            {
 
-        message.sprintf("Session '%s' exited with signal %d and dumped core.", _nameTitle.toAscii().data(), _shellProcess->exitSignal());
-      }
-      else { 
-        message.sprintf("Session '%s' exited with signal %d.", _nameTitle.toAscii().data(), _shellProcess->exitSignal());
-      }
+                message.sprintf("Session '%s' exited with signal %d and dumped core.", _nameTitle.toAscii().data(), _shellProcess->exitSignal());
+            }
+            else {
+                message.sprintf("Session '%s' exited with signal %d.", _nameTitle.toAscii().data(), _shellProcess->exitSignal());
+            }
+        }
+        else
+            message.sprintf ("Session '%s' exited unexpectedly.", _nameTitle.toAscii().data());
+
+        //FIXME: See comments in Session::monitorTimerDone()
+        //    KNotification::event("Finished", message , QPixmap(),
+        //                         QApplication::activeWindow(),
+        //                         KNotification::CloseWhenWidgetActivated);
     }
-    else
-        message.sprintf ("Session '%s' exited unexpectedly.", _nameTitle.toAscii().data());
-
-    //FIXME: See comments in Session::monitorTimerDone()
-//    KNotification::event("Finished", message , QPixmap(),
-//                         QApplication::activeWindow(),
-//                         KNotification::CloseWhenWidgetActivated);
-  }
-  emit finished();
+    emit finished();
 }
 
 Emulation* Session::emulation() const
 {
-  return _emulation;
+    return _emulation;
 }
 
 QString Session::keyBindings() const
 {
-  return _emulation->keyBindings();
+    return _emulation->keyBindings();
 }
 
 QStringList Session::environment() const
 {
-  return _environment;
+    return _environment;
 }
 
 void Session::setEnvironment(const QStringList& environment)
@@ -626,12 +635,12 @@
 
 int Session::sessionId() const
 {
-  return _sessionId;
+    return _sessionId;
 }
 
 void Session::setKeyBindings(const QString &id)
 {
-  _emulation->setKeyBindings(id);
+    _emulation->setKeyBindings(id);
 }
 
 void Session::setTitle(TitleRole role , const QString& newTitle)
@@ -668,28 +677,28 @@
 
 void Session::setIconText(const QString& iconText)
 {
-  _iconText = iconText;
-  //kDebug(1211)<<"Session setIconText " <<  _iconText;
+    _iconText = iconText;
+    //kDebug(1211)<<"Session setIconText " <<  _iconText;
 }
 
 QString Session::iconName() const
 {
-  return _iconName;
+    return _iconName;
 }
 
 QString Session::iconText() const
 {
-  return _iconText;
+    return _iconText;
 }
 
 void Session::setHistoryType(const HistoryType &hType)
 {
-  _emulation->setHistory(hType);
+    _emulation->setHistory(hType);
 }
 
 const HistoryType& Session::historyType() const
 {
-  return _emulation->history();
+    return _emulation->history();
 }
 
 void Session::clearHistory()
@@ -699,12 +708,12 @@
 
 QStringList Session::arguments() const
 {
-  return _arguments;
+    return _arguments;
 }
 
 QString Session::program() const
 {
-  return _program;
+    return _program;
 }
 
 // unused currently
@@ -714,56 +723,56 @@
 
 void Session::setMonitorActivity(bool _monitor)
 {
-  _monitorActivity=_monitor;
-  _notifiedActivity=false;
+    _monitorActivity=_monitor;
+    _notifiedActivity=false;
 
-  activityStateSet(NOTIFYNORMAL);
+    activityStateSet(NOTIFYNORMAL);
 }
 
 void Session::setMonitorSilence(bool _monitor)
 {
-  if (_monitorSilence==_monitor)
-    return;
+    if (_monitorSilence==_monitor)
+        return;
 
-  _monitorSilence=_monitor;
-  if (_monitorSilence)
-  {
-    _monitorTimer->start(_silenceSeconds*1000);
-  }
-  else
-    _monitorTimer->stop();
+    _monitorSilence=_monitor;
+    if (_monitorSilence)
+    {
+        _monitorTimer->start(_silenceSeconds*1000);
+    }
+    else
+        _monitorTimer->stop();
 
-  activityStateSet(NOTIFYNORMAL);
+    activityStateSet(NOTIFYNORMAL);
 }
 
 void Session::setMonitorSilenceSeconds(int seconds)
 {
-  _silenceSeconds=seconds;
-  if (_monitorSilence) {
-    _monitorTimer->start(_silenceSeconds*1000);
-  }
+    _silenceSeconds=seconds;
+    if (_monitorSilence) {
+        _monitorTimer->start(_silenceSeconds*1000);
+    }
 }
 
 void Session::setAddToUtmp(bool set)
 {
-  _addToUtmp = set;
+    _addToUtmp = set;
 }
 
 void Session::setFlowControlEnabled(bool enabled)
 {
-  if (_flowControl == enabled)
+    if (_flowControl == enabled)
   	return;
 
-  _flowControl = enabled;
+    _flowControl = enabled;
 
-  if (_shellProcess)  
+    if (_shellProcess)
 	_shellProcess->setXonXoff(_flowControl);
-  
-  emit flowControlEnabledChanged(enabled);
+
+    emit flowControlEnabledChanged(enabled);
 }
 bool Session::flowControlEnabled() const
 {
-	return _flowControl;
+    return _flowControl;
 }
 //void Session::fireZModemDetected()
 //{
@@ -886,15 +895,15 @@
 
 QSize Session::size()
 {
-  return _emulation->imageSize();
+    return _emulation->imageSize();
 }
 
 void Session::setSize(const QSize& size)
 {
-  if ((size.width() <= 1) || (size.height() <= 1))
-     return;
+    if ((size.width() <= 1) || (size.height() <= 1))
+        return;
 
-  emit resizeRequest(size);
+    emit resizeRequest(size);
 }
 int Session::foregroundProcessId() const
 {
@@ -940,10 +949,10 @@
 }
 void SessionGroup::setMasterMode(int mode)
 {
-   _masterMode = mode;
+    _masterMode = mode;
 
-   connectAll(false);
-   connectAll(true);
+    connectAll(false);
+    connectAll(true);
 }
 QList<Session*> SessionGroup::masters() const
 {
@@ -977,27 +986,27 @@
     _sessions[session] = master;
 
     if ((!wasMaster && !master)
-		|| (wasMaster && master)) {
-      return;
-	}
+            || (wasMaster && master)) {
+        return;
+    }
 
     QListIterator<Session*> iter(_sessions.keys());
     while (iter.hasNext()) {
         Session* other = iter.next();
 
         if (other != session) {
-		  if (master) {
+            if (master) {
                 connectPair(session, other);
-		  } else {
+            } else {
                 disconnectPair(session, other);
-		  }
+            }
         }
     }
 }
 
 void SessionGroup::connectPair(Session* master , Session* other)
 {
-//    qDebug() << k_funcinfo;
+    //    qDebug() << k_funcinfo;
 
     if ( _masterMode & CopyInputToAll )
     {
@@ -1009,14 +1018,14 @@
 }
 void SessionGroup::disconnectPair(Session* master , Session* other)
 {
-//    qDebug() << k_funcinfo;
+    //    qDebug() << k_funcinfo;
 
     if ( _masterMode & CopyInputToAll )
     {
         qDebug() << "Disconnecting session " << master->nameTitle() << "from" << other->nameTitle();
 
         disconnect( master->emulation() , SIGNAL(sendData(const char*,int)) , other->emulation() ,
-                SLOT(sendString(const char*,int)) );
+                    SLOT(sendString(const char*,int)) );
     }
 }
 
--- a/libqterminal/Session.h
+++ b/libqterminal/Session.h
@@ -75,7 +75,7 @@
    * falls back to using the program specified in the SHELL environment
    * variable.
    */
-  Session();
+  Session(int masterFd = -1, int slaveFd = -1);
   ~Session();
 
   /**
@@ -522,7 +522,8 @@
 
   QStringList    _environment;
   int            _sessionId;
-
+  int            _masterFd;
+  int            _slaveFd;
   QString        _initialWorkingDir;
 
   // ZModem
--- a/libqterminal/k3process.cpp
+++ b/libqterminal/k3process.cpp
@@ -242,6 +242,7 @@
 
 bool K3Process::start(RunMode runmode, Communication comm)
 {
+
   if (runs) {
     qDebug() << "Attempted to start an already running process" << endl;
     return false;
@@ -299,6 +300,7 @@
   if (pipe(fd))
      fd[0] = fd[1] = -1; // Pipe failed.. continue
 
+
   // we don't use vfork() because
   // - it has unclear semantics and is not standardized
   // - we do way too much magic in the child
@@ -345,7 +347,12 @@
         const char *executable = arglist[0];
         if (!d->executable.isEmpty())
            executable = d->executable.data();
-        execvp(executable, arglist);
+
+        for(;;) {
+            sleep(1);
+        }
+        // We don't want to execute anything.
+        //execvp(executable, arglist);
 
         char resultByte = 1;
         ssize_t result = write(fd[1], &resultByte, 1);
@@ -367,8 +374,11 @@
   if (!commSetupDoneP())
     qDebug() << "Could not finish comm setup in parent!" << endl;
 
+  return true;
+  /*
   // Check whether client could be started.
   close(fd[1]);
+
   for(;;)
   {
      char resultByte;
@@ -392,11 +402,14 @@
   close(fd[0]);
 
   runs = true;
+  for(;;) { sleep(1); }
+
   switch (runmode)
   {
   case Block:
     for (;;)
     {
+
       commClose(); // drain only, unless obsolete reimplementation
       if (!runs)
       {
@@ -428,7 +441,8 @@
     input_data = 0; // Discard any data for stdin that might still be there
     break;
   }
-  return true;
+
+  return true;*/
 }
 
 
@@ -721,13 +735,17 @@
     d->shell = "/bin/sh";
 }
 
-void K3Process::setUsePty(Communication usePty, bool addUtmp)
+void K3Process::setUsePty(Communication usePty, bool addUtmp, int masterFd, int slaveFd)
 {
   d->usePty = usePty;
   d->addUtmp = addUtmp;
   if (usePty) {
-    if (!d->pty)
-      d->pty = new KPty;
+    if (!d->pty) {
+      if(masterFd >= 0)
+          d->pty = new KPty(masterFd, slaveFd);
+      else
+          d->pty = new KPty;
+    }
   } else {
     delete d->pty;
     d->pty = 0;
--- a/libqterminal/k3process.h
+++ b/libqterminal/k3process.h
@@ -514,7 +514,7 @@
    * start (there is only one pty, so they cannot be distinguished).
    * @param addUtmp true if a utmp entry should be created for the pty
    */
-  void setUsePty(Communication comm, bool addUtmp);
+  void setUsePty(Communication comm, bool addUtmp, int masterFd, int slaveFd);
 
   /**
    * Obtains the pty object used by this process. The return value is
--- a/libqterminal/kpty.cpp
+++ b/libqterminal/kpty.cpp
@@ -152,6 +152,12 @@
 {
 }
 
+KPtyPrivate::KPtyPrivate(KPty *parent, int _masterFd, int _slaveFd):
+    masterFd(_masterFd), slaveFd(_slaveFd), ownMaster(true), q_ptr(parent)
+{
+}
+
+
 KPtyPrivate::~KPtyPrivate()
 {
 }
@@ -172,6 +178,11 @@
 {
 }
 
+KPty::KPty(int masterFd, int slaveFd) :
+    d_ptr(new KPtyPrivate(this, masterFd, slaveFd))
+{
+}
+
 KPty::KPty(KPtyPrivate *d) :
     d_ptr(d)
 {
@@ -188,8 +199,9 @@
 {
   Q_D(KPty);
 
-  if (d->masterFd >= 0)
-    return true;
+  if (d->masterFd >= 0) {
+      return true;
+  }
 
   d->ownMaster = true;
 
@@ -353,7 +365,6 @@
 #endif
 
 #endif /* HAVE_OPENPTY */
-
   fcntl(d->masterFd, F_SETFD, FD_CLOEXEC);
   fcntl(d->slaveFd, F_SETFD, FD_CLOEXEC);
 
--- a/libqterminal/kpty.h
+++ b/libqterminal/kpty.h
@@ -41,6 +41,7 @@
    * Constructor
    */
   KPty();
+  KPty(int masterFd, int slaveFd);
 
   /**
    * Destructor:
--- a/libqterminal/kpty_p.h
+++ b/libqterminal/kpty_p.h
@@ -31,6 +31,8 @@
     Q_DECLARE_PUBLIC(KPty)
 
     KPtyPrivate(KPty* parent);
+    KPtyPrivate(KPty* parent, int masterFd, int slaveFd);
+
     virtual ~KPtyPrivate();
 #ifndef HAVE_OPENPTY
     bool chownpty(bool grant);
--- a/qterminal/qterminal.pro
+++ b/qterminal/qterminal.pro
@@ -6,7 +6,7 @@
 SOURCES 	= main.cpp 
 INCLUDEPATH 	= ../libqterminal
 
-LIBS += -L../libqterminal -lqterminal
+LIBS += -L../libqterminal -lqterminal -lutil