]> git.saurik.com Git - wxWidgets.git/blame - samples/exec/exec.cpp
Fix double-click support for wxListBox (#10548)
[wxWidgets.git] / samples / exec / exec.cpp
CommitLineData
69c33c6c
VZ
1/////////////////////////////////////////////////////////////////////////////
2// Name: exec.cpp
3// Purpose: exec sample demonstrates wxExecute and related functions
4// Author: Vadim Zeitlin
5// Modified by:
6// Created: 15.01.00
7// RCS-ID: $Id$
8// Copyright: (c) Vadim Zeitlin
9// Licence: wxWindows licence
10/////////////////////////////////////////////////////////////////////////////
11
12// ============================================================================
13// declarations
14// ============================================================================
15
16// ----------------------------------------------------------------------------
17// headers
18// ----------------------------------------------------------------------------
19
69c33c6c
VZ
20// For compilers that support precompilation, includes "wx/wx.h".
21#include "wx/wxprec.h"
22
23#ifdef __BORLANDC__
24 #pragma hdrstop
25#endif
26
27// for all others, include the necessary headers (this file is usually all you
be5a51fb 28// need because it includes almost all "standard" wxWidgets headers
69c33c6c
VZ
29#ifndef WX_PRECOMP
30 #include "wx/app.h"
788233da 31 #include "wx/log.h"
69c33c6c 32 #include "wx/frame.h"
92a2a7eb
VZ
33 #include "wx/panel.h"
34
35 #include "wx/timer.h"
eb671557 36
69c33c6c 37 #include "wx/utils.h"
a8f0faf3 38 #include "wx/menu.h"
eb671557 39
a8f0faf3
GRG
40 #include "wx/msgdlg.h"
41 #include "wx/textdlg.h"
8ce88dfa 42 #include "wx/filedlg.h"
50567b69 43 #include "wx/choicdlg.h"
eb671557
VZ
44
45 #include "wx/button.h"
46 #include "wx/textctrl.h"
47 #include "wx/listbox.h"
48
49 #include "wx/sizer.h"
69c33c6c
VZ
50#endif
51
d8e41d42 52#include "wx/txtstrm.h"
e4f3eb42 53#include "wx/numdlg.h"
ba59de5d 54#include "wx/textdlg.h"
1a278e7b 55#include "wx/ffile.h"
22386791 56#include "wx/stopwatch.h"
d8e41d42 57
69c33c6c
VZ
58#include "wx/process.h"
59
6ba63600
VZ
60#include "wx/mimetype.h"
61
d93c719a
VZ
62#ifdef __WINDOWS__
63 #include "wx/dde.h"
64#endif // __WINDOWS__
65
69c33c6c 66// ----------------------------------------------------------------------------
eb671557 67// the usual application and main frame classes
69c33c6c
VZ
68// ----------------------------------------------------------------------------
69
70// Define a new application type, each program should derive a class from wxApp
71class MyApp : public wxApp
72{
73public:
74 // override base class virtuals
75 // ----------------------------
76
77 // this one is called on application startup and is a good place for the app
78 // initialization (doing it here and not in the ctor allows to have an error
79 // return: if OnInit() returns false, the application terminates)
80 virtual bool OnInit();
81};
82
cd6ce4a9
VZ
83// Define an array of process pointers used by MyFrame
84class MyPipedProcess;
5a8561fc
VZ
85WX_DEFINE_ARRAY_PTR(MyPipedProcess *, MyPipedProcessesArray);
86
87class MyProcess;
88WX_DEFINE_ARRAY_PTR(MyProcess *, MyProcessesArray);
cd6ce4a9 89
69c33c6c
VZ
90// Define a new frame type: this is going to be our main frame
91class MyFrame : public wxFrame
92{
93public:
5a8561fc 94 // ctor and dtor
69c33c6c 95 MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size);
5a8561fc 96 virtual ~MyFrame();
69c33c6c
VZ
97
98 // event handlers (these functions should _not_ be virtual)
99 void OnQuit(wxCommandEvent& event);
100
50567b69
VZ
101 void OnKill(wxCommandEvent& event);
102
d8e41d42
VZ
103 void OnClear(wxCommandEvent& event);
104
c6f9dfe8
VZ
105 void OnBeginBusyCursor(wxCommandEvent& event);
106 void OnEndBusyCursor(wxCommandEvent& event);
107
69c33c6c 108 void OnSyncExec(wxCommandEvent& event);
9b6b9e0c 109 void OnSyncNoEventsExec(wxCommandEvent& event);
69c33c6c
VZ
110 void OnAsyncExec(wxCommandEvent& event);
111 void OnShell(wxCommandEvent& event);
d8e41d42 112 void OnExecWithRedirect(wxCommandEvent& event);
f6bcfd97
BP
113 void OnExecWithPipe(wxCommandEvent& event);
114
eb671557
VZ
115 void OnPOpen(wxCommandEvent& event);
116
6ba63600 117 void OnFileExec(wxCommandEvent& event);
979a7347 118 void OnFileLaunch(wxCommandEvent& event);
ba59de5d 119 void OnOpenURL(wxCommandEvent& event);
6ba63600 120
69c33c6c
VZ
121 void OnAbout(wxCommandEvent& event);
122
cd6ce4a9 123 // polling output of async processes
92a2a7eb 124 void OnTimer(wxTimerEvent& event);
cd6ce4a9
VZ
125 void OnIdle(wxIdleEvent& event);
126
d8e41d42 127 // for MyPipedProcess
f6bcfd97 128 void OnProcessTerminated(MyPipedProcess *process);
d8e41d42
VZ
129 wxListBox *GetLogListBox() const { return m_lbox; }
130
5a8561fc
VZ
131 // for MyProcess
132 void OnAsyncTermination(MyProcess *process);
133
69c33c6c 134private:
f6bcfd97
BP
135 void ShowOutput(const wxString& cmd,
136 const wxArrayString& output,
137 const wxString& title);
138
6ba63600
VZ
139 void DoAsyncExec(const wxString& cmd);
140
5a8561fc 141 void AddAsyncProcess(MyProcess *process) { m_allAsync.push_back(process); }
92a2a7eb 142
5a8561fc
VZ
143 void AddPipedProcess(MyPipedProcess *process);
144 void RemovePipedProcess(MyPipedProcess *process);
92a2a7eb 145
92a2a7eb 146
50567b69 147 // the PID of the last process we launched asynchronously
aec18ff7 148 long m_pidLast;
50567b69 149
ca289436 150 // last command we executed
69c33c6c
VZ
151 wxString m_cmdLast;
152
ca289436
VZ
153#ifdef __WINDOWS__
154 void OnDDEExec(wxCommandEvent& event);
155 void OnDDERequest(wxCommandEvent& event);
156
157 bool GetDDEServer();
158
159 // last params of a DDE transaction
160 wxString m_server,
161 m_topic,
162 m_cmdDde;
163#endif // __WINDOWS__
164
d8e41d42
VZ
165 wxListBox *m_lbox;
166
5a8561fc
VZ
167 // array of running processes with redirected IO
168 MyPipedProcessesArray m_running;
169
170 // array of all asynchrously running processes
171 MyProcessesArray m_allAsync;
cd6ce4a9 172
92a2a7eb
VZ
173 // the idle event wake up timer
174 wxTimer m_timerIdleWakeUp;
175
be5a51fb 176 // any class wishing to process wxWidgets events must use this macro
69c33c6c
VZ
177 DECLARE_EVENT_TABLE()
178};
179
eb671557
VZ
180// ----------------------------------------------------------------------------
181// MyPipeFrame: allows the user to communicate with the child process
182// ----------------------------------------------------------------------------
183
184class MyPipeFrame : public wxFrame
185{
186public:
187 MyPipeFrame(wxFrame *parent,
188 const wxString& cmd,
189 wxProcess *process);
190
191protected:
a0b08655
VZ
192 void OnTextEnter(wxCommandEvent& WXUNUSED(event)) { DoSend(); }
193 void OnBtnSend(wxCommandEvent& WXUNUSED(event)) { DoSend(); }
1a278e7b 194 void OnBtnSendFile(wxCommandEvent& WXUNUSED(event));
a0b08655 195 void OnBtnGet(wxCommandEvent& WXUNUSED(event)) { DoGet(); }
1a278e7b 196 void OnBtnClose(wxCommandEvent& WXUNUSED(event)) { DoClose(); }
eb671557
VZ
197
198 void OnClose(wxCloseEvent& event);
199
7ca528cb
VZ
200 void OnProcessTerm(wxProcessEvent& event);
201
202 void DoSend()
203 {
1a278e7b
VZ
204 wxString s(m_textOut->GetValue());
205 s += _T('\n');
206 m_out.Write(s.c_str(), s.length());
207 m_textOut->Clear();
7ca528cb
VZ
208
209 DoGet();
210 }
211
eb671557 212 void DoGet();
1a278e7b 213 void DoClose();
eb671557
VZ
214
215private:
1a278e7b
VZ
216 void DoGetFromStream(wxTextCtrl *text, wxInputStream& in);
217 void DisableInput();
218 void DisableOutput();
219
220
eb671557
VZ
221 wxProcess *m_process;
222
1a278e7b
VZ
223 wxOutputStream &m_out;
224 wxInputStream &m_in,
225 &m_err;
eb671557 226
1a278e7b
VZ
227 wxTextCtrl *m_textOut,
228 *m_textIn,
229 *m_textErr;
eb671557
VZ
230
231 DECLARE_EVENT_TABLE()
232};
233
234// ----------------------------------------------------------------------------
235// wxProcess-derived classes
236// ----------------------------------------------------------------------------
237
69c33c6c
VZ
238// This is the handler for process termination events
239class MyProcess : public wxProcess
240{
241public:
d8e41d42 242 MyProcess(MyFrame *parent, const wxString& cmd)
69c33c6c
VZ
243 : wxProcess(parent), m_cmd(cmd)
244 {
245 m_parent = parent;
246 }
247
248 // instead of overriding this virtual function we might as well process the
249 // event from it in the frame class - this might be more convenient in some
250 // cases
251 virtual void OnTerminate(int pid, int status);
252
d8e41d42
VZ
253protected:
254 MyFrame *m_parent;
69c33c6c
VZ
255 wxString m_cmd;
256};
257
d8e41d42
VZ
258// A specialization of MyProcess for redirecting the output
259class MyPipedProcess : public MyProcess
260{
261public:
262 MyPipedProcess(MyFrame *parent, const wxString& cmd)
263 : MyProcess(parent, cmd)
264 {
cd6ce4a9 265 Redirect();
d8e41d42
VZ
266 }
267
268 virtual void OnTerminate(int pid, int status);
cd6ce4a9 269
f6bcfd97
BP
270 virtual bool HasInput();
271};
272
273// A version of MyPipedProcess which also sends input to the stdin of the
274// child process
275class MyPipedProcess2 : public MyPipedProcess
276{
277public:
278 MyPipedProcess2(MyFrame *parent, const wxString& cmd, const wxString& input)
279 : MyPipedProcess(parent, cmd), m_input(input)
280 {
281 }
282
283 virtual bool HasInput();
284
285private:
286 wxString m_input;
d8e41d42
VZ
287};
288
69c33c6c
VZ
289// ----------------------------------------------------------------------------
290// constants
291// ----------------------------------------------------------------------------
292
293// IDs for the controls and the menu commands
294enum
295{
296 // menu items
297 Exec_Quit = 100,
50567b69 298 Exec_Kill,
d8e41d42 299 Exec_ClearLog,
c6f9dfe8
VZ
300 Exec_BeginBusyCursor,
301 Exec_EndBusyCursor,
69c33c6c 302 Exec_SyncExec = 200,
9b6b9e0c 303 Exec_SyncNoEventsExec,
69c33c6c
VZ
304 Exec_AsyncExec,
305 Exec_Shell,
eb671557 306 Exec_POpen,
6ba63600 307 Exec_OpenFile,
979a7347 308 Exec_LaunchFile,
ba59de5d 309 Exec_OpenURL,
d93c719a 310 Exec_DDEExec,
ca289436 311 Exec_DDERequest,
d8e41d42 312 Exec_Redirect,
f6bcfd97 313 Exec_Pipe,
eb671557
VZ
314 Exec_About = 300,
315
316 // control ids
317 Exec_Btn_Send = 1000,
1a278e7b
VZ
318 Exec_Btn_SendFile,
319 Exec_Btn_Get,
320 Exec_Btn_Close
69c33c6c
VZ
321};
322
d93c719a
VZ
323static const wxChar *DIALOG_TITLE = _T("Exec sample");
324
69c33c6c 325// ----------------------------------------------------------------------------
be5a51fb 326// event tables and other macros for wxWidgets
69c33c6c
VZ
327// ----------------------------------------------------------------------------
328
be5a51fb 329// the event tables connect the wxWidgets events with the functions (event
69c33c6c
VZ
330// handlers) which process them. It can be also done at run-time, but for the
331// simple menu events like this the static method is much simpler.
332BEGIN_EVENT_TABLE(MyFrame, wxFrame)
333 EVT_MENU(Exec_Quit, MyFrame::OnQuit)
50567b69 334 EVT_MENU(Exec_Kill, MyFrame::OnKill)
d8e41d42 335 EVT_MENU(Exec_ClearLog, MyFrame::OnClear)
c6f9dfe8
VZ
336 EVT_MENU(Exec_BeginBusyCursor, MyFrame::OnBeginBusyCursor)
337 EVT_MENU(Exec_EndBusyCursor, MyFrame::OnEndBusyCursor)
69c33c6c
VZ
338
339 EVT_MENU(Exec_SyncExec, MyFrame::OnSyncExec)
9b6b9e0c 340 EVT_MENU(Exec_SyncNoEventsExec, MyFrame::OnSyncNoEventsExec)
69c33c6c
VZ
341 EVT_MENU(Exec_AsyncExec, MyFrame::OnAsyncExec)
342 EVT_MENU(Exec_Shell, MyFrame::OnShell)
d8e41d42 343 EVT_MENU(Exec_Redirect, MyFrame::OnExecWithRedirect)
f6bcfd97
BP
344 EVT_MENU(Exec_Pipe, MyFrame::OnExecWithPipe)
345
eb671557
VZ
346 EVT_MENU(Exec_POpen, MyFrame::OnPOpen)
347
6ba63600 348 EVT_MENU(Exec_OpenFile, MyFrame::OnFileExec)
979a7347 349 EVT_MENU(Exec_LaunchFile, MyFrame::OnFileLaunch)
ba59de5d 350 EVT_MENU(Exec_OpenURL, MyFrame::OnOpenURL)
6ba63600 351
5af4b77f 352#ifdef __WINDOWS__
d93c719a 353 EVT_MENU(Exec_DDEExec, MyFrame::OnDDEExec)
ca289436 354 EVT_MENU(Exec_DDERequest, MyFrame::OnDDERequest)
5af4b77f 355#endif // __WINDOWS__
eb671557 356
69c33c6c 357 EVT_MENU(Exec_About, MyFrame::OnAbout)
cd6ce4a9
VZ
358
359 EVT_IDLE(MyFrame::OnIdle)
92a2a7eb 360
07850a49 361 EVT_TIMER(wxID_ANY, MyFrame::OnTimer)
69c33c6c
VZ
362END_EVENT_TABLE()
363
eb671557
VZ
364BEGIN_EVENT_TABLE(MyPipeFrame, wxFrame)
365 EVT_BUTTON(Exec_Btn_Send, MyPipeFrame::OnBtnSend)
1a278e7b 366 EVT_BUTTON(Exec_Btn_SendFile, MyPipeFrame::OnBtnSendFile)
eb671557 367 EVT_BUTTON(Exec_Btn_Get, MyPipeFrame::OnBtnGet)
1a278e7b 368 EVT_BUTTON(Exec_Btn_Close, MyPipeFrame::OnBtnClose)
eb671557 369
07850a49 370 EVT_TEXT_ENTER(wxID_ANY, MyPipeFrame::OnTextEnter)
eb671557
VZ
371
372 EVT_CLOSE(MyPipeFrame::OnClose)
7ca528cb 373
07850a49 374 EVT_END_PROCESS(wxID_ANY, MyPipeFrame::OnProcessTerm)
eb671557
VZ
375END_EVENT_TABLE()
376
be5a51fb 377// Create a new application object: this macro will allow wxWidgets to create
69c33c6c
VZ
378// the application object during program execution (it's better than using a
379// static object for many reasons) and also declares the accessor function
380// wxGetApp() which will return the reference of the right type (i.e. MyApp and
381// not wxApp)
382IMPLEMENT_APP(MyApp)
383
384// ============================================================================
385// implementation
386// ============================================================================
387
388// ----------------------------------------------------------------------------
389// the application class
390// ----------------------------------------------------------------------------
391
392// `Main program' equivalent: the program execution "starts" here
393bool MyApp::OnInit()
394{
45e6e6f8
VZ
395 if ( !wxApp::OnInit() )
396 return false;
397
69c33c6c 398 // Create the main application window
be5a51fb 399 MyFrame *frame = new MyFrame(_T("Exec wxWidgets sample"),
69c33c6c
VZ
400 wxDefaultPosition, wxSize(500, 140));
401
402 // Show it and tell the application that it's our main window
07850a49 403 frame->Show(true);
69c33c6c
VZ
404 SetTopWindow(frame);
405
406 // success: wxApp::OnRun() will be called which will enter the main message
07850a49 407 // loop and the application will run. If we returned false here, the
69c33c6c 408 // application would exit immediately.
07850a49 409 return true;
69c33c6c
VZ
410}
411
412// ----------------------------------------------------------------------------
413// main frame
414// ----------------------------------------------------------------------------
415
2b5f62a0
VZ
416#ifdef __VISUALC__
417#pragma warning(disable: 4355) // this used in base member initializer list
418#endif
419
69c33c6c
VZ
420// frame constructor
421MyFrame::MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size)
07850a49 422 : wxFrame((wxFrame *)NULL, wxID_ANY, title, pos, size),
92a2a7eb 423 m_timerIdleWakeUp(this)
69c33c6c 424{
50567b69
VZ
425 m_pidLast = 0;
426
69c33c6c
VZ
427#ifdef __WXMAC__
428 // we need this in order to allow the about menu relocation, since ABOUT is
429 // not the default id of the about menu
430 wxApp::s_macAboutMenuItemId = Exec_About;
431#endif
432
69c33c6c 433 // create a menu bar
71307412 434 wxMenu *menuFile = new wxMenu(wxEmptyString, wxMENU_TEAROFF);
50567b69
VZ
435 menuFile->Append(Exec_Kill, _T("&Kill process...\tCtrl-K"),
436 _T("Kill a process by PID"));
437 menuFile->AppendSeparator();
c6f9dfe8 438 menuFile->Append(Exec_ClearLog, _T("&Clear log\tCtrl-L"),
d8e41d42
VZ
439 _T("Clear the log window"));
440 menuFile->AppendSeparator();
c6f9dfe8
VZ
441 menuFile->Append(Exec_BeginBusyCursor, _T("Show &busy cursor\tCtrl-C"));
442 menuFile->Append(Exec_EndBusyCursor, _T("Show &normal cursor\tShift-Ctrl-C"));
443 menuFile->AppendSeparator();
69c33c6c
VZ
444 menuFile->Append(Exec_Quit, _T("E&xit\tAlt-X"), _T("Quit this program"));
445
446 wxMenu *execMenu = new wxMenu;
447 execMenu->Append(Exec_SyncExec, _T("Sync &execution...\tCtrl-E"),
448 _T("Launch a program and return when it terminates"));
9b6b9e0c
VZ
449 execMenu->Append(Exec_SyncNoEventsExec, _T("Sync execution and &block...\tCtrl-B"),
450 _T("Launch a program and block until it terminates"));
69c33c6c
VZ
451 execMenu->Append(Exec_AsyncExec, _T("&Async execution...\tCtrl-A"),
452 _T("Launch a program and return immediately"));
453 execMenu->Append(Exec_Shell, _T("Execute &shell command...\tCtrl-S"),
454 _T("Launch a shell and execute a command in it"));
f6bcfd97 455 execMenu->AppendSeparator();
d8e41d42
VZ
456 execMenu->Append(Exec_Redirect, _T("Capture command &output...\tCtrl-O"),
457 _T("Launch a program and capture its output"));
eb671557 458 execMenu->Append(Exec_Pipe, _T("&Pipe through command..."),
f6bcfd97 459 _T("Pipe a string through a filter"));
eb671557
VZ
460 execMenu->Append(Exec_POpen, _T("&Open a pipe to a command...\tCtrl-P"),
461 _T("Open a pipe to and from another program"));
69c33c6c 462
6ba63600
VZ
463 execMenu->AppendSeparator();
464 execMenu->Append(Exec_OpenFile, _T("Open &file...\tCtrl-F"),
465 _T("Launch the command to open this kind of files"));
979a7347
VZ
466 execMenu->Append(Exec_LaunchFile, _T("La&unch file...\tShift-Ctrl-F"),
467 _T("Launch the default application associated with the file"));
ba59de5d
VZ
468 execMenu->Append(Exec_OpenURL, _T("Open &URL...\tCtrl-U"),
469 _T("Launch the default browser with the given URL"));
d93c719a
VZ
470#ifdef __WINDOWS__
471 execMenu->AppendSeparator();
472 execMenu->Append(Exec_DDEExec, _T("Execute command via &DDE...\tCtrl-D"));
ca289436 473 execMenu->Append(Exec_DDERequest, _T("Send DDE &request...\tCtrl-R"));
d93c719a
VZ
474#endif
475
71307412 476 wxMenu *helpMenu = new wxMenu(wxEmptyString, wxMENU_TEAROFF);
69c33c6c
VZ
477 helpMenu->Append(Exec_About, _T("&About...\tF1"), _T("Show about dialog"));
478
479 // now append the freshly created menu to the menu bar...
480 wxMenuBar *menuBar = new wxMenuBar();
481 menuBar->Append(menuFile, _T("&File"));
482 menuBar->Append(execMenu, _T("&Exec"));
483 menuBar->Append(helpMenu, _T("&Help"));
484
485 // ... and attach this menu bar to the frame
486 SetMenuBar(menuBar);
487
9121bed2 488 // create the listbox in which we will show misc messages as they come
07850a49 489 m_lbox = new wxListBox(this, wxID_ANY);
8ce88dfa
VZ
490 wxFont font(12, wxFONTFAMILY_TELETYPE, wxFONTSTYLE_NORMAL,
491 wxFONTWEIGHT_NORMAL);
492 if ( font.Ok() )
493 m_lbox->SetFont(font);
9121bed2 494
69c33c6c
VZ
495#if wxUSE_STATUSBAR
496 // create a status bar just for fun (by default with 1 pane only)
e680a378 497 CreateStatusBar();
be5a51fb 498 SetStatusText(_T("Welcome to wxWidgets exec sample!"));
69c33c6c
VZ
499#endif // wxUSE_STATUSBAR
500}
501
5a8561fc
VZ
502MyFrame::~MyFrame()
503{
504 // any processes left until now must be deleted manually: normally this is
505 // done when the associated process terminates but it must be still running
506 // if this didn't happen until now
507 for ( size_t n = 0; n < m_allAsync.size(); n++ )
508 {
509 delete m_allAsync[n];
510 }
511}
512
50567b69
VZ
513// ----------------------------------------------------------------------------
514// event handlers: file and help menu
515// ----------------------------------------------------------------------------
69c33c6c
VZ
516
517void MyFrame::OnQuit(wxCommandEvent& WXUNUSED(event))
518{
07850a49
WS
519 // true is to force the frame to close
520 Close(true);
69c33c6c
VZ
521}
522
d8e41d42
VZ
523void MyFrame::OnClear(wxCommandEvent& WXUNUSED(event))
524{
525 m_lbox->Clear();
526}
527
c6f9dfe8
VZ
528void MyFrame::OnBeginBusyCursor(wxCommandEvent& WXUNUSED(event))
529{
530 wxBeginBusyCursor();
531}
532
533void MyFrame::OnEndBusyCursor(wxCommandEvent& WXUNUSED(event))
534{
535 wxEndBusyCursor();
536}
537
69c33c6c
VZ
538void MyFrame::OnAbout(wxCommandEvent& WXUNUSED(event))
539{
749bfe9a 540 wxMessageBox(_T("Exec wxWidgets Sample\n(c) 2000-2002 Vadim Zeitlin"),
69c33c6c
VZ
541 _T("About Exec"), wxOK | wxICON_INFORMATION, this);
542}
543
50567b69
VZ
544void MyFrame::OnKill(wxCommandEvent& WXUNUSED(event))
545{
546 long pid = wxGetNumberFromUser(_T("Please specify the process to kill"),
547 _T("Enter PID:"),
548 _T("Exec question"),
549 m_pidLast,
9c05a3ca
VZ
550 // we need the full unsigned int range
551 -INT_MAX, INT_MAX,
50567b69
VZ
552 this);
553 if ( pid == -1 )
554 {
555 // cancelled
556 return;
557 }
558
559 static const wxString signalNames[] =
560 {
561 _T("Just test (SIGNONE)"),
562 _T("Hangup (SIGHUP)"),
563 _T("Interrupt (SIGINT)"),
564 _T("Quit (SIGQUIT)"),
565 _T("Illegal instruction (SIGILL)"),
566 _T("Trap (SIGTRAP)"),
567 _T("Abort (SIGABRT)"),
568 _T("Emulated trap (SIGEMT)"),
569 _T("FP exception (SIGFPE)"),
570 _T("Kill (SIGKILL)"),
571 _T("Bus (SIGBUS)"),
572 _T("Segment violation (SIGSEGV)"),
573 _T("System (SIGSYS)"),
574 _T("Broken pipe (SIGPIPE)"),
575 _T("Alarm (SIGALRM)"),
576 _T("Terminate (SIGTERM)"),
577 };
578
579 int sig = wxGetSingleChoiceIndex(_T("How to kill the process?"),
580 _T("Exec question"),
581 WXSIZEOF(signalNames), signalNames,
582 this);
583 switch ( sig )
584 {
585 default:
586 wxFAIL_MSG( _T("unexpected return value") );
587 // fall through
588
589 case -1:
590 // cancelled
591 return;
592
593 case wxSIGNONE:
594 case wxSIGHUP:
595 case wxSIGINT:
596 case wxSIGQUIT:
597 case wxSIGILL:
598 case wxSIGTRAP:
599 case wxSIGABRT:
600 case wxSIGEMT:
601 case wxSIGFPE:
602 case wxSIGKILL:
603 case wxSIGBUS:
604 case wxSIGSEGV:
605 case wxSIGSYS:
606 case wxSIGPIPE:
607 case wxSIGALRM:
608 case wxSIGTERM:
609 break;
610 }
611
612 if ( sig == 0 )
613 {
614 if ( wxProcess::Exists(pid) )
aec18ff7 615 wxLogStatus(_T("Process %ld is running."), pid);
50567b69 616 else
aec18ff7 617 wxLogStatus(_T("No process with pid = %ld."), pid);
50567b69
VZ
618 }
619 else // not SIGNONE
620 {
621 wxKillError rc = wxProcess::Kill(pid, (wxSignal)sig);
622 if ( rc == wxKILL_OK )
623 {
aec18ff7 624 wxLogStatus(_T("Process %ld killed with signal %d."), pid, sig);
50567b69
VZ
625 }
626 else
627 {
628 static const wxChar *errorText[] =
629 {
630 _T(""), // no error
631 _T("signal not supported"),
632 _T("permission denied"),
633 _T("no such process"),
634 _T("unspecified error"),
635 };
636
aec18ff7 637 wxLogStatus(_T("Failed to kill process %ld with signal %d: %s"),
50567b69
VZ
638 pid, sig, errorText[rc]);
639 }
640 }
641}
642
643// ----------------------------------------------------------------------------
644// event handlers: exec menu
645// ----------------------------------------------------------------------------
646
6ba63600
VZ
647void MyFrame::DoAsyncExec(const wxString& cmd)
648{
5a8561fc 649 MyProcess * const process = new MyProcess(this, cmd);
4c1ef422 650 m_pidLast = wxExecute(cmd, wxEXEC_ASYNC, process);
50567b69 651 if ( !m_pidLast )
6ba63600 652 {
5a8561fc 653 wxLogError(_T("Execution of '%s' failed."), cmd.c_str());
6ba63600
VZ
654
655 delete process;
656 }
657 else
658 {
5a8561fc 659 wxLogStatus(_T("Process %ld (%s) launched."), m_pidLast, cmd.c_str());
6ba63600
VZ
660
661 m_cmdLast = cmd;
5a8561fc
VZ
662
663 // the parent frame keeps track of all async processes as it needs to
664 // free them if we exit before the child process terminates
665 AddAsyncProcess(process);
6ba63600
VZ
666 }
667}
668
69c33c6c
VZ
669void MyFrame::OnSyncExec(wxCommandEvent& WXUNUSED(event))
670{
671 wxString cmd = wxGetTextFromUser(_T("Enter the command: "),
d93c719a 672 DIALOG_TITLE,
69c33c6c
VZ
673 m_cmdLast);
674
675 if ( !cmd )
676 return;
677
aec18ff7 678 wxLogStatus( _T("'%s' is running please wait..."), cmd.c_str() );
d31b7b68 679
4c1ef422 680 int code = wxExecute(cmd, wxEXEC_SYNC);
d31b7b68 681
69c33c6c 682 wxLogStatus(_T("Process '%s' terminated with exit code %d."),
aec18ff7
MB
683 cmd.c_str(), code);
684
69c33c6c
VZ
685 m_cmdLast = cmd;
686}
687
9b6b9e0c
VZ
688void MyFrame::OnSyncNoEventsExec(wxCommandEvent& WXUNUSED(event))
689{
690 wxString cmd = wxGetTextFromUser(_T("Enter the command: "),
691 DIALOG_TITLE,
692 m_cmdLast);
693
694 if ( !cmd )
695 return;
696
697 wxLogStatus( _T("'%s' is running please wait..."), cmd.c_str() );
698
699 int code = wxExecute(cmd, wxEXEC_BLOCK);
700
701 wxLogStatus(_T("Process '%s' terminated with exit code %d."),
702 cmd.c_str(), code);
703
704 m_cmdLast = cmd;
705}
706
69c33c6c
VZ
707void MyFrame::OnAsyncExec(wxCommandEvent& WXUNUSED(event))
708{
709 wxString cmd = wxGetTextFromUser(_T("Enter the command: "),
d93c719a 710 DIALOG_TITLE,
69c33c6c
VZ
711 m_cmdLast);
712
713 if ( !cmd )
714 return;
715
6ba63600 716 DoAsyncExec(cmd);
69c33c6c
VZ
717}
718
719void MyFrame::OnShell(wxCommandEvent& WXUNUSED(event))
720{
721 wxString cmd = wxGetTextFromUser(_T("Enter the command: "),
d93c719a 722 DIALOG_TITLE,
69c33c6c
VZ
723 m_cmdLast);
724
725 if ( !cmd )
726 return;
727
728 int code = wxShell(cmd);
729 wxLogStatus(_T("Shell command '%s' terminated with exit code %d."),
730 cmd.c_str(), code);
731 m_cmdLast = cmd;
732}
733
d8e41d42
VZ
734void MyFrame::OnExecWithRedirect(wxCommandEvent& WXUNUSED(event))
735{
69328170
VZ
736 if ( !m_cmdLast )
737 {
738#ifdef __WXMSW__
739 m_cmdLast = "type Makefile.in";
740#else
741 m_cmdLast = "cat -n Makefile";
742#endif
743 }
744
d8e41d42
VZ
745 wxString cmd = wxGetTextFromUser(_T("Enter the command: "),
746 DIALOG_TITLE,
747 m_cmdLast);
748
749 if ( !cmd )
750 return;
751
cd6ce4a9
VZ
752 bool sync;
753 switch ( wxMessageBox(_T("Execute it synchronously?"),
754 _T("Exec question"),
755 wxYES_NO | wxCANCEL | wxICON_QUESTION, this) )
d8e41d42 756 {
cd6ce4a9 757 case wxYES:
07850a49 758 sync = true;
cd6ce4a9 759 break;
d8e41d42 760
cd6ce4a9 761 case wxNO:
07850a49 762 sync = false;
cd6ce4a9
VZ
763 break;
764
765 default:
766 return;
d8e41d42 767 }
cd6ce4a9
VZ
768
769 if ( sync )
d8e41d42 770 {
22386791
VZ
771 wxLogStatus("\"%s\" is running please wait...", cmd);
772
773 wxStopWatch sw;
ce0bb89d 774
f6bcfd97
BP
775 wxArrayString output, errors;
776 int code = wxExecute(cmd, output, errors);
ce0bb89d 777
22386791
VZ
778 wxLogStatus("Command \"%s\" terminated after %ldms; exit code %d.",
779 cmd, sw.Time(), code);
cd6ce4a9
VZ
780
781 if ( code != -1 )
782 {
f6bcfd97
BP
783 ShowOutput(cmd, output, _T("Output"));
784 ShowOutput(cmd, errors, _T("Errors"));
cd6ce4a9
VZ
785 }
786 }
787 else // async exec
788 {
789 MyPipedProcess *process = new MyPipedProcess(this, cmd);
4c1ef422 790 if ( !wxExecute(cmd, wxEXEC_ASYNC, process) )
cd6ce4a9
VZ
791 {
792 wxLogError(_T("Execution of '%s' failed."), cmd.c_str());
793
794 delete process;
795 }
796 else
797 {
5a8561fc 798 AddPipedProcess(process);
cd6ce4a9 799 }
d8e41d42 800 }
cd6ce4a9
VZ
801
802 m_cmdLast = cmd;
d8e41d42
VZ
803}
804
f6bcfd97
BP
805void MyFrame::OnExecWithPipe(wxCommandEvent& WXUNUSED(event))
806{
807 if ( !m_cmdLast )
808 m_cmdLast = _T("tr [a-z] [A-Z]");
809
810 wxString cmd = wxGetTextFromUser(_T("Enter the command: "),
811 DIALOG_TITLE,
812 m_cmdLast);
813
814 if ( !cmd )
815 return;
816
817 wxString input = wxGetTextFromUser(_T("Enter the string to send to it: "),
818 DIALOG_TITLE);
819 if ( !input )
820 return;
821
822 // always execute the filter asynchronously
823 MyPipedProcess2 *process = new MyPipedProcess2(this, cmd, input);
aec18ff7 824 long pid = wxExecute(cmd, wxEXEC_ASYNC, process);
f6bcfd97
BP
825 if ( pid )
826 {
5a8561fc 827 wxLogStatus(_T("Process %ld (%s) launched."), pid, cmd.c_str());
f6bcfd97 828
5a8561fc 829 AddPipedProcess(process);
f6bcfd97
BP
830 }
831 else
832 {
833 wxLogError(_T("Execution of '%s' failed."), cmd.c_str());
834
835 delete process;
836 }
837
838 m_cmdLast = cmd;
839}
840
87728739 841void MyFrame::OnPOpen(wxCommandEvent& WXUNUSED(event))
eb671557
VZ
842{
843 wxString cmd = wxGetTextFromUser(_T("Enter the command to launch: "),
844 DIALOG_TITLE,
845 m_cmdLast);
846 if ( cmd.empty() )
847 return;
848
849 wxProcess *process = wxProcess::Open(cmd);
850 if ( !process )
851 {
852 wxLogError(_T("Failed to launch the command."));
853 return;
854 }
855
a387938f
JS
856 wxLogVerbose(_T("PID of the new process: %ld"), process->GetPid());
857
eb671557
VZ
858 wxOutputStream *out = process->GetOutputStream();
859 if ( !out )
860 {
861 wxLogError(_T("Failed to connect to child stdin"));
862 return;
863 }
864
865 wxInputStream *in = process->GetInputStream();
866 if ( !in )
867 {
868 wxLogError(_T("Failed to connect to child stdout"));
869 return;
870 }
871
872 new MyPipeFrame(this, cmd, process);
873}
874
979a7347 875static wxString gs_lastFile;
6ba63600 876
979a7347
VZ
877static bool AskUserForFileName()
878{
71307412
WS
879 wxString filename;
880
881#if wxUSE_FILEDLG
21e413b2 882 filename = wxLoadFileSelector(_T("any"), wxEmptyString, gs_lastFile);
ba59de5d
VZ
883#else // !wxUSE_FILEDLG
884 filename = wxGetTextFromUser(_T("Enter the file name"), _T("exec sample"),
979a7347 885 gs_lastFile);
ba59de5d 886#endif // wxUSE_FILEDLG/!wxUSE_FILEDLG
71307412
WS
887
888 if ( filename.empty() )
979a7347 889 return false;
6ba63600 890
979a7347 891 gs_lastFile = filename;
6ba63600 892
979a7347
VZ
893 return true;
894}
895
896void MyFrame::OnFileExec(wxCommandEvent& WXUNUSED(event))
897{
898 if ( !AskUserForFileName() )
899 return;
900
901 wxString ext = gs_lastFile.AfterLast(_T('.'));
6ba63600
VZ
902 wxFileType *ft = wxTheMimeTypesManager->GetFileTypeFromExtension(ext);
903 if ( !ft )
904 {
905 wxLogError(_T("Impossible to determine the file type for extension '%s'"),
906 ext.c_str());
907 return;
908 }
909
910 wxString cmd;
911 bool ok = ft->GetOpenCommand(&cmd,
979a7347 912 wxFileType::MessageParameters(gs_lastFile));
6ba63600
VZ
913 delete ft;
914 if ( !ok )
915 {
916 wxLogError(_T("Impossible to find out how to open files of extension '%s'"),
917 ext.c_str());
918 return;
919 }
920
921 DoAsyncExec(cmd);
922}
923
979a7347
VZ
924void MyFrame::OnFileLaunch(wxCommandEvent& WXUNUSED(event))
925{
926 if ( !AskUserForFileName() )
927 return;
928
929 if ( !wxLaunchDefaultApplication(gs_lastFile) )
930 {
931 wxLogError("Opening \"%s\" in default application failed.", gs_lastFile);
932 }
933}
934
ba59de5d
VZ
935void MyFrame::OnOpenURL(wxCommandEvent& WXUNUSED(event))
936{
979a7347 937 static wxString s_url(_T("http://www.wxwidgets.org/"));
ba59de5d
VZ
938
939 wxString filename = wxGetTextFromUser
940 (
941 _T("Enter the URL"),
942 _T("exec sample"),
979a7347 943 s_url,
ba59de5d
VZ
944 this
945 );
946
947 if ( filename.empty() )
948 return;
949
979a7347 950 s_url = filename;
ba59de5d 951
979a7347
VZ
952 if ( !wxLaunchDefaultBrowser(s_url) )
953 wxLogError(_T("Failed to open URL \"%s\""), s_url.c_str());
ba59de5d
VZ
954}
955
50567b69
VZ
956// ----------------------------------------------------------------------------
957// DDE stuff
958// ----------------------------------------------------------------------------
959
d93c719a 960#ifdef __WINDOWS__
ca289436
VZ
961
962bool MyFrame::GetDDEServer()
963{
d93c719a 964 wxString server = wxGetTextFromUser(_T("Server to connect to:"),
ca289436 965 DIALOG_TITLE, m_server);
d93c719a 966 if ( !server )
07850a49 967 return false;
ca289436
VZ
968
969 m_server = server;
d93c719a 970
ca289436 971 wxString topic = wxGetTextFromUser(_T("DDE topic:"), DIALOG_TITLE, m_topic);
d93c719a 972 if ( !topic )
07850a49 973 return false;
d93c719a 974
ca289436
VZ
975 m_topic = topic;
976
977 wxString cmd = wxGetTextFromUser(_T("DDE command:"), DIALOG_TITLE, m_cmdDde);
d93c719a 978 if ( !cmd )
07850a49 979 return false;
ca289436
VZ
980
981 m_cmdDde = cmd;
982
07850a49 983 return true;
ca289436
VZ
984}
985
986void MyFrame::OnDDEExec(wxCommandEvent& WXUNUSED(event))
987{
988 if ( !GetDDEServer() )
d93c719a
VZ
989 return;
990
991 wxDDEClient client;
71307412 992 wxConnectionBase *conn = client.MakeConnection(wxEmptyString, m_server, m_topic);
d93c719a
VZ
993 if ( !conn )
994 {
995 wxLogError(_T("Failed to connect to the DDE server '%s'."),
ca289436 996 m_server.c_str());
d93c719a
VZ
997 }
998 else
999 {
ca289436 1000 if ( !conn->Execute(m_cmdDde) )
d93c719a
VZ
1001 {
1002 wxLogError(_T("Failed to execute command '%s' via DDE."),
ca289436 1003 m_cmdDde.c_str());
d93c719a
VZ
1004 }
1005 else
1006 {
1007 wxLogStatus(_T("Successfully executed DDE command"));
1008 }
1009 }
d93c719a
VZ
1010}
1011
ca289436
VZ
1012void MyFrame::OnDDERequest(wxCommandEvent& WXUNUSED(event))
1013{
1014 if ( !GetDDEServer() )
1015 return;
1016
1017 wxDDEClient client;
71307412 1018 wxConnectionBase *conn = client.MakeConnection(wxEmptyString, m_server, m_topic);
ca289436
VZ
1019 if ( !conn )
1020 {
1021 wxLogError(_T("Failed to connect to the DDE server '%s'."),
1022 m_server.c_str());
1023 }
1024 else
1025 {
1026 if ( !conn->Request(m_cmdDde) )
1027 {
1028 wxLogError(_T("Failed to send request '%s' via DDE."),
1029 m_cmdDde.c_str());
1030 }
1031 else
1032 {
1033 wxLogStatus(_T("Successfully sent DDE request."));
1034 }
1035 }
1036}
1037
1038#endif // __WINDOWS__
1039
50567b69
VZ
1040// ----------------------------------------------------------------------------
1041// various helpers
1042// ----------------------------------------------------------------------------
1043
cd6ce4a9
VZ
1044// input polling
1045void MyFrame::OnIdle(wxIdleEvent& event)
1046{
1047 size_t count = m_running.GetCount();
1048 for ( size_t n = 0; n < count; n++ )
1049 {
1050 if ( m_running[n]->HasInput() )
1051 {
1052 event.RequestMore();
1053 }
1054 }
1055}
1056
92a2a7eb
VZ
1057void MyFrame::OnTimer(wxTimerEvent& WXUNUSED(event))
1058{
1059 wxWakeUpIdle();
1060}
1061
f6bcfd97
BP
1062void MyFrame::OnProcessTerminated(MyPipedProcess *process)
1063{
5a8561fc
VZ
1064 RemovePipedProcess(process);
1065}
1066
1067void MyFrame::OnAsyncTermination(MyProcess *process)
1068{
1069 m_allAsync.Remove(process);
1070
1071 delete process;
1072}
1073
1074void MyFrame::AddPipedProcess(MyPipedProcess *process)
1075{
1076 if ( m_running.IsEmpty() )
1077 {
1078 // we want to start getting the timer events to ensure that a
1079 // steady stream of idle events comes in -- otherwise we
1080 // wouldn't be able to poll the child process input
1081 m_timerIdleWakeUp.Start(100);
1082 }
1083 //else: the timer is already running
1084
1085 m_running.Add(process);
1086 m_allAsync.Add(process);
f6bcfd97
BP
1087}
1088
5a8561fc
VZ
1089void MyFrame::RemovePipedProcess(MyPipedProcess *process)
1090{
1091 m_running.Remove(process);
1092
1093 if ( m_running.IsEmpty() )
1094 {
1095 // we don't need to get idle events all the time any more
1096 m_timerIdleWakeUp.Stop();
1097 }
1098}
f6bcfd97
BP
1099
1100void MyFrame::ShowOutput(const wxString& cmd,
1101 const wxArrayString& output,
1102 const wxString& title)
1103{
1104 size_t count = output.GetCount();
1105 if ( !count )
1106 return;
1107
1108 m_lbox->Append(wxString::Format(_T("--- %s of '%s' ---"),
1109 title.c_str(), cmd.c_str()));
1110
1111 for ( size_t n = 0; n < count; n++ )
1112 {
1113 m_lbox->Append(output[n]);
1114 }
1115
eb671557
VZ
1116 m_lbox->Append(wxString::Format(_T("--- End of %s ---"),
1117 title.Lower().c_str()));
f6bcfd97
BP
1118}
1119
69c33c6c
VZ
1120// ----------------------------------------------------------------------------
1121// MyProcess
1122// ----------------------------------------------------------------------------
1123
1124void MyProcess::OnTerminate(int pid, int status)
1125{
1126 wxLogStatus(m_parent, _T("Process %u ('%s') terminated with exit code %d."),
1127 pid, m_cmd.c_str(), status);
1128
5a8561fc 1129 m_parent->OnAsyncTermination(this);
69c33c6c 1130}
d8e41d42 1131
cd6ce4a9
VZ
1132// ----------------------------------------------------------------------------
1133// MyPipedProcess
1134// ----------------------------------------------------------------------------
1135
1136bool MyPipedProcess::HasInput()
d8e41d42 1137{
07850a49 1138 bool hasInput = false;
f6bcfd97 1139
92a2a7eb 1140 if ( IsInputAvailable() )
cd6ce4a9 1141 {
92a2a7eb 1142 wxTextInputStream tis(*GetInputStream());
cd6ce4a9
VZ
1143
1144 // this assumes that the output is always line buffered
1145 wxString msg;
f6bcfd97 1146 msg << m_cmd << _T(" (stdout): ") << tis.ReadLine();
d8e41d42 1147
cd6ce4a9
VZ
1148 m_parent->GetLogListBox()->Append(msg);
1149
07850a49 1150 hasInput = true;
cd6ce4a9 1151 }
f6bcfd97 1152
92a2a7eb 1153 if ( IsErrorAvailable() )
d8e41d42 1154 {
92a2a7eb 1155 wxTextInputStream tis(*GetErrorStream());
f6bcfd97
BP
1156
1157 // this assumes that the output is always line buffered
1158 wxString msg;
1159 msg << m_cmd << _T(" (stderr): ") << tis.ReadLine();
1160
1161 m_parent->GetLogListBox()->Append(msg);
1162
07850a49 1163 hasInput = true;
d8e41d42 1164 }
f6bcfd97
BP
1165
1166 return hasInput;
cd6ce4a9
VZ
1167}
1168
1169void MyPipedProcess::OnTerminate(int pid, int status)
1170{
1171 // show the rest of the output
1172 while ( HasInput() )
1173 ;
1174
1175 m_parent->OnProcessTerminated(this);
d8e41d42
VZ
1176
1177 MyProcess::OnTerminate(pid, status);
1178}
f6bcfd97
BP
1179
1180// ----------------------------------------------------------------------------
1181// MyPipedProcess2
1182// ----------------------------------------------------------------------------
1183
1184bool MyPipedProcess2::HasInput()
1185{
11fdee42 1186 if ( !m_input.empty() )
f6bcfd97
BP
1187 {
1188 wxTextOutputStream os(*GetOutputStream());
1189 os.WriteString(m_input);
1190
1191 CloseOutput();
1192 m_input.clear();
1193
1194 // call us once again - may be we'll have output
07850a49 1195 return true;
f6bcfd97
BP
1196 }
1197
1198 return MyPipedProcess::HasInput();
1199}
eb671557
VZ
1200
1201// ============================================================================
1202// MyPipeFrame implementation
1203// ============================================================================
1204
1205MyPipeFrame::MyPipeFrame(wxFrame *parent,
1206 const wxString& cmd,
1207 wxProcess *process)
07850a49 1208 : wxFrame(parent, wxID_ANY, cmd),
eb671557
VZ
1209 m_process(process),
1210 // in a real program we'd check that the streams are !NULL here
f6def1fa 1211 m_out(*process->GetOutputStream()),
eb671557 1212 m_in(*process->GetInputStream()),
f6def1fa 1213 m_err(*process->GetErrorStream())
eb671557 1214{
7ca528cb
VZ
1215 m_process->SetNextHandler(this);
1216
07850a49 1217 wxPanel *panel = new wxPanel(this, wxID_ANY);
7ca528cb 1218
71307412 1219 m_textOut = new wxTextCtrl(panel, wxID_ANY, wxEmptyString,
eb671557
VZ
1220 wxDefaultPosition, wxDefaultSize,
1221 wxTE_PROCESS_ENTER);
71307412 1222 m_textIn = new wxTextCtrl(panel, wxID_ANY, wxEmptyString,
1a278e7b
VZ
1223 wxDefaultPosition, wxDefaultSize,
1224 wxTE_MULTILINE | wxTE_RICH);
1225 m_textIn->SetEditable(false);
71307412 1226 m_textErr = new wxTextCtrl(panel, wxID_ANY, wxEmptyString,
1a278e7b
VZ
1227 wxDefaultPosition, wxDefaultSize,
1228 wxTE_MULTILINE | wxTE_RICH);
1229 m_textErr->SetEditable(false);
eb671557
VZ
1230
1231 wxSizer *sizerTop = new wxBoxSizer(wxVERTICAL);
1a278e7b 1232 sizerTop->Add(m_textOut, 0, wxGROW | wxALL, 5);
eb671557
VZ
1233
1234 wxSizer *sizerBtns = new wxBoxSizer(wxHORIZONTAL);
1a278e7b
VZ
1235 sizerBtns->
1236 Add(new wxButton(panel, Exec_Btn_Send, _T("&Send")), 0, wxALL, 5);
1237 sizerBtns->
1238 Add(new wxButton(panel, Exec_Btn_SendFile, _T("&File...")), 0, wxALL, 5);
1239 sizerBtns->
1240 Add(new wxButton(panel, Exec_Btn_Get, _T("&Get")), 0, wxALL, 5);
1241 sizerBtns->
1242 Add(new wxButton(panel, Exec_Btn_Close, _T("&Close")), 0, wxALL, 5);
eb671557
VZ
1243
1244 sizerTop->Add(sizerBtns, 0, wxCENTRE | wxALL, 5);
1a278e7b
VZ
1245 sizerTop->Add(m_textIn, 1, wxGROW | wxALL, 5);
1246 sizerTop->Add(m_textErr, 1, wxGROW | wxALL, 5);
eb671557 1247
7ca528cb 1248 panel->SetSizer(sizerTop);
eb671557
VZ
1249 sizerTop->Fit(this);
1250
1251 Show();
1252}
1253
1a278e7b
VZ
1254void MyPipeFrame::OnBtnSendFile(wxCommandEvent& WXUNUSED(event))
1255{
71307412 1256#if wxUSE_FILEDLG
1a278e7b
VZ
1257 wxFileDialog filedlg(this, _T("Select file to send"));
1258 if ( filedlg.ShowModal() != wxID_OK )
1259 return;
1260
1261 wxFFile file(filedlg.GetFilename(), _T("r"));
1262 wxString data;
1263 if ( !file.IsOpened() || !file.ReadAll(&data) )
1264 return;
1265
1266 // can't write the entire string at once, this risk overflowing the pipe
1267 // and we would dead lock
1268 size_t len = data.length();
1269 const wxChar *pc = data.c_str();
1270 while ( len )
1271 {
1272 const size_t CHUNK_SIZE = 4096;
42d0aa30 1273 m_out.Write(pc, len > CHUNK_SIZE ? CHUNK_SIZE : len);
1a278e7b 1274
42d0aa30
VZ
1275 // note that not all data could have been written as we don't block on
1276 // the write end of the pipe
1277 const size_t lenChunk = m_out.LastWrite();
1a278e7b
VZ
1278
1279 pc += lenChunk;
1280 len -= lenChunk;
1281
1282 DoGet();
1283 }
71307412 1284#endif // wxUSE_FILEDLG
1a278e7b
VZ
1285}
1286
eb671557
VZ
1287void MyPipeFrame::DoGet()
1288{
7ca528cb
VZ
1289 // we don't have any way to be notified when any input appears on the
1290 // stream so we have to poll it :-(
1a278e7b
VZ
1291 DoGetFromStream(m_textIn, m_in);
1292 DoGetFromStream(m_textErr, m_err);
1293}
1294
1295void MyPipeFrame::DoGetFromStream(wxTextCtrl *text, wxInputStream& in)
1296{
1297 while ( in.CanRead() )
1298 {
1299 wxChar buffer[4096];
1300 buffer[in.Read(buffer, WXSIZEOF(buffer) - 1).LastRead()] = _T('\0');
7ca528cb 1301
1a278e7b
VZ
1302 text->AppendText(buffer);
1303 }
1304}
1305
1306void MyPipeFrame::DoClose()
1307{
1308 m_process->CloseOutput();
1309
1310 DisableInput();
1311}
1312
1313void MyPipeFrame::DisableInput()
1314{
1315 m_textOut->SetEditable(false);
1316 FindWindow(Exec_Btn_Send)->Disable();
1317 FindWindow(Exec_Btn_SendFile)->Disable();
1318 FindWindow(Exec_Btn_Close)->Disable();
1319}
1320
1321void MyPipeFrame::DisableOutput()
1322{
1323 FindWindow(Exec_Btn_Get)->Disable();
eb671557
VZ
1324}
1325
1326void MyPipeFrame::OnClose(wxCloseEvent& event)
1327{
7ca528cb
VZ
1328 if ( m_process )
1329 {
1330 // we're not interested in getting the process termination notification
1331 // if we are closing it ourselves
1332 wxProcess *process = m_process;
1333 m_process = NULL;
1334 process->SetNextHandler(NULL);
1335
1336 process->CloseOutput();
1337 }
eb671557
VZ
1338
1339 event.Skip();
1340}
1341
87728739 1342void MyPipeFrame::OnProcessTerm(wxProcessEvent& WXUNUSED(event))
7ca528cb 1343{
1a278e7b
VZ
1344 DoGet();
1345
7ca528cb
VZ
1346 delete m_process;
1347 m_process = NULL;
1348
1349 wxLogWarning(_T("The other process has terminated, closing"));
1350
1a278e7b
VZ
1351 DisableInput();
1352 DisableOutput();
7ca528cb 1353}