src/events/SDL_events.c
author Paul Hunkin <paul@bieh.net>
Mon, 17 May 2010 15:14:34 +1200
changeset 4695 b7918263da92
parent 4460 363604b42e84
child 4642 057e8762d2a1
child 4698 52697090c967
permissions -rw-r--r--
Initial commit, adding __ANDROID__ to the platform list
     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_QuitInit();
   258     if (retcode < 0) {
   259         /* We don't expect them to fail, but... */
   260         return (-1);
   261     }
   262 
   263     /* Create the lock and event thread */
   264     if (SDL_StartEventThread(flags) < 0) {
   265         SDL_StopEventLoop();
   266         return (-1);
   267     }
   268     return (0);
   269 }
   270 
   271 
   272 /* Add an event to the event queue -- called with the queue locked */
   273 static int
   274 SDL_AddEvent(SDL_Event * event)
   275 {
   276     int tail, added;
   277 
   278     tail = (SDL_EventQ.tail + 1) % MAXEVENTS;
   279     if (tail == SDL_EventQ.head) {
   280         /* Overflow, drop event */
   281         added = 0;
   282     } else {
   283         SDL_EventQ.event[SDL_EventQ.tail] = *event;
   284         if (event->type == SDL_SYSWMEVENT) {
   285             /* Note that it's possible to lose an event */
   286             int next = SDL_EventQ.wmmsg_next;
   287             SDL_EventQ.wmmsg[next] = *event->syswm.msg;
   288             SDL_EventQ.event[SDL_EventQ.tail].syswm.msg =
   289                 &SDL_EventQ.wmmsg[next];
   290             SDL_EventQ.wmmsg_next = (next + 1) % MAXEVENTS;
   291         }
   292         SDL_EventQ.tail = tail;
   293         added = 1;
   294     }
   295     return (added);
   296 }
   297 
   298 /* Cut an event, and return the next valid spot, or the tail */
   299 /*                           -- called with the queue locked */
   300 static int
   301 SDL_CutEvent(int spot)
   302 {
   303     if (spot == SDL_EventQ.head) {
   304         SDL_EventQ.head = (SDL_EventQ.head + 1) % MAXEVENTS;
   305         return (SDL_EventQ.head);
   306     } else if ((spot + 1) % MAXEVENTS == SDL_EventQ.tail) {
   307         SDL_EventQ.tail = spot;
   308         return (SDL_EventQ.tail);
   309     } else
   310         /* We cut the middle -- shift everything over */
   311     {
   312         int here, next;
   313 
   314         /* This can probably be optimized with SDL_memcpy() -- careful! */
   315         if (--SDL_EventQ.tail < 0) {
   316             SDL_EventQ.tail = MAXEVENTS - 1;
   317         }
   318         for (here = spot; here != SDL_EventQ.tail; here = next) {
   319             next = (here + 1) % MAXEVENTS;
   320             SDL_EventQ.event[here] = SDL_EventQ.event[next];
   321         }
   322         return (spot);
   323     }
   324     /* NOTREACHED */
   325 }
   326 
   327 /* Lock the event queue, take a peep at it, and unlock it */
   328 int
   329 SDL_PeepEvents(SDL_Event * events, int numevents, SDL_eventaction action,
   330                Uint32 minType, Uint32 maxType)
   331 {
   332     int i, used;
   333 
   334     /* Don't look after we've quit */
   335     if (!SDL_EventQ.active) {
   336         return (-1);
   337     }
   338     /* Lock the event queue */
   339     used = 0;
   340     if (SDL_mutexP(SDL_EventQ.lock) == 0) {
   341         if (action == SDL_ADDEVENT) {
   342             for (i = 0; i < numevents; ++i) {
   343                 used += SDL_AddEvent(&events[i]);
   344             }
   345         } else {
   346             SDL_Event tmpevent;
   347             int spot;
   348 
   349             /* If 'events' is NULL, just see if they exist */
   350             if (events == NULL) {
   351                 action = SDL_PEEKEVENT;
   352                 numevents = 1;
   353                 events = &tmpevent;
   354             }
   355             spot = SDL_EventQ.head;
   356             while ((used < numevents) && (spot != SDL_EventQ.tail)) {
   357                 Uint32 type = SDL_EventQ.event[spot].type;
   358                 if (minType <= type && type <= maxType) {
   359                     events[used++] = SDL_EventQ.event[spot];
   360                     if (action == SDL_GETEVENT) {
   361                         spot = SDL_CutEvent(spot);
   362                     } else {
   363                         spot = (spot + 1) % MAXEVENTS;
   364                     }
   365                 } else {
   366                     spot = (spot + 1) % MAXEVENTS;
   367                 }
   368             }
   369         }
   370         SDL_mutexV(SDL_EventQ.lock);
   371     } else {
   372         SDL_SetError("Couldn't lock event queue");
   373         used = -1;
   374     }
   375     return (used);
   376 }
   377 
   378 SDL_bool
   379 SDL_HasEvent(Uint32 type)
   380 {
   381     return (SDL_PeepEvents(NULL, 0, SDL_PEEKEVENT, type, type) > 0);
   382 }
   383 
   384 SDL_bool
   385 SDL_HasEvents(Uint32 minType, Uint32 maxType)
   386 {
   387     return (SDL_PeepEvents(NULL, 0, SDL_PEEKEVENT, minType, maxType) > 0);
   388 }
   389 
   390 void
   391 SDL_FlushEvent(Uint32 type)
   392 {
   393     SDL_FlushEvents(type, type);
   394 }
   395 
   396 void
   397 SDL_FlushEvents(Uint32 minType, Uint32 maxType)
   398 {
   399     /* Don't look after we've quit */
   400     if (!SDL_EventQ.active) {
   401         return;
   402     }
   403 
   404     /* Make sure the events are current */
   405     SDL_PumpEvents();
   406 
   407     /* Lock the event queue */
   408     if (SDL_mutexP(SDL_EventQ.lock) == 0) {
   409         int spot = SDL_EventQ.head;
   410         while (spot != SDL_EventQ.tail) {
   411             Uint32 type = SDL_EventQ.event[spot].type;
   412             if (minType <= type && type <= maxType) {
   413                 spot = SDL_CutEvent(spot);
   414             } else {
   415                 spot = (spot + 1) % MAXEVENTS;
   416             }
   417         }
   418         SDL_mutexV(SDL_EventQ.lock);
   419     }
   420 }
   421 
   422 /* Run the system dependent event loops */
   423 void
   424 SDL_PumpEvents(void)
   425 {
   426     if (!SDL_EventThread) {
   427         SDL_VideoDevice *_this = SDL_GetVideoDevice();
   428 
   429         /* Get events from the video subsystem */
   430         if (_this) {
   431             _this->PumpEvents(_this);
   432         }
   433 #if !SDL_JOYSTICK_DISABLED
   434         /* Check for joystick state change */
   435         if (SDL_ShouldPollJoystick()) {
   436             SDL_JoystickUpdate();
   437         }
   438 #endif
   439     }
   440 }
   441 
   442 /* Public functions */
   443 
   444 int
   445 SDL_PollEvent(SDL_Event * event)
   446 {
   447     return SDL_WaitEventTimeout(event, 0);
   448 }
   449 
   450 int
   451 SDL_WaitEvent(SDL_Event * event)
   452 {
   453     return SDL_WaitEventTimeout(event, -1);
   454 }
   455 
   456 int
   457 SDL_WaitEventTimeout(SDL_Event * event, int timeout)
   458 {
   459     Uint32 expiration = 0;
   460 
   461     if (timeout > 0)
   462         expiration = SDL_GetTicks() + timeout;
   463 
   464     for (;;) {
   465         SDL_PumpEvents();
   466         switch (SDL_PeepEvents(event, 1, SDL_GETEVENT, SDL_FIRSTEVENT, SDL_LASTEVENT)) {
   467         case -1:
   468             return 0;
   469         case 1:
   470             return 1;
   471         case 0:
   472             if (timeout == 0) {
   473                 /* Polling and no events, just return */
   474                 return 0;
   475             }
   476             if (timeout > 0 && ((int) (SDL_GetTicks() - expiration) >= 0)) {
   477                 /* Timeout expired and no events */
   478                 return 0;
   479             }
   480             SDL_Delay(10);
   481             break;
   482         }
   483     }
   484 }
   485 
   486 int
   487 SDL_PushEvent(SDL_Event * event)
   488 {
   489     if (SDL_EventOK && !SDL_EventOK(SDL_EventOKParam, event)) {
   490         return 0;
   491     }
   492     if (SDL_PeepEvents(event, 1, SDL_ADDEVENT, 0, 0) <= 0) {
   493         return -1;
   494     }
   495     return 1;
   496 }
   497 
   498 void
   499 SDL_SetEventFilter(SDL_EventFilter filter, void *userdata)
   500 {
   501     SDL_Event bitbucket;
   502 
   503     /* Set filter and discard pending events */
   504     SDL_EventOK = filter;
   505     SDL_EventOKParam = userdata;
   506     while (SDL_PollEvent(&bitbucket) > 0);
   507 }
   508 
   509 SDL_bool
   510 SDL_GetEventFilter(SDL_EventFilter * filter, void **userdata)
   511 {
   512     if (filter) {
   513         *filter = SDL_EventOK;
   514     }
   515     if (userdata) {
   516         *userdata = SDL_EventOKParam;
   517     }
   518     return SDL_EventOK ? SDL_TRUE : SDL_FALSE;
   519 }
   520 
   521 void
   522 SDL_FilterEvents(SDL_EventFilter filter, void *userdata)
   523 {
   524     if (SDL_mutexP(SDL_EventQ.lock) == 0) {
   525         int spot;
   526 
   527         spot = SDL_EventQ.head;
   528         while (spot != SDL_EventQ.tail) {
   529             if (filter(userdata, &SDL_EventQ.event[spot])) {
   530                 spot = (spot + 1) % MAXEVENTS;
   531             } else {
   532                 spot = SDL_CutEvent(spot);
   533             }
   534         }
   535     }
   536     SDL_mutexV(SDL_EventQ.lock);
   537 }
   538 
   539 Uint8
   540 SDL_EventState(Uint32 type, int state)
   541 {
   542     Uint8 current_state;
   543     Uint8 hi = ((type >> 8) & 0xff);
   544     Uint8 lo = (type & 0xff);
   545 
   546     if (SDL_disabled_events[hi] &&
   547         (SDL_disabled_events[hi]->bits[lo/32] & (1 << (lo&31)))) {
   548         current_state = SDL_DISABLE;
   549     } else {
   550         current_state = SDL_ENABLE;
   551     }
   552 
   553     if (state != current_state)
   554     {
   555         switch (state) {
   556         case SDL_DISABLE:
   557             /* Disable this event type and discard pending events */
   558             if (!SDL_disabled_events[hi]) {
   559                 SDL_disabled_events[hi] = (SDL_DisabledEventBlock*) SDL_calloc(1, sizeof(SDL_DisabledEventBlock));
   560                 if (!SDL_disabled_events[hi]) {
   561                     /* Out of memory, nothing we can do... */
   562                     break;
   563                 }
   564             }
   565             SDL_disabled_events[hi]->bits[lo/32] |= (1 << (lo&31));
   566             SDL_FlushEvent(type);
   567             break;
   568         case SDL_ENABLE:
   569             SDL_disabled_events[hi]->bits[lo/32] &= ~(1 << (lo&31));
   570             break;
   571         default:
   572             /* Querying state... */
   573             break;
   574         }
   575     }
   576 
   577     return current_state;
   578 }
   579 
   580 Uint32
   581 SDL_RegisterEvents(int numevents)
   582 {
   583     Uint32 event_base;
   584 
   585     if (SDL_userevents+numevents <= SDL_LASTEVENT) {
   586         event_base = SDL_userevents;
   587         SDL_userevents += numevents;
   588     } else {
   589         event_base = (Uint32)-1;
   590     }
   591     return event_base;
   592 }
   593 
   594 /* This is a generic event handler.
   595  */
   596 int
   597 SDL_SendSysWMEvent(SDL_SysWMmsg * message)
   598 {
   599     int posted;
   600 
   601     posted = 0;
   602     if (SDL_GetEventState(SDL_SYSWMEVENT) == SDL_ENABLE) {
   603         SDL_Event event;
   604         SDL_memset(&event, 0, sizeof(event));
   605         event.type = SDL_SYSWMEVENT;
   606         event.syswm.msg = message;
   607         posted = (SDL_PushEvent(&event) > 0);
   608     }
   609     /* Update internal event state */
   610     return (posted);
   611 }
   612 
   613 /* vi: set ts=4 sw=4 expandtab: */