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