sdl

FORK: Simple Directmedia Layer
git clone https://git.neptards.moe/neptards/sdl.git
Log | Files | Refs

SDL_events.c (37961B)


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