src/events/SDL_events.c
author Sam Lantinga
Wed, 03 Oct 2012 13:39:42 -0700
changeset 6544 c03db4864789
parent 6495 2bf42c5e897a
child 6588 f739b8044c26
permissions -rw-r--r--
Use Ctrl modifier for window resize key bindings
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2012 Sam Lantinga <slouken@libsdl.org>
     4 
     5   This software is provided 'as-is', without any express or implied
     6   warranty.  In no event will the authors be held liable for any damages
     7   arising from the use of this software.
     8 
     9   Permission is granted to anyone to use this software for any purpose,
    10   including commercial applications, and to alter it and redistribute it
    11   freely, subject to the following restrictions:
    12 
    13   1. The origin of this software must not be misrepresented; you must not
    14      claim that you wrote the original software. If you use this software
    15      in a product, an acknowledgment in the product documentation would be
    16      appreciated but is not required.
    17   2. Altered source versions must be plainly marked as such, and must not be
    18      misrepresented as being the original software.
    19   3. This notice may not be removed or altered from any source distribution.
    20 */
    21 #include "SDL_config.h"
    22 
    23 /* General event handling code for SDL */
    24 
    25 #include "SDL.h"
    26 #include "SDL_events.h"
    27 #include "SDL_syswm.h"
    28 #include "SDL_thread.h"
    29 #include "SDL_events_c.h"
    30 #include "../timer/SDL_timer_c.h"
    31 #if !SDL_JOYSTICK_DISABLED
    32 #include "../joystick/SDL_joystick_c.h"
    33 #endif
    34 #include "../video/SDL_sysvideo.h"
    35 
    36 /* Public data -- the event filter */
    37 SDL_EventFilter SDL_EventOK = NULL;
    38 void *SDL_EventOKParam;
    39 
    40 typedef struct SDL_EventWatcher {
    41     SDL_EventFilter callback;
    42     void *userdata;
    43     struct SDL_EventWatcher *next;
    44 } SDL_EventWatcher;
    45 
    46 static SDL_EventWatcher *SDL_event_watchers = NULL;
    47 
    48 typedef struct {
    49     Uint32 bits[8];
    50 } SDL_DisabledEventBlock;
    51 
    52 static SDL_DisabledEventBlock *SDL_disabled_events[256];
    53 static Uint32 SDL_userevents = SDL_USEREVENT;
    54 
    55 /* Private data -- event queue */
    56 #define MAXEVENTS	128
    57 static struct
    58 {
    59     SDL_mutex *lock;
    60     int active;
    61     int head;
    62     int tail;
    63     SDL_Event event[MAXEVENTS];
    64     int wmmsg_next;
    65     struct SDL_SysWMmsg wmmsg[MAXEVENTS];
    66 } SDL_EventQ;
    67 
    68 
    69 static __inline__ SDL_bool
    70 SDL_ShouldPollJoystick()
    71 {
    72 #if !SDL_JOYSTICK_DISABLED
    73     if (SDL_numjoysticks &&
    74         (!SDL_disabled_events[SDL_JOYAXISMOTION >> 8] ||
    75          SDL_JoystickEventState(SDL_QUERY))) {
    76         return SDL_TRUE;
    77     }
    78 #endif
    79     return SDL_FALSE;
    80 }
    81 
    82 /* Public functions */
    83 
    84 void
    85 SDL_StopEventLoop(void)
    86 {
    87     int i;
    88 
    89     SDL_EventQ.active = 0;
    90 
    91     if (SDL_EventQ.lock) {
    92         SDL_DestroyMutex(SDL_EventQ.lock);
    93         SDL_EventQ.lock = NULL;
    94     }
    95 
    96     /* Clean out EventQ */
    97     SDL_EventQ.head = 0;
    98     SDL_EventQ.tail = 0;
    99     SDL_EventQ.wmmsg_next = 0;
   100 
   101     /* Clear disabled event state */
   102     for (i = 0; i < SDL_arraysize(SDL_disabled_events); ++i) {
   103         if (SDL_disabled_events[i]) {
   104             SDL_free(SDL_disabled_events[i]);
   105             SDL_disabled_events[i] = NULL;
   106         }
   107     }
   108 
   109     while (SDL_event_watchers) {
   110         SDL_EventWatcher *tmp = SDL_event_watchers;
   111         SDL_event_watchers = tmp->next;
   112         SDL_free(tmp);
   113     }
   114 }
   115 
   116 /* This function (and associated calls) may be called more than once */
   117 int
   118 SDL_StartEventLoop(void)
   119 {
   120     /* Clean out the event queue */
   121     SDL_EventQ.lock = NULL;
   122     SDL_StopEventLoop();
   123 
   124     /* No filter to start with, process most event types */
   125     SDL_EventOK = NULL;
   126     SDL_EventState(SDL_DROPFILE, SDL_DISABLE);
   127     SDL_EventState(SDL_SYSWMEVENT, SDL_DISABLE);
   128 
   129     /* Create the lock and set ourselves active */
   130 #if !SDL_THREADS_DISABLED
   131     SDL_EventQ.lock = SDL_CreateMutex();
   132     if (SDL_EventQ.lock == NULL) {
   133         return (-1);
   134     }
   135 #endif /* !SDL_THREADS_DISABLED */
   136     SDL_EventQ.active = 1;
   137 
   138     return (0);
   139 }
   140 
   141 
   142 /* Add an event to the event queue -- called with the queue locked */
   143 static int
   144 SDL_AddEvent(SDL_Event * event)
   145 {
   146     int tail, added;
   147 
   148     tail = (SDL_EventQ.tail + 1) % MAXEVENTS;
   149     if (tail == SDL_EventQ.head) {
   150         /* Overflow, drop event */
   151         added = 0;
   152     } else {
   153         SDL_EventQ.event[SDL_EventQ.tail] = *event;
   154         if (event->type == SDL_SYSWMEVENT) {
   155             /* Note that it's possible to lose an event */
   156             int next = SDL_EventQ.wmmsg_next;
   157             SDL_EventQ.wmmsg[next] = *event->syswm.msg;
   158             SDL_EventQ.event[SDL_EventQ.tail].syswm.msg =
   159                 &SDL_EventQ.wmmsg[next];
   160             SDL_EventQ.wmmsg_next = (next + 1) % MAXEVENTS;
   161         }
   162         SDL_EventQ.tail = tail;
   163         added = 1;
   164     }
   165     return (added);
   166 }
   167 
   168 /* Cut an event, and return the next valid spot, or the tail */
   169 /*                           -- called with the queue locked */
   170 static int
   171 SDL_CutEvent(int spot)
   172 {
   173     if (spot == SDL_EventQ.head) {
   174         SDL_EventQ.head = (SDL_EventQ.head + 1) % MAXEVENTS;
   175         return (SDL_EventQ.head);
   176     } else if ((spot + 1) % MAXEVENTS == SDL_EventQ.tail) {
   177         SDL_EventQ.tail = spot;
   178         return (SDL_EventQ.tail);
   179     } else
   180         /* We cut the middle -- shift everything over */
   181     {
   182         int here, next;
   183 
   184         /* This can probably be optimized with SDL_memcpy() -- careful! */
   185         if (--SDL_EventQ.tail < 0) {
   186             SDL_EventQ.tail = MAXEVENTS - 1;
   187         }
   188         for (here = spot; here != SDL_EventQ.tail; here = next) {
   189             next = (here + 1) % MAXEVENTS;
   190             SDL_EventQ.event[here] = SDL_EventQ.event[next];
   191         }
   192         return (spot);
   193     }
   194     /* NOTREACHED */
   195 }
   196 
   197 /* Lock the event queue, take a peep at it, and unlock it */
   198 int
   199 SDL_PeepEvents(SDL_Event * events, int numevents, SDL_eventaction action,
   200                Uint32 minType, Uint32 maxType)
   201 {
   202     int i, used;
   203 
   204     /* Don't look after we've quit */
   205     if (!SDL_EventQ.active) {
   206         return (-1);
   207     }
   208     /* Lock the event queue */
   209     used = 0;
   210     if (SDL_mutexP(SDL_EventQ.lock) == 0) {
   211         if (action == SDL_ADDEVENT) {
   212             for (i = 0; i < numevents; ++i) {
   213                 used += SDL_AddEvent(&events[i]);
   214             }
   215         } else {
   216             SDL_Event tmpevent;
   217             int spot;
   218 
   219             /* If 'events' is NULL, just see if they exist */
   220             if (events == NULL) {
   221                 action = SDL_PEEKEVENT;
   222                 numevents = 1;
   223                 events = &tmpevent;
   224             }
   225             spot = SDL_EventQ.head;
   226             while ((used < numevents) && (spot != SDL_EventQ.tail)) {
   227                 Uint32 type = SDL_EventQ.event[spot].type;
   228                 if (minType <= type && type <= maxType) {
   229                     events[used++] = SDL_EventQ.event[spot];
   230                     if (action == SDL_GETEVENT) {
   231                         spot = SDL_CutEvent(spot);
   232                     } else {
   233                         spot = (spot + 1) % MAXEVENTS;
   234                     }
   235                 } else {
   236                     spot = (spot + 1) % MAXEVENTS;
   237                 }
   238             }
   239         }
   240         SDL_mutexV(SDL_EventQ.lock);
   241     } else {
   242         SDL_SetError("Couldn't lock event queue");
   243         used = -1;
   244     }
   245     return (used);
   246 }
   247 
   248 SDL_bool
   249 SDL_HasEvent(Uint32 type)
   250 {
   251     return (SDL_PeepEvents(NULL, 0, SDL_PEEKEVENT, type, type) > 0);
   252 }
   253 
   254 SDL_bool
   255 SDL_HasEvents(Uint32 minType, Uint32 maxType)
   256 {
   257     return (SDL_PeepEvents(NULL, 0, SDL_PEEKEVENT, minType, maxType) > 0);
   258 }
   259 
   260 void
   261 SDL_FlushEvent(Uint32 type)
   262 {
   263     SDL_FlushEvents(type, type);
   264 }
   265 
   266 void
   267 SDL_FlushEvents(Uint32 minType, Uint32 maxType)
   268 {
   269     /* Don't look after we've quit */
   270     if (!SDL_EventQ.active) {
   271         return;
   272     }
   273 
   274     /* Make sure the events are current */
   275 #if 0
   276     /* Actually, we can't do this since we might be flushing while processing
   277        a resize event, and calling this might trigger further resize events.
   278     */
   279     SDL_PumpEvents();
   280 #endif
   281 
   282     /* Lock the event queue */
   283     if (SDL_mutexP(SDL_EventQ.lock) == 0) {
   284         int spot = SDL_EventQ.head;
   285         while (spot != SDL_EventQ.tail) {
   286             Uint32 type = SDL_EventQ.event[spot].type;
   287             if (minType <= type && type <= maxType) {
   288                 spot = SDL_CutEvent(spot);
   289             } else {
   290                 spot = (spot + 1) % MAXEVENTS;
   291             }
   292         }
   293         SDL_mutexV(SDL_EventQ.lock);
   294     }
   295 }
   296 
   297 /* Run the system dependent event loops */
   298 void
   299 SDL_PumpEvents(void)
   300 {
   301     SDL_VideoDevice *_this = SDL_GetVideoDevice();
   302 
   303     /* Get events from the video subsystem */
   304     if (_this) {
   305         _this->PumpEvents(_this);
   306     }
   307 #if !SDL_JOYSTICK_DISABLED
   308     /* Check for joystick state change */
   309     if (SDL_ShouldPollJoystick()) {
   310         SDL_JoystickUpdate();
   311     }
   312 #endif
   313 }
   314 
   315 /* Public functions */
   316 
   317 int
   318 SDL_PollEvent(SDL_Event * event)
   319 {
   320     return SDL_WaitEventTimeout(event, 0);
   321 }
   322 
   323 int
   324 SDL_WaitEvent(SDL_Event * event)
   325 {
   326     return SDL_WaitEventTimeout(event, -1);
   327 }
   328 
   329 int
   330 SDL_WaitEventTimeout(SDL_Event * event, int timeout)
   331 {
   332     Uint32 expiration = 0;
   333 
   334     if (timeout > 0)
   335         expiration = SDL_GetTicks() + timeout;
   336 
   337     for (;;) {
   338         SDL_PumpEvents();
   339         switch (SDL_PeepEvents(event, 1, SDL_GETEVENT, SDL_FIRSTEVENT, SDL_LASTEVENT)) {
   340         case -1:
   341             return 0;
   342         case 1:
   343             return 1;
   344         case 0:
   345             if (timeout == 0) {
   346                 /* Polling and no events, just return */
   347                 return 0;
   348             }
   349             if (timeout > 0 && ((int) (SDL_GetTicks() - expiration) >= 0)) {
   350                 /* Timeout expired and no events */
   351                 return 0;
   352             }
   353             SDL_Delay(10);
   354             break;
   355         }
   356     }
   357 }
   358 
   359 int
   360 SDL_PushEvent(SDL_Event * event)
   361 {
   362     SDL_EventWatcher *curr;
   363     event->window.timestamp = SDL_GetTicks();
   364     if (SDL_EventOK && !SDL_EventOK(SDL_EventOKParam, event)) {
   365         return 0;
   366     }
   367 
   368     for (curr = SDL_event_watchers; curr; curr = curr->next) {
   369         curr->callback(curr->userdata, event);
   370     }
   371 
   372     if (SDL_PeepEvents(event, 1, SDL_ADDEVENT, 0, 0) <= 0) {
   373         return -1;
   374     }
   375 
   376     SDL_GestureProcessEvent(event);
   377     
   378 
   379     return 1;
   380 }
   381 
   382 void
   383 SDL_SetEventFilter(SDL_EventFilter filter, void *userdata)
   384 {
   385     SDL_Event bitbucket;
   386 
   387     /* Set filter and discard pending events */
   388     SDL_EventOK = filter;
   389     SDL_EventOKParam = userdata;
   390     while (SDL_PollEvent(&bitbucket) > 0);
   391 }
   392 
   393 SDL_bool
   394 SDL_GetEventFilter(SDL_EventFilter * filter, void **userdata)
   395 {
   396     if (filter) {
   397         *filter = SDL_EventOK;
   398     }
   399     if (userdata) {
   400         *userdata = SDL_EventOKParam;
   401     }
   402     return SDL_EventOK ? SDL_TRUE : SDL_FALSE;
   403 }
   404 
   405 /* FIXME: This is not thread-safe yet */
   406 void
   407 SDL_AddEventWatch(SDL_EventFilter filter, void *userdata)
   408 {
   409     SDL_EventWatcher *watcher;
   410 
   411     watcher = (SDL_EventWatcher *)SDL_malloc(sizeof(*watcher));
   412     if (!watcher) {
   413         /* Uh oh... */
   414         return;
   415     }
   416     watcher->callback = filter;
   417     watcher->userdata = userdata;
   418     watcher->next = SDL_event_watchers;
   419     SDL_event_watchers = watcher;
   420 }
   421 
   422 /* FIXME: This is not thread-safe yet */
   423 void
   424 SDL_DelEventWatch(SDL_EventFilter filter, void *userdata)
   425 {
   426     SDL_EventWatcher *prev = NULL;
   427     SDL_EventWatcher *curr;
   428 
   429     for (curr = SDL_event_watchers; curr; prev = curr, curr = curr->next) {
   430         if (curr->callback == filter && curr->userdata == userdata) {
   431             if (prev) {
   432                 prev->next = curr->next;
   433             } else {
   434                 SDL_event_watchers = curr->next;
   435             }
   436             SDL_free(curr);
   437             break;
   438         }
   439     }
   440 }
   441 
   442 void
   443 SDL_FilterEvents(SDL_EventFilter filter, void *userdata)
   444 {
   445     if (SDL_mutexP(SDL_EventQ.lock) == 0) {
   446         int spot;
   447 
   448         spot = SDL_EventQ.head;
   449         while (spot != SDL_EventQ.tail) {
   450             if (filter(userdata, &SDL_EventQ.event[spot])) {
   451                 spot = (spot + 1) % MAXEVENTS;
   452             } else {
   453                 spot = SDL_CutEvent(spot);
   454             }
   455         }
   456     }
   457     SDL_mutexV(SDL_EventQ.lock);
   458 }
   459 
   460 Uint8
   461 SDL_EventState(Uint32 type, int state)
   462 {
   463     Uint8 current_state;
   464     Uint8 hi = ((type >> 8) & 0xff);
   465     Uint8 lo = (type & 0xff);
   466 
   467     if (SDL_disabled_events[hi] &&
   468         (SDL_disabled_events[hi]->bits[lo/32] & (1 << (lo&31)))) {
   469         current_state = SDL_DISABLE;
   470     } else {
   471         current_state = SDL_ENABLE;
   472     }
   473 
   474     if (state != current_state)
   475     {
   476         switch (state) {
   477         case SDL_DISABLE:
   478             /* Disable this event type and discard pending events */
   479             if (!SDL_disabled_events[hi]) {
   480                 SDL_disabled_events[hi] = (SDL_DisabledEventBlock*) SDL_calloc(1, sizeof(SDL_DisabledEventBlock));
   481                 if (!SDL_disabled_events[hi]) {
   482                     /* Out of memory, nothing we can do... */
   483                     break;
   484                 }
   485             }
   486             SDL_disabled_events[hi]->bits[lo/32] |= (1 << (lo&31));
   487             SDL_FlushEvent(type);
   488             break;
   489         case SDL_ENABLE:
   490             SDL_disabled_events[hi]->bits[lo/32] &= ~(1 << (lo&31));
   491             break;
   492         default:
   493             /* Querying state... */
   494             break;
   495         }
   496     }
   497 
   498     return current_state;
   499 }
   500 
   501 Uint32
   502 SDL_RegisterEvents(int numevents)
   503 {
   504     Uint32 event_base;
   505 
   506     if (SDL_userevents+numevents <= SDL_LASTEVENT) {
   507         event_base = SDL_userevents;
   508         SDL_userevents += numevents;
   509     } else {
   510         event_base = (Uint32)-1;
   511     }
   512     return event_base;
   513 }
   514 
   515 /* This is a generic event handler.
   516  */
   517 int
   518 SDL_SendSysWMEvent(SDL_SysWMmsg * message)
   519 {
   520     int posted;
   521 
   522     posted = 0;
   523     if (SDL_GetEventState(SDL_SYSWMEVENT) == SDL_ENABLE) {
   524         SDL_Event event;
   525         SDL_memset(&event, 0, sizeof(event));
   526         event.type = SDL_SYSWMEVENT;
   527         event.syswm.msg = message;
   528         posted = (SDL_PushEvent(&event) > 0);
   529     }
   530     /* Update internal event state */
   531     return (posted);
   532 }
   533 
   534 /* vi: set ts=4 sw=4 expandtab: */