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