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