src/events/SDL_events.c
author Sam Lantinga
Sun, 08 Mar 2020 21:24:06 -0700
changeset 13600 e42055c6d8b5
parent 13567 e5e55d467f7e
child 13717 3b90978ddf04
permissions -rw-r--r--
Fixed warnings building with mingw64
     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     /* Get events from the video subsystem */
   682     if (_this) {
   683         _this->PumpEvents(_this);
   684     }
   685 #if !SDL_JOYSTICK_DISABLED
   686     /* Check for joystick state change */
   687     if ((!SDL_disabled_events[SDL_JOYAXISMOTION >> 8] || SDL_JoystickEventState(SDL_QUERY))) {
   688         SDL_JoystickUpdate();
   689     }
   690 #endif
   691 
   692 #if !SDL_SENSOR_DISABLED
   693     /* Check for sensor state change */
   694     if (!SDL_disabled_events[SDL_SENSORUPDATE >> 8]) {
   695         SDL_SensorUpdate();
   696     }
   697 #endif
   698 
   699     SDL_SendPendingSignalEvents();  /* in case we had a signal handler fire, etc. */
   700 }
   701 
   702 /* Public functions */
   703 
   704 int
   705 SDL_PollEvent(SDL_Event * event)
   706 {
   707     return SDL_WaitEventTimeout(event, 0);
   708 }
   709 
   710 int
   711 SDL_WaitEvent(SDL_Event * event)
   712 {
   713     return SDL_WaitEventTimeout(event, -1);
   714 }
   715 
   716 int
   717 SDL_WaitEventTimeout(SDL_Event * event, int timeout)
   718 {
   719     Uint32 expiration = 0;
   720 
   721     if (timeout > 0)
   722         expiration = SDL_GetTicks() + timeout;
   723 
   724     for (;;) {
   725         SDL_PumpEvents();
   726         switch (SDL_PeepEvents(event, 1, SDL_GETEVENT, SDL_FIRSTEVENT, SDL_LASTEVENT)) {
   727         case -1:
   728             return 0;
   729         case 0:
   730             if (timeout == 0) {
   731                 /* Polling and no events, just return */
   732                 return 0;
   733             }
   734             if (timeout > 0 && SDL_TICKS_PASSED(SDL_GetTicks(), expiration)) {
   735                 /* Timeout expired and no events */
   736                 return 0;
   737             }
   738             SDL_Delay(1);
   739             break;
   740         default:
   741             /* Has events */
   742             return 1;
   743         }
   744     }
   745 }
   746 
   747 int
   748 SDL_PushEvent(SDL_Event * event)
   749 {
   750     event->common.timestamp = SDL_GetTicks();
   751 
   752     if (SDL_EventOK.callback || SDL_event_watchers_count > 0) {
   753         if (!SDL_event_watchers_lock || SDL_LockMutex(SDL_event_watchers_lock) == 0) {
   754             if (SDL_EventOK.callback && !SDL_EventOK.callback(SDL_EventOK.userdata, event)) {
   755                 if (SDL_event_watchers_lock) {
   756                     SDL_UnlockMutex(SDL_event_watchers_lock);
   757                 }
   758                 return 0;
   759             }
   760 
   761             if (SDL_event_watchers_count > 0) {
   762                 /* Make sure we only dispatch the current watcher list */
   763                 int i, event_watchers_count = SDL_event_watchers_count;
   764 
   765                 SDL_event_watchers_dispatching = SDL_TRUE;
   766                 for (i = 0; i < event_watchers_count; ++i) {
   767                     if (!SDL_event_watchers[i].removed) {
   768                         SDL_event_watchers[i].callback(SDL_event_watchers[i].userdata, event);
   769                     }
   770                 }
   771                 SDL_event_watchers_dispatching = SDL_FALSE;
   772 
   773                 if (SDL_event_watchers_removed) {
   774                     for (i = SDL_event_watchers_count; i--; ) {
   775                         if (SDL_event_watchers[i].removed) {
   776                             --SDL_event_watchers_count;
   777                             if (i < SDL_event_watchers_count) {
   778                                 SDL_memmove(&SDL_event_watchers[i], &SDL_event_watchers[i+1], (SDL_event_watchers_count - i) * sizeof(SDL_event_watchers[i]));
   779                             }
   780                         }
   781                     }
   782                     SDL_event_watchers_removed = SDL_FALSE;
   783                 }
   784             }
   785 
   786             if (SDL_event_watchers_lock) {
   787                 SDL_UnlockMutex(SDL_event_watchers_lock);
   788             }
   789         }
   790     }
   791 
   792     if (SDL_PeepEvents(event, 1, SDL_ADDEVENT, 0, 0) <= 0) {
   793         return -1;
   794     }
   795 
   796     SDL_GestureProcessEvent(event);
   797 
   798     return 1;
   799 }
   800 
   801 void
   802 SDL_SetEventFilter(SDL_EventFilter filter, void *userdata)
   803 {
   804     if (!SDL_event_watchers_lock || SDL_LockMutex(SDL_event_watchers_lock) == 0) {
   805         /* Set filter and discard pending events */
   806         SDL_EventOK.callback = filter;
   807         SDL_EventOK.userdata = userdata;
   808         SDL_FlushEvents(SDL_FIRSTEVENT, SDL_LASTEVENT);
   809 
   810         if (SDL_event_watchers_lock) {
   811             SDL_UnlockMutex(SDL_event_watchers_lock);
   812         }
   813     }
   814 }
   815 
   816 SDL_bool
   817 SDL_GetEventFilter(SDL_EventFilter * filter, void **userdata)
   818 {
   819     SDL_EventWatcher event_ok;
   820 
   821     if (!SDL_event_watchers_lock || SDL_LockMutex(SDL_event_watchers_lock) == 0) {
   822         event_ok = SDL_EventOK;
   823 
   824         if (SDL_event_watchers_lock) {
   825             SDL_UnlockMutex(SDL_event_watchers_lock);
   826         }
   827     } else {
   828         SDL_zero(event_ok);
   829     }
   830 
   831     if (filter) {
   832         *filter = event_ok.callback;
   833     }
   834     if (userdata) {
   835         *userdata = event_ok.userdata;
   836     }
   837     return event_ok.callback ? SDL_TRUE : SDL_FALSE;
   838 }
   839 
   840 void
   841 SDL_AddEventWatch(SDL_EventFilter filter, void *userdata)
   842 {
   843     if (!SDL_event_watchers_lock || SDL_LockMutex(SDL_event_watchers_lock) == 0) {
   844         SDL_EventWatcher *event_watchers;
   845 
   846         event_watchers = SDL_realloc(SDL_event_watchers, (SDL_event_watchers_count + 1) * sizeof(*event_watchers));
   847         if (event_watchers) {
   848             SDL_EventWatcher *watcher;
   849 
   850             SDL_event_watchers = event_watchers;
   851             watcher = &SDL_event_watchers[SDL_event_watchers_count];
   852             watcher->callback = filter;
   853             watcher->userdata = userdata;
   854             watcher->removed = SDL_FALSE;
   855             ++SDL_event_watchers_count;
   856         }
   857 
   858         if (SDL_event_watchers_lock) {
   859             SDL_UnlockMutex(SDL_event_watchers_lock);
   860         }
   861     }
   862 }
   863 
   864 void
   865 SDL_DelEventWatch(SDL_EventFilter filter, void *userdata)
   866 {
   867     if (!SDL_event_watchers_lock || SDL_LockMutex(SDL_event_watchers_lock) == 0) {
   868         int i;
   869 
   870         for (i = 0; i < SDL_event_watchers_count; ++i) {
   871             if (SDL_event_watchers[i].callback == filter && SDL_event_watchers[i].userdata == userdata) {
   872                 if (SDL_event_watchers_dispatching) {
   873                     SDL_event_watchers[i].removed = SDL_TRUE;
   874                     SDL_event_watchers_removed = SDL_TRUE;
   875                 } else {
   876                     --SDL_event_watchers_count;
   877                     if (i < SDL_event_watchers_count) {
   878                         SDL_memmove(&SDL_event_watchers[i], &SDL_event_watchers[i+1], (SDL_event_watchers_count - i) * sizeof(SDL_event_watchers[i]));
   879                     }
   880                 }
   881                 break;
   882             }
   883         }
   884 
   885         if (SDL_event_watchers_lock) {
   886             SDL_UnlockMutex(SDL_event_watchers_lock);
   887         }
   888     }
   889 }
   890 
   891 void
   892 SDL_FilterEvents(SDL_EventFilter filter, void *userdata)
   893 {
   894     if (!SDL_EventQ.lock || SDL_LockMutex(SDL_EventQ.lock) == 0) {
   895         SDL_EventEntry *entry, *next;
   896         for (entry = SDL_EventQ.head; entry; entry = next) {
   897             next = entry->next;
   898             if (!filter(userdata, &entry->event)) {
   899                 SDL_CutEvent(entry);
   900             }
   901         }
   902         if (SDL_EventQ.lock) {
   903             SDL_UnlockMutex(SDL_EventQ.lock);
   904         }
   905     }
   906 }
   907 
   908 Uint8
   909 SDL_EventState(Uint32 type, int state)
   910 {
   911     const SDL_bool isdnd = ((state == SDL_DISABLE) || (state == SDL_ENABLE)) &&
   912                            ((type == SDL_DROPFILE) || (type == SDL_DROPTEXT));
   913     Uint8 current_state;
   914     Uint8 hi = ((type >> 8) & 0xff);
   915     Uint8 lo = (type & 0xff);
   916 
   917     if (SDL_disabled_events[hi] &&
   918         (SDL_disabled_events[hi]->bits[lo/32] & (1 << (lo&31)))) {
   919         current_state = SDL_DISABLE;
   920     } else {
   921         current_state = SDL_ENABLE;
   922     }
   923 
   924     if (state != current_state)
   925     {
   926         switch (state) {
   927         case SDL_DISABLE:
   928             /* Disable this event type and discard pending events */
   929             if (!SDL_disabled_events[hi]) {
   930                 SDL_disabled_events[hi] = (SDL_DisabledEventBlock*) SDL_calloc(1, sizeof(SDL_DisabledEventBlock));
   931                 if (!SDL_disabled_events[hi]) {
   932                     /* Out of memory, nothing we can do... */
   933                     break;
   934                 }
   935             }
   936             SDL_disabled_events[hi]->bits[lo/32] |= (1 << (lo&31));
   937             SDL_FlushEvent(type);
   938             break;
   939         case SDL_ENABLE:
   940             SDL_disabled_events[hi]->bits[lo/32] &= ~(1 << (lo&31));
   941             break;
   942         default:
   943             /* Querying state... */
   944             break;
   945         }
   946     }
   947 
   948     /* turn off drag'n'drop support if we've disabled the events.
   949        This might change some UI details at the OS level. */
   950     if (isdnd) {
   951         SDL_ToggleDragAndDropSupport();
   952     }
   953 
   954     return current_state;
   955 }
   956 
   957 Uint32
   958 SDL_RegisterEvents(int numevents)
   959 {
   960     Uint32 event_base;
   961 
   962     if ((numevents > 0) && (SDL_userevents+numevents <= SDL_LASTEVENT)) {
   963         event_base = SDL_userevents;
   964         SDL_userevents += numevents;
   965     } else {
   966         event_base = (Uint32)-1;
   967     }
   968     return event_base;
   969 }
   970 
   971 int
   972 SDL_SendAppEvent(SDL_EventType eventType)
   973 {
   974     int posted;
   975 
   976     posted = 0;
   977     if (SDL_GetEventState(eventType) == SDL_ENABLE) {
   978         SDL_Event event;
   979         event.type = eventType;
   980         posted = (SDL_PushEvent(&event) > 0);
   981     }
   982     return (posted);
   983 }
   984 
   985 int
   986 SDL_SendSysWMEvent(SDL_SysWMmsg * message)
   987 {
   988     int posted;
   989 
   990     posted = 0;
   991     if (SDL_GetEventState(SDL_SYSWMEVENT) == SDL_ENABLE) {
   992         SDL_Event event;
   993         SDL_memset(&event, 0, sizeof(event));
   994         event.type = SDL_SYSWMEVENT;
   995         event.syswm.msg = message;
   996         posted = (SDL_PushEvent(&event) > 0);
   997     }
   998     /* Update internal event state */
   999     return (posted);
  1000 }
  1001 
  1002 int
  1003 SDL_SendKeymapChangedEvent(void)
  1004 {
  1005     return SDL_SendAppEvent(SDL_KEYMAPCHANGED);
  1006 }
  1007 
  1008 int
  1009 SDL_EventsInit(void)
  1010 {
  1011     SDL_AddHintCallback(SDL_HINT_EVENT_LOGGING, SDL_EventLoggingChanged, NULL);
  1012     if (SDL_StartEventLoop() < 0) {
  1013         SDL_DelHintCallback(SDL_HINT_EVENT_LOGGING, SDL_EventLoggingChanged, NULL);
  1014         return -1;
  1015     }
  1016 
  1017     SDL_QuitInit();
  1018 
  1019     return 0;
  1020 }
  1021 
  1022 void
  1023 SDL_EventsQuit(void)
  1024 {
  1025     SDL_QuitQuit();
  1026     SDL_StopEventLoop();
  1027     SDL_DelHintCallback(SDL_HINT_EVENT_LOGGING, SDL_EventLoggingChanged, NULL);
  1028 }
  1029 
  1030 /* vi: set ts=4 sw=4 expandtab: */