]> git.saurik.com Git - wxWidgets.git/blob - src/unix/appunix.cpp
Fix wxHtmlHelpData::SetTempDir() to behave correctly without trailing slash.
[wxWidgets.git] / src / unix / appunix.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/unix/appunix.cpp
3 // Purpose: wxAppConsole with wxMainLoop implementation
4 // Author: Lukasz Michalski
5 // Created: 28/01/2005
6 // Copyright: (c) Lukasz Michalski
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
9
10 #include "wx/wxprec.h"
11
12 #ifdef __BORLANDC__
13 #pragma hdrstop
14 #endif
15
16 #ifndef WX_PRECOMP
17 #include "wx/app.h"
18 #include "wx/log.h"
19 #endif
20
21 #include "wx/evtloop.h"
22 #include "wx/scopedptr.h"
23 #include "wx/unix/private/wakeuppipe.h"
24 #include "wx/private/fdiodispatcher.h"
25 #include "wx/private/fdioeventloopsourcehandler.h"
26
27 #include <signal.h>
28 #include <unistd.h>
29
30 #ifndef SA_RESTART
31 // don't use for systems which don't define it (at least VMS and QNX)
32 #define SA_RESTART 0
33 #endif
34
35 // ----------------------------------------------------------------------------
36 // Helper class calling CheckSignal() on wake up
37 // ----------------------------------------------------------------------------
38
39 namespace
40 {
41
42 class SignalsWakeUpPipe : public wxWakeUpPipe
43 {
44 public:
45 // Ctor automatically registers this pipe with the event loop.
46 SignalsWakeUpPipe()
47 {
48 m_source = wxEventLoopBase::AddSourceForFD
49 (
50 GetReadFd(),
51 this,
52 wxEVENT_SOURCE_INPUT
53 );
54 }
55
56 virtual void OnReadWaiting()
57 {
58 // The base class wxWakeUpPipe::OnReadWaiting() needs to be called in order
59 // to read the data out of the wake up pipe and clear it for next time.
60 wxWakeUpPipe::OnReadWaiting();
61
62 if ( wxTheApp )
63 wxTheApp->CheckSignal();
64 }
65
66 virtual ~SignalsWakeUpPipe()
67 {
68 delete m_source;
69 }
70
71 private:
72 wxEventLoopSource* m_source;
73 };
74
75 } // anonymous namespace
76
77 wxAppConsole::wxAppConsole()
78 {
79 m_signalWakeUpPipe = NULL;
80 }
81
82 wxAppConsole::~wxAppConsole()
83 {
84 delete m_signalWakeUpPipe;
85 }
86
87 // use unusual names for arg[cv] to avoid clashes with wxApp members with the
88 // same names
89 bool wxAppConsole::Initialize(int& argc_, wxChar** argv_)
90 {
91 if ( !wxAppConsoleBase::Initialize(argc_, argv_) )
92 return false;
93
94 sigemptyset(&m_signalsCaught);
95
96 return true;
97 }
98
99 // The actual signal handler. It does as little as possible (because very few
100 // things are safe to do from inside a signal handler) and just ensures that
101 // CheckSignal() will be called later from SignalsWakeUpPipe::OnReadWaiting().
102 void wxAppConsole::HandleSignal(int signal)
103 {
104 wxAppConsole * const app = wxTheApp;
105 if ( !app )
106 return;
107
108 // Register the signal that is caught.
109 sigaddset(&(app->m_signalsCaught), signal);
110
111 // Wake up the application for handling the signal.
112 //
113 // Notice that we must have a valid wake up pipe here as we only install
114 // our signal handlers after allocating it.
115 app->m_signalWakeUpPipe->WakeUpNoLock();
116 }
117
118 void wxAppConsole::CheckSignal()
119 {
120 for ( SignalHandlerHash::iterator it = m_signalHandlerHash.begin();
121 it != m_signalHandlerHash.end();
122 ++it )
123 {
124 int sig = it->first;
125 if ( sigismember(&m_signalsCaught, sig) )
126 {
127 sigdelset(&m_signalsCaught, sig);
128 (it->second)(sig);
129 }
130 }
131 }
132
133 wxFDIOHandler* wxAppConsole::RegisterSignalWakeUpPipe(wxFDIODispatcher& dispatcher)
134 {
135 wxCHECK_MSG( m_signalWakeUpPipe, NULL, "Should be allocated" );
136
137 // we need a bridge to wxFDIODispatcher
138 //
139 // TODO: refactor the code so that only wxEventLoopSourceHandler is used
140 wxScopedPtr<wxFDIOHandler>
141 fdioHandler(new wxFDIOEventLoopSourceHandler(m_signalWakeUpPipe));
142
143 if ( !dispatcher.RegisterFD
144 (
145 m_signalWakeUpPipe->GetReadFd(),
146 fdioHandler.get(),
147 wxFDIO_INPUT
148 ) )
149 return NULL;
150
151 return fdioHandler.release();
152 }
153
154 // the type of the signal handlers we use is "void(*)(int)" while the real
155 // signal handlers are extern "C" and so have incompatible type and at least
156 // Sun CC warns about it, so use explicit casts to suppress these warnings as
157 // they should be harmless
158 extern "C"
159 {
160 typedef void (*SignalHandler_t)(int);
161 }
162
163 bool wxAppConsole::SetSignalHandler(int signal, SignalHandler handler)
164 {
165 const bool install = (SignalHandler_t)handler != SIG_DFL &&
166 (SignalHandler_t)handler != SIG_IGN;
167
168 if ( !m_signalWakeUpPipe )
169 {
170 // Create the pipe that the signal handler will use to cause the event
171 // loop to call wxAppConsole::CheckSignal().
172 m_signalWakeUpPipe = new SignalsWakeUpPipe();
173 }
174
175 struct sigaction sa;
176 memset(&sa, 0, sizeof(sa));
177 sa.sa_handler = (SignalHandler_t)&wxAppConsole::HandleSignal;
178 sa.sa_flags = SA_RESTART;
179 int res = sigaction(signal, &sa, 0);
180 if ( res != 0 )
181 {
182 wxLogSysError(_("Failed to install signal handler"));
183 return false;
184 }
185
186 if ( install )
187 m_signalHandlerHash[signal] = handler;
188 else
189 m_signalHandlerHash.erase(signal);
190
191 return true;
192 }
193