src/events/SDL_events.c
author Sam Lantinga <slouken@libsdl.org>
Fri, 09 Nov 2012 02:18:27 -0800
changeset 6670 d4883f657288
parent 6668 59c7c2db7638
child 6690 9548c8a58103
permissions -rw-r--r--
We can't check for the screen keyboard in the event code because the video system isn't fully initialized yet.
     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 = { NULL, 1 };
    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     /* We'll leave the event queue alone, since we might have gotten
   121        some important events at launch (like SDL_DROPFILE)
   122 
   123        FIXME: Does this introduce any other bugs with events at startup?
   124      */
   125 
   126     /* No filter to start with, process most event types */
   127     SDL_EventOK = NULL;
   128     SDL_EventState(SDL_TEXTINPUT, SDL_DISABLE);
   129     SDL_EventState(SDL_TEXTEDITING, SDL_DISABLE);
   130     SDL_EventState(SDL_SYSWMEVENT, SDL_DISABLE);
   131 
   132     /* Create the lock and set ourselves active */
   133 #if !SDL_THREADS_DISABLED
   134     if (!SDL_EventQ.lock) {
   135         SDL_EventQ.lock = SDL_CreateMutex();
   136     }
   137     if (SDL_EventQ.lock == NULL) {
   138         return (-1);
   139     }
   140 #endif /* !SDL_THREADS_DISABLED */
   141     SDL_EventQ.active = 1;
   142 
   143     return (0);
   144 }
   145 
   146 
   147 /* Add an event to the event queue -- called with the queue locked */
   148 static int
   149 SDL_AddEvent(SDL_Event * event)
   150 {
   151     int tail, added;
   152 
   153     tail = (SDL_EventQ.tail + 1) % MAXEVENTS;
   154     if (tail == SDL_EventQ.head) {
   155         /* Overflow, drop event */
   156         added = 0;
   157     } else {
   158         SDL_EventQ.event[SDL_EventQ.tail] = *event;
   159         if (event->type == SDL_SYSWMEVENT) {
   160             /* Note that it's possible to lose an event */
   161             int next = SDL_EventQ.wmmsg_next;
   162             SDL_EventQ.wmmsg[next] = *event->syswm.msg;
   163             SDL_EventQ.event[SDL_EventQ.tail].syswm.msg =
   164                 &SDL_EventQ.wmmsg[next];
   165             SDL_EventQ.wmmsg_next = (next + 1) % MAXEVENTS;
   166         }
   167         SDL_EventQ.tail = tail;
   168         added = 1;
   169     }
   170     return (added);
   171 }
   172 
   173 /* Cut an event, and return the next valid spot, or the tail */
   174 /*                           -- called with the queue locked */
   175 static int
   176 SDL_CutEvent(int spot)
   177 {
   178     if (spot == SDL_EventQ.head) {
   179         SDL_EventQ.head = (SDL_EventQ.head + 1) % MAXEVENTS;
   180         return (SDL_EventQ.head);
   181     } else if ((spot + 1) % MAXEVENTS == SDL_EventQ.tail) {
   182         SDL_EventQ.tail = spot;
   183         return (SDL_EventQ.tail);
   184     } else
   185         /* We cut the middle -- shift everything over */
   186     {
   187         int here, next;
   188 
   189         /* This can probably be optimized with SDL_memcpy() -- careful! */
   190         if (--SDL_EventQ.tail < 0) {
   191             SDL_EventQ.tail = MAXEVENTS - 1;
   192         }
   193         for (here = spot; here != SDL_EventQ.tail; here = next) {
   194             next = (here + 1) % MAXEVENTS;
   195             SDL_EventQ.event[here] = SDL_EventQ.event[next];
   196         }
   197         return (spot);
   198     }
   199     /* NOTREACHED */
   200 }
   201 
   202 /* Lock the event queue, take a peep at it, and unlock it */
   203 int
   204 SDL_PeepEvents(SDL_Event * events, int numevents, SDL_eventaction action,
   205                Uint32 minType, Uint32 maxType)
   206 {
   207     int i, used;
   208 
   209     /* Don't look after we've quit */
   210     if (!SDL_EventQ.active) {
   211         return (-1);
   212     }
   213     /* Lock the event queue */
   214     used = 0;
   215     if (!SDL_EventQ.lock || SDL_mutexP(SDL_EventQ.lock) == 0) {
   216         if (action == SDL_ADDEVENT) {
   217             for (i = 0; i < numevents; ++i) {
   218                 used += SDL_AddEvent(&events[i]);
   219             }
   220         } else {
   221             SDL_Event tmpevent;
   222             int spot;
   223 
   224             /* If 'events' is NULL, just see if they exist */
   225             if (events == NULL) {
   226                 action = SDL_PEEKEVENT;
   227                 numevents = 1;
   228                 events = &tmpevent;
   229             }
   230             spot = SDL_EventQ.head;
   231             while ((used < numevents) && (spot != SDL_EventQ.tail)) {
   232                 Uint32 type = SDL_EventQ.event[spot].type;
   233                 if (minType <= type && type <= maxType) {
   234                     events[used++] = SDL_EventQ.event[spot];
   235                     if (action == SDL_GETEVENT) {
   236                         spot = SDL_CutEvent(spot);
   237                     } else {
   238                         spot = (spot + 1) % MAXEVENTS;
   239                     }
   240                 } else {
   241                     spot = (spot + 1) % MAXEVENTS;
   242                 }
   243             }
   244         }
   245         SDL_mutexV(SDL_EventQ.lock);
   246     } else {
   247         SDL_SetError("Couldn't lock event queue");
   248         used = -1;
   249     }
   250     return (used);
   251 }
   252 
   253 SDL_bool
   254 SDL_HasEvent(Uint32 type)
   255 {
   256     return (SDL_PeepEvents(NULL, 0, SDL_PEEKEVENT, type, type) > 0);
   257 }
   258 
   259 SDL_bool
   260 SDL_HasEvents(Uint32 minType, Uint32 maxType)
   261 {
   262     return (SDL_PeepEvents(NULL, 0, SDL_PEEKEVENT, minType, maxType) > 0);
   263 }
   264 
   265 void
   266 SDL_FlushEvent(Uint32 type)
   267 {
   268     SDL_FlushEvents(type, type);
   269 }
   270 
   271 void
   272 SDL_FlushEvents(Uint32 minType, Uint32 maxType)
   273 {
   274     /* Don't look after we've quit */
   275     if (!SDL_EventQ.active) {
   276         return;
   277     }
   278 
   279     /* Make sure the events are current */
   280 #if 0
   281     /* Actually, we can't do this since we might be flushing while processing
   282        a resize event, and calling this might trigger further resize events.
   283     */
   284     SDL_PumpEvents();
   285 #endif
   286 
   287     /* Lock the event queue */
   288     if (SDL_mutexP(SDL_EventQ.lock) == 0) {
   289         int spot = SDL_EventQ.head;
   290         while (spot != SDL_EventQ.tail) {
   291             Uint32 type = SDL_EventQ.event[spot].type;
   292             if (minType <= type && type <= maxType) {
   293                 spot = SDL_CutEvent(spot);
   294             } else {
   295                 spot = (spot + 1) % MAXEVENTS;
   296             }
   297         }
   298         SDL_mutexV(SDL_EventQ.lock);
   299     }
   300 }
   301 
   302 /* Run the system dependent event loops */
   303 void
   304 SDL_PumpEvents(void)
   305 {
   306     SDL_VideoDevice *_this = SDL_GetVideoDevice();
   307 
   308     /* Get events from the video subsystem */
   309     if (_this) {
   310         _this->PumpEvents(_this);
   311     }
   312 #if !SDL_JOYSTICK_DISABLED
   313     /* Check for joystick state change */
   314     if (SDL_ShouldPollJoystick()) {
   315         SDL_JoystickUpdate();
   316     }
   317 #endif
   318 }
   319 
   320 /* Public functions */
   321 
   322 int
   323 SDL_PollEvent(SDL_Event * event)
   324 {
   325     return SDL_WaitEventTimeout(event, 0);
   326 }
   327 
   328 int
   329 SDL_WaitEvent(SDL_Event * event)
   330 {
   331     return SDL_WaitEventTimeout(event, -1);
   332 }
   333 
   334 int
   335 SDL_WaitEventTimeout(SDL_Event * event, int timeout)
   336 {
   337     Uint32 expiration = 0;
   338 
   339     if (timeout > 0)
   340         expiration = SDL_GetTicks() + timeout;
   341 
   342     for (;;) {
   343         SDL_PumpEvents();
   344         switch (SDL_PeepEvents(event, 1, SDL_GETEVENT, SDL_FIRSTEVENT, SDL_LASTEVENT)) {
   345         case -1:
   346             return 0;
   347         case 1:
   348             return 1;
   349         case 0:
   350             if (timeout == 0) {
   351                 /* Polling and no events, just return */
   352                 return 0;
   353             }
   354             if (timeout > 0 && ((int) (SDL_GetTicks() - expiration) >= 0)) {
   355                 /* Timeout expired and no events */
   356                 return 0;
   357             }
   358             SDL_Delay(10);
   359             break;
   360         }
   361     }
   362 }
   363 
   364 int
   365 SDL_PushEvent(SDL_Event * event)
   366 {
   367     SDL_EventWatcher *curr;
   368     event->window.timestamp = SDL_GetTicks();
   369     if (SDL_EventOK && !SDL_EventOK(SDL_EventOKParam, event)) {
   370         return 0;
   371     }
   372 
   373     for (curr = SDL_event_watchers; curr; curr = curr->next) {
   374         curr->callback(curr->userdata, event);
   375     }
   376 
   377     if (SDL_PeepEvents(event, 1, SDL_ADDEVENT, 0, 0) <= 0) {
   378         return -1;
   379     }
   380 
   381     SDL_GestureProcessEvent(event);
   382 
   383     return 1;
   384 }
   385 
   386 void
   387 SDL_SetEventFilter(SDL_EventFilter filter, void *userdata)
   388 {
   389     SDL_Event bitbucket;
   390 
   391     /* Set filter and discard pending events */
   392     SDL_EventOK = filter;
   393     SDL_EventOKParam = userdata;
   394     while (SDL_PollEvent(&bitbucket) > 0);
   395 }
   396 
   397 SDL_bool
   398 SDL_GetEventFilter(SDL_EventFilter * filter, void **userdata)
   399 {
   400     if (filter) {
   401         *filter = SDL_EventOK;
   402     }
   403     if (userdata) {
   404         *userdata = SDL_EventOKParam;
   405     }
   406     return SDL_EventOK ? SDL_TRUE : SDL_FALSE;
   407 }
   408 
   409 /* FIXME: This is not thread-safe yet */
   410 void
   411 SDL_AddEventWatch(SDL_EventFilter filter, void *userdata)
   412 {
   413     SDL_EventWatcher *watcher;
   414 
   415     watcher = (SDL_EventWatcher *)SDL_malloc(sizeof(*watcher));
   416     if (!watcher) {
   417         /* Uh oh... */
   418         return;
   419     }
   420     watcher->callback = filter;
   421     watcher->userdata = userdata;
   422     watcher->next = SDL_event_watchers;
   423     SDL_event_watchers = watcher;
   424 }
   425 
   426 /* FIXME: This is not thread-safe yet */
   427 void
   428 SDL_DelEventWatch(SDL_EventFilter filter, void *userdata)
   429 {
   430     SDL_EventWatcher *prev = NULL;
   431     SDL_EventWatcher *curr;
   432 
   433     for (curr = SDL_event_watchers; curr; prev = curr, curr = curr->next) {
   434         if (curr->callback == filter && curr->userdata == userdata) {
   435             if (prev) {
   436                 prev->next = curr->next;
   437             } else {
   438                 SDL_event_watchers = curr->next;
   439             }
   440             SDL_free(curr);
   441             break;
   442         }
   443     }
   444 }
   445 
   446 void
   447 SDL_FilterEvents(SDL_EventFilter filter, void *userdata)
   448 {
   449     if (SDL_mutexP(SDL_EventQ.lock) == 0) {
   450         int spot;
   451 
   452         spot = SDL_EventQ.head;
   453         while (spot != SDL_EventQ.tail) {
   454             if (filter(userdata, &SDL_EventQ.event[spot])) {
   455                 spot = (spot + 1) % MAXEVENTS;
   456             } else {
   457                 spot = SDL_CutEvent(spot);
   458             }
   459         }
   460     }
   461     SDL_mutexV(SDL_EventQ.lock);
   462 }
   463 
   464 Uint8
   465 SDL_EventState(Uint32 type, int state)
   466 {
   467     Uint8 current_state;
   468     Uint8 hi = ((type >> 8) & 0xff);
   469     Uint8 lo = (type & 0xff);
   470 
   471     if (SDL_disabled_events[hi] &&
   472         (SDL_disabled_events[hi]->bits[lo/32] & (1 << (lo&31)))) {
   473         current_state = SDL_DISABLE;
   474     } else {
   475         current_state = SDL_ENABLE;
   476     }
   477 
   478     if (state != current_state)
   479     {
   480         switch (state) {
   481         case SDL_DISABLE:
   482             /* Disable this event type and discard pending events */
   483             if (!SDL_disabled_events[hi]) {
   484                 SDL_disabled_events[hi] = (SDL_DisabledEventBlock*) SDL_calloc(1, sizeof(SDL_DisabledEventBlock));
   485                 if (!SDL_disabled_events[hi]) {
   486                     /* Out of memory, nothing we can do... */
   487                     break;
   488                 }
   489             }
   490             SDL_disabled_events[hi]->bits[lo/32] |= (1 << (lo&31));
   491             SDL_FlushEvent(type);
   492             break;
   493         case SDL_ENABLE:
   494             SDL_disabled_events[hi]->bits[lo/32] &= ~(1 << (lo&31));
   495             break;
   496         default:
   497             /* Querying state... */
   498             break;
   499         }
   500     }
   501 
   502     return current_state;
   503 }
   504 
   505 Uint32
   506 SDL_RegisterEvents(int numevents)
   507 {
   508     Uint32 event_base;
   509 
   510     if (SDL_userevents+numevents <= SDL_LASTEVENT) {
   511         event_base = SDL_userevents;
   512         SDL_userevents += numevents;
   513     } else {
   514         event_base = (Uint32)-1;
   515     }
   516     return event_base;
   517 }
   518 
   519 /* This is a generic event handler.
   520  */
   521 int
   522 SDL_SendSysWMEvent(SDL_SysWMmsg * message)
   523 {
   524     int posted;
   525 
   526     posted = 0;
   527     if (SDL_GetEventState(SDL_SYSWMEVENT) == SDL_ENABLE) {
   528         SDL_Event event;
   529         SDL_memset(&event, 0, sizeof(event));
   530         event.type = SDL_SYSWMEVENT;
   531         event.syswm.msg = message;
   532         posted = (SDL_PushEvent(&event) > 0);
   533     }
   534     /* Update internal event state */
   535     return (posted);
   536 }
   537 
   538 /* vi: set ts=4 sw=4 expandtab: */