Atlas - SDL_events.c

Home / ext / SDL / src / events Lines: 1 | Size: 70568 bytes [Download] [Show on GitHub] [Search similar files] [Raw] [Raw (proxy)]
[FILE BEGIN]
1/* 2 Simple DirectMedia Layer 3 Copyright (C) 1997-2026 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_SendPendingPenProximity(); 1488 1489 SDL_UpdateCursorAnimation(); 1490 1491 SDL_UpdateTrays(); 1492 1493 SDL_SendPendingSignalEvents(); // in case we had a signal handler fire, etc. 1494} 1495 1496// Run the system dependent event loops 1497static void SDL_PumpEventsInternal(bool push_sentinel) 1498{ 1499 // This should only be called on the main thread, check in debug builds 1500 SDL_assert(SDL_IsMainThread()); 1501 1502 // Free any temporary memory from old events 1503 SDL_FreeTemporaryMemory(); 1504 1505 // Release any keys held down from last frame 1506 SDL_ReleaseAutoReleaseKeys(); 1507 1508 // Run any pending main thread callbacks 1509 SDL_RunMainThreadCallbacks(); 1510 1511#ifdef SDL_USE_LIBDBUS 1512 // DBus event processing is independent of the video subsystem 1513 SDL_DBus_PumpEvents(); 1514#endif 1515 1516#ifdef SDL_PLATFORM_ANDROID 1517 // Android event processing is independent of the video subsystem 1518 Android_PumpEvents(0); 1519#else 1520 // Get events from the video subsystem 1521 SDL_VideoDevice *_this = SDL_GetVideoDevice(); 1522 if (_this) { 1523 _this->PumpEvents(_this); 1524 } 1525#endif 1526 1527 SDL_PumpEventMaintenance(); 1528 1529 if (push_sentinel && SDL_EventEnabled(SDL_EVENT_POLL_SENTINEL)) { 1530 SDL_Event sentinel; 1531 1532 // Make sure we don't already have a sentinel in the queue, and add one to the end 1533 if (SDL_GetAtomicInt(&SDL_sentinel_pending) > 0) { 1534 SDL_PeepEventsInternal(&sentinel, 1, SDL_GETEVENT, SDL_EVENT_POLL_SENTINEL, SDL_EVENT_POLL_SENTINEL, true); 1535 } 1536 1537 sentinel.type = SDL_EVENT_POLL_SENTINEL; 1538 sentinel.common.timestamp = 0; 1539 SDL_PushEvent(&sentinel); 1540 } 1541} 1542 1543void SDL_PumpEvents(void) 1544{ 1545 SDL_PumpEventsInternal(false); 1546} 1547 1548// Public functions 1549 1550bool SDL_PollEvent(SDL_Event *event) 1551{ 1552 return SDL_WaitEventTimeoutNS(event, 0); 1553} 1554 1555#ifndef SDL_PLATFORM_ANDROID 1556 1557static Sint64 SDL_events_get_polling_interval(void) 1558{ 1559 Sint64 poll_intervalNS = SDL_MAX_SINT64; 1560 1561#ifndef SDL_JOYSTICK_DISABLED 1562 if (SDL_WasInit(SDL_INIT_JOYSTICK) && SDL_update_joysticks) { 1563 if (SDL_JoysticksOpened()) { 1564 // If we have joysticks open, we need to poll rapidly for events 1565 poll_intervalNS = SDL_min(poll_intervalNS, EVENT_POLL_INTERVAL_NS); 1566 } else { 1567 // If not, just poll every few seconds to enumerate new joysticks 1568 poll_intervalNS = SDL_min(poll_intervalNS, ENUMERATION_POLL_INTERVAL_NS); 1569 } 1570 } 1571#endif 1572 1573#ifndef SDL_SENSOR_DISABLED 1574 if (SDL_WasInit(SDL_INIT_SENSOR) && SDL_update_sensors && SDL_SensorsOpened()) { 1575 // If we have sensors open, we need to poll rapidly for events 1576 poll_intervalNS = SDL_min(poll_intervalNS, EVENT_POLL_INTERVAL_NS); 1577 } 1578#endif 1579 1580#ifdef SDL_PLATFORM_UNIX 1581 if (SDL_HasActiveTrays()) { 1582 // Tray events on *nix platforms run separately from window system events, and need periodic polling 1583 poll_intervalNS = SDL_min(poll_intervalNS, TRAY_POLL_INTERVAL_NS); 1584 } 1585#endif 1586 1587#ifdef SDL_USE_LIBDBUS 1588 // Wake periodically to pump DBus events 1589 poll_intervalNS = SDL_min(poll_intervalNS, DBUS_POLL_INTERVAL_NS); 1590#endif 1591 return poll_intervalNS; 1592} 1593 1594static int SDL_WaitEventTimeout_Device(SDL_VideoDevice *_this, SDL_Window *wakeup_window, SDL_Event *event, Uint64 start, Sint64 timeoutNS) 1595{ 1596 Sint64 loop_timeoutNS = timeoutNS; 1597 Sint64 poll_intervalNS = SDL_events_get_polling_interval(); 1598 1599 for (;;) { 1600 int status; 1601 /* Pump events on entry and each time we wake to ensure: 1602 a) All pending events are batch processed after waking up from a wait 1603 b) Waiting can be completely skipped if events are already available to be pumped 1604 c) Periodic processing that takes place in some platform PumpEvents() functions happens 1605 d) Signals received in WaitEventTimeout() are turned into SDL events 1606 */ 1607 SDL_PumpEventsInternal(true); 1608 1609 status = SDL_PeepEvents(event, 1, SDL_GETEVENT, SDL_EVENT_FIRST, SDL_EVENT_LAST); 1610 if (status < 0) { 1611 // Got an error: return 1612 break; 1613 } 1614 if (status > 0) { 1615 // There is an event, we can return. 1616 return 1; 1617 } 1618 // No events found in the queue, call WaitEventTimeout to wait for an event. 1619 if (timeoutNS > 0) { 1620 Sint64 elapsed = SDL_GetTicksNS() - start; 1621 if (elapsed >= timeoutNS) { 1622 return 0; 1623 } 1624 loop_timeoutNS = (timeoutNS - elapsed); 1625 } 1626 // Adjust the timeout for any polling requirements we currently have. 1627 if (poll_intervalNS != SDL_MAX_SINT64) { 1628 if (loop_timeoutNS >= 0) { 1629 loop_timeoutNS = SDL_min(loop_timeoutNS, poll_intervalNS); 1630 } else { 1631 loop_timeoutNS = poll_intervalNS; 1632 } 1633 } 1634 SDL_SetAtomicPointer(&_this->wakeup_window, wakeup_window); 1635 status = _this->WaitEventTimeout(_this, loop_timeoutNS); 1636 SDL_SetAtomicPointer(&_this->wakeup_window, NULL); 1637 if (status == 0 && poll_intervalNS != SDL_MAX_SINT64 && loop_timeoutNS == poll_intervalNS) { 1638 // We may have woken up to poll. Try again 1639 continue; 1640 } else if (status <= 0) { 1641 // There is either an error or the timeout is elapsed: return 1642 return status; 1643 } 1644 /* An event was found and pumped into the SDL events queue. Continue the loop 1645 to let SDL_PeepEvents pick it up .*/ 1646 } 1647 return 0; 1648} 1649 1650static SDL_Window *SDL_find_active_window(SDL_VideoDevice *_this) 1651{ 1652 SDL_Window *window; 1653 for (window = _this->windows; window; window = window->next) { 1654 if (!window->is_destroying) { 1655 return window; 1656 } 1657 } 1658 return NULL; 1659} 1660 1661#endif // !SDL_PLATFORM_ANDROID 1662 1663bool SDL_WaitEvent(SDL_Event *event) 1664{ 1665 return SDL_WaitEventTimeoutNS(event, -1); 1666} 1667 1668bool SDL_WaitEventTimeout(SDL_Event *event, Sint32 timeoutMS) 1669{ 1670 Sint64 timeoutNS; 1671 1672 if (timeoutMS > 0) { 1673 timeoutNS = SDL_MS_TO_NS(timeoutMS); 1674 } else { 1675 timeoutNS = timeoutMS; 1676 } 1677 return SDL_WaitEventTimeoutNS(event, timeoutNS); 1678} 1679 1680bool SDL_WaitEventTimeoutNS(SDL_Event *event, Sint64 timeoutNS) 1681{ 1682 Uint64 start, expiration; 1683 bool include_sentinel = (timeoutNS == 0); 1684 int result; 1685 1686 if (timeoutNS > 0) { 1687 start = SDL_GetTicksNS(); 1688 expiration = start + timeoutNS; 1689 } else { 1690 start = 0; 1691 expiration = 0; 1692 } 1693 1694 // If there isn't a poll sentinel event pending, pump events and add one 1695 if (SDL_GetAtomicInt(&SDL_sentinel_pending) == 0) { 1696 SDL_PumpEventsInternal(true); 1697 } 1698 1699 // First check for existing events 1700 result = SDL_PeepEventsInternal(event, 1, SDL_GETEVENT, SDL_EVENT_FIRST, SDL_EVENT_LAST, include_sentinel); 1701 if (result < 0) { 1702 return false; 1703 } 1704 if (include_sentinel) { 1705 if (event) { 1706 if (event->type == SDL_EVENT_POLL_SENTINEL) { 1707 // Reached the end of a poll cycle, and not willing to wait 1708 return false; 1709 } 1710 } else { 1711 // Need to peek the next event to check for sentinel 1712 SDL_Event dummy; 1713 1714 if (SDL_PeepEventsInternal(&dummy, 1, SDL_PEEKEVENT, SDL_EVENT_FIRST, SDL_EVENT_LAST, true) && 1715 dummy.type == SDL_EVENT_POLL_SENTINEL) { 1716 SDL_PeepEventsInternal(&dummy, 1, SDL_GETEVENT, SDL_EVENT_POLL_SENTINEL, SDL_EVENT_POLL_SENTINEL, true); 1717 // Reached the end of a poll cycle, and not willing to wait 1718 return false; 1719 } 1720 } 1721 } 1722 if (result == 0) { 1723 if (timeoutNS == 0) { 1724 // No events available, and not willing to wait 1725 return false; 1726 } 1727 } else { 1728 // Has existing events 1729 return true; 1730 } 1731 // We should have completely handled timeoutNS == 0 above 1732 SDL_assert(timeoutNS != 0); 1733 1734#ifdef SDL_PLATFORM_ANDROID 1735 for (;;) { 1736 SDL_PumpEventsInternal(true); 1737 1738 if (SDL_PeepEvents(event, 1, SDL_GETEVENT, SDL_EVENT_FIRST, SDL_EVENT_LAST) > 0) { 1739 return true; 1740 } 1741 1742 Uint64 delay = -1; 1743 if (timeoutNS > 0) { 1744 Uint64 now = SDL_GetTicksNS(); 1745 if (now >= expiration) { 1746 // Timeout expired and no events 1747 return false; 1748 } 1749 delay = (expiration - now); 1750 } 1751 Android_PumpEvents(delay); 1752 } 1753#else 1754 SDL_VideoDevice *_this = SDL_GetVideoDevice(); 1755 if (_this && _this->WaitEventTimeout && _this->SendWakeupEvent) { 1756 // Look if a shown window is available to send the wakeup event. 1757 SDL_Window *wakeup_window = SDL_find_active_window(_this); 1758 if (wakeup_window) { 1759 result = SDL_WaitEventTimeout_Device(_this, wakeup_window, event, start, timeoutNS); 1760 if (result > 0) { 1761 return true; 1762 } else if (result == 0) { 1763 return false; 1764 } else { 1765 /* There may be implementation-defined conditions where the backend cannot 1766 * reliably wait for the next event. If that happens, fall back to polling. 1767 */ 1768 } 1769 } 1770 } 1771 1772 for (;;) { 1773 SDL_PumpEventsInternal(true); 1774 1775 if (SDL_PeepEvents(event, 1, SDL_GETEVENT, SDL_EVENT_FIRST, SDL_EVENT_LAST) > 0) { 1776 return true; 1777 } 1778 1779 Uint64 delay = EVENT_POLL_INTERVAL_NS; 1780 if (timeoutNS > 0) { 1781 Uint64 now = SDL_GetTicksNS(); 1782 if (now >= expiration) { 1783 // Timeout expired and no events 1784 return false; 1785 } 1786 delay = SDL_min((expiration - now), delay); 1787 } 1788 SDL_DelayNS(delay); 1789 } 1790#endif // SDL_PLATFORM_ANDROID 1791} 1792 1793static bool SDL_CallEventWatchers(SDL_Event *event) 1794{ 1795 if (event->common.type == SDL_EVENT_POLL_SENTINEL) { 1796 return true; 1797 } 1798 1799 return SDL_DispatchEventWatchList(&SDL_event_watchers, event); 1800} 1801 1802bool SDL_PushEvent(SDL_Event *event) 1803{ 1804 if (!event->common.timestamp) { 1805 event->common.timestamp = SDL_GetTicksNS(); 1806 } 1807 1808 if (!SDL_CallEventWatchers(event)) { 1809 SDL_ClearError(); 1810 return false; 1811 } 1812 1813 if (SDL_PeepEvents(event, 1, SDL_ADDEVENT, 0, 0) <= 0) { 1814 return false; 1815 } 1816 1817 return true; 1818} 1819 1820void SDL_SetEventFilter(SDL_EventFilter filter, void *userdata) 1821{ 1822 SDL_EventEntry *event, *next; 1823 SDL_LockMutex(SDL_event_watchers.lock); 1824 { 1825 // Set filter and discard pending events 1826 SDL_event_watchers.filter.callback = filter; 1827 SDL_event_watchers.filter.userdata = userdata; 1828 if (filter) { 1829 // Cut all events not accepted by the filter 1830 SDL_LockMutex(SDL_EventQ.lock); 1831 { 1832 for (event = SDL_EventQ.head; event; event = next) { 1833 next = event->next; 1834 if (!filter(userdata, &event->event)) { 1835 SDL_CutEvent(event); 1836 } 1837 } 1838 } 1839 SDL_UnlockMutex(SDL_EventQ.lock); 1840 } 1841 } 1842 SDL_UnlockMutex(SDL_event_watchers.lock); 1843} 1844 1845bool SDL_GetEventFilter(SDL_EventFilter *filter, void **userdata) 1846{ 1847 SDL_EventWatcher event_ok; 1848 1849 SDL_LockMutex(SDL_event_watchers.lock); 1850 { 1851 event_ok = SDL_event_watchers.filter; 1852 } 1853 SDL_UnlockMutex(SDL_event_watchers.lock); 1854 1855 if (filter) { 1856 *filter = event_ok.callback; 1857 } 1858 if (userdata) { 1859 *userdata = event_ok.userdata; 1860 } 1861 return event_ok.callback ? true : false; 1862} 1863 1864bool SDL_AddEventWatch(SDL_EventFilter filter, void *userdata) 1865{ 1866 return SDL_AddEventWatchList(&SDL_event_watchers, filter, userdata); 1867} 1868 1869void SDL_RemoveEventWatch(SDL_EventFilter filter, void *userdata) 1870{ 1871 SDL_RemoveEventWatchList(&SDL_event_watchers, filter, userdata); 1872} 1873 1874void SDL_FilterEvents(SDL_EventFilter filter, void *userdata) 1875{ 1876 SDL_LockMutex(SDL_EventQ.lock); 1877 { 1878 SDL_EventEntry *entry, *next; 1879 for (entry = SDL_EventQ.head; entry; entry = next) { 1880 next = entry->next; 1881 if (!filter(userdata, &entry->event)) { 1882 SDL_CutEvent(entry); 1883 } 1884 } 1885 } 1886 SDL_UnlockMutex(SDL_EventQ.lock); 1887} 1888 1889void SDL_SetEventEnabled(Uint32 type, bool enabled) 1890{ 1891 bool current_state; 1892 Uint8 hi = ((type >> 8) & 0xff); 1893 Uint8 lo = (type & 0xff); 1894 1895 if (SDL_disabled_events[hi] && 1896 (SDL_disabled_events[hi]->bits[lo / 32] & (1U << (lo & 31)))) { 1897 current_state = false; 1898 } else { 1899 current_state = true; 1900 } 1901 1902 if ((enabled != false) != current_state) { 1903 if (enabled) { 1904 SDL_assert(SDL_disabled_events[hi] != NULL); 1905 SDL_disabled_events[hi]->bits[lo / 32] &= ~(1U << (lo & 31)); 1906 1907 // Gamepad events depend on joystick events 1908 switch (type) { 1909 case SDL_EVENT_GAMEPAD_ADDED: 1910 SDL_SetEventEnabled(SDL_EVENT_JOYSTICK_ADDED, true); 1911 break; 1912 case SDL_EVENT_GAMEPAD_REMOVED: 1913 SDL_SetEventEnabled(SDL_EVENT_JOYSTICK_REMOVED, true); 1914 break; 1915 case SDL_EVENT_GAMEPAD_AXIS_MOTION: 1916 case SDL_EVENT_GAMEPAD_BUTTON_DOWN: 1917 case SDL_EVENT_GAMEPAD_BUTTON_UP: 1918 SDL_SetEventEnabled(SDL_EVENT_JOYSTICK_AXIS_MOTION, true); 1919 SDL_SetEventEnabled(SDL_EVENT_JOYSTICK_HAT_MOTION, true); 1920 SDL_SetEventEnabled(SDL_EVENT_JOYSTICK_BUTTON_DOWN, true); 1921 SDL_SetEventEnabled(SDL_EVENT_JOYSTICK_BUTTON_UP, true); 1922 break; 1923 case SDL_EVENT_GAMEPAD_UPDATE_COMPLETE: 1924 SDL_SetEventEnabled(SDL_EVENT_JOYSTICK_UPDATE_COMPLETE, true); 1925 break; 1926 default: 1927 break; 1928 } 1929 } else { 1930 // Disable this event type and discard pending events 1931 if (!SDL_disabled_events[hi]) { 1932 SDL_disabled_events[hi] = (SDL_DisabledEventBlock *)SDL_calloc(1, sizeof(SDL_DisabledEventBlock)); 1933 } 1934 // Out of memory, nothing we can do... 1935 if (SDL_disabled_events[hi]) { 1936 SDL_disabled_events[hi]->bits[lo / 32] |= (1U << (lo & 31)); 1937 SDL_FlushEvent(type); 1938 } 1939 } 1940 1941 /* turn off drag'n'drop support if we've disabled the events. 1942 This might change some UI details at the OS level. */ 1943 if (type == SDL_EVENT_DROP_FILE || type == SDL_EVENT_DROP_TEXT) { 1944 SDL_ToggleDragAndDropSupport(); 1945 } 1946 } 1947} 1948 1949bool SDL_EventEnabled(Uint32 type) 1950{ 1951 Uint8 hi = ((type >> 8) & 0xff); 1952 Uint8 lo = (type & 0xff); 1953 1954 if (SDL_disabled_events[hi] && 1955 (SDL_disabled_events[hi]->bits[lo / 32] & (1U << (lo & 31)))) { 1956 return false; 1957 } else { 1958 return true; 1959 } 1960} 1961 1962Uint32 SDL_RegisterEvents(int numevents) 1963{ 1964 Uint32 event_base = 0; 1965 1966 if (numevents > 0) { 1967 int value = SDL_AddAtomicInt(&SDL_userevents, numevents); 1968 if (value >= 0 && value <= (SDL_EVENT_LAST - SDL_EVENT_USER)) { 1969 event_base = (Uint32)(SDL_EVENT_USER + value); 1970 } 1971 } 1972 return event_base; 1973} 1974 1975void SDL_SendAppEvent(SDL_EventType eventType) 1976{ 1977 if (SDL_EventEnabled(eventType)) { 1978 SDL_Event event; 1979 event.type = eventType; 1980 event.common.timestamp = 0; 1981 1982 switch (eventType) { 1983 case SDL_EVENT_TERMINATING: 1984 case SDL_EVENT_LOW_MEMORY: 1985 case SDL_EVENT_WILL_ENTER_BACKGROUND: 1986 case SDL_EVENT_DID_ENTER_BACKGROUND: 1987 case SDL_EVENT_WILL_ENTER_FOREGROUND: 1988 case SDL_EVENT_DID_ENTER_FOREGROUND: 1989 // We won't actually queue this event, it needs to be handled in this call stack by an event watcher 1990 if (SDL_EventLoggingVerbosity > 0) { 1991 SDL_LogEvent(&event); 1992 } 1993 SDL_CallEventWatchers(&event); 1994 break; 1995 default: 1996 SDL_PushEvent(&event); 1997 break; 1998 } 1999 } 2000} 2001 2002void SDL_SendKeymapChangedEvent(void) 2003{ 2004 SDL_SendAppEvent(SDL_EVENT_KEYMAP_CHANGED); 2005} 2006 2007void SDL_SendLocaleChangedEvent(void) 2008{ 2009 SDL_SendAppEvent(SDL_EVENT_LOCALE_CHANGED); 2010} 2011 2012void SDL_SendSystemThemeChangedEvent(void) 2013{ 2014 SDL_SendAppEvent(SDL_EVENT_SYSTEM_THEME_CHANGED); 2015} 2016 2017bool SDL_InitEvents(void) 2018{ 2019#ifdef SDL_PLATFORM_ANDROID 2020 Android_InitEvents(); 2021#endif 2022#ifndef SDL_JOYSTICK_DISABLED 2023 SDL_AddHintCallback(SDL_HINT_AUTO_UPDATE_JOYSTICKS, SDL_AutoUpdateJoysticksChanged, NULL); 2024#endif 2025#ifndef SDL_SENSOR_DISABLED 2026 SDL_AddHintCallback(SDL_HINT_AUTO_UPDATE_SENSORS, SDL_AutoUpdateSensorsChanged, NULL); 2027#endif 2028 SDL_AddHintCallback(SDL_HINT_EVENT_LOGGING, SDL_EventLoggingChanged, NULL); 2029 SDL_AddHintCallback(SDL_HINT_POLL_SENTINEL, SDL_PollSentinelChanged, NULL); 2030 SDL_InitMainThreadCallbacks(); 2031 if (!SDL_StartEventLoop()) { 2032 SDL_RemoveHintCallback(SDL_HINT_EVENT_LOGGING, SDL_EventLoggingChanged, NULL); 2033 return false; 2034 } 2035 2036 SDL_InitQuit(); 2037 2038 return true; 2039} 2040 2041void SDL_QuitEvents(void) 2042{ 2043 SDL_QuitQuit(); 2044 SDL_StopEventLoop(); 2045 SDL_QuitMainThreadCallbacks(); 2046 SDL_RemoveHintCallback(SDL_HINT_POLL_SENTINEL, SDL_PollSentinelChanged, NULL); 2047 SDL_RemoveHintCallback(SDL_HINT_EVENT_LOGGING, SDL_EventLoggingChanged, NULL); 2048#ifndef SDL_JOYSTICK_DISABLED 2049 SDL_RemoveHintCallback(SDL_HINT_AUTO_UPDATE_JOYSTICKS, SDL_AutoUpdateJoysticksChanged, NULL); 2050#endif 2051#ifndef SDL_SENSOR_DISABLED 2052 SDL_RemoveHintCallback(SDL_HINT_AUTO_UPDATE_SENSORS, SDL_AutoUpdateSensorsChanged, NULL); 2053#endif 2054#ifdef SDL_PLATFORM_ANDROID 2055 Android_QuitEvents(); 2056#endif 2057} 2058
[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.