src/events/SDL_events.c
author Sam Lantinga
Fri, 11 Feb 2011 22:37:15 -0800
changeset 5262 b530ef003506
parent 5154 fb424691cfc7
child 5293 7e9cdbbf7ba1
permissions -rw-r--r--
Happy 2011! :)
     1 /*
     2     SDL - Simple DirectMedia Layer
     3     Copyright (C) 1997-2011 Sam Lantinga
     4 
     5     This library is free software; you can redistribute it and/or
     6     modify it under the terms of the GNU Lesser General Public
     7     License as published by the Free Software Foundation; either
     8     version 2.1 of the License, or (at your option) any later version.
     9 
    10     This library is distributed in the hope that it will be useful,
    11     but WITHOUT ANY WARRANTY; without even the implied warranty of
    12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    13     Lesser General Public License for more details.
    14 
    15     You should have received a copy of the GNU Lesser General Public
    16     License along with this library; if not, write to the Free Software
    17     Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
    18 
    19     Sam Lantinga
    20     slouken@libsdl.org
    21 */
    22 #include "SDL_config.h"
    23 
    24 /* General event handling code for SDL */
    25 
    26 #include "SDL.h"
    27 #include "SDL_events.h"
    28 #include "SDL_syswm.h"
    29 #include "SDL_thread.h"
    30 #include "SDL_events_c.h"
    31 #include "../timer/SDL_timer_c.h"
    32 #if !SDL_JOYSTICK_DISABLED
    33 #include "../joystick/SDL_joystick_c.h"
    34 #endif
    35 #include "../video/SDL_sysvideo.h"
    36 
    37 /* Public data -- the event filter */
    38 SDL_EventFilter SDL_EventOK = NULL;
    39 void *SDL_EventOKParam;
    40 
    41 typedef struct SDL_EventWatcher {
    42     SDL_EventFilter callback;
    43     void *userdata;
    44     struct SDL_EventWatcher *next;
    45 } SDL_EventWatcher;
    46 
    47 static SDL_EventWatcher *SDL_event_watchers = NULL;
    48 
    49 typedef struct {
    50     Uint32 bits[8];
    51 } SDL_DisabledEventBlock;
    52 
    53 static SDL_DisabledEventBlock *SDL_disabled_events[256];
    54 static Uint32 SDL_userevents = SDL_USEREVENT;
    55 
    56 /* Private data -- event queue */
    57 #define MAXEVENTS	128
    58 static struct
    59 {
    60     SDL_mutex *lock;
    61     int active;
    62     int head;
    63     int tail;
    64     SDL_Event event[MAXEVENTS];
    65     int wmmsg_next;
    66     struct SDL_SysWMmsg wmmsg[MAXEVENTS];
    67 } SDL_EventQ;
    68 
    69 
    70 static __inline__ SDL_bool
    71 SDL_ShouldPollJoystick()
    72 {
    73 #if !SDL_JOYSTICK_DISABLED
    74     if (SDL_numjoysticks &&
    75         (!SDL_disabled_events[SDL_JOYAXISMOTION >> 8] ||
    76          SDL_JoystickEventState(SDL_QUERY))) {
    77         return SDL_TRUE;
    78     }
    79 #endif
    80     return SDL_FALSE;
    81 }
    82 
    83 /* Public functions */
    84 
    85 void
    86 SDL_StopEventLoop(void)
    87 {
    88     int i;
    89 
    90     if (SDL_EventQ.lock) {
    91         SDL_DestroyMutex(SDL_EventQ.lock);
    92         SDL_EventQ.lock = NULL;
    93     }
    94 
    95     /* Clean out EventQ */
    96     SDL_EventQ.head = 0;
    97     SDL_EventQ.tail = 0;
    98     SDL_EventQ.wmmsg_next = 0;
    99 
   100     /* Clear disabled event state */
   101     for (i = 0; i < SDL_arraysize(SDL_disabled_events); ++i) {
   102         if (SDL_disabled_events[i]) {
   103             SDL_free(SDL_disabled_events[i]);
   104             SDL_disabled_events[i] = NULL;
   105         }
   106     }
   107 
   108     while (SDL_event_watchers) {
   109         SDL_EventWatcher *tmp = SDL_event_watchers;
   110         SDL_event_watchers = tmp->next;
   111         SDL_free(tmp);
   112     }
   113 }
   114 
   115 /* This function (and associated calls) may be called more than once */
   116 int
   117 SDL_StartEventLoop(void)
   118 {
   119     /* Clean out the event queue */
   120     SDL_EventQ.lock = NULL;
   121     SDL_StopEventLoop();
   122 
   123     /* No filter to start with, process most event types */
   124     SDL_EventOK = NULL;
   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     SDL_PumpEvents();
   274 
   275     /* Lock the event queue */
   276     if (SDL_mutexP(SDL_EventQ.lock) == 0) {
   277         int spot = SDL_EventQ.head;
   278         while (spot != SDL_EventQ.tail) {
   279             Uint32 type = SDL_EventQ.event[spot].type;
   280             if (minType <= type && type <= maxType) {
   281                 spot = SDL_CutEvent(spot);
   282             } else {
   283                 spot = (spot + 1) % MAXEVENTS;
   284             }
   285         }
   286         SDL_mutexV(SDL_EventQ.lock);
   287     }
   288 }
   289 
   290 /* Run the system dependent event loops */
   291 void
   292 SDL_PumpEvents(void)
   293 {
   294     SDL_VideoDevice *_this = SDL_GetVideoDevice();
   295 
   296     /* Get events from the video subsystem */
   297     if (_this) {
   298         _this->PumpEvents(_this);
   299     }
   300 #if !SDL_JOYSTICK_DISABLED
   301     /* Check for joystick state change */
   302     if (SDL_ShouldPollJoystick()) {
   303         SDL_JoystickUpdate();
   304     }
   305 #endif
   306 }
   307 
   308 /* Public functions */
   309 
   310 int
   311 SDL_PollEvent(SDL_Event * event)
   312 {
   313     return SDL_WaitEventTimeout(event, 0);
   314 }
   315 
   316 int
   317 SDL_WaitEvent(SDL_Event * event)
   318 {
   319     return SDL_WaitEventTimeout(event, -1);
   320 }
   321 
   322 int
   323 SDL_WaitEventTimeout(SDL_Event * event, int timeout)
   324 {
   325     Uint32 expiration = 0;
   326 
   327     if (timeout > 0)
   328         expiration = SDL_GetTicks() + timeout;
   329 
   330     for (;;) {
   331         SDL_PumpEvents();
   332         switch (SDL_PeepEvents(event, 1, SDL_GETEVENT, SDL_FIRSTEVENT, SDL_LASTEVENT)) {
   333         case -1:
   334             return 0;
   335         case 1:
   336             return 1;
   337         case 0:
   338             if (timeout == 0) {
   339                 /* Polling and no events, just return */
   340                 return 0;
   341             }
   342             if (timeout > 0 && ((int) (SDL_GetTicks() - expiration) >= 0)) {
   343                 /* Timeout expired and no events */
   344                 return 0;
   345             }
   346             SDL_Delay(10);
   347             break;
   348         }
   349     }
   350 }
   351 
   352 int
   353 SDL_PushEvent(SDL_Event * event)
   354 {
   355     SDL_EventWatcher *curr;
   356 
   357     if (SDL_EventOK && !SDL_EventOK(SDL_EventOKParam, event)) {
   358         return 0;
   359     }
   360 
   361     for (curr = SDL_event_watchers; curr; curr = curr->next) {
   362         curr->callback(curr->userdata, event);
   363     }
   364 
   365     if (SDL_PeepEvents(event, 1, SDL_ADDEVENT, 0, 0) <= 0) {
   366         return -1;
   367     }
   368 
   369     SDL_GestureProcessEvent(event);
   370     
   371 
   372     return 1;
   373 }
   374 
   375 void
   376 SDL_SetEventFilter(SDL_EventFilter filter, void *userdata)
   377 {
   378     SDL_Event bitbucket;
   379 
   380     /* Set filter and discard pending events */
   381     SDL_EventOK = filter;
   382     SDL_EventOKParam = userdata;
   383     while (SDL_PollEvent(&bitbucket) > 0);
   384 }
   385 
   386 SDL_bool
   387 SDL_GetEventFilter(SDL_EventFilter * filter, void **userdata)
   388 {
   389     if (filter) {
   390         *filter = SDL_EventOK;
   391     }
   392     if (userdata) {
   393         *userdata = SDL_EventOKParam;
   394     }
   395     return SDL_EventOK ? SDL_TRUE : SDL_FALSE;
   396 }
   397 
   398 /* FIXME: This is not thread-safe yet */
   399 void
   400 SDL_AddEventWatch(SDL_EventFilter filter, void *userdata)
   401 {
   402     SDL_EventWatcher *watcher;
   403 
   404     watcher = (SDL_EventWatcher *)SDL_malloc(sizeof(*watcher));
   405     if (!watcher) {
   406         /* Uh oh... */
   407         return;
   408     }
   409     watcher->callback = filter;
   410     watcher->userdata = userdata;
   411     watcher->next = SDL_event_watchers;
   412     SDL_event_watchers = watcher;
   413 }
   414 
   415 /* FIXME: This is not thread-safe yet */
   416 void
   417 SDL_DelEventWatch(SDL_EventFilter filter, void *userdata)
   418 {
   419     SDL_EventWatcher *prev = NULL;
   420     SDL_EventWatcher *curr;
   421 
   422     for (curr = SDL_event_watchers; curr; prev = curr, curr = curr->next) {
   423         if (curr->callback == filter && curr->userdata == userdata) {
   424             if (prev) {
   425                 prev->next = curr->next;
   426             } else {
   427                 SDL_event_watchers = curr->next;
   428             }
   429             SDL_free(curr);
   430             break;
   431         }
   432     }
   433 }
   434 
   435 void
   436 SDL_FilterEvents(SDL_EventFilter filter, void *userdata)
   437 {
   438     if (SDL_mutexP(SDL_EventQ.lock) == 0) {
   439         int spot;
   440 
   441         spot = SDL_EventQ.head;
   442         while (spot != SDL_EventQ.tail) {
   443             if (filter(userdata, &SDL_EventQ.event[spot])) {
   444                 spot = (spot + 1) % MAXEVENTS;
   445             } else {
   446                 spot = SDL_CutEvent(spot);
   447             }
   448         }
   449     }
   450     SDL_mutexV(SDL_EventQ.lock);
   451 }
   452 
   453 Uint8
   454 SDL_EventState(Uint32 type, int state)
   455 {
   456     Uint8 current_state;
   457     Uint8 hi = ((type >> 8) & 0xff);
   458     Uint8 lo = (type & 0xff);
   459 
   460     if (SDL_disabled_events[hi] &&
   461         (SDL_disabled_events[hi]->bits[lo/32] & (1 << (lo&31)))) {
   462         current_state = SDL_DISABLE;
   463     } else {
   464         current_state = SDL_ENABLE;
   465     }
   466 
   467     if (state != current_state)
   468     {
   469         switch (state) {
   470         case SDL_DISABLE:
   471             /* Disable this event type and discard pending events */
   472             if (!SDL_disabled_events[hi]) {
   473                 SDL_disabled_events[hi] = (SDL_DisabledEventBlock*) SDL_calloc(1, sizeof(SDL_DisabledEventBlock));
   474                 if (!SDL_disabled_events[hi]) {
   475                     /* Out of memory, nothing we can do... */
   476                     break;
   477                 }
   478             }
   479             SDL_disabled_events[hi]->bits[lo/32] |= (1 << (lo&31));
   480             SDL_FlushEvent(type);
   481             break;
   482         case SDL_ENABLE:
   483             SDL_disabled_events[hi]->bits[lo/32] &= ~(1 << (lo&31));
   484             break;
   485         default:
   486             /* Querying state... */
   487             break;
   488         }
   489     }
   490 
   491     return current_state;
   492 }
   493 
   494 Uint32
   495 SDL_RegisterEvents(int numevents)
   496 {
   497     Uint32 event_base;
   498 
   499     if (SDL_userevents+numevents <= SDL_LASTEVENT) {
   500         event_base = SDL_userevents;
   501         SDL_userevents += numevents;
   502     } else {
   503         event_base = (Uint32)-1;
   504     }
   505     return event_base;
   506 }
   507 
   508 /* This is a generic event handler.
   509  */
   510 int
   511 SDL_SendSysWMEvent(SDL_SysWMmsg * message)
   512 {
   513     int posted;
   514 
   515     posted = 0;
   516     if (SDL_GetEventState(SDL_SYSWMEVENT) == SDL_ENABLE) {
   517         SDL_Event event;
   518         SDL_memset(&event, 0, sizeof(event));
   519         event.type = SDL_SYSWMEVENT;
   520         event.syswm.msg = message;
   521         posted = (SDL_PushEvent(&event) > 0);
   522     }
   523     /* Update internal event state */
   524     return (posted);
   525 }
   526 
   527 /* vi: set ts=4 sw=4 expandtab: */