src/events/SDL_events.c
author Sam Lantinga
Sun, 13 Feb 2011 22:53:12 -0800
changeset 5293 7e9cdbbf7ba1
parent 5262 b530ef003506
child 5535 96594ac5fd1a
permissions -rw-r--r--
Fixed crash while resizing a window on Mac OS X.
     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 #if 0
   274     /* Actually, we can't do this since we might be flushing while processing
   275        a resize event, and calling this might trigger further resize events.
   276     */
   277     SDL_PumpEvents();
   278 #endif
   279 
   280     /* Lock the event queue */
   281     if (SDL_mutexP(SDL_EventQ.lock) == 0) {
   282         int spot = SDL_EventQ.head;
   283         while (spot != SDL_EventQ.tail) {
   284             Uint32 type = SDL_EventQ.event[spot].type;
   285             if (minType <= type && type <= maxType) {
   286                 spot = SDL_CutEvent(spot);
   287             } else {
   288                 spot = (spot + 1) % MAXEVENTS;
   289             }
   290         }
   291         SDL_mutexV(SDL_EventQ.lock);
   292     }
   293 }
   294 
   295 /* Run the system dependent event loops */
   296 void
   297 SDL_PumpEvents(void)
   298 {
   299     SDL_VideoDevice *_this = SDL_GetVideoDevice();
   300 
   301     /* Get events from the video subsystem */
   302     if (_this) {
   303         _this->PumpEvents(_this);
   304     }
   305 #if !SDL_JOYSTICK_DISABLED
   306     /* Check for joystick state change */
   307     if (SDL_ShouldPollJoystick()) {
   308         SDL_JoystickUpdate();
   309     }
   310 #endif
   311 }
   312 
   313 /* Public functions */
   314 
   315 int
   316 SDL_PollEvent(SDL_Event * event)
   317 {
   318     return SDL_WaitEventTimeout(event, 0);
   319 }
   320 
   321 int
   322 SDL_WaitEvent(SDL_Event * event)
   323 {
   324     return SDL_WaitEventTimeout(event, -1);
   325 }
   326 
   327 int
   328 SDL_WaitEventTimeout(SDL_Event * event, int timeout)
   329 {
   330     Uint32 expiration = 0;
   331 
   332     if (timeout > 0)
   333         expiration = SDL_GetTicks() + timeout;
   334 
   335     for (;;) {
   336         SDL_PumpEvents();
   337         switch (SDL_PeepEvents(event, 1, SDL_GETEVENT, SDL_FIRSTEVENT, SDL_LASTEVENT)) {
   338         case -1:
   339             return 0;
   340         case 1:
   341             return 1;
   342         case 0:
   343             if (timeout == 0) {
   344                 /* Polling and no events, just return */
   345                 return 0;
   346             }
   347             if (timeout > 0 && ((int) (SDL_GetTicks() - expiration) >= 0)) {
   348                 /* Timeout expired and no events */
   349                 return 0;
   350             }
   351             SDL_Delay(10);
   352             break;
   353         }
   354     }
   355 }
   356 
   357 int
   358 SDL_PushEvent(SDL_Event * event)
   359 {
   360     SDL_EventWatcher *curr;
   361 
   362     if (SDL_EventOK && !SDL_EventOK(SDL_EventOKParam, event)) {
   363         return 0;
   364     }
   365 
   366     for (curr = SDL_event_watchers; curr; curr = curr->next) {
   367         curr->callback(curr->userdata, event);
   368     }
   369 
   370     if (SDL_PeepEvents(event, 1, SDL_ADDEVENT, 0, 0) <= 0) {
   371         return -1;
   372     }
   373 
   374     SDL_GestureProcessEvent(event);
   375     
   376 
   377     return 1;
   378 }
   379 
   380 void
   381 SDL_SetEventFilter(SDL_EventFilter filter, void *userdata)
   382 {
   383     SDL_Event bitbucket;
   384 
   385     /* Set filter and discard pending events */
   386     SDL_EventOK = filter;
   387     SDL_EventOKParam = userdata;
   388     while (SDL_PollEvent(&bitbucket) > 0);
   389 }
   390 
   391 SDL_bool
   392 SDL_GetEventFilter(SDL_EventFilter * filter, void **userdata)
   393 {
   394     if (filter) {
   395         *filter = SDL_EventOK;
   396     }
   397     if (userdata) {
   398         *userdata = SDL_EventOKParam;
   399     }
   400     return SDL_EventOK ? SDL_TRUE : SDL_FALSE;
   401 }
   402 
   403 /* FIXME: This is not thread-safe yet */
   404 void
   405 SDL_AddEventWatch(SDL_EventFilter filter, void *userdata)
   406 {
   407     SDL_EventWatcher *watcher;
   408 
   409     watcher = (SDL_EventWatcher *)SDL_malloc(sizeof(*watcher));
   410     if (!watcher) {
   411         /* Uh oh... */
   412         return;
   413     }
   414     watcher->callback = filter;
   415     watcher->userdata = userdata;
   416     watcher->next = SDL_event_watchers;
   417     SDL_event_watchers = watcher;
   418 }
   419 
   420 /* FIXME: This is not thread-safe yet */
   421 void
   422 SDL_DelEventWatch(SDL_EventFilter filter, void *userdata)
   423 {
   424     SDL_EventWatcher *prev = NULL;
   425     SDL_EventWatcher *curr;
   426 
   427     for (curr = SDL_event_watchers; curr; prev = curr, curr = curr->next) {
   428         if (curr->callback == filter && curr->userdata == userdata) {
   429             if (prev) {
   430                 prev->next = curr->next;
   431             } else {
   432                 SDL_event_watchers = curr->next;
   433             }
   434             SDL_free(curr);
   435             break;
   436         }
   437     }
   438 }
   439 
   440 void
   441 SDL_FilterEvents(SDL_EventFilter filter, void *userdata)
   442 {
   443     if (SDL_mutexP(SDL_EventQ.lock) == 0) {
   444         int spot;
   445 
   446         spot = SDL_EventQ.head;
   447         while (spot != SDL_EventQ.tail) {
   448             if (filter(userdata, &SDL_EventQ.event[spot])) {
   449                 spot = (spot + 1) % MAXEVENTS;
   450             } else {
   451                 spot = SDL_CutEvent(spot);
   452             }
   453         }
   454     }
   455     SDL_mutexV(SDL_EventQ.lock);
   456 }
   457 
   458 Uint8
   459 SDL_EventState(Uint32 type, int state)
   460 {
   461     Uint8 current_state;
   462     Uint8 hi = ((type >> 8) & 0xff);
   463     Uint8 lo = (type & 0xff);
   464 
   465     if (SDL_disabled_events[hi] &&
   466         (SDL_disabled_events[hi]->bits[lo/32] & (1 << (lo&31)))) {
   467         current_state = SDL_DISABLE;
   468     } else {
   469         current_state = SDL_ENABLE;
   470     }
   471 
   472     if (state != current_state)
   473     {
   474         switch (state) {
   475         case SDL_DISABLE:
   476             /* Disable this event type and discard pending events */
   477             if (!SDL_disabled_events[hi]) {
   478                 SDL_disabled_events[hi] = (SDL_DisabledEventBlock*) SDL_calloc(1, sizeof(SDL_DisabledEventBlock));
   479                 if (!SDL_disabled_events[hi]) {
   480                     /* Out of memory, nothing we can do... */
   481                     break;
   482                 }
   483             }
   484             SDL_disabled_events[hi]->bits[lo/32] |= (1 << (lo&31));
   485             SDL_FlushEvent(type);
   486             break;
   487         case SDL_ENABLE:
   488             SDL_disabled_events[hi]->bits[lo/32] &= ~(1 << (lo&31));
   489             break;
   490         default:
   491             /* Querying state... */
   492             break;
   493         }
   494     }
   495 
   496     return current_state;
   497 }
   498 
   499 Uint32
   500 SDL_RegisterEvents(int numevents)
   501 {
   502     Uint32 event_base;
   503 
   504     if (SDL_userevents+numevents <= SDL_LASTEVENT) {
   505         event_base = SDL_userevents;
   506         SDL_userevents += numevents;
   507     } else {
   508         event_base = (Uint32)-1;
   509     }
   510     return event_base;
   511 }
   512 
   513 /* This is a generic event handler.
   514  */
   515 int
   516 SDL_SendSysWMEvent(SDL_SysWMmsg * message)
   517 {
   518     int posted;
   519 
   520     posted = 0;
   521     if (SDL_GetEventState(SDL_SYSWMEVENT) == SDL_ENABLE) {
   522         SDL_Event event;
   523         SDL_memset(&event, 0, sizeof(event));
   524         event.type = SDL_SYSWMEVENT;
   525         event.syswm.msg = message;
   526         posted = (SDL_PushEvent(&event) > 0);
   527     }
   528     /* Update internal event state */
   529     return (posted);
   530 }
   531 
   532 /* vi: set ts=4 sw=4 expandtab: */