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