From bc855d0932e12588faa0ab373324e706aa9c6e5f Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Sun, 8 Apr 2007 00:18:09 +0000 Subject: [PATCH] added wxEXEC_BLOCK flag (patch 1620430) git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@45325 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- docs/changes.txt | 1 + docs/latex/wx/function.tex | 7 +++ include/wx/utils.h | 10 +++- src/unix/utilsunx.cpp | 103 +++++++++++++++++++++++++------------ 4 files changed, 88 insertions(+), 33 deletions(-) diff --git a/docs/changes.txt b/docs/changes.txt index b9068df632..11341667f0 100644 --- a/docs/changes.txt +++ b/docs/changes.txt @@ -79,6 +79,7 @@ All: - Added wxMutex::LockTimeout() (Aleksandr Napylov) - Added wxMemoryInputStream(wxInputStream&) ctor (Stas Sergeev) - Implemented wxMemoryInputStream::CanRead() +- Added wxEXEC_BLOCK flag (Hank Schultz) All (GUI): diff --git a/docs/latex/wx/function.tex b/docs/latex/wx/function.tex index c6db80094d..fe1e582e8a 100644 --- a/docs/latex/wx/function.tex +++ b/docs/latex/wx/function.tex @@ -647,6 +647,13 @@ needed). Calling \helpref{wxKill}{wxkill} passing wxKILL\_CHILDREN will kill this process as well as all of its children (except those which have started their own session). +The {\tt wxEXEC\_NOEVENTS} flag prevents processing of any events from taking +place while the child process is running. It should be only used for very +short-lived processes as otherwise the application windows risk becoming +unresponsive from the users point of view. As this flag only makes sense with +{\tt wxEXEC\_SYNC}, {\tt wxEXEC\_BLOCK} equal to the sum of both of these flags +is provided as a convenience. + Finally, you may use the third overloaded version of this function to execute a process (always synchronously, the contents of \arg{flags} is or'd with \texttt{wxEXEC\_SYNC}) and capture its output in the array \arg{output}. The diff --git a/include/wx/utils.h b/include/wx/utils.h index aec1d1ee50..4e4c71a58d 100644 --- a/include/wx/utils.h +++ b/include/wx/utils.h @@ -320,7 +320,15 @@ enum // by default synchronous execution disables all program windows to avoid // that the user interacts with the program while the child process is // running, you can use this flag to prevent this from happening - wxEXEC_NODISABLE = 8 + wxEXEC_NODISABLE = 8, + + // by default, the event loop is run while waiting for synchronous execution + // to complete and this flag can be used to simply block the main process + // until the child process finishes + wxEXEC_NOEVENTS = 16, + + // convenient synonym for flags given system()-like behaviour + wxEXEC_BLOCK = wxEXEC_SYNC | wxEXEC_NOEVENTS }; // Execute another program. diff --git a/src/unix/utilsunx.cpp b/src/unix/utilsunx.cpp index ff387a5124..cdaa159923 100644 --- a/src/unix/utilsunx.cpp +++ b/src/unix/utilsunx.cpp @@ -38,6 +38,7 @@ #include "wx/unix/private.h" #include +#include // waitpid() #ifdef HAVE_SYS_SELECT_H # include @@ -1237,56 +1238,94 @@ int wxGUIAppTraits::WaitForChild(wxExecuteData& execData) } + if ( !(flags & wxEXEC_NOEVENTS) ) + { #if defined(__DARWIN__) && (defined(__WXMAC__) || defined(__WXCOCOA__)) - endProcData->tag = wxAddProcessCallbackForPid(endProcData, execData.pid); + endProcData->tag = wxAddProcessCallbackForPid(endProcData, execData.pid); #else - endProcData->tag = wxAddProcessCallback - ( - endProcData, - execData.pipeEndProcDetect.Detach(wxPipe::Read) - ); + endProcData->tag = wxAddProcessCallback + ( + endProcData, + execData.pipeEndProcDetect.Detach(wxPipe::Read) + ); - execData.pipeEndProcDetect.Close(); + execData.pipeEndProcDetect.Close(); #endif // defined(__DARWIN__) && (defined(__WXMAC__) || defined(__WXCOCOA__)) + } if ( flags & wxEXEC_SYNC ) { wxBusyCursor bc; - wxWindowDisabler *wd = flags & wxEXEC_NODISABLE ? NULL - : new wxWindowDisabler; + int exitcode = 0; - // endProcData->pid will be set to 0 from GTK_EndProcessDetector when the - // process terminates - while ( endProcData->pid != 0 ) + wxWindowDisabler *wd = flags & (wxEXEC_NODISABLE | wxEXEC_NOEVENTS) + ? NULL + : new wxWindowDisabler; + + if ( flags & wxEXEC_NOEVENTS ) { - bool idle = true; + // just block waiting for the child to exit + int status = 0; + + int result = waitpid(execData.pid, &status, 0); + + if ( result == -1 ) + { + wxLogLastError(_T("waitpid")); + exitcode = -1; + } + else + { + wxASSERT_MSG( result == execData.pid, + _T("unexpected waitpid() return value") ); + + if ( WIFEXITED(status) ) + { + exitcode = WEXITSTATUS(status); + } + else // abnormal termination? + { + wxASSERT_MSG( WIFSIGNALED(status), + _T("unexpected child wait status") ); + exitcode = -1; + } + } + } + else // !wxEXEC_NOEVENTS + { + // endProcData->pid will be set to 0 from GTK_EndProcessDetector when the + // process terminates + while ( endProcData->pid != 0 ) + { + bool idle = true; #if HAS_PIPE_INPUT_STREAM - if ( execData.bufOut ) - { - execData.bufOut->Update(); - idle = false; - } + if ( execData.bufOut ) + { + execData.bufOut->Update(); + idle = false; + } - if ( execData.bufErr ) - { - execData.bufErr->Update(); - idle = false; - } + if ( execData.bufErr ) + { + execData.bufErr->Update(); + idle = false; + } #endif // HAS_PIPE_INPUT_STREAM - // don't consume 100% of the CPU while we're sitting in this - // loop - if ( idle ) - wxMilliSleep(1); + // don't consume 100% of the CPU while we're sitting in this + // loop + if ( idle ) + wxMilliSleep(1); - // give GTK+ a chance to call GTK_EndProcessDetector here and - // also repaint the GUI - wxYield(); + // give GTK+ a chance to call GTK_EndProcessDetector here and + // also repaint the GUI + wxYield(); + } + + exitcode = endProcData->exitcode; } - int exitcode = endProcData->exitcode; - delete wd; delete endProcData;