diff options
Diffstat (limited to 'apps/plugins/sdl/src/events/SDL_events.c')
-rw-r--r-- | apps/plugins/sdl/src/events/SDL_events.c | 501 |
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 */ | ||
36 | SDL_EventFilter SDL_EventOK = NULL; | ||
37 | Uint8 SDL_ProcessEvents[SDL_NUMEVENTS]; | ||
38 | static Uint32 SDL_eventstate = 0; | ||
39 | |||
40 | /* Private data -- event queue */ | ||
41 | #define MAXEVENTS 128 | ||
42 | static 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 */ | ||
53 | static struct { | ||
54 | SDL_mutex *lock; | ||
55 | int safe; | ||
56 | } SDL_EventLock; | ||
57 | |||
58 | /* Thread functions */ | ||
59 | static SDL_Thread *SDL_EventThread = NULL; /* Thread handle */ | ||
60 | static Uint32 event_thread; /* The event thread id */ | ||
61 | |||
62 | void 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 | } | ||
72 | void 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 | |||
90 | static 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 | |||
144 | static 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 | |||
187 | static 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 | |||
202 | Uint32 SDL_EventThreadID(void) | ||
203 | { | ||
204 | return(event_thread); | ||
205 | } | ||
206 | |||
207 | /* Public functions */ | ||
208 | |||
209 | void 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 */ | ||
227 | int 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 */ | ||
264 | static 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 */ | ||
290 | static 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 */ | ||
318 | int 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 */ | ||
367 | void 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 | |||
392 | int 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 | |||
402 | int 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 | |||
414 | int SDL_PushEvent(SDL_Event *event) | ||
415 | { | ||
416 | if ( SDL_PeepEvents(event, 1, SDL_ADDEVENT, 0) <= 0 ) | ||
417 | return -1; | ||
418 | return 0; | ||
419 | } | ||
420 | |||
421 | void 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 | |||
431 | SDL_EventFilter SDL_GetEventFilter(void) | ||
432 | { | ||
433 | return(SDL_EventOK); | ||
434 | } | ||
435 | |||
436 | Uint8 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 | */ | ||
484 | int 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 | } | ||