Added some more files
[wxWidgets.git] / src / msw / evtloop.cpp
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 license
10 ///////////////////////////////////////////////////////////////////////////////
11
12 // ============================================================================
13 // declarations
14 // ============================================================================
15
16 // ----------------------------------------------------------------------------
17 // headers
18 // ----------------------------------------------------------------------------
19
20 #ifdef __GNUG__
21 #pragma implementation "evtloop.h"
22 #endif
23
24 // For compilers that support precompilation, includes "wx.h".
25 #include "wx/wxprec.h"
26
27 #ifdef __BORLANDC__
28 #pragma hdrstop
29 #endif
30
31 #ifndef WX_PRECOMP
32 #endif //WX_PRECOMP
33
34 #include "wx/evtloop.h"
35
36 #include "wx/msw/private.h"
37
38 // ----------------------------------------------------------------------------
39 // wxEventLoopImpl
40 // ----------------------------------------------------------------------------
41
42 class WXDLLEXPORT wxEventLoopImpl
43 {
44 public:
45 // ctor
46 wxEventLoopImpl() { SetExitCode(0); }
47
48 // process a message
49 void ProcessMessage(MSG *msg);
50
51 // generate an idle message, return TRUE if more idle time requested
52 bool SendIdleMessage();
53
54 // set/get the exit code
55 void SetExitCode(int exitcode) { m_exitcode = exitcode; }
56 int GetExitCode() const { return m_exitcode; }
57
58 private:
59 // preprocess a message, return TRUE if processed (i.e. no further
60 // dispatching required)
61 bool PreProcessMessage(MSG *msg);
62
63 // the exit code of the event loop
64 int m_exitcode;
65 };
66
67 // ============================================================================
68 // wxEventLoopImpl implementation
69 // ============================================================================
70
71 // ----------------------------------------------------------------------------
72 // wxEventLoopImpl message processing
73 // ----------------------------------------------------------------------------
74
75 void wxEventLoopImpl::ProcessMessage(MSG *msg)
76 {
77 // give us the chance to preprocess the message first
78 if ( !PreProcessMessage(msg) )
79 {
80 // if it wasn't done, dispatch it to the corresponding window
81 ::TranslateMessage(msg);
82 ::DispatchMessage(msg);
83 }
84 }
85
86 bool wxEventLoopImpl::PreProcessMessage(MSG *msg)
87 {
88 HWND hWnd = msg->hwnd;
89 wxWindow *wndThis = wxGetWindowFromHWND((WXHWND)hWnd);
90
91 #if wxUSE_TOOLTIPS
92 // we must relay WM_MOUSEMOVE events to the tooltip ctrl if we want it to
93 // popup the tooltip bubbles
94 if ( wndThis && (msg->message == WM_MOUSEMOVE) )
95 {
96 wxToolTip *tt = wndThis->GetToolTip();
97 if ( tt )
98 {
99 tt->RelayEvent((WXMSG *)msg);
100 }
101 }
102 #endif // wxUSE_TOOLTIPS
103
104 // try translations first; find the youngest window with a translation
105 // table.
106 wxWindow *wnd;
107 for ( wnd = wndThis; wnd; wnd = wnd->GetParent() )
108 {
109 if ( wnd->MSWTranslateMessage((WXMSG *)msg) )
110 return TRUE;
111 }
112
113 // Anyone for a non-translation message? Try youngest descendants first.
114 for ( wnd = wndThis; wnd; wnd = wnd->GetParent() )
115 {
116 if ( wnd->MSWProcessMessage((WXMSG *)msg) )
117 return TRUE;
118 }
119
120 return FALSE;
121 }
122
123 // ----------------------------------------------------------------------------
124 // wxEventLoopImpl idle event processing
125 // ----------------------------------------------------------------------------
126
127 bool wxEventLoopImpl::SendIdleMessage()
128 {
129 wxIdleEvent event;
130
131 return wxTheApp->ProcessEvent(event) && event.MoreRequested();
132 }
133
134 // ============================================================================
135 // wxEventLoop implementation
136 // ============================================================================
137
138 // ----------------------------------------------------------------------------
139 // wxEventLoop running and exiting
140 // ----------------------------------------------------------------------------
141
142 wxEventLoop::~wxEventLoop()
143 {
144 wxASSERT_MSG( !m_impl, _T("should have been deleted in Run()") );
145 }
146
147 bool wxEventLoop::IsRunning() const
148 {
149 return m_impl != NULL;
150 }
151
152 int wxEventLoop::Run()
153 {
154 // event loops are not recursive, you need to create another loop!
155 wxCHECK_MSG( !IsRunning(), -1, _T("can't reenter a message loop") );
156
157 m_impl = new wxEventLoopImpl;
158
159 for ( ;; )
160 {
161 #if wxUSE_THREADS
162 wxMutexGuiLeaveOrEnter();
163 #endif // wxUSE_THREADS
164
165 // generate and process idle events for as long as we don't have
166 // anything else to do
167 while ( !Pending() && m_impl->SendIdleMessage() )
168 ;
169
170 // a message came or no more idle processing to do, sit in Dispatch()
171 // waiting for the next message
172 if ( !Dispatch() )
173 {
174 // we got WM_QUIT
175 break;
176 }
177 }
178
179 int exitcode = m_impl->GetExitCode();
180 delete m_impl;
181 m_impl = NULL;
182
183 return exitcode;
184 }
185
186 void wxEventLoop::Exit(int rc)
187 {
188 wxCHECK_RET( IsRunning(), _T("can't call Exit() if not running") );
189
190 m_impl->SetExitCode(rc);
191
192 ::PostQuitMessage(rc);
193 }
194
195 // ----------------------------------------------------------------------------
196 // wxEventLoop message processing dispatching
197 // ----------------------------------------------------------------------------
198
199 bool wxEventLoop::Pending() const
200 {
201 MSG msg;
202 return ::PeekMessage(&msg, 0, 0, 0, PM_NOREMOVE) != 0;
203 }
204
205 bool wxEventLoop::Dispatch()
206 {
207 wxCHECK_MSG( IsRunning(), FALSE, _T("can't call Dispatch() if not running") );
208
209 MSG msg;
210 BOOL rc = ::GetMessage(&msg, (HWND) NULL, 0, 0);
211
212 if ( rc == 0 )
213 {
214 // got WM_QUIT
215 return FALSE;
216 }
217
218 if ( rc == -1 )
219 {
220 // should never happen, but let's test for it nevertheless
221 wxLogLastError(wxT("GetMessage"));
222
223 // still break from the loop
224 return FALSE;
225 }
226
227 #if wxUSE_THREADS
228 wxASSERT_MSG( wxThread::IsMain(),
229 wxT("only the main thread can process Windows messages") );
230
231 static bool s_hadGuiLock = TRUE;
232 static wxMsgArray s_aSavedMessages;
233
234 // if a secondary thread owning the mutex is doing GUI calls, save all
235 // messages for later processing - we can't process them right now because
236 // it will lead to recursive library calls (and we're not reentrant)
237 if ( !wxGuiOwnedByMainThread() )
238 {
239 s_hadGuiLock = FALSE;
240
241 // leave out WM_COMMAND messages: too dangerous, sometimes
242 // the message will be processed twice
243 if ( !wxIsWaitingForThread() ||
244 s_currentMsg.message != WM_COMMAND )
245 {
246 s_aSavedMessages.Add(s_currentMsg);
247 }
248
249 return TRUE;
250 }
251 else
252 {
253 // have we just regained the GUI lock? if so, post all of the saved
254 // messages
255 //
256 // FIXME of course, it's not _exactly_ the same as processing the
257 // messages normally - expect some things to break...
258 if ( !s_hadGuiLock )
259 {
260 s_hadGuiLock = TRUE;
261
262 size_t count = s_aSavedMessages.Count();
263 for ( size_t n = 0; n < count; n++ )
264 {
265 MSG& msg = s_aSavedMessages[n];
266 m_impl->ProcessMessage(&msg);
267 }
268
269 s_aSavedMessages.Empty();
270 }
271 }
272 #endif // wxUSE_THREADS
273
274 m_impl->ProcessMessage(&msg);
275
276 return TRUE;
277 }
278