src/events/SDL_events.c
author Jim Grandpre
Wed, 07 Jul 2010 04:13:08 -0700
changeset 4657 eed063a0bf5b
parent 4642 057e8762d2a1
child 4729 1f7ad083fd3c
permissions -rw-r--r--
Moved Multi finger gesture recognition into the library.
     1 /*
     2     SDL - Simple DirectMedia Layer
     3     Copyright (C) 1997-2010 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_sysevents.h"
    31 #include "SDL_events_c.h"
    32 #include "../timer/SDL_timer_c.h"
    33 #if !SDL_JOYSTICK_DISABLED
    34 #include "../joystick/SDL_joystick_c.h"
    35 #endif
    36 
    37 /* Public data -- the event filter */
    38 SDL_EventFilter SDL_EventOK = NULL;
    39 void *SDL_EventOKParam;
    40 
    41 typedef struct {
    42     Uint32 bits[8];
    43 } SDL_DisabledEventBlock;
    44 
    45 static SDL_DisabledEventBlock *SDL_disabled_events[256];
    46 static Uint32 SDL_userevents = SDL_USEREVENT;
    47 
    48 /* Private data -- event queue */
    49 #define MAXEVENTS	128
    50 static struct
    51 {
    52     SDL_mutex *lock;
    53     int active;
    54     int head;
    55     int tail;
    56     SDL_Event event[MAXEVENTS];
    57     int wmmsg_next;
    58     struct SDL_SysWMmsg wmmsg[MAXEVENTS];
    59 } SDL_EventQ;
    60 
    61 /* Private data -- event locking structure */
    62 static struct
    63 {
    64     SDL_mutex *lock;
    65     int safe;
    66 } SDL_EventLock;
    67 
    68 /* Thread functions */
    69 static SDL_Thread *SDL_EventThread = NULL;      /* Thread handle */
    70 static SDL_threadID event_thread;     /* The event thread id */
    71 
    72 void
    73 SDL_Lock_EventThread(void)
    74 {
    75     if (SDL_EventThread && (SDL_ThreadID() != event_thread)) {
    76         /* Grab lock and spin until we're sure event thread stopped */
    77         SDL_mutexP(SDL_EventLock.lock);
    78         while (!SDL_EventLock.safe) {
    79             SDL_Delay(1);
    80         }
    81     }
    82 }
    83 
    84 void
    85 SDL_Unlock_EventThread(void)
    86 {
    87     if (SDL_EventThread && (SDL_ThreadID() != event_thread)) {
    88         SDL_mutexV(SDL_EventLock.lock);
    89     }
    90 }
    91 
    92 static __inline__ SDL_bool
    93 SDL_ShouldPollJoystick()
    94 {
    95     if (SDL_numjoysticks &&
    96         (!SDL_disabled_events[SDL_JOYAXISMOTION >> 8] ||
    97          SDL_JoystickEventState(SDL_QUERY))) {
    98         return SDL_TRUE;
    99     }
   100     return SDL_FALSE;
   101 }
   102 
   103 static int SDLCALL
   104 SDL_GobbleEvents(void *unused)
   105 {
   106     event_thread = SDL_ThreadID();
   107 
   108     while (SDL_EventQ.active) {
   109         SDL_VideoDevice *_this = SDL_GetVideoDevice();
   110 
   111         /* Get events from the video subsystem */
   112         if (_this) {
   113             _this->PumpEvents(_this);
   114         }
   115 #if !SDL_JOYSTICK_DISABLED
   116         /* Check for joystick state change */
   117         if (SDL_ShouldPollJoystick()) {
   118             SDL_JoystickUpdate();
   119         }
   120 #endif
   121 
   122         /* Give up the CPU for the rest of our timeslice */
   123         SDL_EventLock.safe = 1;
   124         if (SDL_timer_running) {
   125             SDL_ThreadedTimerCheck();
   126         }
   127         SDL_Delay(1);
   128 
   129         /* Check for event locking.
   130            On the P of the lock mutex, if the lock is held, this thread
   131            will wait until the lock is released before continuing.  The
   132            safe flag will be set, meaning that the other thread can go
   133            about it's business.  The safe flag is reset before the V,
   134            so as soon as the mutex is free, other threads can see that
   135            it's not safe to interfere with the event thread.
   136          */
   137         SDL_mutexP(SDL_EventLock.lock);
   138         SDL_EventLock.safe = 0;
   139         SDL_mutexV(SDL_EventLock.lock);
   140     }
   141     SDL_SetTimerThreaded(0);
   142     event_thread = 0;
   143     return (0);
   144 }
   145 
   146 static int
   147 SDL_StartEventThread(Uint32 flags)
   148 {
   149     /* Reset everything to zero */
   150     SDL_EventThread = NULL;
   151     SDL_memset(&SDL_EventLock, 0, sizeof(SDL_EventLock));
   152 
   153     /* Create the lock and set ourselves active */
   154 #if !SDL_THREADS_DISABLED
   155     SDL_EventQ.lock = SDL_CreateMutex();
   156     if (SDL_EventQ.lock == NULL) {
   157         return (-1);
   158     }
   159 #endif /* !SDL_THREADS_DISABLED */
   160     SDL_EventQ.active = 1;
   161 
   162     if ((flags & SDL_INIT_EVENTTHREAD) == SDL_INIT_EVENTTHREAD) {
   163         SDL_EventLock.lock = SDL_CreateMutex();
   164         if (SDL_EventLock.lock == NULL) {
   165             return (-1);
   166         }
   167         SDL_EventLock.safe = 0;
   168 
   169         /* The event thread will handle timers too */
   170         SDL_SetTimerThreaded(2);
   171 #if (defined(__WIN32__) && !defined(_WIN32_WCE)) && !defined(HAVE_LIBC)
   172 #undef SDL_CreateThread
   173         SDL_EventThread =
   174             SDL_CreateThread(SDL_GobbleEvents, NULL, NULL, NULL);
   175 #else
   176         SDL_EventThread = SDL_CreateThread(SDL_GobbleEvents, NULL);
   177 #endif
   178         if (SDL_EventThread == NULL) {
   179             return (-1);
   180         }
   181     } else {
   182         event_thread = 0;
   183     }
   184     return (0);
   185 }
   186 
   187 static void
   188 SDL_StopEventThread(void)
   189 {
   190     SDL_EventQ.active = 0;
   191     if (SDL_EventThread) {
   192         SDL_WaitThread(SDL_EventThread, NULL);
   193         SDL_EventThread = NULL;
   194         SDL_DestroyMutex(SDL_EventLock.lock);
   195         SDL_EventLock.lock = NULL;
   196     }
   197     if (SDL_EventQ.lock) {
   198         SDL_DestroyMutex(SDL_EventQ.lock);
   199         SDL_EventQ.lock = NULL;
   200     }
   201 }
   202 
   203 SDL_threadID
   204 SDL_EventThreadID(void)
   205 {
   206     return (event_thread);
   207 }
   208 
   209 /* Public functions */
   210 
   211 void
   212 SDL_StopEventLoop(void)
   213 {
   214     int i;
   215 
   216     /* Halt the event thread, if running */
   217     SDL_StopEventThread();
   218 
   219     /* Shutdown event handlers */
   220     SDL_KeyboardQuit();
   221     SDL_MouseQuit();
   222     SDL_QuitQuit();
   223 
   224     /* Clean out EventQ */
   225     SDL_EventQ.head = 0;
   226     SDL_EventQ.tail = 0;
   227     SDL_EventQ.wmmsg_next = 0;
   228 
   229     /* Clear disabled event state */
   230     for (i = 0; i < SDL_arraysize(SDL_disabled_events); ++i) {
   231         if (SDL_disabled_events[i]) {
   232             SDL_free(SDL_disabled_events[i]);
   233             SDL_disabled_events[i] = NULL;
   234         }
   235     }
   236 }
   237 
   238 /* This function (and associated calls) may be called more than once */
   239 int
   240 SDL_StartEventLoop(Uint32 flags)
   241 {
   242     int retcode;
   243 
   244     /* Clean out the event queue */
   245     SDL_EventThread = NULL;
   246     SDL_EventQ.lock = NULL;
   247     SDL_StopEventLoop();
   248 
   249     /* No filter to start with, process most event types */
   250     SDL_EventOK = NULL;
   251     SDL_EventState(SDL_SYSWMEVENT, SDL_DISABLE);
   252 
   253     /* Initialize event handlers */
   254     retcode = 0;
   255     retcode += SDL_KeyboardInit();
   256     retcode += SDL_MouseInit();
   257     retcode += SDL_TouchInit();
   258     retcode += SDL_QuitInit();
   259     if (retcode < 0) {
   260         /* We don't expect them to fail, but... */
   261         return (-1);
   262     }
   263 
   264     /* Create the lock and event thread */
   265     if (SDL_StartEventThread(flags) < 0) {
   266         SDL_StopEventLoop();
   267         return (-1);
   268     }
   269     return (0);
   270 }
   271 
   272 
   273 /* Add an event to the event queue -- called with the queue locked */
   274 static int
   275 SDL_AddEvent(SDL_Event * event)
   276 {
   277     int tail, added;
   278 
   279     tail = (SDL_EventQ.tail + 1) % MAXEVENTS;
   280     if (tail == SDL_EventQ.head) {
   281         /* Overflow, drop event */
   282         added = 0;
   283     } else {
   284         SDL_EventQ.event[SDL_EventQ.tail] = *event;
   285         if (event->type == SDL_SYSWMEVENT) {
   286             /* Note that it's possible to lose an event */
   287             int next = SDL_EventQ.wmmsg_next;
   288             SDL_EventQ.wmmsg[next] = *event->syswm.msg;
   289             SDL_EventQ.event[SDL_EventQ.tail].syswm.msg =
   290                 &SDL_EventQ.wmmsg[next];
   291             SDL_EventQ.wmmsg_next = (next + 1) % MAXEVENTS;
   292         }
   293         SDL_EventQ.tail = tail;
   294         added = 1;
   295     }
   296     return (added);
   297 }
   298 
   299 /* Cut an event, and return the next valid spot, or the tail */
   300 /*                           -- called with the queue locked */
   301 static int
   302 SDL_CutEvent(int spot)
   303 {
   304     if (spot == SDL_EventQ.head) {
   305         SDL_EventQ.head = (SDL_EventQ.head + 1) % MAXEVENTS;
   306         return (SDL_EventQ.head);
   307     } else if ((spot + 1) % MAXEVENTS == SDL_EventQ.tail) {
   308         SDL_EventQ.tail = spot;
   309         return (SDL_EventQ.tail);
   310     } else
   311         /* We cut the middle -- shift everything over */
   312     {
   313         int here, next;
   314 
   315         /* This can probably be optimized with SDL_memcpy() -- careful! */
   316         if (--SDL_EventQ.tail < 0) {
   317             SDL_EventQ.tail = MAXEVENTS - 1;
   318         }
   319         for (here = spot; here != SDL_EventQ.tail; here = next) {
   320             next = (here + 1) % MAXEVENTS;
   321             SDL_EventQ.event[here] = SDL_EventQ.event[next];
   322         }
   323         return (spot);
   324     }
   325     /* NOTREACHED */
   326 }
   327 
   328 /* Lock the event queue, take a peep at it, and unlock it */
   329 int
   330 SDL_PeepEvents(SDL_Event * events, int numevents, SDL_eventaction action,
   331                Uint32 minType, Uint32 maxType)
   332 {
   333     int i, used;
   334 
   335     /* Don't look after we've quit */
   336     if (!SDL_EventQ.active) {
   337         return (-1);
   338     }
   339     /* Lock the event queue */
   340     used = 0;
   341     if (SDL_mutexP(SDL_EventQ.lock) == 0) {
   342         if (action == SDL_ADDEVENT) {
   343             for (i = 0; i < numevents; ++i) {
   344                 used += SDL_AddEvent(&events[i]);
   345             }
   346         } else {
   347             SDL_Event tmpevent;
   348             int spot;
   349 
   350             /* If 'events' is NULL, just see if they exist */
   351             if (events == NULL) {
   352                 action = SDL_PEEKEVENT;
   353                 numevents = 1;
   354                 events = &tmpevent;
   355             }
   356             spot = SDL_EventQ.head;
   357             while ((used < numevents) && (spot != SDL_EventQ.tail)) {
   358                 Uint32 type = SDL_EventQ.event[spot].type;
   359                 if (minType <= type && type <= maxType) {
   360                     events[used++] = SDL_EventQ.event[spot];
   361                     if (action == SDL_GETEVENT) {
   362                         spot = SDL_CutEvent(spot);
   363                     } else {
   364                         spot = (spot + 1) % MAXEVENTS;
   365                     }
   366                 } else {
   367                     spot = (spot + 1) % MAXEVENTS;
   368                 }
   369             }
   370         }
   371         SDL_mutexV(SDL_EventQ.lock);
   372     } else {
   373         SDL_SetError("Couldn't lock event queue");
   374         used = -1;
   375     }
   376     return (used);
   377 }
   378 
   379 SDL_bool
   380 SDL_HasEvent(Uint32 type)
   381 {
   382     return (SDL_PeepEvents(NULL, 0, SDL_PEEKEVENT, type, type) > 0);
   383 }
   384 
   385 SDL_bool
   386 SDL_HasEvents(Uint32 minType, Uint32 maxType)
   387 {
   388     return (SDL_PeepEvents(NULL, 0, SDL_PEEKEVENT, minType, maxType) > 0);
   389 }
   390 
   391 void
   392 SDL_FlushEvent(Uint32 type)
   393 {
   394     SDL_FlushEvents(type, type);
   395 }
   396 
   397 void
   398 SDL_FlushEvents(Uint32 minType, Uint32 maxType)
   399 {
   400     /* Don't look after we've quit */
   401     if (!SDL_EventQ.active) {
   402         return;
   403     }
   404 
   405     /* Make sure the events are current */
   406     SDL_PumpEvents();
   407 
   408     /* Lock the event queue */
   409     if (SDL_mutexP(SDL_EventQ.lock) == 0) {
   410         int spot = SDL_EventQ.head;
   411         while (spot != SDL_EventQ.tail) {
   412             Uint32 type = SDL_EventQ.event[spot].type;
   413             if (minType <= type && type <= maxType) {
   414                 spot = SDL_CutEvent(spot);
   415             } else {
   416                 spot = (spot + 1) % MAXEVENTS;
   417             }
   418         }
   419         SDL_mutexV(SDL_EventQ.lock);
   420     }
   421 }
   422 
   423 /* Run the system dependent event loops */
   424 void
   425 SDL_PumpEvents(void)
   426 {
   427     if (!SDL_EventThread) {
   428         SDL_VideoDevice *_this = SDL_GetVideoDevice();
   429 
   430         /* Get events from the video subsystem */
   431         if (_this) {
   432             _this->PumpEvents(_this);
   433         }
   434 #if !SDL_JOYSTICK_DISABLED
   435         /* Check for joystick state change */
   436         if (SDL_ShouldPollJoystick()) {
   437             SDL_JoystickUpdate();
   438         }
   439 #endif
   440     }
   441 }
   442 
   443 /* Public functions */
   444 
   445 int
   446 SDL_PollEvent(SDL_Event * event)
   447 {
   448     return SDL_WaitEventTimeout(event, 0);
   449 }
   450 
   451 int
   452 SDL_WaitEvent(SDL_Event * event)
   453 {
   454     return SDL_WaitEventTimeout(event, -1);
   455 }
   456 
   457 int
   458 SDL_WaitEventTimeout(SDL_Event * event, int timeout)
   459 {
   460     Uint32 expiration = 0;
   461 
   462     if (timeout > 0)
   463         expiration = SDL_GetTicks() + timeout;
   464 
   465     for (;;) {
   466         SDL_PumpEvents();
   467         switch (SDL_PeepEvents(event, 1, SDL_GETEVENT, SDL_FIRSTEVENT, SDL_LASTEVENT)) {
   468         case -1:
   469             return 0;
   470         case 1:
   471             return 1;
   472         case 0:
   473             if (timeout == 0) {
   474                 /* Polling and no events, just return */
   475                 return 0;
   476             }
   477             if (timeout > 0 && ((int) (SDL_GetTicks() - expiration) >= 0)) {
   478                 /* Timeout expired and no events */
   479                 return 0;
   480             }
   481             SDL_Delay(10);
   482             break;
   483         }
   484     }
   485 }
   486 
   487 int
   488 SDL_PushEvent(SDL_Event * event)
   489 {
   490     if (SDL_EventOK && !SDL_EventOK(SDL_EventOKParam, event)) {
   491         return 0;
   492     }
   493     if (SDL_PeepEvents(event, 1, SDL_ADDEVENT, 0, 0) <= 0) {
   494         return -1;
   495     }
   496 
   497     SDL_GestureProcessEvent(event);
   498     
   499 
   500     return 1;
   501 }
   502 
   503 void
   504 SDL_SetEventFilter(SDL_EventFilter filter, void *userdata)
   505 {
   506     SDL_Event bitbucket;
   507 
   508     /* Set filter and discard pending events */
   509     SDL_EventOK = filter;
   510     SDL_EventOKParam = userdata;
   511     while (SDL_PollEvent(&bitbucket) > 0);
   512 }
   513 
   514 SDL_bool
   515 SDL_GetEventFilter(SDL_EventFilter * filter, void **userdata)
   516 {
   517     if (filter) {
   518         *filter = SDL_EventOK;
   519     }
   520     if (userdata) {
   521         *userdata = SDL_EventOKParam;
   522     }
   523     return SDL_EventOK ? SDL_TRUE : SDL_FALSE;
   524 }
   525 
   526 void
   527 SDL_FilterEvents(SDL_EventFilter filter, void *userdata)
   528 {
   529     if (SDL_mutexP(SDL_EventQ.lock) == 0) {
   530         int spot;
   531 
   532         spot = SDL_EventQ.head;
   533         while (spot != SDL_EventQ.tail) {
   534             if (filter(userdata, &SDL_EventQ.event[spot])) {
   535                 spot = (spot + 1) % MAXEVENTS;
   536             } else {
   537                 spot = SDL_CutEvent(spot);
   538             }
   539         }
   540     }
   541     SDL_mutexV(SDL_EventQ.lock);
   542 }
   543 
   544 Uint8
   545 SDL_EventState(Uint32 type, int state)
   546 {
   547     Uint8 current_state;
   548     Uint8 hi = ((type >> 8) & 0xff);
   549     Uint8 lo = (type & 0xff);
   550 
   551     if (SDL_disabled_events[hi] &&
   552         (SDL_disabled_events[hi]->bits[lo/32] & (1 << (lo&31)))) {
   553         current_state = SDL_DISABLE;
   554     } else {
   555         current_state = SDL_ENABLE;
   556     }
   557 
   558     if (state != current_state)
   559     {
   560         switch (state) {
   561         case SDL_DISABLE:
   562             /* Disable this event type and discard pending events */
   563             if (!SDL_disabled_events[hi]) {
   564                 SDL_disabled_events[hi] = (SDL_DisabledEventBlock*) SDL_calloc(1, sizeof(SDL_DisabledEventBlock));
   565                 if (!SDL_disabled_events[hi]) {
   566                     /* Out of memory, nothing we can do... */
   567                     break;
   568                 }
   569             }
   570             SDL_disabled_events[hi]->bits[lo/32] |= (1 << (lo&31));
   571             SDL_FlushEvent(type);
   572             break;
   573         case SDL_ENABLE:
   574             SDL_disabled_events[hi]->bits[lo/32] &= ~(1 << (lo&31));
   575             break;
   576         default:
   577             /* Querying state... */
   578             break;
   579         }
   580     }
   581 
   582     return current_state;
   583 }
   584 
   585 Uint32
   586 SDL_RegisterEvents(int numevents)
   587 {
   588     Uint32 event_base;
   589 
   590     if (SDL_userevents+numevents <= SDL_LASTEVENT) {
   591         event_base = SDL_userevents;
   592         SDL_userevents += numevents;
   593     } else {
   594         event_base = (Uint32)-1;
   595     }
   596     return event_base;
   597 }
   598 
   599 /* This is a generic event handler.
   600  */
   601 int
   602 SDL_SendSysWMEvent(SDL_SysWMmsg * message)
   603 {
   604     int posted;
   605 
   606     posted = 0;
   607     if (SDL_GetEventState(SDL_SYSWMEVENT) == SDL_ENABLE) {
   608         SDL_Event event;
   609         SDL_memset(&event, 0, sizeof(event));
   610         event.type = SDL_SYSWMEVENT;
   611         event.syswm.msg = message;
   612         posted = (SDL_PushEvent(&event) > 0);
   613     }
   614     /* Update internal event state */
   615     return (posted);
   616 }
   617 
   618 /* vi: set ts=4 sw=4 expandtab: */