]> git.saurik.com Git - wxWidgets.git/blame_incremental - src/motif/evtloop.cpp
Typo fix
[wxWidgets.git] / src / motif / evtloop.cpp
... / ...
CommitLineData
1///////////////////////////////////////////////////////////////////////////////
2// Name: motif/evtloop.cpp
3// Purpose: implements wxEventLoop for Motif
4// Author: Mattia Barbon
5// Modified by:
6// Created: 01.11.02
7// RCS-ID: $Id$
8// Copyright: (c) 2002 Mattia Barbon
9// License: wxWindows licence
10///////////////////////////////////////////////////////////////////////////////
11
12// ============================================================================
13// declarations
14// ============================================================================
15
16// ----------------------------------------------------------------------------
17// headers
18// ----------------------------------------------------------------------------
19
20#ifdef __GNUG__
21 #pragma implementation "evtloop.h"
22#endif
23
24#ifdef __VMS
25#define XtParent XTPARENT
26#define XtDisplay XTDISPLAY
27#endif
28
29// For compilers that support precompilation, includes "wx.h".
30#include "wx/wxprec.h"
31
32#ifndef WX_PRECOMP
33#endif //WX_PRECOMP
34
35#include "wx/evtloop.h"
36#include "wx/event.h"
37#include "wx/app.h"
38
39#ifdef __VMS__
40#pragma message disable nosimpint
41#endif
42#include <Xm/Xm.h>
43#include <X11/Xlib.h>
44#ifdef __VMS__
45#pragma message enable nosimpint
46#endif
47
48#include "wx/motif/private.h"
49
50static bool CheckForKeyUp(XEvent* event);
51static bool CheckForKeyDown(XEvent* event);
52static bool CheckForAccelerator(XEvent* event);
53static void ProcessXEvent(XEvent* event);
54static void wxBreakDispatch();
55
56// ----------------------------------------------------------------------------
57// wxEventLoopImpl
58// ----------------------------------------------------------------------------
59
60class WXDLLEXPORT wxEventLoopImpl
61{
62public:
63 // ctor
64 wxEventLoopImpl() { SetExitCode(0); }
65
66 // set/get the exit code
67 void SetExitCode(int exitcode) { m_exitcode = exitcode; }
68 int GetExitCode() const { return m_exitcode; }
69
70 bool SendIdleMessage();
71 bool GetKeepGoing() const { return m_keepGoing; }
72 void SetKeepGoing(bool keepGoing) { m_keepGoing = keepGoing; }
73private:
74 // the exit code of the event loop
75 int m_exitcode;
76 bool m_keepGoing;
77};
78
79// ----------------------------------------------------------------------------
80// wxEventLoopImpl idle event processing
81// ----------------------------------------------------------------------------
82
83static bool SendIdleMessage()
84{
85 wxIdleEvent event;
86
87 return wxTheApp->ProcessEvent(event) && event.MoreRequested();
88}
89
90bool wxEventLoopImpl::SendIdleMessage()
91{
92 return ::SendIdleMessage();
93}
94
95// ============================================================================
96// wxEventLoop implementation
97// ============================================================================
98
99// ----------------------------------------------------------------------------
100// wxEventLoop running and exiting
101// ----------------------------------------------------------------------------
102
103wxEventLoop *wxEventLoop::ms_activeLoop = NULL;
104
105wxEventLoop::~wxEventLoop()
106{
107 wxASSERT_MSG( !m_impl, _T("should have been deleted in Run()") );
108}
109
110bool wxEventLoop::IsRunning() const
111{
112 return m_impl != NULL;
113}
114
115int wxEventLoop::Run()
116{
117 // event loops are not recursive, you need to create another loop!
118 wxCHECK_MSG( !IsRunning(), -1, _T("can't reenter a message loop") );
119
120 wxEventLoop *oldLoop = ms_activeLoop;
121 ms_activeLoop = this;
122
123 m_impl = new wxEventLoopImpl;
124 m_impl->SetKeepGoing( true );
125
126 for( ;; )
127 {
128 if( !wxDoEventLoopIteration( *this ) )
129 break;
130 }
131
132 int exitcode = m_impl->GetExitCode();
133 delete m_impl;
134 m_impl = NULL;
135
136 ms_activeLoop = oldLoop;
137
138 return exitcode;
139}
140
141void wxEventLoop::Exit(int rc)
142{
143 wxCHECK_RET( IsRunning(), _T("can't call Exit() if not running") );
144
145 m_impl->SetExitCode(rc);
146 m_impl->SetKeepGoing( false );
147
148 ::wxBreakDispatch();
149}
150
151// ----------------------------------------------------------------------------
152// wxEventLoop message processing dispatching
153// ----------------------------------------------------------------------------
154
155bool wxEventLoop::Pending() const
156{
157 return XtAppPending( (XtAppContext)wxTheApp->GetAppContext() ) != 0;
158}
159
160bool wxEventLoop::Dispatch()
161{
162 XEvent event;
163 XtAppContext context = (XtAppContext)wxTheApp->GetAppContext();
164
165 if( XtAppPeekEvent( context, &event ) != 0 )
166 {
167 XtAppNextEvent( context, &event );
168 ProcessXEvent( &event );
169 }
170 else
171#ifdef __VMS
172 XtAppProcessEvent( context, XtIMTimer|XtIMAlternateInput );
173#else
174 XtAppProcessEvent( context, XtIMTimer|XtIMAlternateInput|XtIMSignal );
175#endif
176
177 return m_impl ? m_impl->GetKeepGoing() : true;
178}
179
180// ----------------------------------------------------------------------------
181// Static functions (originally in app.cpp)
182// ----------------------------------------------------------------------------
183
184void ProcessXEvent(XEvent* event)
185{
186 if (event->type == KeyPress)
187 {
188 if (CheckForAccelerator(event))
189 {
190 // Do nothing! We intercepted and processed the event as an
191 // accelerator.
192 return;
193 }
194 // It seemed before that this hack was redundant and
195 // key down events were being generated by wxCanvasInputEvent.
196 // But no longer - why ???
197 //
198 else if (CheckForKeyDown(event))
199 {
200 // We intercepted and processed the key down event
201 return;
202 }
203 else
204 {
205 XtDispatchEvent(event);
206 return;
207 }
208 }
209 else if (event->type == KeyRelease)
210 {
211 // TODO: work out why we still need this ! -michael
212 //
213 if (::CheckForKeyUp(event))
214 {
215 // We intercepted and processed the key up event
216 return;
217 }
218 else
219 {
220 XtDispatchEvent(event);
221 return;
222 }
223 }
224 else if (event->type == PropertyNotify)
225 {
226 wxTheApp->HandlePropertyChange(event);
227 return;
228 }
229 else if (event->type == ResizeRequest)
230 {
231 /* Terry Gitnick <terryg@scientech.com> - 1/21/98
232 * If resize event, don't resize until the last resize event for this
233 * window is recieved. Prevents flicker as windows are resized.
234 */
235
236 Display *disp = XtDisplay((Widget) wxTheApp->GetTopLevelWidget());
237 Window win = event->xany.window;
238 XEvent report;
239
240 // to avoid flicker
241 report = * event;
242 while( XCheckTypedWindowEvent (disp, win, ResizeRequest, &report));
243
244 // TODO: when implementing refresh optimization, we can use
245 // XtAddExposureToRegion to expand the window's paint region.
246
247 XtDispatchEvent(event);
248 }
249 else
250 {
251 XtDispatchEvent(event);
252 }
253}
254
255// Returns true if an accelerator has been processed
256bool CheckForAccelerator(XEvent* event)
257{
258 if (event->xany.type == KeyPress)
259 {
260 // Find a wxWindow for this window
261 // TODO: should get display for the window, not the current display
262 Widget widget = XtWindowToWidget((Display*) wxGetDisplay(),
263 event->xany.window);
264 wxWindow* win = NULL;
265
266 // Find the first wxWindow that corresponds to this event window
267 while (widget && !(win = wxGetWindowFromTable(widget)))
268 widget = XtParent(widget);
269
270 if (!widget || !win)
271 return false;
272
273 wxKeyEvent keyEvent(wxEVT_CHAR);
274 wxTranslateKeyEvent(keyEvent, win, (Widget) 0, event);
275
276 // Now we have a wxKeyEvent and we have a wxWindow.
277 // Go up the hierarchy until we find a matching accelerator,
278 // or we get to the top.
279 while (win)
280 {
281 if (win->ProcessAccelerator(keyEvent))
282 return true;
283 win = win->GetParent();
284 }
285 return false;
286 }
287 return false;
288}
289
290// bool wxApp::CheckForKeyDown(WXEvent* event) { wxFAIL; return false; }
291
292bool CheckForKeyDown(XEvent* event)
293{
294 if (event->xany.type == KeyPress)
295 {
296 Widget widget = XtWindowToWidget((Display*) wxGetDisplay(),
297 event->xany.window);
298 wxWindow* win = NULL;
299
300 // Find the first wxWindow that corresponds to this event window
301 while (widget && !(win = wxGetWindowFromTable(widget)))
302 widget = XtParent(widget);
303
304 if (!widget || !win)
305 return false;
306
307 wxKeyEvent keyEvent(wxEVT_KEY_DOWN);
308 wxTranslateKeyEvent(keyEvent, win, (Widget) 0, event);
309
310 return win->ProcessEvent( keyEvent );
311 }
312
313 return false;
314}
315
316// bool wxApp::CheckForKeyUp(WXEvent* event) { wxFAIL; return false; }
317
318bool CheckForKeyUp(XEvent* event)
319{
320 if (event->xany.type == KeyRelease)
321 {
322 Widget widget = XtWindowToWidget((Display*) wxGetDisplay(),
323 event->xany.window);
324 wxWindow* win = NULL;
325
326 // Find the first wxWindow that corresponds to this event window
327 while (widget && !(win = wxGetWindowFromTable(widget)))
328 widget = XtParent(widget);
329
330 if (!widget || !win)
331 return false;
332
333 wxKeyEvent keyEvent(wxEVT_KEY_UP);
334 wxTranslateKeyEvent(keyEvent, win, (Widget) 0, event);
335
336 return win->ProcessEvent( keyEvent );
337 }
338
339 return false;
340}
341
342// ----------------------------------------------------------------------------
343// executes one main loop iteration (declared in include/wx/motif/private.h)
344// ----------------------------------------------------------------------------
345
346bool wxDoEventLoopIteration( wxEventLoop& evtLoop )
347{
348 bool moreRequested, pendingEvents;
349
350 for(;;)
351 {
352 pendingEvents = evtLoop.Pending();
353 if( pendingEvents ) break;
354 moreRequested = ::SendIdleMessage();
355 if( !moreRequested ) break;
356 }
357
358#if wxUSE_THREADS
359 if( !pendingEvents && !moreRequested )
360 {
361 // leave the main loop to give other threads a chance to
362 // perform their GUI work
363 wxMutexGuiLeave();
364 wxUsleep(20);
365 wxMutexGuiEnter();
366 }
367#endif
368
369 if( !evtLoop.Dispatch() )
370 return false;
371
372 return true;
373}
374
375// ----------------------------------------------------------------------------
376// ::wxWakeUpIdle implementation
377// ----------------------------------------------------------------------------
378
379// As per Vadim's suggestion, we open a pipe, and XtAppAddInputSource it;
380// writing a single byte to the pipe will cause wxEventLoop::Pending
381// to return true, and wxEventLoop::Dispatch to dispatch an input handler
382// that simply removes the byte(s), and to return, which will cause
383// an idle event to be sent
384
385// also wxEventLoop::Exit is implemented that way, so that exiting an
386// event loop won't require an event being in the queue
387
388#include "wx/module.h"
389
390#include <sys/types.h>
391#include <sys/time.h>
392#include <unistd.h>
393
394static XtInputId inputId;
395static int idleFds[2] = { -1, -1 };
396
397class wxIdlePipeModule : public wxModule
398{
399public:
400 wxIdlePipeModule() {};
401
402 virtual bool OnInit()
403 {
404 if( pipe(idleFds) != 0 )
405 return false;
406
407 return true;
408 }
409
410 virtual void OnExit()
411 {
412 close( idleFds[0] );
413 close( idleFds[1] );
414 }
415private:
416 DECLARE_DYNAMIC_CLASS(wxIdlePipeModule);
417};
418
419IMPLEMENT_DYNAMIC_CLASS(wxIdlePipeModule, wxModule);
420
421static void wxInputCallback( XtPointer, int* fd, XtInputId* )
422{
423 char buffer[128];
424
425 // wxWakeUpIdle may have been called more than once
426 for(;;)
427 {
428 fd_set in;
429 struct timeval timeout;
430
431 timeout.tv_sec = 0;
432 timeout.tv_usec = 0;
433
434 FD_ZERO( &in );
435 FD_SET( *fd, &in );
436
437 if( select( *fd + 1, &in, NULL, NULL, &timeout ) <= 0 )
438 break;
439 if( read( *fd, buffer, sizeof(buffer) - 1 ) != sizeof(buffer) - 1 )
440 break;
441 }
442}
443
444static void wxBreakDispatch()
445{
446 char dummy;
447
448 // check if wxWakeUpIdle has already been called
449 fd_set in;
450 struct timeval timeout;
451
452 timeout.tv_sec = 0;
453 timeout.tv_usec = 0;
454
455 FD_ZERO( &in );
456 FD_SET( idleFds[0], &in );
457
458 if( select( idleFds[0] + 1, &in, NULL, NULL, &timeout ) > 0 )
459 return;
460
461 // write a single byte
462 write( idleFds[1], &dummy, 1 );
463}
464
465void wxWakeUpIdle()
466{
467 ::wxBreakDispatch();
468}
469
470bool wxAddIdleCallback()
471{
472 // install input handler for wxWakeUpIdle
473 inputId = XtAppAddInput( (XtAppContext) wxTheApp->GetAppContext(),
474 idleFds[0],
475 (XtPointer)XtInputReadMask,
476 wxInputCallback,
477 NULL );
478
479 return true;
480}
481