]> git.saurik.com Git - wxWidgets.git/blame_incremental - src/x11/evtloop.cpp
Implement wxChoice::Insert.
[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
342wxEventLoop *wxEventLoopBase::ms_activeLoop = NULL;
343
344// ----------------------------------------------------------------------------
345// wxEventLoop running and exiting
346// ----------------------------------------------------------------------------
347
348wxEventLoop::~wxEventLoop()
349{
350 wxASSERT_MSG( !m_impl, _T("should have been deleted in Run()") );
351}
352
353int wxEventLoop::Run()
354{
355 // event loops are not recursive, you need to create another loop!
356 wxCHECK_MSG( !IsRunning(), -1, _T("can't reenter a message loop") );
357
358 m_impl = new wxEventLoopImpl;
359
360 wxEventLoop *oldLoop = ms_activeLoop;
361 ms_activeLoop = this;
362
363 m_impl->m_keepGoing = TRUE;
364 while ( m_impl->m_keepGoing )
365 {
366#if 0 // wxUSE_THREADS
367 wxMutexGuiLeaveOrEnter();
368#endif // wxUSE_THREADS
369
370 // generate and process idle events for as long as we don't have
371 // anything else to do
372 while ( ! Pending() )
373 {
374#if wxUSE_TIMER
375 wxTimer::NotifyTimers(); // TODO: is this the correct place for it?
376#endif
377 if (!m_impl->SendIdleEvent())
378 {
379#if 0 // wxUSE_THREADS
380 // leave the main loop to give other threads a chance to
381 // perform their GUI work
382 wxMutexGuiLeave();
383 wxUsleep(20);
384 wxMutexGuiEnter();
385#endif
386 // Break out of while loop
387 break;
388 }
389 }
390
391 // a message came or no more idle processing to do, sit in Dispatch()
392 // waiting for the next message
393 if ( !Dispatch() )
394 {
395 break;
396 }
397 }
398
399 int exitcode = m_impl->GetExitCode();
400 delete m_impl;
401 m_impl = NULL;
402
403 ms_activeLoop = oldLoop;
404
405 return exitcode;
406}
407
408void wxEventLoop::Exit(int rc)
409{
410 wxCHECK_RET( IsRunning(), _T("can't call Exit() if not running") );
411
412 m_impl->SetExitCode(rc);
413 m_impl->m_keepGoing = FALSE;
414}
415
416// ----------------------------------------------------------------------------
417// wxEventLoop message processing dispatching
418// ----------------------------------------------------------------------------
419
420bool wxEventLoop::Pending() const
421{
422 XFlush( wxGlobalDisplay() );
423 return (XPending( wxGlobalDisplay() ) > 0);
424}
425
426bool wxEventLoop::Dispatch()
427{
428 XEvent event;
429
430 // TODO allowing for threads, as per e.g. wxMSW
431
432 // This now waits until either an X event is received,
433 // or the select times out. So we should now process
434 // wxTimers in a reasonably timely fashion. However it
435 // does also mean that idle processing will happen more
436 // often, so we should probably limit idle processing to
437 // not be repeated more than every N milliseconds.
438
439 if (XPending( wxGlobalDisplay() ) == 0)
440 {
441#if wxUSE_NANOX
442 GR_TIMEOUT timeout = 10; // Milliseconds
443 // Wait for next event, or timeout
444 GrGetNextEventTimeout(& event, timeout);
445
446 // Fall through to ProcessEvent.
447 // we'll assume that ProcessEvent will just ignore
448 // the event if there was a timeout and no event.
449
450#else
451 struct timeval tv;
452 tv.tv_sec=0;
453 tv.tv_usec=10000; // TODO make this configurable
454 int fd = ConnectionNumber( wxGlobalDisplay() );
455
456 fd_set readset;
457 fd_set writeset;
458 int highest = fd;
459 wxFD_ZERO(&readset);
460 wxFD_ZERO(&writeset);
461
462 wxFD_SET(fd, &readset);
463
464#if wxUSE_SOCKETS
465 if (wxTheSocketTable)
466 wxTheSocketTable->FillSets( &readset, &writeset, &highest );
467#endif
468
469 if (select( highest+1, &readset, &writeset, NULL, &tv ) == 0)
470 {
471 // Timed out, so no event to process
472 return TRUE;
473 }
474 else
475 {
476 // An X11 event was pending, so get it
477 if (wxFD_ISSET( fd, &readset ))
478 XNextEvent( wxGlobalDisplay(), &event );
479
480#if wxUSE_SOCKETS
481 // Check if any socket events were pending,
482 // and if so, call their callbacks
483 if (wxTheSocketTable)
484 wxTheSocketTable->ProcessEvents( &readset, &writeset );
485#endif
486 }
487#endif
488 }
489 else
490 {
491 XNextEvent( wxGlobalDisplay(), &event );
492 }
493
494
495 (void) m_impl->ProcessEvent( &event );
496 return TRUE;
497}
498