src/events/SDL_events.c
author Jim Grandpre
Fri, 28 May 2010 01:26:52 -0400
changeset 4642 057e8762d2a1
parent 4460 363604b42e84
child 4657 eed063a0bf5b
permissions -rw-r--r--
Added reading of event* for touch events.
     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     return 1;
   497 }
   498 
   499 void
   500 SDL_SetEventFilter(SDL_EventFilter filter, void *userdata)
   501 {
   502     SDL_Event bitbucket;
   503 
   504     /* Set filter and discard pending events */
   505     SDL_EventOK = filter;
   506     SDL_EventOKParam = userdata;
   507     while (SDL_PollEvent(&bitbucket) > 0);
   508 }
   509 
   510 SDL_bool
   511 SDL_GetEventFilter(SDL_EventFilter * filter, void **userdata)
   512 {
   513     if (filter) {
   514         *filter = SDL_EventOK;
   515     }
   516     if (userdata) {
   517         *userdata = SDL_EventOKParam;
   518     }
   519     return SDL_EventOK ? SDL_TRUE : SDL_FALSE;
   520 }
   521 
   522 void
   523 SDL_FilterEvents(SDL_EventFilter filter, void *userdata)
   524 {
   525     if (SDL_mutexP(SDL_EventQ.lock) == 0) {
   526         int spot;
   527 
   528         spot = SDL_EventQ.head;
   529         while (spot != SDL_EventQ.tail) {
   530             if (filter(userdata, &SDL_EventQ.event[spot])) {
   531                 spot = (spot + 1) % MAXEVENTS;
   532             } else {
   533                 spot = SDL_CutEvent(spot);
   534             }
   535         }
   536     }
   537     SDL_mutexV(SDL_EventQ.lock);
   538 }
   539 
   540 Uint8
   541 SDL_EventState(Uint32 type, int state)
   542 {
   543     Uint8 current_state;
   544     Uint8 hi = ((type >> 8) & 0xff);
   545     Uint8 lo = (type & 0xff);
   546 
   547     if (SDL_disabled_events[hi] &&
   548         (SDL_disabled_events[hi]->bits[lo/32] & (1 << (lo&31)))) {
   549         current_state = SDL_DISABLE;
   550     } else {
   551         current_state = SDL_ENABLE;
   552     }
   553 
   554     if (state != current_state)
   555     {
   556         switch (state) {
   557         case SDL_DISABLE:
   558             /* Disable this event type and discard pending events */
   559             if (!SDL_disabled_events[hi]) {
   560                 SDL_disabled_events[hi] = (SDL_DisabledEventBlock*) SDL_calloc(1, sizeof(SDL_DisabledEventBlock));
   561                 if (!SDL_disabled_events[hi]) {
   562                     /* Out of memory, nothing we can do... */
   563                     break;
   564                 }
   565             }
   566             SDL_disabled_events[hi]->bits[lo/32] |= (1 << (lo&31));
   567             SDL_FlushEvent(type);
   568             break;
   569         case SDL_ENABLE:
   570             SDL_disabled_events[hi]->bits[lo/32] &= ~(1 << (lo&31));
   571             break;
   572         default:
   573             /* Querying state... */
   574             break;
   575         }
   576     }
   577 
   578     return current_state;
   579 }
   580 
   581 Uint32
   582 SDL_RegisterEvents(int numevents)
   583 {
   584     Uint32 event_base;
   585 
   586     if (SDL_userevents+numevents <= SDL_LASTEVENT) {
   587         event_base = SDL_userevents;
   588         SDL_userevents += numevents;
   589     } else {
   590         event_base = (Uint32)-1;
   591     }
   592     return event_base;
   593 }
   594 
   595 /* This is a generic event handler.
   596  */
   597 int
   598 SDL_SendSysWMEvent(SDL_SysWMmsg * message)
   599 {
   600     int posted;
   601 
   602     posted = 0;
   603     if (SDL_GetEventState(SDL_SYSWMEVENT) == SDL_ENABLE) {
   604         SDL_Event event;
   605         SDL_memset(&event, 0, sizeof(event));
   606         event.type = SDL_SYSWMEVENT;
   607         event.syswm.msg = message;
   608         posted = (SDL_PushEvent(&event) > 0);
   609     }
   610     /* Update internal event state */
   611     return (posted);
   612 }
   613 
   614 /* vi: set ts=4 sw=4 expandtab: */