00001
00025
00026
00027 #include <config.h>
00028 #include "panoinc_WX.h"
00029 #include "panoinc.h"
00030
00031 #include <errno.h>
00032
00033 #include "base_wx/wxPlatform.h"
00034
00035 #include "wx/ffile.h"
00036 #include "wx/process.h"
00037 #include "wx/mimetype.h"
00038
00039 #ifdef __WINDOWS__
00040 #include "wx/dde.h"
00041 #include <windows.h>
00042 #include <tlhelp32.h>
00043 #else
00044 #include <sys/types.h>
00045 #include <signal.h>
00046 #include <unistd.h>
00047 #endif // __WINDOWS__
00048
00049
00050 #ifdef __WXMAC__
00051 #include <iostream>
00052 #include <stdio.h>
00053 #include "wx/utils.h"
00054 #endif
00055
00056 #include "MyExternalCmdExecDialog.h"
00057 #include "hugin/config_defaults.h"
00058
00059
00060 using namespace std;
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074 enum
00075 {
00076
00077 Exec_Btn_Cancel = 1000,
00078 };
00079
00080
00081
00082
00083
00084
00085 BEGIN_EVENT_TABLE(MyExecPanel, wxPanel)
00086
00087 EVT_TIMER(wxID_ANY, MyExecPanel::OnTimer)
00088 END_EVENT_TABLE()
00089
00090
00091
00092
00093
00094
00095
00096
00097 MyExecPanel::MyExecPanel(wxWindow * parent)
00098 : wxPanel(parent),
00099 m_timerIdleWakeUp(this)
00100 {
00101 m_pidLast = 0;
00102
00103 wxBoxSizer * topsizer = new wxBoxSizer( wxVERTICAL );
00104
00105 #ifdef HUGIN_EXEC_LISTBOX
00106 m_lbox = new wxListBox(this, wxID_ANY);
00107 m_lbox->Append(m_currLine);
00108 #else
00109 m_textctrl = new wxTextCtrl(this, wxID_ANY, _T(""), wxDefaultPosition, wxDefaultSize, wxTE_MULTILINE|wxTE_READONLY);
00110 m_lastLineStart = 0;
00111 #endif
00112
00113 #ifdef __WXMAC__
00114 wxFont font(10, wxFONTFAMILY_TELETYPE, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL);
00115 #else
00116 wxFont font(8, wxFONTFAMILY_TELETYPE, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL);
00117 #endif
00118
00119 if ( font.Ok() ) {
00120 #ifdef HUGIN_EXEC_LISTBOX
00121 m_lbox->SetFont(font);
00122 #else
00123 m_textctrl->SetFont(font);
00124 #endif
00125 }
00126
00127 #ifdef HUGIN_EXEC_LISTBOX
00128 topsizer->Add(m_lbox, 1, wxEXPAND | wxALL, 10);
00129 #else
00130 topsizer->Add(m_textctrl, 1, wxEXPAND | wxALL, 10);
00131 #endif
00132
00133
00134
00135
00136 SetSizer( topsizer );
00137
00138 }
00139
00140 void MyExecPanel::KillProcess()
00141 {
00142 if (m_pidLast) {
00143 #ifdef __WXMSW__
00144 DEBUG_DEBUG("Killing process " << m_pidLast << " with sigkill");
00145 wxKillError rc = wxProcess::Kill(m_pidLast, wxSIGKILL, wxKILL_CHILDREN);
00146 #else
00147 DEBUG_DEBUG("Killing process " << m_pidLast << " with sigterm");
00148 wxKillError rc = wxProcess::Kill(m_pidLast, wxSIGTERM, wxKILL_CHILDREN);
00149 #endif
00150 if ( rc != wxKILL_OK ) {
00151 static const wxChar *errorText[] =
00152 {
00153 _T(""),
00154 _T("signal not supported"),
00155 _T("permission denied"),
00156 _T("no such process"),
00157 _T("unspecified error"),
00158 };
00159
00160 wxLogError(_("Failed to kill process %ld, error %d: %s"),
00161 m_pidLast, rc, errorText[rc]);
00162 }
00163 }
00164 }
00165
00167 void MyExecPanel::PauseProcess(bool pause)
00168 {
00169 #ifdef __WXMSW__
00170 HANDLE hProcessSnapshot = NULL;
00171 HANDLE hThreadSnapshot = NULL;
00172 PROCESSENTRY32 pEntry = {0};
00173 THREADENTRY32 tEntry = {0};
00174
00175
00176 hProcessSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
00177
00178 if (hProcessSnapshot == INVALID_HANDLE_VALUE)
00179 wxLogError(_("Error pausing process %ld, code 1"),m_pidLast);
00180 else
00181 {
00182 pEntry.dwSize = sizeof(PROCESSENTRY32);
00183 tEntry.dwSize = sizeof(THREADENTRY32);
00184
00185
00186 if(Process32First(hProcessSnapshot, &pEntry))
00187 {
00188 do
00189 {
00190
00191 if((pEntry.th32ProcessID == m_pidLast) || (pEntry.th32ParentProcessID == m_pidLast))
00192 {
00193
00194 hThreadSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
00195 if (hThreadSnapshot == INVALID_HANDLE_VALUE)
00196 wxLogError(_("Error pausing process %ld, code 2"),m_pidLast);
00197
00198
00199 if(Thread32First(hThreadSnapshot, &tEntry))
00200 {
00201 do
00202 {
00203
00204 if(tEntry.th32OwnerProcessID == pEntry.th32ProcessID)
00205 {
00206 HANDLE hThread = OpenThread(THREAD_SUSPEND_RESUME, FALSE, tEntry.th32ThreadID);
00207 if(pause)
00208 SuspendThread(hThread);
00209 else
00210 ResumeThread(hThread);
00211 CloseHandle(hThread);
00212 }
00213 }while(Thread32Next(hThreadSnapshot, &tEntry));
00214 }
00215 CloseHandle(hThreadSnapshot);
00216 }
00217 }while(Process32Next(hProcessSnapshot, &pEntry));
00218 }
00219 }
00220 CloseHandle(hProcessSnapshot);
00221 #else
00222
00223 if(pause)
00224 killpg(m_pidLast,SIGSTOP);
00225 else
00226 killpg(m_pidLast,SIGCONT);
00227 #endif //__WXMSW__
00228 }
00229
00230 void MyExecPanel::ContinueProcess()
00231 {
00232 PauseProcess(false);
00233 }
00234
00235 long MyExecPanel::GetPid()
00236 {
00237 return m_pidLast;
00238 }
00239
00240 int MyExecPanel::ExecWithRedirect(wxString cmd)
00241 {
00242 if ( !cmd )
00243 return -1;
00244
00245
00246 #if defined __WXMAC__ && defined __ppc__
00247 int osVersionMajor;
00248 int osVersionMinor;
00249
00250 int os = wxGetOsVersion(&osVersionMajor, &osVersionMinor);
00251
00252 cout << "osVersionCheck: os is " << os << "\n" << endl;
00253 cout << "osVersionCheck: osVersionMajor = " << osVersionMajor << endl;
00254 cout << "osVersionCheck: osVersionMinor = " << osVersionMinor << endl;
00255 if ((osVersionMajor == 0x10) && (osVersionMinor >= 0x50))
00256 {
00257
00258
00259 signal(SIGCHLD,SIG_IGN);
00260 cout << "osVersionCheck: Leopard loop 1" << endl;
00261 }
00262 else
00263 {
00264 cout << "osVersionCheck: Tiger loop 1" << endl;
00265 }
00266 #endif
00267
00268 MyPipedProcess *process = new MyPipedProcess(this, cmd);
00269 m_pidLast = wxExecute(cmd, wxEXEC_ASYNC|wxEXEC_MAKE_GROUP_LEADER, process);
00270 if ( m_pidLast == 0 )
00271 {
00272 wxLogError(_T("Execution of '%s' failed."), cmd.c_str());
00273 delete process;
00274 return -1;
00275 }
00276 else
00277 {
00278 AddAsyncProcess(process);
00279 #ifndef __WINDOWS__
00280
00281
00282 setpgid(m_pidLast,m_pidLast);
00283 #endif
00284 }
00285 m_cmdLast = cmd;
00286 return 0;
00287 }
00288
00289 void MyExecPanel::AddAsyncProcess(MyPipedProcess *process)
00290 {
00291 if ( m_running.IsEmpty() )
00292 {
00293
00294
00295
00296 m_timerIdleWakeUp.Start(200);
00297 }
00298
00299
00300 m_running.Add(process);
00301 }
00302
00303
00304 void MyExecPanel::RemoveAsyncProcess(MyPipedProcess *process)
00305 {
00306 m_running.Remove(process);
00307
00308 if ( m_running.IsEmpty() )
00309 {
00310
00311 m_timerIdleWakeUp.Stop();
00312 }
00313 }
00314
00315
00316
00317
00318
00319
00320 void MyExecPanel::AddToOutput(wxInputStream & s)
00321 {
00322 DEBUG_TRACE("");
00323 wxTextInputStream ts(s);
00324 #if HUGIN_EXEC_LISTBOX
00325 while(s.CanRead()) {
00326 wxChar c = ts.GetChar();
00327 if (c == '\b') {
00328 m_currLine.RemoveLast();
00329 } else if (c == 0x0d) {
00330
00331 m_currLine.clear();
00332 } else if (c == '\n') {
00333
00334 m_lbox->SetString(m_lbox->GetCount()-1, m_currLine);
00335 m_currLine.clear();
00336 m_lbox->Append(m_currLine);
00337 } else {
00338 m_currLine.Append(c);
00339 }
00340 }
00341 m_lbox->SetString(m_lbox->GetCount()-1, m_currLine);
00342
00343 #else
00344
00345 #ifdef HUGIN_EXEC_AVOID_STREAM_GETCHAR
00346 while(s.CanRead()) {
00347 wxString buffer = ts.ReadLine() + wxT("\n");
00348 while(true) {
00349 int pos = buffer.Find(wxChar('\b'));
00350 if(pos == wxNOT_FOUND)
00351 break;
00352 else if(pos == 0)
00353 buffer = buffer.erase(0,1);
00354 else
00355 buffer = buffer.erase(pos-1,2);
00356 }
00357 buffer = buffer.AfterLast(wxChar(0x0d));
00358 m_textctrl->AppendText(buffer);
00359 }
00360 return;
00361 #endif
00362 bool lastCR= false;
00363 wxString currLine = m_textctrl->GetRange(m_lastLineStart, m_textctrl->GetLastPosition());
00364 while(s.CanRead()) {
00365 wxChar c = ts.GetChar();
00366 if (c == '\b') {
00367 lastCR=false;
00368
00369 if (currLine.size() > 0) {
00370 if (currLine.Last() != wxChar('\n') )
00371 currLine.Trim();
00372 }
00373
00374
00375
00376
00377 } else if (c == 0x0d) {
00378 lastCR=true;
00379 #ifndef __WXMSW__
00380
00381 if (currLine.Last() != wxChar('\n') ) {
00382 currLine = currLine.BeforeLast('\n');
00383 if(currLine.size() > 0) {
00384 currLine.Append('\n');
00385 }
00386 }
00387 #endif
00388 } else if (c == '\n') {
00389 currLine.Append(c);
00390 lastCR=false;
00391 } else {
00392 #ifdef __WXMSW__
00393 if (lastCR) {
00394
00395 if (currLine.Last() != wxChar('\n') ) {
00396 currLine = currLine.BeforeLast('\n');
00397 if(currLine.size() > 0) {
00398 currLine.Append('\n');
00399 }
00400 }
00401 }
00402 #endif
00403 currLine.Append(c);
00404 lastCR=false;
00405 }
00406 }
00407
00408 m_textctrl->Replace(m_lastLineStart, m_textctrl->GetLastPosition(), currLine);
00409 size_t lret = currLine.find_last_of(wxChar('\n'));
00410 if (lret > 0 && lret+1 < currLine.size()) {
00411 m_lastLineStart += lret+1;
00412 }
00413 #endif
00414 }
00415
00416 void MyExecPanel::OnTimer(wxTimerEvent& WXUNUSED(event))
00417 {
00418
00419
00420 #ifndef HUGIN_EXEC_LISTBOX
00421
00422 #endif
00423 bool changed=false;
00424 size_t count = m_running.GetCount();
00425 for ( size_t n = 0; n < count; n++ )
00426 {
00427 while ( m_running[n]->IsInputAvailable() )
00428 {
00429 AddToOutput(*(m_running[n]->GetInputStream()));
00430 changed=true;
00431 }
00432 while ( m_running[n]->IsErrorAvailable() )
00433 {
00434 AddToOutput(*(m_running[n]->GetErrorStream()));
00435 changed=true;
00436 }
00437 }
00438 #ifdef HUGIN_EXEC_LISTBOX
00439
00440 #else
00441 if (changed) {
00442 DEBUG_DEBUG("refreshing textctrl");
00443 #ifndef LINE_IO
00444
00445
00446 #endif
00447 }
00448
00449 #endif
00450
00451
00452 #if defined __WXMAC__ && defined __ppc__
00453 int osVersionMajor;
00454 int osVersionMinor;
00455
00456 int os = wxGetOsVersion(&osVersionMajor, &osVersionMinor);
00457
00458 cerr << "osVersionCheck: os is " << os << "\n" << endl;
00459 cerr << "osVersionCheck: osVersionMajor = " << osVersionMajor << endl;
00460 cerr << "osVersionCheck: osVersionMinor = " << osVersionMinor << endl;
00461
00462 if ((osVersionMajor == 0x10) && (osVersionMinor >= 0x50))
00463 {
00464 cerr << "osVersionCheck: Leopard loop 2" << endl;
00465 if(m_pidLast)
00466 {
00467 if(kill((pid_t)m_pidLast,0)!=0)
00468 {
00469 DEBUG_DEBUG("Found terminated process: " << (pid_t)m_pidLast)
00470
00471
00472
00473
00474
00475 if (this->GetParent()) {
00476 wxProcessEvent event( wxID_ANY, m_pidLast, 0);
00477 event.SetEventObject( this );
00478 DEBUG_TRACE("Sending wxProcess event");
00479 this->GetParent()->ProcessEvent( event );
00480 }
00481 }
00482 }
00483 }
00484 else
00485 {
00486 cerr << "osVersionCheck: Tiger loop 2" << endl;
00487 }
00488 #endif
00489 }
00490
00491 void MyExecPanel::OnProcessTerminated(MyPipedProcess *process, int pid, int status)
00492 {
00493 DEBUG_TRACE("process terminated: pid " << pid << " exit code:" << status);
00494
00495 AddToOutput(*(process->GetInputStream()));
00496 AddToOutput(*(process->GetErrorStream()));
00497
00498 RemoveAsyncProcess(process);
00499
00500 if (this->GetParent()) {
00501 wxProcessEvent event( wxID_ANY, pid, status);
00502 event.SetEventObject( this );
00503 DEBUG_TRACE("Sending wxProcess event");
00504 this->GetParent()->GetEventHandler()->ProcessEvent( event );
00505 }
00506
00507 }
00508
00509 MyExecPanel::~MyExecPanel() {
00510 #ifdef HUGIN_EXEC_LISTBOX
00511 delete m_lbox;
00512 #else
00513 delete m_textctrl;
00514 #endif
00515 }
00516
00517 bool MyExecPanel::SaveLog(const wxString &filename)
00518 {
00519 return m_textctrl->SaveFile(filename);
00520 };
00521
00522 void MyExecPanel::CopyLogToClipboard()
00523 {
00524 m_textctrl->SelectAll();
00525 m_textctrl->Copy();
00526 };
00527
00528
00529
00530
00531
00532 void MyProcess::OnTerminate(int pid, int status)
00533 {
00534 DEBUG_TRACE("");
00535
00536
00537
00538
00539
00540 delete this;
00541 }
00542
00543
00544
00545
00546
00547
00548
00549
00550
00551
00552
00553
00554
00555
00556
00557
00558
00559
00560
00561
00562
00563
00564
00565
00566
00567
00568
00569
00570
00571
00572
00573
00574
00575
00576
00577
00578
00579
00580
00581
00582
00583 void MyPipedProcess::OnTerminate(int pid, int status)
00584 {
00585 DEBUG_DEBUG("Process " << pid << " terminated with return code: " << status);
00586 m_parent->OnProcessTerminated(this, pid, status);
00587
00588 MyProcess::OnTerminate(pid, status);
00589 }
00590
00591
00592
00593
00594 BEGIN_EVENT_TABLE(MyExecDialog, wxDialog)
00595 EVT_BUTTON(wxID_CANCEL, MyExecDialog::OnCancel)
00596 EVT_END_PROCESS(wxID_ANY, MyExecDialog::OnProcessTerminate)
00597 END_EVENT_TABLE()
00598
00599
00600
00601
00602 MyExecDialog::MyExecDialog(wxWindow * parent, const wxString& title, const wxPoint& pos, const wxSize& size)
00603 : wxDialog(parent, wxID_ANY, title, pos, size, wxRESIZE_BORDER | wxCAPTION | wxCLOSE_BOX | wxSYSTEM_MENU)
00604 {
00605
00606 wxBoxSizer * topsizer = new wxBoxSizer( wxVERTICAL );
00607 m_execPanel = new MyExecPanel(this);
00608 m_cancelled = false;
00609
00610 topsizer->Add(m_execPanel, 1, wxEXPAND | wxALL, 2);
00611
00612 topsizer->Add( new wxButton(this, wxID_CANCEL, _("Cancel")),
00613 0, wxALL | wxALIGN_RIGHT, 10);
00614
00615 #ifdef __WXMSW__
00616
00617 this->SetBackgroundColour(m_execPanel->GetBackgroundColour());
00618 #endif
00619 SetSizer( topsizer );
00620
00621 }
00622
00623 void MyExecDialog::OnProcessTerminate(wxProcessEvent & event)
00624 {
00625 DEBUG_DEBUG("Process terminated with return code: " << event.GetExitCode());
00626 if(wxConfigBase::Get()->Read(wxT("CopyLogToClipboard"), 0l)==1l)
00627 {
00628 m_execPanel->CopyLogToClipboard();
00629 };
00630 if (m_cancelled) {
00631 EndModal(HUGIN_EXIT_CODE_CANCELLED);
00632 } else {
00633 EndModal(event.GetExitCode());
00634 }
00635 }
00636
00637 void MyExecDialog::OnCancel(wxCommandEvent& WXUNUSED(event))
00638 {
00639 DEBUG_DEBUG("Cancel Pressed");
00640 m_cancelled = true;
00641 m_execPanel->KillProcess();
00642 }
00643
00644
00645 int MyExecDialog::ExecWithRedirect(wxString cmd)
00646 {
00647 if (m_execPanel->ExecWithRedirect(cmd) == -1) {
00648 return -1;
00649 }
00650
00651 return ShowModal();
00652 }
00653
00654 MyExecDialog::~MyExecDialog() {
00655 delete m_execPanel;
00656 }
00657
00658 int MyExecuteCommandOnDialog(wxString command, wxString args, wxWindow* parent,
00659 wxString title, bool isQuoted)
00660 {
00661 if(!isQuoted)
00662 {
00663 command = hugin_utils::wxQuoteFilename(command);
00664 };
00665 wxString cmdline = command + wxT(" ") + args;
00666 MyExecDialog dlg(parent, title,
00667 wxDefaultPosition, wxSize(640, 400));
00668 #ifdef __WXMAC__
00669 dlg.CentreOnParent();
00670 #endif
00671 return dlg.ExecWithRedirect(cmdline);
00672 }
00673
00674
00675
00676 BEGIN_EVENT_TABLE(MyExternalCmdExecDialog, wxDialog)
00677 EVT_IDLE(MyExternalCmdExecDialog::OnIdle)
00678 EVT_TIMER(wxID_ANY, MyExternalCmdExecDialog::OnTimer)
00679 END_EVENT_TABLE()
00680
00681
00682 MyExternalCmdExecDialog::MyExternalCmdExecDialog(wxWindow* parent,
00683 wxWindowID id,
00684 const wxString& title,
00685 const wxPoint& pos,
00686 const wxSize& size,
00687 long style,
00688 const wxString& name)
00689 : wxDialog(parent, id, title, pos, size, style, name),
00690 m_timerIdleWakeUp(this)
00691 {
00692
00693 wxBoxSizer *m_sizer = new wxBoxSizer(wxVERTICAL);
00694 this->SetSizer(m_sizer);
00695 m_tbox = new wxTextCtrl(this, wxID_ANY, _T(""), wxDefaultPosition, wxDefaultSize, wxTE_MULTILINE|wxTE_READONLY);
00696 #ifdef __WXMAC__
00697 wxFont font(12, wxFONTFAMILY_TELETYPE, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL);
00698 #else
00699 wxFont font(8, wxFONTFAMILY_TELETYPE, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL);
00700 #endif
00701 if ( font.Ok() )
00702 m_tbox->SetFont(font);
00703 m_sizer->Add(m_tbox, 1, wxEXPAND);
00704 m_sizer->AddSpacer(30);
00705 }
00706
00707
00708 int MyExternalCmdExecDialog::ShowModal(const wxString &cmd)
00709 {
00710 process = new HuginPipedProcess(this, cmd);
00711
00712 processID = wxExecute(cmd, wxEXEC_ASYNC, process);
00713 if (!processID)
00714 {
00715 delete process;
00716 EndModal(-1);
00717 }
00718 else
00719 {
00720 m_timerIdleWakeUp.Start(200);
00721 }
00722 return wxDialog::ShowModal();
00723 }
00724
00725 int MyExternalCmdExecDialog::Execute(const wxString & cmd)
00726 {
00727 process = new HuginPipedProcess(this, cmd);
00728
00729 m_exitCode = 0;
00730 processID = wxExecute(cmd, wxEXEC_ASYNC, process);
00731 if (!processID)
00732 {
00733 delete process;
00734 EndModal(-1);
00735 }
00736 else
00737 {
00738 m_timerIdleWakeUp.Start(200);
00739 }
00740 return wxDialog::ShowModal();
00741 }
00742
00743 int MyExternalCmdExecDialog::GetExitCode()
00744 {
00745 return m_exitCode;
00746 }
00747
00748 void MyExternalCmdExecDialog::SetExitCode(int ret)
00749 {
00750 m_exitCode = ret;
00751 }
00752
00753
00754 void MyExternalCmdExecDialog::OnTimer(wxTimerEvent& WXUNUSED(event))
00755 {
00756 wxWakeUpIdle();
00757 }
00758
00759 void MyExternalCmdExecDialog::OnIdle(wxIdleEvent& event)
00760 {
00761 if ( process->HasInput() )
00762 {
00763 event.RequestMore();
00764 }
00765
00766
00767 #ifdef __WXMAC__
00768 wxTextCtrl * tb = GetLogTextBox();
00769 tb->SetInsertionPoint(tb->GetLastPosition());
00770 #endif
00771 }
00772
00773 MyExternalCmdExecDialog::~MyExternalCmdExecDialog() {
00774 delete m_tbox;
00775 }
00776
00777
00778
00779 bool HuginPipedProcess::HasInput()
00780 {
00781 bool hasInput = false;
00782
00783 wxTextInputStream tis(*GetInputStream());
00784
00785 if (GetInputStream()->CanRead() )
00786 {
00787 DEBUG_DEBUG("input available");
00788 wxTextCtrl * tb = m_parent->GetLogTextBox();
00789
00790
00791
00792 wxString text = tb->GetValue();
00793
00794 while(GetInputStream()->CanRead())
00795 {
00796 wxChar c = tis.GetChar();
00797 if (c) {
00798 if (c == '\b') {
00799
00800 if (text.Last() != '\n') {
00801 text.RemoveLast();
00802 }
00803 } else if (c == 0x0d) {
00804
00805 text = text.BeforeLast('\n') + wxT("\n");
00806 } else {
00807 text.Append(c);
00808 }
00809 }
00810 }
00811
00812 tb->SetValue(text);
00813 tb->ShowPosition(tb->GetLastPosition());
00814 hasInput = true;
00815 }
00816
00817 wxTextInputStream tes(*GetErrorStream());
00818
00819 if (GetErrorStream()->CanRead())
00820 {
00821 DEBUG_DEBUG("error available");
00822
00823
00824
00825 wxTextCtrl * tb = m_parent->GetLogTextBox();
00826 wxString text = tb->GetValue();
00827
00828 while(GetErrorStream()->CanRead())
00829 {
00830 wxChar c = tes.GetChar();
00831 if (c) {
00832 if (c == '\b') {
00833
00834 if (text.Last() != '\n') {
00835 text.RemoveLast();
00836 }
00837 } else if (c == 0x0d) {
00838
00839 text = text.BeforeLast('\n') + wxT("\n");
00840 } else {
00841 text.Append(c);
00842 }
00843 }
00844 }
00845
00846 tb->SetValue(text);
00847 tb->ShowPosition(tb->GetLastPosition());
00848 hasInput = true;
00849 }
00850 return hasInput;
00851 }
00852
00853 void HuginPipedProcess::OnTerminate(int pid, int status)
00854 {
00855
00856 while ( HasInput() ) ;
00857
00858 m_parent->SetExitCode(status);
00859 m_parent->EndModal(-3);
00860
00861
00862 delete this;
00863 }
00864