1/*
2 Simple DirectMedia Layer
3 Copyright (C) 1997-2025 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_events_c.h"
26#include "SDL_eventwatch_c.h"
27#include "SDL_windowevents_c.h"
28#include "../SDL_hints_c.h"
29#include "../audio/SDL_audio_c.h"
30#include "../camera/SDL_camera_c.h"
31#include "../timer/SDL_timer_c.h"
32#ifndef SDL_JOYSTICK_DISABLED
33#include "../joystick/SDL_joystick_c.h"
34#endif
35#ifndef SDL_SENSOR_DISABLED
36#include "../sensor/SDL_sensor_c.h"
37#endif
38#include "../video/SDL_sysvideo.h"
39
40#ifdef SDL_PLATFORM_ANDROID
41#include "../core/android/SDL_android.h"
42#include "../video/android/SDL_androidevents.h"
43#endif
44
45// An arbitrary limit so we don't have unbounded growth
46#define SDL_MAX_QUEUED_EVENTS 65535
47
48// Determines how often we pump events if joystick or sensor subsystems are active
49#define ENUMERATION_POLL_INTERVAL_NS (3 * SDL_NS_PER_SECOND)
50
51// Determines how often to pump events if joysticks or sensors are actively being read
52#define EVENT_POLL_INTERVAL_NS SDL_MS_TO_NS(1)
53
54// Make sure the type in the SDL_Event aligns properly across the union
55SDL_COMPILE_TIME_ASSERT(SDL_Event_type, sizeof(Uint32) == sizeof(SDL_EventType));
56
57#define SDL2_SYSWMEVENT 0x201
58
59#ifdef SDL_VIDEO_DRIVER_WINDOWS
60#include "../core/windows/SDL_windows.h"
61#endif
62
63#ifdef SDL_VIDEO_DRIVER_X11
64#include <X11/Xlib.h>
65#endif
66
67typedef struct SDL2_version
68{
69 Uint8 major;
70 Uint8 minor;
71 Uint8 patch;
72} SDL2_version;
73
74typedef enum
75{
76 SDL2_SYSWM_UNKNOWN
77} SDL2_SYSWM_TYPE;
78
79typedef struct SDL2_SysWMmsg
80{
81 SDL2_version version;
82 SDL2_SYSWM_TYPE subsystem;
83 union
84 {
85#ifdef SDL_VIDEO_DRIVER_WINDOWS
86 struct {
87 HWND hwnd; /**< The window for the message */
88 UINT msg; /**< The type of message */
89 WPARAM wParam; /**< WORD message parameter */
90 LPARAM lParam; /**< LONG message parameter */
91 } win;
92#endif
93#ifdef SDL_VIDEO_DRIVER_X11
94 struct {
95 XEvent event;
96 } x11;
97#endif
98 /* Can't have an empty union */
99 int dummy;
100 } msg;
101} SDL2_SysWMmsg;
102
103static SDL_EventWatchList SDL_event_watchers;
104static SDL_AtomicInt SDL_sentinel_pending;
105static Uint32 SDL_last_event_id = 0;
106
107typedef struct
108{
109 Uint32 bits[8];
110} SDL_DisabledEventBlock;
111
112static SDL_DisabledEventBlock *SDL_disabled_events[256];
113static SDL_AtomicInt SDL_userevents;
114
115typedef struct SDL_TemporaryMemory
116{
117 void *memory;
118 struct SDL_TemporaryMemory *prev;
119 struct SDL_TemporaryMemory *next;
120} SDL_TemporaryMemory;
121
122typedef struct SDL_TemporaryMemoryState
123{
124 SDL_TemporaryMemory *head;
125 SDL_TemporaryMemory *tail;
126} SDL_TemporaryMemoryState;
127
128static SDL_TLSID SDL_temporary_memory;
129
130typedef struct SDL_EventEntry
131{
132 SDL_Event event;
133 SDL_TemporaryMemory *memory;
134 struct SDL_EventEntry *prev;
135 struct SDL_EventEntry *next;
136} SDL_EventEntry;
137
138static struct
139{
140 SDL_Mutex *lock;
141 bool active;
142 SDL_AtomicInt count;
143 int max_events_seen;
144 SDL_EventEntry *head;
145 SDL_EventEntry *tail;
146 SDL_EventEntry *free;
147} SDL_EventQ = { NULL, false, { 0 }, 0, NULL, NULL, NULL };
148
149
150static void SDL_CleanupTemporaryMemory(void *data)
151{
152 SDL_TemporaryMemoryState *state = (SDL_TemporaryMemoryState *)data;
153
154 SDL_FreeTemporaryMemory();
155 SDL_free(state);
156}
157
158static SDL_TemporaryMemoryState *SDL_GetTemporaryMemoryState(bool create)
159{
160 SDL_TemporaryMemoryState *state;
161
162 state = (SDL_TemporaryMemoryState *)SDL_GetTLS(&SDL_temporary_memory);
163 if (!state) {
164 if (!create) {
165 return NULL;
166 }
167
168 state = (SDL_TemporaryMemoryState *)SDL_calloc(1, sizeof(*state));
169 if (!state) {
170 return NULL;
171 }
172
173 if (!SDL_SetTLS(&SDL_temporary_memory, state, SDL_CleanupTemporaryMemory)) {
174 SDL_free(state);
175 return NULL;
176 }
177 }
178 return state;
179}
180
181static SDL_TemporaryMemory *SDL_GetTemporaryMemoryEntry(SDL_TemporaryMemoryState *state, const void *mem)
182{
183 SDL_TemporaryMemory *entry;
184
185 // Start from the end, it's likely to have been recently allocated
186 for (entry = state->tail; entry; entry = entry->prev) {
187 if (mem == entry->memory) {
188 return entry;
189 }
190 }
191 return NULL;
192}
193
194static void SDL_LinkTemporaryMemoryEntry(SDL_TemporaryMemoryState *state, SDL_TemporaryMemory *entry)
195{
196 entry->prev = state->tail;
197 entry->next = NULL;
198
199 if (state->tail) {
200 state->tail->next = entry;
201 } else {
202 state->head = entry;
203 }
204 state->tail = entry;
205}
206
207static void SDL_UnlinkTemporaryMemoryEntry(SDL_TemporaryMemoryState *state, SDL_TemporaryMemory *entry)
208{
209 if (state->head == entry) {
210 state->head = entry->next;
211 }
212 if (state->tail == entry) {
213 state->tail = entry->prev;
214 }
215
216 if (entry->prev) {
217 entry->prev->next = entry->next;
218 }
219 if (entry->next) {
220 entry->next->prev = entry->prev;
221 }
222
223 entry->prev = NULL;
224 entry->next = NULL;
225}
226
227static void SDL_FreeTemporaryMemoryEntry(SDL_TemporaryMemoryState *state, SDL_TemporaryMemory *entry, bool free_data)
228{
229 if (free_data) {
230 SDL_free(entry->memory);
231 }
232 SDL_free(entry);
233}
234
235static void SDL_LinkTemporaryMemoryToEvent(SDL_EventEntry *event, const void *mem)
236{
237 SDL_TemporaryMemoryState *state;
238 SDL_TemporaryMemory *entry;
239
240 state = SDL_GetTemporaryMemoryState(false);
241 if (!state) {
242 return;
243 }
244
245 entry = SDL_GetTemporaryMemoryEntry(state, mem);
246 if (entry) {
247 SDL_UnlinkTemporaryMemoryEntry(state, entry);
248 entry->next = event->memory;
249 event->memory = entry;
250 }
251}
252
253static void SDL_TransferSysWMMemoryToEvent(SDL_EventEntry *event)
254{
255 SDL2_SysWMmsg **wmmsg = (SDL2_SysWMmsg **)((&event->event.common)+1);
256 SDL2_SysWMmsg *mem = SDL_AllocateTemporaryMemory(sizeof(*mem));
257 if (mem) {
258 SDL_copyp(mem, *wmmsg);
259 *wmmsg = mem;
260 SDL_LinkTemporaryMemoryToEvent(event, mem);
261 }
262}
263
264// Transfer the event memory from the thread-local event memory list to the event
265static void SDL_TransferTemporaryMemoryToEvent(SDL_EventEntry *event)
266{
267 switch (event->event.type) {
268 case SDL_EVENT_TEXT_EDITING:
269 SDL_LinkTemporaryMemoryToEvent(event, event->event.edit.text);
270 break;
271 case SDL_EVENT_TEXT_EDITING_CANDIDATES:
272 SDL_LinkTemporaryMemoryToEvent(event, event->event.edit_candidates.candidates);
273 break;
274 case SDL_EVENT_TEXT_INPUT:
275 SDL_LinkTemporaryMemoryToEvent(event, event->event.text.text);
276 break;
277 case SDL_EVENT_DROP_BEGIN:
278 case SDL_EVENT_DROP_FILE:
279 case SDL_EVENT_DROP_TEXT:
280 case SDL_EVENT_DROP_COMPLETE:
281 case SDL_EVENT_DROP_POSITION:
282 SDL_LinkTemporaryMemoryToEvent(event, event->event.drop.source);
283 SDL_LinkTemporaryMemoryToEvent(event, event->event.drop.data);
284 break;
285 case SDL_EVENT_CLIPBOARD_UPDATE:
286 SDL_LinkTemporaryMemoryToEvent(event, event->event.clipboard.mime_types);
287 break;
288 case SDL2_SYSWMEVENT:
289 // We need to copy the stack pointer into temporary memory
290 SDL_TransferSysWMMemoryToEvent(event);
291 break;
292 default:
293 break;
294 }
295}
296
297// Transfer the event memory from the event to the thread-local event memory list
298static void SDL_TransferTemporaryMemoryFromEvent(SDL_EventEntry *event)
299{
300 SDL_TemporaryMemoryState *state;
301 SDL_TemporaryMemory *entry, *next;
302
303 if (!event->memory) {
304 return;
305 }
306
307 state = SDL_GetTemporaryMemoryState(true);
308 if (!state) {
309 return; // this is now a leak, but you probably have bigger problems if malloc failed.
310 }
311
312 for (entry = event->memory; entry; entry = next) {
313 next = entry->next;
314 SDL_LinkTemporaryMemoryEntry(state, entry);
315 }
316 event->memory = NULL;
317}
318
319static void *SDL_FreeLater(void *memory)
320{
321 SDL_TemporaryMemoryState *state;
322
323 if (memory == NULL) {
324 return NULL;
325 }
326
327 // Make sure we're not adding this to the list twice
328 //SDL_assert(!SDL_ClaimTemporaryMemory(memory));
329
330 state = SDL_GetTemporaryMemoryState(true);
331 if (!state) {
332 return memory; // this is now a leak, but you probably have bigger problems if malloc failed.
333 }
334
335 SDL_TemporaryMemory *entry = (SDL_TemporaryMemory *)SDL_malloc(sizeof(*entry));
336 if (!entry) {
337 return memory; // this is now a leak, but you probably have bigger problems if malloc failed. We could probably pool up and reuse entries, though.
338 }
339
340 entry->memory = memory;
341
342 SDL_LinkTemporaryMemoryEntry(state, entry);
343
344 return memory;
345}
346
347void *SDL_AllocateTemporaryMemory(size_t size)
348{
349 return SDL_FreeLater(SDL_malloc(size));
350}
351
352const char *SDL_CreateTemporaryString(const char *string)
353{
354 if (string) {
355 return (const char *)SDL_FreeLater(SDL_strdup(string));
356 }
357 return NULL;
358}
359
360void *SDL_ClaimTemporaryMemory(const void *mem)
361{
362 SDL_TemporaryMemoryState *state;
363
364 state = SDL_GetTemporaryMemoryState(false);
365 if (state && mem) {
366 SDL_TemporaryMemory *entry = SDL_GetTemporaryMemoryEntry(state, mem);
367 if (entry) {
368 SDL_UnlinkTemporaryMemoryEntry(state, entry);
369 SDL_FreeTemporaryMemoryEntry(state, entry, false);
370 return (void *)mem;
371 }
372 }
373 return NULL;
374}
375
376void SDL_FreeTemporaryMemory(void)
377{
378 SDL_TemporaryMemoryState *state;
379
380 state = SDL_GetTemporaryMemoryState(false);
381 if (!state) {
382 return;
383 }
384
385 while (state->head) {
386 SDL_TemporaryMemory *entry = state->head;
387
388 SDL_UnlinkTemporaryMemoryEntry(state, entry);
389 SDL_FreeTemporaryMemoryEntry(state, entry, true);
390 }
391}
392
393#ifndef SDL_JOYSTICK_DISABLED
394
395static bool SDL_update_joysticks = true;
396
397static void SDLCALL SDL_AutoUpdateJoysticksChanged(void *userdata, const char *name, const char *oldValue, const char *hint)
398{
399 SDL_update_joysticks = SDL_GetStringBoolean(hint, true);
400}
401
402#endif // !SDL_JOYSTICK_DISABLED
403
404#ifndef SDL_SENSOR_DISABLED
405
406static bool SDL_update_sensors = true;
407
408static void SDLCALL SDL_AutoUpdateSensorsChanged(void *userdata, const char *name, const char *oldValue, const char *hint)
409{
410 SDL_update_sensors = SDL_GetStringBoolean(hint, true);
411}
412
413#endif // !SDL_SENSOR_DISABLED
414
415static void SDLCALL SDL_PollSentinelChanged(void *userdata, const char *name, const char *oldValue, const char *hint)
416{
417 SDL_SetEventEnabled(SDL_EVENT_POLL_SENTINEL, SDL_GetStringBoolean(hint, true));
418}
419
420/**
421 * Verbosity of logged events as defined in SDL_HINT_EVENT_LOGGING:
422 * - 0: (default) no logging
423 * - 1: logging of most events
424 * - 2: as above, plus mouse, pen, and finger motion
425 */
426static int SDL_EventLoggingVerbosity = 0;
427
428static void SDLCALL SDL_EventLoggingChanged(void *userdata, const char *name, const char *oldValue, const char *hint)
429{
430 SDL_EventLoggingVerbosity = (hint && *hint) ? SDL_clamp(SDL_atoi(hint), 0, 3) : 0;
431}
432
433static void SDL_LogEvent(const SDL_Event *event)
434{
435 static const char *pen_axisnames[] = { "PRESSURE", "XTILT", "YTILT", "DISTANCE", "ROTATION", "SLIDER", "TANGENTIAL_PRESSURE" };
436 SDL_COMPILE_TIME_ASSERT(pen_axisnames_array_matches, SDL_arraysize(pen_axisnames) == SDL_PEN_AXIS_COUNT);
437
438 char name[64];
439 char details[128];
440
441 // sensor/mouse/pen/finger motion are spammy, ignore these if they aren't demanded.
442 if ((SDL_EventLoggingVerbosity < 2) &&
443 ((event->type == SDL_EVENT_MOUSE_MOTION) ||
444 (event->type == SDL_EVENT_FINGER_MOTION) ||
445 (event->type == SDL_EVENT_PEN_AXIS) ||
446 (event->type == SDL_EVENT_PEN_MOTION) ||
447 (event->type == SDL_EVENT_GAMEPAD_TOUCHPAD_MOTION) ||
448 (event->type == SDL_EVENT_GAMEPAD_SENSOR_UPDATE) ||
449 (event->type == SDL_EVENT_SENSOR_UPDATE))) {
450 return;
451 }
452
453// this is to make (void)SDL_snprintf() calls cleaner.
454#define uint unsigned int
455
456 name[0] = '\0';
457 details[0] = '\0';
458
459 // !!! FIXME: This code is kinda ugly, sorry.
460
461 if ((event->type >= SDL_EVENT_USER) && (event->type <= SDL_EVENT_LAST)) {
462 char plusstr[16];
463 SDL_strlcpy(name, "SDL_EVENT_USER", sizeof(name));
464 if (event->type > SDL_EVENT_USER) {
465 (void)SDL_snprintf(plusstr, sizeof(plusstr), "+%u", ((uint)event->type) - SDL_EVENT_USER);
466 } else {
467 plusstr[0] = '\0';
468 }
469 (void)SDL_snprintf(details, sizeof(details), "%s (timestamp=%u windowid=%u code=%d data1=%p data2=%p)",
470 plusstr, (uint)event->user.timestamp, (uint)event->user.windowID,
471 (int)event->user.code, event->user.data1, event->user.data2);
472 }
473
474 switch (event->type) {
475#define SDL_EVENT_CASE(x) \
476 case x: \
477 SDL_strlcpy(name, #x, sizeof(name));
478 SDL_EVENT_CASE(SDL_EVENT_FIRST)
479 SDL_strlcpy(details, " (THIS IS PROBABLY A BUG!)", sizeof(details));
480 break;
481 SDL_EVENT_CASE(SDL_EVENT_QUIT)
482 (void)SDL_snprintf(details, sizeof(details), " (timestamp=%u)", (uint)event->quit.timestamp);
483 break;
484 SDL_EVENT_CASE(SDL_EVENT_TERMINATING)
485 break;
486 SDL_EVENT_CASE(SDL_EVENT_LOW_MEMORY)
487 break;
488 SDL_EVENT_CASE(SDL_EVENT_WILL_ENTER_BACKGROUND)
489 break;
490 SDL_EVENT_CASE(SDL_EVENT_DID_ENTER_BACKGROUND)
491 break;
492 SDL_EVENT_CASE(SDL_EVENT_WILL_ENTER_FOREGROUND)
493 break;
494 SDL_EVENT_CASE(SDL_EVENT_DID_ENTER_FOREGROUND)
495 break;
496 SDL_EVENT_CASE(SDL_EVENT_LOCALE_CHANGED)
497 break;
498 SDL_EVENT_CASE(SDL_EVENT_SYSTEM_THEME_CHANGED)
499 break;
500 SDL_EVENT_CASE(SDL_EVENT_KEYMAP_CHANGED)
501 break;
502 SDL_EVENT_CASE(SDL_EVENT_CLIPBOARD_UPDATE)
503 break;
504
505#define SDL_RENDEREVENT_CASE(x) \
506 case x: \
507 SDL_strlcpy(name, #x, sizeof(name)); \
508 (void)SDL_snprintf(details, sizeof(details), " (timestamp=%u event=%s windowid=%u)", \
509 (uint)event->display.timestamp, name, (uint)event->render.windowID); \
510 break
511 SDL_RENDEREVENT_CASE(SDL_EVENT_RENDER_TARGETS_RESET);
512 SDL_RENDEREVENT_CASE(SDL_EVENT_RENDER_DEVICE_RESET);
513 SDL_RENDEREVENT_CASE(SDL_EVENT_RENDER_DEVICE_LOST);
514
515#define SDL_DISPLAYEVENT_CASE(x) \
516 case x: \
517 SDL_strlcpy(name, #x, sizeof(name)); \
518 (void)SDL_snprintf(details, sizeof(details), " (timestamp=%u display=%u event=%s data1=%d, data2=%d)", \
519 (uint)event->display.timestamp, (uint)event->display.displayID, name, (int)event->display.data1, (int)event->display.data2); \
520 break
521 SDL_DISPLAYEVENT_CASE(SDL_EVENT_DISPLAY_ORIENTATION);
522 SDL_DISPLAYEVENT_CASE(SDL_EVENT_DISPLAY_ADDED);
523 SDL_DISPLAYEVENT_CASE(SDL_EVENT_DISPLAY_REMOVED);
524 SDL_DISPLAYEVENT_CASE(SDL_EVENT_DISPLAY_MOVED);
525 SDL_DISPLAYEVENT_CASE(SDL_EVENT_DISPLAY_DESKTOP_MODE_CHANGED);
526 SDL_DISPLAYEVENT_CASE(SDL_EVENT_DISPLAY_CURRENT_MODE_CHANGED);
527 SDL_DISPLAYEVENT_CASE(SDL_EVENT_DISPLAY_CONTENT_SCALE_CHANGED);
528#undef SDL_DISPLAYEVENT_CASE
529
530#define SDL_WINDOWEVENT_CASE(x) \
531 case x: \
532 SDL_strlcpy(name, #x, sizeof(name)); \
533 (void)SDL_snprintf(details, sizeof(details), " (timestamp=%u windowid=%u event=%s data1=%d data2=%d)", \
534 (uint)event->window.timestamp, (uint)event->window.windowID, name, (int)event->window.data1, (int)event->window.data2); \
535 break
536 SDL_WINDOWEVENT_CASE(SDL_EVENT_WINDOW_SHOWN);
537 SDL_WINDOWEVENT_CASE(SDL_EVENT_WINDOW_HIDDEN);
538 SDL_WINDOWEVENT_CASE(SDL_EVENT_WINDOW_EXPOSED);
539 SDL_WINDOWEVENT_CASE(SDL_EVENT_WINDOW_MOVED);
540 SDL_WINDOWEVENT_CASE(SDL_EVENT_WINDOW_RESIZED);
541 SDL_WINDOWEVENT_CASE(SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED);
542 SDL_WINDOWEVENT_CASE(SDL_EVENT_WINDOW_METAL_VIEW_RESIZED);
543 SDL_WINDOWEVENT_CASE(SDL_EVENT_WINDOW_SAFE_AREA_CHANGED);
544 SDL_WINDOWEVENT_CASE(SDL_EVENT_WINDOW_MINIMIZED);
545 SDL_WINDOWEVENT_CASE(SDL_EVENT_WINDOW_MAXIMIZED);
546 SDL_WINDOWEVENT_CASE(SDL_EVENT_WINDOW_RESTORED);
547 SDL_WINDOWEVENT_CASE(SDL_EVENT_WINDOW_MOUSE_ENTER);
548 SDL_WINDOWEVENT_CASE(SDL_EVENT_WINDOW_MOUSE_LEAVE);
549 SDL_WINDOWEVENT_CASE(SDL_EVENT_WINDOW_FOCUS_GAINED);
550 SDL_WINDOWEVENT_CASE(SDL_EVENT_WINDOW_FOCUS_LOST);
551 SDL_WINDOWEVENT_CASE(SDL_EVENT_WINDOW_CLOSE_REQUESTED);
552 SDL_WINDOWEVENT_CASE(SDL_EVENT_WINDOW_HIT_TEST);
553 SDL_WINDOWEVENT_CASE(SDL_EVENT_WINDOW_ICCPROF_CHANGED);
554 SDL_WINDOWEVENT_CASE(SDL_EVENT_WINDOW_DISPLAY_CHANGED);
555 SDL_WINDOWEVENT_CASE(SDL_EVENT_WINDOW_DISPLAY_SCALE_CHANGED);
556 SDL_WINDOWEVENT_CASE(SDL_EVENT_WINDOW_OCCLUDED);
557 SDL_WINDOWEVENT_CASE(SDL_EVENT_WINDOW_ENTER_FULLSCREEN);
558 SDL_WINDOWEVENT_CASE(SDL_EVENT_WINDOW_LEAVE_FULLSCREEN);
559 SDL_WINDOWEVENT_CASE(SDL_EVENT_WINDOW_DESTROYED);
560 SDL_WINDOWEVENT_CASE(SDL_EVENT_WINDOW_HDR_STATE_CHANGED);
561#undef SDL_WINDOWEVENT_CASE
562
563#define PRINT_KEYDEV_EVENT(event) (void)SDL_snprintf(details, sizeof(details), " (timestamp=%u which=%u)", (uint)event->kdevice.timestamp, (uint)event->kdevice.which)
564 SDL_EVENT_CASE(SDL_EVENT_KEYBOARD_ADDED)
565 PRINT_KEYDEV_EVENT(event);
566 break;
567 SDL_EVENT_CASE(SDL_EVENT_KEYBOARD_REMOVED)
568 PRINT_KEYDEV_EVENT(event);
569 break;
570#undef PRINT_KEYDEV_EVENT
571
572#define PRINT_KEY_EVENT(event) \
573 (void)SDL_snprintf(details, sizeof(details), " (timestamp=%u windowid=%u which=%u state=%s repeat=%s scancode=%u keycode=%u mod=0x%x)", \
574 (uint)event->key.timestamp, (uint)event->key.windowID, (uint)event->key.which, \
575 event->key.down ? "pressed" : "released", \
576 event->key.repeat ? "true" : "false", \
577 (uint)event->key.scancode, \
578 (uint)event->key.key, \
579 (uint)event->key.mod)
580 SDL_EVENT_CASE(SDL_EVENT_KEY_DOWN)
581 PRINT_KEY_EVENT(event);
582 break;
583 SDL_EVENT_CASE(SDL_EVENT_KEY_UP)
584 PRINT_KEY_EVENT(event);
585 break;
586#undef PRINT_KEY_EVENT
587
588 SDL_EVENT_CASE(SDL_EVENT_TEXT_EDITING)
589 (void)SDL_snprintf(details, sizeof(details), " (timestamp=%u windowid=%u text='%s' start=%d length=%d)",
590 (uint)event->edit.timestamp, (uint)event->edit.windowID,
591 event->edit.text, (int)event->edit.start, (int)event->edit.length);
592 break;
593
594 SDL_EVENT_CASE(SDL_EVENT_TEXT_EDITING_CANDIDATES)
595 (void)SDL_snprintf(details, sizeof(details), " (timestamp=%u windowid=%u num_candidates=%d selected_candidate=%d)",
596 (uint)event->edit_candidates.timestamp, (uint)event->edit_candidates.windowID,
597 (int)event->edit_candidates.num_candidates, (int)event->edit_candidates.selected_candidate);
598 break;
599
600 SDL_EVENT_CASE(SDL_EVENT_TEXT_INPUT)
601 (void)SDL_snprintf(details, sizeof(details), " (timestamp=%u windowid=%u text='%s')", (uint)event->text.timestamp, (uint)event->text.windowID, event->text.text);
602 break;
603
604#define PRINT_MOUSEDEV_EVENT(event) (void)SDL_snprintf(details, sizeof(details), " (timestamp=%u which=%u)", (uint)event->mdevice.timestamp, (uint)event->mdevice.which)
605 SDL_EVENT_CASE(SDL_EVENT_MOUSE_ADDED)
606 PRINT_MOUSEDEV_EVENT(event);
607 break;
608 SDL_EVENT_CASE(SDL_EVENT_MOUSE_REMOVED)
609 PRINT_MOUSEDEV_EVENT(event);
610 break;
611#undef PRINT_MOUSEDEV_EVENT
612
613 SDL_EVENT_CASE(SDL_EVENT_MOUSE_MOTION)
614 (void)SDL_snprintf(details, sizeof(details), " (timestamp=%u windowid=%u which=%u state=%u x=%g y=%g xrel=%g yrel=%g)",
615 (uint)event->motion.timestamp, (uint)event->motion.windowID,
616 (uint)event->motion.which, (uint)event->motion.state,
617 event->motion.x, event->motion.y,
618 event->motion.xrel, event->motion.yrel);
619 break;
620
621#define PRINT_MBUTTON_EVENT(event) \
622 (void)SDL_snprintf(details, sizeof(details), " (timestamp=%u windowid=%u which=%u button=%u state=%s clicks=%u x=%g y=%g)", \
623 (uint)event->button.timestamp, (uint)event->button.windowID, \
624 (uint)event->button.which, (uint)event->button.button, \
625 event->button.down ? "pressed" : "released", \
626 (uint)event->button.clicks, event->button.x, event->button.y)
627 SDL_EVENT_CASE(SDL_EVENT_MOUSE_BUTTON_DOWN)
628 PRINT_MBUTTON_EVENT(event);
629 break;
630 SDL_EVENT_CASE(SDL_EVENT_MOUSE_BUTTON_UP)
631 PRINT_MBUTTON_EVENT(event);
632 break;
633#undef PRINT_MBUTTON_EVENT
634
635 SDL_EVENT_CASE(SDL_EVENT_MOUSE_WHEEL)
636 (void)SDL_snprintf(details, sizeof(details), " (timestamp=%u windowid=%u which=%u x=%g y=%g direction=%s)",
637 (uint)event->wheel.timestamp, (uint)event->wheel.windowID,
638 (uint)event->wheel.which, event->wheel.x, event->wheel.y,
639 event->wheel.direction == SDL_MOUSEWHEEL_NORMAL ? "normal" : "flipped");
640 break;
641
642 SDL_EVENT_CASE(SDL_EVENT_JOYSTICK_AXIS_MOTION)
643 (void)SDL_snprintf(details, sizeof(details), " (timestamp=%u which=%d axis=%u value=%d)",
644 (uint)event->jaxis.timestamp, (int)event->jaxis.which,
645 (uint)event->jaxis.axis, (int)event->jaxis.value);
646 break;
647
648 SDL_EVENT_CASE(SDL_EVENT_JOYSTICK_BALL_MOTION)
649 (void)SDL_snprintf(details, sizeof(details), " (timestamp=%u which=%d ball=%u xrel=%d yrel=%d)",
650 (uint)event->jball.timestamp, (int)event->jball.which,
651 (uint)event->jball.ball, (int)event->jball.xrel, (int)event->jball.yrel);
652 break;
653
654 SDL_EVENT_CASE(SDL_EVENT_JOYSTICK_HAT_MOTION)
655 (void)SDL_snprintf(details, sizeof(details), " (timestamp=%u which=%d hat=%u value=%u)",
656 (uint)event->jhat.timestamp, (int)event->jhat.which,
657 (uint)event->jhat.hat, (uint)event->jhat.value);
658 break;
659
660#define PRINT_JBUTTON_EVENT(event) \
661 (void)SDL_snprintf(details, sizeof(details), " (timestamp=%u which=%d button=%u state=%s)", \
662 (uint)event->jbutton.timestamp, (int)event->jbutton.which, \
663 (uint)event->jbutton.button, event->jbutton.down ? "pressed" : "released")
664 SDL_EVENT_CASE(SDL_EVENT_JOYSTICK_BUTTON_DOWN)
665 PRINT_JBUTTON_EVENT(event);
666 break;
667 SDL_EVENT_CASE(SDL_EVENT_JOYSTICK_BUTTON_UP)
668 PRINT_JBUTTON_EVENT(event);
669 break;
670#undef PRINT_JBUTTON_EVENT
671
672 SDL_EVENT_CASE(SDL_EVENT_JOYSTICK_BATTERY_UPDATED)
673 (void)SDL_snprintf(details, sizeof(details), " (timestamp=%u which=%d state=%u percent=%d)",
674 (uint)event->jbattery.timestamp, (int)event->jbattery.which,
675 event->jbattery.state, event->jbattery.percent);
676 break;
677
678#define PRINT_JOYDEV_EVENT(event) (void)SDL_snprintf(details, sizeof(details), " (timestamp=%u which=%d)", (uint)event->jdevice.timestamp, (int)event->jdevice.which)
679 SDL_EVENT_CASE(SDL_EVENT_JOYSTICK_ADDED)
680 PRINT_JOYDEV_EVENT(event);
681 break;
682 SDL_EVENT_CASE(SDL_EVENT_JOYSTICK_REMOVED)
683 PRINT_JOYDEV_EVENT(event);
684 break;
685 SDL_EVENT_CASE(SDL_EVENT_JOYSTICK_UPDATE_COMPLETE)
686 PRINT_JOYDEV_EVENT(event);
687 break;
688#undef PRINT_JOYDEV_EVENT
689
690 SDL_EVENT_CASE(SDL_EVENT_GAMEPAD_AXIS_MOTION)
691 (void)SDL_snprintf(details, sizeof(details), " (timestamp=%u which=%d axis=%u value=%d)",
692 (uint)event->gaxis.timestamp, (int)event->gaxis.which,
693 (uint)event->gaxis.axis, (int)event->gaxis.value);
694 break;
695
696#define PRINT_CBUTTON_EVENT(event) \
697 (void)SDL_snprintf(details, sizeof(details), " (timestamp=%u which=%d button=%u state=%s)", \
698 (uint)event->gbutton.timestamp, (int)event->gbutton.which, \
699 (uint)event->gbutton.button, event->gbutton.down ? "pressed" : "released")
700 SDL_EVENT_CASE(SDL_EVENT_GAMEPAD_BUTTON_DOWN)
701 PRINT_CBUTTON_EVENT(event);
702 break;
703 SDL_EVENT_CASE(SDL_EVENT_GAMEPAD_BUTTON_UP)
704 PRINT_CBUTTON_EVENT(event);
705 break;
706#undef PRINT_CBUTTON_EVENT
707
708#define PRINT_GAMEPADDEV_EVENT(event) (void)SDL_snprintf(details, sizeof(details), " (timestamp=%u which=%d)", (uint)event->gdevice.timestamp, (int)event->gdevice.which)
709 SDL_EVENT_CASE(SDL_EVENT_GAMEPAD_ADDED)
710 PRINT_GAMEPADDEV_EVENT(event);
711 break;
712 SDL_EVENT_CASE(SDL_EVENT_GAMEPAD_REMOVED)
713 PRINT_GAMEPADDEV_EVENT(event);
714 break;
715 SDL_EVENT_CASE(SDL_EVENT_GAMEPAD_REMAPPED)
716 PRINT_GAMEPADDEV_EVENT(event);
717 break;
718 SDL_EVENT_CASE(SDL_EVENT_GAMEPAD_UPDATE_COMPLETE)
719 PRINT_GAMEPADDEV_EVENT(event);
720 break;
721 SDL_EVENT_CASE(SDL_EVENT_GAMEPAD_STEAM_HANDLE_UPDATED)
722 PRINT_GAMEPADDEV_EVENT(event);
723 break;
724#undef PRINT_GAMEPADDEV_EVENT
725
726#define PRINT_CTOUCHPAD_EVENT(event) \
727 (void)SDL_snprintf(details, sizeof(details), " (timestamp=%u which=%d touchpad=%d finger=%d x=%f y=%f pressure=%f)", \
728 (uint)event->gtouchpad.timestamp, (int)event->gtouchpad.which, \
729 (int)event->gtouchpad.touchpad, (int)event->gtouchpad.finger, \
730 event->gtouchpad.x, event->gtouchpad.y, event->gtouchpad.pressure)
731 SDL_EVENT_CASE(SDL_EVENT_GAMEPAD_TOUCHPAD_DOWN)
732 PRINT_CTOUCHPAD_EVENT(event);
733 break;
734 SDL_EVENT_CASE(SDL_EVENT_GAMEPAD_TOUCHPAD_UP)
735 PRINT_CTOUCHPAD_EVENT(event);
736 break;
737 SDL_EVENT_CASE(SDL_EVENT_GAMEPAD_TOUCHPAD_MOTION)
738 PRINT_CTOUCHPAD_EVENT(event);
739 break;
740#undef PRINT_CTOUCHPAD_EVENT
741
742 SDL_EVENT_CASE(SDL_EVENT_GAMEPAD_SENSOR_UPDATE)
743 (void)SDL_snprintf(details, sizeof(details), " (timestamp=%u which=%d sensor=%d data[0]=%f data[1]=%f data[2]=%f)",
744 (uint)event->gsensor.timestamp, (int)event->gsensor.which, (int)event->gsensor.sensor,
745 event->gsensor.data[0], event->gsensor.data[1], event->gsensor.data[2]);
746 break;
747
748#define PRINT_FINGER_EVENT(event) \
749 (void)SDL_snprintf(details, sizeof(details), " (timestamp=%u touchid=%" SDL_PRIu64 " fingerid=%" SDL_PRIu64 " x=%f y=%f dx=%f dy=%f pressure=%f)", \
750 (uint)event->tfinger.timestamp, event->tfinger.touchID, \
751 event->tfinger.fingerID, event->tfinger.x, event->tfinger.y, \
752 event->tfinger.dx, event->tfinger.dy, event->tfinger.pressure)
753 SDL_EVENT_CASE(SDL_EVENT_FINGER_DOWN)
754 PRINT_FINGER_EVENT(event);
755 break;
756 SDL_EVENT_CASE(SDL_EVENT_FINGER_UP)
757 PRINT_FINGER_EVENT(event);
758 break;
759 SDL_EVENT_CASE(SDL_EVENT_FINGER_CANCELED)
760 PRINT_FINGER_EVENT(event);
761 break;
762 SDL_EVENT_CASE(SDL_EVENT_FINGER_MOTION)
763 PRINT_FINGER_EVENT(event);
764 break;
765#undef PRINT_FINGER_EVENT
766
767#define PRINT_PTOUCH_EVENT(event) \
768 (void)SDL_snprintf(details, sizeof(details), " (timestamp=%u windowid=%u which=%u pen_state=%u x=%g y=%g eraser=%s state=%s)", \
769 (uint)event->ptouch.timestamp, (uint)event->ptouch.windowID, (uint)event->ptouch.which, (uint)event->ptouch.pen_state, event->ptouch.x, event->ptouch.y, \
770 event->ptouch.eraser ? "yes" : "no", event->ptouch.down ? "down" : "up");
771 SDL_EVENT_CASE(SDL_EVENT_PEN_DOWN)
772 PRINT_PTOUCH_EVENT(event);
773 break;
774 SDL_EVENT_CASE(SDL_EVENT_PEN_UP)
775 PRINT_PTOUCH_EVENT(event);
776 break;
777#undef PRINT_PTOUCH_EVENT
778
779#define PRINT_PPROXIMITY_EVENT(event) \
780 (void)SDL_snprintf(details, sizeof(details), " (timestamp=%u windowid=%u which=%u)", \
781 (uint)event->pproximity.timestamp, (uint)event->pproximity.windowID, (uint)event->pproximity.which);
782 SDL_EVENT_CASE(SDL_EVENT_PEN_PROXIMITY_IN)
783 PRINT_PPROXIMITY_EVENT(event);
784 break;
785 SDL_EVENT_CASE(SDL_EVENT_PEN_PROXIMITY_OUT)
786 PRINT_PPROXIMITY_EVENT(event);
787 break;
788#undef PRINT_PPROXIMITY_EVENT
789
790 SDL_EVENT_CASE(SDL_EVENT_PEN_AXIS)
791 (void)SDL_snprintf(details, sizeof(details), " (timestamp=%u windowid=%u which=%u pen_state=%u x=%g y=%g axis=%s value=%g)",
792 (uint)event->paxis.timestamp, (uint)event->paxis.windowID, (uint)event->paxis.which, (uint)event->paxis.pen_state, event->paxis.x, event->paxis.y,
793 ((((int) event->paxis.axis) >= 0) && (event->paxis.axis < SDL_arraysize(pen_axisnames))) ? pen_axisnames[event->paxis.axis] : "[UNKNOWN]", event->paxis.value);
794 break;
795
796 SDL_EVENT_CASE(SDL_EVENT_PEN_MOTION)
797 (void)SDL_snprintf(details, sizeof(details), " (timestamp=%u windowid=%u which=%u pen_state=%u x=%g y=%g)",
798 (uint)event->pmotion.timestamp, (uint)event->pmotion.windowID, (uint)event->pmotion.which, (uint)event->pmotion.pen_state, event->pmotion.x, event->pmotion.y);
799 break;
800
801#define PRINT_PBUTTON_EVENT(event) \
802 (void)SDL_snprintf(details, sizeof(details), " (timestamp=%u windowid=%u which=%u pen_state=%u x=%g y=%g button=%u state=%s)", \
803 (uint)event->pbutton.timestamp, (uint)event->pbutton.windowID, (uint)event->pbutton.which, (uint)event->pbutton.pen_state, event->pbutton.x, event->pbutton.y, \
804 (uint)event->pbutton.button, event->pbutton.down ? "down" : "up");
805 SDL_EVENT_CASE(SDL_EVENT_PEN_BUTTON_DOWN)
806 PRINT_PBUTTON_EVENT(event);
807 break;
808 SDL_EVENT_CASE(SDL_EVENT_PEN_BUTTON_UP)
809 PRINT_PBUTTON_EVENT(event);
810 break;
811#undef PRINT_PBUTTON_EVENT
812
813#define PRINT_DROP_EVENT(event) (void)SDL_snprintf(details, sizeof(details), " (data='%s' timestamp=%u windowid=%u x=%f y=%f)", event->drop.data, (uint)event->drop.timestamp, (uint)event->drop.windowID, event->drop.x, event->drop.y)
814 SDL_EVENT_CASE(SDL_EVENT_DROP_FILE)
815 PRINT_DROP_EVENT(event);
816 break;
817 SDL_EVENT_CASE(SDL_EVENT_DROP_TEXT)
818 PRINT_DROP_EVENT(event);
819 break;
820 SDL_EVENT_CASE(SDL_EVENT_DROP_BEGIN)
821 PRINT_DROP_EVENT(event);
822 break;
823 SDL_EVENT_CASE(SDL_EVENT_DROP_COMPLETE)
824 PRINT_DROP_EVENT(event);
825 break;
826 SDL_EVENT_CASE(SDL_EVENT_DROP_POSITION)
827 PRINT_DROP_EVENT(event);
828 break;
829#undef PRINT_DROP_EVENT
830
831#define PRINT_AUDIODEV_EVENT(event) (void)SDL_snprintf(details, sizeof(details), " (timestamp=%u which=%u recording=%s)", (uint)event->adevice.timestamp, (uint)event->adevice.which, event->adevice.recording ? "true" : "false")
832 SDL_EVENT_CASE(SDL_EVENT_AUDIO_DEVICE_ADDED)
833 PRINT_AUDIODEV_EVENT(event);
834 break;
835 SDL_EVENT_CASE(SDL_EVENT_AUDIO_DEVICE_REMOVED)
836 PRINT_AUDIODEV_EVENT(event);
837 break;
838 SDL_EVENT_CASE(SDL_EVENT_AUDIO_DEVICE_FORMAT_CHANGED)
839 PRINT_AUDIODEV_EVENT(event);
840 break;
841#undef PRINT_AUDIODEV_EVENT
842
843#define PRINT_CAMERADEV_EVENT(event) (void)SDL_snprintf(details, sizeof(details), " (timestamp=%u which=%u)", (uint)event->cdevice.timestamp, (uint)event->cdevice.which)
844 SDL_EVENT_CASE(SDL_EVENT_CAMERA_DEVICE_ADDED)
845 PRINT_CAMERADEV_EVENT(event);
846 break;
847 SDL_EVENT_CASE(SDL_EVENT_CAMERA_DEVICE_REMOVED)
848 PRINT_CAMERADEV_EVENT(event);
849 break;
850 SDL_EVENT_CASE(SDL_EVENT_CAMERA_DEVICE_APPROVED)
851 PRINT_CAMERADEV_EVENT(event);
852 break;
853 SDL_EVENT_CASE(SDL_EVENT_CAMERA_DEVICE_DENIED)
854 PRINT_CAMERADEV_EVENT(event);
855 break;
856#undef PRINT_CAMERADEV_EVENT
857
858 SDL_EVENT_CASE(SDL_EVENT_SENSOR_UPDATE)
859 (void)SDL_snprintf(details, sizeof(details), " (timestamp=%u which=%d data[0]=%f data[1]=%f data[2]=%f data[3]=%f data[4]=%f data[5]=%f)",
860 (uint)event->sensor.timestamp, (int)event->sensor.which,
861 event->sensor.data[0], event->sensor.data[1], event->sensor.data[2],
862 event->sensor.data[3], event->sensor.data[4], event->sensor.data[5]);
863 break;
864
865#undef SDL_EVENT_CASE
866
867 case SDL_EVENT_POLL_SENTINEL:
868 // No logging necessary for this one
869 break;
870
871 default:
872 if (!name[0]) {
873 if (event->type >= SDL_EVENT_USER) {
874 SDL_strlcpy(name, "USER", sizeof(name));
875 } else {
876 SDL_strlcpy(name, "UNKNOWN", sizeof(name));
877 }
878 (void)SDL_snprintf(details, sizeof(details), " 0x%x", (uint)event->type);
879 }
880 break;
881 }
882
883 if (name[0]) {
884 SDL_Log("SDL EVENT: %s%s", name, details);
885 }
886
887#undef uint
888}
889
890void SDL_StopEventLoop(void)
891{
892 const char *report = SDL_GetHint("SDL_EVENT_QUEUE_STATISTICS");
893 int i;
894 SDL_EventEntry *entry;
895
896 SDL_LockMutex(SDL_EventQ.lock);
897
898 SDL_EventQ.active = false;
899
900 if (report && SDL_atoi(report)) {
901 SDL_Log("SDL EVENT QUEUE: Maximum events in-flight: %d",
902 SDL_EventQ.max_events_seen);
903 }
904
905 // Clean out EventQ
906 for (entry = SDL_EventQ.head; entry;) {
907 SDL_EventEntry *next = entry->next;
908 SDL_TransferTemporaryMemoryFromEvent(entry);
909 SDL_free(entry);
910 entry = next;
911 }
912 for (entry = SDL_EventQ.free; entry;) {
913 SDL_EventEntry *next = entry->next;
914 SDL_free(entry);
915 entry = next;
916 }
917
918 SDL_SetAtomicInt(&SDL_EventQ.count, 0);
919 SDL_EventQ.max_events_seen = 0;
920 SDL_EventQ.head = NULL;
921 SDL_EventQ.tail = NULL;
922 SDL_EventQ.free = NULL;
923 SDL_SetAtomicInt(&SDL_sentinel_pending, 0);
924
925 // Clear disabled event state
926 for (i = 0; i < SDL_arraysize(SDL_disabled_events); ++i) {
927 SDL_free(SDL_disabled_events[i]);
928 SDL_disabled_events[i] = NULL;
929 }
930
931 SDL_QuitEventWatchList(&SDL_event_watchers);
932 SDL_QuitWindowEventWatch();
933
934 SDL_Mutex *lock = NULL;
935 if (SDL_EventQ.lock) {
936 lock = SDL_EventQ.lock;
937 SDL_EventQ.lock = NULL;
938 }
939
940 SDL_UnlockMutex(lock);
941
942 if (lock) {
943 SDL_DestroyMutex(lock);
944 }
945}
946
947// This function (and associated calls) may be called more than once
948bool SDL_StartEventLoop(void)
949{
950 /* We'll leave the event queue alone, since we might have gotten
951 some important events at launch (like SDL_EVENT_DROP_FILE)
952
953 FIXME: Does this introduce any other bugs with events at startup?
954 */
955
956 // Create the lock and set ourselves active
957#ifndef SDL_THREADS_DISABLED
958 if (!SDL_EventQ.lock) {
959 SDL_EventQ.lock = SDL_CreateMutex();
960 if (SDL_EventQ.lock == NULL) {
961 return false;
962 }
963 }
964 SDL_LockMutex(SDL_EventQ.lock);
965
966 if (!SDL_InitEventWatchList(&SDL_event_watchers)) {
967 SDL_UnlockMutex(SDL_EventQ.lock);
968 return false;
969 }
970#endif // !SDL_THREADS_DISABLED
971
972 SDL_InitWindowEventWatch();
973
974 SDL_EventQ.active = true;
975
976#ifndef SDL_THREADS_DISABLED
977 SDL_UnlockMutex(SDL_EventQ.lock);
978#endif
979 return true;
980}
981
982// Add an event to the event queue -- called with the queue locked
983static int SDL_AddEvent(SDL_Event *event)
984{
985 SDL_EventEntry *entry;
986 const int initial_count = SDL_GetAtomicInt(&SDL_EventQ.count);
987 int final_count;
988
989 if (initial_count >= SDL_MAX_QUEUED_EVENTS) {
990 SDL_SetError("Event queue is full (%d events)", initial_count);
991 return 0;
992 }
993
994 if (SDL_EventQ.free == NULL) {
995 entry = (SDL_EventEntry *)SDL_malloc(sizeof(*entry));
996 if (entry == NULL) {
997 return 0;
998 }
999 } else {
1000 entry = SDL_EventQ.free;
1001 SDL_EventQ.free = entry->next;
1002 }
1003
1004 if (SDL_EventLoggingVerbosity > 0) {
1005 SDL_LogEvent(event);
1006 }
1007
1008 SDL_copyp(&entry->event, event);
1009 if (event->type == SDL_EVENT_POLL_SENTINEL) {
1010 SDL_AddAtomicInt(&SDL_sentinel_pending, 1);
1011 }
1012 entry->memory = NULL;
1013 SDL_TransferTemporaryMemoryToEvent(entry);
1014
1015 if (SDL_EventQ.tail) {
1016 SDL_EventQ.tail->next = entry;
1017 entry->prev = SDL_EventQ.tail;
1018 SDL_EventQ.tail = entry;
1019 entry->next = NULL;
1020 } else {
1021 SDL_assert(!SDL_EventQ.head);
1022 SDL_EventQ.head = entry;
1023 SDL_EventQ.tail = entry;
1024 entry->prev = NULL;
1025 entry->next = NULL;
1026 }
1027
1028 final_count = SDL_AddAtomicInt(&SDL_EventQ.count, 1) + 1;
1029 if (final_count > SDL_EventQ.max_events_seen) {
1030 SDL_EventQ.max_events_seen = final_count;
1031 }
1032
1033 ++SDL_last_event_id;
1034
1035 return 1;
1036}
1037
1038// Remove an event from the queue -- called with the queue locked
1039static void SDL_CutEvent(SDL_EventEntry *entry)
1040{
1041 SDL_TransferTemporaryMemoryFromEvent(entry);
1042
1043 if (entry->prev) {
1044 entry->prev->next = entry->next;
1045 }
1046 if (entry->next) {
1047 entry->next->prev = entry->prev;
1048 }
1049
1050 if (entry == SDL_EventQ.head) {
1051 SDL_assert(entry->prev == NULL);
1052 SDL_EventQ.head = entry->next;
1053 }
1054 if (entry == SDL_EventQ.tail) {
1055 SDL_assert(entry->next == NULL);
1056 SDL_EventQ.tail = entry->prev;
1057 }
1058
1059 if (entry->event.type == SDL_EVENT_POLL_SENTINEL) {
1060 SDL_AddAtomicInt(&SDL_sentinel_pending, -1);
1061 }
1062
1063 entry->next = SDL_EventQ.free;
1064 SDL_EventQ.free = entry;
1065 SDL_assert(SDL_GetAtomicInt(&SDL_EventQ.count) > 0);
1066 SDL_AddAtomicInt(&SDL_EventQ.count, -1);
1067}
1068
1069static void SDL_SendWakeupEvent(void)
1070{
1071#ifdef SDL_PLATFORM_ANDROID
1072 Android_SendLifecycleEvent(SDL_ANDROID_LIFECYCLE_WAKE);
1073#else
1074 SDL_VideoDevice *_this = SDL_GetVideoDevice();
1075 if (_this == NULL || !_this->SendWakeupEvent) {
1076 return;
1077 }
1078
1079 SDL_LockMutex(_this->wakeup_lock);
1080 {
1081 if (_this->wakeup_window) {
1082 _this->SendWakeupEvent(_this, _this->wakeup_window);
1083
1084 // No more wakeup events needed until we enter a new wait
1085 _this->wakeup_window = NULL;
1086 }
1087 }
1088 SDL_UnlockMutex(_this->wakeup_lock);
1089#endif
1090}
1091
1092// Lock the event queue, take a peep at it, and unlock it
1093static int SDL_PeepEventsInternal(SDL_Event *events, int numevents, SDL_EventAction action,
1094 Uint32 minType, Uint32 maxType, bool include_sentinel)
1095{
1096 int i, used, sentinels_expected = 0;
1097
1098 // Lock the event queue
1099 used = 0;
1100
1101 SDL_LockMutex(SDL_EventQ.lock);
1102 {
1103 // Don't look after we've quit
1104 if (!SDL_EventQ.active) {
1105 // We get a few spurious events at shutdown, so don't warn then
1106 if (action == SDL_GETEVENT) {
1107 SDL_SetError("The event system has been shut down");
1108 }
1109 SDL_UnlockMutex(SDL_EventQ.lock);
1110 return -1;
1111 }
1112 if (action == SDL_ADDEVENT) {
1113 if (!events) {
1114 SDL_UnlockMutex(SDL_EventQ.lock);
1115 return SDL_InvalidParamError("events");
1116 }
1117 for (i = 0; i < numevents; ++i) {
1118 used += SDL_AddEvent(&events[i]);
1119 }
1120 } else {
1121 SDL_EventEntry *entry, *next;
1122 Uint32 type;
1123
1124 for (entry = SDL_EventQ.head; entry && (events == NULL || used < numevents); entry = next) {
1125 next = entry->next;
1126 type = entry->event.type;
1127 if (minType <= type && type <= maxType) {
1128 if (events) {
1129 SDL_copyp(&events[used], &entry->event);
1130
1131 if (action == SDL_GETEVENT) {
1132 SDL_CutEvent(entry);
1133 }
1134 }
1135 if (type == SDL_EVENT_POLL_SENTINEL) {
1136 // Special handling for the sentinel event
1137 if (!include_sentinel) {
1138 // Skip it, we don't want to include it
1139 continue;
1140 }
1141 if (events == NULL || action != SDL_GETEVENT) {
1142 ++sentinels_expected;
1143 }
1144 if (SDL_GetAtomicInt(&SDL_sentinel_pending) > sentinels_expected) {
1145 // Skip it, there's another one pending
1146 continue;
1147 }
1148 }
1149 ++used;
1150 }
1151 }
1152 }
1153 }
1154 SDL_UnlockMutex(SDL_EventQ.lock);
1155
1156 if (used > 0 && action == SDL_ADDEVENT) {
1157 SDL_SendWakeupEvent();
1158 }
1159
1160 return used;
1161}
1162int SDL_PeepEvents(SDL_Event *events, int numevents, SDL_EventAction action,
1163 Uint32 minType, Uint32 maxType)
1164{
1165 return SDL_PeepEventsInternal(events, numevents, action, minType, maxType, false);
1166}
1167
1168bool SDL_HasEvent(Uint32 type)
1169{
1170 return SDL_HasEvents(type, type);
1171}
1172
1173bool SDL_HasEvents(Uint32 minType, Uint32 maxType)
1174{
1175 bool found = false;
1176
1177 SDL_LockMutex(SDL_EventQ.lock);
1178 {
1179 if (SDL_EventQ.active) {
1180 for (SDL_EventEntry *entry = SDL_EventQ.head; entry; entry = entry->next) {
1181 const Uint32 type = entry->event.type;
1182 if (minType <= type && type <= maxType) {
1183 found = true;
1184 break;
1185 }
1186 }
1187 }
1188 }
1189 SDL_UnlockMutex(SDL_EventQ.lock);
1190
1191 return found;
1192}
1193
1194void SDL_FlushEvent(Uint32 type)
1195{
1196 SDL_FlushEvents(type, type);
1197}
1198
1199void SDL_FlushEvents(Uint32 minType, Uint32 maxType)
1200{
1201 SDL_EventEntry *entry, *next;
1202 Uint32 type;
1203
1204 // Make sure the events are current
1205#if 0
1206 /* Actually, we can't do this since we might be flushing while processing
1207 a resize event, and calling this might trigger further resize events.
1208 */
1209 SDL_PumpEvents();
1210#endif
1211
1212 // Lock the event queue
1213 SDL_LockMutex(SDL_EventQ.lock);
1214 {
1215 // Don't look after we've quit
1216 if (!SDL_EventQ.active) {
1217 SDL_UnlockMutex(SDL_EventQ.lock);
1218 return;
1219 }
1220 for (entry = SDL_EventQ.head; entry; entry = next) {
1221 next = entry->next;
1222 type = entry->event.type;
1223 if (minType <= type && type <= maxType) {
1224 SDL_CutEvent(entry);
1225 }
1226 }
1227 }
1228 SDL_UnlockMutex(SDL_EventQ.lock);
1229}
1230
1231typedef enum
1232{
1233 SDL_MAIN_CALLBACK_WAITING,
1234 SDL_MAIN_CALLBACK_COMPLETE,
1235 SDL_MAIN_CALLBACK_CANCELED,
1236} SDL_MainThreadCallbackState;
1237
1238typedef struct SDL_MainThreadCallbackEntry
1239{
1240 SDL_MainThreadCallback callback;
1241 void *userdata;
1242 SDL_AtomicInt state;
1243 SDL_Semaphore *semaphore;
1244 struct SDL_MainThreadCallbackEntry *next;
1245} SDL_MainThreadCallbackEntry;
1246
1247static SDL_Mutex *SDL_main_callbacks_lock;
1248static SDL_MainThreadCallbackEntry *SDL_main_callbacks_head;
1249static SDL_MainThreadCallbackEntry *SDL_main_callbacks_tail;
1250
1251static SDL_MainThreadCallbackEntry *SDL_CreateMainThreadCallback(SDL_MainThreadCallback callback, void *userdata, bool wait_complete)
1252{
1253 SDL_MainThreadCallbackEntry *entry = (SDL_MainThreadCallbackEntry *)SDL_malloc(sizeof(*entry));
1254 if (!entry) {
1255 return NULL;
1256 }
1257
1258 entry->callback = callback;
1259 entry->userdata = userdata;
1260 SDL_SetAtomicInt(&entry->state, SDL_MAIN_CALLBACK_WAITING);
1261 if (wait_complete) {
1262 entry->semaphore = SDL_CreateSemaphore(0);
1263 if (!entry->semaphore) {
1264 SDL_free(entry);
1265 return NULL;
1266 }
1267 } else {
1268 entry->semaphore = NULL;
1269 }
1270 entry->next = NULL;
1271
1272 return entry;
1273}
1274
1275static void SDL_DestroyMainThreadCallback(SDL_MainThreadCallbackEntry *entry)
1276{
1277 if (entry->semaphore) {
1278 SDL_DestroySemaphore(entry->semaphore);
1279 }
1280 SDL_free(entry);
1281}
1282
1283static void SDL_InitMainThreadCallbacks(void)
1284{
1285 SDL_main_callbacks_lock = SDL_CreateMutex();
1286 SDL_assert(SDL_main_callbacks_head == NULL &&
1287 SDL_main_callbacks_tail == NULL);
1288}
1289
1290static void SDL_QuitMainThreadCallbacks(void)
1291{
1292 SDL_MainThreadCallbackEntry *entry;
1293
1294 SDL_LockMutex(SDL_main_callbacks_lock);
1295 {
1296 entry = SDL_main_callbacks_head;
1297 SDL_main_callbacks_head = NULL;
1298 SDL_main_callbacks_tail = NULL;
1299 }
1300 SDL_UnlockMutex(SDL_main_callbacks_lock);
1301
1302 while (entry) {
1303 SDL_MainThreadCallbackEntry *next = entry->next;
1304
1305 if (entry->semaphore) {
1306 // Let the waiting thread know this is canceled
1307 SDL_SetAtomicInt(&entry->state, SDL_MAIN_CALLBACK_CANCELED);
1308 SDL_SignalSemaphore(entry->semaphore);
1309 } else {
1310 // Nobody's waiting for this, clean it up
1311 SDL_DestroyMainThreadCallback(entry);
1312 }
1313 entry = next;
1314 }
1315
1316 SDL_DestroyMutex(SDL_main_callbacks_lock);
1317 SDL_main_callbacks_lock = NULL;
1318}
1319
1320static void SDL_RunMainThreadCallbacks(void)
1321{
1322 SDL_MainThreadCallbackEntry *entry;
1323
1324 SDL_LockMutex(SDL_main_callbacks_lock);
1325 {
1326 entry = SDL_main_callbacks_head;
1327 SDL_main_callbacks_head = NULL;
1328 SDL_main_callbacks_tail = NULL;
1329 }
1330 SDL_UnlockMutex(SDL_main_callbacks_lock);
1331
1332 while (entry) {
1333 SDL_MainThreadCallbackEntry *next = entry->next;
1334
1335 entry->callback(entry->userdata);
1336
1337 if (entry->semaphore) {
1338 // Let the waiting thread know this is done
1339 SDL_SetAtomicInt(&entry->state, SDL_MAIN_CALLBACK_COMPLETE);
1340 SDL_SignalSemaphore(entry->semaphore);
1341 } else {
1342 // Nobody's waiting for this, clean it up
1343 SDL_DestroyMainThreadCallback(entry);
1344 }
1345 entry = next;
1346 }
1347}
1348
1349bool SDL_RunOnMainThread(SDL_MainThreadCallback callback, void *userdata, bool wait_complete)
1350{
1351 if (SDL_IsMainThread() || !SDL_WasInit(SDL_INIT_EVENTS)) {
1352 // No need to queue the callback
1353 callback(userdata);
1354 return true;
1355 }
1356
1357 SDL_MainThreadCallbackEntry *entry = SDL_CreateMainThreadCallback(callback, userdata, wait_complete);
1358 if (!entry) {
1359 return false;
1360 }
1361
1362 SDL_LockMutex(SDL_main_callbacks_lock);
1363 {
1364 if (SDL_main_callbacks_tail) {
1365 SDL_main_callbacks_tail->next = entry;
1366 SDL_main_callbacks_tail = entry;
1367 } else {
1368 SDL_main_callbacks_head = entry;
1369 SDL_main_callbacks_tail = entry;
1370 }
1371 }
1372 SDL_UnlockMutex(SDL_main_callbacks_lock);
1373
1374 // If the main thread is waiting for events, wake it up
1375 SDL_SendWakeupEvent();
1376
1377 if (!wait_complete) {
1378 // Queued for execution, wait not requested
1379 return true;
1380 }
1381
1382 // Maximum wait of 30 seconds to prevent deadlocking forever
1383 const Sint32 MAX_CALLBACK_WAIT = 30 * 1000;
1384 SDL_WaitSemaphoreTimeout(entry->semaphore, MAX_CALLBACK_WAIT);
1385
1386 switch (SDL_GetAtomicInt(&entry->state)) {
1387 case SDL_MAIN_CALLBACK_COMPLETE:
1388 // Execution complete!
1389 SDL_DestroyMainThreadCallback(entry);
1390 return true;
1391
1392 case SDL_MAIN_CALLBACK_CANCELED:
1393 // The callback was canceled on the main thread
1394 SDL_DestroyMainThreadCallback(entry);
1395 return SDL_SetError("Callback canceled");
1396
1397 default:
1398 // Probably hit a deadlock in the callback
1399 // We can't destroy the entry as the semaphore will be signaled
1400 // if it ever comes back, just leak it here.
1401 return SDL_SetError("Callback timed out");
1402 }
1403}
1404
1405void SDL_PumpEventMaintenance(void)
1406{
1407#ifndef SDL_AUDIO_DISABLED
1408 SDL_UpdateAudio();
1409#endif
1410
1411#ifndef SDL_CAMERA_DISABLED
1412 SDL_UpdateCamera();
1413#endif
1414
1415#ifndef SDL_SENSOR_DISABLED
1416 // Check for sensor state change
1417 if (SDL_update_sensors) {
1418 SDL_UpdateSensors();
1419 }
1420#endif
1421
1422#ifndef SDL_JOYSTICK_DISABLED
1423 // Check for joystick state change
1424 if (SDL_update_joysticks) {
1425 SDL_UpdateJoysticks();
1426 }
1427#endif
1428
1429 SDL_UpdateTrays();
1430
1431 SDL_SendPendingSignalEvents(); // in case we had a signal handler fire, etc.
1432}
1433
1434// Run the system dependent event loops
1435static void SDL_PumpEventsInternal(bool push_sentinel)
1436{
1437 // Free any temporary memory from old events
1438 SDL_FreeTemporaryMemory();
1439
1440 // Release any keys held down from last frame
1441 SDL_ReleaseAutoReleaseKeys();
1442
1443 // Run any pending main thread callbacks
1444 SDL_RunMainThreadCallbacks();
1445
1446#ifdef SDL_PLATFORM_ANDROID
1447 // Android event processing is independent of the video subsystem
1448 Android_PumpEvents(0);
1449#else
1450 // Get events from the video subsystem
1451 SDL_VideoDevice *_this = SDL_GetVideoDevice();
1452 if (_this) {
1453 _this->PumpEvents(_this);
1454 }
1455#endif
1456
1457 SDL_PumpEventMaintenance();
1458
1459 if (push_sentinel && SDL_EventEnabled(SDL_EVENT_POLL_SENTINEL)) {
1460 SDL_Event sentinel;
1461
1462 // Make sure we don't already have a sentinel in the queue, and add one to the end
1463 if (SDL_GetAtomicInt(&SDL_sentinel_pending) > 0) {
1464 SDL_PeepEventsInternal(&sentinel, 1, SDL_GETEVENT, SDL_EVENT_POLL_SENTINEL, SDL_EVENT_POLL_SENTINEL, true);
1465 }
1466
1467 sentinel.type = SDL_EVENT_POLL_SENTINEL;
1468 sentinel.common.timestamp = 0;
1469 SDL_PushEvent(&sentinel);
1470 }
1471}
1472
1473void SDL_PumpEvents(void)
1474{
1475 SDL_PumpEventsInternal(false);
1476}
1477
1478// Public functions
1479
1480bool SDL_PollEvent(SDL_Event *event)
1481{
1482 return SDL_WaitEventTimeoutNS(event, 0);
1483}
1484
1485#ifndef SDL_PLATFORM_ANDROID
1486
1487static Sint64 SDL_events_get_polling_interval(void)
1488{
1489 Sint64 poll_intervalNS = SDL_MAX_SINT64;
1490
1491#ifndef SDL_JOYSTICK_DISABLED
1492 if (SDL_WasInit(SDL_INIT_JOYSTICK) && SDL_update_joysticks) {
1493 if (SDL_JoysticksOpened()) {
1494 // If we have joysticks open, we need to poll rapidly for events
1495 poll_intervalNS = SDL_min(poll_intervalNS, EVENT_POLL_INTERVAL_NS);
1496 } else {
1497 // If not, just poll every few seconds to enumerate new joysticks
1498 poll_intervalNS = SDL_min(poll_intervalNS, ENUMERATION_POLL_INTERVAL_NS);
1499 }
1500 }
1501#endif
1502
1503#ifndef SDL_SENSOR_DISABLED
1504 if (SDL_WasInit(SDL_INIT_SENSOR) && SDL_update_sensors && SDL_SensorsOpened()) {
1505 // If we have sensors open, we need to poll rapidly for events
1506 poll_intervalNS = SDL_min(poll_intervalNS, EVENT_POLL_INTERVAL_NS);
1507 }
1508#endif
1509
1510 return poll_intervalNS;
1511}
1512
1513static int SDL_WaitEventTimeout_Device(SDL_VideoDevice *_this, SDL_Window *wakeup_window, SDL_Event *event, Uint64 start, Sint64 timeoutNS)
1514{
1515 Sint64 loop_timeoutNS = timeoutNS;
1516 Sint64 poll_intervalNS = SDL_events_get_polling_interval();
1517
1518 for (;;) {
1519 int status;
1520 /* Pump events on entry and each time we wake to ensure:
1521 a) All pending events are batch processed after waking up from a wait
1522 b) Waiting can be completely skipped if events are already available to be pumped
1523 c) Periodic processing that takes place in some platform PumpEvents() functions happens
1524 d) Signals received in WaitEventTimeout() are turned into SDL events
1525 */
1526 SDL_PumpEventsInternal(true);
1527
1528 SDL_LockMutex(_this->wakeup_lock);
1529 {
1530 status = SDL_PeepEvents(event, 1, SDL_GETEVENT, SDL_EVENT_FIRST, SDL_EVENT_LAST);
1531 // If status == 0 we are going to block so wakeup will be needed.
1532 if (status == 0) {
1533 _this->wakeup_window = wakeup_window;
1534 } else {
1535 _this->wakeup_window = NULL;
1536 }
1537 }
1538 SDL_UnlockMutex(_this->wakeup_lock);
1539
1540 if (status < 0) {
1541 // Got an error: return
1542 break;
1543 }
1544 if (status > 0) {
1545 // There is an event, we can return.
1546 return 1;
1547 }
1548 // No events found in the queue, call WaitEventTimeout to wait for an event.
1549 if (timeoutNS > 0) {
1550 Sint64 elapsed = SDL_GetTicksNS() - start;
1551 if (elapsed >= timeoutNS) {
1552 // Set wakeup_window to NULL without holding the lock.
1553 _this->wakeup_window = NULL;
1554 return 0;
1555 }
1556 loop_timeoutNS = (timeoutNS - elapsed);
1557 }
1558 // Adjust the timeout for any polling requirements we currently have.
1559 if (poll_intervalNS != SDL_MAX_SINT64) {
1560 if (loop_timeoutNS >= 0) {
1561 loop_timeoutNS = SDL_min(loop_timeoutNS, poll_intervalNS);
1562 } else {
1563 loop_timeoutNS = poll_intervalNS;
1564 }
1565 }
1566 status = _this->WaitEventTimeout(_this, loop_timeoutNS);
1567 // Set wakeup_window to NULL without holding the lock.
1568 _this->wakeup_window = NULL;
1569 if (status == 0 && poll_intervalNS != SDL_MAX_SINT64 && loop_timeoutNS == poll_intervalNS) {
1570 // We may have woken up to poll. Try again
1571 continue;
1572 } else if (status <= 0) {
1573 // There is either an error or the timeout is elapsed: return
1574 return status;
1575 }
1576 /* An event was found and pumped into the SDL events queue. Continue the loop
1577 to let SDL_PeepEvents pick it up .*/
1578 }
1579 return 0;
1580}
1581
1582static SDL_Window *SDL_find_active_window(SDL_VideoDevice *_this)
1583{
1584 SDL_Window *window;
1585 for (window = _this->windows; window; window = window->next) {
1586 if (!window->is_destroying) {
1587 return window;
1588 }
1589 }
1590 return NULL;
1591}
1592
1593#endif // !SDL_PLATFORM_ANDROID
1594
1595bool SDL_WaitEvent(SDL_Event *event)
1596{
1597 return SDL_WaitEventTimeoutNS(event, -1);
1598}
1599
1600bool SDL_WaitEventTimeout(SDL_Event *event, Sint32 timeoutMS)
1601{
1602 Sint64 timeoutNS;
1603
1604 if (timeoutMS > 0) {
1605 timeoutNS = SDL_MS_TO_NS(timeoutMS);
1606 } else {
1607 timeoutNS = timeoutMS;
1608 }
1609 return SDL_WaitEventTimeoutNS(event, timeoutNS);
1610}
1611
1612bool SDL_WaitEventTimeoutNS(SDL_Event *event, Sint64 timeoutNS)
1613{
1614 Uint64 start, expiration;
1615 bool include_sentinel = (timeoutNS == 0);
1616 int result;
1617
1618 if (timeoutNS > 0) {
1619 start = SDL_GetTicksNS();
1620 expiration = start + timeoutNS;
1621 } else {
1622 start = 0;
1623 expiration = 0;
1624 }
1625
1626 // If there isn't a poll sentinel event pending, pump events and add one
1627 if (SDL_GetAtomicInt(&SDL_sentinel_pending) == 0) {
1628 SDL_PumpEventsInternal(true);
1629 }
1630
1631 // First check for existing events
1632 result = SDL_PeepEventsInternal(event, 1, SDL_GETEVENT, SDL_EVENT_FIRST, SDL_EVENT_LAST, include_sentinel);
1633 if (result < 0) {
1634 return false;
1635 }
1636 if (include_sentinel) {
1637 if (event) {
1638 if (event->type == SDL_EVENT_POLL_SENTINEL) {
1639 // Reached the end of a poll cycle, and not willing to wait
1640 return false;
1641 }
1642 } else {
1643 // Need to peek the next event to check for sentinel
1644 SDL_Event dummy;
1645
1646 if (SDL_PeepEventsInternal(&dummy, 1, SDL_PEEKEVENT, SDL_EVENT_FIRST, SDL_EVENT_LAST, true) &&
1647 dummy.type == SDL_EVENT_POLL_SENTINEL) {
1648 SDL_PeepEventsInternal(&dummy, 1, SDL_GETEVENT, SDL_EVENT_POLL_SENTINEL, SDL_EVENT_POLL_SENTINEL, true);
1649 // Reached the end of a poll cycle, and not willing to wait
1650 return false;
1651 }
1652 }
1653 }
1654 if (result == 0) {
1655 if (timeoutNS == 0) {
1656 // No events available, and not willing to wait
1657 return false;
1658 }
1659 } else {
1660 // Has existing events
1661 return true;
1662 }
1663 // We should have completely handled timeoutNS == 0 above
1664 SDL_assert(timeoutNS != 0);
1665
1666#ifdef SDL_PLATFORM_ANDROID
1667 for (;;) {
1668 if (SDL_PeepEvents(event, 1, SDL_GETEVENT, SDL_EVENT_FIRST, SDL_EVENT_LAST) > 0) {
1669 return true;
1670 }
1671
1672 Uint64 delay = -1;
1673 if (timeoutNS > 0) {
1674 Uint64 now = SDL_GetTicksNS();
1675 if (now >= expiration) {
1676 // Timeout expired and no events
1677 return false;
1678 }
1679 delay = (expiration - now);
1680 }
1681 Android_PumpEvents(delay);
1682 }
1683#else
1684 SDL_VideoDevice *_this = SDL_GetVideoDevice();
1685 if (_this && _this->WaitEventTimeout && _this->SendWakeupEvent) {
1686 // Look if a shown window is available to send the wakeup event.
1687 SDL_Window *wakeup_window = SDL_find_active_window(_this);
1688 if (wakeup_window) {
1689 result = SDL_WaitEventTimeout_Device(_this, wakeup_window, event, start, timeoutNS);
1690 if (result > 0) {
1691 return true;
1692 } else if (result == 0) {
1693 return false;
1694 } else {
1695 /* There may be implementation-defined conditions where the backend cannot
1696 * reliably wait for the next event. If that happens, fall back to polling.
1697 */
1698 }
1699 }
1700 }
1701
1702 for (;;) {
1703 SDL_PumpEventsInternal(true);
1704
1705 if (SDL_PeepEvents(event, 1, SDL_GETEVENT, SDL_EVENT_FIRST, SDL_EVENT_LAST) > 0) {
1706 return true;
1707 }
1708
1709 Uint64 delay = EVENT_POLL_INTERVAL_NS;
1710 if (timeoutNS > 0) {
1711 Uint64 now = SDL_GetTicksNS();
1712 if (now >= expiration) {
1713 // Timeout expired and no events
1714 return false;
1715 }
1716 delay = SDL_min((expiration - now), delay);
1717 }
1718 SDL_DelayNS(delay);
1719 }
1720#endif // SDL_PLATFORM_ANDROID
1721}
1722
1723static bool SDL_CallEventWatchers(SDL_Event *event)
1724{
1725 if (event->common.type == SDL_EVENT_POLL_SENTINEL) {
1726 return true;
1727 }
1728
1729 return SDL_DispatchEventWatchList(&SDL_event_watchers, event);
1730}
1731
1732bool SDL_PushEvent(SDL_Event *event)
1733{
1734 if (!event->common.timestamp) {
1735 event->common.timestamp = SDL_GetTicksNS();
1736 }
1737
1738 if (!SDL_CallEventWatchers(event)) {
1739 SDL_ClearError();
1740 return false;
1741 }
1742
1743 if (SDL_PeepEvents(event, 1, SDL_ADDEVENT, 0, 0) <= 0) {
1744 return false;
1745 }
1746
1747 return true;
1748}
1749
1750void SDL_SetEventFilter(SDL_EventFilter filter, void *userdata)
1751{
1752 SDL_EventEntry *event, *next;
1753 SDL_LockMutex(SDL_event_watchers.lock);
1754 {
1755 // Set filter and discard pending events
1756 SDL_event_watchers.filter.callback = filter;
1757 SDL_event_watchers.filter.userdata = userdata;
1758 if (filter) {
1759 // Cut all events not accepted by the filter
1760 SDL_LockMutex(SDL_EventQ.lock);
1761 {
1762 for (event = SDL_EventQ.head; event; event = next) {
1763 next = event->next;
1764 if (!filter(userdata, &event->event)) {
1765 SDL_CutEvent(event);
1766 }
1767 }
1768 }
1769 SDL_UnlockMutex(SDL_EventQ.lock);
1770 }
1771 }
1772 SDL_UnlockMutex(SDL_event_watchers.lock);
1773}
1774
1775bool SDL_GetEventFilter(SDL_EventFilter *filter, void **userdata)
1776{
1777 SDL_EventWatcher event_ok;
1778
1779 SDL_LockMutex(SDL_event_watchers.lock);
1780 {
1781 event_ok = SDL_event_watchers.filter;
1782 }
1783 SDL_UnlockMutex(SDL_event_watchers.lock);
1784
1785 if (filter) {
1786 *filter = event_ok.callback;
1787 }
1788 if (userdata) {
1789 *userdata = event_ok.userdata;
1790 }
1791 return event_ok.callback ? true : false;
1792}
1793
1794bool SDL_AddEventWatch(SDL_EventFilter filter, void *userdata)
1795{
1796 return SDL_AddEventWatchList(&SDL_event_watchers, filter, userdata);
1797}
1798
1799void SDL_RemoveEventWatch(SDL_EventFilter filter, void *userdata)
1800{
1801 SDL_RemoveEventWatchList(&SDL_event_watchers, filter, userdata);
1802}
1803
1804void SDL_FilterEvents(SDL_EventFilter filter, void *userdata)
1805{
1806 SDL_LockMutex(SDL_EventQ.lock);
1807 {
1808 SDL_EventEntry *entry, *next;
1809 for (entry = SDL_EventQ.head; entry; entry = next) {
1810 next = entry->next;
1811 if (!filter(userdata, &entry->event)) {
1812 SDL_CutEvent(entry);
1813 }
1814 }
1815 }
1816 SDL_UnlockMutex(SDL_EventQ.lock);
1817}
1818
1819void SDL_SetEventEnabled(Uint32 type, bool enabled)
1820{
1821 bool current_state;
1822 Uint8 hi = ((type >> 8) & 0xff);
1823 Uint8 lo = (type & 0xff);
1824
1825 if (SDL_disabled_events[hi] &&
1826 (SDL_disabled_events[hi]->bits[lo / 32] & (1 << (lo & 31)))) {
1827 current_state = false;
1828 } else {
1829 current_state = true;
1830 }
1831
1832 if ((enabled != false) != current_state) {
1833 if (enabled) {
1834 SDL_assert(SDL_disabled_events[hi] != NULL);
1835 SDL_disabled_events[hi]->bits[lo / 32] &= ~(1 << (lo & 31));
1836
1837 // Gamepad events depend on joystick events
1838 switch (type) {
1839 case SDL_EVENT_GAMEPAD_ADDED:
1840 SDL_SetEventEnabled(SDL_EVENT_JOYSTICK_ADDED, true);
1841 break;
1842 case SDL_EVENT_GAMEPAD_REMOVED:
1843 SDL_SetEventEnabled(SDL_EVENT_JOYSTICK_REMOVED, true);
1844 break;
1845 case SDL_EVENT_GAMEPAD_AXIS_MOTION:
1846 case SDL_EVENT_GAMEPAD_BUTTON_DOWN:
1847 case SDL_EVENT_GAMEPAD_BUTTON_UP:
1848 SDL_SetEventEnabled(SDL_EVENT_JOYSTICK_AXIS_MOTION, true);
1849 SDL_SetEventEnabled(SDL_EVENT_JOYSTICK_HAT_MOTION, true);
1850 SDL_SetEventEnabled(SDL_EVENT_JOYSTICK_BUTTON_DOWN, true);
1851 SDL_SetEventEnabled(SDL_EVENT_JOYSTICK_BUTTON_UP, true);
1852 break;
1853 case SDL_EVENT_GAMEPAD_UPDATE_COMPLETE:
1854 SDL_SetEventEnabled(SDL_EVENT_JOYSTICK_UPDATE_COMPLETE, true);
1855 break;
1856 default:
1857 break;
1858 }
1859 } else {
1860 // Disable this event type and discard pending events
1861 if (!SDL_disabled_events[hi]) {
1862 SDL_disabled_events[hi] = (SDL_DisabledEventBlock *)SDL_calloc(1, sizeof(SDL_DisabledEventBlock));
1863 }
1864 // Out of memory, nothing we can do...
1865 if (SDL_disabled_events[hi]) {
1866 SDL_disabled_events[hi]->bits[lo / 32] |= (1 << (lo & 31));
1867 SDL_FlushEvent(type);
1868 }
1869 }
1870
1871 /* turn off drag'n'drop support if we've disabled the events.
1872 This might change some UI details at the OS level. */
1873 if (type == SDL_EVENT_DROP_FILE || type == SDL_EVENT_DROP_TEXT) {
1874 SDL_ToggleDragAndDropSupport();
1875 }
1876 }
1877}
1878
1879bool SDL_EventEnabled(Uint32 type)
1880{
1881 Uint8 hi = ((type >> 8) & 0xff);
1882 Uint8 lo = (type & 0xff);
1883
1884 if (SDL_disabled_events[hi] &&
1885 (SDL_disabled_events[hi]->bits[lo / 32] & (1 << (lo & 31)))) {
1886 return false;
1887 } else {
1888 return true;
1889 }
1890}
1891
1892Uint32 SDL_RegisterEvents(int numevents)
1893{
1894 Uint32 event_base = 0;
1895
1896 if (numevents > 0) {
1897 int value = SDL_AddAtomicInt(&SDL_userevents, numevents);
1898 if (value >= 0 && value <= (SDL_EVENT_LAST - SDL_EVENT_USER)) {
1899 event_base = (Uint32)(SDL_EVENT_USER + value);
1900 }
1901 }
1902 return event_base;
1903}
1904
1905void SDL_SendAppEvent(SDL_EventType eventType)
1906{
1907 if (SDL_EventEnabled(eventType)) {
1908 SDL_Event event;
1909 event.type = eventType;
1910 event.common.timestamp = 0;
1911
1912 switch (eventType) {
1913 case SDL_EVENT_TERMINATING:
1914 case SDL_EVENT_LOW_MEMORY:
1915 case SDL_EVENT_WILL_ENTER_BACKGROUND:
1916 case SDL_EVENT_DID_ENTER_BACKGROUND:
1917 case SDL_EVENT_WILL_ENTER_FOREGROUND:
1918 case SDL_EVENT_DID_ENTER_FOREGROUND:
1919 // We won't actually queue this event, it needs to be handled in this call stack by an event watcher
1920 if (SDL_EventLoggingVerbosity > 0) {
1921 SDL_LogEvent(&event);
1922 }
1923 SDL_CallEventWatchers(&event);
1924 break;
1925 default:
1926 SDL_PushEvent(&event);
1927 break;
1928 }
1929 }
1930}
1931
1932void SDL_SendKeymapChangedEvent(void)
1933{
1934 SDL_SendAppEvent(SDL_EVENT_KEYMAP_CHANGED);
1935}
1936
1937void SDL_SendLocaleChangedEvent(void)
1938{
1939 SDL_SendAppEvent(SDL_EVENT_LOCALE_CHANGED);
1940}
1941
1942void SDL_SendSystemThemeChangedEvent(void)
1943{
1944 SDL_SendAppEvent(SDL_EVENT_SYSTEM_THEME_CHANGED);
1945}
1946
1947bool SDL_InitEvents(void)
1948{
1949#ifdef SDL_PLATFORM_ANDROID
1950 Android_InitEvents();
1951#endif
1952#ifndef SDL_JOYSTICK_DISABLED
1953 SDL_AddHintCallback(SDL_HINT_AUTO_UPDATE_JOYSTICKS, SDL_AutoUpdateJoysticksChanged, NULL);
1954#endif
1955#ifndef SDL_SENSOR_DISABLED
1956 SDL_AddHintCallback(SDL_HINT_AUTO_UPDATE_SENSORS, SDL_AutoUpdateSensorsChanged, NULL);
1957#endif
1958 SDL_AddHintCallback(SDL_HINT_EVENT_LOGGING, SDL_EventLoggingChanged, NULL);
1959 SDL_AddHintCallback(SDL_HINT_POLL_SENTINEL, SDL_PollSentinelChanged, NULL);
1960 SDL_InitMainThreadCallbacks();
1961 if (!SDL_StartEventLoop()) {
1962 SDL_RemoveHintCallback(SDL_HINT_EVENT_LOGGING, SDL_EventLoggingChanged, NULL);
1963 return false;
1964 }
1965
1966 SDL_InitQuit();
1967
1968 return true;
1969}
1970
1971void SDL_QuitEvents(void)
1972{
1973 SDL_QuitQuit();
1974 SDL_StopEventLoop();
1975 SDL_QuitMainThreadCallbacks();
1976 SDL_RemoveHintCallback(SDL_HINT_POLL_SENTINEL, SDL_PollSentinelChanged, NULL);
1977 SDL_RemoveHintCallback(SDL_HINT_EVENT_LOGGING, SDL_EventLoggingChanged, NULL);
1978#ifndef SDL_JOYSTICK_DISABLED
1979 SDL_RemoveHintCallback(SDL_HINT_AUTO_UPDATE_JOYSTICKS, SDL_AutoUpdateJoysticksChanged, NULL);
1980#endif
1981#ifndef SDL_SENSOR_DISABLED
1982 SDL_RemoveHintCallback(SDL_HINT_AUTO_UPDATE_SENSORS, SDL_AutoUpdateSensorsChanged, NULL);
1983#endif
1984#ifdef SDL_PLATFORM_ANDROID
1985 Android_QuitEvents();
1986#endif
1987}
1988