src/qt3support/other/q3process_win.cpp
changeset 0 1918ee327afb
child 4 3b1da2848fc7
equal deleted inserted replaced
-1:000000000000 0:1918ee327afb
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     6 **
       
     7 ** This file is part of the Qt3Support module of the Qt Toolkit.
       
     8 **
       
     9 ** $QT_BEGIN_LICENSE:LGPL$
       
    10 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    15 **
       
    16 ** GNU Lesser General Public License Usage
       
    17 ** Alternatively, this file may be used under the terms of the GNU Lesser
       
    18 ** General Public License version 2.1 as published by the Free Software
       
    19 ** Foundation and appearing in the file LICENSE.LGPL included in the
       
    20 ** packaging of this file.  Please review the following information to
       
    21 ** ensure the GNU Lesser General Public License version 2.1 requirements
       
    22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
       
    23 **
       
    24 ** In addition, as a special exception, Nokia gives you certain additional
       
    25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
       
    26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
       
    27 **
       
    28 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    36 **
       
    37 **
       
    38 ** $QT_END_LICENSE$
       
    39 **
       
    40 ****************************************************************************/
       
    41 
       
    42 #include "qplatformdefs.h"
       
    43 #include "q3process.h"
       
    44 
       
    45 #ifndef QT_NO_PROCESS
       
    46 
       
    47 #include "qapplication.h"
       
    48 #include "q3cstring.h"
       
    49 #include "q3ptrqueue.h"
       
    50 #include "qtimer.h"
       
    51 #include "qregexp.h"
       
    52 #include "private/q3membuf_p.h"
       
    53 #include "qt_windows.h"
       
    54 
       
    55 #ifdef Q_OS_WINCE
       
    56 #define STARTF_USESTDHANDLES 1
       
    57 #endif
       
    58 
       
    59 QT_BEGIN_NAMESPACE
       
    60 
       
    61 //#define QT_Q3PROCESS_DEBUG
       
    62 
       
    63 /***********************************************************************
       
    64  *
       
    65  * Q3ProcessPrivate
       
    66  *
       
    67  **********************************************************************/
       
    68 class Q3ProcessPrivate
       
    69 {
       
    70 public:
       
    71     Q3ProcessPrivate( Q3Process *proc )
       
    72     {
       
    73 	stdinBufRead = 0;
       
    74 	pipeStdin[0] = 0;
       
    75 	pipeStdin[1] = 0;
       
    76 	pipeStdout[0] = 0;
       
    77 	pipeStdout[1] = 0;
       
    78 	pipeStderr[0] = 0;
       
    79 	pipeStderr[1] = 0;
       
    80 	exitValuesCalculated = false;
       
    81 
       
    82 	lookup = new QTimer( proc );
       
    83 	qApp->connect( lookup, SIGNAL(timeout()),
       
    84 		proc, SLOT(timeout()) );
       
    85 
       
    86 	pid = 0;
       
    87     }
       
    88 
       
    89     ~Q3ProcessPrivate()
       
    90     {
       
    91 	reset();
       
    92     }
       
    93 
       
    94     void reset()
       
    95     {
       
    96 	while ( !stdinBuf.isEmpty() ) {
       
    97 	    delete stdinBuf.dequeue();
       
    98 	}
       
    99 	closeHandles();
       
   100 	stdinBufRead = 0;
       
   101 	pipeStdin[0] = 0;
       
   102 	pipeStdin[1] = 0;
       
   103 	pipeStdout[0] = 0;
       
   104 	pipeStdout[1] = 0;
       
   105 	pipeStderr[0] = 0;
       
   106 	pipeStderr[1] = 0;
       
   107 	exitValuesCalculated = false;
       
   108 
       
   109 	deletePid();
       
   110     }
       
   111 
       
   112     void closeHandles()
       
   113     {
       
   114 	if( pipeStdin[1] != 0 ) {
       
   115 	    CloseHandle( pipeStdin[1] );
       
   116 	    pipeStdin[1] = 0;
       
   117 	}
       
   118 	if( pipeStdout[0] != 0 ) {
       
   119 	    CloseHandle( pipeStdout[0] );
       
   120 	    pipeStdout[0] = 0;
       
   121 	}
       
   122 	if( pipeStderr[0] != 0 ) {
       
   123 	    CloseHandle( pipeStderr[0] );
       
   124 	    pipeStderr[0] = 0;
       
   125 	}
       
   126     }
       
   127 
       
   128     void deletePid()
       
   129     {
       
   130 	if ( pid ) {
       
   131 	    CloseHandle( pid->hProcess );
       
   132 	    CloseHandle( pid->hThread );
       
   133 	    delete pid;
       
   134 	    pid = 0;
       
   135 	}
       
   136     }
       
   137 
       
   138     void newPid()
       
   139     {
       
   140 	deletePid();
       
   141 	pid = new PROCESS_INFORMATION;
       
   142 	memset( pid, 0, sizeof(PROCESS_INFORMATION) );
       
   143     }
       
   144 
       
   145     Q3Membuf bufStdout;
       
   146     Q3Membuf bufStderr;
       
   147 
       
   148     Q3PtrQueue<QByteArray> stdinBuf;
       
   149 
       
   150     HANDLE pipeStdin[2];
       
   151     HANDLE pipeStdout[2];
       
   152     HANDLE pipeStderr[2];
       
   153     QTimer *lookup;
       
   154 
       
   155     PROCESS_INFORMATION *pid;
       
   156     uint stdinBufRead;
       
   157 
       
   158     bool exitValuesCalculated;
       
   159 };
       
   160 
       
   161 
       
   162 /***********************************************************************
       
   163  *
       
   164  * Q3Process
       
   165  *
       
   166  **********************************************************************/
       
   167 void Q3Process::init()
       
   168 {
       
   169     d = new Q3ProcessPrivate( this );
       
   170     exitStat = 0;
       
   171     exitNormal = false;
       
   172 }
       
   173 
       
   174 void Q3Process::reset()
       
   175 {
       
   176     d->reset();
       
   177     exitStat = 0;
       
   178     exitNormal = false;
       
   179     d->bufStdout.clear();
       
   180     d->bufStderr.clear();
       
   181 }
       
   182 
       
   183 Q3Membuf* Q3Process::membufStdout()
       
   184 {
       
   185     if( d->pipeStdout[0] != 0 )
       
   186 	socketRead( 1 );
       
   187     return &d->bufStdout;
       
   188 }
       
   189 
       
   190 Q3Membuf* Q3Process::membufStderr()
       
   191 {
       
   192     if( d->pipeStderr[0] != 0 )
       
   193 	socketRead( 2 );
       
   194     return &d->bufStderr;
       
   195 }
       
   196 
       
   197 Q3Process::~Q3Process()
       
   198 {
       
   199     delete d;
       
   200 }
       
   201 
       
   202 bool Q3Process::start( QStringList *env )
       
   203 {
       
   204 #if defined(QT_Q3PROCESS_DEBUG)
       
   205     qDebug( "Q3Process::start()" );
       
   206 #endif
       
   207     reset();
       
   208 
       
   209     if ( _arguments.isEmpty() )
       
   210 	return false;
       
   211 
       
   212     // Open the pipes.  Make non-inheritable copies of input write and output
       
   213     // read handles to avoid non-closable handles (this is done by the
       
   214     // DuplicateHandle() call).
       
   215     SECURITY_ATTRIBUTES secAtt = { sizeof( SECURITY_ATTRIBUTES ), NULL, TRUE };
       
   216 #ifndef Q_OS_WINCE
       
   217     // I guess there is no stdin stdout and stderr on Q_OS_WINCE to dup
       
   218     // CreatePipe and DupilcateHandle aren't available for Q_OS_WINCE
       
   219     HANDLE tmpStdin, tmpStdout, tmpStderr;
       
   220     if ( comms & Stdin ) {
       
   221 	if ( !CreatePipe( &d->pipeStdin[0], &tmpStdin, &secAtt, 0 ) ) {
       
   222 	    d->closeHandles();
       
   223 	    return false;
       
   224 	}
       
   225 	if ( !DuplicateHandle( GetCurrentProcess(), tmpStdin, GetCurrentProcess(), &d->pipeStdin[1], 0, FALSE, DUPLICATE_SAME_ACCESS ) ) {
       
   226 	    d->closeHandles();
       
   227 	    return false;
       
   228 	}
       
   229 	if ( !CloseHandle( tmpStdin ) ) {
       
   230 	    d->closeHandles();
       
   231 	    return false;
       
   232 	}
       
   233     }
       
   234     if ( comms & Stdout ) {
       
   235 	if ( !CreatePipe( &tmpStdout, &d->pipeStdout[1], &secAtt, 0 ) ) {
       
   236 	    d->closeHandles();
       
   237 	    return false;
       
   238 	}
       
   239 	if ( !DuplicateHandle( GetCurrentProcess(), tmpStdout, GetCurrentProcess(), &d->pipeStdout[0], 0, FALSE, DUPLICATE_SAME_ACCESS ) ) {
       
   240 	    d->closeHandles();
       
   241 	    return false;
       
   242 	}
       
   243 	if ( !CloseHandle( tmpStdout ) ) {
       
   244 	    d->closeHandles();
       
   245 	    return false;
       
   246 	}
       
   247     }
       
   248     if ( comms & Stderr ) {
       
   249 	if ( !CreatePipe( &tmpStderr, &d->pipeStderr[1], &secAtt, 0 ) ) {
       
   250 	    d->closeHandles();
       
   251 	    return false;
       
   252 	}
       
   253 	if ( !DuplicateHandle( GetCurrentProcess(), tmpStderr, GetCurrentProcess(), &d->pipeStderr[0], 0, FALSE, DUPLICATE_SAME_ACCESS ) ) {
       
   254 	    d->closeHandles();
       
   255 	    return false;
       
   256 	}
       
   257 	if ( !CloseHandle( tmpStderr ) ) {
       
   258 	    d->closeHandles();
       
   259 	    return false;
       
   260 	}
       
   261     }
       
   262     if ( comms & DupStderr ) {
       
   263 	CloseHandle( d->pipeStderr[1] );
       
   264 	d->pipeStderr[1] = d->pipeStdout[1];
       
   265     }
       
   266 #endif
       
   267 
       
   268     // construct the arguments for CreateProcess()
       
   269     QString args;
       
   270     QString appName;
       
   271     QStringList::Iterator it = _arguments.begin();
       
   272     args = *it;
       
   273     ++it;
       
   274     if ( args.endsWith( QLatin1String(".bat") ) && args.contains( QLatin1Char(' ') ) ) {
       
   275 	// CreateProcess() seems to have a strange semantics (see also
       
   276 	// http://www.experts-exchange.com/Programming/Programming_Platforms/Win_Prog/Q_11138647.html):
       
   277 	// If you start a batch file with spaces in the filename, the first
       
   278 	// argument to CreateProcess() must be the name of the batchfile
       
   279 	// without quotes, but the second argument must start with the same
       
   280 	// argument with quotes included. But if the same approach is used for
       
   281 	// .exe files, it doesn't work.
       
   282 	appName = args;
       
   283 	args = QLatin1Char('"') + args + QLatin1Char('"');
       
   284     }
       
   285     for ( ; it != _arguments.end(); ++it ) {
       
   286 	QString tmp = *it;
       
   287 	// escape a single " because the arguments will be parsed
       
   288 	tmp.replace( QLatin1Char('\"'), QLatin1String("\\\"") );
       
   289 	if ( tmp.isEmpty() || tmp.contains( QLatin1Char(' ') ) || tmp.contains( QLatin1Char('\t') ) ) {
       
   290 	    // The argument must not end with a \ since this would be interpreted
       
   291 	    // as escaping the quote -- rather put the \ behind the quote: e.g.
       
   292 	    // rather use "foo"\ than "foo\"
       
   293 	    QString endQuote( QLatin1String("\"") );
       
   294 	    int i = tmp.length();
       
   295 	    while ( i>0 && tmp.at( i-1 ) == QLatin1Char('\\') ) {
       
   296 		--i;
       
   297 		endQuote += QLatin1Char('\\');
       
   298 	    }
       
   299         args += QLatin1String(" \"") + tmp.left( i ) + endQuote;
       
   300 	} else {
       
   301 	    args += QLatin1Char(' ') + tmp;
       
   302 	}
       
   303     }
       
   304 #if defined(QT_Q3PROCESS_DEBUG)
       
   305     qDebug( "Q3Process::start(): args [%s]", args.latin1() );
       
   306 #endif
       
   307 
       
   308     // CreateProcess()
       
   309     bool success;
       
   310     d->newPid();
       
   311 
       
   312     STARTUPINFOW startupInfo = {
       
   313         sizeof( STARTUPINFO ), 0, 0, 0,
       
   314         (ulong)CW_USEDEFAULT, (ulong)CW_USEDEFAULT, (ulong)CW_USEDEFAULT, (ulong)CW_USEDEFAULT,
       
   315         0, 0, 0,
       
   316         STARTF_USESTDHANDLES,
       
   317         0, 0, 0,
       
   318         d->pipeStdin[0], d->pipeStdout[1], d->pipeStderr[1]
       
   319     };
       
   320     wchar_t *applicationName;
       
   321     if ( appName.isNull() )
       
   322         applicationName = 0;
       
   323     else
       
   324         applicationName = _wcsdup( (wchar_t*)appName.utf16() );
       
   325     wchar_t *commandLine = _wcsdup( (wchar_t*)args.utf16() );
       
   326     QByteArray envlist;
       
   327     if ( env != 0 ) {
       
   328         int pos = 0;
       
   329         // add PATH if necessary (for DLL loading)
       
   330         QByteArray path = qgetenv( "PATH" );
       
   331         if ( env->grep( QRegExp(QLatin1String("^PATH="),FALSE) ).empty() && !path.isNull() ) {
       
   332             QString tmp = QString::fromLatin1("PATH=%1").arg(QLatin1String(path.constData()));
       
   333             uint tmpSize = sizeof(wchar_t) * (tmp.length() + 1);
       
   334             envlist.resize( envlist.size() + tmpSize );
       
   335             memcpy( envlist.data() + pos, tmp.utf16(), tmpSize );
       
   336             pos += tmpSize;
       
   337         }
       
   338         // add the user environment
       
   339         for ( QStringList::Iterator it = env->begin(); it != env->end(); it++ ) {
       
   340             QString tmp = *it;
       
   341             uint tmpSize = sizeof(wchar_t) * (tmp.length() + 1);
       
   342             envlist.resize( envlist.size() + tmpSize );
       
   343             memcpy( envlist.data() + pos, tmp.utf16(), tmpSize );
       
   344             pos += tmpSize;
       
   345         }
       
   346         // add the 2 terminating 0 (actually 4, just to be on the safe side)
       
   347         envlist.resize( envlist.size()+4 );
       
   348         envlist[pos++] = 0;
       
   349         envlist[pos++] = 0;
       
   350         envlist[pos++] = 0;
       
   351         envlist[pos++] = 0;
       
   352     }
       
   353     success = CreateProcess( applicationName, commandLine,
       
   354                             0, 0, TRUE, ( comms == 0 ? CREATE_NEW_CONSOLE : CREATE_NO_WINDOW )
       
   355 #ifndef Q_OS_WINCE
       
   356                             | CREATE_UNICODE_ENVIRONMENT
       
   357 #endif
       
   358                             , env == 0 ? 0 : envlist.data(),
       
   359                             (wchar_t*)QDir::toNativeSeparators(workingDir.absPath()).utf16(),
       
   360                             &startupInfo, d->pid );
       
   361 
       
   362     free( applicationName );
       
   363     free( commandLine );
       
   364 
       
   365     if  ( !success ) {
       
   366 	d->deletePid();
       
   367 	return false;
       
   368     }
       
   369 
       
   370 #ifndef Q_OS_WINCE
       
   371     if ( comms & Stdin )
       
   372 	CloseHandle( d->pipeStdin[0] );
       
   373     if ( comms & Stdout )
       
   374         CloseHandle( d->pipeStdout[1] );
       
   375     if ( (comms & Stderr) && !(comms & DupStderr) )
       
   376 	CloseHandle( d->pipeStderr[1] );
       
   377 #endif
       
   378 
       
   379     if ( ioRedirection || notifyOnExit ) {
       
   380 	d->lookup->start( 100 );
       
   381     }
       
   382 
       
   383     // cleanup and return
       
   384     return true;
       
   385 }
       
   386 
       
   387 static BOOL CALLBACK qt_terminateApp( HWND hwnd, LPARAM procId )
       
   388 {
       
   389     DWORD procId_win;
       
   390     GetWindowThreadProcessId( hwnd, &procId_win );
       
   391     if( procId_win == (DWORD)procId )
       
   392 	PostMessage( hwnd, WM_CLOSE, 0, 0 );
       
   393 
       
   394     return TRUE;
       
   395 }
       
   396 
       
   397 void Q3Process::tryTerminate() const
       
   398 {
       
   399     if ( d->pid )
       
   400 	EnumWindows( qt_terminateApp, (LPARAM)d->pid->dwProcessId );
       
   401 }
       
   402 
       
   403 void Q3Process::kill() const
       
   404 {
       
   405     if ( d->pid )
       
   406 	TerminateProcess( d->pid->hProcess, 0xf291 );
       
   407 }
       
   408 
       
   409 bool Q3Process::isRunning() const
       
   410 {
       
   411     if ( !d->pid )
       
   412 	return false;
       
   413 
       
   414     if ( WaitForSingleObject( d->pid->hProcess, 0) == WAIT_OBJECT_0 ) {
       
   415 	// there might be data to read
       
   416 	Q3Process *that = (Q3Process*)this;
       
   417 	that->socketRead( 1 ); // try stdout
       
   418 	that->socketRead( 2 ); // try stderr
       
   419 	// compute the exit values
       
   420 	if ( !d->exitValuesCalculated ) {
       
   421 	    DWORD exitCode;
       
   422 	    if ( GetExitCodeProcess( d->pid->hProcess, &exitCode ) ) {
       
   423 		if ( exitCode != STILL_ACTIVE ) { // this should ever be true?
       
   424 		    that->exitNormal = exitCode != 0xf291;
       
   425 		    that->exitStat = exitCode;
       
   426 		}
       
   427 	    }
       
   428 	    d->exitValuesCalculated = true;
       
   429 	}
       
   430 	d->deletePid();
       
   431 	d->closeHandles();
       
   432 	return false;
       
   433     } else {
       
   434         return true;
       
   435     }
       
   436 }
       
   437 
       
   438 bool Q3Process::canReadLineStdout() const
       
   439 {
       
   440     if( !d->pipeStdout[0] )
       
   441 	return d->bufStdout.size() != 0;
       
   442 
       
   443     Q3Process *that = (Q3Process*)this;
       
   444     return that->membufStdout()->scanNewline( 0 );
       
   445 }
       
   446 
       
   447 bool Q3Process::canReadLineStderr() const
       
   448 {
       
   449     if( !d->pipeStderr[0] )
       
   450 	return d->bufStderr.size() != 0;
       
   451 
       
   452     Q3Process *that = (Q3Process*)this;
       
   453     return that->membufStderr()->scanNewline( 0 );
       
   454 }
       
   455 
       
   456 void Q3Process::writeToStdin( const QByteArray& buf )
       
   457 {
       
   458     d->stdinBuf.enqueue( new QByteArray(buf) );
       
   459     socketWrite( 0 );
       
   460 }
       
   461 
       
   462 void Q3Process::closeStdin( )
       
   463 {
       
   464     if ( d->pipeStdin[1] != 0 ) {
       
   465 	CloseHandle( d->pipeStdin[1] );
       
   466 	d->pipeStdin[1] = 0;
       
   467     }
       
   468 }
       
   469 
       
   470 void Q3Process::socketRead( int fd )
       
   471 {
       
   472     // fd == 1: stdout, fd == 2: stderr
       
   473     HANDLE dev;
       
   474     if ( fd == 1 ) {
       
   475 	dev = d->pipeStdout[0];
       
   476     } else if ( fd == 2 ) {
       
   477 	dev = d->pipeStderr[0];
       
   478     } else {
       
   479 	return;
       
   480     }
       
   481 #ifndef Q_OS_WINCE
       
   482     // get the number of bytes that are waiting to be read
       
   483     unsigned long i, r;
       
   484     char dummy;
       
   485     if ( !PeekNamedPipe( dev, &dummy, 1, &r, &i, 0 ) ) {
       
   486 	return; // ### is it worth to dig for the reason of the error?
       
   487     }
       
   488 #else
       
   489     unsigned long i = 1000;
       
   490 #endif
       
   491     if ( i > 0 ) {
       
   492 	Q3Membuf *buffer;
       
   493 	if ( fd == 1 )
       
   494 	    buffer = &d->bufStdout;
       
   495 	else
       
   496 	    buffer = &d->bufStderr;
       
   497 
       
   498 	QByteArray *ba = new QByteArray( i );
       
   499 	uint sz = readStddev( dev, ba->data(), i );
       
   500 	if ( sz != i )
       
   501 	    ba->resize( i );
       
   502 
       
   503 	if ( sz == 0 ) {
       
   504 	    delete ba;
       
   505 	    return;
       
   506 	}
       
   507 	buffer->append( ba );
       
   508 	if ( fd == 1 )
       
   509 	    emit readyReadStdout();
       
   510 	else
       
   511 	    emit readyReadStderr();
       
   512     }
       
   513 }
       
   514 
       
   515 void Q3Process::socketWrite( int )
       
   516 {
       
   517     DWORD written;
       
   518     while ( !d->stdinBuf.isEmpty() && isRunning() ) {
       
   519 	if ( !WriteFile( d->pipeStdin[1],
       
   520 		    d->stdinBuf.head()->data() + d->stdinBufRead,
       
   521 		    qMin( 8192, int(d->stdinBuf.head()->size() - d->stdinBufRead) ),
       
   522 		    &written, 0 ) ) {
       
   523 	    d->lookup->start( 100 );
       
   524 	    return;
       
   525 	}
       
   526 	d->stdinBufRead += written;
       
   527 	if ( d->stdinBufRead == (DWORD)d->stdinBuf.head()->size() ) {
       
   528 	    d->stdinBufRead = 0;
       
   529 	    delete d->stdinBuf.dequeue();
       
   530 	    if ( wroteToStdinConnected && d->stdinBuf.isEmpty() )
       
   531 		emit wroteToStdin();
       
   532 	}
       
   533     }
       
   534 }
       
   535 
       
   536 void Q3Process::flushStdin()
       
   537 {
       
   538     socketWrite( 0 );
       
   539 }
       
   540 
       
   541 /*
       
   542   Use a timer for polling misc. stuff.
       
   543 */
       
   544 void Q3Process::timeout()
       
   545 {
       
   546     // Disable the timer temporary since one of the slots that are connected to
       
   547     // the readyRead...(), etc. signals might trigger recursion if
       
   548     // processEvents() is called.
       
   549     d->lookup->stop();
       
   550 
       
   551     // try to write pending data to stdin
       
   552     if ( !d->stdinBuf.isEmpty() )
       
   553 	socketWrite( 0 );
       
   554 
       
   555     if ( ioRedirection ) {
       
   556 	socketRead( 1 ); // try stdout
       
   557 	socketRead( 2 ); // try stderr
       
   558     }
       
   559 
       
   560     if ( isRunning() ) {
       
   561 	// enable timer again, if needed
       
   562 	if ( !d->stdinBuf.isEmpty() || ioRedirection || notifyOnExit )
       
   563 	    d->lookup->start( 100 );
       
   564     } else if ( notifyOnExit ) {
       
   565 	emit processExited();
       
   566     }
       
   567 }
       
   568 
       
   569 /*
       
   570   read on the pipe
       
   571 */
       
   572 uint Q3Process::readStddev( HANDLE dev, char *buf, uint bytes )
       
   573 {
       
   574     if ( bytes > 0 ) {
       
   575 	ulong r;
       
   576 	if ( ReadFile( dev, buf, bytes, &r, 0 ) )
       
   577 	    return r;
       
   578     }
       
   579     return 0;
       
   580 }
       
   581 
       
   582 /*
       
   583   Used by connectNotify() and disconnectNotify() to change the value of
       
   584   ioRedirection (and related behaviour)
       
   585 */
       
   586 void Q3Process::setIoRedirection( bool value )
       
   587 {
       
   588     ioRedirection = value;
       
   589     if ( !ioRedirection && !notifyOnExit )
       
   590 	d->lookup->stop();
       
   591     if ( ioRedirection ) {
       
   592 	if ( isRunning() )
       
   593 	    d->lookup->start( 100 );
       
   594     }
       
   595 }
       
   596 
       
   597 /*
       
   598   Used by connectNotify() and disconnectNotify() to change the value of
       
   599   notifyOnExit (and related behaviour)
       
   600 */
       
   601 void Q3Process::setNotifyOnExit( bool value )
       
   602 {
       
   603     notifyOnExit = value;
       
   604     if ( !ioRedirection && !notifyOnExit )
       
   605 	d->lookup->stop();
       
   606     if ( notifyOnExit ) {
       
   607 	if ( isRunning() )
       
   608 	    d->lookup->start( 100 );
       
   609     }
       
   610 }
       
   611 
       
   612 /*
       
   613   Used by connectNotify() and disconnectNotify() to change the value of
       
   614   wroteToStdinConnected (and related behaviour)
       
   615 */
       
   616 void Q3Process::setWroteStdinConnected( bool value )
       
   617 {
       
   618     wroteToStdinConnected = value;
       
   619 }
       
   620 
       
   621 Q3Process::PID Q3Process::processIdentifier()
       
   622 {
       
   623     return d->pid;
       
   624 }
       
   625 
       
   626 QT_END_NAMESPACE
       
   627 
       
   628 #endif // QT_NO_PROCESS