1 /*
2   Simple DirectMedia Layer
3   Copyright (C) 1997-2020 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_thread.h"
28 #include "SDL_events_c.h"
29 #include "../timer/SDL_timer_c.h"
30 #if !SDL_JOYSTICK_DISABLED
31 #include "../joystick/SDL_joystick_c.h"
32 #endif
33 #include "../video/SDL_sysvideo.h"
34 #include "SDL_syswm.h"
35 
36 #undef SDL_PRIs64
37 #ifdef __WIN32__
38 #define SDL_PRIs64  "I64d"
39 #else
40 #define SDL_PRIs64  "lld"
41 #endif
42 
43 /* An arbitrary limit so we don't have unbounded growth */
44 #define SDL_MAX_QUEUED_EVENTS   65535
45 
46 typedef struct SDL_EventWatcher {
47     SDL_EventFilter callback;
48     void *userdata;
49     SDL_bool removed;
50 } SDL_EventWatcher;
51 
52 static SDL_mutex *SDL_event_watchers_lock;
53 static SDL_EventWatcher SDL_EventOK;
54 static SDL_EventWatcher *SDL_event_watchers = NULL;
55 static int SDL_event_watchers_count = 0;
56 static SDL_bool SDL_event_watchers_dispatching = SDL_FALSE;
57 static SDL_bool SDL_event_watchers_removed = SDL_FALSE;
58 
59 typedef struct {
60     Uint32 bits[8];
61 } SDL_DisabledEventBlock;
62 
63 static SDL_DisabledEventBlock *SDL_disabled_events[256];
64 static Uint32 SDL_userevents = SDL_USEREVENT;
65 
66 /* Private data -- event queue */
67 typedef struct _SDL_EventEntry
68 {
69     SDL_Event event;
70     SDL_SysWMmsg msg;
71     struct _SDL_EventEntry *prev;
72     struct _SDL_EventEntry *next;
73 } SDL_EventEntry;
74 
75 typedef struct _SDL_SysWMEntry
76 {
77     SDL_SysWMmsg msg;
78     struct _SDL_SysWMEntry *next;
79 } SDL_SysWMEntry;
80 
81 static struct
82 {
83     SDL_mutex *lock;
84     SDL_atomic_t active;
85     SDL_atomic_t count;
86     int max_events_seen;
87     SDL_EventEntry *head;
88     SDL_EventEntry *tail;
89     SDL_EventEntry *free;
90     SDL_SysWMEntry *wmmsg_used;
91     SDL_SysWMEntry *wmmsg_free;
92 } SDL_EventQ = { NULL, { 1 }, { 0 }, 0, NULL, NULL, NULL, NULL, NULL };
93 
94 
95 /* 0 (default) means no logging, 1 means logging, 2 means logging with mouse and finger motion */
96 static int SDL_DoEventLogging = 0;
97 
98 static void SDLCALL
SDL_EventLoggingChanged(void * userdata,const char * name,const char * oldValue,const char * hint)99 SDL_EventLoggingChanged(void *userdata, const char *name, const char *oldValue, const char *hint)
100 {
101     SDL_DoEventLogging = (hint && *hint) ? SDL_max(SDL_min(SDL_atoi(hint), 2), 0) : 0;
102 }
103 
104 static void
SDL_LogEvent(const SDL_Event * event)105 SDL_LogEvent(const SDL_Event *event)
106 {
107     char name[32];
108     char details[128];
109 
110     /* mouse/finger motion are spammy, ignore these if they aren't demanded. */
111     if ( (SDL_DoEventLogging < 2) &&
112             ( (event->type == SDL_MOUSEMOTION) ||
113               (event->type == SDL_FINGERMOTION) ) ) {
114         return;
115     }
116 
117     /* this is to make SDL_snprintf() calls cleaner. */
118     #define uint unsigned int
119 
120     name[0] = '\0';
121     details[0] = '\0';
122 
123     /* !!! FIXME: This code is kinda ugly, sorry. */
124 
125     if ((event->type >= SDL_USEREVENT) && (event->type <= SDL_LASTEVENT)) {
126         char plusstr[16];
127         SDL_strlcpy(name, "SDL_USEREVENT", sizeof (name));
128         if (event->type > SDL_USEREVENT) {
129             SDL_snprintf(plusstr, sizeof (plusstr), "+%u", ((uint) event->type) - SDL_USEREVENT);
130         } else {
131             plusstr[0] = '\0';
132         }
133         SDL_snprintf(details, sizeof (details), "%s (timestamp=%u windowid=%u code=%d data1=%p data2=%p)",
134                 plusstr, (uint) event->user.timestamp, (uint) event->user.windowID,
135                 (int) event->user.code, event->user.data1, event->user.data2);
136     }
137 
138     switch (event->type) {
139         #define SDL_EVENT_CASE(x) case x: SDL_strlcpy(name, #x, sizeof (name));
140         SDL_EVENT_CASE(SDL_FIRSTEVENT) SDL_strlcpy(details, " (THIS IS PROBABLY A BUG!)", sizeof (details)); break;
141         SDL_EVENT_CASE(SDL_QUIT) SDL_snprintf(details, sizeof (details), " (timestamp=%u)", (uint) event->quit.timestamp); break;
142         SDL_EVENT_CASE(SDL_APP_TERMINATING) break;
143         SDL_EVENT_CASE(SDL_APP_LOWMEMORY) break;
144         SDL_EVENT_CASE(SDL_APP_WILLENTERBACKGROUND) break;
145         SDL_EVENT_CASE(SDL_APP_DIDENTERBACKGROUND) break;
146         SDL_EVENT_CASE(SDL_APP_WILLENTERFOREGROUND) break;
147         SDL_EVENT_CASE(SDL_APP_DIDENTERFOREGROUND) break;
148         SDL_EVENT_CASE(SDL_KEYMAPCHANGED) break;
149         SDL_EVENT_CASE(SDL_CLIPBOARDUPDATE) break;
150         SDL_EVENT_CASE(SDL_RENDER_TARGETS_RESET) break;
151         SDL_EVENT_CASE(SDL_RENDER_DEVICE_RESET) break;
152 
153         SDL_EVENT_CASE(SDL_WINDOWEVENT) {
154             char name2[64];
155             switch(event->window.event) {
156                 case SDL_WINDOWEVENT_NONE: SDL_strlcpy(name2, "SDL_WINDOWEVENT_NONE (THIS IS PROBABLY A BUG!)", sizeof (name2)); break;
157                 #define SDL_WINDOWEVENT_CASE(x) case x: SDL_strlcpy(name2, #x, sizeof (name2)); break
158                 SDL_WINDOWEVENT_CASE(SDL_WINDOWEVENT_SHOWN);
159                 SDL_WINDOWEVENT_CASE(SDL_WINDOWEVENT_HIDDEN);
160                 SDL_WINDOWEVENT_CASE(SDL_WINDOWEVENT_EXPOSED);
161                 SDL_WINDOWEVENT_CASE(SDL_WINDOWEVENT_MOVED);
162                 SDL_WINDOWEVENT_CASE(SDL_WINDOWEVENT_RESIZED);
163                 SDL_WINDOWEVENT_CASE(SDL_WINDOWEVENT_SIZE_CHANGED);
164                 SDL_WINDOWEVENT_CASE(SDL_WINDOWEVENT_MINIMIZED);
165                 SDL_WINDOWEVENT_CASE(SDL_WINDOWEVENT_MAXIMIZED);
166                 SDL_WINDOWEVENT_CASE(SDL_WINDOWEVENT_RESTORED);
167                 SDL_WINDOWEVENT_CASE(SDL_WINDOWEVENT_ENTER);
168                 SDL_WINDOWEVENT_CASE(SDL_WINDOWEVENT_LEAVE);
169                 SDL_WINDOWEVENT_CASE(SDL_WINDOWEVENT_FOCUS_GAINED);
170                 SDL_WINDOWEVENT_CASE(SDL_WINDOWEVENT_FOCUS_LOST);
171                 SDL_WINDOWEVENT_CASE(SDL_WINDOWEVENT_CLOSE);
172                 SDL_WINDOWEVENT_CASE(SDL_WINDOWEVENT_TAKE_FOCUS);
173                 SDL_WINDOWEVENT_CASE(SDL_WINDOWEVENT_HIT_TEST);
174                 #undef SDL_WINDOWEVENT_CASE
175                 default: SDL_strlcpy(name2, "UNKNOWN (bug? fixme?)", sizeof (name2)); break;
176             }
177             SDL_snprintf(details, sizeof (details), " (timestamp=%u windowid=%u event=%s data1=%d data2=%d)",
178                         (uint) event->window.timestamp, (uint) event->window.windowID, name2, (int) event->window.data1, (int) event->window.data2);
179             break;
180         }
181 
182         SDL_EVENT_CASE(SDL_SYSWMEVENT)
183             /* !!! FIXME: we don't delve further at the moment. */
184             SDL_snprintf(details, sizeof (details), " (timestamp=%u)", (uint) event->syswm.timestamp);
185             break;
186 
187         #define PRINT_KEY_EVENT(event) \
188             SDL_snprintf(details, sizeof (details), " (timestamp=%u windowid=%u state=%s repeat=%s scancode=%u keycode=%u mod=%u)", \
189                 (uint) event->key.timestamp, (uint) event->key.windowID, \
190                 event->key.state == SDL_PRESSED ? "pressed" : "released", \
191                 event->key.repeat ? "true" : "false", \
192                 (uint) event->key.keysym.scancode, \
193                 (uint) event->key.keysym.sym, \
194                 (uint) event->key.keysym.mod)
195         SDL_EVENT_CASE(SDL_KEYDOWN) PRINT_KEY_EVENT(event); break;
196         SDL_EVENT_CASE(SDL_KEYUP) PRINT_KEY_EVENT(event); break;
197         #undef PRINT_KEY_EVENT
198 
199         SDL_EVENT_CASE(SDL_TEXTEDITING)
200             SDL_snprintf(details, sizeof (details), " (timestamp=%u windowid=%u text='%s' start=%d length=%d)",
201                 (uint) event->edit.timestamp, (uint) event->edit.windowID,
202                 event->edit.text, (int) event->edit.start, (int) event->edit.length);
203             break;
204 
205         SDL_EVENT_CASE(SDL_TEXTINPUT)
206             SDL_snprintf(details, sizeof (details), " (timestamp=%u windowid=%u text='%s')", (uint) event->text.timestamp, (uint) event->text.windowID, event->text.text);
207             break;
208 
209 
210         SDL_EVENT_CASE(SDL_MOUSEMOTION)
211             SDL_snprintf(details, sizeof (details), " (timestamp=%u windowid=%u which=%u state=%u x=%d y=%d xrel=%d yrel=%d)",
212                     (uint) event->motion.timestamp, (uint) event->motion.windowID,
213                     (uint) event->motion.which, (uint) event->motion.state,
214                     (int) event->motion.x, (int) event->motion.y,
215                     (int) event->motion.xrel, (int) event->motion.yrel);
216             break;
217 
218         #define PRINT_MBUTTON_EVENT(event) \
219             SDL_snprintf(details, sizeof (details), " (timestamp=%u windowid=%u which=%u button=%u state=%s clicks=%u x=%d y=%d)", \
220                     (uint) event->button.timestamp, (uint) event->button.windowID, \
221                     (uint) event->button.which, (uint) event->button.button, \
222                     event->button.state == SDL_PRESSED ? "pressed" : "released", \
223                     (uint) event->button.clicks, (int) event->button.x, (int) event->button.y)
224         SDL_EVENT_CASE(SDL_MOUSEBUTTONDOWN) PRINT_MBUTTON_EVENT(event); break;
225         SDL_EVENT_CASE(SDL_MOUSEBUTTONUP) PRINT_MBUTTON_EVENT(event); break;
226         #undef PRINT_MBUTTON_EVENT
227 
228 
229         SDL_EVENT_CASE(SDL_MOUSEWHEEL)
230             SDL_snprintf(details, sizeof (details), " (timestamp=%u windowid=%u which=%u x=%d y=%d direction=%s)",
231                     (uint) event->wheel.timestamp, (uint) event->wheel.windowID,
232                     (uint) event->wheel.which, (int) event->wheel.x, (int) event->wheel.y,
233                     event->wheel.direction == SDL_MOUSEWHEEL_NORMAL ? "normal" : "flipped");
234             break;
235 
236         SDL_EVENT_CASE(SDL_JOYAXISMOTION)
237             SDL_snprintf(details, sizeof (details), " (timestamp=%u which=%d axis=%u value=%d)",
238                 (uint) event->jaxis.timestamp, (int) event->jaxis.which,
239                 (uint) event->jaxis.axis, (int) event->jaxis.value);
240             break;
241 
242         SDL_EVENT_CASE(SDL_JOYBALLMOTION)
243             SDL_snprintf(details, sizeof (details), " (timestamp=%u which=%d ball=%u xrel=%d yrel=%d)",
244                 (uint) event->jball.timestamp, (int) event->jball.which,
245                 (uint) event->jball.ball, (int) event->jball.xrel, (int) event->jball.yrel);
246             break;
247 
248         SDL_EVENT_CASE(SDL_JOYHATMOTION)
249             SDL_snprintf(details, sizeof (details), " (timestamp=%u which=%d hat=%u value=%u)",
250                 (uint) event->jhat.timestamp, (int) event->jhat.which,
251                 (uint) event->jhat.hat, (uint) event->jhat.value);
252             break;
253 
254         #define PRINT_JBUTTON_EVENT(event) \
255             SDL_snprintf(details, sizeof (details), " (timestamp=%u which=%d button=%u state=%s)", \
256                 (uint) event->jbutton.timestamp, (int) event->jbutton.which, \
257                 (uint) event->jbutton.button, event->jbutton.state == SDL_PRESSED ? "pressed" : "released")
258         SDL_EVENT_CASE(SDL_JOYBUTTONDOWN) PRINT_JBUTTON_EVENT(event); break;
259         SDL_EVENT_CASE(SDL_JOYBUTTONUP) PRINT_JBUTTON_EVENT(event); break;
260         #undef PRINT_JBUTTON_EVENT
261 
262         #define PRINT_JOYDEV_EVENT(event) SDL_snprintf(details, sizeof (details), " (timestamp=%u which=%d)", (uint) event->jdevice.timestamp, (int) event->jdevice.which)
263         SDL_EVENT_CASE(SDL_JOYDEVICEADDED) PRINT_JOYDEV_EVENT(event); break;
264         SDL_EVENT_CASE(SDL_JOYDEVICEREMOVED) PRINT_JOYDEV_EVENT(event); break;
265         #undef PRINT_JOYDEV_EVENT
266 
267         SDL_EVENT_CASE(SDL_CONTROLLERAXISMOTION)
268             SDL_snprintf(details, sizeof (details), " (timestamp=%u which=%d axis=%u value=%d)",
269                 (uint) event->caxis.timestamp, (int) event->caxis.which,
270                 (uint) event->caxis.axis, (int) event->caxis.value);
271             break;
272 
273         #define PRINT_CBUTTON_EVENT(event) \
274             SDL_snprintf(details, sizeof (details), " (timestamp=%u which=%d button=%u state=%s)", \
275                 (uint) event->cbutton.timestamp, (int) event->cbutton.which, \
276                 (uint) event->cbutton.button, event->cbutton.state == SDL_PRESSED ? "pressed" : "released")
277         SDL_EVENT_CASE(SDL_CONTROLLERBUTTONDOWN) PRINT_CBUTTON_EVENT(event); break;
278         SDL_EVENT_CASE(SDL_CONTROLLERBUTTONUP) PRINT_CBUTTON_EVENT(event); break;
279         #undef PRINT_CBUTTON_EVENT
280 
281         #define PRINT_CONTROLLERDEV_EVENT(event) SDL_snprintf(details, sizeof (details), " (timestamp=%u which=%d)", (uint) event->cdevice.timestamp, (int) event->cdevice.which)
282         SDL_EVENT_CASE(SDL_CONTROLLERDEVICEADDED) PRINT_CONTROLLERDEV_EVENT(event); break;
283         SDL_EVENT_CASE(SDL_CONTROLLERDEVICEREMOVED) PRINT_CONTROLLERDEV_EVENT(event); break;
284         SDL_EVENT_CASE(SDL_CONTROLLERDEVICEREMAPPED) PRINT_CONTROLLERDEV_EVENT(event); break;
285         #undef PRINT_CONTROLLERDEV_EVENT
286 
287         #define PRINT_FINGER_EVENT(event) \
288             SDL_snprintf(details, sizeof (details), " (timestamp=%u touchid=%"SDL_PRIs64" fingerid=%"SDL_PRIs64" x=%f y=%f dx=%f dy=%f pressure=%f)", \
289                 (uint) event->tfinger.timestamp, (long long)event->tfinger.touchId, \
290                 (long long)event->tfinger.fingerId, event->tfinger.x, event->tfinger.y, \
291                 event->tfinger.dx, event->tfinger.dy, event->tfinger.pressure)
292         SDL_EVENT_CASE(SDL_FINGERDOWN) PRINT_FINGER_EVENT(event); break;
293         SDL_EVENT_CASE(SDL_FINGERUP) PRINT_FINGER_EVENT(event); break;
294         SDL_EVENT_CASE(SDL_FINGERMOTION) PRINT_FINGER_EVENT(event); break;
295         #undef PRINT_FINGER_EVENT
296 
297         #define PRINT_DOLLAR_EVENT(event) \
298             SDL_snprintf(details, sizeof (details), " (timestamp=%u touchid=%"SDL_PRIs64" gestureid=%"SDL_PRIs64" numfingers=%u error=%f x=%f y=%f)", \
299                 (uint) event->dgesture.timestamp, (long long)event->dgesture.touchId, \
300                 (long long)event->dgesture.gestureId, (uint) event->dgesture.numFingers, \
301                 event->dgesture.error, event->dgesture.x, event->dgesture.y);
302         SDL_EVENT_CASE(SDL_DOLLARGESTURE) PRINT_DOLLAR_EVENT(event); break;
303         SDL_EVENT_CASE(SDL_DOLLARRECORD) PRINT_DOLLAR_EVENT(event); break;
304         #undef PRINT_DOLLAR_EVENT
305 
306         SDL_EVENT_CASE(SDL_MULTIGESTURE)
307             SDL_snprintf(details, sizeof (details), " (timestamp=%u touchid=%"SDL_PRIs64" dtheta=%f ddist=%f x=%f y=%f numfingers=%u)",
308                 (uint) event->mgesture.timestamp, (long long)event->mgesture.touchId,
309                 event->mgesture.dTheta, event->mgesture.dDist,
310                 event->mgesture.x, event->mgesture.y, (uint) event->mgesture.numFingers);
311             break;
312 
313         #define PRINT_DROP_EVENT(event) SDL_snprintf(details, sizeof (details), " (file='%s' timestamp=%u windowid=%u)", event->drop.file, (uint) event->drop.timestamp, (uint) event->drop.windowID)
314         SDL_EVENT_CASE(SDL_DROPFILE) PRINT_DROP_EVENT(event); break;
315         SDL_EVENT_CASE(SDL_DROPTEXT) PRINT_DROP_EVENT(event); break;
316         SDL_EVENT_CASE(SDL_DROPBEGIN) PRINT_DROP_EVENT(event); break;
317         SDL_EVENT_CASE(SDL_DROPCOMPLETE) PRINT_DROP_EVENT(event); break;
318         #undef PRINT_DROP_EVENT
319 
320         #define PRINT_AUDIODEV_EVENT(event) SDL_snprintf(details, sizeof (details), " (timestamp=%u which=%u iscapture=%s)", (uint) event->adevice.timestamp, (uint) event->adevice.which, event->adevice.iscapture ? "true" : "false");
321         SDL_EVENT_CASE(SDL_AUDIODEVICEADDED) PRINT_AUDIODEV_EVENT(event); break;
322         SDL_EVENT_CASE(SDL_AUDIODEVICEREMOVED) PRINT_AUDIODEV_EVENT(event); break;
323         #undef PRINT_AUDIODEV_EVENT
324 
325         #undef SDL_EVENT_CASE
326 
327         default:
328             if (!name[0]) {
329                 SDL_strlcpy(name, "UNKNOWN", sizeof (name));
330                 SDL_snprintf(details, sizeof (details), " #%u! (Bug? FIXME?)", (uint) event->type);
331             }
332             break;
333     }
334 
335     if (name[0]) {
336         SDL_Log("SDL EVENT: %s%s", name, details);
337     }
338 
339     #undef uint
340 }
341 
342 
343 
344 /* Public functions */
345 
346 void
SDL_StopEventLoop(void)347 SDL_StopEventLoop(void)
348 {
349     const char *report = SDL_GetHint("SDL_EVENT_QUEUE_STATISTICS");
350     int i;
351     SDL_EventEntry *entry;
352     SDL_SysWMEntry *wmmsg;
353 
354     if (SDL_EventQ.lock) {
355         SDL_LockMutex(SDL_EventQ.lock);
356     }
357 
358     SDL_AtomicSet(&SDL_EventQ.active, 0);
359 
360     if (report && SDL_atoi(report)) {
361         SDL_Log("SDL EVENT QUEUE: Maximum events in-flight: %d\n",
362                 SDL_EventQ.max_events_seen);
363     }
364 
365     /* Clean out EventQ */
366     for (entry = SDL_EventQ.head; entry; ) {
367         SDL_EventEntry *next = entry->next;
368         SDL_free(entry);
369         entry = next;
370     }
371     for (entry = SDL_EventQ.free; entry; ) {
372         SDL_EventEntry *next = entry->next;
373         SDL_free(entry);
374         entry = next;
375     }
376     for (wmmsg = SDL_EventQ.wmmsg_used; wmmsg; ) {
377         SDL_SysWMEntry *next = wmmsg->next;
378         SDL_free(wmmsg);
379         wmmsg = next;
380     }
381     for (wmmsg = SDL_EventQ.wmmsg_free; wmmsg; ) {
382         SDL_SysWMEntry *next = wmmsg->next;
383         SDL_free(wmmsg);
384         wmmsg = next;
385     }
386 
387     SDL_AtomicSet(&SDL_EventQ.count, 0);
388     SDL_EventQ.max_events_seen = 0;
389     SDL_EventQ.head = NULL;
390     SDL_EventQ.tail = NULL;
391     SDL_EventQ.free = NULL;
392     SDL_EventQ.wmmsg_used = NULL;
393     SDL_EventQ.wmmsg_free = NULL;
394 
395     /* Clear disabled event state */
396     for (i = 0; i < SDL_arraysize(SDL_disabled_events); ++i) {
397         SDL_free(SDL_disabled_events[i]);
398         SDL_disabled_events[i] = NULL;
399     }
400 
401     if (SDL_event_watchers_lock) {
402         SDL_DestroyMutex(SDL_event_watchers_lock);
403         SDL_event_watchers_lock = NULL;
404     }
405     if (SDL_event_watchers) {
406         SDL_free(SDL_event_watchers);
407         SDL_event_watchers = NULL;
408         SDL_event_watchers_count = 0;
409     }
410     SDL_zero(SDL_EventOK);
411 
412     if (SDL_EventQ.lock) {
413         SDL_UnlockMutex(SDL_EventQ.lock);
414         SDL_DestroyMutex(SDL_EventQ.lock);
415         SDL_EventQ.lock = NULL;
416     }
417 }
418 
419 /* This function (and associated calls) may be called more than once */
420 int
SDL_StartEventLoop(void)421 SDL_StartEventLoop(void)
422 {
423     /* We'll leave the event queue alone, since we might have gotten
424        some important events at launch (like SDL_DROPFILE)
425 
426        FIXME: Does this introduce any other bugs with events at startup?
427      */
428 
429     /* Create the lock and set ourselves active */
430 #if !SDL_THREADS_DISABLED
431     if (!SDL_EventQ.lock) {
432         SDL_EventQ.lock = SDL_CreateMutex();
433         if (SDL_EventQ.lock == NULL) {
434             return -1;
435         }
436     }
437 
438     if (!SDL_event_watchers_lock) {
439         SDL_event_watchers_lock = SDL_CreateMutex();
440         if (SDL_event_watchers_lock == NULL) {
441             return -1;
442         }
443     }
444 #endif /* !SDL_THREADS_DISABLED */
445 
446     /* Process most event types */
447     SDL_EventState(SDL_TEXTINPUT, SDL_DISABLE);
448     SDL_EventState(SDL_TEXTEDITING, SDL_DISABLE);
449     SDL_EventState(SDL_SYSWMEVENT, SDL_DISABLE);
450 #if 0 /* Leave these events enabled so apps can respond to items being dragged onto them at startup */
451     SDL_EventState(SDL_DROPFILE, SDL_DISABLE);
452     SDL_EventState(SDL_DROPTEXT, SDL_DISABLE);
453 #endif
454 
455     SDL_AtomicSet(&SDL_EventQ.active, 1);
456 
457     return 0;
458 }
459 
460 
461 /* Add an event to the event queue -- called with the queue locked */
462 static int
SDL_AddEvent(SDL_Event * event)463 SDL_AddEvent(SDL_Event * event)
464 {
465     SDL_EventEntry *entry;
466     const int initial_count = SDL_AtomicGet(&SDL_EventQ.count);
467     int final_count;
468 
469     if (initial_count >= SDL_MAX_QUEUED_EVENTS) {
470         SDL_SetError("Event queue is full (%d events)", initial_count);
471         return 0;
472     }
473 
474     if (SDL_EventQ.free == NULL) {
475         entry = (SDL_EventEntry *)SDL_malloc(sizeof(*entry));
476         if (!entry) {
477             return 0;
478         }
479     } else {
480         entry = SDL_EventQ.free;
481         SDL_EventQ.free = entry->next;
482     }
483 
484     if (SDL_DoEventLogging) {
485         SDL_LogEvent(event);
486     }
487 
488     entry->event = *event;
489     if (event->type == SDL_SYSWMEVENT) {
490         entry->msg = *event->syswm.msg;
491         entry->event.syswm.msg = &entry->msg;
492     }
493 
494     if (SDL_EventQ.tail) {
495         SDL_EventQ.tail->next = entry;
496         entry->prev = SDL_EventQ.tail;
497         SDL_EventQ.tail = entry;
498         entry->next = NULL;
499     } else {
500         SDL_assert(!SDL_EventQ.head);
501         SDL_EventQ.head = entry;
502         SDL_EventQ.tail = entry;
503         entry->prev = NULL;
504         entry->next = NULL;
505     }
506 
507     final_count = SDL_AtomicAdd(&SDL_EventQ.count, 1) + 1;
508     if (final_count > SDL_EventQ.max_events_seen) {
509         SDL_EventQ.max_events_seen = final_count;
510     }
511 
512     return 1;
513 }
514 
515 /* Remove an event from the queue -- called with the queue locked */
516 static void
SDL_CutEvent(SDL_EventEntry * entry)517 SDL_CutEvent(SDL_EventEntry *entry)
518 {
519     if (entry->prev) {
520         entry->prev->next = entry->next;
521     }
522     if (entry->next) {
523         entry->next->prev = entry->prev;
524     }
525 
526     if (entry == SDL_EventQ.head) {
527         SDL_assert(entry->prev == NULL);
528         SDL_EventQ.head = entry->next;
529     }
530     if (entry == SDL_EventQ.tail) {
531         SDL_assert(entry->next == NULL);
532         SDL_EventQ.tail = entry->prev;
533     }
534 
535     entry->next = SDL_EventQ.free;
536     SDL_EventQ.free = entry;
537     SDL_assert(SDL_AtomicGet(&SDL_EventQ.count) > 0);
538     SDL_AtomicAdd(&SDL_EventQ.count, -1);
539 }
540 
541 /* Lock the event queue, take a peep at it, and unlock it */
542 int
SDL_PeepEvents(SDL_Event * events,int numevents,SDL_eventaction action,Uint32 minType,Uint32 maxType)543 SDL_PeepEvents(SDL_Event * events, int numevents, SDL_eventaction action,
544                Uint32 minType, Uint32 maxType)
545 {
546     int i, used;
547 
548     /* Don't look after we've quit */
549     if (!SDL_AtomicGet(&SDL_EventQ.active)) {
550         /* We get a few spurious events at shutdown, so don't warn then */
551         if (action != SDL_ADDEVENT) {
552             SDL_SetError("The event system has been shut down");
553         }
554         return (-1);
555     }
556     /* Lock the event queue */
557     used = 0;
558     if (!SDL_EventQ.lock || SDL_LockMutex(SDL_EventQ.lock) == 0) {
559         if (action == SDL_ADDEVENT) {
560             for (i = 0; i < numevents; ++i) {
561                 used += SDL_AddEvent(&events[i]);
562             }
563         } else {
564             SDL_EventEntry *entry, *next;
565             SDL_SysWMEntry *wmmsg, *wmmsg_next;
566             Uint32 type;
567 
568             if (action == SDL_GETEVENT) {
569                 /* Clean out any used wmmsg data
570                    FIXME: Do we want to retain the data for some period of time?
571                  */
572                 for (wmmsg = SDL_EventQ.wmmsg_used; wmmsg; wmmsg = wmmsg_next) {
573                     wmmsg_next = wmmsg->next;
574                     wmmsg->next = SDL_EventQ.wmmsg_free;
575                     SDL_EventQ.wmmsg_free = wmmsg;
576                 }
577                 SDL_EventQ.wmmsg_used = NULL;
578             }
579 
580             for (entry = SDL_EventQ.head; entry && (!events || used < numevents); entry = next) {
581                 next = entry->next;
582                 type = entry->event.type;
583                 if (minType <= type && type <= maxType) {
584                     if (events) {
585                         events[used] = entry->event;
586                         if (entry->event.type == SDL_SYSWMEVENT) {
587                             /* We need to copy the wmmsg somewhere safe.
588                                For now we'll guarantee it's valid at least until
589                                the next call to SDL_PeepEvents()
590                              */
591                             if (SDL_EventQ.wmmsg_free) {
592                                 wmmsg = SDL_EventQ.wmmsg_free;
593                                 SDL_EventQ.wmmsg_free = wmmsg->next;
594                             } else {
595                                 wmmsg = (SDL_SysWMEntry *)SDL_malloc(sizeof(*wmmsg));
596                             }
597                             wmmsg->msg = *entry->event.syswm.msg;
598                             wmmsg->next = SDL_EventQ.wmmsg_used;
599                             SDL_EventQ.wmmsg_used = wmmsg;
600                             events[used].syswm.msg = &wmmsg->msg;
601                         }
602 
603                         if (action == SDL_GETEVENT) {
604                             SDL_CutEvent(entry);
605                         }
606                     }
607                     ++used;
608                 }
609             }
610         }
611         if (SDL_EventQ.lock) {
612             SDL_UnlockMutex(SDL_EventQ.lock);
613         }
614     } else {
615         return SDL_SetError("Couldn't lock event queue");
616     }
617     return (used);
618 }
619 
620 SDL_bool
SDL_HasEvent(Uint32 type)621 SDL_HasEvent(Uint32 type)
622 {
623     return (SDL_PeepEvents(NULL, 0, SDL_PEEKEVENT, type, type) > 0);
624 }
625 
626 SDL_bool
SDL_HasEvents(Uint32 minType,Uint32 maxType)627 SDL_HasEvents(Uint32 minType, Uint32 maxType)
628 {
629     return (SDL_PeepEvents(NULL, 0, SDL_PEEKEVENT, minType, maxType) > 0);
630 }
631 
632 void
SDL_FlushEvent(Uint32 type)633 SDL_FlushEvent(Uint32 type)
634 {
635     SDL_FlushEvents(type, type);
636 }
637 
638 void
SDL_FlushEvents(Uint32 minType,Uint32 maxType)639 SDL_FlushEvents(Uint32 minType, Uint32 maxType)
640 {
641     /* !!! FIXME: we need to manually SDL_free() the strings in TEXTINPUT and
642        drag'n'drop events if we're flushing them without passing them to the
643        app, but I don't know if this is the right place to do that. */
644 
645     /* Don't look after we've quit */
646     if (!SDL_AtomicGet(&SDL_EventQ.active)) {
647         return;
648     }
649 
650     /* Make sure the events are current */
651 #if 0
652     /* Actually, we can't do this since we might be flushing while processing
653        a resize event, and calling this might trigger further resize events.
654     */
655     SDL_PumpEvents();
656 #endif
657 
658     /* Lock the event queue */
659     if (!SDL_EventQ.lock || SDL_LockMutex(SDL_EventQ.lock) == 0) {
660         SDL_EventEntry *entry, *next;
661         Uint32 type;
662         for (entry = SDL_EventQ.head; entry; entry = next) {
663             next = entry->next;
664             type = entry->event.type;
665             if (minType <= type && type <= maxType) {
666                 SDL_CutEvent(entry);
667             }
668         }
669         if (SDL_EventQ.lock) {
670             SDL_UnlockMutex(SDL_EventQ.lock);
671         }
672     }
673 }
674 
675 /* Run the system dependent event loops */
676 void
SDL_PumpEvents(void)677 SDL_PumpEvents(void)
678 {
679     SDL_VideoDevice *_this = SDL_GetVideoDevice();
680 
681     /* Release any keys held down from last frame */
682     SDL_ReleaseAutoReleaseKeys();
683 
684     /* Get events from the video subsystem */
685     if (_this) {
686         _this->PumpEvents(_this);
687     }
688 
689 #if !SDL_JOYSTICK_DISABLED
690     /* Check for joystick state change */
691     if ((!SDL_disabled_events[SDL_JOYAXISMOTION >> 8] || SDL_JoystickEventState(SDL_QUERY))) {
692         SDL_JoystickUpdate();
693     }
694 #endif
695 
696 #if !SDL_SENSOR_DISABLED
697     /* Check for sensor state change */
698     if (!SDL_disabled_events[SDL_SENSORUPDATE >> 8]) {
699         SDL_SensorUpdate();
700     }
701 #endif
702 
703     SDL_SendPendingSignalEvents();  /* in case we had a signal handler fire, etc. */
704 }
705 
706 /* Public functions */
707 
708 int
SDL_PollEvent(SDL_Event * event)709 SDL_PollEvent(SDL_Event * event)
710 {
711     return SDL_WaitEventTimeout(event, 0);
712 }
713 
714 int
SDL_WaitEvent(SDL_Event * event)715 SDL_WaitEvent(SDL_Event * event)
716 {
717     return SDL_WaitEventTimeout(event, -1);
718 }
719 
720 int
SDL_WaitEventTimeout(SDL_Event * event,int timeout)721 SDL_WaitEventTimeout(SDL_Event * event, int timeout)
722 {
723     Uint32 expiration = 0;
724 
725     if (timeout > 0)
726         expiration = SDL_GetTicks() + timeout;
727 
728     for (;;) {
729         SDL_PumpEvents();
730         switch (SDL_PeepEvents(event, 1, SDL_GETEVENT, SDL_FIRSTEVENT, SDL_LASTEVENT)) {
731         case -1:
732             return 0;
733         case 0:
734             if (timeout == 0) {
735                 /* Polling and no events, just return */
736                 return 0;
737             }
738             if (timeout > 0 && SDL_TICKS_PASSED(SDL_GetTicks(), expiration)) {
739                 /* Timeout expired and no events */
740                 return 0;
741             }
742             SDL_Delay(1);
743             break;
744         default:
745             /* Has events */
746             return 1;
747         }
748     }
749 }
750 
751 int
SDL_PushEvent(SDL_Event * event)752 SDL_PushEvent(SDL_Event * event)
753 {
754     event->common.timestamp = SDL_GetTicks();
755 
756     if (SDL_EventOK.callback || SDL_event_watchers_count > 0) {
757         if (!SDL_event_watchers_lock || SDL_LockMutex(SDL_event_watchers_lock) == 0) {
758             if (SDL_EventOK.callback && !SDL_EventOK.callback(SDL_EventOK.userdata, event)) {
759                 if (SDL_event_watchers_lock) {
760                     SDL_UnlockMutex(SDL_event_watchers_lock);
761                 }
762                 return 0;
763             }
764 
765             if (SDL_event_watchers_count > 0) {
766                 /* Make sure we only dispatch the current watcher list */
767                 int i, event_watchers_count = SDL_event_watchers_count;
768 
769                 SDL_event_watchers_dispatching = SDL_TRUE;
770                 for (i = 0; i < event_watchers_count; ++i) {
771                     if (!SDL_event_watchers[i].removed) {
772                         SDL_event_watchers[i].callback(SDL_event_watchers[i].userdata, event);
773                     }
774                 }
775                 SDL_event_watchers_dispatching = SDL_FALSE;
776 
777                 if (SDL_event_watchers_removed) {
778                     for (i = SDL_event_watchers_count; i--; ) {
779                         if (SDL_event_watchers[i].removed) {
780                             --SDL_event_watchers_count;
781                             if (i < SDL_event_watchers_count) {
782                                 SDL_memmove(&SDL_event_watchers[i], &SDL_event_watchers[i+1], (SDL_event_watchers_count - i) * sizeof(SDL_event_watchers[i]));
783                             }
784                         }
785                     }
786                     SDL_event_watchers_removed = SDL_FALSE;
787                 }
788             }
789 
790             if (SDL_event_watchers_lock) {
791                 SDL_UnlockMutex(SDL_event_watchers_lock);
792             }
793         }
794     }
795 
796     if (SDL_PeepEvents(event, 1, SDL_ADDEVENT, 0, 0) <= 0) {
797         return -1;
798     }
799 
800     SDL_GestureProcessEvent(event);
801 
802     return 1;
803 }
804 
805 void
SDL_SetEventFilter(SDL_EventFilter filter,void * userdata)806 SDL_SetEventFilter(SDL_EventFilter filter, void *userdata)
807 {
808     if (!SDL_event_watchers_lock || SDL_LockMutex(SDL_event_watchers_lock) == 0) {
809         /* Set filter and discard pending events */
810         SDL_EventOK.callback = filter;
811         SDL_EventOK.userdata = userdata;
812         SDL_FlushEvents(SDL_FIRSTEVENT, SDL_LASTEVENT);
813 
814         if (SDL_event_watchers_lock) {
815             SDL_UnlockMutex(SDL_event_watchers_lock);
816         }
817     }
818 }
819 
820 SDL_bool
SDL_GetEventFilter(SDL_EventFilter * filter,void ** userdata)821 SDL_GetEventFilter(SDL_EventFilter * filter, void **userdata)
822 {
823     SDL_EventWatcher event_ok;
824 
825     if (!SDL_event_watchers_lock || SDL_LockMutex(SDL_event_watchers_lock) == 0) {
826         event_ok = SDL_EventOK;
827 
828         if (SDL_event_watchers_lock) {
829             SDL_UnlockMutex(SDL_event_watchers_lock);
830         }
831     } else {
832         SDL_zero(event_ok);
833     }
834 
835     if (filter) {
836         *filter = event_ok.callback;
837     }
838     if (userdata) {
839         *userdata = event_ok.userdata;
840     }
841     return event_ok.callback ? SDL_TRUE : SDL_FALSE;
842 }
843 
844 void
SDL_AddEventWatch(SDL_EventFilter filter,void * userdata)845 SDL_AddEventWatch(SDL_EventFilter filter, void *userdata)
846 {
847     if (!SDL_event_watchers_lock || SDL_LockMutex(SDL_event_watchers_lock) == 0) {
848         SDL_EventWatcher *event_watchers;
849 
850         event_watchers = SDL_realloc(SDL_event_watchers, (SDL_event_watchers_count + 1) * sizeof(*event_watchers));
851         if (event_watchers) {
852             SDL_EventWatcher *watcher;
853 
854             SDL_event_watchers = event_watchers;
855             watcher = &SDL_event_watchers[SDL_event_watchers_count];
856             watcher->callback = filter;
857             watcher->userdata = userdata;
858             watcher->removed = SDL_FALSE;
859             ++SDL_event_watchers_count;
860         }
861 
862         if (SDL_event_watchers_lock) {
863             SDL_UnlockMutex(SDL_event_watchers_lock);
864         }
865     }
866 }
867 
868 void
SDL_DelEventWatch(SDL_EventFilter filter,void * userdata)869 SDL_DelEventWatch(SDL_EventFilter filter, void *userdata)
870 {
871     if (!SDL_event_watchers_lock || SDL_LockMutex(SDL_event_watchers_lock) == 0) {
872         int i;
873 
874         for (i = 0; i < SDL_event_watchers_count; ++i) {
875             if (SDL_event_watchers[i].callback == filter && SDL_event_watchers[i].userdata == userdata) {
876                 if (SDL_event_watchers_dispatching) {
877                     SDL_event_watchers[i].removed = SDL_TRUE;
878                     SDL_event_watchers_removed = SDL_TRUE;
879                 } else {
880                     --SDL_event_watchers_count;
881                     if (i < SDL_event_watchers_count) {
882                         SDL_memmove(&SDL_event_watchers[i], &SDL_event_watchers[i+1], (SDL_event_watchers_count - i) * sizeof(SDL_event_watchers[i]));
883                     }
884                 }
885                 break;
886             }
887         }
888 
889         if (SDL_event_watchers_lock) {
890             SDL_UnlockMutex(SDL_event_watchers_lock);
891         }
892     }
893 }
894 
895 void
SDL_FilterEvents(SDL_EventFilter filter,void * userdata)896 SDL_FilterEvents(SDL_EventFilter filter, void *userdata)
897 {
898     if (!SDL_EventQ.lock || SDL_LockMutex(SDL_EventQ.lock) == 0) {
899         SDL_EventEntry *entry, *next;
900         for (entry = SDL_EventQ.head; entry; entry = next) {
901             next = entry->next;
902             if (!filter(userdata, &entry->event)) {
903                 SDL_CutEvent(entry);
904             }
905         }
906         if (SDL_EventQ.lock) {
907             SDL_UnlockMutex(SDL_EventQ.lock);
908         }
909     }
910 }
911 
912 Uint8
SDL_EventState(Uint32 type,int state)913 SDL_EventState(Uint32 type, int state)
914 {
915     const SDL_bool isdnd = ((state == SDL_DISABLE) || (state == SDL_ENABLE)) &&
916                            ((type == SDL_DROPFILE) || (type == SDL_DROPTEXT));
917     Uint8 current_state;
918     Uint8 hi = ((type >> 8) & 0xff);
919     Uint8 lo = (type & 0xff);
920 
921     if (SDL_disabled_events[hi] &&
922         (SDL_disabled_events[hi]->bits[lo/32] & (1 << (lo&31)))) {
923         current_state = SDL_DISABLE;
924     } else {
925         current_state = SDL_ENABLE;
926     }
927 
928     if (state != current_state)
929     {
930         switch (state) {
931         case SDL_DISABLE:
932             /* Disable this event type and discard pending events */
933             if (!SDL_disabled_events[hi]) {
934                 SDL_disabled_events[hi] = (SDL_DisabledEventBlock*) SDL_calloc(1, sizeof(SDL_DisabledEventBlock));
935                 if (!SDL_disabled_events[hi]) {
936                     /* Out of memory, nothing we can do... */
937                     break;
938                 }
939             }
940             SDL_disabled_events[hi]->bits[lo/32] |= (1 << (lo&31));
941             SDL_FlushEvent(type);
942             break;
943         case SDL_ENABLE:
944             SDL_disabled_events[hi]->bits[lo/32] &= ~(1 << (lo&31));
945             break;
946         default:
947             /* Querying state... */
948             break;
949         }
950     }
951 
952     /* turn off drag'n'drop support if we've disabled the events.
953        This might change some UI details at the OS level. */
954     if (isdnd) {
955         SDL_ToggleDragAndDropSupport();
956     }
957 
958     return current_state;
959 }
960 
961 Uint32
SDL_RegisterEvents(int numevents)962 SDL_RegisterEvents(int numevents)
963 {
964     Uint32 event_base;
965 
966     if ((numevents > 0) && (SDL_userevents+numevents <= SDL_LASTEVENT)) {
967         event_base = SDL_userevents;
968         SDL_userevents += numevents;
969     } else {
970         event_base = (Uint32)-1;
971     }
972     return event_base;
973 }
974 
975 int
SDL_SendAppEvent(SDL_EventType eventType)976 SDL_SendAppEvent(SDL_EventType eventType)
977 {
978     int posted;
979 
980     posted = 0;
981     if (SDL_GetEventState(eventType) == SDL_ENABLE) {
982         SDL_Event event;
983         event.type = eventType;
984         posted = (SDL_PushEvent(&event) > 0);
985     }
986     return (posted);
987 }
988 
989 int
SDL_SendSysWMEvent(SDL_SysWMmsg * message)990 SDL_SendSysWMEvent(SDL_SysWMmsg * message)
991 {
992     int posted;
993 
994     posted = 0;
995     if (SDL_GetEventState(SDL_SYSWMEVENT) == SDL_ENABLE) {
996         SDL_Event event;
997         SDL_memset(&event, 0, sizeof(event));
998         event.type = SDL_SYSWMEVENT;
999         event.syswm.msg = message;
1000         posted = (SDL_PushEvent(&event) > 0);
1001     }
1002     /* Update internal event state */
1003     return (posted);
1004 }
1005 
1006 int
SDL_SendKeymapChangedEvent(void)1007 SDL_SendKeymapChangedEvent(void)
1008 {
1009     return SDL_SendAppEvent(SDL_KEYMAPCHANGED);
1010 }
1011 
1012 int
SDL_SendLocaleChangedEvent(void)1013 SDL_SendLocaleChangedEvent(void)
1014 {
1015     return SDL_SendAppEvent(SDL_LOCALECHANGED);
1016 }
1017 
1018 int
SDL_EventsInit(void)1019 SDL_EventsInit(void)
1020 {
1021     SDL_AddHintCallback(SDL_HINT_EVENT_LOGGING, SDL_EventLoggingChanged, NULL);
1022     if (SDL_StartEventLoop() < 0) {
1023         SDL_DelHintCallback(SDL_HINT_EVENT_LOGGING, SDL_EventLoggingChanged, NULL);
1024         return -1;
1025     }
1026 
1027     SDL_QuitInit();
1028 
1029     return 0;
1030 }
1031 
1032 void
SDL_EventsQuit(void)1033 SDL_EventsQuit(void)
1034 {
1035     SDL_QuitQuit();
1036     SDL_StopEventLoop();
1037     SDL_DelHintCallback(SDL_HINT_EVENT_LOGGING, SDL_EventLoggingChanged, NULL);
1038 }
1039 
1040 /* vi: set ts=4 sw=4 expandtab: */
1041