src/events/SDL_events.c
author Ryan C. Gordon
Sat, 14 Jun 2014 23:31:23 -0400
changeset 8860 c4133d635375
parent 8791 44dc9af6b7c2
child 8910 c23ffe72934c
permissions -rw-r--r--
Removed SDL_SYS_JoystickNeedsPolling().

It was simpler to just have the polling (actually: hotplug detection)
functions return immediately if it's not an appropriate time to poll.

Note that previously, if any joystick/controller was opened, we would poll
every time anyhow, skipping this function.
     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                         SDL_SysWMEntry *wmmsg;
   306                         if (SDL_EventQ.wmmsg_free) {
   307                             wmmsg = SDL_EventQ.wmmsg_free;
   308                             SDL_EventQ.wmmsg_free = wmmsg->next;
   309                         } else {
   310                             wmmsg = (SDL_SysWMEntry *)SDL_malloc(sizeof(*wmmsg));
   311                         }
   312                         wmmsg->msg = *entry->event.syswm.msg;
   313                         wmmsg->next = SDL_EventQ.wmmsg_used;
   314                         SDL_EventQ.wmmsg_used = wmmsg;
   315                         events[used].syswm.msg = &wmmsg->msg;
   316                     }
   317                     ++used;
   318 
   319                     if (action == SDL_GETEVENT) {
   320                         SDL_CutEvent(entry);
   321                     }
   322                 }
   323             }
   324         }
   325         SDL_UnlockMutex(SDL_EventQ.lock);
   326     } else {
   327         return SDL_SetError("Couldn't lock event queue");
   328     }
   329     return (used);
   330 }
   331 
   332 SDL_bool
   333 SDL_HasEvent(Uint32 type)
   334 {
   335     return (SDL_PeepEvents(NULL, 0, SDL_PEEKEVENT, type, type) > 0);
   336 }
   337 
   338 SDL_bool
   339 SDL_HasEvents(Uint32 minType, Uint32 maxType)
   340 {
   341     return (SDL_PeepEvents(NULL, 0, SDL_PEEKEVENT, minType, maxType) > 0);
   342 }
   343 
   344 void
   345 SDL_FlushEvent(Uint32 type)
   346 {
   347     SDL_FlushEvents(type, type);
   348 }
   349 
   350 void
   351 SDL_FlushEvents(Uint32 minType, Uint32 maxType)
   352 {
   353     /* Don't look after we've quit */
   354     if (!SDL_EventQ.active) {
   355         return;
   356     }
   357 
   358     /* Make sure the events are current */
   359 #if 0
   360     /* Actually, we can't do this since we might be flushing while processing
   361        a resize event, and calling this might trigger further resize events.
   362     */
   363     SDL_PumpEvents();
   364 #endif
   365 
   366     /* Lock the event queue */
   367     if (SDL_LockMutex(SDL_EventQ.lock) == 0) {
   368         SDL_EventEntry *entry, *next;
   369         Uint32 type;
   370         for (entry = SDL_EventQ.head; entry; entry = next) {
   371             next = entry->next;
   372             type = entry->event.type;
   373             if (minType <= type && type <= maxType) {
   374                 SDL_CutEvent(entry);
   375             }
   376         }
   377         SDL_UnlockMutex(SDL_EventQ.lock);
   378     }
   379 }
   380 
   381 /* Run the system dependent event loops */
   382 void
   383 SDL_PumpEvents(void)
   384 {
   385     SDL_VideoDevice *_this = SDL_GetVideoDevice();
   386 
   387     /* Get events from the video subsystem */
   388     if (_this) {
   389         _this->PumpEvents(_this);
   390     }
   391 #if !SDL_JOYSTICK_DISABLED
   392     /* Check for joystick state change */
   393     if ((!SDL_disabled_events[SDL_JOYAXISMOTION >> 8] || SDL_JoystickEventState(SDL_QUERY))) {
   394         SDL_JoystickUpdate();
   395     }
   396 #endif
   397 }
   398 
   399 /* Public functions */
   400 
   401 int
   402 SDL_PollEvent(SDL_Event * event)
   403 {
   404     return SDL_WaitEventTimeout(event, 0);
   405 }
   406 
   407 int
   408 SDL_WaitEvent(SDL_Event * event)
   409 {
   410     return SDL_WaitEventTimeout(event, -1);
   411 }
   412 
   413 int
   414 SDL_WaitEventTimeout(SDL_Event * event, int timeout)
   415 {
   416     Uint32 expiration = 0;
   417 
   418     if (timeout > 0)
   419         expiration = SDL_GetTicks() + timeout;
   420 
   421     for (;;) {
   422         SDL_PumpEvents();
   423         switch (SDL_PeepEvents(event, 1, SDL_GETEVENT, SDL_FIRSTEVENT, SDL_LASTEVENT)) {
   424         case -1:
   425             return 0;
   426         case 1:
   427             return 1;
   428         case 0:
   429             if (timeout == 0) {
   430                 /* Polling and no events, just return */
   431                 return 0;
   432             }
   433             if (timeout > 0 && SDL_TICKS_PASSED(SDL_GetTicks(), expiration)) {
   434                 /* Timeout expired and no events */
   435                 return 0;
   436             }
   437             SDL_Delay(10);
   438             break;
   439         }
   440     }
   441 }
   442 
   443 int
   444 SDL_PushEvent(SDL_Event * event)
   445 {
   446     SDL_EventWatcher *curr;
   447 
   448     event->common.timestamp = SDL_GetTicks();
   449 
   450     if (SDL_EventOK && !SDL_EventOK(SDL_EventOKParam, event)) {
   451         return 0;
   452     }
   453 
   454     for (curr = SDL_event_watchers; curr; curr = curr->next) {
   455         curr->callback(curr->userdata, event);
   456     }
   457 
   458     if (SDL_PeepEvents(event, 1, SDL_ADDEVENT, 0, 0) <= 0) {
   459         return -1;
   460     }
   461 
   462     SDL_GestureProcessEvent(event);
   463 
   464     return 1;
   465 }
   466 
   467 void
   468 SDL_SetEventFilter(SDL_EventFilter filter, void *userdata)
   469 {
   470     /* Set filter and discard pending events */
   471     SDL_EventOK = NULL;
   472     SDL_FlushEvents(SDL_FIRSTEVENT, SDL_LASTEVENT);
   473     SDL_EventOKParam = userdata;
   474     SDL_EventOK = filter;
   475 }
   476 
   477 SDL_bool
   478 SDL_GetEventFilter(SDL_EventFilter * filter, void **userdata)
   479 {
   480     if (filter) {
   481         *filter = SDL_EventOK;
   482     }
   483     if (userdata) {
   484         *userdata = SDL_EventOKParam;
   485     }
   486     return SDL_EventOK ? SDL_TRUE : SDL_FALSE;
   487 }
   488 
   489 /* FIXME: This is not thread-safe yet */
   490 void
   491 SDL_AddEventWatch(SDL_EventFilter filter, void *userdata)
   492 {
   493     SDL_EventWatcher *watcher, *tail;
   494 
   495     watcher = (SDL_EventWatcher *)SDL_malloc(sizeof(*watcher));
   496     if (!watcher) {
   497         /* Uh oh... */
   498         return;
   499     }
   500 
   501     /* create the watcher */
   502     watcher->callback = filter;
   503     watcher->userdata = userdata;
   504     watcher->next = NULL;
   505 
   506     /* add the watcher to the end of the list */
   507     if (SDL_event_watchers) {
   508         for (tail = SDL_event_watchers; tail->next; tail = tail->next) {
   509             continue;
   510         }
   511         tail->next = watcher;
   512     } else {
   513         SDL_event_watchers = watcher;
   514     }
   515 }
   516 
   517 /* FIXME: This is not thread-safe yet */
   518 void
   519 SDL_DelEventWatch(SDL_EventFilter filter, void *userdata)
   520 {
   521     SDL_EventWatcher *prev = NULL;
   522     SDL_EventWatcher *curr;
   523 
   524     for (curr = SDL_event_watchers; curr; prev = curr, curr = curr->next) {
   525         if (curr->callback == filter && curr->userdata == userdata) {
   526             if (prev) {
   527                 prev->next = curr->next;
   528             } else {
   529                 SDL_event_watchers = curr->next;
   530             }
   531             SDL_free(curr);
   532             break;
   533         }
   534     }
   535 }
   536 
   537 void
   538 SDL_FilterEvents(SDL_EventFilter filter, void *userdata)
   539 {
   540     if (SDL_EventQ.lock && SDL_LockMutex(SDL_EventQ.lock) == 0) {
   541         SDL_EventEntry *entry, *next;
   542         for (entry = SDL_EventQ.head; entry; entry = next) {
   543             next = entry->next;
   544             if (!filter(userdata, &entry->event)) {
   545                 SDL_CutEvent(entry);
   546             }
   547         }
   548         SDL_UnlockMutex(SDL_EventQ.lock);
   549     }
   550 }
   551 
   552 Uint8
   553 SDL_EventState(Uint32 type, int state)
   554 {
   555     Uint8 current_state;
   556     Uint8 hi = ((type >> 8) & 0xff);
   557     Uint8 lo = (type & 0xff);
   558 
   559     if (SDL_disabled_events[hi] &&
   560         (SDL_disabled_events[hi]->bits[lo/32] & (1 << (lo&31)))) {
   561         current_state = SDL_DISABLE;
   562     } else {
   563         current_state = SDL_ENABLE;
   564     }
   565 
   566     if (state != current_state)
   567     {
   568         switch (state) {
   569         case SDL_DISABLE:
   570             /* Disable this event type and discard pending events */
   571             if (!SDL_disabled_events[hi]) {
   572                 SDL_disabled_events[hi] = (SDL_DisabledEventBlock*) SDL_calloc(1, sizeof(SDL_DisabledEventBlock));
   573                 if (!SDL_disabled_events[hi]) {
   574                     /* Out of memory, nothing we can do... */
   575                     break;
   576                 }
   577             }
   578             SDL_disabled_events[hi]->bits[lo/32] |= (1 << (lo&31));
   579             SDL_FlushEvent(type);
   580             break;
   581         case SDL_ENABLE:
   582             SDL_disabled_events[hi]->bits[lo/32] &= ~(1 << (lo&31));
   583             break;
   584         default:
   585             /* Querying state... */
   586             break;
   587         }
   588     }
   589 
   590     return current_state;
   591 }
   592 
   593 Uint32
   594 SDL_RegisterEvents(int numevents)
   595 {
   596     Uint32 event_base;
   597 
   598     if ((numevents > 0) && (SDL_userevents+numevents <= SDL_LASTEVENT)) {
   599         event_base = SDL_userevents;
   600         SDL_userevents += numevents;
   601     } else {
   602         event_base = (Uint32)-1;
   603     }
   604     return event_base;
   605 }
   606 
   607 int
   608 SDL_SendAppEvent(SDL_EventType eventType)
   609 {
   610     int posted;
   611 
   612     posted = 0;
   613     if (SDL_GetEventState(eventType) == SDL_ENABLE) {
   614         SDL_Event event;
   615         event.type = eventType;
   616         posted = (SDL_PushEvent(&event) > 0);
   617     }
   618     return (posted);
   619 }
   620 
   621 int
   622 SDL_SendSysWMEvent(SDL_SysWMmsg * message)
   623 {
   624     int posted;
   625 
   626     posted = 0;
   627     if (SDL_GetEventState(SDL_SYSWMEVENT) == SDL_ENABLE) {
   628         SDL_Event event;
   629         SDL_memset(&event, 0, sizeof(event));
   630         event.type = SDL_SYSWMEVENT;
   631         event.syswm.msg = message;
   632         posted = (SDL_PushEvent(&event) > 0);
   633     }
   634     /* Update internal event state */
   635     return (posted);
   636 }
   637 
   638 /* vi: set ts=4 sw=4 expandtab: */