#include "wx/choicdlg.h"
#include "wx/button.h"
+ #include "wx/checkbox.h"
+ #include "wx/stattext.h"
#include "wx/textctrl.h"
#include "wx/listbox.h"
#include "wx/numdlg.h"
#include "wx/textdlg.h"
#include "wx/ffile.h"
+#include "wx/stopwatch.h"
#include "wx/process.h"
// 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);
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);
void OnPOpen(wxCommandEvent& event);
void OnFileExec(wxCommandEvent& event);
+ void OnFileLaunch(wxCommandEvent& event);
void OnOpenURL(wxCommandEvent& event);
void OnAbout(wxCommandEvent& event);
// polling output of async processes
- void OnTimer(wxTimerEvent& event);
+ void OnIdleTimer(wxTimerEvent& event);
void OnIdle(wxIdleEvent& event);
// for MyPipedProcess
void OnProcessTerminated(MyPipedProcess *process);
wxListBox *GetLogListBox() const { return m_lbox; }
+ // for MyProcess
+ void OnAsyncTermination(MyProcess *process);
+
+ // timer updating a counter in the background
+ void OnBgTimer(wxTimerEvent& event);
+
private:
void ShowOutput(const wxString& cmd,
const wxArrayString& output,
const wxString& title);
- void DoAsyncExec(const wxString& cmd);
+ int GetExecFlags() const;
- 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
+ void DoAsyncExec(const wxString& cmd);
- 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;
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;
+ // a background timer allowing to easily check visually whether the
+ // messages are processed or not
+ wxTimer m_timerBg;
+
// any class wishing to process wxWidgets events must use this macro
DECLARE_EVENT_TABLE()
};
void DoSend()
{
wxString s(m_textOut->GetValue());
- s += _T('\n');
+ s += wxT('\n');
m_out.Write(s.c_str(), s.length());
m_textOut->Clear();
// IDs for the controls and the menu commands
enum
{
+ // timer ids
+ Exec_TimerIdle = 10,
+ Exec_TimerBg,
+
// menu items
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,
Exec_Pipe,
- Exec_About = 300,
+ Exec_Flags_HideConsole,
+ Exec_Flags_ShowConsole,
+ Exec_Flags_NoEvents,
+ Exec_About = wxID_ABOUT,
// control ids
Exec_Btn_Send = 1000,
Exec_Btn_Close
};
-static const wxChar *DIALOG_TITLE = _T("Exec sample");
+static const wxChar *DIALOG_TITLE = wxT("Exec sample");
// ----------------------------------------------------------------------------
// event tables and other macros for wxWidgets
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)
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_IDLE(MyFrame::OnIdle)
- EVT_TIMER(wxID_ANY, MyFrame::OnTimer)
+ EVT_TIMER(Exec_TimerIdle, MyFrame::OnIdleTimer)
+ EVT_TIMER(Exec_TimerBg, MyFrame::OnBgTimer)
END_EVENT_TABLE()
BEGIN_EVENT_TABLE(MyPipeFrame, wxFrame)
return false;
// Create the main application window
- MyFrame *frame = new MyFrame(_T("Exec wxWidgets sample"),
+ MyFrame *frame = new MyFrame(wxT("Exec wxWidgets sample"),
wxDefaultPosition, wxSize(500, 140));
- // Show it and tell the application that it's our main window
+ // Show it
frame->Show(true);
- SetTopWindow(frame);
// success: wxApp::OnRun() will be called which will enter the main message
// loop and the application will run. If we returned false here, the
// frame constructor
MyFrame::MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size)
: wxFrame((wxFrame *)NULL, wxID_ANY, title, pos, size),
- m_timerIdleWakeUp(this)
+ m_timerIdleWakeUp(this, Exec_TimerIdle),
+ m_timerBg(this, Exec_TimerBg)
{
m_pidLast = 0;
// create a menu bar
wxMenu *menuFile = new wxMenu(wxEmptyString, wxMENU_TEAROFF);
- menuFile->Append(Exec_Kill, _T("&Kill process...\tCtrl-K"),
- _T("Kill a process by PID"));
+ menuFile->Append(Exec_Kill, wxT("&Kill process...\tCtrl-K"),
+ wxT("Kill a process by PID"));
menuFile->AppendSeparator();
- menuFile->Append(Exec_ClearLog, _T("&Clear log\tCtrl-C"),
- _T("Clear the log window"));
+ menuFile->Append(Exec_ClearLog, wxT("&Clear log\tCtrl-L"),
+ wxT("Clear the log window"));
menuFile->AppendSeparator();
- menuFile->Append(Exec_Quit, _T("E&xit\tAlt-X"), _T("Quit this program"));
+ menuFile->Append(Exec_BeginBusyCursor, wxT("Show &busy cursor\tCtrl-C"));
+ menuFile->Append(Exec_EndBusyCursor, wxT("Show &normal cursor\tShift-Ctrl-C"));
+ menuFile->AppendSeparator();
+ menuFile->Append(Exec_Quit, wxT("E&xit\tAlt-X"), wxT("Quit this program"));
+
+ wxMenu *flagsMenu = new wxMenu;
+ flagsMenu->AppendCheckItem(Exec_Flags_HideConsole, "Always &hide console");
+ flagsMenu->AppendCheckItem(Exec_Flags_ShowConsole, "Always &show console");
+ flagsMenu->AppendCheckItem(Exec_Flags_NoEvents, "Disable &events",
+ "This flag is valid for sync execution only");
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"),
- _T("Launch a shell and execute a command in it"));
+ execMenu->AppendSubMenu(flagsMenu, "Execution flags");
+ execMenu->AppendSeparator();
+ execMenu->Append(Exec_SyncExec, wxT("Sync &execution...\tCtrl-E"),
+ wxT("Launch a program and return when it terminates"));
+ execMenu->Append(Exec_AsyncExec, wxT("&Async execution...\tCtrl-A"),
+ wxT("Launch a program and return immediately"));
+ execMenu->Append(Exec_Shell, wxT("Execute &shell command...\tCtrl-S"),
+ wxT("Launch a shell and execute a command in it"));
execMenu->AppendSeparator();
- execMenu->Append(Exec_Redirect, _T("Capture command &output...\tCtrl-O"),
- _T("Launch a program and capture its output"));
- execMenu->Append(Exec_Pipe, _T("&Pipe through command..."),
- _T("Pipe a string through a filter"));
- execMenu->Append(Exec_POpen, _T("&Open a pipe to a command...\tCtrl-P"),
- _T("Open a pipe to and from another program"));
+ execMenu->Append(Exec_Redirect, wxT("Capture command &output...\tCtrl-O"),
+ wxT("Launch a program and capture its output"));
+ execMenu->Append(Exec_Pipe, wxT("&Pipe through command..."),
+ wxT("Pipe a string through a filter"));
+ execMenu->Append(Exec_POpen, wxT("&Open a pipe to a command...\tCtrl-P"),
+ wxT("Open a pipe to and from another program"));
execMenu->AppendSeparator();
- execMenu->Append(Exec_OpenFile, _T("Open &file...\tCtrl-F"),
- _T("Launch the command to open this kind of files"));
- execMenu->Append(Exec_OpenURL, _T("Open &URL...\tCtrl-U"),
- _T("Launch the default browser with the given URL"));
+ execMenu->Append(Exec_OpenFile, wxT("Open &file...\tCtrl-F"),
+ wxT("Launch the command to open this kind of files"));
+ execMenu->Append(Exec_LaunchFile, wxT("La&unch file...\tShift-Ctrl-F"),
+ wxT("Launch the default application associated with the file"));
+ execMenu->Append(Exec_OpenURL, wxT("Open &URL...\tCtrl-U"),
+ wxT("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"));
+ execMenu->Append(Exec_DDEExec, wxT("Execute command via &DDE...\tCtrl-D"));
+ execMenu->Append(Exec_DDERequest, wxT("Send DDE &request...\tCtrl-R"));
#endif
wxMenu *helpMenu = new wxMenu(wxEmptyString, wxMENU_TEAROFF);
- helpMenu->Append(Exec_About, _T("&About...\tF1"), _T("Show about dialog"));
+ helpMenu->Append(Exec_About, wxT("&About\tF1"), wxT("Show about dialog"));
// now append the freshly created menu to the menu bar...
wxMenuBar *menuBar = new wxMenuBar();
- menuBar->Append(menuFile, _T("&File"));
- menuBar->Append(execMenu, _T("&Exec"));
- menuBar->Append(helpMenu, _T("&Help"));
+ menuBar->Append(menuFile, wxT("&File"));
+ menuBar->Append(execMenu, wxT("&Exec"));
+ menuBar->Append(helpMenu, wxT("&Help"));
// ... and attach this menu bar to the frame
SetMenuBar(menuBar);
m_lbox = new wxListBox(this, wxID_ANY);
wxFont font(12, wxFONTFAMILY_TELETYPE, wxFONTSTYLE_NORMAL,
wxFONTWEIGHT_NORMAL);
- if ( font.Ok() )
+ if ( font.IsOk() )
m_lbox->SetFont(font);
#if wxUSE_STATUSBAR
// create a status bar just for fun (by default with 1 pane only)
- CreateStatusBar();
- SetStatusText(_T("Welcome to wxWidgets exec sample!"));
+ CreateStatusBar(2);
+ SetStatusText(wxT("Welcome to wxWidgets exec sample!"));
#endif // wxUSE_STATUSBAR
+
+ m_timerBg.Start(1000);
+}
+
+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];
+ }
}
// ----------------------------------------------------------------------------
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"),
- _T("About Exec"), wxOK | wxICON_INFORMATION, this);
+ wxMessageBox(wxT("Exec wxWidgets Sample\n(c) 2000-2002 Vadim Zeitlin"),
+ wxT("About Exec"), wxOK | wxICON_INFORMATION, this);
}
void MyFrame::OnKill(wxCommandEvent& WXUNUSED(event))
{
- long pid = wxGetNumberFromUser(_T("Please specify the process to kill"),
- _T("Enter PID:"),
- _T("Exec question"),
+ long pid = wxGetNumberFromUser(wxT("Please specify the process to kill"),
+ wxT("Enter PID:"),
+ wxT("Exec question"),
m_pidLast,
// we need the full unsigned int range
-INT_MAX, INT_MAX,
return;
}
+ m_pidLast = pid;
+
static const wxString signalNames[] =
{
- _T("Just test (SIGNONE)"),
- _T("Hangup (SIGHUP)"),
- _T("Interrupt (SIGINT)"),
- _T("Quit (SIGQUIT)"),
- _T("Illegal instruction (SIGILL)"),
- _T("Trap (SIGTRAP)"),
- _T("Abort (SIGABRT)"),
- _T("Emulated trap (SIGEMT)"),
- _T("FP exception (SIGFPE)"),
- _T("Kill (SIGKILL)"),
- _T("Bus (SIGBUS)"),
- _T("Segment violation (SIGSEGV)"),
- _T("System (SIGSYS)"),
- _T("Broken pipe (SIGPIPE)"),
- _T("Alarm (SIGALRM)"),
- _T("Terminate (SIGTERM)"),
+ wxT("Just test (SIGNONE)"),
+ wxT("Hangup (SIGHUP)"),
+ wxT("Interrupt (SIGINT)"),
+ wxT("Quit (SIGQUIT)"),
+ wxT("Illegal instruction (SIGILL)"),
+ wxT("Trap (SIGTRAP)"),
+ wxT("Abort (SIGABRT)"),
+ wxT("Emulated trap (SIGEMT)"),
+ wxT("FP exception (SIGFPE)"),
+ wxT("Kill (SIGKILL)"),
+ wxT("Bus (SIGBUS)"),
+ wxT("Segment violation (SIGSEGV)"),
+ wxT("System (SIGSYS)"),
+ wxT("Broken pipe (SIGPIPE)"),
+ wxT("Alarm (SIGALRM)"),
+ wxT("Terminate (SIGTERM)"),
};
- int sig = wxGetSingleChoiceIndex(_T("How to kill the process?"),
- _T("Exec question"),
+ static int s_sigLast = wxSIGNONE;
+ int sig = wxGetSingleChoiceIndex(wxT("How to kill the process?"),
+ wxT("Exec question"),
WXSIZEOF(signalNames), signalNames,
+ s_sigLast,
this);
switch ( sig )
{
default:
- wxFAIL_MSG( _T("unexpected return value") );
+ wxFAIL_MSG( wxT("unexpected return value") );
// fall through
case -1:
break;
}
- if ( sig == 0 )
+ s_sigLast = sig;
+
+ if ( sig == wxSIGNONE )
{
+ // This simply calls Kill(wxSIGNONE) but using it is more convenient.
if ( wxProcess::Exists(pid) )
- wxLogStatus(_T("Process %ld is running."), pid);
+ {
+ wxLogStatus(wxT("Process %ld is running."), pid);
+ }
else
- wxLogStatus(_T("No process with pid = %ld."), pid);
+ {
+ wxLogStatus(wxT("No process with pid = %ld."), pid);
+ }
}
else // not SIGNONE
{
wxKillError rc = wxProcess::Kill(pid, (wxSignal)sig);
if ( rc == wxKILL_OK )
{
- wxLogStatus(_T("Process %ld killed with signal %d."), pid, sig);
+ wxLogStatus(wxT("Process %ld killed with signal %d."), pid, sig);
}
else
{
static const wxChar *errorText[] =
{
- _T(""), // no error
- _T("signal not supported"),
- _T("permission denied"),
- _T("no such process"),
- _T("unspecified error"),
+ wxT(""), // no error
+ wxT("signal not supported"),
+ wxT("permission denied"),
+ wxT("no such process"),
+ wxT("unspecified error"),
};
- wxLogStatus(_T("Failed to kill process %ld with signal %d: %s"),
+ wxLogStatus(wxT("Failed to kill process %ld with signal %d: %s"),
pid, sig, errorText[rc]);
}
}
}
// ----------------------------------------------------------------------------
-// event handlers: exec menu
+// execution options dialog
// ----------------------------------------------------------------------------
-void MyFrame::DoAsyncExec(const wxString& cmd)
+enum ExecQueryDialogID
{
- wxProcess *process = new MyProcess(this, cmd);
- m_pidLast = wxExecute(cmd, wxEXEC_ASYNC, process);
- if ( !m_pidLast )
+ TEXT_EXECUTABLE,
+ TEXT_CWD,
+ TEXT_ENVIRONMENT
+};
+
+class ExecQueryDialog : public wxDialog
+{
+public:
+ ExecQueryDialog(const wxString& cmd);
+
+ wxString GetExecutable() const
{
- wxLogError( _T("Execution of '%s' failed."), cmd.c_str() );
+ return m_executable->GetValue();
+ }
- delete process;
+ wxString GetWorkDir() const
+ {
+ return m_useCWD->GetValue() ? m_cwdtext->GetValue() : wxString();
}
- else
+
+ void GetEnvironment(wxEnvVariableHashMap& env);
+
+private:
+ void OnUpdateWorkingDirectoryUI(wxUpdateUIEvent& event)
{
- wxLogStatus( _T("Process %ld (%s) launched."),
- m_pidLast, cmd.c_str() );
+ event.Enable(m_useCWD->GetValue());
+ }
- m_cmdLast = cmd;
+ void OnUpdateEnvironmentUI(wxUpdateUIEvent& event)
+ {
+ event.Enable(m_useEnv->GetValue());
+ }
+
+ wxTextCtrl* m_executable;
+ wxTextCtrl* m_cwdtext;
+ wxTextCtrl* m_envtext;
+ wxCheckBox* m_useCWD;
+ wxCheckBox* m_useEnv;
+
+ DECLARE_EVENT_TABLE()
+};
+
+BEGIN_EVENT_TABLE(ExecQueryDialog, wxDialog)
+ EVT_UPDATE_UI(TEXT_CWD, ExecQueryDialog::OnUpdateWorkingDirectoryUI)
+ EVT_UPDATE_UI(TEXT_ENVIRONMENT, ExecQueryDialog::OnUpdateEnvironmentUI)
+END_EVENT_TABLE()
+
+ExecQueryDialog::ExecQueryDialog(const wxString& cmd)
+ : wxDialog(NULL, wxID_ANY, DIALOG_TITLE,
+ wxDefaultPosition, wxDefaultSize,
+ wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER)
+{
+ wxSizer* globalSizer = new wxBoxSizer(wxVERTICAL);
+
+ m_executable = new wxTextCtrl(this, TEXT_EXECUTABLE, wxString());
+ m_cwdtext = new wxTextCtrl(this, TEXT_CWD, wxString());
+ m_envtext = new wxTextCtrl(this, TEXT_ENVIRONMENT, wxString(),
+ wxDefaultPosition, wxSize(300, 200),
+ wxTE_MULTILINE|wxHSCROLL);
+
+ const wxSizerFlags flagsExpand = wxSizerFlags().Expand().Border();
+ globalSizer->Add(new wxStaticText(this, wxID_ANY, "Enter the command: "),
+ flagsExpand);
+ globalSizer->Add(m_executable, flagsExpand);
+
+ m_useCWD = new wxCheckBox(this, wxID_ANY, "Working directory: ");
+ globalSizer->Add(m_useCWD, flagsExpand);
+ globalSizer->Add(m_cwdtext, flagsExpand);
+
+ m_useEnv = new wxCheckBox(this, wxID_ANY, "Environment: ");
+ globalSizer->Add(m_useEnv, flagsExpand);
+ globalSizer->Add(m_envtext, wxSizerFlags(flagsExpand).Proportion(1));
+
+ globalSizer->Add(CreateStdDialogButtonSizer(wxOK|wxCANCEL), flagsExpand);
+ SetSizerAndFit(globalSizer);
+
+
+ m_executable->SetValue(cmd);
+ m_cwdtext->SetValue(wxGetCwd());
+ wxEnvVariableHashMap env;
+ if ( wxGetEnvMap(&env) )
+ {
+ for ( wxEnvVariableHashMap::iterator it = env.begin();
+ it != env.end();
+ ++it )
+ {
+ m_envtext->AppendText(it->first + '=' + it->second + '\n');
+ }
}
+ m_useCWD->SetValue(false);
+ m_useEnv->SetValue(false);
}
-void MyFrame::OnSyncExec(wxCommandEvent& WXUNUSED(event))
+void ExecQueryDialog::GetEnvironment(wxEnvVariableHashMap& env)
{
- wxString cmd = wxGetTextFromUser(_T("Enter the command: "),
- DIALOG_TITLE,
- m_cmdLast);
+ env.clear();
+ if ( m_useEnv->GetValue() )
+ {
+ wxString name,
+ value;
- if ( !cmd )
- return;
+ const int nb = m_envtext->GetNumberOfLines();
+ for ( int l = 0; l < nb; l++ )
+ {
+ const wxString line = m_envtext->GetLineText(l).Trim();
+
+ if ( !line.empty() )
+ {
+ name = line.BeforeFirst('=', &value);
+ if ( name.empty() )
+ {
+ wxLogWarning("Skipping invalid environment line \"%s\".", line);
+ continue;
+ }
+
+ env[name] = value;
+ }
+ }
+ }
+}
- wxLogStatus( _T("'%s' is running please wait..."), cmd.c_str() );
+static bool QueryExec(wxString& cmd, wxExecuteEnv& env)
+{
+ ExecQueryDialog dialog(cmd);
- int code = wxExecute(cmd, wxEXEC_SYNC);
+ if ( dialog.ShowModal() != wxID_OK )
+ return false;
- wxLogStatus(_T("Process '%s' terminated with exit code %d."),
- cmd.c_str(), code);
+ cmd = dialog.GetExecutable();
+ env.cwd = dialog.GetWorkDir();
+ dialog.GetEnvironment(env.env);
- m_cmdLast = cmd;
+ return true;
}
-void MyFrame::OnSyncNoEventsExec(wxCommandEvent& WXUNUSED(event))
+// ----------------------------------------------------------------------------
+// event handlers: exec menu
+// ----------------------------------------------------------------------------
+
+int MyFrame::GetExecFlags() const
{
- wxString cmd = wxGetTextFromUser(_T("Enter the command: "),
- DIALOG_TITLE,
- m_cmdLast);
+ wxMenuBar* const mbar = GetMenuBar();
- if ( !cmd )
+ int flags = 0;
+
+ if ( mbar->IsChecked(Exec_Flags_HideConsole) )
+ flags |= wxEXEC_HIDE_CONSOLE;
+ if ( mbar->IsChecked(Exec_Flags_ShowConsole) )
+ flags |= wxEXEC_SHOW_CONSOLE;
+ if ( mbar->IsChecked(Exec_Flags_NoEvents) )
+ flags |= wxEXEC_NOEVENTS;
+
+ return flags;
+}
+
+void MyFrame::DoAsyncExec(const wxString& cmd)
+{
+ MyProcess * const process = new MyProcess(this, cmd);
+ m_pidLast = wxExecute(cmd, wxEXEC_ASYNC | GetExecFlags(), process);
+ if ( !m_pidLast )
+ {
+ wxLogError(wxT("Execution of '%s' failed."), cmd.c_str());
+
+ delete process;
+ }
+ else
+ {
+ wxLogStatus(wxT("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);
+ }
+}
+
+void MyFrame::OnSyncExec(wxCommandEvent& WXUNUSED(event))
+{
+ wxString cmd;
+ wxExecuteEnv env;
+ if ( !QueryExec(cmd, env) )
return;
- wxLogStatus( _T("'%s' is running please wait..."), cmd.c_str() );
+ wxLogStatus( wxT("'%s' is running please wait..."), cmd.c_str() );
- int code = wxExecute(cmd, wxEXEC_BLOCK);
+ int code = wxExecute(cmd, wxEXEC_SYNC | GetExecFlags(), NULL, &env);
- wxLogStatus(_T("Process '%s' terminated with exit code %d."),
+ wxLogStatus(wxT("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: "),
+ wxString cmd = wxGetTextFromUser(wxT("Enter the command: "),
DIALOG_TITLE,
m_cmdLast);
void MyFrame::OnShell(wxCommandEvent& WXUNUSED(event))
{
- wxString cmd = wxGetTextFromUser(_T("Enter the command: "),
+ wxString cmd = wxGetTextFromUser(wxT("Enter the command: "),
DIALOG_TITLE,
m_cmdLast);
return;
int code = wxShell(cmd);
- wxLogStatus(_T("Shell command '%s' terminated with exit code %d."),
+ wxLogStatus(wxT("Shell command '%s' terminated with exit code %d."),
cmd.c_str(), code);
m_cmdLast = cmd;
}
void MyFrame::OnExecWithRedirect(wxCommandEvent& WXUNUSED(event))
{
- wxString cmd = wxGetTextFromUser(_T("Enter the command: "),
+ if ( !m_cmdLast )
+ {
+#ifdef __WXMSW__
+ m_cmdLast = "type Makefile.in";
+#else
+ m_cmdLast = "cat -n Makefile";
+#endif
+ }
+
+ wxString cmd = wxGetTextFromUser(wxT("Enter the command: "),
DIALOG_TITLE,
m_cmdLast);
return;
bool sync;
- switch ( wxMessageBox(_T("Execute it synchronously?"),
- _T("Exec question"),
+ switch ( wxMessageBox(wxT("Execute it synchronously?"),
+ wxT("Exec question"),
wxYES_NO | wxCANCEL | wxICON_QUESTION, this) )
{
case wxYES:
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 )
{
- ShowOutput(cmd, output, _T("Output"));
- ShowOutput(cmd, errors, _T("Errors"));
+ ShowOutput(cmd, output, wxT("Output"));
+ ShowOutput(cmd, errors, wxT("Errors"));
}
}
else // async exec
MyPipedProcess *process = new MyPipedProcess(this, cmd);
if ( !wxExecute(cmd, wxEXEC_ASYNC, process) )
{
- wxLogError(_T("Execution of '%s' failed."), cmd.c_str());
+ wxLogError(wxT("Execution of '%s' failed."), cmd.c_str());
delete process;
}
else
{
- AddAsyncProcess(process);
+ AddPipedProcess(process);
}
}
void MyFrame::OnExecWithPipe(wxCommandEvent& WXUNUSED(event))
{
if ( !m_cmdLast )
- m_cmdLast = _T("tr [a-z] [A-Z]");
+ m_cmdLast = wxT("tr [a-z] [A-Z]");
- wxString cmd = wxGetTextFromUser(_T("Enter the command: "),
+ wxString cmd = wxGetTextFromUser(wxT("Enter the command: "),
DIALOG_TITLE,
m_cmdLast);
if ( !cmd )
return;
- wxString input = wxGetTextFromUser(_T("Enter the string to send to it: "),
+ wxString input = wxGetTextFromUser(wxT("Enter the string to send to it: "),
DIALOG_TITLE);
if ( !input )
return;
long pid = wxExecute(cmd, wxEXEC_ASYNC, process);
if ( pid )
{
- wxLogStatus( _T("Process %ld (%s) launched."), pid, cmd.c_str() );
+ wxLogStatus(wxT("Process %ld (%s) launched."), pid, cmd.c_str());
- AddAsyncProcess(process);
+ AddPipedProcess(process);
}
else
{
- wxLogError(_T("Execution of '%s' failed."), cmd.c_str());
+ wxLogError(wxT("Execution of '%s' failed."), cmd.c_str());
delete process;
}
void MyFrame::OnPOpen(wxCommandEvent& WXUNUSED(event))
{
- wxString cmd = wxGetTextFromUser(_T("Enter the command to launch: "),
+ wxString cmd = wxGetTextFromUser(wxT("Enter the command to launch: "),
DIALOG_TITLE,
m_cmdLast);
if ( cmd.empty() )
wxProcess *process = wxProcess::Open(cmd);
if ( !process )
{
- wxLogError(_T("Failed to launch the command."));
+ wxLogError(wxT("Failed to launch the command."));
return;
}
- wxLogVerbose(_T("PID of the new process: %ld"), process->GetPid());
+ wxLogVerbose(wxT("PID of the new process: %ld"), process->GetPid());
wxOutputStream *out = process->GetOutputStream();
if ( !out )
{
- wxLogError(_T("Failed to connect to child stdin"));
+ wxLogError(wxT("Failed to connect to child stdin"));
return;
}
wxInputStream *in = process->GetInputStream();
if ( !in )
{
- wxLogError(_T("Failed to connect to child stdout"));
+ wxLogError(wxT("Failed to connect to child stdout"));
return;
}
new MyPipeFrame(this, cmd, process);
}
-void MyFrame::OnFileExec(wxCommandEvent& WXUNUSED(event))
-{
- static wxString s_filename;
+static wxString gs_lastFile;
+static bool AskUserForFileName()
+{
wxString filename;
#if wxUSE_FILEDLG
- filename = wxLoadFileSelector(_T("any file"), wxEmptyString, s_filename, this);
+ filename = wxLoadFileSelector(wxT("any"), wxEmptyString, gs_lastFile);
#else // !wxUSE_FILEDLG
- filename = wxGetTextFromUser(_T("Enter the file name"), _T("exec sample"),
- s_filename, this);
+ filename = wxGetTextFromUser(wxT("Enter the file name"), wxT("exec sample"),
+ gs_lastFile);
#endif // wxUSE_FILEDLG/!wxUSE_FILEDLG
if ( filename.empty() )
- return;
+ return false;
+
+ gs_lastFile = filename;
- s_filename = filename;
+ return true;
+}
- wxString ext = filename.AfterFirst(_T('.'));
+void MyFrame::OnFileExec(wxCommandEvent& WXUNUSED(event))
+{
+ if ( !AskUserForFileName() )
+ return;
+
+ wxString ext = gs_lastFile.AfterLast(wxT('.'));
wxFileType *ft = wxTheMimeTypesManager->GetFileTypeFromExtension(ext);
if ( !ft )
{
- wxLogError(_T("Impossible to determine the file type for extension '%s'"),
+ wxLogError(wxT("Impossible to determine the file type for extension '%s'"),
ext.c_str());
return;
}
wxString cmd;
bool ok = ft->GetOpenCommand(&cmd,
- wxFileType::MessageParameters(filename));
+ wxFileType::MessageParameters(gs_lastFile));
delete ft;
if ( !ok )
{
- wxLogError(_T("Impossible to find out how to open files of extension '%s'"),
+ wxLogError(wxT("Impossible to find out how to open files of extension '%s'"),
ext.c_str());
return;
}
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_filename(_T("http://www.wxwidgets.org/"));
+ static wxString s_url(wxT("http://www.wxwidgets.org/"));
wxString filename = wxGetTextFromUser
(
- _T("Enter the URL"),
- _T("exec sample"),
- s_filename,
+ wxT("Enter the URL"),
+ wxT("exec sample"),
+ s_url,
this
);
if ( filename.empty() )
return;
- s_filename = filename;
+ s_url = filename;
- if ( !wxLaunchDefaultBrowser(s_filename) )
- wxLogError(_T("Failed to open URL \"%s\""), s_filename.c_str());
+ if ( !wxLaunchDefaultBrowser(s_url) )
+ {
+ wxLogError(wxT("Failed to open URL \"%s\""), s_url.c_str());
+ }
}
// ----------------------------------------------------------------------------
bool MyFrame::GetDDEServer()
{
- wxString server = wxGetTextFromUser(_T("Server to connect to:"),
+ wxString server = wxGetTextFromUser(wxT("Server to connect to:"),
DIALOG_TITLE, m_server);
if ( !server )
return false;
m_server = server;
- wxString topic = wxGetTextFromUser(_T("DDE topic:"), DIALOG_TITLE, m_topic);
+ wxString topic = wxGetTextFromUser(wxT("DDE topic:"), DIALOG_TITLE, m_topic);
if ( !topic )
return false;
m_topic = topic;
- wxString cmd = wxGetTextFromUser(_T("DDE command:"), DIALOG_TITLE, m_cmdDde);
+ wxString cmd = wxGetTextFromUser(wxT("DDE command:"), DIALOG_TITLE, m_cmdDde);
if ( !cmd )
return false;
wxConnectionBase *conn = client.MakeConnection(wxEmptyString, m_server, m_topic);
if ( !conn )
{
- wxLogError(_T("Failed to connect to the DDE server '%s'."),
+ wxLogError(wxT("Failed to connect to the DDE server '%s'."),
m_server.c_str());
}
else
{
if ( !conn->Execute(m_cmdDde) )
{
- wxLogError(_T("Failed to execute command '%s' via DDE."),
+ wxLogError(wxT("Failed to execute command '%s' via DDE."),
m_cmdDde.c_str());
}
else
{
- wxLogStatus(_T("Successfully executed DDE command"));
+ wxLogStatus(wxT("Successfully executed DDE command"));
}
}
}
wxConnectionBase *conn = client.MakeConnection(wxEmptyString, m_server, m_topic);
if ( !conn )
{
- wxLogError(_T("Failed to connect to the DDE server '%s'."),
+ wxLogError(wxT("Failed to connect to the DDE server '%s'."),
m_server.c_str());
}
else
{
if ( !conn->Request(m_cmdDde) )
{
- wxLogError(_T("Failed to send request '%s' via DDE."),
+ wxLogError(wxT("Failed to send request '%s' via DDE."),
m_cmdDde.c_str());
}
else
{
- wxLogStatus(_T("Successfully sent DDE request."));
+ wxLogStatus(wxT("Successfully sent DDE request."));
}
}
}
}
}
-void MyFrame::OnTimer(wxTimerEvent& WXUNUSED(event))
+void MyFrame::OnIdleTimer(wxTimerEvent& WXUNUSED(event))
{
wxWakeUpIdle();
}
+void MyFrame::OnBgTimer(wxTimerEvent& WXUNUSED(event))
+{
+ static unsigned long s_ticks = 0;
+ SetStatusText(wxString::Format("%lu ticks", s_ticks++), 1);
+}
+
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,
if ( !count )
return;
- m_lbox->Append(wxString::Format(_T("--- %s of '%s' ---"),
+ m_lbox->Append(wxString::Format(wxT("--- %s of '%s' ---"),
title.c_str(), cmd.c_str()));
for ( size_t n = 0; n < count; n++ )
m_lbox->Append(output[n]);
}
- m_lbox->Append(wxString::Format(_T("--- End of %s ---"),
+ m_lbox->Append(wxString::Format(wxT("--- End of %s ---"),
title.Lower().c_str()));
}
void MyProcess::OnTerminate(int pid, int status)
{
- wxLogStatus(m_parent, _T("Process %u ('%s') terminated with exit code %d."),
+ wxLogStatus(m_parent, wxT("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);
}
// ----------------------------------------------------------------------------
// this assumes that the output is always line buffered
wxString msg;
- msg << m_cmd << _T(" (stdout): ") << tis.ReadLine();
+ msg << m_cmd << wxT(" (stdout): ") << tis.ReadLine();
m_parent->GetLogListBox()->Append(msg);
// this assumes that the output is always line buffered
wxString msg;
- msg << m_cmd << _T(" (stderr): ") << tis.ReadLine();
+ msg << m_cmd << wxT(" (stderr): ") << tis.ReadLine();
m_parent->GetLogListBox()->Append(msg);
wxSizer *sizerBtns = new wxBoxSizer(wxHORIZONTAL);
sizerBtns->
- Add(new wxButton(panel, Exec_Btn_Send, _T("&Send")), 0, wxALL, 5);
+ Add(new wxButton(panel, Exec_Btn_Send, wxT("&Send")), 0, wxALL, 5);
sizerBtns->
- Add(new wxButton(panel, Exec_Btn_SendFile, _T("&File...")), 0, wxALL, 5);
+ Add(new wxButton(panel, Exec_Btn_SendFile, wxT("&File...")), 0, wxALL, 5);
sizerBtns->
- Add(new wxButton(panel, Exec_Btn_Get, _T("&Get")), 0, wxALL, 5);
+ Add(new wxButton(panel, Exec_Btn_Get, wxT("&Get")), 0, wxALL, 5);
sizerBtns->
- Add(new wxButton(panel, Exec_Btn_Close, _T("&Close")), 0, wxALL, 5);
+ Add(new wxButton(panel, Exec_Btn_Close, wxT("&Close")), 0, wxALL, 5);
sizerTop->Add(sizerBtns, 0, wxCENTRE | wxALL, 5);
sizerTop->Add(m_textIn, 1, wxGROW | wxALL, 5);
void MyPipeFrame::OnBtnSendFile(wxCommandEvent& WXUNUSED(event))
{
#if wxUSE_FILEDLG
- wxFileDialog filedlg(this, _T("Select file to send"));
+ wxFileDialog filedlg(this, wxT("Select file to send"));
if ( filedlg.ShowModal() != wxID_OK )
return;
- wxFFile file(filedlg.GetFilename(), _T("r"));
+ wxFFile file(filedlg.GetFilename(), wxT("r"));
wxString data;
if ( !file.IsOpened() || !file.ReadAll(&data) )
return;
{
while ( in.CanRead() )
{
- wxChar buffer[4096];
- buffer[in.Read(buffer, WXSIZEOF(buffer) - 1).LastRead()] = _T('\0');
+ char buffer[4096];
+ buffer[in.Read(buffer, WXSIZEOF(buffer) - 1).LastRead()] = '\0';
text->AppendText(buffer);
}
{
DoGet();
- delete m_process;
- m_process = NULL;
+ wxDELETE(m_process);
- wxLogWarning(_T("The other process has terminated, closing"));
+ wxLogWarning(wxT("The other process has terminated, closing"));
DisableInput();
DisableOutput();