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