Bumped copyright dates for 2013
[barry.git] / desktop / src / exechelper.h
blob784f4addc5a55ad8181948cab5ccd6c46850561f
1 ///
2 /// \file exechelper.h
3 /// Helper class to wrap wxProcess and wxExecute operations
4 ///
6 /*
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__
25 #include <wx/wx.h>
26 #include <wx/process.h>
27 #include <time.h>
29 class ExecHelper;
31 class TermCatcher
33 friend class ExecHelper;
35 wxEvtHandler *m_handler;
36 int m_id;
37 ExecHelper *m_eh;
39 public:
40 TermCatcher(wxEvtHandler *handler = 0, int id = 0)
41 : m_handler(handler)
42 , m_id(id)
43 , m_eh(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)
58 if( m_handler ) {
59 wxProcessEvent pe(m_id, pid, status);
60 m_handler->AddPendingEvent(pe);
66 // ExecHelper
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.
71 ///
72 /// If ExecHelper is destroyed before the app exits, the callback
73 /// will be "lost", but the AppCallback class will cleanup after itself.
74 ///
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.
80 ///
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.
86 ///
87 class ExecHelper
89 friend class TermCatcher;
91 protected:
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;
98 public:
99 AppCallback(ExecHelper *container)
100 : m_container(container)
104 void Detach()
106 m_container = 0;
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;
117 // signal if legal
118 if( m_container->m_catcher ) {
119 try {
120 m_container->m_catcher->ExecTerminated(pid, status);
122 catch( ... ) {
123 // we are fully responsible
124 // for cleaning ourselves up,
125 // so do that, and then re-
126 // throw, and hope for the
127 // best...
128 delete this;
129 throw;
134 // cleanup
135 delete this;
139 TermCatcher *m_catcher;
140 AppCallback *m_app_callback;
141 int m_app_pid;
142 int m_app_status;
143 time_t m_started;
145 protected:
146 // helper functions
147 void RunError(wxWindow *parent, const wxString &msg);
148 int Execute(bool use_wx, const wxString &command, AppCallback *cb);
150 public:
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);
176 #endif