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