]> git.saurik.com Git - wxWidgets.git/blame - samples/exec/exec.cpp
Make sure all Bakefile formats that use CRLF line feeds are set to use CRLF in SVN.
[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
574 static const wxString signalNames[] =
575 {
9a83f860
VZ
576 wxT("Just test (SIGNONE)"),
577 wxT("Hangup (SIGHUP)"),
578 wxT("Interrupt (SIGINT)"),
579 wxT("Quit (SIGQUIT)"),
580 wxT("Illegal instruction (SIGILL)"),
581 wxT("Trap (SIGTRAP)"),
582 wxT("Abort (SIGABRT)"),
583 wxT("Emulated trap (SIGEMT)"),
584 wxT("FP exception (SIGFPE)"),
585 wxT("Kill (SIGKILL)"),
586 wxT("Bus (SIGBUS)"),
587 wxT("Segment violation (SIGSEGV)"),
588 wxT("System (SIGSYS)"),
589 wxT("Broken pipe (SIGPIPE)"),
590 wxT("Alarm (SIGALRM)"),
591 wxT("Terminate (SIGTERM)"),
50567b69
VZ
592 };
593
9a83f860
VZ
594 int sig = wxGetSingleChoiceIndex(wxT("How to kill the process?"),
595 wxT("Exec question"),
50567b69
VZ
596 WXSIZEOF(signalNames), signalNames,
597 this);
598 switch ( sig )
599 {
600 default:
9a83f860 601 wxFAIL_MSG( wxT("unexpected return value") );
50567b69
VZ
602 // fall through
603
604 case -1:
605 // cancelled
606 return;
607
608 case wxSIGNONE:
609 case wxSIGHUP:
610 case wxSIGINT:
611 case wxSIGQUIT:
612 case wxSIGILL:
613 case wxSIGTRAP:
614 case wxSIGABRT:
615 case wxSIGEMT:
616 case wxSIGFPE:
617 case wxSIGKILL:
618 case wxSIGBUS:
619 case wxSIGSEGV:
620 case wxSIGSYS:
621 case wxSIGPIPE:
622 case wxSIGALRM:
623 case wxSIGTERM:
624 break;
625 }
626
627 if ( sig == 0 )
628 {
629 if ( wxProcess::Exists(pid) )
43b2d5e7 630 {
9a83f860 631 wxLogStatus(wxT("Process %ld is running."), pid);
43b2d5e7 632 }
50567b69 633 else
43b2d5e7 634 {
9a83f860 635 wxLogStatus(wxT("No process with pid = %ld."), pid);
43b2d5e7 636 }
50567b69
VZ
637 }
638 else // not SIGNONE
639 {
640 wxKillError rc = wxProcess::Kill(pid, (wxSignal)sig);
641 if ( rc == wxKILL_OK )
642 {
9a83f860 643 wxLogStatus(wxT("Process %ld killed with signal %d."), pid, sig);
50567b69
VZ
644 }
645 else
646 {
647 static const wxChar *errorText[] =
648 {
9a83f860
VZ
649 wxT(""), // no error
650 wxT("signal not supported"),
651 wxT("permission denied"),
652 wxT("no such process"),
653 wxT("unspecified error"),
50567b69
VZ
654 };
655
9a83f860 656 wxLogStatus(wxT("Failed to kill process %ld with signal %d: %s"),
50567b69
VZ
657 pid, sig, errorText[rc]);
658 }
659 }
660}
661
662// ----------------------------------------------------------------------------
663// event handlers: exec menu
664// ----------------------------------------------------------------------------
665
6ba63600
VZ
666void MyFrame::DoAsyncExec(const wxString& cmd)
667{
5a8561fc 668 MyProcess * const process = new MyProcess(this, cmd);
4c1ef422 669 m_pidLast = wxExecute(cmd, wxEXEC_ASYNC, process);
50567b69 670 if ( !m_pidLast )
6ba63600 671 {
9a83f860 672 wxLogError(wxT("Execution of '%s' failed."), cmd.c_str());
6ba63600
VZ
673
674 delete process;
675 }
676 else
677 {
9a83f860 678 wxLogStatus(wxT("Process %ld (%s) launched."), m_pidLast, cmd.c_str());
6ba63600
VZ
679
680 m_cmdLast = cmd;
5a8561fc
VZ
681
682 // the parent frame keeps track of all async processes as it needs to
683 // free them if we exit before the child process terminates
684 AddAsyncProcess(process);
6ba63600
VZ
685 }
686}
687
69c33c6c
VZ
688void MyFrame::OnSyncExec(wxCommandEvent& WXUNUSED(event))
689{
9a83f860 690 wxString cmd = wxGetTextFromUser(wxT("Enter the command: "),
d93c719a 691 DIALOG_TITLE,
69c33c6c
VZ
692 m_cmdLast);
693
694 if ( !cmd )
695 return;
696
9a83f860 697 wxLogStatus( wxT("'%s' is running please wait..."), cmd.c_str() );
d31b7b68 698
4c1ef422 699 int code = wxExecute(cmd, wxEXEC_SYNC);
d31b7b68 700
9a83f860 701 wxLogStatus(wxT("Process '%s' terminated with exit code %d."),
aec18ff7
MB
702 cmd.c_str(), code);
703
69c33c6c
VZ
704 m_cmdLast = cmd;
705}
706
9b6b9e0c
VZ
707void MyFrame::OnSyncNoEventsExec(wxCommandEvent& WXUNUSED(event))
708{
9a83f860 709 wxString cmd = wxGetTextFromUser(wxT("Enter the command: "),
9b6b9e0c
VZ
710 DIALOG_TITLE,
711 m_cmdLast);
712
713 if ( !cmd )
714 return;
715
9a83f860 716 wxLogStatus( wxT("'%s' is running please wait..."), cmd.c_str() );
9b6b9e0c
VZ
717
718 int code = wxExecute(cmd, wxEXEC_BLOCK);
719
9a83f860 720 wxLogStatus(wxT("Process '%s' terminated with exit code %d."),
9b6b9e0c
VZ
721 cmd.c_str(), code);
722
723 m_cmdLast = cmd;
724}
725
69c33c6c
VZ
726void MyFrame::OnAsyncExec(wxCommandEvent& WXUNUSED(event))
727{
9a83f860 728 wxString cmd = wxGetTextFromUser(wxT("Enter the command: "),
d93c719a 729 DIALOG_TITLE,
69c33c6c
VZ
730 m_cmdLast);
731
732 if ( !cmd )
733 return;
734
6ba63600 735 DoAsyncExec(cmd);
69c33c6c
VZ
736}
737
738void MyFrame::OnShell(wxCommandEvent& WXUNUSED(event))
739{
9a83f860 740 wxString cmd = wxGetTextFromUser(wxT("Enter the command: "),
d93c719a 741 DIALOG_TITLE,
69c33c6c
VZ
742 m_cmdLast);
743
744 if ( !cmd )
745 return;
746
747 int code = wxShell(cmd);
9a83f860 748 wxLogStatus(wxT("Shell command '%s' terminated with exit code %d."),
69c33c6c
VZ
749 cmd.c_str(), code);
750 m_cmdLast = cmd;
751}
752
d8e41d42
VZ
753void MyFrame::OnExecWithRedirect(wxCommandEvent& WXUNUSED(event))
754{
69328170
VZ
755 if ( !m_cmdLast )
756 {
757#ifdef __WXMSW__
758 m_cmdLast = "type Makefile.in";
759#else
760 m_cmdLast = "cat -n Makefile";
761#endif
762 }
763
9a83f860 764 wxString cmd = wxGetTextFromUser(wxT("Enter the command: "),
d8e41d42
VZ
765 DIALOG_TITLE,
766 m_cmdLast);
767
768 if ( !cmd )
769 return;
770
cd6ce4a9 771 bool sync;
9a83f860
VZ
772 switch ( wxMessageBox(wxT("Execute it synchronously?"),
773 wxT("Exec question"),
cd6ce4a9 774 wxYES_NO | wxCANCEL | wxICON_QUESTION, this) )
d8e41d42 775 {
cd6ce4a9 776 case wxYES:
07850a49 777 sync = true;
cd6ce4a9 778 break;
d8e41d42 779
cd6ce4a9 780 case wxNO:
07850a49 781 sync = false;
cd6ce4a9
VZ
782 break;
783
784 default:
785 return;
d8e41d42 786 }
cd6ce4a9
VZ
787
788 if ( sync )
d8e41d42 789 {
22386791
VZ
790 wxLogStatus("\"%s\" is running please wait...", cmd);
791
792 wxStopWatch sw;
ce0bb89d 793
f6bcfd97
BP
794 wxArrayString output, errors;
795 int code = wxExecute(cmd, output, errors);
ce0bb89d 796
22386791
VZ
797 wxLogStatus("Command \"%s\" terminated after %ldms; exit code %d.",
798 cmd, sw.Time(), code);
cd6ce4a9
VZ
799
800 if ( code != -1 )
801 {
9a83f860
VZ
802 ShowOutput(cmd, output, wxT("Output"));
803 ShowOutput(cmd, errors, wxT("Errors"));
cd6ce4a9
VZ
804 }
805 }
806 else // async exec
807 {
808 MyPipedProcess *process = new MyPipedProcess(this, cmd);
4c1ef422 809 if ( !wxExecute(cmd, wxEXEC_ASYNC, process) )
cd6ce4a9 810 {
9a83f860 811 wxLogError(wxT("Execution of '%s' failed."), cmd.c_str());
cd6ce4a9
VZ
812
813 delete process;
814 }
815 else
816 {
5a8561fc 817 AddPipedProcess(process);
cd6ce4a9 818 }
d8e41d42 819 }
cd6ce4a9
VZ
820
821 m_cmdLast = cmd;
d8e41d42
VZ
822}
823
f6bcfd97
BP
824void MyFrame::OnExecWithPipe(wxCommandEvent& WXUNUSED(event))
825{
826 if ( !m_cmdLast )
9a83f860 827 m_cmdLast = wxT("tr [a-z] [A-Z]");
f6bcfd97 828
9a83f860 829 wxString cmd = wxGetTextFromUser(wxT("Enter the command: "),
f6bcfd97
BP
830 DIALOG_TITLE,
831 m_cmdLast);
832
833 if ( !cmd )
834 return;
835
9a83f860 836 wxString input = wxGetTextFromUser(wxT("Enter the string to send to it: "),
f6bcfd97
BP
837 DIALOG_TITLE);
838 if ( !input )
839 return;
840
841 // always execute the filter asynchronously
842 MyPipedProcess2 *process = new MyPipedProcess2(this, cmd, input);
aec18ff7 843 long pid = wxExecute(cmd, wxEXEC_ASYNC, process);
f6bcfd97
BP
844 if ( pid )
845 {
9a83f860 846 wxLogStatus(wxT("Process %ld (%s) launched."), pid, cmd.c_str());
f6bcfd97 847
5a8561fc 848 AddPipedProcess(process);
f6bcfd97
BP
849 }
850 else
851 {
9a83f860 852 wxLogError(wxT("Execution of '%s' failed."), cmd.c_str());
f6bcfd97
BP
853
854 delete process;
855 }
856
857 m_cmdLast = cmd;
858}
859
87728739 860void MyFrame::OnPOpen(wxCommandEvent& WXUNUSED(event))
eb671557 861{
9a83f860 862 wxString cmd = wxGetTextFromUser(wxT("Enter the command to launch: "),
eb671557
VZ
863 DIALOG_TITLE,
864 m_cmdLast);
865 if ( cmd.empty() )
866 return;
867
868 wxProcess *process = wxProcess::Open(cmd);
869 if ( !process )
870 {
9a83f860 871 wxLogError(wxT("Failed to launch the command."));
eb671557
VZ
872 return;
873 }
874
9a83f860 875 wxLogVerbose(wxT("PID of the new process: %ld"), process->GetPid());
a387938f 876
eb671557
VZ
877 wxOutputStream *out = process->GetOutputStream();
878 if ( !out )
879 {
9a83f860 880 wxLogError(wxT("Failed to connect to child stdin"));
eb671557
VZ
881 return;
882 }
883
884 wxInputStream *in = process->GetInputStream();
885 if ( !in )
886 {
9a83f860 887 wxLogError(wxT("Failed to connect to child stdout"));
eb671557
VZ
888 return;
889 }
890
891 new MyPipeFrame(this, cmd, process);
892}
893
979a7347 894static wxString gs_lastFile;
6ba63600 895
979a7347
VZ
896static bool AskUserForFileName()
897{
71307412
WS
898 wxString filename;
899
900#if wxUSE_FILEDLG
9a83f860 901 filename = wxLoadFileSelector(wxT("any"), wxEmptyString, gs_lastFile);
ba59de5d 902#else // !wxUSE_FILEDLG
9a83f860 903 filename = wxGetTextFromUser(wxT("Enter the file name"), wxT("exec sample"),
979a7347 904 gs_lastFile);
ba59de5d 905#endif // wxUSE_FILEDLG/!wxUSE_FILEDLG
71307412
WS
906
907 if ( filename.empty() )
979a7347 908 return false;
6ba63600 909
979a7347 910 gs_lastFile = filename;
6ba63600 911
979a7347
VZ
912 return true;
913}
914
915void MyFrame::OnFileExec(wxCommandEvent& WXUNUSED(event))
916{
917 if ( !AskUserForFileName() )
918 return;
919
9a83f860 920 wxString ext = gs_lastFile.AfterLast(wxT('.'));
6ba63600
VZ
921 wxFileType *ft = wxTheMimeTypesManager->GetFileTypeFromExtension(ext);
922 if ( !ft )
923 {
9a83f860 924 wxLogError(wxT("Impossible to determine the file type for extension '%s'"),
6ba63600
VZ
925 ext.c_str());
926 return;
927 }
928
929 wxString cmd;
930 bool ok = ft->GetOpenCommand(&cmd,
979a7347 931 wxFileType::MessageParameters(gs_lastFile));
6ba63600
VZ
932 delete ft;
933 if ( !ok )
934 {
9a83f860 935 wxLogError(wxT("Impossible to find out how to open files of extension '%s'"),
6ba63600
VZ
936 ext.c_str());
937 return;
938 }
939
940 DoAsyncExec(cmd);
941}
942
979a7347
VZ
943void MyFrame::OnFileLaunch(wxCommandEvent& WXUNUSED(event))
944{
945 if ( !AskUserForFileName() )
946 return;
947
948 if ( !wxLaunchDefaultApplication(gs_lastFile) )
949 {
950 wxLogError("Opening \"%s\" in default application failed.", gs_lastFile);
951 }
952}
953
ba59de5d
VZ
954void MyFrame::OnOpenURL(wxCommandEvent& WXUNUSED(event))
955{
9a83f860 956 static wxString s_url(wxT("http://www.wxwidgets.org/"));
ba59de5d
VZ
957
958 wxString filename = wxGetTextFromUser
959 (
9a83f860
VZ
960 wxT("Enter the URL"),
961 wxT("exec sample"),
979a7347 962 s_url,
ba59de5d
VZ
963 this
964 );
965
966 if ( filename.empty() )
967 return;
968
979a7347 969 s_url = filename;
ba59de5d 970
979a7347 971 if ( !wxLaunchDefaultBrowser(s_url) )
43b2d5e7 972 {
9a83f860 973 wxLogError(wxT("Failed to open URL \"%s\""), s_url.c_str());
43b2d5e7 974 }
ba59de5d
VZ
975}
976
50567b69
VZ
977// ----------------------------------------------------------------------------
978// DDE stuff
979// ----------------------------------------------------------------------------
980
d93c719a 981#ifdef __WINDOWS__
ca289436
VZ
982
983bool MyFrame::GetDDEServer()
984{
9a83f860 985 wxString server = wxGetTextFromUser(wxT("Server to connect to:"),
ca289436 986 DIALOG_TITLE, m_server);
d93c719a 987 if ( !server )
07850a49 988 return false;
ca289436
VZ
989
990 m_server = server;
d93c719a 991
9a83f860 992 wxString topic = wxGetTextFromUser(wxT("DDE topic:"), DIALOG_TITLE, m_topic);
d93c719a 993 if ( !topic )
07850a49 994 return false;
d93c719a 995
ca289436
VZ
996 m_topic = topic;
997
9a83f860 998 wxString cmd = wxGetTextFromUser(wxT("DDE command:"), DIALOG_TITLE, m_cmdDde);
d93c719a 999 if ( !cmd )
07850a49 1000 return false;
ca289436
VZ
1001
1002 m_cmdDde = cmd;
1003
07850a49 1004 return true;
ca289436
VZ
1005}
1006
1007void MyFrame::OnDDEExec(wxCommandEvent& WXUNUSED(event))
1008{
1009 if ( !GetDDEServer() )
d93c719a
VZ
1010 return;
1011
1012 wxDDEClient client;
71307412 1013 wxConnectionBase *conn = client.MakeConnection(wxEmptyString, m_server, m_topic);
d93c719a
VZ
1014 if ( !conn )
1015 {
9a83f860 1016 wxLogError(wxT("Failed to connect to the DDE server '%s'."),
ca289436 1017 m_server.c_str());
d93c719a
VZ
1018 }
1019 else
1020 {
ca289436 1021 if ( !conn->Execute(m_cmdDde) )
d93c719a 1022 {
9a83f860 1023 wxLogError(wxT("Failed to execute command '%s' via DDE."),
ca289436 1024 m_cmdDde.c_str());
d93c719a
VZ
1025 }
1026 else
1027 {
9a83f860 1028 wxLogStatus(wxT("Successfully executed DDE command"));
d93c719a
VZ
1029 }
1030 }
d93c719a
VZ
1031}
1032
ca289436
VZ
1033void MyFrame::OnDDERequest(wxCommandEvent& WXUNUSED(event))
1034{
1035 if ( !GetDDEServer() )
1036 return;
1037
1038 wxDDEClient client;
71307412 1039 wxConnectionBase *conn = client.MakeConnection(wxEmptyString, m_server, m_topic);
ca289436
VZ
1040 if ( !conn )
1041 {
9a83f860 1042 wxLogError(wxT("Failed to connect to the DDE server '%s'."),
ca289436
VZ
1043 m_server.c_str());
1044 }
1045 else
1046 {
1047 if ( !conn->Request(m_cmdDde) )
1048 {
9a83f860 1049 wxLogError(wxT("Failed to send request '%s' via DDE."),
ca289436
VZ
1050 m_cmdDde.c_str());
1051 }
1052 else
1053 {
9a83f860 1054 wxLogStatus(wxT("Successfully sent DDE request."));
ca289436
VZ
1055 }
1056 }
1057}
1058
1059#endif // __WINDOWS__
1060
50567b69
VZ
1061// ----------------------------------------------------------------------------
1062// various helpers
1063// ----------------------------------------------------------------------------
1064
cd6ce4a9
VZ
1065// input polling
1066void MyFrame::OnIdle(wxIdleEvent& event)
1067{
1068 size_t count = m_running.GetCount();
1069 for ( size_t n = 0; n < count; n++ )
1070 {
1071 if ( m_running[n]->HasInput() )
1072 {
1073 event.RequestMore();
1074 }
1075 }
1076}
1077
9cd203f7 1078void MyFrame::OnIdleTimer(wxTimerEvent& WXUNUSED(event))
92a2a7eb
VZ
1079{
1080 wxWakeUpIdle();
1081}
1082
9cd203f7
VZ
1083void MyFrame::OnBgTimer(wxTimerEvent& WXUNUSED(event))
1084{
1085 static unsigned long s_ticks = 0;
1086 SetStatusText(wxString::Format("%lu ticks", s_ticks++), 1);
1087}
1088
f6bcfd97
BP
1089void MyFrame::OnProcessTerminated(MyPipedProcess *process)
1090{
5a8561fc
VZ
1091 RemovePipedProcess(process);
1092}
1093
1094void MyFrame::OnAsyncTermination(MyProcess *process)
1095{
1096 m_allAsync.Remove(process);
1097
1098 delete process;
1099}
1100
1101void MyFrame::AddPipedProcess(MyPipedProcess *process)
1102{
1103 if ( m_running.IsEmpty() )
1104 {
1105 // we want to start getting the timer events to ensure that a
1106 // steady stream of idle events comes in -- otherwise we
1107 // wouldn't be able to poll the child process input
1108 m_timerIdleWakeUp.Start(100);
1109 }
1110 //else: the timer is already running
1111
1112 m_running.Add(process);
1113 m_allAsync.Add(process);
f6bcfd97
BP
1114}
1115
5a8561fc
VZ
1116void MyFrame::RemovePipedProcess(MyPipedProcess *process)
1117{
1118 m_running.Remove(process);
1119
1120 if ( m_running.IsEmpty() )
1121 {
1122 // we don't need to get idle events all the time any more
1123 m_timerIdleWakeUp.Stop();
1124 }
1125}
f6bcfd97
BP
1126
1127void MyFrame::ShowOutput(const wxString& cmd,
1128 const wxArrayString& output,
1129 const wxString& title)
1130{
1131 size_t count = output.GetCount();
1132 if ( !count )
1133 return;
1134
9a83f860 1135 m_lbox->Append(wxString::Format(wxT("--- %s of '%s' ---"),
f6bcfd97
BP
1136 title.c_str(), cmd.c_str()));
1137
1138 for ( size_t n = 0; n < count; n++ )
1139 {
1140 m_lbox->Append(output[n]);
1141 }
1142
9a83f860 1143 m_lbox->Append(wxString::Format(wxT("--- End of %s ---"),
eb671557 1144 title.Lower().c_str()));
f6bcfd97
BP
1145}
1146
69c33c6c
VZ
1147// ----------------------------------------------------------------------------
1148// MyProcess
1149// ----------------------------------------------------------------------------
1150
1151void MyProcess::OnTerminate(int pid, int status)
1152{
9a83f860 1153 wxLogStatus(m_parent, wxT("Process %u ('%s') terminated with exit code %d."),
69c33c6c
VZ
1154 pid, m_cmd.c_str(), status);
1155
5a8561fc 1156 m_parent->OnAsyncTermination(this);
69c33c6c 1157}
d8e41d42 1158
cd6ce4a9
VZ
1159// ----------------------------------------------------------------------------
1160// MyPipedProcess
1161// ----------------------------------------------------------------------------
1162
1163bool MyPipedProcess::HasInput()
d8e41d42 1164{
07850a49 1165 bool hasInput = false;
f6bcfd97 1166
92a2a7eb 1167 if ( IsInputAvailable() )
cd6ce4a9 1168 {
92a2a7eb 1169 wxTextInputStream tis(*GetInputStream());
cd6ce4a9
VZ
1170
1171 // this assumes that the output is always line buffered
1172 wxString msg;
9a83f860 1173 msg << m_cmd << wxT(" (stdout): ") << tis.ReadLine();
d8e41d42 1174
cd6ce4a9
VZ
1175 m_parent->GetLogListBox()->Append(msg);
1176
07850a49 1177 hasInput = true;
cd6ce4a9 1178 }
f6bcfd97 1179
92a2a7eb 1180 if ( IsErrorAvailable() )
d8e41d42 1181 {
92a2a7eb 1182 wxTextInputStream tis(*GetErrorStream());
f6bcfd97
BP
1183
1184 // this assumes that the output is always line buffered
1185 wxString msg;
9a83f860 1186 msg << m_cmd << wxT(" (stderr): ") << tis.ReadLine();
f6bcfd97
BP
1187
1188 m_parent->GetLogListBox()->Append(msg);
1189
07850a49 1190 hasInput = true;
d8e41d42 1191 }
f6bcfd97
BP
1192
1193 return hasInput;
cd6ce4a9
VZ
1194}
1195
1196void MyPipedProcess::OnTerminate(int pid, int status)
1197{
1198 // show the rest of the output
1199 while ( HasInput() )
1200 ;
1201
1202 m_parent->OnProcessTerminated(this);
d8e41d42
VZ
1203
1204 MyProcess::OnTerminate(pid, status);
1205}
f6bcfd97
BP
1206
1207// ----------------------------------------------------------------------------
1208// MyPipedProcess2
1209// ----------------------------------------------------------------------------
1210
1211bool MyPipedProcess2::HasInput()
1212{
11fdee42 1213 if ( !m_input.empty() )
f6bcfd97
BP
1214 {
1215 wxTextOutputStream os(*GetOutputStream());
1216 os.WriteString(m_input);
1217
1218 CloseOutput();
1219 m_input.clear();
1220
1221 // call us once again - may be we'll have output
07850a49 1222 return true;
f6bcfd97
BP
1223 }
1224
1225 return MyPipedProcess::HasInput();
1226}
eb671557
VZ
1227
1228// ============================================================================
1229// MyPipeFrame implementation
1230// ============================================================================
1231
1232MyPipeFrame::MyPipeFrame(wxFrame *parent,
1233 const wxString& cmd,
1234 wxProcess *process)
07850a49 1235 : wxFrame(parent, wxID_ANY, cmd),
eb671557
VZ
1236 m_process(process),
1237 // in a real program we'd check that the streams are !NULL here
f6def1fa 1238 m_out(*process->GetOutputStream()),
eb671557 1239 m_in(*process->GetInputStream()),
f6def1fa 1240 m_err(*process->GetErrorStream())
eb671557 1241{
7ca528cb
VZ
1242 m_process->SetNextHandler(this);
1243
07850a49 1244 wxPanel *panel = new wxPanel(this, wxID_ANY);
7ca528cb 1245
71307412 1246 m_textOut = new wxTextCtrl(panel, wxID_ANY, wxEmptyString,
eb671557
VZ
1247 wxDefaultPosition, wxDefaultSize,
1248 wxTE_PROCESS_ENTER);
71307412 1249 m_textIn = new wxTextCtrl(panel, wxID_ANY, wxEmptyString,
1a278e7b
VZ
1250 wxDefaultPosition, wxDefaultSize,
1251 wxTE_MULTILINE | wxTE_RICH);
1252 m_textIn->SetEditable(false);
71307412 1253 m_textErr = new wxTextCtrl(panel, wxID_ANY, wxEmptyString,
1a278e7b
VZ
1254 wxDefaultPosition, wxDefaultSize,
1255 wxTE_MULTILINE | wxTE_RICH);
1256 m_textErr->SetEditable(false);
eb671557
VZ
1257
1258 wxSizer *sizerTop = new wxBoxSizer(wxVERTICAL);
1a278e7b 1259 sizerTop->Add(m_textOut, 0, wxGROW | wxALL, 5);
eb671557
VZ
1260
1261 wxSizer *sizerBtns = new wxBoxSizer(wxHORIZONTAL);
1a278e7b 1262 sizerBtns->
9a83f860 1263 Add(new wxButton(panel, Exec_Btn_Send, wxT("&Send")), 0, wxALL, 5);
1a278e7b 1264 sizerBtns->
9a83f860 1265 Add(new wxButton(panel, Exec_Btn_SendFile, wxT("&File...")), 0, wxALL, 5);
1a278e7b 1266 sizerBtns->
9a83f860 1267 Add(new wxButton(panel, Exec_Btn_Get, wxT("&Get")), 0, wxALL, 5);
1a278e7b 1268 sizerBtns->
9a83f860 1269 Add(new wxButton(panel, Exec_Btn_Close, wxT("&Close")), 0, wxALL, 5);
eb671557
VZ
1270
1271 sizerTop->Add(sizerBtns, 0, wxCENTRE | wxALL, 5);
1a278e7b
VZ
1272 sizerTop->Add(m_textIn, 1, wxGROW | wxALL, 5);
1273 sizerTop->Add(m_textErr, 1, wxGROW | wxALL, 5);
eb671557 1274
7ca528cb 1275 panel->SetSizer(sizerTop);
eb671557
VZ
1276 sizerTop->Fit(this);
1277
1278 Show();
1279}
1280
1a278e7b
VZ
1281void MyPipeFrame::OnBtnSendFile(wxCommandEvent& WXUNUSED(event))
1282{
71307412 1283#if wxUSE_FILEDLG
9a83f860 1284 wxFileDialog filedlg(this, wxT("Select file to send"));
1a278e7b
VZ
1285 if ( filedlg.ShowModal() != wxID_OK )
1286 return;
1287
9a83f860 1288 wxFFile file(filedlg.GetFilename(), wxT("r"));
1a278e7b
VZ
1289 wxString data;
1290 if ( !file.IsOpened() || !file.ReadAll(&data) )
1291 return;
1292
1293 // can't write the entire string at once, this risk overflowing the pipe
1294 // and we would dead lock
1295 size_t len = data.length();
1296 const wxChar *pc = data.c_str();
1297 while ( len )
1298 {
1299 const size_t CHUNK_SIZE = 4096;
42d0aa30 1300 m_out.Write(pc, len > CHUNK_SIZE ? CHUNK_SIZE : len);
1a278e7b 1301
42d0aa30
VZ
1302 // note that not all data could have been written as we don't block on
1303 // the write end of the pipe
1304 const size_t lenChunk = m_out.LastWrite();
1a278e7b
VZ
1305
1306 pc += lenChunk;
1307 len -= lenChunk;
1308
1309 DoGet();
1310 }
71307412 1311#endif // wxUSE_FILEDLG
1a278e7b
VZ
1312}
1313
eb671557
VZ
1314void MyPipeFrame::DoGet()
1315{
7ca528cb
VZ
1316 // we don't have any way to be notified when any input appears on the
1317 // stream so we have to poll it :-(
1a278e7b
VZ
1318 DoGetFromStream(m_textIn, m_in);
1319 DoGetFromStream(m_textErr, m_err);
1320}
1321
1322void MyPipeFrame::DoGetFromStream(wxTextCtrl *text, wxInputStream& in)
1323{
1324 while ( in.CanRead() )
1325 {
1326 wxChar buffer[4096];
9a83f860 1327 buffer[in.Read(buffer, WXSIZEOF(buffer) - 1).LastRead()] = wxT('\0');
7ca528cb 1328
1a278e7b
VZ
1329 text->AppendText(buffer);
1330 }
1331}
1332
1333void MyPipeFrame::DoClose()
1334{
1335 m_process->CloseOutput();
1336
1337 DisableInput();
1338}
1339
1340void MyPipeFrame::DisableInput()
1341{
1342 m_textOut->SetEditable(false);
1343 FindWindow(Exec_Btn_Send)->Disable();
1344 FindWindow(Exec_Btn_SendFile)->Disable();
1345 FindWindow(Exec_Btn_Close)->Disable();
1346}
1347
1348void MyPipeFrame::DisableOutput()
1349{
1350 FindWindow(Exec_Btn_Get)->Disable();
eb671557
VZ
1351}
1352
1353void MyPipeFrame::OnClose(wxCloseEvent& event)
1354{
7ca528cb
VZ
1355 if ( m_process )
1356 {
1357 // we're not interested in getting the process termination notification
1358 // if we are closing it ourselves
1359 wxProcess *process = m_process;
1360 m_process = NULL;
1361 process->SetNextHandler(NULL);
1362
1363 process->CloseOutput();
1364 }
eb671557
VZ
1365
1366 event.Skip();
1367}
1368
87728739 1369void MyPipeFrame::OnProcessTerm(wxProcessEvent& WXUNUSED(event))
7ca528cb 1370{
1a278e7b
VZ
1371 DoGet();
1372
7ca528cb
VZ
1373 delete m_process;
1374 m_process = NULL;
1375
9a83f860 1376 wxLogWarning(wxT("The other process has terminated, closing"));
7ca528cb 1377
1a278e7b
VZ
1378 DisableInput();
1379 DisableOutput();
7ca528cb 1380}