X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/749bfe9a6de1187def2b26c0cbbb249c1548c1ac..e7492fa205a0a8a548aa437629636a42269c7b88:/samples/exec/exec.cpp diff --git a/samples/exec/exec.cpp b/samples/exec/exec.cpp index 0a08de9af5..aa86ac198f 100644 --- a/samples/exec/exec.cpp +++ b/samples/exec/exec.cpp @@ -17,11 +17,6 @@ // headers // ---------------------------------------------------------------------------- -#if defined(__GNUG__) && !defined(__APPLE__) - #pragma implementation "exec.cpp" - #pragma interface "exec.cpp" -#endif - // For compilers that support precompilation, includes "wx/wx.h". #include "wx/wxprec.h" @@ -56,7 +51,9 @@ #include "wx/txtstrm.h" #include "wx/numdlg.h" +#include "wx/textdlg.h" #include "wx/ffile.h" +#include "wx/stopwatch.h" #include "wx/process.h" @@ -85,14 +82,18 @@ public: // Define an array of process pointers used by MyFrame class MyPipedProcess; -WX_DEFINE_ARRAY_PTR(MyPipedProcess *, MyProcessesArray); +WX_DEFINE_ARRAY_PTR(MyPipedProcess *, MyPipedProcessesArray); + +class MyProcess; +WX_DEFINE_ARRAY_PTR(MyProcess *, MyProcessesArray); // Define a new frame type: this is going to be our main frame class MyFrame : public wxFrame { public: - // ctor(s) + // ctor and dtor MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size); + virtual ~MyFrame(); // event handlers (these functions should _not_ be virtual) void OnQuit(wxCommandEvent& event); @@ -101,7 +102,11 @@ public: void OnClear(wxCommandEvent& event); + void OnBeginBusyCursor(wxCommandEvent& event); + void OnEndBusyCursor(wxCommandEvent& event); + void OnSyncExec(wxCommandEvent& event); + void OnSyncNoEventsExec(wxCommandEvent& event); void OnAsyncExec(wxCommandEvent& event); void OnShell(wxCommandEvent& event); void OnExecWithRedirect(wxCommandEvent& event); @@ -110,6 +115,8 @@ public: void OnPOpen(wxCommandEvent& event); void OnFileExec(wxCommandEvent& event); + void OnFileLaunch(wxCommandEvent& event); + void OnOpenURL(wxCommandEvent& event); void OnAbout(wxCommandEvent& event); @@ -121,6 +128,9 @@ public: void OnProcessTerminated(MyPipedProcess *process); wxListBox *GetLogListBox() const { return m_lbox; } + // for MyProcess + void OnAsyncTermination(MyProcess *process); + private: void ShowOutput(const wxString& cmd, const wxArrayString& output, @@ -128,30 +138,11 @@ 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 AddAsyncProcess(MyProcess *process) { m_allAsync.push_back(process); } - void RemoveAsyncProcess(MyPipedProcess *process) - { - m_running.Remove(process); + void AddPipedProcess(MyPipedProcess *process); + void RemovePipedProcess(MyPipedProcess *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 long m_pidLast; @@ -173,7 +164,11 @@ private: wxListBox *m_lbox; - MyProcessesArray m_running; + // array of running processes with redirected IO + MyPipedProcessesArray m_running; + + // array of all asynchrously running processes + MyProcessesArray m_allAsync; // the idle event wake up timer wxTimer m_timerIdleWakeUp; @@ -302,11 +297,16 @@ enum Exec_Quit = 100, Exec_Kill, Exec_ClearLog, + Exec_BeginBusyCursor, + Exec_EndBusyCursor, Exec_SyncExec = 200, + Exec_SyncNoEventsExec, Exec_AsyncExec, Exec_Shell, Exec_POpen, Exec_OpenFile, + Exec_LaunchFile, + Exec_OpenURL, Exec_DDEExec, Exec_DDERequest, Exec_Redirect, @@ -333,8 +333,11 @@ BEGIN_EVENT_TABLE(MyFrame, wxFrame) EVT_MENU(Exec_Quit, MyFrame::OnQuit) EVT_MENU(Exec_Kill, MyFrame::OnKill) EVT_MENU(Exec_ClearLog, MyFrame::OnClear) + EVT_MENU(Exec_BeginBusyCursor, MyFrame::OnBeginBusyCursor) + EVT_MENU(Exec_EndBusyCursor, MyFrame::OnEndBusyCursor) EVT_MENU(Exec_SyncExec, MyFrame::OnSyncExec) + EVT_MENU(Exec_SyncNoEventsExec, MyFrame::OnSyncNoEventsExec) EVT_MENU(Exec_AsyncExec, MyFrame::OnAsyncExec) EVT_MENU(Exec_Shell, MyFrame::OnShell) EVT_MENU(Exec_Redirect, MyFrame::OnExecWithRedirect) @@ -343,6 +346,8 @@ BEGIN_EVENT_TABLE(MyFrame, wxFrame) EVT_MENU(Exec_POpen, MyFrame::OnPOpen) EVT_MENU(Exec_OpenFile, MyFrame::OnFileExec) + EVT_MENU(Exec_LaunchFile, MyFrame::OnFileLaunch) + EVT_MENU(Exec_OpenURL, MyFrame::OnOpenURL) #ifdef __WINDOWS__ EVT_MENU(Exec_DDEExec, MyFrame::OnDDEExec) @@ -387,6 +392,9 @@ IMPLEMENT_APP(MyApp) // `Main program' equivalent: the program execution "starts" here bool MyApp::OnInit() { + if ( !wxApp::OnInit() ) + return false; + // Create the main application window MyFrame *frame = new MyFrame(_T("Exec wxWidgets sample"), wxDefaultPosition, wxSize(500, 140)); @@ -423,18 +431,23 @@ MyFrame::MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size) #endif // create a menu bar - wxMenu *menuFile = new wxMenu(_T(""), wxMENU_TEAROFF); + wxMenu *menuFile = new wxMenu(wxEmptyString, wxMENU_TEAROFF); menuFile->Append(Exec_Kill, _T("&Kill process...\tCtrl-K"), _T("Kill a process by PID")); menuFile->AppendSeparator(); - menuFile->Append(Exec_ClearLog, _T("&Clear log\tCtrl-C"), + menuFile->Append(Exec_ClearLog, _T("&Clear log\tCtrl-L"), _T("Clear the log window")); menuFile->AppendSeparator(); + menuFile->Append(Exec_BeginBusyCursor, _T("Show &busy cursor\tCtrl-C")); + menuFile->Append(Exec_EndBusyCursor, _T("Show &normal cursor\tShift-Ctrl-C")); + menuFile->AppendSeparator(); menuFile->Append(Exec_Quit, _T("E&xit\tAlt-X"), _T("Quit this program")); wxMenu *execMenu = new wxMenu; execMenu->Append(Exec_SyncExec, _T("Sync &execution...\tCtrl-E"), _T("Launch a program and return when it terminates")); + execMenu->Append(Exec_SyncNoEventsExec, _T("Sync execution and &block...\tCtrl-B"), + _T("Launch a program and block until it terminates")); execMenu->Append(Exec_AsyncExec, _T("&Async execution...\tCtrl-A"), _T("Launch a program and return immediately")); execMenu->Append(Exec_Shell, _T("Execute &shell command...\tCtrl-S"), @@ -450,13 +463,17 @@ MyFrame::MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size) execMenu->AppendSeparator(); execMenu->Append(Exec_OpenFile, _T("Open &file...\tCtrl-F"), _T("Launch the command to open this kind of files")); + execMenu->Append(Exec_LaunchFile, _T("La&unch file...\tShift-Ctrl-F"), + _T("Launch the default application associated with the file")); + execMenu->Append(Exec_OpenURL, _T("Open &URL...\tCtrl-U"), + _T("Launch the default browser with the given URL")); #ifdef __WINDOWS__ execMenu->AppendSeparator(); execMenu->Append(Exec_DDEExec, _T("Execute command via &DDE...\tCtrl-D")); execMenu->Append(Exec_DDERequest, _T("Send DDE &request...\tCtrl-R")); #endif - wxMenu *helpMenu = new wxMenu(_T(""), wxMENU_TEAROFF); + wxMenu *helpMenu = new wxMenu(wxEmptyString, wxMENU_TEAROFF); helpMenu->Append(Exec_About, _T("&About...\tF1"), _T("Show about dialog")); // now append the freshly created menu to the menu bar... @@ -482,6 +499,17 @@ MyFrame::MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size) #endif // wxUSE_STATUSBAR } +MyFrame::~MyFrame() +{ + // any processes left until now must be deleted manually: normally this is + // done when the associated process terminates but it must be still running + // if this didn't happen until now + for ( size_t n = 0; n < m_allAsync.size(); n++ ) + { + delete m_allAsync[n]; + } +} + // ---------------------------------------------------------------------------- // event handlers: file and help menu // ---------------------------------------------------------------------------- @@ -497,6 +525,16 @@ void MyFrame::OnClear(wxCommandEvent& WXUNUSED(event)) m_lbox->Clear(); } +void MyFrame::OnBeginBusyCursor(wxCommandEvent& WXUNUSED(event)) +{ + wxBeginBusyCursor(); +} + +void MyFrame::OnEndBusyCursor(wxCommandEvent& WXUNUSED(event)) +{ + wxEndBusyCursor(); +} + void MyFrame::OnAbout(wxCommandEvent& WXUNUSED(event)) { wxMessageBox(_T("Exec wxWidgets Sample\n(c) 2000-2002 Vadim Zeitlin"), @@ -608,20 +646,23 @@ void MyFrame::OnKill(wxCommandEvent& WXUNUSED(event)) void MyFrame::DoAsyncExec(const wxString& cmd) { - wxProcess *process = new MyProcess(this, cmd); + MyProcess * const process = new MyProcess(this, 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; + + // the parent frame keeps track of all async processes as it needs to + // free them if we exit before the child process terminates + AddAsyncProcess(process); } } @@ -644,6 +685,25 @@ void MyFrame::OnSyncExec(wxCommandEvent& WXUNUSED(event)) m_cmdLast = cmd; } +void MyFrame::OnSyncNoEventsExec(wxCommandEvent& WXUNUSED(event)) +{ + wxString cmd = wxGetTextFromUser(_T("Enter the command: "), + DIALOG_TITLE, + m_cmdLast); + + if ( !cmd ) + return; + + wxLogStatus( _T("'%s' is running please wait..."), cmd.c_str() ); + + int code = wxExecute(cmd, wxEXEC_BLOCK); + + wxLogStatus(_T("Process '%s' terminated with exit code %d."), + cmd.c_str(), code); + + m_cmdLast = cmd; +} + void MyFrame::OnAsyncExec(wxCommandEvent& WXUNUSED(event)) { wxString cmd = wxGetTextFromUser(_T("Enter the command: "), @@ -673,6 +733,15 @@ void MyFrame::OnShell(wxCommandEvent& WXUNUSED(event)) void MyFrame::OnExecWithRedirect(wxCommandEvent& WXUNUSED(event)) { + if ( !m_cmdLast ) + { +#ifdef __WXMSW__ + m_cmdLast = "type Makefile.in"; +#else + m_cmdLast = "cat -n Makefile"; +#endif + } + wxString cmd = wxGetTextFromUser(_T("Enter the command: "), DIALOG_TITLE, m_cmdLast); @@ -699,10 +768,15 @@ void MyFrame::OnExecWithRedirect(wxCommandEvent& WXUNUSED(event)) if ( sync ) { + wxLogStatus("\"%s\" is running please wait...", cmd); + + wxStopWatch sw; + wxArrayString output, errors; int code = wxExecute(cmd, output, errors); - wxLogStatus(_T("command '%s' terminated with exit code %d."), - cmd.c_str(), code); + + wxLogStatus("Command \"%s\" terminated after %ldms; exit code %d.", + cmd, sw.Time(), code); if ( code != -1 ) { @@ -721,7 +795,7 @@ void MyFrame::OnExecWithRedirect(wxCommandEvent& WXUNUSED(event)) } else { - AddAsyncProcess(process); + AddPipedProcess(process); } } @@ -750,9 +824,9 @@ void MyFrame::OnExecWithPipe(wxCommandEvent& WXUNUSED(event)) 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()); - AddAsyncProcess(process); + AddPipedProcess(process); } else { @@ -779,6 +853,8 @@ void MyFrame::OnPOpen(wxCommandEvent& WXUNUSED(event)) return; } + wxLogVerbose(_T("PID of the new process: %ld"), process->GetPid()); + wxOutputStream *out = process->GetOutputStream(); if ( !out ) { @@ -796,17 +872,33 @@ void MyFrame::OnPOpen(wxCommandEvent& WXUNUSED(event)) new MyPipeFrame(this, cmd, process); } -void MyFrame::OnFileExec(wxCommandEvent& WXUNUSED(event)) +static wxString gs_lastFile; + +static bool AskUserForFileName() { - static wxString s_filename; + wxString filename; - wxString filename = wxLoadFileSelector(_T(""), _T(""), s_filename); - if ( !filename ) - return; +#if wxUSE_FILEDLG + filename = wxLoadFileSelector(_T("any"), wxEmptyString, gs_lastFile); +#else // !wxUSE_FILEDLG + filename = wxGetTextFromUser(_T("Enter the file name"), _T("exec sample"), + gs_lastFile); +#endif // wxUSE_FILEDLG/!wxUSE_FILEDLG + + if ( filename.empty() ) + return false; - s_filename = filename; + gs_lastFile = filename; - wxString ext = filename.AfterFirst(_T('.')); + return true; +} + +void MyFrame::OnFileExec(wxCommandEvent& WXUNUSED(event)) +{ + if ( !AskUserForFileName() ) + return; + + wxString ext = gs_lastFile.AfterLast(_T('.')); wxFileType *ft = wxTheMimeTypesManager->GetFileTypeFromExtension(ext); if ( !ft ) { @@ -817,7 +909,7 @@ void MyFrame::OnFileExec(wxCommandEvent& WXUNUSED(event)) wxString cmd; bool ok = ft->GetOpenCommand(&cmd, - wxFileType::MessageParameters(filename, _T(""))); + wxFileType::MessageParameters(gs_lastFile)); delete ft; if ( !ok ) { @@ -829,6 +921,38 @@ void MyFrame::OnFileExec(wxCommandEvent& WXUNUSED(event)) DoAsyncExec(cmd); } +void MyFrame::OnFileLaunch(wxCommandEvent& WXUNUSED(event)) +{ + if ( !AskUserForFileName() ) + return; + + if ( !wxLaunchDefaultApplication(gs_lastFile) ) + { + wxLogError("Opening \"%s\" in default application failed.", gs_lastFile); + } +} + +void MyFrame::OnOpenURL(wxCommandEvent& WXUNUSED(event)) +{ + static wxString s_url(_T("http://www.wxwidgets.org/")); + + wxString filename = wxGetTextFromUser + ( + _T("Enter the URL"), + _T("exec sample"), + s_url, + this + ); + + if ( filename.empty() ) + return; + + s_url = filename; + + if ( !wxLaunchDefaultBrowser(s_url) ) + wxLogError(_T("Failed to open URL \"%s\""), s_url.c_str()); +} + // ---------------------------------------------------------------------------- // DDE stuff // ---------------------------------------------------------------------------- @@ -865,7 +989,7 @@ void MyFrame::OnDDEExec(wxCommandEvent& WXUNUSED(event)) return; wxDDEClient client; - wxConnectionBase *conn = client.MakeConnection(_T(""), m_server, m_topic); + wxConnectionBase *conn = client.MakeConnection(wxEmptyString, m_server, m_topic); if ( !conn ) { wxLogError(_T("Failed to connect to the DDE server '%s'."), @@ -891,7 +1015,7 @@ void MyFrame::OnDDERequest(wxCommandEvent& WXUNUSED(event)) return; wxDDEClient client; - wxConnectionBase *conn = client.MakeConnection(_T(""), m_server, m_topic); + wxConnectionBase *conn = client.MakeConnection(wxEmptyString, m_server, m_topic); if ( !conn ) { wxLogError(_T("Failed to connect to the DDE server '%s'."), @@ -937,9 +1061,41 @@ void MyFrame::OnTimer(wxTimerEvent& WXUNUSED(event)) void MyFrame::OnProcessTerminated(MyPipedProcess *process) { - RemoveAsyncProcess(process); + RemovePipedProcess(process); } +void MyFrame::OnAsyncTermination(MyProcess *process) +{ + m_allAsync.Remove(process); + + delete process; +} + +void MyFrame::AddPipedProcess(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); + m_allAsync.Add(process); +} + +void MyFrame::RemovePipedProcess(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(); + } +} void MyFrame::ShowOutput(const wxString& cmd, const wxArrayString& output, @@ -970,8 +1126,7 @@ void MyProcess::OnTerminate(int pid, int status) wxLogStatus(m_parent, _T("Process %u ('%s') terminated with exit code %d."), pid, m_cmd.c_str(), status); - // we're not needed any more - delete this; + m_parent->OnAsyncTermination(this); } // ---------------------------------------------------------------------------- @@ -1028,7 +1183,7 @@ void MyPipedProcess::OnTerminate(int pid, int status) bool MyPipedProcess2::HasInput() { - if ( !!m_input ) + if ( !m_input.empty() ) { wxTextOutputStream os(*GetOutputStream()); os.WriteString(m_input); @@ -1061,14 +1216,14 @@ MyPipeFrame::MyPipeFrame(wxFrame *parent, wxPanel *panel = new wxPanel(this, wxID_ANY); - m_textOut = new wxTextCtrl(panel, wxID_ANY, _T(""), + m_textOut = new wxTextCtrl(panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_PROCESS_ENTER); - m_textIn = new wxTextCtrl(panel, wxID_ANY, _T(""), + m_textIn = new wxTextCtrl(panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_MULTILINE | wxTE_RICH); m_textIn->SetEditable(false); - m_textErr = new wxTextCtrl(panel, wxID_ANY, _T(""), + m_textErr = new wxTextCtrl(panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_MULTILINE | wxTE_RICH); m_textErr->SetEditable(false); @@ -1098,6 +1253,7 @@ MyPipeFrame::MyPipeFrame(wxFrame *parent, void MyPipeFrame::OnBtnSendFile(wxCommandEvent& WXUNUSED(event)) { +#if wxUSE_FILEDLG wxFileDialog filedlg(this, _T("Select file to send")); if ( filedlg.ShowModal() != wxID_OK ) return; @@ -1125,6 +1281,7 @@ void MyPipeFrame::OnBtnSendFile(wxCommandEvent& WXUNUSED(event)) DoGet(); } +#endif // wxUSE_FILEDLG } void MyPipeFrame::DoGet()