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