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