]> git.saurik.com Git - wxWidgets.git/blame - src/os2/evtloop.cpp
applied patch 890642: wxRE_ADVANCED flag and docs
[wxWidgets.git] / src / os2 / evtloop.cpp
CommitLineData
251b80c4
KB
1///////////////////////////////////////////////////////////////////////////////
2// Name: os2/evtloop.cpp
3// Purpose: implements wxEventLoop for PM
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>
6aa89a22 9// License: wxWindows licence
251b80c4
KB
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 #include "wx/window.h"
33 #include "wx/app.h"
598dc9b7 34 #include "wx/timer.h"
251b80c4
KB
35#endif //WX_PRECOMP
36
37#include "wx/evtloop.h"
598dc9b7 38#include "wx/log.h"
251b80c4 39#include "wx/tooltip.h"
598dc9b7 40#include "wx/ptr_scpd.h"
251b80c4
KB
41
42#include "wx/os2/private.h"
43
44#if wxUSE_THREADS
45 // define the array of QMSG strutures
46 WX_DECLARE_OBJARRAY(QMSG, wxMsgArray);
598dc9b7
SN
47
48 #include "wx/arrimpl.cpp"
49
50 WX_DEFINE_OBJARRAY(wxMsgArray);
251b80c4
KB
51#endif
52
598dc9b7 53extern HAB vHabmain;
251b80c4
KB
54
55// ----------------------------------------------------------------------------
56// wxEventLoopImpl
57// ----------------------------------------------------------------------------
58
59class WXDLLEXPORT wxEventLoopImpl
60{
61public:
62 // ctor
63 wxEventLoopImpl() { SetExitCode(0); }
64
65 // process a message
66 void ProcessMessage(QMSG *msg);
67
68 // generate an idle message, return TRUE if more idle time requested
69 bool SendIdleMessage();
70
71 // set/get the exit code
72 void SetExitCode(int exitcode) { m_exitcode = exitcode; }
73 int GetExitCode() const { return m_exitcode; }
74
75private:
76 // preprocess a message, return TRUE if processed (i.e. no further
77 // dispatching required)
78 bool PreProcessMessage(QMSG *msg);
79
80 // the exit code of the event loop
81 int m_exitcode;
82};
83
598dc9b7
SN
84// ----------------------------------------------------------------------------
85// helper class
86// ----------------------------------------------------------------------------
87
88wxDEFINE_TIED_SCOPED_PTR_TYPE(wxEventLoopImpl);
89
90// this object sets the wxEventLoop given to the ctor as the currently active
91// one and unsets it in its dtor
92class wxEventLoopActivator
93{
94public:
95 wxEventLoopActivator(wxEventLoop **pActive,
96 wxEventLoop *evtLoop)
97 {
98 m_pActive = pActive;
99 m_evtLoopOld = *pActive;
100 *pActive = evtLoop;
101 }
102
103 ~wxEventLoopActivator()
104 {
105 // restore the previously active event loop
106 *m_pActive = m_evtLoopOld;
107 }
108
109private:
110 wxEventLoop *m_evtLoopOld;
111 wxEventLoop **m_pActive;
112};
113
251b80c4
KB
114// ============================================================================
115// wxEventLoopImpl implementation
116// ============================================================================
117
118// ----------------------------------------------------------------------------
119// wxEventLoopImpl message processing
120// ----------------------------------------------------------------------------
121
122void wxEventLoopImpl::ProcessMessage(QMSG *msg)
123{
124 // give us the chance to preprocess the message first
125 if ( !PreProcessMessage(msg) )
126 {
127 // if it wasn't done, dispatch it to the corresponding window
598dc9b7 128 ::WinDispatchMsg(vHabmain, msg);
251b80c4
KB
129 }
130}
131
598dc9b7 132bool wxEventLoopImpl::PreProcessMessage(QMSG *pMsg)
251b80c4 133{
598dc9b7
SN
134 HWND hWnd = pMsg->hwnd;
135 wxWindow *pWndThis = wxFindWinFromHandle((WXHWND)hWnd);
136 wxWindow *pWnd;
137
138 //
139 // Pass non-system timer messages to the wxTimerProc
140 //
141 if (pMsg->msg == WM_TIMER &&
142 (SHORT1FROMMP(pMsg->mp1) != TID_CURSOR &&
143 SHORT1FROMMP(pMsg->mp1) != TID_FLASHWINDOW &&
144 SHORT1FROMMP(pMsg->mp1) != TID_SCROLL &&
145 SHORT1FROMMP(pMsg->mp1) != 0x0000
146 ))
147 wxTimerProc(NULL, 0, (int)pMsg->mp1, 0);
148
149 // Allow the window to prevent certain messages from being
150 // translated/processed (this is currently used by wxTextCtrl to always
151 // grab Ctrl-C/V/X, even if they are also accelerators in some parent)
152 //
153 if (pWndThis && !pWndThis->OS2ShouldPreProcessMessage((WXMSG*)pMsg))
251b80c4 154 {
598dc9b7 155 return FALSE;
251b80c4 156 }
251b80c4 157
598dc9b7
SN
158 //
159 // For some composite controls (like a combobox), wndThis might be NULL
160 // because the subcontrol is not a wxWindow, but only the control itself
161 // is - try to catch this case
162 //
163 while (hWnd && !pWndThis)
251b80c4 164 {
598dc9b7
SN
165 hWnd = ::WinQueryWindow(hWnd, QW_PARENT);
166 pWndThis = wxFindWinFromHandle((WXHWND)hWnd);
251b80c4
KB
167 }
168
598dc9b7
SN
169
170 //
171 // Try translations first; find the youngest window with
172 // a translation table. OS/2 has case sensiive accels, so
173 // this block, coded by BK, removes that and helps make them
174 // case insensitive.
175 //
176 if(pMsg->msg == WM_CHAR)
251b80c4 177 {
598dc9b7
SN
178 PBYTE pChmsg = (PBYTE)&(pMsg->msg);
179 USHORT uSch = CHARMSG(pChmsg)->chr;
180 bool bRc = FALSE;
181
182 //
183 // Do not process keyup events
184 //
185 if(!(CHARMSG(pChmsg)->fs & KC_KEYUP))
186 {
187 if((CHARMSG(pChmsg)->fs & (KC_ALT | KC_CTRL)) && CHARMSG(pChmsg)->chr != 0)
188 CHARMSG(pChmsg)->chr = (USHORT)wxToupper((UCHAR)uSch);
189
190
191 for(pWnd = pWndThis; pWnd; pWnd = pWnd->GetParent() )
192 {
193 if((bRc = pWnd->OS2TranslateMessage((WXMSG*)pMsg)) == TRUE)
194 return TRUE;
195 // break;
196 // stop at first top level window, i.e. don't try to process the
197 // key strokes originating in a dialog using the accelerators of
198 // the parent frame - this doesn't make much sense
199 if ( pWnd->IsTopLevel() )
200 break;
201 }
202
203 if(!bRc) // untranslated, should restore original value
204 CHARMSG(pChmsg)->chr = uSch;
205 }
251b80c4 206 }
598dc9b7
SN
207 //
208 // Anyone for a non-translation message? Try youngest descendants first.
209 //
210// for (pWnd = pWndThis->GetParent(); pWnd; pWnd = pWnd->GetParent())
211// {
212// if (pWnd->OS2ProcessMessage(pWxmsg))
213// return TRUE;
214// }
251b80c4
KB
215 return FALSE;
216}
217
218// ----------------------------------------------------------------------------
219// wxEventLoopImpl idle event processing
220// ----------------------------------------------------------------------------
221
222bool wxEventLoopImpl::SendIdleMessage()
223{
e39af974 224 return wxTheApp->ProcessIdle() ;
251b80c4
KB
225}
226
227// ============================================================================
228// wxEventLoop implementation
229// ============================================================================
230
231wxEventLoop *wxEventLoop::ms_activeLoop = NULL;
232
233// ----------------------------------------------------------------------------
234// wxEventLoop running and exiting
235// ----------------------------------------------------------------------------
236
237wxEventLoop::~wxEventLoop()
238{
239 wxASSERT_MSG( !m_impl, _T("should have been deleted in Run()") );
240}
241
242bool wxEventLoop::IsRunning() const
243{
244 return m_impl != NULL;
245}
246
598dc9b7
SN
247//////////////////////////////////////////////////////////////////////////////
248//
249// Keep trying to process messages until WM_QUIT
250// received.
251//
252// If there are messages to be processed, they will all be
253// processed and OnIdle will not be called.
254// When there are no more messages, OnIdle is called.
255// If OnIdle requests more time,
256// it will be repeatedly called so long as there are no pending messages.
257// A 'feature' of this is that once OnIdle has decided that no more processing
258// is required, then it won't get processing time until further messages
259// are processed (it'll sit in Dispatch).
260//
261//////////////////////////////////////////////////////////////////////////////
262class CallEventLoopMethod
263{
264public:
265 typedef void (wxEventLoop::*FuncType)();
266
267 CallEventLoopMethod(wxEventLoop *evtLoop, FuncType fn)
268 : m_evtLoop(evtLoop), m_fn(fn) { }
269 ~CallEventLoopMethod() { (m_evtLoop->*m_fn)(); }
270
271private:
272 wxEventLoop *m_evtLoop;
273 FuncType m_fn;
274};
275
251b80c4
KB
276int wxEventLoop::Run()
277{
278 // event loops are not recursive, you need to create another loop!
279 wxCHECK_MSG( !IsRunning(), -1, _T("can't reenter a message loop") );
280
598dc9b7
SN
281 // SendIdleMessage() and Dispatch() below may throw so the code here should
282 // be exception-safe, hence we must use local objects for all actions we
283 // should undo
284 wxEventLoopActivator activate(&ms_activeLoop, this);
285 wxEventLoopImplTiedPtr impl(&m_impl, new wxEventLoopImpl);
251b80c4 286
598dc9b7 287 CallEventLoopMethod callOnExit(this, &wxEventLoop::OnExit);
251b80c4
KB
288
289 for ( ;; )
290 {
291#if wxUSE_THREADS
292 wxMutexGuiLeaveOrEnter();
293#endif // wxUSE_THREADS
294
295 // generate and process idle events for as long as we don't have
296 // anything else to do
297 while ( !Pending() && m_impl->SendIdleMessage() )
598dc9b7
SN
298 {
299 wxTheApp->HandleSockets();
300 wxUsleep(10);
301 }
302
303 wxTheApp->HandleSockets();
304 if (Pending())
305 {
306 if ( !Dispatch() )
307 {
308 // we got WM_QUIT
309 break;
310 }
311 }
312 else
313 wxUsleep(10);
251b80c4
KB
314 }
315
598dc9b7 316 return m_impl->GetExitCode();
251b80c4
KB
317}
318
319void wxEventLoop::Exit(int rc)
320{
321 wxCHECK_RET( IsRunning(), _T("can't call Exit() if not running") );
322
323 m_impl->SetExitCode(rc);
324
325 ::WinPostMsg(NULL, WM_QUIT, 0, 0);
326}
327
328// ----------------------------------------------------------------------------
329// wxEventLoop message processing dispatching
330// ----------------------------------------------------------------------------
331
332bool wxEventLoop::Pending() const
333{
334 QMSG msg;
598dc9b7 335 return ::WinPeekMsg(vHabmain, &msg, 0, 0, 0, PM_NOREMOVE) != 0;
251b80c4
KB
336}
337
338bool wxEventLoop::Dispatch()
339{
340 wxCHECK_MSG( IsRunning(), FALSE, _T("can't call Dispatch() if not running") );
341
342 QMSG msg;
598dc9b7 343 BOOL bRc = ::WinGetMsg(vHabmain, &msg, (HWND) NULL, 0, 0);
251b80c4 344
598dc9b7 345 if ( bRc == 0 )
251b80c4
KB
346 {
347 // got WM_QUIT
348 return FALSE;
349 }
350
251b80c4
KB
351#if wxUSE_THREADS
352 wxASSERT_MSG( wxThread::IsMain(),
353 wxT("only the main thread can process Windows messages") );
354
355 static bool s_hadGuiLock = TRUE;
356 static wxMsgArray s_aSavedMessages;
357
358 // if a secondary thread owning the mutex is doing GUI calls, save all
359 // messages for later processing - we can't process them right now because
360 // it will lead to recursive library calls (and we're not reentrant)
361 if ( !wxGuiOwnedByMainThread() )
362 {
363 s_hadGuiLock = FALSE;
364
365 // leave out WM_COMMAND messages: too dangerous, sometimes
366 // the message will be processed twice
598dc9b7 367 if ( !wxIsWaitingForThread() || msg.msg != WM_COMMAND )
251b80c4
KB
368 {
369 s_aSavedMessages.Add(msg);
370 }
371
372 return TRUE;
373 }
374 else
375 {
376 // have we just regained the GUI lock? if so, post all of the saved
377 // messages
378 //
379 // FIXME of course, it's not _exactly_ the same as processing the
380 // messages normally - expect some things to break...
381 if ( !s_hadGuiLock )
382 {
383 s_hadGuiLock = TRUE;
384
385 size_t count = s_aSavedMessages.Count();
386 for ( size_t n = 0; n < count; n++ )
387 {
598dc9b7 388 QMSG& msg = s_aSavedMessages[n];
251b80c4
KB
389 m_impl->ProcessMessage(&msg);
390 }
391
392 s_aSavedMessages.Empty();
393 }
394 }
395#endif // wxUSE_THREADS
396
397 m_impl->ProcessMessage(&msg);
398
399 return TRUE;
400}
401