\wxheading{See also}
-\helpref{wxBeginBusyCursor}{wxbeginbusycursor}, \helpref{wxEndBusyCursor}{wxendbusycursor}
+\helpref{wxBeginBusyCursor}{wxbeginbusycursor},\rtfsp
+\helpref{wxEndBusyCursor}{wxendbusycursor},\rtfsp
+\helpref{wxWindowDisabler}{wxwindowdisabler}
\latexignore{\rtfignore{\wxheading{Members}}}
Called when wxWindows exits, to clean up the DDE system. This no longer needs to be
called by the application.
-See also helpref{wxDDEInitialize}{wxddeinitialize}.
+See also \helpref{wxDDEInitialize}{wxddeinitialize}.
\wxheading{Include files}
\func{long}{wxExecute}{\param{char **}{argv}, \param{bool }{sync = FALSE}, \param{wxProcess *}{callback = NULL}}
+\func{long}{wxExecute}{\param{const wxString\& }{command}, \param{wxArrayString\& }{output}}
+
Executes another program in Unix or Windows.
The first form takes a command string, such as {\tt "emacs file.txt"}.
The second form takes an array of values: a command, any number of
arguments, terminated by NULL.
+The semantics of the third version is different from the first two and is
+described in more details below.
+
If {\it sync} is FALSE (the default), flow of control immediately returns.
If TRUE, the current application waits until the other program has terminated.
\helpref{wxProcess::OnTerminate}{wxprocessonterminate} will be called when
the process finishes.
+Finally, you may use the third overloaded version of this function to execute
+a process (always synchronously) and capture its output in the array
+{\it output}.
+
See also \helpref{wxShell}{wxshell}, \helpref{wxProcess}{wxprocess},
\helpref{Exec sample}{sampleexec}.
Returns the first character in the input queue and removes it.
+\membersection{wxInputStream::Eof}\label{wxinputstreameof}
+
+\constfunc{wxInputStream}{Eof}{\void}
+
+Returns TRUE if the end of stream has been reached.
+
\membersection{wxInputStream::LastRead}\label{wxinputstreamlastread}
\constfunc{size\_t}{LastRead}{\void}
\wxheading{Return value}
-It returns the size of the data read. If thereturned size is different of the specified
+It returns the size of the data read. If the returned size is different of the specified
{\it size}, an error has occured and should be tested using
\helpref{LastError}{wxstreambaselasterror}.
Destructor.
+\membersection{wxStreamBase::IsOk}\label{wxstreambaseisok}
+
+\constfunc{wxStreamError}{IsOk}{\void}
+
+Returns TRUE if no error occured on the stream.
+
+\wxheading{See also}
+
+\helpref{LastError}{wxstreambaselasterror}
+
\membersection{wxStreamBase::LastError}\label{wxstreambaselasterror}
\constfunc{wxStreamError}{LastError}{\void}
\constfunc{size\_t}{GetSize}{\void}
This function returns the size of the stream. For example, for a file it is the size of
-the file).
+the file.
\wxheading{Warning}
--- /dev/null
+\section{\class{wxWindowDisabler}}\label{wxwindowdisabler}
+
+This class disables all windows of the application (may be with the exception
+of one of them) in its constructor and enables them back in its destructor.
+This comes in handy when you want to indicate to the user that the application
+is currently busy and cannot respond to user input.
+
+\wxheading{Derived from}
+
+None
+
+\wxheading{Include files}
+
+<wx/utils.h>
+
+\wxheading{See also}
+
+\helpref{wxBusyCursor}{wxbusycursor}
+
+\latexignore{\rtfignore{\wxheading{Members}}}
+
+\membersection{wxWindowDisabler::wxWindowDisabler}
+
+\func{}{wxWindowDisabler}{\param{wxWindow *}{winToSkip = NULL}}
+
+Disables all top level windows of the applications with the exception of
+{\it winToSkip} if it is not {\tt NULL}.
+
+\membersection{wxWindowDisabler::\destruct{wxWindowDisabler}}
+
+Reenables back the windows disabled by the constructor.
DECLARE_DYNAMIC_CLASS(wxProcess)
public:
- wxProcess(wxEvtHandler *parent = (wxEvtHandler *) NULL, bool needPipe = FALSE, int id = -1);
- ~wxProcess();
+ wxProcess(wxEvtHandler *parent = (wxEvtHandler *) NULL, int id = -1)
+ { Init(parent, id, FALSE); }
+ wxProcess(wxEvtHandler *parent, bool redirect)
+ { Init(parent, -1, redirect); }
+ virtual ~wxProcess();
+
+ // may be overridden to be notified about process termination
virtual void OnTerminate(int pid, int status);
+ // call this before passing the object to wxExecute() to redirect the
+ // launched process stdin/stdout, then use GetInputStream() and
+ // GetOutputStream() to get access to them
+ void Redirect() { m_redirect = TRUE; }
+ bool IsRedirected() const { return m_redirect; }
+
// detach from the parent - should be called by the parent if it's deleted
// before the process it started terminates
void Detach();
// Pipe handling
- wxInputStream *GetInputStream() const;
- wxOutputStream *GetOutputStream() const;
+ wxInputStream *GetInputStream() const { return m_inputStream; }
+ wxOutputStream *GetOutputStream() const { return m_outputStream; }
- // These functions should not be called by the usual user. They are only
- // intended to be used by wxExecute.
- // Install pipes
- void SetPipeStreams(wxInputStream *in_stream, wxOutputStream *out_stream);
- bool NeedPipe() const;
+ // implementation only (for wxExecute)
+ void SetPipeStreams(wxInputStream *inStream, wxOutputStream *outStream);
protected:
+ void Init(wxEvtHandler *parent, int id, bool redirect);
+
int m_id;
- bool m_needPipe;
- wxInputStream *m_in_stream;
- wxOutputStream *m_out_stream;
+
+ wxInputStream *m_inputStream;
+ wxOutputStream *m_outputStream;
+
+ bool m_redirect;
};
typedef void (wxObject::*wxProcessEventFunction)(wxProcessEvent&);
// wxStream: base classes
// ---------------------------------------------------------------------------
-#define wxStream_NOERROR wxSTREAM_NOERROR
-#define wxStream_EOF wxSTREAM_EOF
-#define wxStream_WRITE_ERR wxSTREAM_WRITE_ERROR
-#define wxStream_READ_ERR wxSTREAM_READ_ERROR
-
-typedef enum {
+typedef enum
+{
wxSTREAM_NO_ERROR = 0,
wxSTREAM_NO_ERR = wxSTREAM_NO_ERROR,
wxSTREAM_NOERROR = wxSTREAM_NO_ERROR,
} wxStreamError;
+// compatibility
+#define wxStream_NOERROR wxSTREAM_NOERROR
+#define wxStream_EOF wxSTREAM_EOF
+#define wxStream_WRITE_ERR wxSTREAM_WRITE_ERROR
+#define wxStream_READ_ERR wxSTREAM_READ_ERROR
+
class WXDLLEXPORT wxStreamBase
{
public:
wxStreamBase();
virtual ~wxStreamBase();
- bool operator!() const { return (LastError() != wxSTREAM_NOERROR); }
+ // error testing
wxStreamError LastError() const { return m_lasterror; }
+ wxStreamError GetLastError() const { return m_lasterror; }
+ bool IsOk() const { return LastError() == wxSTREAM_NOERROR; }
+ bool operator!() const { return LastError() != wxSTREAM_NOERROR; }
+
virtual size_t GetSize() const { return ~((size_t)0); }
size_t StreamSize() const { return GetSize(); }
wxInputStream();
virtual ~wxInputStream();
+ // is the stream at EOF?
+ virtual bool Eof() const;
+
// IO functions
virtual char Peek();
char GetC();
class WXDLLEXPORT wxProcess;
class WXDLLEXPORT wxFrame;
class WXDLLEXPORT wxWindow;
+class WXDLLEXPORT wxWindowList;
// FIXME should use wxStricmp() instead
#if defined(__GNUWIN32__)
WXDLLEXPORT long wxExecute(const wxString& command, bool sync = FALSE,
wxProcess *process = (wxProcess *) NULL);
+// execute the command capturing its output into an array line by line
+WXDLLEXPORT long wxExecute(const wxString& command, wxArrayString& output);
+
enum wxSignal
{
wxSIGNONE = 0, // verify if the process exists under Unix
// Consume all events until no more left
WXDLLEXPORT void wxFlushEvents();
+// a class which disables all windows (except, may be, thegiven one) in its
+// ctor and enables them back in its dtor
+class WXDLLEXPORT wxWindowDisabler
+{
+public:
+ wxWindowDisabler(wxWindow *winToSkip = (wxWindow *)NULL);
+ ~wxWindowDisabler();
+
+private:
+ wxWindowList *m_winDisabled;
+};
+
// ----------------------------------------------------------------------------
// Cursors
// ----------------------------------------------------------------------------
virtual bool OnInit();
};
+// Define an array of process pointers used by MyFrame
+class MyPipedProcess;
+WX_DEFINE_ARRAY(MyPipedProcess *, MyProcessesArray);
+
// Define a new frame type: this is going to be our main frame
class MyFrame : public wxFrame
{
void OnAbout(wxCommandEvent& event);
+ // polling output of async processes
+ void OnIdle(wxIdleEvent& event);
+
// for MyPipedProcess
+ void OnProcessTerminated(MyPipedProcess *process)
+ { m_running.Remove(process); }
wxListBox *GetLogListBox() const { return m_lbox; }
private:
wxListBox *m_lbox;
+ MyProcessesArray m_running;
+
// any class wishing to process wxWindows events must use this macro
DECLARE_EVENT_TABLE()
};
MyPipedProcess(MyFrame *parent, const wxString& cmd)
: MyProcess(parent, cmd)
{
- m_needPipe = TRUE;
+ Redirect();
}
virtual void OnTerminate(int pid, int status);
+
+ bool HasInput();
};
// ----------------------------------------------------------------------------
EVT_MENU(Exec_DDEExec, MyFrame::OnDDEExec)
EVT_MENU(Exec_About, MyFrame::OnAbout)
+
+ EVT_IDLE(MyFrame::OnIdle)
END_EVENT_TABLE()
// Create a new application object: this macro will allow wxWindows to create
if ( !cmd )
return;
- wxProcess *process = new MyPipedProcess(this, cmd);
- if ( !wxExecute(cmd, FALSE /* async */, process) )
+ bool sync;
+ switch ( wxMessageBox(_T("Execute it synchronously?"),
+ _T("Exec question"),
+ wxYES_NO | wxCANCEL | wxICON_QUESTION, this) )
{
- wxLogError(_T("Execution of '%s' failed."), cmd.c_str());
+ case wxYES:
+ sync = TRUE;
+ break;
- delete process;
+ case wxNO:
+ sync = FALSE;
+ break;
+
+ default:
+ return;
}
- else
+
+ if ( sync )
{
- m_cmdLast = cmd;
+ wxArrayString output;
+ int code = wxExecute(cmd, output);
+ wxLogStatus(_T("command '%s' terminated with exit code %d."),
+ cmd.c_str(), code);
+
+ if ( code != -1 )
+ {
+ m_lbox->Append(wxString::Format(_T("--- Output of '%s' ---"),
+ cmd.c_str()));
+
+ size_t count = output.GetCount();
+ for ( size_t n = 0; n < count; n++ )
+ {
+ m_lbox->Append(output[n]);
+ }
+ }
+ }
+ else // async exec
+ {
+ MyPipedProcess *process = new MyPipedProcess(this, cmd);
+ if ( !wxExecute(cmd, FALSE /* async */, process) )
+ {
+ wxLogError(_T("Execution of '%s' failed."), cmd.c_str());
+
+ delete process;
+ }
+ else
+ {
+ m_running.Add(process);
+ }
}
+
+ m_cmdLast = cmd;
}
void MyFrame::OnDDEExec(wxCommandEvent& WXUNUSED(event))
#endif // __WINDOWS__
}
+// input polling
+void MyFrame::OnIdle(wxIdleEvent& event)
+{
+ size_t count = m_running.GetCount();
+ for ( size_t n = 0; n < count; n++ )
+ {
+ if ( m_running[n]->HasInput() )
+ {
+ event.RequestMore();
+ }
+ }
+}
+
// ----------------------------------------------------------------------------
// MyProcess
// ----------------------------------------------------------------------------
delete this;
}
-void MyPipedProcess::OnTerminate(int pid, int status)
+// ----------------------------------------------------------------------------
+// MyPipedProcess
+// ----------------------------------------------------------------------------
+
+bool MyPipedProcess::HasInput()
{
- // show the program output
- wxListBox *lbox = m_parent->GetLogListBox();
- lbox->Append(wxString::Format(_T("--- Output of '%s' ---"), m_cmd.c_str()));
+ wxInputStream& is = *GetInputStream();
+ if ( !is.Eof() )
+ {
+ wxTextInputStream tis(is);
+
+ // this assumes that the output is always line buffered
+ wxString msg;
+ msg << m_cmd << _T(": ") << tis.ReadLine();
- wxTextInputStream tis(*m_in_stream);
- while ( !m_in_stream->LastError() )
+ m_parent->GetLogListBox()->Append(msg);
+
+ return TRUE;
+ }
+ else
{
- lbox->Append(tis.ReadLine());
+ return FALSE;
}
+}
+
+void MyPipedProcess::OnTerminate(int pid, int status)
+{
+ // show the rest of the output
+ while ( HasInput() )
+ ;
+
+ m_parent->OnProcessTerminated(this);
MyProcess::OnTerminate(pid, status);
}
IMPLEMENT_DYNAMIC_CLASS(wxProcess, wxEvtHandler)
IMPLEMENT_DYNAMIC_CLASS(wxProcessEvent, wxEvent)
-wxProcess::wxProcess(wxEvtHandler *parent, bool needPipe, int id)
+void wxProcess::Init(wxEvtHandler *parent, int id, bool redirect)
{
- if (parent)
+ if ( parent )
SetNextHandler(parent);
m_id = id;
- m_needPipe = needPipe;
- m_in_stream = NULL;
- m_out_stream = NULL;
+ m_redirect = redirect;
+ m_inputStream = NULL;
+ m_outputStream = NULL;
}
wxProcess::~wxProcess()
{
- if (m_in_stream)
- delete m_in_stream;
- if (m_out_stream)
- delete m_out_stream;
+ delete m_inputStream;
+ delete m_outputStream;
}
void wxProcess::OnTerminate(int pid, int status)
void wxProcess::SetPipeStreams(wxInputStream *in_stream, wxOutputStream *out_stream)
{
- m_in_stream = in_stream;
- m_out_stream = out_stream;
+ m_inputStream = in_stream;
+ m_outputStream = out_stream;
}
-wxInputStream *wxProcess::GetInputStream() const
-{
- return m_in_stream;
-}
-
-wxOutputStream *wxProcess::GetOutputStream() const
-{
- return m_out_stream;
-}
-
-bool wxProcess::NeedPipe() const
-{
- return m_needPipe;
-}
}
GetFromBuffer(&c, 1);
-
+
m_stream->m_lastcount = 1;
return c;
}
size_t buf_left, orig_size = size;
while (size > 0) {
- buf_left = GetDataLeft();
+ buf_left = GetDataLeft();
// First case: the requested buffer is larger than the stream buffer,
// we split it.
return wxInvalidOffset;
pos += GetIntPosition();
-
+
if (m_mode == read && m_flushable)
pos -= GetLastAccess();
-
+
return pos;
}
/* Why is this done? RR. */
if (m_buffer_end == m_buffer_pos && m_flushable)
FillBuffer();
-
+
return m_buffer_end-m_buffer_pos;
}
free(m_wback);
}
+bool wxInputStream::Eof() const
+{
+ wxInputStream *self = (wxInputStream *)this; // const_cast
+
+ char c;
+ self->Read(&c, 1);
+ if ( GetLastError() == wxSTREAM_EOF )
+ {
+ return TRUE;
+ }
+
+ self->Ungetch(c);
+
+ return FALSE;
+}
+
char *wxInputStream::AllocSpaceWBack(size_t needed_size)
{
/* get number of bytes left from previous wback buffer */
memcpy(buf, (m_wback+m_wbackcur), s_toget);
m_wbackcur += s_toget;
- if (m_wbackcur == m_wbacksize)
+ if (m_wbackcur == m_wbacksize)
{
free(m_wback);
m_wback = (char *)NULL;
m_wbacksize = 0;
m_wbackcur = 0;
}
-
+
return s_toget;
}
char *ptrback = AllocSpaceWBack(bufsize);
if (!ptrback)
return 0;
-
+
memcpy(ptrback, buf, bufsize);
return bufsize;
}
char *buf = (char *)buffer;
size_t retsize = GetWBack(buf, size);
- if (retsize == size)
+ if (retsize == size)
{
m_lastcount = size;
m_lasterror = wxStream_NOERROR;
{
char c;
Read(&c, 1);
- if (m_lasterror == wxStream_NOERROR)
+ if (m_lasterror == wxStream_NOERROR)
{
Ungetch(c);
return c;
}
-
+
return 0;
}
wxInputStream& wxInputStream::Read(wxOutputStream& stream_out)
{
- char buf[BUF_TEMP_SIZE];
+ char buf[BUF_TEMP_SIZE];
size_t bytes_read = BUF_TEMP_SIZE;
- while (bytes_read == BUF_TEMP_SIZE)
+ while (bytes_read == BUF_TEMP_SIZE)
{
bytes_read = Read(buf, bytes_read).LastRead();
bytes_read = stream_out.Write(buf, bytes_read).LastWrite();
{
/* Should be check and improve, just to remove a slight bug !
I don't know whether it should be put as well in wxFileInputStream::OnSysSeek ? */
- if (m_lasterror==wxSTREAM_EOF)
+ if (m_lasterror==wxSTREAM_EOF)
m_lasterror=wxSTREAM_NOERROR;
/* A call to SeekI() will automatically invalidate any previous call
when seeking in wxFromCurrent mode, else it would invalidate
anyway...
*/
- if (m_wback)
+ if (m_wback)
{
free(m_wback);
m_wback = (char*) NULL;
m_currentPos = m_lastcount + pos;
else
m_currentPos += pos;
-
+
if (m_currentPos > m_lastcount) m_lastcount = m_currentPos;
-
+
return m_currentPos;
}
{
return m_currentPos;
}
-
+
// ----------------------------------------------------------------------------
// wxFilterInputStream
// ----------------------------------------------------------------------------
retsize = GetWBack(buf, size);
m_lastcount = retsize;
- if (retsize == size)
+ if (retsize == size)
{
m_lasterror = wxStream_NOERROR;
return *this;
// Created: 28/06/98
// RCS-ID: $Id$
// Copyright: (c) Guilhem Lavaux
-// Licence: wxWindows license
+// Licence: wxWindows license
/////////////////////////////////////////////////////////////////////////////
#ifdef __GNUG__
wxChar c = (wxChar) 0;
for (;;)
{
- if (!m_input) return (wxChar) 0;
+ if (!m_input) return (wxChar) 0;
c = m_input.GetC();
-
- if (c != wxT('\n') &&
- c != wxT('\r') &&
- !m_separators.Contains(c))
- return c;
+
+ if (c != wxT('\n') &&
+ c != wxT('\r') &&
+ !m_separators.Contains(c))
+ return c;
}
}
inline bool wxTextInputStream::EatEOL(const wxChar &c)
{
if (c == wxT('\n')) return TRUE; // eat on UNIX
-
+
if (c == wxT('\r')) // eat on both Mac and DOS
{
if (!m_input) return TRUE;
wxChar c2 = m_input.GetC();
-
+
if (c2 != wxT('\n')) m_input.Ungetch( c2 ); // Don't eat on Mac
return TRUE;
}
wxUint32 wxTextInputStream::Read32()
{
/* I only implemented a simple integer parser */
+ // VZ: what about using strtol()?? (TODO)
+
int sign;
wxInt32 i;
if (!m_input) return 0;
- int c = NextNonSeparators();
+ int c = NextNonSeparators();
if (c==(wxChar)0) return 0;
i = 0;
double wxTextInputStream::ReadDouble()
{
/* I only implemented a simple float parser */
+ // VZ: what about using strtod()?? (TODO)
double f;
int sign;
c = m_input.GetC();
while (isdigit(c))
- {
+ {
f += (c-wxT('0'))*f_multiplicator;
f_multiplicator /= 10;
c = m_input.GetC();
}
if (c == wxT('e'))
- {
+ {
double f_multiplicator = 0.0;
int i, e;
c = m_input.GetC();
switch (c)
- {
+ {
case wxT('-'): f_multiplicator = 0.1; break;
- case wxT('+'): f_multiplicator = 10.0; break;
- }
+ case wxT('+'): f_multiplicator = 10.0; break;
+ }
e = Read8(); // why only max 256 ?
for (i=0;i<e;i++)
f *= f_multiplicator;
}
- else
- SkipIfEndOfLine( c );
+ else
+ SkipIfEndOfLine( c );
}
else
{
wxString wxTextInputStream::ReadString()
{
- return ReadLine();
+ return ReadLine();
}
wxString wxTextInputStream::ReadLine()
wxChar c;
wxString line;
- for (;;)
+ while ( !m_input.Eof() )
{
- if (!m_input) break;
c = m_input.GetC();
-
- if (EatEOL(c)) break;
-
+ if ( !m_input )
+ break;
+
+ if (EatEOL(c))
+ break;
+
line += c;
}
wxString wxTextInputStream::ReadWord()
{
- if (!m_input) return "";
-
wxString word;
- wxChar c=NextNonSeparators();
- if (c==(wxChar)0) return "";
- for (;;)
+ if ( !m_input )
+ return word;
+
+ wxChar c = NextNonSeparators();
+ if ( !c )
+ return word;
+
+ while ( !m_input.Eof() )
{
- if (m_separators.Contains(c)) break;
-
- if (EatEOL(c)) break;
-
+ if (m_separators.Contains(c))
+ break;
+
+ if (EatEOL(c))
+ break;
+
word += c;
- if (!m_input) break;
c = m_input.GetC();
+ if (!m_input)
+ break;
}
return word;
wxTextInputStream& wxTextInputStream::operator>>(wxString& word)
{
- word = ReadWord();
- return *this;
+ word = ReadWord();
+ return *this;
}
wxTextInputStream& wxTextInputStream::operator>>(wxChar& c)
wxChar c = string[i];
if (c == wxT('\n'))
{
- if (m_mode == wxEOL_DOS)
- {
+ if (m_mode == wxEOL_DOS)
+ {
c = wxT('\r');
m_output.Write( (const void*)(&c), sizeof(wxChar) );
c = wxT('\n');
m_output.Write( (const void*)(&c), sizeof(wxChar) );
- } else
- if (m_mode == wxEOL_MAC)
- {
+ } else
+ if (m_mode == wxEOL_MAC)
+ {
c = wxT('\r');
m_output.Write( (const void*)(&c), sizeof(wxChar) );
- } else
- {
+ } else
+ {
c = wxT('\n');
m_output.Write( (const void*)(&c), sizeof(wxChar) );
}
wxString str;
str.Printf(wxT("%d"), (signed int)c);
WriteString(str);
-
+
return *this;
}
wxString str;
str.Printf(wxT("%ld"), (signed long)c);
WriteString(str);
-
+
return *this;
}
wxString str;
str.Printf(wxT("%u"), (unsigned int)c);
WriteString(str);
-
+
return *this;
}
#endif // wxUSE_GUI
#endif // WX_PRECOMP
+#include "wx/process.h"
+#include "wx/txtstrm.h"
+
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
for ( node = win->GetChildren().GetFirst(); node; node = node->GetNext() )
{
wxWindow *child = node->GetData();
+ wxFindDisabledWindows(winDisabled, child);
+
if ( child->IsEnabled() )
{
winDisabled.Append(child);
+ child->Disable();
}
-
- wxFindDisabledWindows(winDisabled, child);
}
}
-// Yield to other apps/messages and disable user input to all windows except
-// the given one
-bool wxSafeYield(wxWindow *win)
+wxWindowDisabler::wxWindowDisabler(wxWindow *winToSkip)
{
// remember all windows we're going to (temporarily) disable
- wxWindowList winDisabled;
+ m_winDisabled = new wxWindowList;
wxWindowList::Node *node;
for ( node = wxTopLevelWindows.GetFirst(); node; node = node->GetNext() )
{
wxWindow *winTop = node->GetData();
- wxFindDisabledWindows(winDisabled, winTop);
+ if ( winTop->IsEnabled() )
+ {
+ wxFindDisabledWindows(*m_winDisabled, winTop);
- winTop->Disable();
+ m_winDisabled->Append(winTop);
+ winTop->Disable();
+ }
}
- if ( win )
+ if ( winToSkip && m_winDisabled->Find(winToSkip) )
{
// always enable ourselves
- win->Enable();
+ m_winDisabled->DeleteObject(winToSkip);
+ winToSkip->Enable();
}
+}
- bool rc = wxYield();
-
- // don't call wxEnableTopLevelWindows(TRUE) because this will reenable even
- // the window which had been disabled before, do it manually instead
- for ( node = winDisabled.GetFirst(); node; node = node->GetNext() )
+wxWindowDisabler::~wxWindowDisabler()
+{
+ wxWindowList::Node *node;
+ for ( node = m_winDisabled->GetFirst(); node; node = node->GetNext() )
{
node->GetData()->Enable();
}
+ delete m_winDisabled;
+}
+
+// Yield to other apps/messages and disable user input to all windows except
+// the given one
+bool wxSafeYield(wxWindow *win)
+{
+ wxWindowDisabler wd;
+
+ bool rc = wxYield();
+
return rc;
}
}
#endif // 0
+
+// ----------------------------------------------------------------------------
+// wxExecute
+// ----------------------------------------------------------------------------
+
+long wxExecute(const wxString& command, wxArrayString& output)
+{
+ // create a wxProcess which will capture the output
+ wxProcess *process = new wxProcess;
+ process->Redirect();
+
+ long rc = wxExecute(command, TRUE /* sync */, process);
+ if ( rc != -1 )
+ {
+ wxInputStream& is = *process->GetInputStream();
+ wxTextInputStream tis(is);
+ while ( !is.Eof() )
+ {
+ wxString line = tis.ReadLine();
+ if ( is.LastError() )
+ break;
+
+ output.Add(line);
+ }
+ }
+
+ return rc;
+}
wxPipeInputStream::wxPipeInputStream(HANDLE hInput)
{
m_hInput = hInput;
-}
+}
wxPipeInputStream::~wxPipeInputStream()
{
wxPipeOutputStream::wxPipeOutputStream(HANDLE hOutput)
{
m_hOutput = hOutput;
-}
+}
wxPipeOutputStream::~wxPipeOutputStream()
{
return result;
#else // 1
-
+
HANDLE h_readPipe[2];
HANDLE h_writePipe[2];
HANDLE h_oldreadPipe;
HANDLE h_oldwritePipe;
BOOL inheritHandles;
- // ------------------------------------
- // Pipe handling
- // We are in the case of opening a pipe
+ // open the pipes to which child process IO will be redirected if needed
inheritHandles = FALSE;
- if (handler && handler->NeedPipe()) {
+ if ( handler && handler->IsRedirected() )
+ {
SECURITY_ATTRIBUTES security;
security.nLength = sizeof(security);
security.lpSecurityDescriptor = NULL;
security.bInheritHandle = TRUE;
- if (! ::CreatePipe(&h_readPipe[0], &h_readPipe[1], &security, 0) ) {
- wxLogSysError(_T("Can't create the inter-process read pipe"));
+ if (! ::CreatePipe(&h_readPipe[0], &h_readPipe[1], &security, 0) )
+ {
+ wxLogSysError(_("Can't create the inter-process read pipe"));
return 0;
}
- if (! ::CreatePipe(&h_writePipe[0], &h_writePipe[1], &security, 0) ) {
- wxLogSysError(_T("Can't create the inter-process read pipe"));
+ if (! ::CreatePipe(&h_writePipe[0], &h_writePipe[1], &security, 0) )
+ {
+ ::CloseHandle(h_readPipe[0]);
+ ::CloseHandle(h_readPipe[1]);
+
+ wxLogSysError(_("Can't create the inter-process write pipe"));
return 0;
}
&pi // process info
) == 0 )
{
- if (inheritHandles) {
+ if ( inheritHandles )
+ {
::CloseHandle(h_writePipe[0]);
::CloseHandle(h_writePipe[1]);
::CloseHandle(h_readPipe[0]);
::CloseHandle(h_readPipe[1]);
}
+
wxLogSysError(_("Execution of command '%s' failed"), command.c_str());
return 0;
// waiting until command executed (disable everything while doing it)
#if wxUSE_GUI
- wxBeginBusyCursor();
- wxEnableTopLevelWindows(FALSE);
+ {
+ wxBusyCursor bc;
+
+ wxWindowDisabler wd;
#endif // wxUSE_GUI
while ( data->state )
wxYield();
#if wxUSE_GUI
- wxEnableTopLevelWindows(TRUE);
- wxEndBusyCursor();
+ }
#endif // wxUSE_GUI
DWORD dwExitCode = data->dwExitCode;
bool wxShell(const wxString& command)
{
wxString cmd;
- if ( !!command )
- cmd.Printf(wxT("xterm -e %s"), command.c_str());
+ if ( !command )
+ cmd = _T("xterm");
else
cmd = command;
#endif // wxUSE_GUI
-#if wxUSE_GUI
- #define WXUNUSED_UNLESS_GUI(p) p
-#else
- #define WXUNUSED_UNLESS_GUI(p)
-#endif
+// ----------------------------------------------------------------------------
+// wxStream classes to support IO redirection in wxExecute
+// ----------------------------------------------------------------------------
-// New wxStream classes to clean up the data when the process terminates
+class wxProcessFileInputStream : public wxInputStream
+{
+public:
+ wxProcessFileInputStream(int fd) { m_fd = fd; }
+ ~wxProcessFileInputStream() { close(m_fd); }
-#if wxUSE_GUI
-class wxProcessFileInputStream: public wxInputStream {
- public:
- wxProcessFileInputStream(int fd);
- ~wxProcessFileInputStream();
+ virtual bool Eof() const;
- protected:
+protected:
size_t OnSysRead(void *buffer, size_t bufsize);
- protected:
+protected:
int m_fd;
};
-class wxProcessFileOutputStream: public wxOutputStream {
- public:
- wxProcessFileOutputStream(int fd);
- ~wxProcessFileOutputStream();
+class wxProcessFileOutputStream : public wxOutputStream
+{
+public:
+ wxProcessFileOutputStream(int fd) { m_fd = fd; }
+ ~wxProcessFileOutputStream() { close(m_fd); }
- protected:
+protected:
size_t OnSysWrite(const void *buffer, size_t bufsize);
- protected:
+protected:
int m_fd;
};
-wxProcessFileInputStream::wxProcessFileInputStream(int fd)
+bool wxProcessFileInputStream::Eof() const
{
- m_fd = fd;
-}
+ if ( m_lasterror == wxSTREAM_EOF )
+ return TRUE;
-wxProcessFileInputStream::~wxProcessFileInputStream()
-{
- close(m_fd);
-}
+ // check if there is any input available
+ struct timeval tv;
+ tv.tv_sec = 0;
+ tv.tv_usec = 0;
-size_t wxProcessFileInputStream::OnSysRead(void *buffer, size_t bufsize)
-{
- int ret;
-
- ret = read(m_fd, buffer, bufsize);
- m_lasterror = wxSTREAM_NOERROR;
- if (ret == 0)
- m_lasterror = wxSTREAM_EOF;
- if (ret == -1) {
- m_lasterror = wxSTREAM_READ_ERROR;
- ret = 0;
+ fd_set readfds;
+ FD_ZERO(&readfds);
+ FD_SET(m_fd, &readfds);
+ switch ( select(m_fd + 1, &readfds, NULL, NULL, &tv) )
+ {
+ case -1:
+ wxLogSysError(_("Impossible to get child process input"));
+ // fall through
+
+ case 0:
+ return TRUE;
+
+ default:
+ wxFAIL_MSG(_T("unexpected select() return value"));
+ // still fall through
+
+ case 1:
+ // input available: check if there is any
+ return wxInputStream::Eof();
}
- return ret;
}
-wxProcessFileOutputStream::wxProcessFileOutputStream(int fd)
+size_t wxProcessFileInputStream::OnSysRead(void *buffer, size_t bufsize)
{
- m_fd = fd;
-}
+ int ret = read(m_fd, buffer, bufsize);
+ if ( ret == 0 )
+ {
+ m_lasterror = wxSTREAM_EOF;
+ }
+ else if ( ret == -1 )
+ {
+ m_lasterror = wxSTREAM_READ_ERROR;
+ ret = 0;
+ }
+ else
+ {
+ m_lasterror = wxSTREAM_NOERROR;
+ }
-wxProcessFileOutputStream::~wxProcessFileOutputStream()
-{
- close(m_fd);
+ return ret;
}
size_t wxProcessFileOutputStream::OnSysWrite(const void *buffer, size_t bufsize)
{
- int ret;
-
- ret = write(m_fd, buffer, bufsize);
- m_lasterror = wxSTREAM_NOERROR;
- if (ret == -1) {
- m_lasterror = wxSTREAM_WRITE_ERROR;
- ret = 0;
+ int ret = write(m_fd, buffer, bufsize);
+ if ( ret == -1 )
+ {
+ m_lasterror = wxSTREAM_WRITE_ERROR;
+ ret = 0;
+ }
+ else
+ {
+ m_lasterror = wxSTREAM_NOERROR;
}
+
return ret;
}
-#endif
-
long wxExecute(wxChar **argv,
bool sync,
- wxProcess * WXUNUSED_UNLESS_GUI(process))
+ wxProcess *process)
{
wxCHECK_MSG( *argv, 0, wxT("can't exec empty command") );
while (argv[mb_argc])
{
- wxWX2MBbuf mb_arg = wxConvertWX2MB(argv[mb_argc]);
- mb_argv[mb_argc] = strdup(mb_arg);
- mb_argc++;
+ wxWX2MBbuf mb_arg = wxConvertWX2MB(argv[mb_argc]);
+ mb_argv[mb_argc] = strdup(mb_arg);
+ mb_argc++;
}
mb_argv[mb_argc] = (char *) NULL;
#if wxUSE_GUI
// create pipes
int end_proc_detect[2];
- if (pipe(end_proc_detect) == -1)
+ if ( pipe(end_proc_detect) == -1 )
{
wxLogSysError( _("Pipe creation failed") );
+ wxLogError( _("Failed to execute '%s'\n"), *argv );
ARGS_CLEANUP;
}
#endif // wxUSE_GUI
-#if wxUSE_GUI
- int in_pipe[2] = { -1, -1 };
- int out_pipe[2] = { -1, -1 };
- // Only asynchronous mode is interresting
- if (!sync && process && process->NeedPipe())
+ int pipeIn[2];
+ int pipeOut[2];
+ pipeIn[0] = pipeIn[1] =
+ pipeOut[0] = pipeOut[1] = -1;
+
+ if ( process && process->IsRedirected() )
{
- if (pipe(in_pipe) == -1 || pipe(out_pipe) == -1)
+ if ( pipe(pipeIn) == -1 || pipe(pipeOut) == -1 )
{
- /* Free fds */
+#if wxUSE_GUI
+ // free previously allocated resources
close(end_proc_detect[0]);
close(end_proc_detect[1]);
- wxLogSysError( _("Pipe creation failed (Console pipes)") );
+#endif // wxUSE_GUI
+
+ wxLogSysError( _("Pipe creation failed") );
+ wxLogError( _("Failed to execute '%s'\n"), *argv );
ARGS_CLEANUP;
return 0;
}
}
-#endif // wxUSE_GUI
// fork the process
#ifdef HAVE_VFORK
#else
pid_t pid = fork();
#endif
- if (pid == -1)
+
+ if ( pid == -1 ) // error?
{
#if wxUSE_GUI
close(end_proc_detect[0]);
close(end_proc_detect[1]);
- close(in_pipe[0]);
- close(in_pipe[1]);
- close(out_pipe[0]);
- close(out_pipe[1]);
-#endif
+ close(pipeIn[0]);
+ close(pipeIn[1]);
+ close(pipeOut[0]);
+ close(pipeOut[1]);
+#endif // wxUSE_GUI
+
wxLogSysError( _("Fork failed") );
ARGS_CLEANUP;
return 0;
}
- else if (pid == 0)
+ else if ( pid == 0 ) // we're in child
{
#if wxUSE_GUI
- // we're in child
close(end_proc_detect[0]); // close reading side
#endif // wxUSE_GUI
- // These three lines close the open file descriptors to to avoid any
+ // These lines close the open file descriptors to to avoid any
// input/output which might block the process or irritate the user. If
- // one wants proper IO for the subprocess, the right thing to do is
- // to start an xterm executing it.
- if (sync == 0)
+ // one wants proper IO for the subprocess, the right thing to do is to
+ // start an xterm executing it.
+ if ( !sync )
{
- // leave stderr opened, it won't do any hurm
for ( int fd = 0; fd < FD_SETSIZE; fd++ )
{
+ if ( fd == pipeIn[0] || fd == pipeOut[1]
#if wxUSE_GUI
- if ( fd == end_proc_detect[1] || fd == in_pipe[0] || fd == out_pipe[1] )
- continue;
+ || fd == end_proc_detect[1]
#endif // wxUSE_GUI
+ )
+ {
+ // don't close this one, we still need it
+ continue;
+ }
+ // leave stderr opened too, it won't do any hurm
if ( fd != STDERR_FILENO )
close(fd);
}
}
- // Fake a console by duplicating pipes
-#if wxUSE_GUI
- if (in_pipe[0] != -1) {
- dup2(in_pipe[0], STDIN_FILENO);
- dup2(out_pipe[1], STDOUT_FILENO);
- close(in_pipe[0]);
- close(out_pipe[1]);
- }
-#endif // wxUSE_GUI
-
-#if 0
- close(STDERR_FILENO);
+ // redirect stdio and stdout
+ // (TODO: what about stderr?)
+ if ( pipeIn[0] != -1 )
+ {
+ if ( dup2(pipeIn[0], STDIN_FILENO) == -1 ||
+ dup2(pipeOut[1], STDOUT_FILENO) == -1 )
+ {
+ wxLogSysError(_("Failed to redirect child process "
+ "input/output"));
+ }
- // some programs complain about stderr not being open, so redirect
- // them:
- open("/dev/null", O_RDONLY); // stdin
- open("/dev/null", O_WRONLY); // stdout
- open("/dev/null", O_WRONLY); // stderr
-#endif
+ close(pipeIn[0]);
+ close(pipeOut[1]);
+ }
execvp (*mb_argv, mb_argv);
// there is no return after successful exec()
- wxFprintf(stderr, _("Can't execute '%s'\n"), *argv);
-
_exit(-1);
}
- else
+ else // we're in parent
{
+ ARGS_CLEANUP;
+
+ // pipe initialization: construction of the wxStreams
+ if ( process && process->IsRedirected() )
+ {
+ // These two streams are relative to this process.
+ wxOutputStream *outStream = new wxProcessFileOutputStream(pipeIn[1]);
+ wxInputStream *inStream = new wxProcessFileInputStream(pipeOut[0]);
+ close(pipeIn[0]); // close reading side
+ close(pipeOut[1]); // close writing side
+
+ process->SetPipeStreams(inStream, outStream);
+ }
+
#if wxUSE_GUI
wxEndProcessData *data = new wxEndProcessData;
- ARGS_CLEANUP;
-
if ( sync )
{
- wxASSERT_MSG( !process, wxT("wxProcess param ignored for sync exec") );
+ // we may have process for capturing the program output, but it's
+ // not used in wxEndProcessData in the case of sync execution
data->process = NULL;
// sync execution: indicate it by negating the pid
- data->pid = -pid;
- data->tag = wxAddProcessCallback(data, end_proc_detect[0]);
- // we're in parent
+ data->pid = -pid;
+ data->tag = wxAddProcessCallback(data, end_proc_detect[0]);
+
close(end_proc_detect[1]); // close writing side
+ wxBusyCursor bc;
+ wxWindowDisabler wd;
+
// it will be set to 0 from GTK_EndProcessDetector
while (data->pid != 0)
wxYield();
return exitcode;
}
- else
+ else // async execution
{
- // pipe initialization: construction of the wxStreams
- if (process && process->NeedPipe()) {
- // These two streams are relative to this process.
- wxOutputStream *my_output_stream;
- wxInputStream *my_input_stream;
-
- my_output_stream = new wxProcessFileOutputStream(in_pipe[1]);
- my_input_stream = new wxProcessFileInputStream(out_pipe[0]);
- close(in_pipe[0]); // close reading side
- close(out_pipe[1]); // close writing side
-
- process->SetPipeStreams(my_input_stream, my_output_stream);
- }
-
// async execution, nothing special to do - caller will be
// notified about the process termination if process != NULL, data
// will be deleted in GTK_EndProcessDetector
data->process = process;
data->pid = pid;
data->tag = wxAddProcessCallback(data, end_proc_detect[0]);
- // we're in parent
+
close(end_proc_detect[1]); // close writing side
return pid;
return exitcode;
#endif // wxUSE_GUI
}
- return 0;
+
+ return 0;
#undef ARGS_CLEANUP
}