src/events/SDL_events.c
author Ryan C. Gordon <icculus@icculus.org>
Mon, 17 Mar 2014 19:11:18 -0400
changeset 8629 4c01875a4620
parent 8583 fb2933ca805f
child 8791 44dc9af6b7c2
permissions -rw-r--r--
Fixed SDL_HapticOpenFromJoystick() with DirectInput devices.
     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 static SDL_INLINE SDL_bool
    87 SDL_ShouldPollJoystick()
    88 {
    89 #if !SDL_JOYSTICK_DISABLED
    90     if ((!SDL_disabled_events[SDL_JOYAXISMOTION >> 8] ||
    91          SDL_JoystickEventState(SDL_QUERY)) &&
    92         SDL_PrivateJoystickNeedsPolling()) {
    93         return SDL_TRUE;
    94     }
    95 #endif
    96     return SDL_FALSE;
    97 }
    98 
    99 /* Public functions */
   100 
   101 void
   102 SDL_StopEventLoop(void)
   103 {
   104     int i;
   105     SDL_EventEntry *entry;
   106     SDL_SysWMEntry *wmmsg;
   107 
   108     if (SDL_EventQ.lock) {
   109         SDL_LockMutex(SDL_EventQ.lock);
   110     }
   111 
   112     SDL_EventQ.active = SDL_FALSE;
   113 
   114     /* Clean out EventQ */
   115     for (entry = SDL_EventQ.head; entry; ) {
   116         SDL_EventEntry *next = entry->next;
   117         SDL_free(entry);
   118         entry = next;
   119     }
   120     for (entry = SDL_EventQ.free; entry; ) {
   121         SDL_EventEntry *next = entry->next;
   122         SDL_free(entry);
   123         entry = next;
   124     }
   125     for (wmmsg = SDL_EventQ.wmmsg_used; wmmsg; ) {
   126         SDL_SysWMEntry *next = wmmsg->next;
   127         SDL_free(wmmsg);
   128         wmmsg = next;
   129     }
   130     for (wmmsg = SDL_EventQ.wmmsg_free; wmmsg; ) {
   131         SDL_SysWMEntry *next = wmmsg->next;
   132         SDL_free(wmmsg);
   133         wmmsg = next;
   134     }
   135     SDL_EventQ.count = 0;
   136     SDL_EventQ.head = NULL;
   137     SDL_EventQ.tail = NULL;
   138     SDL_EventQ.free = NULL;
   139     SDL_EventQ.wmmsg_used = NULL;
   140     SDL_EventQ.wmmsg_free = NULL;
   141 
   142     /* Clear disabled event state */
   143     for (i = 0; i < SDL_arraysize(SDL_disabled_events); ++i) {
   144         SDL_free(SDL_disabled_events[i]);
   145         SDL_disabled_events[i] = NULL;
   146     }
   147 
   148     while (SDL_event_watchers) {
   149         SDL_EventWatcher *tmp = SDL_event_watchers;
   150         SDL_event_watchers = tmp->next;
   151         SDL_free(tmp);
   152     }
   153     SDL_EventOK = NULL;
   154 
   155     if (SDL_EventQ.lock) {
   156         SDL_UnlockMutex(SDL_EventQ.lock);
   157         SDL_DestroyMutex(SDL_EventQ.lock);
   158         SDL_EventQ.lock = NULL;
   159     }
   160 }
   161 
   162 /* This function (and associated calls) may be called more than once */
   163 int
   164 SDL_StartEventLoop(void)
   165 {
   166     /* We'll leave the event queue alone, since we might have gotten
   167        some important events at launch (like SDL_DROPFILE)
   168 
   169        FIXME: Does this introduce any other bugs with events at startup?
   170      */
   171 
   172     /* Create the lock and set ourselves active */
   173 #if !SDL_THREADS_DISABLED
   174     if (!SDL_EventQ.lock) {
   175         SDL_EventQ.lock = SDL_CreateMutex();
   176     }
   177     if (SDL_EventQ.lock == NULL) {
   178         return (-1);
   179     }
   180 #endif /* !SDL_THREADS_DISABLED */
   181 
   182     /* Process most event types */
   183     SDL_EventState(SDL_TEXTINPUT, SDL_DISABLE);
   184     SDL_EventState(SDL_TEXTEDITING, SDL_DISABLE);
   185     SDL_EventState(SDL_SYSWMEVENT, SDL_DISABLE);
   186 
   187     SDL_EventQ.active = SDL_TRUE;
   188 
   189     return (0);
   190 }
   191 
   192 
   193 /* Add an event to the event queue -- called with the queue locked */
   194 static int
   195 SDL_AddEvent(SDL_Event * event)
   196 {
   197     SDL_EventEntry *entry;
   198 
   199     if (SDL_EventQ.count >= SDL_MAX_QUEUED_EVENTS) {
   200         SDL_SetError("Event queue is full (%d events)", SDL_EventQ.count);
   201         return 0;
   202     }
   203 
   204     if (SDL_EventQ.free == NULL) {
   205         entry = (SDL_EventEntry *)SDL_malloc(sizeof(*entry));
   206         if (!entry) {
   207             return 0;
   208         }
   209     } else {
   210         entry = SDL_EventQ.free;
   211         SDL_EventQ.free = entry->next;
   212     }
   213 
   214     entry->event = *event;
   215     if (event->type == SDL_SYSWMEVENT) {
   216         entry->msg = *event->syswm.msg;
   217         entry->event.syswm.msg = &entry->msg;
   218     }
   219 
   220     if (SDL_EventQ.tail) {
   221         SDL_EventQ.tail->next = entry;
   222         entry->prev = SDL_EventQ.tail;
   223         SDL_EventQ.tail = entry;
   224         entry->next = NULL;
   225     } else {
   226         SDL_assert(!SDL_EventQ.head);
   227         SDL_EventQ.head = entry;
   228         SDL_EventQ.tail = entry;
   229         entry->prev = NULL;
   230         entry->next = NULL;
   231     }
   232     ++SDL_EventQ.count;
   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                         SDL_SysWMEntry *wmmsg;
   319                         if (SDL_EventQ.wmmsg_free) {
   320                             wmmsg = SDL_EventQ.wmmsg_free;
   321                             SDL_EventQ.wmmsg_free = wmmsg->next;
   322                         } else {
   323                             wmmsg = (SDL_SysWMEntry *)SDL_malloc(sizeof(*wmmsg));
   324                         }
   325                         wmmsg->msg = *entry->event.syswm.msg;
   326                         wmmsg->next = SDL_EventQ.wmmsg_used;
   327                         SDL_EventQ.wmmsg_used = wmmsg;
   328                         events[used].syswm.msg = &wmmsg->msg;
   329                     }
   330                     ++used;
   331 
   332                     if (action == SDL_GETEVENT) {
   333                         SDL_CutEvent(entry);
   334                     }
   335                 }
   336             }
   337         }
   338         SDL_UnlockMutex(SDL_EventQ.lock);
   339     } else {
   340         return SDL_SetError("Couldn't lock event queue");
   341     }
   342     return (used);
   343 }
   344 
   345 SDL_bool
   346 SDL_HasEvent(Uint32 type)
   347 {
   348     return (SDL_PeepEvents(NULL, 0, SDL_PEEKEVENT, type, type) > 0);
   349 }
   350 
   351 SDL_bool
   352 SDL_HasEvents(Uint32 minType, Uint32 maxType)
   353 {
   354     return (SDL_PeepEvents(NULL, 0, SDL_PEEKEVENT, minType, maxType) > 0);
   355 }
   356 
   357 void
   358 SDL_FlushEvent(Uint32 type)
   359 {
   360     SDL_FlushEvents(type, type);
   361 }
   362 
   363 void
   364 SDL_FlushEvents(Uint32 minType, Uint32 maxType)
   365 {
   366     /* Don't look after we've quit */
   367     if (!SDL_EventQ.active) {
   368         return;
   369     }
   370 
   371     /* Make sure the events are current */
   372 #if 0
   373     /* Actually, we can't do this since we might be flushing while processing
   374        a resize event, and calling this might trigger further resize events.
   375     */
   376     SDL_PumpEvents();
   377 #endif
   378 
   379     /* Lock the event queue */
   380     if (SDL_LockMutex(SDL_EventQ.lock) == 0) {
   381         SDL_EventEntry *entry, *next;
   382         Uint32 type;
   383         for (entry = SDL_EventQ.head; entry; entry = next) {
   384             next = entry->next;
   385             type = entry->event.type;
   386             if (minType <= type && type <= maxType) {
   387                 SDL_CutEvent(entry);
   388             }
   389         }
   390         SDL_UnlockMutex(SDL_EventQ.lock);
   391     }
   392 }
   393 
   394 /* Run the system dependent event loops */
   395 void
   396 SDL_PumpEvents(void)
   397 {
   398     SDL_VideoDevice *_this = SDL_GetVideoDevice();
   399 
   400     /* Get events from the video subsystem */
   401     if (_this) {
   402         _this->PumpEvents(_this);
   403     }
   404 #if !SDL_JOYSTICK_DISABLED
   405     /* Check for joystick state change */
   406     if (SDL_ShouldPollJoystick()) {
   407         SDL_JoystickUpdate();
   408     }
   409 #endif
   410 }
   411 
   412 /* Public functions */
   413 
   414 int
   415 SDL_PollEvent(SDL_Event * event)
   416 {
   417     return SDL_WaitEventTimeout(event, 0);
   418 }
   419 
   420 int
   421 SDL_WaitEvent(SDL_Event * event)
   422 {
   423     return SDL_WaitEventTimeout(event, -1);
   424 }
   425 
   426 int
   427 SDL_WaitEventTimeout(SDL_Event * event, int timeout)
   428 {
   429     Uint32 expiration = 0;
   430 
   431     if (timeout > 0)
   432         expiration = SDL_GetTicks() + timeout;
   433 
   434     for (;;) {
   435         SDL_PumpEvents();
   436         switch (SDL_PeepEvents(event, 1, SDL_GETEVENT, SDL_FIRSTEVENT, SDL_LASTEVENT)) {
   437         case -1:
   438             return 0;
   439         case 1:
   440             return 1;
   441         case 0:
   442             if (timeout == 0) {
   443                 /* Polling and no events, just return */
   444                 return 0;
   445             }
   446             if (timeout > 0 && SDL_TICKS_PASSED(SDL_GetTicks(), expiration)) {
   447                 /* Timeout expired and no events */
   448                 return 0;
   449             }
   450             SDL_Delay(10);
   451             break;
   452         }
   453     }
   454 }
   455 
   456 int
   457 SDL_PushEvent(SDL_Event * event)
   458 {
   459     SDL_EventWatcher *curr;
   460 
   461     event->common.timestamp = SDL_GetTicks();
   462 
   463     if (SDL_EventOK && !SDL_EventOK(SDL_EventOKParam, event)) {
   464         return 0;
   465     }
   466 
   467     for (curr = SDL_event_watchers; curr; curr = curr->next) {
   468         curr->callback(curr->userdata, event);
   469     }
   470 
   471     if (SDL_PeepEvents(event, 1, SDL_ADDEVENT, 0, 0) <= 0) {
   472         return -1;
   473     }
   474 
   475     SDL_GestureProcessEvent(event);
   476 
   477     return 1;
   478 }
   479 
   480 void
   481 SDL_SetEventFilter(SDL_EventFilter filter, void *userdata)
   482 {
   483     /* Set filter and discard pending events */
   484     SDL_EventOK = NULL;
   485     SDL_FlushEvents(SDL_FIRSTEVENT, SDL_LASTEVENT);
   486     SDL_EventOKParam = userdata;
   487     SDL_EventOK = filter;
   488 }
   489 
   490 SDL_bool
   491 SDL_GetEventFilter(SDL_EventFilter * filter, void **userdata)
   492 {
   493     if (filter) {
   494         *filter = SDL_EventOK;
   495     }
   496     if (userdata) {
   497         *userdata = SDL_EventOKParam;
   498     }
   499     return SDL_EventOK ? SDL_TRUE : SDL_FALSE;
   500 }
   501 
   502 /* FIXME: This is not thread-safe yet */
   503 void
   504 SDL_AddEventWatch(SDL_EventFilter filter, void *userdata)
   505 {
   506     SDL_EventWatcher *watcher, *tail;
   507 
   508     watcher = (SDL_EventWatcher *)SDL_malloc(sizeof(*watcher));
   509     if (!watcher) {
   510         /* Uh oh... */
   511         return;
   512     }
   513 
   514     /* create the watcher */
   515     watcher->callback = filter;
   516     watcher->userdata = userdata;
   517     watcher->next = NULL;
   518 
   519     /* add the watcher to the end of the list */
   520     if (SDL_event_watchers) {
   521         for (tail = SDL_event_watchers; tail->next; tail = tail->next) {
   522             continue;
   523         }
   524         tail->next = watcher;
   525     } else {
   526         SDL_event_watchers = watcher;
   527     }
   528 }
   529 
   530 /* FIXME: This is not thread-safe yet */
   531 void
   532 SDL_DelEventWatch(SDL_EventFilter filter, void *userdata)
   533 {
   534     SDL_EventWatcher *prev = NULL;
   535     SDL_EventWatcher *curr;
   536 
   537     for (curr = SDL_event_watchers; curr; prev = curr, curr = curr->next) {
   538         if (curr->callback == filter && curr->userdata == userdata) {
   539             if (prev) {
   540                 prev->next = curr->next;
   541             } else {
   542                 SDL_event_watchers = curr->next;
   543             }
   544             SDL_free(curr);
   545             break;
   546         }
   547     }
   548 }
   549 
   550 void
   551 SDL_FilterEvents(SDL_EventFilter filter, void *userdata)
   552 {
   553     if (SDL_LockMutex(SDL_EventQ.lock) == 0) {
   554         SDL_EventEntry *entry, *next;
   555         for (entry = SDL_EventQ.head; entry; entry = next) {
   556             next = entry->next;
   557             if (!filter(userdata, &entry->event)) {
   558                 SDL_CutEvent(entry);
   559             }
   560         }
   561         SDL_UnlockMutex(SDL_EventQ.lock);
   562     }
   563 }
   564 
   565 Uint8
   566 SDL_EventState(Uint32 type, int state)
   567 {
   568     Uint8 current_state;
   569     Uint8 hi = ((type >> 8) & 0xff);
   570     Uint8 lo = (type & 0xff);
   571 
   572     if (SDL_disabled_events[hi] &&
   573         (SDL_disabled_events[hi]->bits[lo/32] & (1 << (lo&31)))) {
   574         current_state = SDL_DISABLE;
   575     } else {
   576         current_state = SDL_ENABLE;
   577     }
   578 
   579     if (state != current_state)
   580     {
   581         switch (state) {
   582         case SDL_DISABLE:
   583             /* Disable this event type and discard pending events */
   584             if (!SDL_disabled_events[hi]) {
   585                 SDL_disabled_events[hi] = (SDL_DisabledEventBlock*) SDL_calloc(1, sizeof(SDL_DisabledEventBlock));
   586                 if (!SDL_disabled_events[hi]) {
   587                     /* Out of memory, nothing we can do... */
   588                     break;
   589                 }
   590             }
   591             SDL_disabled_events[hi]->bits[lo/32] |= (1 << (lo&31));
   592             SDL_FlushEvent(type);
   593             break;
   594         case SDL_ENABLE:
   595             SDL_disabled_events[hi]->bits[lo/32] &= ~(1 << (lo&31));
   596             break;
   597         default:
   598             /* Querying state... */
   599             break;
   600         }
   601     }
   602 
   603     return current_state;
   604 }
   605 
   606 Uint32
   607 SDL_RegisterEvents(int numevents)
   608 {
   609     Uint32 event_base;
   610 
   611     if ((numevents > 0) && (SDL_userevents+numevents <= SDL_LASTEVENT)) {
   612         event_base = SDL_userevents;
   613         SDL_userevents += numevents;
   614     } else {
   615         event_base = (Uint32)-1;
   616     }
   617     return event_base;
   618 }
   619 
   620 int
   621 SDL_SendAppEvent(SDL_EventType eventType)
   622 {
   623     int posted;
   624 
   625     posted = 0;
   626     if (SDL_GetEventState(eventType) == SDL_ENABLE) {
   627         SDL_Event event;
   628         event.type = eventType;
   629         posted = (SDL_PushEvent(&event) > 0);
   630     }
   631     return (posted);
   632 }
   633 
   634 int
   635 SDL_SendSysWMEvent(SDL_SysWMmsg * message)
   636 {
   637     int posted;
   638 
   639     posted = 0;
   640     if (SDL_GetEventState(SDL_SYSWMEVENT) == SDL_ENABLE) {
   641         SDL_Event event;
   642         SDL_memset(&event, 0, sizeof(event));
   643         event.type = SDL_SYSWMEVENT;
   644         event.syswm.msg = message;
   645         posted = (SDL_PushEvent(&event) > 0);
   646     }
   647     /* Update internal event state */
   648     return (posted);
   649 }
   650 
   651 /* vi: set ts=4 sw=4 expandtab: */