src/events/SDL_events.c
author Sam Lantinga
Fri, 08 Apr 2011 13:03:26 -0700
changeset 5535 96594ac5fd1a
parent 5293 7e9cdbbf7ba1
child 6091 61fa4f3238c5
permissions -rw-r--r--
SDL 1.3 is now under the zlib license.
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2011 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 #define MAXEVENTS	128
    57 static struct
    58 {
    59     SDL_mutex *lock;
    60     int active;
    61     int head;
    62     int tail;
    63     SDL_Event event[MAXEVENTS];
    64     int wmmsg_next;
    65     struct SDL_SysWMmsg wmmsg[MAXEVENTS];
    66 } SDL_EventQ;
    67 
    68 
    69 static __inline__ SDL_bool
    70 SDL_ShouldPollJoystick()
    71 {
    72 #if !SDL_JOYSTICK_DISABLED
    73     if (SDL_numjoysticks &&
    74         (!SDL_disabled_events[SDL_JOYAXISMOTION >> 8] ||
    75          SDL_JoystickEventState(SDL_QUERY))) {
    76         return SDL_TRUE;
    77     }
    78 #endif
    79     return SDL_FALSE;
    80 }
    81 
    82 /* Public functions */
    83 
    84 void
    85 SDL_StopEventLoop(void)
    86 {
    87     int i;
    88 
    89     if (SDL_EventQ.lock) {
    90         SDL_DestroyMutex(SDL_EventQ.lock);
    91         SDL_EventQ.lock = NULL;
    92     }
    93 
    94     /* Clean out EventQ */
    95     SDL_EventQ.head = 0;
    96     SDL_EventQ.tail = 0;
    97     SDL_EventQ.wmmsg_next = 0;
    98 
    99     /* Clear disabled event state */
   100     for (i = 0; i < SDL_arraysize(SDL_disabled_events); ++i) {
   101         if (SDL_disabled_events[i]) {
   102             SDL_free(SDL_disabled_events[i]);
   103             SDL_disabled_events[i] = NULL;
   104         }
   105     }
   106 
   107     while (SDL_event_watchers) {
   108         SDL_EventWatcher *tmp = SDL_event_watchers;
   109         SDL_event_watchers = tmp->next;
   110         SDL_free(tmp);
   111     }
   112 }
   113 
   114 /* This function (and associated calls) may be called more than once */
   115 int
   116 SDL_StartEventLoop(void)
   117 {
   118     /* Clean out the event queue */
   119     SDL_EventQ.lock = NULL;
   120     SDL_StopEventLoop();
   121 
   122     /* No filter to start with, process most event types */
   123     SDL_EventOK = NULL;
   124     SDL_EventState(SDL_SYSWMEVENT, SDL_DISABLE);
   125 
   126     /* Create the lock and set ourselves active */
   127 #if !SDL_THREADS_DISABLED
   128     SDL_EventQ.lock = SDL_CreateMutex();
   129     if (SDL_EventQ.lock == NULL) {
   130         return (-1);
   131     }
   132 #endif /* !SDL_THREADS_DISABLED */
   133     SDL_EventQ.active = 1;
   134 
   135     return (0);
   136 }
   137 
   138 
   139 /* Add an event to the event queue -- called with the queue locked */
   140 static int
   141 SDL_AddEvent(SDL_Event * event)
   142 {
   143     int tail, added;
   144 
   145     tail = (SDL_EventQ.tail + 1) % MAXEVENTS;
   146     if (tail == SDL_EventQ.head) {
   147         /* Overflow, drop event */
   148         added = 0;
   149     } else {
   150         SDL_EventQ.event[SDL_EventQ.tail] = *event;
   151         if (event->type == SDL_SYSWMEVENT) {
   152             /* Note that it's possible to lose an event */
   153             int next = SDL_EventQ.wmmsg_next;
   154             SDL_EventQ.wmmsg[next] = *event->syswm.msg;
   155             SDL_EventQ.event[SDL_EventQ.tail].syswm.msg =
   156                 &SDL_EventQ.wmmsg[next];
   157             SDL_EventQ.wmmsg_next = (next + 1) % MAXEVENTS;
   158         }
   159         SDL_EventQ.tail = tail;
   160         added = 1;
   161     }
   162     return (added);
   163 }
   164 
   165 /* Cut an event, and return the next valid spot, or the tail */
   166 /*                           -- called with the queue locked */
   167 static int
   168 SDL_CutEvent(int spot)
   169 {
   170     if (spot == SDL_EventQ.head) {
   171         SDL_EventQ.head = (SDL_EventQ.head + 1) % MAXEVENTS;
   172         return (SDL_EventQ.head);
   173     } else if ((spot + 1) % MAXEVENTS == SDL_EventQ.tail) {
   174         SDL_EventQ.tail = spot;
   175         return (SDL_EventQ.tail);
   176     } else
   177         /* We cut the middle -- shift everything over */
   178     {
   179         int here, next;
   180 
   181         /* This can probably be optimized with SDL_memcpy() -- careful! */
   182         if (--SDL_EventQ.tail < 0) {
   183             SDL_EventQ.tail = MAXEVENTS - 1;
   184         }
   185         for (here = spot; here != SDL_EventQ.tail; here = next) {
   186             next = (here + 1) % MAXEVENTS;
   187             SDL_EventQ.event[here] = SDL_EventQ.event[next];
   188         }
   189         return (spot);
   190     }
   191     /* NOTREACHED */
   192 }
   193 
   194 /* Lock the event queue, take a peep at it, and unlock it */
   195 int
   196 SDL_PeepEvents(SDL_Event * events, int numevents, SDL_eventaction action,
   197                Uint32 minType, Uint32 maxType)
   198 {
   199     int i, used;
   200 
   201     /* Don't look after we've quit */
   202     if (!SDL_EventQ.active) {
   203         return (-1);
   204     }
   205     /* Lock the event queue */
   206     used = 0;
   207     if (SDL_mutexP(SDL_EventQ.lock) == 0) {
   208         if (action == SDL_ADDEVENT) {
   209             for (i = 0; i < numevents; ++i) {
   210                 used += SDL_AddEvent(&events[i]);
   211             }
   212         } else {
   213             SDL_Event tmpevent;
   214             int spot;
   215 
   216             /* If 'events' is NULL, just see if they exist */
   217             if (events == NULL) {
   218                 action = SDL_PEEKEVENT;
   219                 numevents = 1;
   220                 events = &tmpevent;
   221             }
   222             spot = SDL_EventQ.head;
   223             while ((used < numevents) && (spot != SDL_EventQ.tail)) {
   224                 Uint32 type = SDL_EventQ.event[spot].type;
   225                 if (minType <= type && type <= maxType) {
   226                     events[used++] = SDL_EventQ.event[spot];
   227                     if (action == SDL_GETEVENT) {
   228                         spot = SDL_CutEvent(spot);
   229                     } else {
   230                         spot = (spot + 1) % MAXEVENTS;
   231                     }
   232                 } else {
   233                     spot = (spot + 1) % MAXEVENTS;
   234                 }
   235             }
   236         }
   237         SDL_mutexV(SDL_EventQ.lock);
   238     } else {
   239         SDL_SetError("Couldn't lock event queue");
   240         used = -1;
   241     }
   242     return (used);
   243 }
   244 
   245 SDL_bool
   246 SDL_HasEvent(Uint32 type)
   247 {
   248     return (SDL_PeepEvents(NULL, 0, SDL_PEEKEVENT, type, type) > 0);
   249 }
   250 
   251 SDL_bool
   252 SDL_HasEvents(Uint32 minType, Uint32 maxType)
   253 {
   254     return (SDL_PeepEvents(NULL, 0, SDL_PEEKEVENT, minType, maxType) > 0);
   255 }
   256 
   257 void
   258 SDL_FlushEvent(Uint32 type)
   259 {
   260     SDL_FlushEvents(type, type);
   261 }
   262 
   263 void
   264 SDL_FlushEvents(Uint32 minType, Uint32 maxType)
   265 {
   266     /* Don't look after we've quit */
   267     if (!SDL_EventQ.active) {
   268         return;
   269     }
   270 
   271     /* Make sure the events are current */
   272 #if 0
   273     /* Actually, we can't do this since we might be flushing while processing
   274        a resize event, and calling this might trigger further resize events.
   275     */
   276     SDL_PumpEvents();
   277 #endif
   278 
   279     /* Lock the event queue */
   280     if (SDL_mutexP(SDL_EventQ.lock) == 0) {
   281         int spot = SDL_EventQ.head;
   282         while (spot != SDL_EventQ.tail) {
   283             Uint32 type = SDL_EventQ.event[spot].type;
   284             if (minType <= type && type <= maxType) {
   285                 spot = SDL_CutEvent(spot);
   286             } else {
   287                 spot = (spot + 1) % MAXEVENTS;
   288             }
   289         }
   290         SDL_mutexV(SDL_EventQ.lock);
   291     }
   292 }
   293 
   294 /* Run the system dependent event loops */
   295 void
   296 SDL_PumpEvents(void)
   297 {
   298     SDL_VideoDevice *_this = SDL_GetVideoDevice();
   299 
   300     /* Get events from the video subsystem */
   301     if (_this) {
   302         _this->PumpEvents(_this);
   303     }
   304 #if !SDL_JOYSTICK_DISABLED
   305     /* Check for joystick state change */
   306     if (SDL_ShouldPollJoystick()) {
   307         SDL_JoystickUpdate();
   308     }
   309 #endif
   310 }
   311 
   312 /* Public functions */
   313 
   314 int
   315 SDL_PollEvent(SDL_Event * event)
   316 {
   317     return SDL_WaitEventTimeout(event, 0);
   318 }
   319 
   320 int
   321 SDL_WaitEvent(SDL_Event * event)
   322 {
   323     return SDL_WaitEventTimeout(event, -1);
   324 }
   325 
   326 int
   327 SDL_WaitEventTimeout(SDL_Event * event, int timeout)
   328 {
   329     Uint32 expiration = 0;
   330 
   331     if (timeout > 0)
   332         expiration = SDL_GetTicks() + timeout;
   333 
   334     for (;;) {
   335         SDL_PumpEvents();
   336         switch (SDL_PeepEvents(event, 1, SDL_GETEVENT, SDL_FIRSTEVENT, SDL_LASTEVENT)) {
   337         case -1:
   338             return 0;
   339         case 1:
   340             return 1;
   341         case 0:
   342             if (timeout == 0) {
   343                 /* Polling and no events, just return */
   344                 return 0;
   345             }
   346             if (timeout > 0 && ((int) (SDL_GetTicks() - expiration) >= 0)) {
   347                 /* Timeout expired and no events */
   348                 return 0;
   349             }
   350             SDL_Delay(10);
   351             break;
   352         }
   353     }
   354 }
   355 
   356 int
   357 SDL_PushEvent(SDL_Event * event)
   358 {
   359     SDL_EventWatcher *curr;
   360 
   361     if (SDL_EventOK && !SDL_EventOK(SDL_EventOKParam, event)) {
   362         return 0;
   363     }
   364 
   365     for (curr = SDL_event_watchers; curr; curr = curr->next) {
   366         curr->callback(curr->userdata, event);
   367     }
   368 
   369     if (SDL_PeepEvents(event, 1, SDL_ADDEVENT, 0, 0) <= 0) {
   370         return -1;
   371     }
   372 
   373     SDL_GestureProcessEvent(event);
   374     
   375 
   376     return 1;
   377 }
   378 
   379 void
   380 SDL_SetEventFilter(SDL_EventFilter filter, void *userdata)
   381 {
   382     SDL_Event bitbucket;
   383 
   384     /* Set filter and discard pending events */
   385     SDL_EventOK = filter;
   386     SDL_EventOKParam = userdata;
   387     while (SDL_PollEvent(&bitbucket) > 0);
   388 }
   389 
   390 SDL_bool
   391 SDL_GetEventFilter(SDL_EventFilter * filter, void **userdata)
   392 {
   393     if (filter) {
   394         *filter = SDL_EventOK;
   395     }
   396     if (userdata) {
   397         *userdata = SDL_EventOKParam;
   398     }
   399     return SDL_EventOK ? SDL_TRUE : SDL_FALSE;
   400 }
   401 
   402 /* FIXME: This is not thread-safe yet */
   403 void
   404 SDL_AddEventWatch(SDL_EventFilter filter, void *userdata)
   405 {
   406     SDL_EventWatcher *watcher;
   407 
   408     watcher = (SDL_EventWatcher *)SDL_malloc(sizeof(*watcher));
   409     if (!watcher) {
   410         /* Uh oh... */
   411         return;
   412     }
   413     watcher->callback = filter;
   414     watcher->userdata = userdata;
   415     watcher->next = SDL_event_watchers;
   416     SDL_event_watchers = watcher;
   417 }
   418 
   419 /* FIXME: This is not thread-safe yet */
   420 void
   421 SDL_DelEventWatch(SDL_EventFilter filter, void *userdata)
   422 {
   423     SDL_EventWatcher *prev = NULL;
   424     SDL_EventWatcher *curr;
   425 
   426     for (curr = SDL_event_watchers; curr; prev = curr, curr = curr->next) {
   427         if (curr->callback == filter && curr->userdata == userdata) {
   428             if (prev) {
   429                 prev->next = curr->next;
   430             } else {
   431                 SDL_event_watchers = curr->next;
   432             }
   433             SDL_free(curr);
   434             break;
   435         }
   436     }
   437 }
   438 
   439 void
   440 SDL_FilterEvents(SDL_EventFilter filter, void *userdata)
   441 {
   442     if (SDL_mutexP(SDL_EventQ.lock) == 0) {
   443         int spot;
   444 
   445         spot = SDL_EventQ.head;
   446         while (spot != SDL_EventQ.tail) {
   447             if (filter(userdata, &SDL_EventQ.event[spot])) {
   448                 spot = (spot + 1) % MAXEVENTS;
   449             } else {
   450                 spot = SDL_CutEvent(spot);
   451             }
   452         }
   453     }
   454     SDL_mutexV(SDL_EventQ.lock);
   455 }
   456 
   457 Uint8
   458 SDL_EventState(Uint32 type, int state)
   459 {
   460     Uint8 current_state;
   461     Uint8 hi = ((type >> 8) & 0xff);
   462     Uint8 lo = (type & 0xff);
   463 
   464     if (SDL_disabled_events[hi] &&
   465         (SDL_disabled_events[hi]->bits[lo/32] & (1 << (lo&31)))) {
   466         current_state = SDL_DISABLE;
   467     } else {
   468         current_state = SDL_ENABLE;
   469     }
   470 
   471     if (state != current_state)
   472     {
   473         switch (state) {
   474         case SDL_DISABLE:
   475             /* Disable this event type and discard pending events */
   476             if (!SDL_disabled_events[hi]) {
   477                 SDL_disabled_events[hi] = (SDL_DisabledEventBlock*) SDL_calloc(1, sizeof(SDL_DisabledEventBlock));
   478                 if (!SDL_disabled_events[hi]) {
   479                     /* Out of memory, nothing we can do... */
   480                     break;
   481                 }
   482             }
   483             SDL_disabled_events[hi]->bits[lo/32] |= (1 << (lo&31));
   484             SDL_FlushEvent(type);
   485             break;
   486         case SDL_ENABLE:
   487             SDL_disabled_events[hi]->bits[lo/32] &= ~(1 << (lo&31));
   488             break;
   489         default:
   490             /* Querying state... */
   491             break;
   492         }
   493     }
   494 
   495     return current_state;
   496 }
   497 
   498 Uint32
   499 SDL_RegisterEvents(int numevents)
   500 {
   501     Uint32 event_base;
   502 
   503     if (SDL_userevents+numevents <= SDL_LASTEVENT) {
   504         event_base = SDL_userevents;
   505         SDL_userevents += numevents;
   506     } else {
   507         event_base = (Uint32)-1;
   508     }
   509     return event_base;
   510 }
   511 
   512 /* This is a generic event handler.
   513  */
   514 int
   515 SDL_SendSysWMEvent(SDL_SysWMmsg * message)
   516 {
   517     int posted;
   518 
   519     posted = 0;
   520     if (SDL_GetEventState(SDL_SYSWMEVENT) == SDL_ENABLE) {
   521         SDL_Event event;
   522         SDL_memset(&event, 0, sizeof(event));
   523         event.type = SDL_SYSWMEVENT;
   524         event.syswm.msg = message;
   525         posted = (SDL_PushEvent(&event) > 0);
   526     }
   527     /* Update internal event state */
   528     return (posted);
   529 }
   530 
   531 /* vi: set ts=4 sw=4 expandtab: */