src/events/SDL_events.c
author Ryan C. Gordon
Sun, 31 Mar 2013 12:48:50 -0400
changeset 7037 3fedf1f25b94
parent 6977 b73d51026c68
child 7077 f8e3dcefed59
child 8461 ca8dad9be3d4
permissions -rw-r--r--
Make SDL_SetError and friends unconditionally return -1.

This lets us change things like this...

if (Failed) {
SDL_SetError("We failed");
return -1;
}

...into this...

if (Failed) {
return SDL_SetError("We failed");
}


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