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