3 /// Helper class to wrap wxProcess and wxExecute operations
7 Copyright (C) 2010-2013, Chris Frey <cdfrey@foursquare.net>
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
18 See the GNU General Public License in the COPYING file at the
19 root directory of this project for more details.
22 #ifndef __BARRYDESKTOP_EXECHELPER_H__
23 #define __BARRYDESKTOP_EXECHELPER_H__
26 #include <wx/process.h>
33 friend class ExecHelper
;
35 wxEvtHandler
*m_handler
;
40 TermCatcher(wxEvtHandler
*handler
= 0, int id
= 0)
47 virtual ~TermCatcher();
49 // WARNING: this can be called from another thread when not
50 // using wxWidgets' exec code... it may not be possible to
51 // safely call GUI functions from this callback on all platforms.
53 // By default it just posts a wxProcessEvent(windowid, pid, status)
54 // which is thread-safe. Add a EVT_END_PROCESS(windowid, func)
55 // handler to your event table to handle this.
56 virtual void ExecTerminated(int pid
, int status
)
59 wxProcessEvent
pe(m_id
, pid
, status
);
60 m_handler
->AddPendingEvent(pe
);
68 /// Wrapper around the wxProcess class, that does much of the same
69 /// stuff, but also stores the child process's status code without
70 /// requiring a virtual override.
72 /// If ExecHelper is destroyed before the app exits, the callback
73 /// will be "lost", but the AppCallback class will cleanup after itself.
75 /// If you specify a TermCatcher pointer, then as long as TermCatcher
76 /// and ExecHelper exist, you will get an event via the virtual
77 /// ExecTerminated() call. If either ExecHelper or TermCatcher
78 /// go out of scope before that happens, the callback will be "lost"
79 /// but everything will be cleaned up automatically.
81 /// The idea: Create a class where your real work happens, and derive
82 /// that class from TermCatcher. Then create an instance
83 /// of ExecHelper inside that class, and pass 'this' to its
84 /// constructor. If this is a dialog class that disappears
85 /// before the app exits, the destructors will handle things automatically.
89 friend class TermCatcher
;
92 // This funky class is required because wxProcess deletes itself,
93 // so that if ExecHelper is deleted before AppCallback, a segfault
94 // is not caused by the OnTerminate() call.
95 class AppCallback
: public wxProcess
97 ExecHelper
*m_container
;
99 AppCallback(ExecHelper
*container
)
100 : m_container(container
)
109 // virtual overrides (wxProcess)
110 virtual void OnTerminate(int pid
, int status
)
112 if( m_container
&& this == m_container
->m_app_callback
) {
113 m_container
->m_app_pid
= -1;
114 m_container
->m_app_status
= status
;
115 m_container
->m_app_callback
= 0;
118 if( m_container
->m_catcher
) {
120 m_container
->m_catcher
->ExecTerminated(pid
, status
);
123 // we are fully responsible
124 // for cleaning ourselves up,
125 // so do that, and then re-
126 // throw, and hope for the
139 TermCatcher
*m_catcher
;
140 AppCallback
*m_app_callback
;
147 void RunError(wxWindow
*parent
, const wxString
&msg
);
148 int Execute(bool use_wx
, const wxString
&command
, AppCallback
*cb
);
151 /// It is safe to pass a NULL catcher here. No default is
152 /// specified so that the compiler helps prevent forgetfulness.
153 ExecHelper(TermCatcher
*catcher
);
154 virtual ~ExecHelper();
156 time_t GetStartTime() const { return m_started
; }
158 /// Runs the Application, if not already running.. parent may
159 /// be NULL if you don't want this class to pop up error messages
160 /// if unable to run the app. The 'appname' argument is a
161 /// user-friendly name for the application you are running.
162 virtual bool Run(wxWindow
*parent
, const std::string
&appname
,
163 const wxString
&command
);
164 /// Returns true if App is currently running
165 virtual bool IsAppRunning();
166 /// Blocks until child exits
167 virtual void WaitForChild();
168 /// Returns raw status code: see waitpid() for info on how to use it
169 virtual int GetRawAppStatus() const { return m_app_status
; }
170 /// Returns child's exit code
171 virtual int GetChildExitCode() const;
172 /// Sends a termination signal to the App, if running
173 virtual void KillApp(bool hardkill
= false);