]> git.saurik.com Git - wxWidgets.git/blame - src/msw/evtloop.cpp
catch unhandled exceptions in POSIX threads implementation the same way wxMSW does
[wxWidgets.git] / src / msw / evtloop.cpp
CommitLineData
3808e191
JS
1///////////////////////////////////////////////////////////////////////////////
2// Name: msw/evtloop.cpp
3// Purpose: implements wxEventLoop for MSW
4// Author: Vadim Zeitlin
5// Modified by:
6// Created: 01.06.01
7// RCS-ID: $Id$
8// Copyright: (c) 2001 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>
65571936 9// License: wxWindows licence
3808e191
JS
10///////////////////////////////////////////////////////////////////////////////
11
12// ============================================================================
13// declarations
14// ============================================================================
15
16// ----------------------------------------------------------------------------
17// headers
18// ----------------------------------------------------------------------------
19
3808e191
JS
20// For compilers that support precompilation, includes "wx.h".
21#include "wx/wxprec.h"
22
23#ifdef __BORLANDC__
24 #pragma hdrstop
25#endif
26
27#ifndef WX_PRECOMP
81df6af3
VZ
28 #if wxUSE_GUI
29 #include "wx/window.h"
30 #endif
6c0e8b4e 31 #include "wx/app.h"
3808e191
JS
32#endif //WX_PRECOMP
33
34#include "wx/evtloop.h"
4300caa7 35
81df6af3 36
4300caa7
VZ
37#include "wx/except.h"
38#include "wx/ptr_scpd.h"
3808e191
JS
39
40#include "wx/msw/private.h"
41
81df6af3
VZ
42#if wxUSE_GUI
43 #include "wx/tooltip.h"
44 #if wxUSE_THREADS
45 #include "wx/thread.h"
4300caa7 46
81df6af3
VZ
47 // define the list of MSG strutures
48 WX_DECLARE_LIST(MSG, wxMsgList);
4300caa7 49
81df6af3 50 #include "wx/listimpl.cpp"
4300caa7 51
81df6af3
VZ
52 WX_DEFINE_LIST(wxMsgList)
53 #endif // wxUSE_THREADS
54#endif //wxUSE_GUI
55
56#if wxUSE_BASE
0cd7d9b2 57
3808e191 58// ============================================================================
81df6af3 59// wxMSWEventLoopBase implementation
3808e191
JS
60// ============================================================================
61
62// ----------------------------------------------------------------------------
3754265e 63// ctor/dtor
3808e191
JS
64// ----------------------------------------------------------------------------
65
81df6af3 66wxMSWEventLoopBase::wxMSWEventLoopBase()
3754265e
VZ
67{
68 m_shouldExit = false;
69 m_exitcode = 0;
70}
71
72// ----------------------------------------------------------------------------
81df6af3 73// wxEventLoop message processing dispatching
3754265e
VZ
74// ----------------------------------------------------------------------------
75
81df6af3 76bool wxMSWEventLoopBase::Pending() const
3808e191 77{
81df6af3
VZ
78 MSG msg;
79 return ::PeekMessage(&msg, 0, 0, 0, PM_NOREMOVE) != 0;
80}
81
82bool wxMSWEventLoopBase::GetNextMessage(WXMSG* msg)
83{
84 wxCHECK_MSG( IsRunning(), false, _T("can't get messages if not running") );
85
86 const BOOL rc = ::GetMessage(msg, NULL, 0, 0);
87
88 if ( rc == 0 )
3808e191 89 {
81df6af3
VZ
90 // got WM_QUIT
91 return false;
3808e191 92 }
81df6af3
VZ
93
94 if ( rc == -1 )
95 {
96 // should never happen, but let's test for it nevertheless
97 wxLogLastError(wxT("GetMessage"));
98
99 // still break from the loop
100 return false;
101 }
102
103 return true;
3808e191
JS
104}
105
81df6af3
VZ
106#endif // wxUSE_BASE
107
108#if wxUSE_GUI
109
110// ============================================================================
111// GUI wxEventLoop implementation
112// ============================================================================
113
114wxWindowMSW *wxGUIEventLoop::ms_winCritical = NULL;
115
116bool wxGUIEventLoop::IsChildOfCriticalWindow(wxWindowMSW *win)
a7b7500c
VZ
117{
118 while ( win )
119 {
120 if ( win == ms_winCritical )
121 return true;
122
123 win = win->GetParent();
124 }
125
126 return false;
127}
128
81df6af3 129bool wxGUIEventLoop::PreProcessMessage(WXMSG *msg)
3808e191 130{
ac8d0c11 131 HWND hwnd = msg->hwnd;
89c83180 132 wxWindow *wndThis = wxGetWindowFromHWND((WXHWND)hwnd);
a7b7500c 133 wxWindow *wnd;
ac8d0c11 134
18f5234f
DS
135 // this might happen if we're in a modeless dialog, or if a wx control has
136 // children which themselves were not created by wx (i.e. wxActiveX control children)
ac8d0c11
VZ
137 if ( !wndThis )
138 {
18f5234f 139 while ( hwnd && (::GetWindowLong(hwnd, GWL_STYLE) & WS_CHILD ))
ac8d0c11
VZ
140 {
141 hwnd = ::GetParent(hwnd);
89c83180 142
18f5234f
DS
143 // If the control has a wx parent, break and give the parent a chance
144 // to process the window message
145 wndThis = wxGetWindowFromHWND((WXHWND)hwnd);
146 if (wndThis != NULL)
147 break;
ac8d0c11
VZ
148 }
149
18f5234f
DS
150 if ( !wndThis )
151 {
152 // this may happen if the event occurred in a standard modeless dialog (the
153 // only example of which I know of is the find/replace dialog) - then call
154 // IsDialogMessage() to make TAB navigation in it work
155
156 // NOTE: IsDialogMessage() just eats all the messages (i.e. returns true for
157 // them) if we call it for the control itself
158 return hwnd && ::IsDialogMessage(hwnd, msg) != 0;
159 }
ac8d0c11 160 }
3808e191 161
a7b7500c
VZ
162 if ( !AllowProcessing(wndThis) )
163 {
164 // not a child of critical window, so we eat the event but take care to
165 // stop an endless stream of WM_PAINTs which would have resulted if we
166 // didn't validate the invalidated part of the window
167 if ( msg->message == WM_PAINT )
168 ::ValidateRect(hwnd, NULL);
169
170 return true;
171 }
172
3808e191
JS
173#if wxUSE_TOOLTIPS
174 // we must relay WM_MOUSEMOVE events to the tooltip ctrl if we want it to
175 // popup the tooltip bubbles
ac8d0c11 176 if ( msg->message == WM_MOUSEMOVE )
3808e191 177 {
c009bf3e
VZ
178 // we should do it if one of window children has an associated tooltip
179 // (and not just if the window has a tooltip itself)
180 if ( wndThis->HasToolTips() )
181 wxToolTip::RelayEvent((WXMSG *)msg);
3808e191
JS
182 }
183#endif // wxUSE_TOOLTIPS
184
ac8d0c11
VZ
185 // allow the window to prevent certain messages from being
186 // translated/processed (this is currently used by wxTextCtrl to always
187 // grab Ctrl-C/V/X, even if they are also accelerators in some parent)
188 if ( !wndThis->MSWShouldPreProcessMessage((WXMSG *)msg) )
189 {
3754265e 190 return false;
ac8d0c11
VZ
191 }
192
193 // try translations first: the accelerators override everything
3808e191
JS
194 for ( wnd = wndThis; wnd; wnd = wnd->GetParent() )
195 {
ac8d0c11 196 if ( wnd->MSWTranslateMessage((WXMSG *)msg))
3754265e 197 return true;
ac8d0c11
VZ
198
199 // stop at first top level window, i.e. don't try to process the key
200 // strokes originating in a dialog using the accelerators of the parent
201 // frame - this doesn't make much sense
202 if ( wnd->IsTopLevel() )
203 break;
3808e191
JS
204 }
205
22cfea03
JS
206 // now try the other hooks (kbd navigation is handled here)
207 for ( wnd = wndThis; wnd; wnd = wnd->GetParent() )
3808e191 208 {
f6388667
VZ
209 if ( wnd->MSWProcessMessage((WXMSG *)msg) )
210 return true;
c8026dea 211
f6388667
VZ
212 // also stop at first top level window here, just as above because
213 // if we don't do this, pressing ESC on a modal dialog shown as child
214 // of a modal dialog with wxID_CANCEL will cause the parent dialog to
215 // be closed, for example
216 if ( wnd->IsTopLevel() )
22cfea03 217 break;
3808e191
JS
218 }
219
ac8d0c11 220 // no special preprocessing for this message, dispatch it normally
3754265e 221 return false;
cea62f9c
JS
222}
223
81df6af3 224void wxGUIEventLoop::ProcessMessage(WXMSG *msg)
3808e191 225{
81df6af3
VZ
226 // give us the chance to preprocess the message first
227 if ( !PreProcessMessage(msg) )
228 {
229 // if it wasn't done, dispatch it to the corresponding window
230 ::TranslateMessage(msg);
231 ::DispatchMessage(msg);
232 }
3808e191
JS
233}
234
81df6af3 235bool wxGUIEventLoop::Dispatch()
3808e191 236{
3808e191 237 MSG msg;
81df6af3 238 if ( !GetNextMessage(&msg) )
3754265e 239 return false;
3808e191
JS
240
241#if wxUSE_THREADS
242 wxASSERT_MSG( wxThread::IsMain(),
243 wxT("only the main thread can process Windows messages") );
244
3754265e 245 static bool s_hadGuiLock = true;
9af08eb8 246 static wxMsgList s_aSavedMessages;
3808e191
JS
247
248 // if a secondary thread owning the mutex is doing GUI calls, save all
249 // messages for later processing - we can't process them right now because
250 // it will lead to recursive library calls (and we're not reentrant)
251 if ( !wxGuiOwnedByMainThread() )
252 {
3754265e 253 s_hadGuiLock = false;
3808e191
JS
254
255 // leave out WM_COMMAND messages: too dangerous, sometimes
256 // the message will be processed twice
6c0e8b4e 257 if ( !wxIsWaitingForThread() || msg.message != WM_COMMAND )
3808e191 258 {
9af08eb8
VZ
259 MSG* pMsg = new MSG(msg);
260 s_aSavedMessages.Append(pMsg);
3808e191
JS
261 }
262
3754265e 263 return true;
3808e191
JS
264 }
265 else
266 {
267 // have we just regained the GUI lock? if so, post all of the saved
268 // messages
269 //
270 // FIXME of course, it's not _exactly_ the same as processing the
271 // messages normally - expect some things to break...
272 if ( !s_hadGuiLock )
273 {
3754265e 274 s_hadGuiLock = true;
3808e191 275
9af08eb8
VZ
276 wxMsgList::compatibility_iterator node = s_aSavedMessages.GetFirst();
277 while (node)
3808e191 278 {
9af08eb8
VZ
279 MSG* pMsg = node->GetData();
280 s_aSavedMessages.Erase(node);
281
282 ProcessMessage(pMsg);
283 delete pMsg;
3808e191 284
9af08eb8
VZ
285 node = s_aSavedMessages.GetFirst();
286 }
3808e191
JS
287 }
288 }
289#endif // wxUSE_THREADS
290
3754265e 291 ProcessMessage(&msg);
3808e191 292
3754265e 293 return true;
3808e191
JS
294}
295
81df6af3
VZ
296void wxGUIEventLoop::OnNextIteration()
297{
298#if wxUSE_THREADS
299 wxMutexGuiLeaveOrEnter();
300#endif // wxUSE_THREADS
301}
302
303void wxGUIEventLoop::WakeUp()
304{
305 ::PostMessage(NULL, WM_NULL, 0, 0);
306}
307
308#else // !wxUSE_GUI
309
61478ea0
VZ
310#if wxUSE_CONSOLE_EVENTLOOP
311
81df6af3
VZ
312void wxConsoleEventLoop::OnNextIteration()
313{
314 if ( wxTheApp )
315 wxTheApp->ProcessPendingEvents();
316}
317
318void wxConsoleEventLoop::WakeUp()
319{
320#if wxUSE_THREADS
321 wxWakeUpMainThread();
322#endif
323}
324
325bool wxConsoleEventLoop::Dispatch()
326{
327 MSG msg;
328 if ( !GetNextMessage(&msg) )
329 return false;
330
331 if ( msg.message == WM_TIMER )
332 {
333 TIMERPROC proc = (TIMERPROC)msg.lParam;
334 if ( proc )
335 (*proc)(NULL, 0, msg.wParam, 0);
336 }
337 else
338 {
985acf87 339 wxLogDebug(_T("Ignoring unexpected message %d"), msg.message);
81df6af3
VZ
340 }
341
342 return !m_shouldExit;
343}
344
61478ea0
VZ
345#endif // wxUSE_CONSOLE_EVENTLOOP
346
81df6af3 347#endif //wxUSE_GUI