X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/eb671557a8ff1d3b607dcffd00bc4d4e6e8d93eb..3682ea7d2cafc2cbb3f9093e0f864dfff54327dd:/samples/exec/exec.cpp diff --git a/samples/exec/exec.cpp b/samples/exec/exec.cpp index 7791cc1801..50f2a1acb3 100644 --- a/samples/exec/exec.cpp +++ b/samples/exec/exec.cpp @@ -17,7 +17,7 @@ // headers // ---------------------------------------------------------------------------- -#ifdef __GNUG__ +#if defined(__GNUG__) && !defined(__APPLE__) #pragma implementation "exec.cpp" #pragma interface "exec.cpp" #endif @@ -33,7 +33,11 @@ // need because it includes almost all "standard" wxWindows headers #ifndef WX_PRECOMP #include "wx/app.h" + #include "wx/log.h" #include "wx/frame.h" + #include "wx/panel.h" + + #include "wx/timer.h" #include "wx/utils.h" #include "wx/menu.h" @@ -79,7 +83,7 @@ public: // Define an array of process pointers used by MyFrame class MyPipedProcess; -WX_DEFINE_ARRAY(MyPipedProcess *, MyProcessesArray); +WX_DEFINE_ARRAY_NO_PTR(MyPipedProcess *, MyProcessesArray); // Define a new frame type: this is going to be our main frame class MyFrame : public wxFrame @@ -108,6 +112,7 @@ public: void OnAbout(wxCommandEvent& event); // polling output of async processes + void OnTimer(wxTimerEvent& event); void OnIdle(wxIdleEvent& event); // for MyPipedProcess @@ -121,8 +126,33 @@ private: void DoAsyncExec(const wxString& cmd); + void AddAsyncProcess(MyPipedProcess *process) + { + if ( m_running.IsEmpty() ) + { + // we want to start getting the timer events to ensure that a + // steady stream of idle events comes in -- otherwise we + // wouldn't be able to poll the child process input + m_timerIdleWakeUp.Start(100); + } + //else: the timer is already running + + m_running.Add(process); + } + + void RemoveAsyncProcess(MyPipedProcess *process) + { + m_running.Remove(process); + + if ( m_running.IsEmpty() ) + { + // we don't need to get idle events all the time any more + m_timerIdleWakeUp.Stop(); + } + } + // the PID of the last process we launched asynchronously - int m_pidLast; + long m_pidLast; // last command we executed wxString m_cmdLast; @@ -143,6 +173,9 @@ private: MyProcessesArray m_running; + // the idle event wake up timer + wxTimer m_timerIdleWakeUp; + // any class wishing to process wxWindows events must use this macro DECLARE_EVENT_TABLE() }; @@ -165,7 +198,16 @@ protected: void OnClose(wxCloseEvent& event); - void DoSend() { m_out.WriteString(m_textIn->GetValue() + '\n'); DoGet(); } + void OnProcessTerm(wxProcessEvent& event); + + void DoSend() + { + m_out.WriteString(m_textIn->GetValue() + _T('\n')); + m_textIn->Clear(); + + DoGet(); + } + void DoGet(); private: @@ -294,6 +336,8 @@ BEGIN_EVENT_TABLE(MyFrame, wxFrame) EVT_MENU(Exec_About, MyFrame::OnAbout) EVT_IDLE(MyFrame::OnIdle) + + EVT_TIMER(-1, MyFrame::OnTimer) END_EVENT_TABLE() BEGIN_EVENT_TABLE(MyPipeFrame, wxFrame) @@ -303,6 +347,8 @@ BEGIN_EVENT_TABLE(MyPipeFrame, wxFrame) EVT_TEXT_ENTER(-1, MyPipeFrame::OnTextEnter) EVT_CLOSE(MyPipeFrame::OnClose) + + EVT_END_PROCESS(-1, MyPipeFrame::OnProcessTerm) END_EVENT_TABLE() // Create a new application object: this macro will allow wxWindows to create @@ -341,9 +387,14 @@ bool MyApp::OnInit() // main frame // ---------------------------------------------------------------------------- +#ifdef __VISUALC__ +#pragma warning(disable: 4355) // this used in base member initializer list +#endif + // frame constructor MyFrame::MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size) - : wxFrame((wxFrame *)NULL, -1, title, pos, size) + : wxFrame((wxFrame *)NULL, -1, title, pos, size), + m_timerIdleWakeUp(this) { m_pidLast = 0; @@ -430,7 +481,7 @@ void MyFrame::OnClear(wxCommandEvent& WXUNUSED(event)) void MyFrame::OnAbout(wxCommandEvent& WXUNUSED(event)) { - wxMessageBox(_T("Exec wxWindows Sample\n© 2000-2001 Vadim Zeitlin"), + wxMessageBox(_T("Exec wxWindows Sample\n© 2000-2002 Vadim Zeitlin"), _T("About Exec"), wxOK | wxICON_INFORMATION, this); } @@ -505,16 +556,16 @@ void MyFrame::OnKill(wxCommandEvent& WXUNUSED(event)) if ( sig == 0 ) { if ( wxProcess::Exists(pid) ) - wxLogStatus(_T("Process %d is running."), pid); + wxLogStatus(_T("Process %ld is running."), pid); else - wxLogStatus(_T("No process with pid = %d."), pid); + wxLogStatus(_T("No process with pid = %ld."), pid); } else // not SIGNONE { wxKillError rc = wxProcess::Kill(pid, (wxSignal)sig); if ( rc == wxKILL_OK ) { - wxLogStatus(_T("Process %d killed with signal %d."), pid, sig); + wxLogStatus(_T("Process %ld killed with signal %d."), pid, sig); } else { @@ -527,7 +578,7 @@ void MyFrame::OnKill(wxCommandEvent& WXUNUSED(event)) _T("unspecified error"), }; - wxLogStatus(_T("Failed to kill process %d with signal %d: %s"), + wxLogStatus(_T("Failed to kill process %ld with signal %d: %s"), pid, sig, errorText[rc]); } } @@ -543,13 +594,14 @@ void MyFrame::DoAsyncExec(const wxString& cmd) m_pidLast = wxExecute(cmd, wxEXEC_ASYNC, process); if ( !m_pidLast ) { - wxLogError(_T("Execution of '%s' failed."), cmd.c_str()); + wxLogError( _T("Execution of '%s' failed."), cmd.c_str() ); delete process; } else { - wxLogStatus(_T("Process %ld (%s) launched."), m_pidLast, cmd.c_str()); + wxLogStatus( _T("Process %ld (%s) launched."), + m_pidLast, cmd.c_str() ); m_cmdLast = cmd; } @@ -564,12 +616,13 @@ void MyFrame::OnSyncExec(wxCommandEvent& WXUNUSED(event)) if ( !cmd ) return; - wxLogStatus(_T("'%s' is running please wait..."), cmd.c_str()); + wxLogStatus( _T("'%s' is running please wait..."), cmd.c_str() ); int code = wxExecute(cmd, wxEXEC_SYNC); wxLogStatus(_T("Process '%s' terminated with exit code %d."), - cmd.c_str(), code); + cmd.c_str(), code); + m_cmdLast = cmd; } @@ -650,7 +703,7 @@ void MyFrame::OnExecWithRedirect(wxCommandEvent& WXUNUSED(event)) } else { - m_running.Add(process); + AddAsyncProcess(process); } } @@ -676,12 +729,12 @@ void MyFrame::OnExecWithPipe(wxCommandEvent& WXUNUSED(event)) // always execute the filter asynchronously MyPipedProcess2 *process = new MyPipedProcess2(this, cmd, input); - int pid = wxExecute(cmd, wxEXEC_ASYNC, process); + long pid = wxExecute(cmd, wxEXEC_ASYNC, process); if ( pid ) { - wxLogStatus(_T("Process %ld (%s) launched."), pid, cmd.c_str()); + wxLogStatus( _T("Process %ld (%s) launched."), pid, cmd.c_str() ); - m_running.Add(process); + AddAsyncProcess(process); } else { @@ -693,7 +746,7 @@ void MyFrame::OnExecWithPipe(wxCommandEvent& WXUNUSED(event)) m_cmdLast = cmd; } -void MyFrame::OnPOpen(wxCommandEvent& event) +void MyFrame::OnPOpen(wxCommandEvent& WXUNUSED(event)) { wxString cmd = wxGetTextFromUser(_T("Enter the command to launch: "), DIALOG_TITLE, @@ -725,7 +778,7 @@ void MyFrame::OnPOpen(wxCommandEvent& event) new MyPipeFrame(this, cmd, process); } -void MyFrame::OnFileExec(wxCommandEvent& event) +void MyFrame::OnFileExec(wxCommandEvent& WXUNUSED(event)) { static wxString s_filename; @@ -794,7 +847,7 @@ void MyFrame::OnDDEExec(wxCommandEvent& WXUNUSED(event)) return; wxDDEClient client; - wxConnectionBase *conn = client.MakeConnection("", m_server, m_topic); + wxConnectionBase *conn = client.MakeConnection(_T(""), m_server, m_topic); if ( !conn ) { wxLogError(_T("Failed to connect to the DDE server '%s'."), @@ -820,7 +873,7 @@ void MyFrame::OnDDERequest(wxCommandEvent& WXUNUSED(event)) return; wxDDEClient client; - wxConnectionBase *conn = client.MakeConnection("", m_server, m_topic); + wxConnectionBase *conn = client.MakeConnection(_T(""), m_server, m_topic); if ( !conn ) { wxLogError(_T("Failed to connect to the DDE server '%s'."), @@ -859,9 +912,14 @@ void MyFrame::OnIdle(wxIdleEvent& event) } } +void MyFrame::OnTimer(wxTimerEvent& WXUNUSED(event)) +{ + wxWakeUpIdle(); +} + void MyFrame::OnProcessTerminated(MyPipedProcess *process) { - m_running.Remove(process); + RemoveAsyncProcess(process); } @@ -906,10 +964,9 @@ bool MyPipedProcess::HasInput() { bool hasInput = FALSE; - wxInputStream& is = *GetInputStream(); - if ( !is.Eof() ) + if ( IsInputAvailable() ) { - wxTextInputStream tis(is); + wxTextInputStream tis(*GetInputStream()); // this assumes that the output is always line buffered wxString msg; @@ -920,10 +977,9 @@ bool MyPipedProcess::HasInput() hasInput = TRUE; } - wxInputStream& es = *GetErrorStream(); - if ( !es.Eof() ) + if ( IsErrorAvailable() ) { - wxTextInputStream tis(es); + wxTextInputStream tis(*GetErrorStream()); // this assumes that the output is always line buffered wxString msg; @@ -982,25 +1038,29 @@ MyPipeFrame::MyPipeFrame(wxFrame *parent, m_in(*process->GetInputStream()), m_out(*process->GetOutputStream()) { - m_textIn = new wxTextCtrl(this, -1, _T(""), + m_process->SetNextHandler(this); + + wxPanel *panel = new wxPanel(this, -1); + + m_textIn = new wxTextCtrl(panel, -1, _T(""), wxDefaultPosition, wxDefaultSize, wxTE_PROCESS_ENTER); - m_textOut = new wxTextCtrl(this, -1, _T("")); + m_textOut = new wxTextCtrl(panel, -1, _T("")); m_textOut->SetEditable(FALSE); wxSizer *sizerTop = new wxBoxSizer(wxVERTICAL); sizerTop->Add(m_textIn, 0, wxGROW | wxALL, 5); wxSizer *sizerBtns = new wxBoxSizer(wxHORIZONTAL); - sizerBtns->Add(new wxButton(this, Exec_Btn_Send, _T("&Send")), 0, + sizerBtns->Add(new wxButton(panel, Exec_Btn_Send, _T("&Send")), 0, wxALL, 10); - sizerBtns->Add(new wxButton(this, Exec_Btn_Get, _T("&Get")), 0, + sizerBtns->Add(new wxButton(panel, Exec_Btn_Get, _T("&Get")), 0, wxALL, 10); sizerTop->Add(sizerBtns, 0, wxCENTRE | wxALL, 5); sizerTop->Add(m_textOut, 0, wxGROW | wxALL, 5); - SetSizer(sizerTop); + panel->SetSizer(sizerTop); sizerTop->Fit(this); Show(); @@ -1008,13 +1068,40 @@ MyPipeFrame::MyPipeFrame(wxFrame *parent, void MyPipeFrame::DoGet() { + // we don't have any way to be notified when any input appears on the + // stream so we have to poll it :-( + // + // NB: this really must be done because otherwise the other program might + // not have enough time to receive or process our data and we'd read + // an empty string + while ( !m_process->IsInputAvailable() && m_process->IsInputOpened() ) + ; + m_textOut->SetValue(m_in.ReadLine()); } void MyPipeFrame::OnClose(wxCloseEvent& event) { - m_process->CloseOutput(); + if ( m_process ) + { + // we're not interested in getting the process termination notification + // if we are closing it ourselves + wxProcess *process = m_process; + m_process = NULL; + process->SetNextHandler(NULL); + + process->CloseOutput(); + } event.Skip(); } +void MyPipeFrame::OnProcessTerm(wxProcessEvent& WXUNUSED(event)) +{ + delete m_process; + m_process = NULL; + + wxLogWarning(_T("The other process has terminated, closing")); + + Close(); +}