1 /*
2 Simple DirectMedia Layer
3 Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
4
5 This software is provided 'as-is', without any express or implied
6 warranty. In no event will the authors be held liable for any damages
7 arising from the use of this software.
8
9 Permission is granted to anyone to use this software for any purpose,
10 including commercial applications, and to alter it and redistribute it
11 freely, subject to the following restrictions:
12
13 1. The origin of this software must not be misrepresented; you must not
14 claim that you wrote the original software. If you use this software
15 in a product, an acknowledgment in the product documentation would be
16 appreciated but is not required.
17 2. Altered source versions must be plainly marked as such, and must not be
18 misrepresented as being the original software.
19 3. This notice may not be removed or altered from any source distribution.
20 */
21 #include "../SDL_internal.h"
22
23 /* General event handling code for SDL */
24
25 #include "SDL.h"
26 #include "SDL_events.h"
27 #include "SDL_syswm.h"
28 #include "SDL_thread.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 #include "../video/SDL_sysvideo.h"
35
36 /* An arbitrary limit so we don't have unbounded growth */
37 #define SDL_MAX_QUEUED_EVENTS 65535
38
39 /* Public data -- the event filter */
40 SDL_EventFilter SDL_EventOK = NULL;
41 void *SDL_EventOKParam;
42
43 typedef struct SDL_EventWatcher {
44 SDL_EventFilter callback;
45 void *userdata;
46 struct SDL_EventWatcher *next;
47 } SDL_EventWatcher;
48
49 static SDL_EventWatcher *SDL_event_watchers = NULL;
50
51 typedef struct {
52 Uint32 bits[8];
53 } SDL_DisabledEventBlock;
54
55 static SDL_DisabledEventBlock *SDL_disabled_events[256];
56 static Uint32 SDL_userevents = SDL_USEREVENT;
57
58 /* Private data -- event queue */
59 typedef struct _SDL_EventEntry
60 {
61 SDL_Event event;
62 SDL_SysWMmsg msg;
63 struct _SDL_EventEntry *prev;
64 struct _SDL_EventEntry *next;
65 } SDL_EventEntry;
66
67 typedef struct _SDL_SysWMEntry
68 {
69 SDL_SysWMmsg msg;
70 struct _SDL_SysWMEntry *next;
71 } SDL_SysWMEntry;
72
73 static struct
74 {
75 SDL_mutex *lock;
76 SDL_atomic_t active;
77 SDL_atomic_t count;
78 int max_events_seen;
79 SDL_EventEntry *head;
80 SDL_EventEntry *tail;
81 SDL_EventEntry *free;
82 SDL_SysWMEntry *wmmsg_used;
83 SDL_SysWMEntry *wmmsg_free;
84 } SDL_EventQ = { NULL, { 1 }, { 0 }, 0, NULL, NULL, NULL, NULL, NULL };
85
86
87 /* Public functions */
88
89 void
SDL_StopEventLoop(void)90 SDL_StopEventLoop(void)
91 {
92 const char *report = SDL_GetHint("SDL_EVENT_QUEUE_STATISTICS");
93 int i;
94 SDL_EventEntry *entry;
95 SDL_SysWMEntry *wmmsg;
96
97 if (SDL_EventQ.lock) {
98 SDL_LockMutex(SDL_EventQ.lock);
99 }
100
101 SDL_AtomicSet(&SDL_EventQ.active, 0);
102
103 if (report && SDL_atoi(report)) {
104 SDL_Log("SDL EVENT QUEUE: Maximum events in-flight: %d\n",
105 SDL_EventQ.max_events_seen);
106 }
107
108 /* Clean out EventQ */
109 for (entry = SDL_EventQ.head; entry; ) {
110 SDL_EventEntry *next = entry->next;
111 SDL_free(entry);
112 entry = next;
113 }
114 for (entry = SDL_EventQ.free; entry; ) {
115 SDL_EventEntry *next = entry->next;
116 SDL_free(entry);
117 entry = next;
118 }
119 for (wmmsg = SDL_EventQ.wmmsg_used; wmmsg; ) {
120 SDL_SysWMEntry *next = wmmsg->next;
121 SDL_free(wmmsg);
122 wmmsg = next;
123 }
124 for (wmmsg = SDL_EventQ.wmmsg_free; wmmsg; ) {
125 SDL_SysWMEntry *next = wmmsg->next;
126 SDL_free(wmmsg);
127 wmmsg = next;
128 }
129
130 SDL_AtomicSet(&SDL_EventQ.count, 0);
131 SDL_EventQ.max_events_seen = 0;
132 SDL_EventQ.head = NULL;
133 SDL_EventQ.tail = NULL;
134 SDL_EventQ.free = NULL;
135 SDL_EventQ.wmmsg_used = NULL;
136 SDL_EventQ.wmmsg_free = NULL;
137
138 /* Clear disabled event state */
139 for (i = 0; i < SDL_arraysize(SDL_disabled_events); ++i) {
140 SDL_free(SDL_disabled_events[i]);
141 SDL_disabled_events[i] = NULL;
142 }
143
144 while (SDL_event_watchers) {
145 SDL_EventWatcher *tmp = SDL_event_watchers;
146 SDL_event_watchers = tmp->next;
147 SDL_free(tmp);
148 }
149 SDL_EventOK = NULL;
150
151 if (SDL_EventQ.lock) {
152 SDL_UnlockMutex(SDL_EventQ.lock);
153 SDL_DestroyMutex(SDL_EventQ.lock);
154 SDL_EventQ.lock = NULL;
155 }
156 }
157
158 /* This function (and associated calls) may be called more than once */
159 int
SDL_StartEventLoop(void)160 SDL_StartEventLoop(void)
161 {
162 /* We'll leave the event queue alone, since we might have gotten
163 some important events at launch (like SDL_DROPFILE)
164
165 FIXME: Does this introduce any other bugs with events at startup?
166 */
167
168 /* Create the lock and set ourselves active */
169 #if !SDL_THREADS_DISABLED
170 if (!SDL_EventQ.lock) {
171 SDL_EventQ.lock = SDL_CreateMutex();
172 }
173 if (SDL_EventQ.lock == NULL) {
174 return -1;
175 }
176 #endif /* !SDL_THREADS_DISABLED */
177
178 /* Process most event types */
179 SDL_EventState(SDL_TEXTINPUT, SDL_DISABLE);
180 SDL_EventState(SDL_TEXTEDITING, SDL_DISABLE);
181 SDL_EventState(SDL_SYSWMEVENT, SDL_DISABLE);
182
183 SDL_AtomicSet(&SDL_EventQ.active, 1);
184
185 return 0;
186 }
187
188
189 /* Add an event to the event queue -- called with the queue locked */
190 static int
SDL_AddEvent(SDL_Event * event)191 SDL_AddEvent(SDL_Event * event)
192 {
193 SDL_EventEntry *entry;
194 const int initial_count = SDL_AtomicGet(&SDL_EventQ.count);
195 int final_count;
196
197 if (initial_count >= SDL_MAX_QUEUED_EVENTS) {
198 SDL_SetError("Event queue is full (%d events)", initial_count);
199 return 0;
200 }
201
202 if (SDL_EventQ.free == NULL) {
203 entry = (SDL_EventEntry *)SDL_malloc(sizeof(*entry));
204 if (!entry) {
205 return 0;
206 }
207 } else {
208 entry = SDL_EventQ.free;
209 SDL_EventQ.free = entry->next;
210 }
211
212 entry->event = *event;
213 if (event->type == SDL_SYSWMEVENT) {
214 entry->msg = *event->syswm.msg;
215 entry->event.syswm.msg = &entry->msg;
216 }
217
218 if (SDL_EventQ.tail) {
219 SDL_EventQ.tail->next = entry;
220 entry->prev = SDL_EventQ.tail;
221 SDL_EventQ.tail = entry;
222 entry->next = NULL;
223 } else {
224 SDL_assert(!SDL_EventQ.head);
225 SDL_EventQ.head = entry;
226 SDL_EventQ.tail = entry;
227 entry->prev = NULL;
228 entry->next = NULL;
229 }
230
231 final_count = SDL_AtomicAdd(&SDL_EventQ.count, 1) + 1;
232 if (final_count > SDL_EventQ.max_events_seen) {
233 SDL_EventQ.max_events_seen = final_count;
234 }
235
236 return 1;
237 }
238
239 /* Remove an event from the queue -- called with the queue locked */
240 static void
SDL_CutEvent(SDL_EventEntry * entry)241 SDL_CutEvent(SDL_EventEntry *entry)
242 {
243 if (entry->prev) {
244 entry->prev->next = entry->next;
245 }
246 if (entry->next) {
247 entry->next->prev = entry->prev;
248 }
249
250 if (entry == SDL_EventQ.head) {
251 SDL_assert(entry->prev == NULL);
252 SDL_EventQ.head = entry->next;
253 }
254 if (entry == SDL_EventQ.tail) {
255 SDL_assert(entry->next == NULL);
256 SDL_EventQ.tail = entry->prev;
257 }
258
259 entry->next = SDL_EventQ.free;
260 SDL_EventQ.free = entry;
261 SDL_assert(SDL_AtomicGet(&SDL_EventQ.count) > 0);
262 SDL_AtomicAdd(&SDL_EventQ.count, -1);
263 }
264
265 /* Lock the event queue, take a peep at it, and unlock it */
266 int
SDL_PeepEvents(SDL_Event * events,int numevents,SDL_eventaction action,Uint32 minType,Uint32 maxType)267 SDL_PeepEvents(SDL_Event * events, int numevents, SDL_eventaction action,
268 Uint32 minType, Uint32 maxType)
269 {
270 int i, used;
271
272 /* Don't look after we've quit */
273 if (!SDL_AtomicGet(&SDL_EventQ.active)) {
274 /* We get a few spurious events at shutdown, so don't warn then */
275 if (action != SDL_ADDEVENT) {
276 SDL_SetError("The event system has been shut down");
277 }
278 return (-1);
279 }
280 /* Lock the event queue */
281 used = 0;
282 if (!SDL_EventQ.lock || SDL_LockMutex(SDL_EventQ.lock) == 0) {
283 if (action == SDL_ADDEVENT) {
284 for (i = 0; i < numevents; ++i) {
285 used += SDL_AddEvent(&events[i]);
286 }
287 } else {
288 SDL_EventEntry *entry, *next;
289 SDL_SysWMEntry *wmmsg, *wmmsg_next;
290 Uint32 type;
291
292 if (action == SDL_GETEVENT) {
293 /* Clean out any used wmmsg data
294 FIXME: Do we want to retain the data for some period of time?
295 */
296 for (wmmsg = SDL_EventQ.wmmsg_used; wmmsg; wmmsg = wmmsg_next) {
297 wmmsg_next = wmmsg->next;
298 wmmsg->next = SDL_EventQ.wmmsg_free;
299 SDL_EventQ.wmmsg_free = wmmsg;
300 }
301 SDL_EventQ.wmmsg_used = NULL;
302 }
303
304 for (entry = SDL_EventQ.head; entry && (!events || used < numevents); entry = next) {
305 next = entry->next;
306 type = entry->event.type;
307 if (minType <= type && type <= maxType) {
308 if (events) {
309 events[used] = entry->event;
310 if (entry->event.type == SDL_SYSWMEVENT) {
311 /* We need to copy the wmmsg somewhere safe.
312 For now we'll guarantee it's valid at least until
313 the next call to SDL_PeepEvents()
314 */
315 if (SDL_EventQ.wmmsg_free) {
316 wmmsg = SDL_EventQ.wmmsg_free;
317 SDL_EventQ.wmmsg_free = wmmsg->next;
318 } else {
319 wmmsg = (SDL_SysWMEntry *)SDL_malloc(sizeof(*wmmsg));
320 }
321 wmmsg->msg = *entry->event.syswm.msg;
322 wmmsg->next = SDL_EventQ.wmmsg_used;
323 SDL_EventQ.wmmsg_used = wmmsg;
324 events[used].syswm.msg = &wmmsg->msg;
325 }
326
327 if (action == SDL_GETEVENT) {
328 SDL_CutEvent(entry);
329 }
330 }
331 ++used;
332 }
333 }
334 }
335 if (SDL_EventQ.lock) {
336 SDL_UnlockMutex(SDL_EventQ.lock);
337 }
338 } else {
339 return SDL_SetError("Couldn't lock event queue");
340 }
341 return (used);
342 }
343
344 SDL_bool
SDL_HasEvent(Uint32 type)345 SDL_HasEvent(Uint32 type)
346 {
347 return (SDL_PeepEvents(NULL, 0, SDL_PEEKEVENT, type, type) > 0);
348 }
349
350 SDL_bool
SDL_HasEvents(Uint32 minType,Uint32 maxType)351 SDL_HasEvents(Uint32 minType, Uint32 maxType)
352 {
353 return (SDL_PeepEvents(NULL, 0, SDL_PEEKEVENT, minType, maxType) > 0);
354 }
355
356 void
SDL_FlushEvent(Uint32 type)357 SDL_FlushEvent(Uint32 type)
358 {
359 SDL_FlushEvents(type, type);
360 }
361
362 void
SDL_FlushEvents(Uint32 minType,Uint32 maxType)363 SDL_FlushEvents(Uint32 minType, Uint32 maxType)
364 {
365 /* Don't look after we've quit */
366 if (!SDL_AtomicGet(&SDL_EventQ.active)) {
367 return;
368 }
369
370 /* Make sure the events are current */
371 #if 0
372 /* Actually, we can't do this since we might be flushing while processing
373 a resize event, and calling this might trigger further resize events.
374 */
375 SDL_PumpEvents();
376 #endif
377
378 /* Lock the event queue */
379 if (SDL_EventQ.lock && SDL_LockMutex(SDL_EventQ.lock) == 0) {
380 SDL_EventEntry *entry, *next;
381 Uint32 type;
382 for (entry = SDL_EventQ.head; entry; entry = next) {
383 next = entry->next;
384 type = entry->event.type;
385 if (minType <= type && type <= maxType) {
386 SDL_CutEvent(entry);
387 }
388 }
389 SDL_UnlockMutex(SDL_EventQ.lock);
390 }
391 }
392
393 /* Run the system dependent event loops */
394 void
SDL_PumpEvents(void)395 SDL_PumpEvents(void)
396 {
397 SDL_VideoDevice *_this = SDL_GetVideoDevice();
398
399 /* Get events from the video subsystem */
400 if (_this) {
401 _this->PumpEvents(_this);
402 }
403 #if !SDL_JOYSTICK_DISABLED
404 /* Check for joystick state change */
405 if ((!SDL_disabled_events[SDL_JOYAXISMOTION >> 8] || SDL_JoystickEventState(SDL_QUERY))) {
406 SDL_JoystickUpdate();
407 }
408 #endif
409
410 SDL_SendPendingQuit(); /* in case we had a signal handler fire, etc. */
411 }
412
413 /* Public functions */
414
415 int
SDL_PollEvent(SDL_Event * event)416 SDL_PollEvent(SDL_Event * event)
417 {
418 return SDL_WaitEventTimeout(event, 0);
419 }
420
421 int
SDL_WaitEvent(SDL_Event * event)422 SDL_WaitEvent(SDL_Event * event)
423 {
424 return SDL_WaitEventTimeout(event, -1);
425 }
426
427 int
SDL_WaitEventTimeout(SDL_Event * event,int timeout)428 SDL_WaitEventTimeout(SDL_Event * event, int timeout)
429 {
430 Uint32 expiration = 0;
431
432 if (timeout > 0)
433 expiration = SDL_GetTicks() + timeout;
434
435 for (;;) {
436 SDL_PumpEvents();
437 switch (SDL_PeepEvents(event, 1, SDL_GETEVENT, SDL_FIRSTEVENT, SDL_LASTEVENT)) {
438 case -1:
439 return 0;
440 case 0:
441 if (timeout == 0) {
442 /* Polling and no events, just return */
443 return 0;
444 }
445 if (timeout > 0 && SDL_TICKS_PASSED(SDL_GetTicks(), expiration)) {
446 /* Timeout expired and no events */
447 return 0;
448 }
449 SDL_Delay(10);
450 break;
451 default:
452 /* Has events */
453 return 1;
454 }
455 }
456 }
457
458 int
SDL_PushEvent(SDL_Event * event)459 SDL_PushEvent(SDL_Event * event)
460 {
461 SDL_EventWatcher *curr;
462
463 event->common.timestamp = SDL_GetTicks();
464
465 if (SDL_EventOK && !SDL_EventOK(SDL_EventOKParam, event)) {
466 return 0;
467 }
468
469 for (curr = SDL_event_watchers; curr; curr = curr->next) {
470 curr->callback(curr->userdata, event);
471 }
472
473 if (SDL_PeepEvents(event, 1, SDL_ADDEVENT, 0, 0) <= 0) {
474 return -1;
475 }
476
477 SDL_GestureProcessEvent(event);
478
479 return 1;
480 }
481
482 void
SDL_SetEventFilter(SDL_EventFilter filter,void * userdata)483 SDL_SetEventFilter(SDL_EventFilter filter, void *userdata)
484 {
485 /* Set filter and discard pending events */
486 SDL_EventOK = NULL;
487 SDL_FlushEvents(SDL_FIRSTEVENT, SDL_LASTEVENT);
488 SDL_EventOKParam = userdata;
489 SDL_EventOK = filter;
490 }
491
492 SDL_bool
SDL_GetEventFilter(SDL_EventFilter * filter,void ** userdata)493 SDL_GetEventFilter(SDL_EventFilter * filter, void **userdata)
494 {
495 if (filter) {
496 *filter = SDL_EventOK;
497 }
498 if (userdata) {
499 *userdata = SDL_EventOKParam;
500 }
501 return SDL_EventOK ? SDL_TRUE : SDL_FALSE;
502 }
503
504 /* FIXME: This is not thread-safe yet */
505 void
SDL_AddEventWatch(SDL_EventFilter filter,void * userdata)506 SDL_AddEventWatch(SDL_EventFilter filter, void *userdata)
507 {
508 SDL_EventWatcher *watcher, *tail;
509
510 watcher = (SDL_EventWatcher *)SDL_malloc(sizeof(*watcher));
511 if (!watcher) {
512 /* Uh oh... */
513 return;
514 }
515
516 /* create the watcher */
517 watcher->callback = filter;
518 watcher->userdata = userdata;
519 watcher->next = NULL;
520
521 /* add the watcher to the end of the list */
522 if (SDL_event_watchers) {
523 for (tail = SDL_event_watchers; tail->next; tail = tail->next) {
524 continue;
525 }
526 tail->next = watcher;
527 } else {
528 SDL_event_watchers = watcher;
529 }
530 }
531
532 /* FIXME: This is not thread-safe yet */
533 void
SDL_DelEventWatch(SDL_EventFilter filter,void * userdata)534 SDL_DelEventWatch(SDL_EventFilter filter, void *userdata)
535 {
536 SDL_EventWatcher *prev = NULL;
537 SDL_EventWatcher *curr;
538
539 for (curr = SDL_event_watchers; curr; prev = curr, curr = curr->next) {
540 if (curr->callback == filter && curr->userdata == userdata) {
541 if (prev) {
542 prev->next = curr->next;
543 } else {
544 SDL_event_watchers = curr->next;
545 }
546 SDL_free(curr);
547 break;
548 }
549 }
550 }
551
552 void
SDL_FilterEvents(SDL_EventFilter filter,void * userdata)553 SDL_FilterEvents(SDL_EventFilter filter, void *userdata)
554 {
555 if (SDL_EventQ.lock && SDL_LockMutex(SDL_EventQ.lock) == 0) {
556 SDL_EventEntry *entry, *next;
557 for (entry = SDL_EventQ.head; entry; entry = next) {
558 next = entry->next;
559 if (!filter(userdata, &entry->event)) {
560 SDL_CutEvent(entry);
561 }
562 }
563 SDL_UnlockMutex(SDL_EventQ.lock);
564 }
565 }
566
567 Uint8
SDL_EventState(Uint32 type,int state)568 SDL_EventState(Uint32 type, int state)
569 {
570 Uint8 current_state;
571 Uint8 hi = ((type >> 8) & 0xff);
572 Uint8 lo = (type & 0xff);
573
574 if (SDL_disabled_events[hi] &&
575 (SDL_disabled_events[hi]->bits[lo/32] & (1 << (lo&31)))) {
576 current_state = SDL_DISABLE;
577 } else {
578 current_state = SDL_ENABLE;
579 }
580
581 if (state != current_state)
582 {
583 switch (state) {
584 case SDL_DISABLE:
585 /* Disable this event type and discard pending events */
586 if (!SDL_disabled_events[hi]) {
587 SDL_disabled_events[hi] = (SDL_DisabledEventBlock*) SDL_calloc(1, sizeof(SDL_DisabledEventBlock));
588 if (!SDL_disabled_events[hi]) {
589 /* Out of memory, nothing we can do... */
590 break;
591 }
592 }
593 SDL_disabled_events[hi]->bits[lo/32] |= (1 << (lo&31));
594 SDL_FlushEvent(type);
595 break;
596 case SDL_ENABLE:
597 SDL_disabled_events[hi]->bits[lo/32] &= ~(1 << (lo&31));
598 break;
599 default:
600 /* Querying state... */
601 break;
602 }
603 }
604
605 return current_state;
606 }
607
608 Uint32
SDL_RegisterEvents(int numevents)609 SDL_RegisterEvents(int numevents)
610 {
611 Uint32 event_base;
612
613 if ((numevents > 0) && (SDL_userevents+numevents <= SDL_LASTEVENT)) {
614 event_base = SDL_userevents;
615 SDL_userevents += numevents;
616 } else {
617 event_base = (Uint32)-1;
618 }
619 return event_base;
620 }
621
622 int
SDL_SendAppEvent(SDL_EventType eventType)623 SDL_SendAppEvent(SDL_EventType eventType)
624 {
625 int posted;
626
627 posted = 0;
628 if (SDL_GetEventState(eventType) == SDL_ENABLE) {
629 SDL_Event event;
630 event.type = eventType;
631 posted = (SDL_PushEvent(&event) > 0);
632 }
633 return (posted);
634 }
635
636 int
SDL_SendSysWMEvent(SDL_SysWMmsg * message)637 SDL_SendSysWMEvent(SDL_SysWMmsg * message)
638 {
639 int posted;
640
641 posted = 0;
642 if (SDL_GetEventState(SDL_SYSWMEVENT) == SDL_ENABLE) {
643 SDL_Event event;
644 SDL_memset(&event, 0, sizeof(event));
645 event.type = SDL_SYSWMEVENT;
646 event.syswm.msg = message;
647 posted = (SDL_PushEvent(&event) > 0);
648 }
649 /* Update internal event state */
650 return (posted);
651 }
652
653 int
SDL_SendKeymapChangedEvent(void)654 SDL_SendKeymapChangedEvent(void)
655 {
656 return SDL_SendAppEvent(SDL_KEYMAPCHANGED);
657 }
658
659 /* vi: set ts=4 sw=4 expandtab: */
660