]> git.saurik.com Git - wxWidgets.git/blame_incremental - src/x11/evtloop.cpp
Updates for wxToolbook class
[wxWidgets.git] / src / x11 / evtloop.cpp
... / ...
CommitLineData
1///////////////////////////////////////////////////////////////////////////////
2// Name: x11/evtloop.cpp
3// Purpose: implements wxEventLoop for X11
4// Author: Julian Smart
5// Modified by:
6// Created: 01.06.01
7// RCS-ID: $Id$
8// Copyright: (c) 2002 Julian Smart
9// License: wxWindows licence
10///////////////////////////////////////////////////////////////////////////////
11
12// ============================================================================
13// declarations
14// ============================================================================
15
16// ----------------------------------------------------------------------------
17// headers
18// ----------------------------------------------------------------------------
19
20#include "wx/window.h"
21#include "wx/app.h"
22#include "wx/evtloop.h"
23#include "wx/tooltip.h"
24#if wxUSE_THREADS
25#include "wx/thread.h"
26#endif
27#include "wx/timer.h"
28#include "wx/hash.h"
29#include "wx/module.h"
30#include "wx/unix/private.h"
31#include "wx/x11/private.h"
32#include "X11/Xlib.h"
33
34#include <sys/time.h>
35#include <unistd.h>
36
37#if wxUSE_SOCKETS
38// ----------------------------------------------------------------------------
39// wxSocketTable
40// ----------------------------------------------------------------------------
41
42typedef void (*wxSocketCallback) (int fd, void* data);
43
44class wxSocketTableEntry: public wxObject
45{
46 public:
47 wxSocketTableEntry()
48 {
49 m_fdInput = -1; m_fdOutput = -1;
50 m_callbackInput = NULL; m_callbackOutput = NULL;
51 m_dataInput = NULL; m_dataOutput = NULL;
52 }
53
54 int m_fdInput;
55 int m_fdOutput;
56 wxSocketCallback m_callbackInput;
57 wxSocketCallback m_callbackOutput;
58 void* m_dataInput;
59 void* m_dataOutput;
60};
61
62typedef enum
63{ wxSocketTableInput, wxSocketTableOutput } wxSocketTableType ;
64
65class wxSocketTable: public wxHashTable
66{
67 public:
68 wxSocketTable(): wxHashTable(wxKEY_INTEGER)
69 {
70 }
71 ~wxSocketTable()
72 {
73 WX_CLEAR_HASH_TABLE(*this)
74 }
75
76 wxSocketTableEntry* FindEntry(int fd);
77
78 void RegisterCallback(int fd, wxSocketTableType socketType, wxSocketCallback callback, void* data);
79
80 void UnregisterCallback(int fd, wxSocketTableType socketType);
81
82 bool CallCallback(int fd, wxSocketTableType socketType);
83
84 void FillSets(fd_set* readset, fd_set* writeset, int* highest);
85
86 void ProcessEvents(fd_set* readset, fd_set* writeset);
87};
88
89wxSocketTableEntry* wxSocketTable::FindEntry(int fd)
90{
91 wxSocketTableEntry* entry = (wxSocketTableEntry*) Get(fd);
92 return entry;
93}
94
95void wxSocketTable::RegisterCallback(int fd, wxSocketTableType socketType, wxSocketCallback callback, void* data)
96{
97 wxSocketTableEntry* entry = FindEntry(fd);
98 if (!entry)
99 {
100 entry = new wxSocketTableEntry();
101 Put(fd, entry);
102 }
103
104 if (socketType == wxSocketTableInput)
105 {
106 entry->m_fdInput = fd;
107 entry->m_dataInput = data;
108 entry->m_callbackInput = callback;
109 }
110 else
111 {
112 entry->m_fdOutput = fd;
113 entry->m_dataOutput = data;
114 entry->m_callbackOutput = callback;
115 }
116}
117
118void wxSocketTable::UnregisterCallback(int fd, wxSocketTableType socketType)
119{
120 wxSocketTableEntry* entry = FindEntry(fd);
121 if (entry)
122 {
123 if (socketType == wxSocketTableInput)
124 {
125 entry->m_fdInput = -1;
126 entry->m_dataInput = NULL;
127 entry->m_callbackInput = NULL;
128 }
129 else
130 {
131 entry->m_fdOutput = -1;
132 entry->m_dataOutput = NULL;
133 entry->m_callbackOutput = NULL;
134 }
135 if (entry->m_fdInput == -1 && entry->m_fdOutput == -1)
136 {
137 Delete(fd);
138 delete entry;
139 }
140 }
141}
142
143bool wxSocketTable::CallCallback(int fd, wxSocketTableType socketType)
144{
145 wxSocketTableEntry* entry = FindEntry(fd);
146 if (entry)
147 {
148 if (socketType == wxSocketTableInput)
149 {
150 if (entry->m_fdInput != -1 && entry->m_callbackInput)
151 {
152 (entry->m_callbackInput) (entry->m_fdInput, entry->m_dataInput);
153 }
154 }
155 else
156 {
157 if (entry->m_fdOutput != -1 && entry->m_callbackOutput)
158 {
159 (entry->m_callbackOutput) (entry->m_fdOutput, entry->m_dataOutput);
160 }
161 }
162 return TRUE;
163 }
164 else
165 return FALSE;
166}
167
168void wxSocketTable::FillSets(fd_set* readset, fd_set* writeset, int* highest)
169{
170 BeginFind();
171 wxHashTable::compatibility_iterator node = Next();
172 while (node)
173 {
174 wxSocketTableEntry* entry = (wxSocketTableEntry*) node->GetData();
175
176 if (entry->m_fdInput != -1)
177 {
178 wxFD_SET(entry->m_fdInput, readset);
179 if (entry->m_fdInput > *highest)
180 * highest = entry->m_fdInput;
181 }
182
183 if (entry->m_fdOutput != -1)
184 {
185 wxFD_SET(entry->m_fdOutput, writeset);
186 if (entry->m_fdOutput > *highest)
187 * highest = entry->m_fdOutput;
188 }
189
190 node = Next();
191 }
192}
193
194void wxSocketTable::ProcessEvents(fd_set* readset, fd_set* writeset)
195{
196 BeginFind();
197 wxHashTable::compatibility_iterator node = Next();
198 while (node)
199 {
200 wxSocketTableEntry* entry = (wxSocketTableEntry*) node->GetData();
201
202 if (entry->m_fdInput != -1 && wxFD_ISSET(entry->m_fdInput, readset))
203 {
204 (entry->m_callbackInput) (entry->m_fdInput, entry->m_dataInput);
205 }
206
207 if (entry->m_fdOutput != -1 && wxFD_ISSET(entry->m_fdOutput, writeset))
208 {
209 (entry->m_callbackOutput) (entry->m_fdOutput, entry->m_dataOutput);
210 }
211
212 node = Next();
213 }
214}
215
216wxSocketTable* wxTheSocketTable = NULL;
217
218class wxSocketTableModule: public wxModule
219{
220DECLARE_DYNAMIC_CLASS(wxSocketTableModule)
221public:
222 wxSocketTableModule() {}
223 bool OnInit() { wxTheSocketTable = new wxSocketTable; return TRUE; };
224 void OnExit() { delete wxTheSocketTable; wxTheSocketTable = NULL; };
225};
226
227IMPLEMENT_DYNAMIC_CLASS(wxSocketTableModule, wxModule)
228
229// Implement registration functions as C functions so they
230// can be called from gsock11.c
231
232extern "C" void wxRegisterSocketCallback(int fd, wxSocketTableType socketType, wxSocketCallback callback, void* data)
233{
234 if (wxTheSocketTable)
235 {
236 wxTheSocketTable->RegisterCallback(fd, socketType, callback, data);
237 }
238}
239
240extern "C" void wxUnregisterSocketCallback(int fd, wxSocketTableType socketType)
241{
242 if (wxTheSocketTable)
243 {
244 wxTheSocketTable->UnregisterCallback(fd, socketType);
245 }
246}
247#endif
248
249// ----------------------------------------------------------------------------
250// wxEventLoopImpl
251// ----------------------------------------------------------------------------
252
253class WXDLLEXPORT wxEventLoopImpl
254{
255public:
256 // ctor
257 wxEventLoopImpl() { SetExitCode(0); m_keepGoing = FALSE; }
258
259 // process an XEvent, return TRUE if it was processed
260 bool ProcessEvent(XEvent* event);
261
262 // generate an idle message, return TRUE if more idle time requested
263 bool SendIdleEvent();
264
265 // set/get the exit code
266 void SetExitCode(int exitcode) { m_exitcode = exitcode; }
267 int GetExitCode() const { return m_exitcode; }
268
269public:
270 // preprocess an event, return TRUE if processed (i.e. no further
271 // dispatching required)
272 bool PreProcessEvent(XEvent* event);
273
274 // the exit code of the event loop
275 int m_exitcode;
276
277 bool m_keepGoing;
278};
279
280// ============================================================================
281// wxEventLoopImpl implementation
282// ============================================================================
283
284// ----------------------------------------------------------------------------
285// wxEventLoopImpl message processing
286// ----------------------------------------------------------------------------
287
288bool wxEventLoopImpl::ProcessEvent(XEvent *event)
289{
290 // give us the chance to preprocess the message first
291 if ( PreProcessEvent(event) )
292 return TRUE;
293
294 // if it wasn't done, dispatch it to the corresponding window
295 if (wxTheApp)
296 return wxTheApp->ProcessXEvent((WXEvent*) event);
297
298 return FALSE;
299}
300
301bool wxEventLoopImpl::PreProcessEvent(XEvent *event)
302{
303 // TODO
304#if 0
305 HWND hWnd = msg->hwnd;
306 wxWindow *wndThis = wxGetWindowFromHWND((WXHWND)hWnd);
307
308
309 // try translations first; find the youngest window with a translation
310 // table.
311 wxWindow *wnd;
312 for ( wnd = wndThis; wnd; wnd = wnd->GetParent() )
313 {
314 if ( wnd->MSWTranslateMessage((WXMSG *)msg) )
315 return TRUE;
316 }
317
318 // Anyone for a non-translation message? Try youngest descendants first.
319 for ( wnd = wndThis; wnd; wnd = wnd->GetParent() )
320 {
321 if ( wnd->MSWProcessMessage((WXMSG *)msg) )
322 return TRUE;
323 }
324#endif
325
326 return FALSE;
327}
328
329// ----------------------------------------------------------------------------
330// wxEventLoopImpl idle event processing
331// ----------------------------------------------------------------------------
332
333bool wxEventLoopImpl::SendIdleEvent()
334{
335 return wxTheApp->ProcessIdle();
336}
337
338// ============================================================================
339// wxEventLoop implementation
340// ============================================================================
341
342// ----------------------------------------------------------------------------
343// wxEventLoop running and exiting
344// ----------------------------------------------------------------------------
345
346wxEventLoop::~wxEventLoop()
347{
348 wxASSERT_MSG( !m_impl, _T("should have been deleted in Run()") );
349}
350
351int wxEventLoop::Run()
352{
353 // event loops are not recursive, you need to create another loop!
354 wxCHECK_MSG( !IsRunning(), -1, _T("can't reenter a message loop") );
355
356 m_impl = new wxEventLoopImpl;
357
358 wxEventLoopActivator activate(this);
359
360 m_impl->m_keepGoing = TRUE;
361 while ( m_impl->m_keepGoing )
362 {
363#if 0 // wxUSE_THREADS
364 wxMutexGuiLeaveOrEnter();
365#endif // wxUSE_THREADS
366
367 // generate and process idle events for as long as we don't have
368 // anything else to do
369 while ( ! Pending() )
370 {
371#if wxUSE_TIMER
372 wxTimer::NotifyTimers(); // TODO: is this the correct place for it?
373#endif
374 if (!m_impl->SendIdleEvent())
375 {
376#if 0 // wxUSE_THREADS
377 // leave the main loop to give other threads a chance to
378 // perform their GUI work
379 wxMutexGuiLeave();
380 wxUsleep(20);
381 wxMutexGuiEnter();
382#endif
383 // Break out of while loop
384 break;
385 }
386 }
387
388 // a message came or no more idle processing to do, sit in Dispatch()
389 // waiting for the next message
390 if ( !Dispatch() )
391 {
392 break;
393 }
394 }
395
396 int exitcode = m_impl->GetExitCode();
397 delete m_impl;
398 m_impl = NULL;
399
400 return exitcode;
401}
402
403void wxEventLoop::Exit(int rc)
404{
405 wxCHECK_RET( IsRunning(), _T("can't call Exit() if not running") );
406
407 m_impl->SetExitCode(rc);
408 m_impl->m_keepGoing = FALSE;
409}
410
411// ----------------------------------------------------------------------------
412// wxEventLoop message processing dispatching
413// ----------------------------------------------------------------------------
414
415bool wxEventLoop::Pending() const
416{
417 XFlush( wxGlobalDisplay() );
418 return (XPending( wxGlobalDisplay() ) > 0);
419}
420
421bool wxEventLoop::Dispatch()
422{
423 XEvent event;
424
425 // TODO allowing for threads, as per e.g. wxMSW
426
427 // This now waits until either an X event is received,
428 // or the select times out. So we should now process
429 // wxTimers in a reasonably timely fashion. However it
430 // does also mean that idle processing will happen more
431 // often, so we should probably limit idle processing to
432 // not be repeated more than every N milliseconds.
433
434 if (XPending( wxGlobalDisplay() ) == 0)
435 {
436#if wxUSE_NANOX
437 GR_TIMEOUT timeout = 10; // Milliseconds
438 // Wait for next event, or timeout
439 GrGetNextEventTimeout(& event, timeout);
440
441 // Fall through to ProcessEvent.
442 // we'll assume that ProcessEvent will just ignore
443 // the event if there was a timeout and no event.
444
445#else
446 struct timeval tv;
447 tv.tv_sec=0;
448 tv.tv_usec=10000; // TODO make this configurable
449 int fd = ConnectionNumber( wxGlobalDisplay() );
450
451 fd_set readset;
452 fd_set writeset;
453 int highest = fd;
454 wxFD_ZERO(&readset);
455 wxFD_ZERO(&writeset);
456
457 wxFD_SET(fd, &readset);
458
459#if wxUSE_SOCKETS
460 if (wxTheSocketTable)
461 wxTheSocketTable->FillSets( &readset, &writeset, &highest );
462#endif
463
464 if (select( highest+1, &readset, &writeset, NULL, &tv ) == 0)
465 {
466 // Timed out, so no event to process
467 return TRUE;
468 }
469 else
470 {
471 // An X11 event was pending, so get it
472 if (wxFD_ISSET( fd, &readset ))
473 XNextEvent( wxGlobalDisplay(), &event );
474
475#if wxUSE_SOCKETS
476 // Check if any socket events were pending,
477 // and if so, call their callbacks
478 if (wxTheSocketTable)
479 wxTheSocketTable->ProcessEvents( &readset, &writeset );
480#endif
481 }
482#endif
483 }
484 else
485 {
486 XNextEvent( wxGlobalDisplay(), &event );
487 }
488
489
490 (void) m_impl->ProcessEvent( &event );
491 return TRUE;
492}
493