src/events/SDL_events.c
author Philipp Wiesemann <philipp.wiesemann@arcor.de>
Sun, 27 Mar 2016 22:22:13 +0200
changeset 10123 d2686deec646
parent 10106 d240baef8248
child 10488 3e61babccbbe
permissions -rw-r--r--
Fixed comment in gesture source.
     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     SDL_atomic_t active;
    77     SDL_atomic_t count;
    78     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, { 1 }, { 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_AtomicSet(&SDL_EventQ.active, 0);
   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_AtomicSet(&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_AtomicSet(&SDL_EventQ.active, 1);
   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     const int initial_count = SDL_AtomicGet(&SDL_EventQ.count);
   195     int final_count;
   196 
   197     if (initial_count >= SDL_MAX_QUEUED_EVENTS) {
   198         SDL_SetError("Event queue is full (%d events)", initial_count);
   199         return 0;
   200     }
   201 
   202     if (SDL_EventQ.free == NULL) {
   203         entry = (SDL_EventEntry *)SDL_malloc(sizeof(*entry));
   204         if (!entry) {
   205             return 0;
   206         }
   207     } else {
   208         entry = SDL_EventQ.free;
   209         SDL_EventQ.free = entry->next;
   210     }
   211 
   212     entry->event = *event;
   213     if (event->type == SDL_SYSWMEVENT) {
   214         entry->msg = *event->syswm.msg;
   215         entry->event.syswm.msg = &entry->msg;
   216     }
   217 
   218     if (SDL_EventQ.tail) {
   219         SDL_EventQ.tail->next = entry;
   220         entry->prev = SDL_EventQ.tail;
   221         SDL_EventQ.tail = entry;
   222         entry->next = NULL;
   223     } else {
   224         SDL_assert(!SDL_EventQ.head);
   225         SDL_EventQ.head = entry;
   226         SDL_EventQ.tail = entry;
   227         entry->prev = NULL;
   228         entry->next = NULL;
   229     }
   230 
   231     final_count = SDL_AtomicAdd(&SDL_EventQ.count, 1) + 1;
   232     if (final_count > SDL_EventQ.max_events_seen) {
   233         SDL_EventQ.max_events_seen = final_count;
   234     }
   235 
   236     return 1;
   237 }
   238 
   239 /* Remove an event from the queue -- called with the queue locked */
   240 static void
   241 SDL_CutEvent(SDL_EventEntry *entry)
   242 {
   243     if (entry->prev) {
   244         entry->prev->next = entry->next;
   245     }
   246     if (entry->next) {
   247         entry->next->prev = entry->prev;
   248     }
   249 
   250     if (entry == SDL_EventQ.head) {
   251         SDL_assert(entry->prev == NULL);
   252         SDL_EventQ.head = entry->next;
   253     }
   254     if (entry == SDL_EventQ.tail) {
   255         SDL_assert(entry->next == NULL);
   256         SDL_EventQ.tail = entry->prev;
   257     }
   258 
   259     entry->next = SDL_EventQ.free;
   260     SDL_EventQ.free = entry;
   261     SDL_assert(SDL_AtomicGet(&SDL_EventQ.count) > 0);
   262     SDL_AtomicAdd(&SDL_EventQ.count, -1);
   263 }
   264 
   265 /* Lock the event queue, take a peep at it, and unlock it */
   266 int
   267 SDL_PeepEvents(SDL_Event * events, int numevents, SDL_eventaction action,
   268                Uint32 minType, Uint32 maxType)
   269 {
   270     int i, used;
   271 
   272     /* Don't look after we've quit */
   273     if (!SDL_AtomicGet(&SDL_EventQ.active)) {
   274         /* We get a few spurious events at shutdown, so don't warn then */
   275         if (action != SDL_ADDEVENT) {
   276             SDL_SetError("The event system has been shut down");
   277         }
   278         return (-1);
   279     }
   280     /* Lock the event queue */
   281     used = 0;
   282     if (!SDL_EventQ.lock || SDL_LockMutex(SDL_EventQ.lock) == 0) {
   283         if (action == SDL_ADDEVENT) {
   284             for (i = 0; i < numevents; ++i) {
   285                 used += SDL_AddEvent(&events[i]);
   286             }
   287         } else {
   288             SDL_EventEntry *entry, *next;
   289             SDL_SysWMEntry *wmmsg, *wmmsg_next;
   290             Uint32 type;
   291 
   292             if (action == SDL_GETEVENT) {
   293                 /* Clean out any used wmmsg data
   294                    FIXME: Do we want to retain the data for some period of time?
   295                  */
   296                 for (wmmsg = SDL_EventQ.wmmsg_used; wmmsg; wmmsg = wmmsg_next) {
   297                     wmmsg_next = wmmsg->next;
   298                     wmmsg->next = SDL_EventQ.wmmsg_free;
   299                     SDL_EventQ.wmmsg_free = wmmsg;
   300                 }
   301                 SDL_EventQ.wmmsg_used = NULL;
   302             }
   303 
   304             for (entry = SDL_EventQ.head; entry && (!events || used < numevents); entry = next) {
   305                 next = entry->next;
   306                 type = entry->event.type;
   307                 if (minType <= type && type <= maxType) {
   308                     if (events) {
   309                         events[used] = entry->event;
   310                         if (entry->event.type == SDL_SYSWMEVENT) {
   311                             /* We need to copy the wmmsg somewhere safe.
   312                                For now we'll guarantee it's valid at least until
   313                                the next call to SDL_PeepEvents()
   314                              */
   315                             if (SDL_EventQ.wmmsg_free) {
   316                                 wmmsg = SDL_EventQ.wmmsg_free;
   317                                 SDL_EventQ.wmmsg_free = wmmsg->next;
   318                             } else {
   319                                 wmmsg = (SDL_SysWMEntry *)SDL_malloc(sizeof(*wmmsg));
   320                             }
   321                             wmmsg->msg = *entry->event.syswm.msg;
   322                             wmmsg->next = SDL_EventQ.wmmsg_used;
   323                             SDL_EventQ.wmmsg_used = wmmsg;
   324                             events[used].syswm.msg = &wmmsg->msg;
   325                         }
   326 
   327                         if (action == SDL_GETEVENT) {
   328                             SDL_CutEvent(entry);
   329                         }
   330                     }
   331                     ++used;
   332                 }
   333             }
   334         }
   335         SDL_UnlockMutex(SDL_EventQ.lock);
   336     } else {
   337         return SDL_SetError("Couldn't lock event queue");
   338     }
   339     return (used);
   340 }
   341 
   342 SDL_bool
   343 SDL_HasEvent(Uint32 type)
   344 {
   345     return (SDL_PeepEvents(NULL, 0, SDL_PEEKEVENT, type, type) > 0);
   346 }
   347 
   348 SDL_bool
   349 SDL_HasEvents(Uint32 minType, Uint32 maxType)
   350 {
   351     return (SDL_PeepEvents(NULL, 0, SDL_PEEKEVENT, minType, maxType) > 0);
   352 }
   353 
   354 void
   355 SDL_FlushEvent(Uint32 type)
   356 {
   357     SDL_FlushEvents(type, type);
   358 }
   359 
   360 void
   361 SDL_FlushEvents(Uint32 minType, Uint32 maxType)
   362 {
   363     /* Don't look after we've quit */
   364     if (!SDL_AtomicGet(&SDL_EventQ.active)) {
   365         return;
   366     }
   367 
   368     /* Make sure the events are current */
   369 #if 0
   370     /* Actually, we can't do this since we might be flushing while processing
   371        a resize event, and calling this might trigger further resize events.
   372     */
   373     SDL_PumpEvents();
   374 #endif
   375 
   376     /* Lock the event queue */
   377     if (SDL_LockMutex(SDL_EventQ.lock) == 0) {
   378         SDL_EventEntry *entry, *next;
   379         Uint32 type;
   380         for (entry = SDL_EventQ.head; entry; entry = next) {
   381             next = entry->next;
   382             type = entry->event.type;
   383             if (minType <= type && type <= maxType) {
   384                 SDL_CutEvent(entry);
   385             }
   386         }
   387         SDL_UnlockMutex(SDL_EventQ.lock);
   388     }
   389 }
   390 
   391 /* Run the system dependent event loops */
   392 void
   393 SDL_PumpEvents(void)
   394 {
   395     SDL_VideoDevice *_this = SDL_GetVideoDevice();
   396 
   397     /* Get events from the video subsystem */
   398     if (_this) {
   399         _this->PumpEvents(_this);
   400     }
   401 #if !SDL_JOYSTICK_DISABLED
   402     /* Check for joystick state change */
   403     if ((!SDL_disabled_events[SDL_JOYAXISMOTION >> 8] || SDL_JoystickEventState(SDL_QUERY))) {
   404         SDL_JoystickUpdate();
   405     }
   406 #endif
   407 
   408     SDL_SendPendingQuit();  /* in case we had a signal handler fire, etc. */
   409 }
   410 
   411 /* Public functions */
   412 
   413 int
   414 SDL_PollEvent(SDL_Event * event)
   415 {
   416     return SDL_WaitEventTimeout(event, 0);
   417 }
   418 
   419 int
   420 SDL_WaitEvent(SDL_Event * event)
   421 {
   422     return SDL_WaitEventTimeout(event, -1);
   423 }
   424 
   425 int
   426 SDL_WaitEventTimeout(SDL_Event * event, int timeout)
   427 {
   428     Uint32 expiration = 0;
   429 
   430     if (timeout > 0)
   431         expiration = SDL_GetTicks() + timeout;
   432 
   433     for (;;) {
   434         SDL_PumpEvents();
   435         switch (SDL_PeepEvents(event, 1, SDL_GETEVENT, SDL_FIRSTEVENT, SDL_LASTEVENT)) {
   436         case -1:
   437             return 0;
   438         case 0:
   439             if (timeout == 0) {
   440                 /* Polling and no events, just return */
   441                 return 0;
   442             }
   443             if (timeout > 0 && SDL_TICKS_PASSED(SDL_GetTicks(), expiration)) {
   444                 /* Timeout expired and no events */
   445                 return 0;
   446             }
   447             SDL_Delay(10);
   448             break;
   449         default:
   450             /* Has events */
   451             return 1;
   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_EventQ.lock && 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 int
   652 SDL_SendKeymapChangedEvent(void)
   653 {
   654     return SDL_SendAppEvent(SDL_KEYMAPCHANGED);
   655 }
   656 
   657 /* vi: set ts=4 sw=4 expandtab: */