summaryrefslogtreecommitdiff
path: root/apps/plugins/sdl/src/events/SDL_events.c
diff options
context:
space:
mode:
Diffstat (limited to 'apps/plugins/sdl/src/events/SDL_events.c')
-rw-r--r--apps/plugins/sdl/src/events/SDL_events.c501
1 files changed, 501 insertions, 0 deletions
diff --git a/apps/plugins/sdl/src/events/SDL_events.c b/apps/plugins/sdl/src/events/SDL_events.c
new file mode 100644
index 0000000000..6a146e45ff
--- /dev/null
+++ b/apps/plugins/sdl/src/events/SDL_events.c
@@ -0,0 +1,501 @@
1/*
2 SDL - Simple DirectMedia Layer
3 Copyright (C) 1997-2012 Sam Lantinga
4
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.
9
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.
14
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
18
19 Sam Lantinga
20 slouken@libsdl.org
21*/
22#include "SDL_config.h"
23
24/* General event handling code for SDL */
25
26#include "SDL.h"
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"
33#endif
34
35/* Public data -- the event filter */
36SDL_EventFilter SDL_EventOK = NULL;
37Uint8 SDL_ProcessEvents[SDL_NUMEVENTS];
38static Uint32 SDL_eventstate = 0;
39
40/* Private data -- event queue */
41#define MAXEVENTS 128
42static struct {
43 SDL_mutex *lock;
44 int active;
45 int head;
46 int tail;
47 SDL_Event event[MAXEVENTS];
48 int wmmsg_next;
49 struct SDL_SysWMmsg wmmsg[MAXEVENTS];
50} SDL_EventQ;
51
52/* Private data -- event locking structure */
53static struct {
54 SDL_mutex *lock;
55 int safe;
56} SDL_EventLock;
57
58/* Thread functions */
59static SDL_Thread *SDL_EventThread = NULL; /* Thread handle */
60static Uint32 event_thread; /* The event thread id */
61
62void SDL_Lock_EventThread(void)
63{
64 if ( SDL_EventThread && (SDL_ThreadID() != event_thread) ) {
65 /* Grab lock and spin until we're sure event thread stopped */
66 SDL_mutexP(SDL_EventLock.lock);
67 while ( ! SDL_EventLock.safe ) {
68 SDL_Delay(1);
69 }
70 }
71}
72void SDL_Unlock_EventThread(void)
73{
74 if ( SDL_EventThread && (SDL_ThreadID() != event_thread) ) {
75 SDL_mutexV(SDL_EventLock.lock);
76 }
77}
78
79#ifdef __OS2__
80/*
81 * We'll increase the priority of GobbleEvents thread, so it will process
82 * events in time for sure! For this, we need the DosSetPriority() API
83 * from the os2.h include file.
84 */
85#define INCL_DOSPROCESS
86#include <os2.h>
87#include <time.h>
88#endif
89
90static int SDLCALL SDL_GobbleEvents(void *unused)
91{
92 event_thread = SDL_ThreadID();
93
94#ifdef __OS2__
95#ifdef USE_DOSSETPRIORITY
96 /* Increase thread priority, so it will process events in time for sure! */
97 DosSetPriority(PRTYS_THREAD, PRTYC_REGULAR, +16, 0);
98#endif
99#endif
100
101 while ( SDL_EventQ.active ) {
102 SDL_VideoDevice *video = current_video;
103 SDL_VideoDevice *this = current_video;
104
105 /* Get events from the video subsystem */
106 if ( video ) {
107 video->PumpEvents(this);
108 }
109
110 /* Queue pending key-repeat events */
111 SDL_CheckKeyRepeat();
112
113#if !SDL_JOYSTICK_DISABLED
114 /* Check for joystick state change */
115 if ( SDL_numjoysticks && (SDL_eventstate & SDL_JOYEVENTMASK) ) {
116 SDL_JoystickUpdate();
117 }
118#endif
119
120 /* Give up the CPU for the rest of our timeslice */
121 SDL_EventLock.safe = 1;
122 if ( SDL_timer_running ) {
123 SDL_ThreadedTimerCheck();
124 }
125 SDL_Delay(1);
126
127 /* Check for event locking.
128 On the P of the lock mutex, if the lock is held, this thread
129 will wait until the lock is released before continuing. The
130 safe flag will be set, meaning that the other thread can go
131 about it's business. The safe flag is reset before the V,
132 so as soon as the mutex is free, other threads can see that
133 it's not safe to interfere with the event thread.
134 */
135 SDL_mutexP(SDL_EventLock.lock);
136 SDL_EventLock.safe = 0;
137 SDL_mutexV(SDL_EventLock.lock);
138 }
139 SDL_SetTimerThreaded(0);
140 event_thread = 0;
141 return(0);
142}
143
144static int SDL_StartEventThread(Uint32 flags)
145{
146 /* Reset everything to zero */
147 SDL_EventThread = NULL;
148 SDL_memset(&SDL_EventLock, 0, sizeof(SDL_EventLock));
149
150 /* Create the lock and set ourselves active */
151#if !SDL_THREADS_DISABLED
152 SDL_EventQ.lock = SDL_CreateMutex();
153 if ( SDL_EventQ.lock == NULL ) {
154#ifdef __MACOS__ /* MacOS classic you can't multithread, so no lock needed */
155 ;
156#else
157 return(-1);
158#endif
159 }
160#endif /* !SDL_THREADS_DISABLED */
161 SDL_EventQ.active = 1;
162
163 if ( (flags&SDL_INIT_EVENTTHREAD) == SDL_INIT_EVENTTHREAD ) {
164 SDL_EventLock.lock = SDL_CreateMutex();
165 if ( SDL_EventLock.lock == NULL ) {
166 return(-1);
167 }
168 SDL_EventLock.safe = 0;
169
170 /* The event thread will handle timers too */
171 SDL_SetTimerThreaded(2);
172#if (defined(__WIN32__) && !defined(_WIN32_WCE)) && !defined(HAVE_LIBC) && !defined(__SYMBIAN32__)
173#undef SDL_CreateThread
174 SDL_EventThread = SDL_CreateThread(SDL_GobbleEvents, NULL, NULL, NULL);
175#else
176 SDL_EventThread = SDL_CreateThread(SDL_GobbleEvents, NULL);
177#endif
178 if ( SDL_EventThread == NULL ) {
179 return(-1);
180 }
181 } else {
182 event_thread = 0;
183 }
184 return(0);
185}
186
187static void SDL_StopEventThread(void)
188{
189 SDL_EventQ.active = 0;
190 if ( SDL_EventThread ) {
191 SDL_WaitThread(SDL_EventThread, NULL);
192 SDL_EventThread = NULL;
193 SDL_DestroyMutex(SDL_EventLock.lock);
194 SDL_EventLock.lock = NULL;
195 }
196#ifndef IPOD
197 SDL_DestroyMutex(SDL_EventQ.lock);
198 SDL_EventQ.lock = NULL;
199#endif
200}
201
202Uint32 SDL_EventThreadID(void)
203{
204 return(event_thread);
205}
206
207/* Public functions */
208
209void SDL_StopEventLoop(void)
210{
211 /* Halt the event thread, if running */
212 SDL_StopEventThread();
213
214 /* Shutdown event handlers */
215 SDL_AppActiveQuit();
216 SDL_KeyboardQuit();
217 SDL_MouseQuit();
218 SDL_QuitQuit();
219
220 /* Clean out EventQ */
221 SDL_EventQ.head = 0;
222 SDL_EventQ.tail = 0;
223 SDL_EventQ.wmmsg_next = 0;
224}
225
226/* This function (and associated calls) may be called more than once */
227int SDL_StartEventLoop(Uint32 flags)
228{
229 int retcode;
230
231 /* Clean out the event queue */
232 SDL_EventThread = NULL;
233 SDL_EventQ.lock = NULL;
234 SDL_StopEventLoop();
235
236 /* No filter to start with, process most event types */
237 SDL_EventOK = NULL;
238 SDL_memset(SDL_ProcessEvents,SDL_ENABLE,sizeof(SDL_ProcessEvents));
239 SDL_eventstate = ~0;
240 /* It's not save to call SDL_EventState() yet */
241 SDL_eventstate &= ~(0x00000001 << SDL_SYSWMEVENT);
242 SDL_ProcessEvents[SDL_SYSWMEVENT] = SDL_IGNORE;
243
244 /* Initialize event handlers */
245 retcode = 0;
246 retcode += SDL_AppActiveInit();
247 retcode += SDL_KeyboardInit();
248 retcode += SDL_MouseInit();
249 retcode += SDL_QuitInit();
250 if ( retcode < 0 ) {
251 /* We don't expect them to fail, but... */
252 return(-1);
253 }
254 /* Create the lock and event thread */
255 if ( SDL_StartEventThread(flags) < 0 ) {
256 SDL_StopEventLoop();
257 return(-1);
258 }
259 return(0);
260}
261
262
263/* Add an event to the event queue -- called with the queue locked */
264static int SDL_AddEvent(SDL_Event *event)
265{
266 int tail, added;
267
268 tail = (SDL_EventQ.tail+1)%MAXEVENTS;
269 if ( tail == SDL_EventQ.head ) {
270 /* Overflow, drop event */
271 added = 0;
272 } else {
273 SDL_EventQ.event[SDL_EventQ.tail] = *event;
274 if (event->type == SDL_SYSWMEVENT) {
275 /* Note that it's possible to lose an event */
276 int next = SDL_EventQ.wmmsg_next;
277 SDL_EventQ.wmmsg[next] = *event->syswm.msg;
278 SDL_EventQ.event[SDL_EventQ.tail].syswm.msg =
279 &SDL_EventQ.wmmsg[next];
280 SDL_EventQ.wmmsg_next = (next+1)%MAXEVENTS;
281 }
282 SDL_EventQ.tail = tail;
283 added = 1;
284 }
285 return(added);
286}
287
288/* Cut an event, and return the next valid spot, or the tail */
289/* -- called with the queue locked */
290static int SDL_CutEvent(int spot)
291{
292 if ( spot == SDL_EventQ.head ) {
293 SDL_EventQ.head = (SDL_EventQ.head+1)%MAXEVENTS;
294 return(SDL_EventQ.head);
295 } else
296 if ( (spot+1)%MAXEVENTS == SDL_EventQ.tail ) {
297 SDL_EventQ.tail = spot;
298 return(SDL_EventQ.tail);
299 } else
300 /* We cut the middle -- shift everything over */
301 {
302 int here, next;
303
304 /* This can probably be optimized with SDL_memcpy() -- careful! */
305 if ( --SDL_EventQ.tail < 0 ) {
306 SDL_EventQ.tail = MAXEVENTS-1;
307 }
308 for ( here=spot; here != SDL_EventQ.tail; here = next ) {
309 next = (here+1)%MAXEVENTS;
310 SDL_EventQ.event[here] = SDL_EventQ.event[next];
311 }
312 return(spot);
313 }
314 /* NOTREACHED */
315}
316
317/* Lock the event queue, take a peep at it, and unlock it */
318int SDL_PeepEvents(SDL_Event *events, int numevents, SDL_eventaction action,
319 Uint32 mask)
320{
321 int i, used;
322
323 /* Don't look after we've quit */
324 if ( ! SDL_EventQ.active ) {
325 return(-1);
326 }
327 /* Lock the event queue */
328 used = 0;
329 if ( SDL_mutexP(SDL_EventQ.lock) == 0 ) {
330 if ( action == SDL_ADDEVENT ) {
331 for ( i=0; i<numevents; ++i ) {
332 used += SDL_AddEvent(&events[i]);
333 }
334 } else {
335 SDL_Event tmpevent;
336 int spot;
337
338 /* If 'events' is NULL, just see if they exist */
339 if ( events == NULL ) {
340 action = SDL_PEEKEVENT;
341 numevents = 1;
342 events = &tmpevent;
343 }
344 spot = SDL_EventQ.head;
345 while ((used < numevents)&&(spot != SDL_EventQ.tail)) {
346 if ( mask & SDL_EVENTMASK(SDL_EventQ.event[spot].type) ) {
347 events[used++] = SDL_EventQ.event[spot];
348 if ( action == SDL_GETEVENT ) {
349 spot = SDL_CutEvent(spot);
350 } else {
351 spot = (spot+1)%MAXEVENTS;
352 }
353 } else {
354 spot = (spot+1)%MAXEVENTS;
355 }
356 }
357 }
358 SDL_mutexV(SDL_EventQ.lock);
359 } else {
360 SDL_SetError("Couldn't lock event queue");
361 used = -1;
362 }
363 return(used);
364}
365
366/* Run the system dependent event loops */
367void SDL_PumpEvents(void)
368{
369 if ( !SDL_EventThread ) {
370 SDL_VideoDevice *video = current_video;
371 SDL_VideoDevice *this = current_video;
372
373 /* Get events from the video subsystem */
374 if ( video ) {
375 video->PumpEvents(this);
376 }
377
378 /* Queue pending key-repeat events */
379 SDL_CheckKeyRepeat();
380
381#if !SDL_JOYSTICK_DISABLED
382 /* Check for joystick state change */
383 if ( SDL_numjoysticks && (SDL_eventstate & SDL_JOYEVENTMASK) ) {
384 SDL_JoystickUpdate();
385 }
386#endif
387 }
388}
389
390/* Public functions */
391
392int SDL_PollEvent (SDL_Event *event)
393{
394 SDL_PumpEvents();
395
396 /* We can't return -1, just return 0 (no event) on error */
397 if ( SDL_PeepEvents(event, 1, SDL_GETEVENT, SDL_ALLEVENTS) <= 0 )
398 return 0;
399 return 1;
400}
401
402int SDL_WaitEvent (SDL_Event *event)
403{
404 while ( 1 ) {
405 SDL_PumpEvents();
406 switch(SDL_PeepEvents(event, 1, SDL_GETEVENT, SDL_ALLEVENTS)) {
407 case -1: return 0;
408 case 1: return 1;
409 case 0: SDL_Delay(10);
410 }
411 }
412}
413
414int SDL_PushEvent(SDL_Event *event)
415{
416 if ( SDL_PeepEvents(event, 1, SDL_ADDEVENT, 0) <= 0 )
417 return -1;
418 return 0;
419}
420
421void SDL_SetEventFilter (SDL_EventFilter filter)
422{
423 SDL_Event bitbucket;
424
425 /* Set filter and discard pending events */
426 SDL_EventOK = filter;
427 while ( SDL_PollEvent(&bitbucket) > 0 )
428 ;
429}
430
431SDL_EventFilter SDL_GetEventFilter(void)
432{
433 return(SDL_EventOK);
434}
435
436Uint8 SDL_EventState (Uint8 type, int state)
437{
438 SDL_Event bitbucket;
439 Uint8 current_state;
440
441 /* If SDL_ALLEVENTS was specified... */
442 if ( type == 0xFF ) {
443 current_state = SDL_IGNORE;
444 for ( type=0; type<SDL_NUMEVENTS; ++type ) {
445 if ( SDL_ProcessEvents[type] != SDL_IGNORE ) {
446 current_state = SDL_ENABLE;
447 }
448 SDL_ProcessEvents[type] = state;
449 if ( state == SDL_ENABLE ) {
450 SDL_eventstate |= (0x00000001 << (type));
451 } else {
452 SDL_eventstate &= ~(0x00000001 << (type));
453 }
454 }
455 while ( SDL_PollEvent(&bitbucket) > 0 )
456 ;
457 return(current_state);
458 }
459
460 /* Just set the state for one event type */
461 current_state = SDL_ProcessEvents[type];
462 switch (state) {
463 case SDL_IGNORE:
464 case SDL_ENABLE:
465 /* Set state and discard pending events */
466 SDL_ProcessEvents[type] = state;
467 if ( state == SDL_ENABLE ) {
468 SDL_eventstate |= (0x00000001 << (type));
469 } else {
470 SDL_eventstate &= ~(0x00000001 << (type));
471 }
472 while ( SDL_PollEvent(&bitbucket) > 0 )
473 ;
474 break;
475 default:
476 /* Querying state? */
477 break;
478 }
479 return(current_state);
480}
481
482/* This is a generic event handler.
483 */
484int SDL_PrivateSysWMEvent(SDL_SysWMmsg *message)
485{
486 int posted;
487
488 posted = 0;
489 if ( SDL_ProcessEvents[SDL_SYSWMEVENT] == SDL_ENABLE ) {
490 SDL_Event event;
491 SDL_memset(&event, 0, sizeof(event));
492 event.type = SDL_SYSWMEVENT;
493 event.syswm.msg = message;
494 if ( (SDL_EventOK == NULL) || (*SDL_EventOK)(&event) ) {
495 posted = 1;
496 SDL_PushEvent(&event);
497 }
498 }
499 /* Update internal event state */
500 return(posted);
501}