Atlas - SDL_events.c

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