src/events/SDL_events.c
author Sam Lantinga
Sun, 22 Jun 2014 11:02:56 -0700
changeset 8910 c23ffe72934c
parent 8860 c4133d635375
child 9437 569cfb86df95
permissions -rw-r--r--
Partial fix for bug 2556 - add compilation flag -Wshadow

I added -Wshadow and then turned it off again because of massive variable shadowing in the blit macros.

Feel free to go through that code and fix these if you want. Just uncomment CheckWarnShadow in configure.in if you want to try this.
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2014 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 /* An arbitrary limit so we don't have unbounded growth */
    37 #define SDL_MAX_QUEUED_EVENTS   65535
    38 
    39 /* Public data -- the event filter */
    40 SDL_EventFilter SDL_EventOK = NULL;
    41 void *SDL_EventOKParam;
    42 
    43 typedef struct SDL_EventWatcher {
    44     SDL_EventFilter callback;
    45     void *userdata;
    46     struct SDL_EventWatcher *next;
    47 } SDL_EventWatcher;
    48 
    49 static SDL_EventWatcher *SDL_event_watchers = NULL;
    50 
    51 typedef struct {
    52     Uint32 bits[8];
    53 } SDL_DisabledEventBlock;
    54 
    55 static SDL_DisabledEventBlock *SDL_disabled_events[256];
    56 static Uint32 SDL_userevents = SDL_USEREVENT;
    57 
    58 /* Private data -- event queue */
    59 typedef struct _SDL_EventEntry
    60 {
    61     SDL_Event event;
    62     SDL_SysWMmsg msg;
    63     struct _SDL_EventEntry *prev;
    64     struct _SDL_EventEntry *next;
    65 } SDL_EventEntry;
    66 
    67 typedef struct _SDL_SysWMEntry
    68 {
    69     SDL_SysWMmsg msg;
    70     struct _SDL_SysWMEntry *next;
    71 } SDL_SysWMEntry;
    72 
    73 static struct
    74 {
    75     SDL_mutex *lock;
    76     volatile SDL_bool active;
    77     volatile int count;
    78     SDL_EventEntry *head;
    79     SDL_EventEntry *tail;
    80     SDL_EventEntry *free;
    81     SDL_SysWMEntry *wmmsg_used;
    82     SDL_SysWMEntry *wmmsg_free;
    83 } SDL_EventQ = { NULL, SDL_TRUE };
    84 
    85 
    86 /* Public functions */
    87 
    88 void
    89 SDL_StopEventLoop(void)
    90 {
    91     int i;
    92     SDL_EventEntry *entry;
    93     SDL_SysWMEntry *wmmsg;
    94 
    95     if (SDL_EventQ.lock) {
    96         SDL_LockMutex(SDL_EventQ.lock);
    97     }
    98 
    99     SDL_EventQ.active = SDL_FALSE;
   100 
   101     /* Clean out EventQ */
   102     for (entry = SDL_EventQ.head; entry; ) {
   103         SDL_EventEntry *next = entry->next;
   104         SDL_free(entry);
   105         entry = next;
   106     }
   107     for (entry = SDL_EventQ.free; entry; ) {
   108         SDL_EventEntry *next = entry->next;
   109         SDL_free(entry);
   110         entry = next;
   111     }
   112     for (wmmsg = SDL_EventQ.wmmsg_used; wmmsg; ) {
   113         SDL_SysWMEntry *next = wmmsg->next;
   114         SDL_free(wmmsg);
   115         wmmsg = next;
   116     }
   117     for (wmmsg = SDL_EventQ.wmmsg_free; wmmsg; ) {
   118         SDL_SysWMEntry *next = wmmsg->next;
   119         SDL_free(wmmsg);
   120         wmmsg = next;
   121     }
   122     SDL_EventQ.count = 0;
   123     SDL_EventQ.head = NULL;
   124     SDL_EventQ.tail = NULL;
   125     SDL_EventQ.free = NULL;
   126     SDL_EventQ.wmmsg_used = NULL;
   127     SDL_EventQ.wmmsg_free = NULL;
   128 
   129     /* Clear disabled event state */
   130     for (i = 0; i < SDL_arraysize(SDL_disabled_events); ++i) {
   131         SDL_free(SDL_disabled_events[i]);
   132         SDL_disabled_events[i] = NULL;
   133     }
   134 
   135     while (SDL_event_watchers) {
   136         SDL_EventWatcher *tmp = SDL_event_watchers;
   137         SDL_event_watchers = tmp->next;
   138         SDL_free(tmp);
   139     }
   140     SDL_EventOK = NULL;
   141 
   142     if (SDL_EventQ.lock) {
   143         SDL_UnlockMutex(SDL_EventQ.lock);
   144         SDL_DestroyMutex(SDL_EventQ.lock);
   145         SDL_EventQ.lock = NULL;
   146     }
   147 }
   148 
   149 /* This function (and associated calls) may be called more than once */
   150 int
   151 SDL_StartEventLoop(void)
   152 {
   153     /* We'll leave the event queue alone, since we might have gotten
   154        some important events at launch (like SDL_DROPFILE)
   155 
   156        FIXME: Does this introduce any other bugs with events at startup?
   157      */
   158 
   159     /* Create the lock and set ourselves active */
   160 #if !SDL_THREADS_DISABLED
   161     if (!SDL_EventQ.lock) {
   162         SDL_EventQ.lock = SDL_CreateMutex();
   163     }
   164     if (SDL_EventQ.lock == NULL) {
   165         return (-1);
   166     }
   167 #endif /* !SDL_THREADS_DISABLED */
   168 
   169     /* Process most event types */
   170     SDL_EventState(SDL_TEXTINPUT, SDL_DISABLE);
   171     SDL_EventState(SDL_TEXTEDITING, SDL_DISABLE);
   172     SDL_EventState(SDL_SYSWMEVENT, SDL_DISABLE);
   173 
   174     SDL_EventQ.active = SDL_TRUE;
   175 
   176     return (0);
   177 }
   178 
   179 
   180 /* Add an event to the event queue -- called with the queue locked */
   181 static int
   182 SDL_AddEvent(SDL_Event * event)
   183 {
   184     SDL_EventEntry *entry;
   185 
   186     if (SDL_EventQ.count >= SDL_MAX_QUEUED_EVENTS) {
   187         SDL_SetError("Event queue is full (%d events)", SDL_EventQ.count);
   188         return 0;
   189     }
   190 
   191     if (SDL_EventQ.free == NULL) {
   192         entry = (SDL_EventEntry *)SDL_malloc(sizeof(*entry));
   193         if (!entry) {
   194             return 0;
   195         }
   196     } else {
   197         entry = SDL_EventQ.free;
   198         SDL_EventQ.free = entry->next;
   199     }
   200 
   201     entry->event = *event;
   202     if (event->type == SDL_SYSWMEVENT) {
   203         entry->msg = *event->syswm.msg;
   204         entry->event.syswm.msg = &entry->msg;
   205     }
   206 
   207     if (SDL_EventQ.tail) {
   208         SDL_EventQ.tail->next = entry;
   209         entry->prev = SDL_EventQ.tail;
   210         SDL_EventQ.tail = entry;
   211         entry->next = NULL;
   212     } else {
   213         SDL_assert(!SDL_EventQ.head);
   214         SDL_EventQ.head = entry;
   215         SDL_EventQ.tail = entry;
   216         entry->prev = NULL;
   217         entry->next = NULL;
   218     }
   219     ++SDL_EventQ.count;
   220 
   221     return 1;
   222 }
   223 
   224 /* Remove an event from the queue -- called with the queue locked */
   225 static void
   226 SDL_CutEvent(SDL_EventEntry *entry)
   227 {
   228     if (entry->prev) {
   229         entry->prev->next = entry->next;
   230     }
   231     if (entry->next) {
   232         entry->next->prev = entry->prev;
   233     }
   234 
   235     if (entry == SDL_EventQ.head) {
   236         SDL_assert(entry->prev == NULL);
   237         SDL_EventQ.head = entry->next;
   238     }
   239     if (entry == SDL_EventQ.tail) {
   240         SDL_assert(entry->next == NULL);
   241         SDL_EventQ.tail = entry->prev;
   242     }
   243 
   244     entry->next = SDL_EventQ.free;
   245     SDL_EventQ.free = entry;
   246     SDL_assert(SDL_EventQ.count > 0);
   247     --SDL_EventQ.count;
   248 }
   249 
   250 /* Lock the event queue, take a peep at it, and unlock it */
   251 int
   252 SDL_PeepEvents(SDL_Event * events, int numevents, SDL_eventaction action,
   253                Uint32 minType, Uint32 maxType)
   254 {
   255     int i, used;
   256 
   257     /* Don't look after we've quit */
   258     if (!SDL_EventQ.active) {
   259         /* We get a few spurious events at shutdown, so don't warn then */
   260         if (action != SDL_ADDEVENT) {
   261             SDL_SetError("The event system has been shut down");
   262         }
   263         return (-1);
   264     }
   265     /* Lock the event queue */
   266     used = 0;
   267     if (!SDL_EventQ.lock || SDL_LockMutex(SDL_EventQ.lock) == 0) {
   268         if (action == SDL_ADDEVENT) {
   269             for (i = 0; i < numevents; ++i) {
   270                 used += SDL_AddEvent(&events[i]);
   271             }
   272         } else {
   273             SDL_EventEntry *entry, *next;
   274             SDL_SysWMEntry *wmmsg, *wmmsg_next;
   275             SDL_Event tmpevent;
   276             Uint32 type;
   277 
   278             /* If 'events' is NULL, just see if they exist */
   279             if (events == NULL) {
   280                 action = SDL_PEEKEVENT;
   281                 numevents = 1;
   282                 events = &tmpevent;
   283             }
   284 
   285             /* Clean out any used wmmsg data
   286                FIXME: Do we want to retain the data for some period of time?
   287              */
   288             for (wmmsg = SDL_EventQ.wmmsg_used; wmmsg; wmmsg = wmmsg_next) {
   289                 wmmsg_next = wmmsg->next;
   290                 wmmsg->next = SDL_EventQ.wmmsg_free;
   291                 SDL_EventQ.wmmsg_free = wmmsg;
   292             }
   293             SDL_EventQ.wmmsg_used = NULL;
   294 
   295             for (entry = SDL_EventQ.head; entry && used < numevents; entry = next) {
   296                 next = entry->next;
   297                 type = entry->event.type;
   298                 if (minType <= type && type <= maxType) {
   299                     events[used] = entry->event;
   300                     if (entry->event.type == SDL_SYSWMEVENT) {
   301                         /* We need to copy the wmmsg somewhere safe.
   302                            For now we'll guarantee it's valid at least until
   303                            the next call to SDL_PeepEvents()
   304                          */
   305                         if (SDL_EventQ.wmmsg_free) {
   306                             wmmsg = SDL_EventQ.wmmsg_free;
   307                             SDL_EventQ.wmmsg_free = wmmsg->next;
   308                         } else {
   309                             wmmsg = (SDL_SysWMEntry *)SDL_malloc(sizeof(*wmmsg));
   310                         }
   311                         wmmsg->msg = *entry->event.syswm.msg;
   312                         wmmsg->next = SDL_EventQ.wmmsg_used;
   313                         SDL_EventQ.wmmsg_used = wmmsg;
   314                         events[used].syswm.msg = &wmmsg->msg;
   315                     }
   316                     ++used;
   317 
   318                     if (action == SDL_GETEVENT) {
   319                         SDL_CutEvent(entry);
   320                     }
   321                 }
   322             }
   323         }
   324         SDL_UnlockMutex(SDL_EventQ.lock);
   325     } else {
   326         return SDL_SetError("Couldn't lock event queue");
   327     }
   328     return (used);
   329 }
   330 
   331 SDL_bool
   332 SDL_HasEvent(Uint32 type)
   333 {
   334     return (SDL_PeepEvents(NULL, 0, SDL_PEEKEVENT, type, type) > 0);
   335 }
   336 
   337 SDL_bool
   338 SDL_HasEvents(Uint32 minType, Uint32 maxType)
   339 {
   340     return (SDL_PeepEvents(NULL, 0, SDL_PEEKEVENT, minType, maxType) > 0);
   341 }
   342 
   343 void
   344 SDL_FlushEvent(Uint32 type)
   345 {
   346     SDL_FlushEvents(type, type);
   347 }
   348 
   349 void
   350 SDL_FlushEvents(Uint32 minType, Uint32 maxType)
   351 {
   352     /* Don't look after we've quit */
   353     if (!SDL_EventQ.active) {
   354         return;
   355     }
   356 
   357     /* Make sure the events are current */
   358 #if 0
   359     /* Actually, we can't do this since we might be flushing while processing
   360        a resize event, and calling this might trigger further resize events.
   361     */
   362     SDL_PumpEvents();
   363 #endif
   364 
   365     /* Lock the event queue */
   366     if (SDL_LockMutex(SDL_EventQ.lock) == 0) {
   367         SDL_EventEntry *entry, *next;
   368         Uint32 type;
   369         for (entry = SDL_EventQ.head; entry; entry = next) {
   370             next = entry->next;
   371             type = entry->event.type;
   372             if (minType <= type && type <= maxType) {
   373                 SDL_CutEvent(entry);
   374             }
   375         }
   376         SDL_UnlockMutex(SDL_EventQ.lock);
   377     }
   378 }
   379 
   380 /* Run the system dependent event loops */
   381 void
   382 SDL_PumpEvents(void)
   383 {
   384     SDL_VideoDevice *_this = SDL_GetVideoDevice();
   385 
   386     /* Get events from the video subsystem */
   387     if (_this) {
   388         _this->PumpEvents(_this);
   389     }
   390 #if !SDL_JOYSTICK_DISABLED
   391     /* Check for joystick state change */
   392     if ((!SDL_disabled_events[SDL_JOYAXISMOTION >> 8] || SDL_JoystickEventState(SDL_QUERY))) {
   393         SDL_JoystickUpdate();
   394     }
   395 #endif
   396 }
   397 
   398 /* Public functions */
   399 
   400 int
   401 SDL_PollEvent(SDL_Event * event)
   402 {
   403     return SDL_WaitEventTimeout(event, 0);
   404 }
   405 
   406 int
   407 SDL_WaitEvent(SDL_Event * event)
   408 {
   409     return SDL_WaitEventTimeout(event, -1);
   410 }
   411 
   412 int
   413 SDL_WaitEventTimeout(SDL_Event * event, int timeout)
   414 {
   415     Uint32 expiration = 0;
   416 
   417     if (timeout > 0)
   418         expiration = SDL_GetTicks() + timeout;
   419 
   420     for (;;) {
   421         SDL_PumpEvents();
   422         switch (SDL_PeepEvents(event, 1, SDL_GETEVENT, SDL_FIRSTEVENT, SDL_LASTEVENT)) {
   423         case -1:
   424             return 0;
   425         case 1:
   426             return 1;
   427         case 0:
   428             if (timeout == 0) {
   429                 /* Polling and no events, just return */
   430                 return 0;
   431             }
   432             if (timeout > 0 && SDL_TICKS_PASSED(SDL_GetTicks(), expiration)) {
   433                 /* Timeout expired and no events */
   434                 return 0;
   435             }
   436             SDL_Delay(10);
   437             break;
   438         }
   439     }
   440 }
   441 
   442 int
   443 SDL_PushEvent(SDL_Event * event)
   444 {
   445     SDL_EventWatcher *curr;
   446 
   447     event->common.timestamp = SDL_GetTicks();
   448 
   449     if (SDL_EventOK && !SDL_EventOK(SDL_EventOKParam, event)) {
   450         return 0;
   451     }
   452 
   453     for (curr = SDL_event_watchers; curr; curr = curr->next) {
   454         curr->callback(curr->userdata, event);
   455     }
   456 
   457     if (SDL_PeepEvents(event, 1, SDL_ADDEVENT, 0, 0) <= 0) {
   458         return -1;
   459     }
   460 
   461     SDL_GestureProcessEvent(event);
   462 
   463     return 1;
   464 }
   465 
   466 void
   467 SDL_SetEventFilter(SDL_EventFilter filter, void *userdata)
   468 {
   469     /* Set filter and discard pending events */
   470     SDL_EventOK = NULL;
   471     SDL_FlushEvents(SDL_FIRSTEVENT, SDL_LASTEVENT);
   472     SDL_EventOKParam = userdata;
   473     SDL_EventOK = filter;
   474 }
   475 
   476 SDL_bool
   477 SDL_GetEventFilter(SDL_EventFilter * filter, void **userdata)
   478 {
   479     if (filter) {
   480         *filter = SDL_EventOK;
   481     }
   482     if (userdata) {
   483         *userdata = SDL_EventOKParam;
   484     }
   485     return SDL_EventOK ? SDL_TRUE : SDL_FALSE;
   486 }
   487 
   488 /* FIXME: This is not thread-safe yet */
   489 void
   490 SDL_AddEventWatch(SDL_EventFilter filter, void *userdata)
   491 {
   492     SDL_EventWatcher *watcher, *tail;
   493 
   494     watcher = (SDL_EventWatcher *)SDL_malloc(sizeof(*watcher));
   495     if (!watcher) {
   496         /* Uh oh... */
   497         return;
   498     }
   499 
   500     /* create the watcher */
   501     watcher->callback = filter;
   502     watcher->userdata = userdata;
   503     watcher->next = NULL;
   504 
   505     /* add the watcher to the end of the list */
   506     if (SDL_event_watchers) {
   507         for (tail = SDL_event_watchers; tail->next; tail = tail->next) {
   508             continue;
   509         }
   510         tail->next = watcher;
   511     } else {
   512         SDL_event_watchers = watcher;
   513     }
   514 }
   515 
   516 /* FIXME: This is not thread-safe yet */
   517 void
   518 SDL_DelEventWatch(SDL_EventFilter filter, void *userdata)
   519 {
   520     SDL_EventWatcher *prev = NULL;
   521     SDL_EventWatcher *curr;
   522 
   523     for (curr = SDL_event_watchers; curr; prev = curr, curr = curr->next) {
   524         if (curr->callback == filter && curr->userdata == userdata) {
   525             if (prev) {
   526                 prev->next = curr->next;
   527             } else {
   528                 SDL_event_watchers = curr->next;
   529             }
   530             SDL_free(curr);
   531             break;
   532         }
   533     }
   534 }
   535 
   536 void
   537 SDL_FilterEvents(SDL_EventFilter filter, void *userdata)
   538 {
   539     if (SDL_EventQ.lock && SDL_LockMutex(SDL_EventQ.lock) == 0) {
   540         SDL_EventEntry *entry, *next;
   541         for (entry = SDL_EventQ.head; entry; entry = next) {
   542             next = entry->next;
   543             if (!filter(userdata, &entry->event)) {
   544                 SDL_CutEvent(entry);
   545             }
   546         }
   547         SDL_UnlockMutex(SDL_EventQ.lock);
   548     }
   549 }
   550 
   551 Uint8
   552 SDL_EventState(Uint32 type, int state)
   553 {
   554     Uint8 current_state;
   555     Uint8 hi = ((type >> 8) & 0xff);
   556     Uint8 lo = (type & 0xff);
   557 
   558     if (SDL_disabled_events[hi] &&
   559         (SDL_disabled_events[hi]->bits[lo/32] & (1 << (lo&31)))) {
   560         current_state = SDL_DISABLE;
   561     } else {
   562         current_state = SDL_ENABLE;
   563     }
   564 
   565     if (state != current_state)
   566     {
   567         switch (state) {
   568         case SDL_DISABLE:
   569             /* Disable this event type and discard pending events */
   570             if (!SDL_disabled_events[hi]) {
   571                 SDL_disabled_events[hi] = (SDL_DisabledEventBlock*) SDL_calloc(1, sizeof(SDL_DisabledEventBlock));
   572                 if (!SDL_disabled_events[hi]) {
   573                     /* Out of memory, nothing we can do... */
   574                     break;
   575                 }
   576             }
   577             SDL_disabled_events[hi]->bits[lo/32] |= (1 << (lo&31));
   578             SDL_FlushEvent(type);
   579             break;
   580         case SDL_ENABLE:
   581             SDL_disabled_events[hi]->bits[lo/32] &= ~(1 << (lo&31));
   582             break;
   583         default:
   584             /* Querying state... */
   585             break;
   586         }
   587     }
   588 
   589     return current_state;
   590 }
   591 
   592 Uint32
   593 SDL_RegisterEvents(int numevents)
   594 {
   595     Uint32 event_base;
   596 
   597     if ((numevents > 0) && (SDL_userevents+numevents <= SDL_LASTEVENT)) {
   598         event_base = SDL_userevents;
   599         SDL_userevents += numevents;
   600     } else {
   601         event_base = (Uint32)-1;
   602     }
   603     return event_base;
   604 }
   605 
   606 int
   607 SDL_SendAppEvent(SDL_EventType eventType)
   608 {
   609     int posted;
   610 
   611     posted = 0;
   612     if (SDL_GetEventState(eventType) == SDL_ENABLE) {
   613         SDL_Event event;
   614         event.type = eventType;
   615         posted = (SDL_PushEvent(&event) > 0);
   616     }
   617     return (posted);
   618 }
   619 
   620 int
   621 SDL_SendSysWMEvent(SDL_SysWMmsg * message)
   622 {
   623     int posted;
   624 
   625     posted = 0;
   626     if (SDL_GetEventState(SDL_SYSWMEVENT) == SDL_ENABLE) {
   627         SDL_Event event;
   628         SDL_memset(&event, 0, sizeof(event));
   629         event.type = SDL_SYSWMEVENT;
   630         event.syswm.msg = message;
   631         posted = (SDL_PushEvent(&event) > 0);
   632     }
   633     /* Update internal event state */
   634     return (posted);
   635 }
   636 
   637 /* vi: set ts=4 sw=4 expandtab: */