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