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