Added a userdata parameter for event filters.
Added a function to filter the existing queued events.
Added explicit support for relative mouse mode to the API.
2 SDL - Simple DirectMedia Layer
3 Copyright (C) 1997-2006 Sam Lantinga
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public
16 License along with this library; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22 #include "SDL_config.h"
24 /* General event handling code for SDL */
27 #include "SDL_syswm.h"
28 #include "SDL_sysevents.h"
29 #include "SDL_events_c.h"
30 #include "../timer/SDL_timer_c.h"
31 #if !SDL_JOYSTICK_DISABLED
32 #include "../joystick/SDL_joystick_c.h"
35 /* Public data -- the event filter */
36 SDL_EventFilter SDL_EventOK = NULL;
37 void *SDL_EventOKParam;
38 Uint8 SDL_ProcessEvents[SDL_NUMEVENTS];
39 static Uint32 SDL_eventstate = 0;
41 /* Private data -- event queue */
49 SDL_Event event[MAXEVENTS];
51 struct SDL_SysWMmsg wmmsg[MAXEVENTS];
54 /* Private data -- event locking structure */
61 /* Thread functions */
62 static SDL_Thread *SDL_EventThread = NULL; /* Thread handle */
63 static Uint32 event_thread; /* The event thread id */
66 SDL_Lock_EventThread(void)
68 if (SDL_EventThread && (SDL_ThreadID() != event_thread)) {
69 /* Grab lock and spin until we're sure event thread stopped */
70 SDL_mutexP(SDL_EventLock.lock);
71 while (!SDL_EventLock.safe) {
77 SDL_Unlock_EventThread(void)
79 if (SDL_EventThread && (SDL_ThreadID() != event_thread)) {
80 SDL_mutexV(SDL_EventLock.lock);
86 * We'll increase the priority of GobbleEvents thread, so it will process
87 * events in time for sure! For this, we need the DosSetPriority() API
88 * from the os2.h include file.
90 #define INCL_DOSPROCESS
96 SDL_GobbleEvents(void *unused)
98 event_thread = SDL_ThreadID();
101 #ifdef USE_DOSSETPRIORITY
102 /* Increase thread priority, so it will process events in time for sure! */
103 DosSetPriority(PRTYS_THREAD, PRTYC_REGULAR, +16, 0);
107 while (SDL_EventQ.active) {
108 SDL_VideoDevice *_this = SDL_GetVideoDevice();
110 /* Get events from the video subsystem */
112 _this->PumpEvents(_this);
115 /* Queue pending key-repeat events */
116 SDL_CheckKeyRepeat();
118 #if !SDL_JOYSTICK_DISABLED
119 /* Check for joystick state change */
120 if (SDL_numjoysticks && (SDL_eventstate & SDL_JOYEVENTMASK)) {
121 SDL_JoystickUpdate();
125 /* Give up the CPU for the rest of our timeslice */
126 SDL_EventLock.safe = 1;
127 if (SDL_timer_running) {
128 SDL_ThreadedTimerCheck();
132 /* Check for event locking.
133 On the P of the lock mutex, if the lock is held, this thread
134 will wait until the lock is released before continuing. The
135 safe flag will be set, meaning that the other thread can go
136 about it's business. The safe flag is reset before the V,
137 so as soon as the mutex is free, other threads can see that
138 it's not safe to interfere with the event thread.
140 SDL_mutexP(SDL_EventLock.lock);
141 SDL_EventLock.safe = 0;
142 SDL_mutexV(SDL_EventLock.lock);
144 SDL_SetTimerThreaded(0);
150 SDL_StartEventThread(Uint32 flags)
152 /* Reset everything to zero */
153 SDL_EventThread = NULL;
154 SDL_memset(&SDL_EventLock, 0, sizeof(SDL_EventLock));
156 /* Create the lock and set ourselves active */
157 #if !SDL_THREADS_DISABLED
158 SDL_EventQ.lock = SDL_CreateMutex();
159 if (SDL_EventQ.lock == NULL) {
160 #ifdef __MACOS__ /* MacOS classic you can't multithread, so no lock needed */
166 #endif /* !SDL_THREADS_DISABLED */
167 SDL_EventQ.active = 1;
169 if ((flags & SDL_INIT_EVENTTHREAD) == SDL_INIT_EVENTTHREAD) {
170 SDL_EventLock.lock = SDL_CreateMutex();
171 if (SDL_EventLock.lock == NULL) {
174 SDL_EventLock.safe = 0;
176 /* The event thread will handle timers too */
177 SDL_SetTimerThreaded(2);
178 #if (defined(__WIN32__) && !defined(_WIN32_WCE)) && !defined(HAVE_LIBC)
179 #undef SDL_CreateThread
181 SDL_CreateThread(SDL_GobbleEvents, NULL, NULL, NULL);
183 SDL_EventThread = SDL_CreateThread(SDL_GobbleEvents, NULL);
185 if (SDL_EventThread == NULL) {
195 SDL_StopEventThread(void)
197 SDL_EventQ.active = 0;
198 if (SDL_EventThread) {
199 SDL_WaitThread(SDL_EventThread, NULL);
200 SDL_EventThread = NULL;
201 SDL_DestroyMutex(SDL_EventLock.lock);
204 SDL_DestroyMutex(SDL_EventQ.lock);
209 SDL_EventThreadID(void)
211 return (event_thread);
214 /* Public functions */
217 SDL_StopEventLoop(void)
219 /* Halt the event thread, if running */
220 SDL_StopEventThread();
222 /* Shutdown event handlers */
227 /* Clean out EventQ */
230 SDL_EventQ.wmmsg_next = 0;
233 /* This function (and associated calls) may be called more than once */
235 SDL_StartEventLoop(Uint32 flags)
239 /* Clean out the event queue */
240 SDL_EventThread = NULL;
241 SDL_EventQ.lock = NULL;
244 /* No filter to start with, process most event types */
246 SDL_memset(SDL_ProcessEvents, SDL_ENABLE, sizeof(SDL_ProcessEvents));
248 /* It's not save to call SDL_EventState() yet */
249 SDL_eventstate &= ~(0x00000001 << SDL_SYSWMEVENT);
250 SDL_ProcessEvents[SDL_SYSWMEVENT] = SDL_IGNORE;
252 /* Initialize event handlers */
254 retcode += SDL_KeyboardInit();
255 retcode += SDL_MouseInit();
256 retcode += SDL_QuitInit();
258 /* We don't expect them to fail, but... */
262 /* Create the lock and event thread */
263 if (SDL_StartEventThread(flags) < 0) {
271 /* Add an event to the event queue -- called with the queue locked */
273 SDL_AddEvent(SDL_Event * event)
277 tail = (SDL_EventQ.tail + 1) % MAXEVENTS;
278 if (tail == SDL_EventQ.head) {
279 /* Overflow, drop event */
282 SDL_EventQ.event[SDL_EventQ.tail] = *event;
283 if (event->type == SDL_SYSWMEVENT) {
284 /* Note that it's possible to lose an event */
285 int next = SDL_EventQ.wmmsg_next;
286 SDL_EventQ.wmmsg[next] = *event->syswm.msg;
287 SDL_EventQ.event[SDL_EventQ.tail].syswm.msg =
288 &SDL_EventQ.wmmsg[next];
289 SDL_EventQ.wmmsg_next = (next + 1) % MAXEVENTS;
291 SDL_EventQ.tail = tail;
297 /* Cut an event, and return the next valid spot, or the tail */
298 /* -- called with the queue locked */
300 SDL_CutEvent(int spot)
302 if (spot == SDL_EventQ.head) {
303 SDL_EventQ.head = (SDL_EventQ.head + 1) % MAXEVENTS;
304 return (SDL_EventQ.head);
305 } else if ((spot + 1) % MAXEVENTS == SDL_EventQ.tail) {
306 SDL_EventQ.tail = spot;
307 return (SDL_EventQ.tail);
309 /* We cut the middle -- shift everything over */
313 /* This can probably be optimized with SDL_memcpy() -- careful! */
314 if (--SDL_EventQ.tail < 0) {
315 SDL_EventQ.tail = MAXEVENTS - 1;
317 for (here = spot; here != SDL_EventQ.tail; here = next) {
318 next = (here + 1) % MAXEVENTS;
319 SDL_EventQ.event[here] = SDL_EventQ.event[next];
326 /* Lock the event queue, take a peep at it, and unlock it */
328 SDL_PeepEvents(SDL_Event * events, int numevents, SDL_eventaction action,
333 /* Don't look after we've quit */
334 if (!SDL_EventQ.active) {
337 /* Lock the event queue */
339 if (SDL_mutexP(SDL_EventQ.lock) == 0) {
340 if (action == SDL_ADDEVENT) {
341 for (i = 0; i < numevents; ++i) {
342 used += SDL_AddEvent(&events[i]);
348 /* If 'events' is NULL, just see if they exist */
349 if (events == NULL) {
350 action = SDL_PEEKEVENT;
354 spot = SDL_EventQ.head;
355 while ((used < numevents) && (spot != SDL_EventQ.tail)) {
356 if (mask & SDL_EVENTMASK(SDL_EventQ.event[spot].type)) {
357 events[used++] = SDL_EventQ.event[spot];
358 if (action == SDL_GETEVENT) {
359 spot = SDL_CutEvent(spot);
361 spot = (spot + 1) % MAXEVENTS;
364 spot = (spot + 1) % MAXEVENTS;
368 SDL_mutexV(SDL_EventQ.lock);
370 SDL_SetError("Couldn't lock event queue");
376 /* Run the system dependent event loops */
380 if (!SDL_EventThread) {
381 SDL_VideoDevice *_this = SDL_GetVideoDevice();
383 /* Get events from the video subsystem */
385 _this->PumpEvents(_this);
388 /* Queue pending key-repeat events */
389 SDL_CheckKeyRepeat();
391 #if !SDL_JOYSTICK_DISABLED
392 /* Check for joystick state change */
393 if (SDL_numjoysticks && (SDL_eventstate & SDL_JOYEVENTMASK)) {
394 SDL_JoystickUpdate();
400 /* Public functions */
403 SDL_PollEvent(SDL_Event * event)
407 /* We can't return -1, just return 0 (no event) on error */
408 if (SDL_PeepEvents(event, 1, SDL_GETEVENT, SDL_ALLEVENTS) <= 0)
414 SDL_WaitEvent(SDL_Event * event)
418 switch (SDL_PeepEvents(event, 1, SDL_GETEVENT, SDL_ALLEVENTS)) {
430 SDL_PushEvent(SDL_Event * event)
432 if (SDL_PeepEvents(event, 1, SDL_ADDEVENT, 0) <= 0)
438 SDL_SetEventFilter(SDL_EventFilter filter, void *userdata)
442 /* Set filter and discard pending events */
443 SDL_EventOK = filter;
444 SDL_EventOKParam = userdata;
445 while (SDL_PollEvent(&bitbucket) > 0);
449 SDL_GetEventFilter(void **userdata)
452 *userdata = SDL_EventOKParam;
454 return (SDL_EventOK);
458 SDL_FilterEvents(SDL_EventFilter filter, void *userdata)
460 if (SDL_mutexP(SDL_EventQ.lock) == 0) {
463 spot = SDL_EventQ.head;
464 while (spot != SDL_EventQ.tail) {
465 if (filter(userdata, &SDL_EventQ.event[spot])) {
466 spot = (spot + 1) % MAXEVENTS;
468 spot = SDL_CutEvent(spot);
472 SDL_mutexV(SDL_EventQ.lock);
476 SDL_EventState(Uint8 type, int state)
481 /* If SDL_ALLEVENTS was specified... */
483 current_state = SDL_IGNORE;
484 for (type = 0; type < SDL_NUMEVENTS; ++type) {
485 if (SDL_ProcessEvents[type] != SDL_IGNORE) {
486 current_state = SDL_ENABLE;
488 SDL_ProcessEvents[type] = state;
489 if (state == SDL_ENABLE) {
490 SDL_eventstate |= (0x00000001 << (type));
492 SDL_eventstate &= ~(0x00000001 << (type));
495 while (SDL_PollEvent(&bitbucket) > 0);
496 return (current_state);
499 /* Just set the state for one event type */
500 current_state = SDL_ProcessEvents[type];
504 /* Set state and discard pending events */
505 SDL_ProcessEvents[type] = state;
506 if (state == SDL_ENABLE) {
507 SDL_eventstate |= (0x00000001 << (type));
509 SDL_eventstate &= ~(0x00000001 << (type));
511 while (SDL_PollEvent(&bitbucket) > 0);
514 /* Querying state? */
517 return (current_state);
520 /* This is a generic event handler.
523 SDL_PrivateSysWMEvent(SDL_SysWMmsg * message)
528 if (SDL_ProcessEvents[SDL_SYSWMEVENT] == SDL_ENABLE) {
530 SDL_memset(&event, 0, sizeof(event));
531 event.type = SDL_SYSWMEVENT;
532 event.syswm.msg = message;
533 if ((SDL_EventOK == NULL)
534 || (*SDL_EventOK) (SDL_EventOKParam, &event)) {
536 SDL_PushEvent(&event);
539 /* Update internal event state */
543 /* vi: set ts=4 sw=4 expandtab: */