]> git.saurik.com Git - wxWidgets.git/blame_incremental - src/msw/evtloop.cpp
don't keep dangling m_prevRadio pointer (2nd part of patch 1836644)
[wxWidgets.git] / src / msw / evtloop.cpp
... / ...
CommitLineData
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>
9// License: wxWindows licence
10///////////////////////////////////////////////////////////////////////////////
11
12// ============================================================================
13// declarations
14// ============================================================================
15
16// ----------------------------------------------------------------------------
17// headers
18// ----------------------------------------------------------------------------
19
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
28 #if wxUSE_GUI
29 #include "wx/window.h"
30 #endif
31 #include "wx/app.h"
32#endif //WX_PRECOMP
33
34#include "wx/evtloop.h"
35
36
37#include "wx/except.h"
38#include "wx/ptr_scpd.h"
39
40#include "wx/msw/private.h"
41
42#if wxUSE_GUI
43 #include "wx/tooltip.h"
44 #if wxUSE_THREADS
45 #include "wx/thread.h"
46
47 // define the list of MSG strutures
48 WX_DECLARE_LIST(MSG, wxMsgList);
49
50 #include "wx/listimpl.cpp"
51
52 WX_DEFINE_LIST(wxMsgList)
53 #endif // wxUSE_THREADS
54#endif //wxUSE_GUI
55
56#if wxUSE_BASE
57
58// ============================================================================
59// wxMSWEventLoopBase implementation
60// ============================================================================
61
62// ----------------------------------------------------------------------------
63// ctor/dtor
64// ----------------------------------------------------------------------------
65
66wxMSWEventLoopBase::wxMSWEventLoopBase()
67{
68 m_shouldExit = false;
69 m_exitcode = 0;
70}
71
72// ----------------------------------------------------------------------------
73// wxEventLoop message processing dispatching
74// ----------------------------------------------------------------------------
75
76bool wxMSWEventLoopBase::Pending() const
77{
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 )
89 {
90 // got WM_QUIT
91 return false;
92 }
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;
104}
105
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)
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
129bool wxGUIEventLoop::PreProcessMessage(WXMSG *msg)
130{
131 HWND hwnd = msg->hwnd;
132 wxWindow *wndThis = wxGetWindowFromHWND((WXHWND)hwnd);
133 wxWindow *wnd;
134
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)
137 if ( !wndThis )
138 {
139 while ( hwnd && (::GetWindowLong(hwnd, GWL_STYLE) & WS_CHILD ))
140 {
141 hwnd = ::GetParent(hwnd);
142
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;
148 }
149
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 }
160 }
161
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
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
176 if ( msg->message == WM_MOUSEMOVE )
177 {
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);
182 }
183#endif // wxUSE_TOOLTIPS
184
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 {
190 return false;
191 }
192
193 // try translations first: the accelerators override everything
194 for ( wnd = wndThis; wnd; wnd = wnd->GetParent() )
195 {
196 if ( wnd->MSWTranslateMessage((WXMSG *)msg))
197 return true;
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;
204 }
205
206 // now try the other hooks (kbd navigation is handled here)
207 for ( wnd = wndThis; wnd; wnd = wnd->GetParent() )
208 {
209 if ( wnd->MSWProcessMessage((WXMSG *)msg) )
210 return true;
211
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() )
217 break;
218 }
219
220 // no special preprocessing for this message, dispatch it normally
221 return false;
222}
223
224void wxGUIEventLoop::ProcessMessage(WXMSG *msg)
225{
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 }
233}
234
235bool wxGUIEventLoop::Dispatch()
236{
237 MSG msg;
238 if ( !GetNextMessage(&msg) )
239 return false;
240
241#if wxUSE_THREADS
242 wxASSERT_MSG( wxThread::IsMain(),
243 wxT("only the main thread can process Windows messages") );
244
245 static bool s_hadGuiLock = true;
246 static wxMsgList s_aSavedMessages;
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 {
253 s_hadGuiLock = false;
254
255 // leave out WM_COMMAND messages: too dangerous, sometimes
256 // the message will be processed twice
257 if ( !wxIsWaitingForThread() || msg.message != WM_COMMAND )
258 {
259 MSG* pMsg = new MSG(msg);
260 s_aSavedMessages.Append(pMsg);
261 }
262
263 return true;
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 {
274 s_hadGuiLock = true;
275
276 wxMsgList::compatibility_iterator node = s_aSavedMessages.GetFirst();
277 while (node)
278 {
279 MSG* pMsg = node->GetData();
280 s_aSavedMessages.Erase(node);
281
282 ProcessMessage(pMsg);
283 delete pMsg;
284
285 node = s_aSavedMessages.GetFirst();
286 }
287 }
288 }
289#endif // wxUSE_THREADS
290
291 ProcessMessage(&msg);
292
293 return true;
294}
295
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
310#if wxUSE_CONSOLE_EVENTLOOP
311
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 {
339 wxLogDebug(_T("Ignoring unexpected message %d"), msg.message);
340 }
341
342 return !m_shouldExit;
343}
344
345#endif // wxUSE_CONSOLE_EVENTLOOP
346
347#endif //wxUSE_GUI