cscg22-gearboy

CSCG 2022 Challenge 'Gearboy'
git clone https://git.sinitax.com/sinitax/cscg22-gearboy
Log | Files | Refs | sfeed.txt

SDL_events.c (16751B)


      1/*
      2  Simple DirectMedia Layer
      3  Copyright (C) 1997-2014 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_internal.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/* An arbitrary limit so we don't have unbounded growth */
     37#define SDL_MAX_QUEUED_EVENTS   65535
     38
     39/* Public data -- the event filter */
     40SDL_EventFilter SDL_EventOK = NULL;
     41void *SDL_EventOKParam;
     42
     43typedef struct SDL_EventWatcher {
     44    SDL_EventFilter callback;
     45    void *userdata;
     46    struct SDL_EventWatcher *next;
     47} SDL_EventWatcher;
     48
     49static SDL_EventWatcher *SDL_event_watchers = NULL;
     50
     51typedef struct {
     52    Uint32 bits[8];
     53} SDL_DisabledEventBlock;
     54
     55static SDL_DisabledEventBlock *SDL_disabled_events[256];
     56static Uint32 SDL_userevents = SDL_USEREVENT;
     57
     58/* Private data -- event queue */
     59typedef struct _SDL_EventEntry
     60{
     61    SDL_Event event;
     62    SDL_SysWMmsg msg;
     63    struct _SDL_EventEntry *prev;
     64    struct _SDL_EventEntry *next;
     65} SDL_EventEntry;
     66
     67typedef struct _SDL_SysWMEntry
     68{
     69    SDL_SysWMmsg msg;
     70    struct _SDL_SysWMEntry *next;
     71} SDL_SysWMEntry;
     72
     73static struct
     74{
     75    SDL_mutex *lock;
     76    volatile SDL_bool active;
     77    volatile int count;
     78    SDL_EventEntry *head;
     79    SDL_EventEntry *tail;
     80    SDL_EventEntry *free;
     81    SDL_SysWMEntry *wmmsg_used;
     82    SDL_SysWMEntry *wmmsg_free;
     83} SDL_EventQ = { NULL, SDL_TRUE };
     84
     85
     86/* Public functions */
     87
     88void
     89SDL_StopEventLoop(void)
     90{
     91    int i;
     92    SDL_EventEntry *entry;
     93    SDL_SysWMEntry *wmmsg;
     94
     95    if (SDL_EventQ.lock) {
     96        SDL_LockMutex(SDL_EventQ.lock);
     97    }
     98
     99    SDL_EventQ.active = SDL_FALSE;
    100
    101    /* Clean out EventQ */
    102    for (entry = SDL_EventQ.head; entry; ) {
    103        SDL_EventEntry *next = entry->next;
    104        SDL_free(entry);
    105        entry = next;
    106    }
    107    for (entry = SDL_EventQ.free; entry; ) {
    108        SDL_EventEntry *next = entry->next;
    109        SDL_free(entry);
    110        entry = next;
    111    }
    112    for (wmmsg = SDL_EventQ.wmmsg_used; wmmsg; ) {
    113        SDL_SysWMEntry *next = wmmsg->next;
    114        SDL_free(wmmsg);
    115        wmmsg = next;
    116    }
    117    for (wmmsg = SDL_EventQ.wmmsg_free; wmmsg; ) {
    118        SDL_SysWMEntry *next = wmmsg->next;
    119        SDL_free(wmmsg);
    120        wmmsg = next;
    121    }
    122    SDL_EventQ.count = 0;
    123    SDL_EventQ.head = NULL;
    124    SDL_EventQ.tail = NULL;
    125    SDL_EventQ.free = NULL;
    126    SDL_EventQ.wmmsg_used = NULL;
    127    SDL_EventQ.wmmsg_free = NULL;
    128
    129    /* Clear disabled event state */
    130    for (i = 0; i < SDL_arraysize(SDL_disabled_events); ++i) {
    131        SDL_free(SDL_disabled_events[i]);
    132        SDL_disabled_events[i] = NULL;
    133    }
    134
    135    while (SDL_event_watchers) {
    136        SDL_EventWatcher *tmp = SDL_event_watchers;
    137        SDL_event_watchers = tmp->next;
    138        SDL_free(tmp);
    139    }
    140    SDL_EventOK = NULL;
    141
    142    if (SDL_EventQ.lock) {
    143        SDL_UnlockMutex(SDL_EventQ.lock);
    144        SDL_DestroyMutex(SDL_EventQ.lock);
    145        SDL_EventQ.lock = NULL;
    146    }
    147}
    148
    149/* This function (and associated calls) may be called more than once */
    150int
    151SDL_StartEventLoop(void)
    152{
    153    /* We'll leave the event queue alone, since we might have gotten
    154       some important events at launch (like SDL_DROPFILE)
    155
    156       FIXME: Does this introduce any other bugs with events at startup?
    157     */
    158
    159    /* Create the lock and set ourselves active */
    160#if !SDL_THREADS_DISABLED
    161    if (!SDL_EventQ.lock) {
    162        SDL_EventQ.lock = SDL_CreateMutex();
    163    }
    164    if (SDL_EventQ.lock == NULL) {
    165        return (-1);
    166    }
    167#endif /* !SDL_THREADS_DISABLED */
    168
    169    /* Process most event types */
    170    SDL_EventState(SDL_TEXTINPUT, SDL_DISABLE);
    171    SDL_EventState(SDL_TEXTEDITING, SDL_DISABLE);
    172    SDL_EventState(SDL_SYSWMEVENT, SDL_DISABLE);
    173
    174    SDL_EventQ.active = SDL_TRUE;
    175
    176    return (0);
    177}
    178
    179
    180/* Add an event to the event queue -- called with the queue locked */
    181static int
    182SDL_AddEvent(SDL_Event * event)
    183{
    184    SDL_EventEntry *entry;
    185
    186    if (SDL_EventQ.count >= SDL_MAX_QUEUED_EVENTS) {
    187        SDL_SetError("Event queue is full (%d events)", SDL_EventQ.count);
    188        return 0;
    189    }
    190
    191    if (SDL_EventQ.free == NULL) {
    192        entry = (SDL_EventEntry *)SDL_malloc(sizeof(*entry));
    193        if (!entry) {
    194            return 0;
    195        }
    196    } else {
    197        entry = SDL_EventQ.free;
    198        SDL_EventQ.free = entry->next;
    199    }
    200
    201    entry->event = *event;
    202    if (event->type == SDL_SYSWMEVENT) {
    203        entry->msg = *event->syswm.msg;
    204        entry->event.syswm.msg = &entry->msg;
    205    }
    206
    207    if (SDL_EventQ.tail) {
    208        SDL_EventQ.tail->next = entry;
    209        entry->prev = SDL_EventQ.tail;
    210        SDL_EventQ.tail = entry;
    211        entry->next = NULL;
    212    } else {
    213        SDL_assert(!SDL_EventQ.head);
    214        SDL_EventQ.head = entry;
    215        SDL_EventQ.tail = entry;
    216        entry->prev = NULL;
    217        entry->next = NULL;
    218    }
    219    ++SDL_EventQ.count;
    220
    221    return 1;
    222}
    223
    224/* Remove an event from the queue -- called with the queue locked */
    225static void
    226SDL_CutEvent(SDL_EventEntry *entry)
    227{
    228    if (entry->prev) {
    229        entry->prev->next = entry->next;
    230    }
    231    if (entry->next) {
    232        entry->next->prev = entry->prev;
    233    }
    234
    235    if (entry == SDL_EventQ.head) {
    236        SDL_assert(entry->prev == NULL);
    237        SDL_EventQ.head = entry->next;
    238    }
    239    if (entry == SDL_EventQ.tail) {
    240        SDL_assert(entry->next == NULL);
    241        SDL_EventQ.tail = entry->prev;
    242    }
    243
    244    entry->next = SDL_EventQ.free;
    245    SDL_EventQ.free = entry;
    246    SDL_assert(SDL_EventQ.count > 0);
    247    --SDL_EventQ.count;
    248}
    249
    250/* Lock the event queue, take a peep at it, and unlock it */
    251int
    252SDL_PeepEvents(SDL_Event * events, int numevents, SDL_eventaction action,
    253               Uint32 minType, Uint32 maxType)
    254{
    255    int i, used;
    256
    257    /* Don't look after we've quit */
    258    if (!SDL_EventQ.active) {
    259        /* We get a few spurious events at shutdown, so don't warn then */
    260        if (action != SDL_ADDEVENT) {
    261            SDL_SetError("The event system has been shut down");
    262        }
    263        return (-1);
    264    }
    265    /* Lock the event queue */
    266    used = 0;
    267    if (!SDL_EventQ.lock || SDL_LockMutex(SDL_EventQ.lock) == 0) {
    268        if (action == SDL_ADDEVENT) {
    269            for (i = 0; i < numevents; ++i) {
    270                used += SDL_AddEvent(&events[i]);
    271            }
    272        } else {
    273            SDL_EventEntry *entry, *next;
    274            SDL_SysWMEntry *wmmsg, *wmmsg_next;
    275            SDL_Event tmpevent;
    276            Uint32 type;
    277
    278            /* If 'events' is NULL, just see if they exist */
    279            if (events == NULL) {
    280                action = SDL_PEEKEVENT;
    281                numevents = 1;
    282                events = &tmpevent;
    283            }
    284
    285            /* Clean out any used wmmsg data
    286               FIXME: Do we want to retain the data for some period of time?
    287             */
    288            for (wmmsg = SDL_EventQ.wmmsg_used; wmmsg; wmmsg = wmmsg_next) {
    289                wmmsg_next = wmmsg->next;
    290                wmmsg->next = SDL_EventQ.wmmsg_free;
    291                SDL_EventQ.wmmsg_free = wmmsg;
    292            }
    293            SDL_EventQ.wmmsg_used = NULL;
    294
    295            for (entry = SDL_EventQ.head; entry && used < numevents; entry = next) {
    296                next = entry->next;
    297                type = entry->event.type;
    298                if (minType <= type && type <= maxType) {
    299                    events[used] = entry->event;
    300                    if (entry->event.type == SDL_SYSWMEVENT) {
    301                        /* We need to copy the wmmsg somewhere safe.
    302                           For now we'll guarantee it's valid at least until
    303                           the next call to SDL_PeepEvents()
    304                         */
    305                        if (SDL_EventQ.wmmsg_free) {
    306                            wmmsg = SDL_EventQ.wmmsg_free;
    307                            SDL_EventQ.wmmsg_free = wmmsg->next;
    308                        } else {
    309                            wmmsg = (SDL_SysWMEntry *)SDL_malloc(sizeof(*wmmsg));
    310                        }
    311                        wmmsg->msg = *entry->event.syswm.msg;
    312                        wmmsg->next = SDL_EventQ.wmmsg_used;
    313                        SDL_EventQ.wmmsg_used = wmmsg;
    314                        events[used].syswm.msg = &wmmsg->msg;
    315                    }
    316                    ++used;
    317
    318                    if (action == SDL_GETEVENT) {
    319                        SDL_CutEvent(entry);
    320                    }
    321                }
    322            }
    323        }
    324        SDL_UnlockMutex(SDL_EventQ.lock);
    325    } else {
    326        return SDL_SetError("Couldn't lock event queue");
    327    }
    328    return (used);
    329}
    330
    331SDL_bool
    332SDL_HasEvent(Uint32 type)
    333{
    334    return (SDL_PeepEvents(NULL, 0, SDL_PEEKEVENT, type, type) > 0);
    335}
    336
    337SDL_bool
    338SDL_HasEvents(Uint32 minType, Uint32 maxType)
    339{
    340    return (SDL_PeepEvents(NULL, 0, SDL_PEEKEVENT, minType, maxType) > 0);
    341}
    342
    343void
    344SDL_FlushEvent(Uint32 type)
    345{
    346    SDL_FlushEvents(type, type);
    347}
    348
    349void
    350SDL_FlushEvents(Uint32 minType, Uint32 maxType)
    351{
    352    /* Don't look after we've quit */
    353    if (!SDL_EventQ.active) {
    354        return;
    355    }
    356
    357    /* Make sure the events are current */
    358#if 0
    359    /* Actually, we can't do this since we might be flushing while processing
    360       a resize event, and calling this might trigger further resize events.
    361    */
    362    SDL_PumpEvents();
    363#endif
    364
    365    /* Lock the event queue */
    366    if (SDL_LockMutex(SDL_EventQ.lock) == 0) {
    367        SDL_EventEntry *entry, *next;
    368        Uint32 type;
    369        for (entry = SDL_EventQ.head; entry; entry = next) {
    370            next = entry->next;
    371            type = entry->event.type;
    372            if (minType <= type && type <= maxType) {
    373                SDL_CutEvent(entry);
    374            }
    375        }
    376        SDL_UnlockMutex(SDL_EventQ.lock);
    377    }
    378}
    379
    380/* Run the system dependent event loops */
    381void
    382SDL_PumpEvents(void)
    383{
    384    SDL_VideoDevice *_this = SDL_GetVideoDevice();
    385
    386    /* Get events from the video subsystem */
    387    if (_this) {
    388        _this->PumpEvents(_this);
    389    }
    390#if !SDL_JOYSTICK_DISABLED
    391    /* Check for joystick state change */
    392    if ((!SDL_disabled_events[SDL_JOYAXISMOTION >> 8] || SDL_JoystickEventState(SDL_QUERY))) {
    393        SDL_JoystickUpdate();
    394    }
    395#endif
    396}
    397
    398/* Public functions */
    399
    400int
    401SDL_PollEvent(SDL_Event * event)
    402{
    403    return SDL_WaitEventTimeout(event, 0);
    404}
    405
    406int
    407SDL_WaitEvent(SDL_Event * event)
    408{
    409    return SDL_WaitEventTimeout(event, -1);
    410}
    411
    412int
    413SDL_WaitEventTimeout(SDL_Event * event, int timeout)
    414{
    415    Uint32 expiration = 0;
    416
    417    if (timeout > 0)
    418        expiration = SDL_GetTicks() + timeout;
    419
    420    for (;;) {
    421        SDL_PumpEvents();
    422        switch (SDL_PeepEvents(event, 1, SDL_GETEVENT, SDL_FIRSTEVENT, SDL_LASTEVENT)) {
    423        case -1:
    424            return 0;
    425        case 1:
    426            return 1;
    427        case 0:
    428            if (timeout == 0) {
    429                /* Polling and no events, just return */
    430                return 0;
    431            }
    432            if (timeout > 0 && SDL_TICKS_PASSED(SDL_GetTicks(), expiration)) {
    433                /* Timeout expired and no events */
    434                return 0;
    435            }
    436            SDL_Delay(10);
    437            break;
    438        }
    439    }
    440}
    441
    442int
    443SDL_PushEvent(SDL_Event * event)
    444{
    445    SDL_EventWatcher *curr;
    446
    447    event->common.timestamp = SDL_GetTicks();
    448
    449    if (SDL_EventOK && !SDL_EventOK(SDL_EventOKParam, event)) {
    450        return 0;
    451    }
    452
    453    for (curr = SDL_event_watchers; curr; curr = curr->next) {
    454        curr->callback(curr->userdata, event);
    455    }
    456
    457    if (SDL_PeepEvents(event, 1, SDL_ADDEVENT, 0, 0) <= 0) {
    458        return -1;
    459    }
    460
    461    SDL_GestureProcessEvent(event);
    462
    463    return 1;
    464}
    465
    466void
    467SDL_SetEventFilter(SDL_EventFilter filter, void *userdata)
    468{
    469    /* Set filter and discard pending events */
    470    SDL_EventOK = NULL;
    471    SDL_FlushEvents(SDL_FIRSTEVENT, SDL_LASTEVENT);
    472    SDL_EventOKParam = userdata;
    473    SDL_EventOK = filter;
    474}
    475
    476SDL_bool
    477SDL_GetEventFilter(SDL_EventFilter * filter, void **userdata)
    478{
    479    if (filter) {
    480        *filter = SDL_EventOK;
    481    }
    482    if (userdata) {
    483        *userdata = SDL_EventOKParam;
    484    }
    485    return SDL_EventOK ? SDL_TRUE : SDL_FALSE;
    486}
    487
    488/* FIXME: This is not thread-safe yet */
    489void
    490SDL_AddEventWatch(SDL_EventFilter filter, void *userdata)
    491{
    492    SDL_EventWatcher *watcher, *tail;
    493
    494    watcher = (SDL_EventWatcher *)SDL_malloc(sizeof(*watcher));
    495    if (!watcher) {
    496        /* Uh oh... */
    497        return;
    498    }
    499
    500    /* create the watcher */
    501    watcher->callback = filter;
    502    watcher->userdata = userdata;
    503    watcher->next = NULL;
    504
    505    /* add the watcher to the end of the list */
    506    if (SDL_event_watchers) {
    507        for (tail = SDL_event_watchers; tail->next; tail = tail->next) {
    508            continue;
    509        }
    510        tail->next = watcher;
    511    } else {
    512        SDL_event_watchers = watcher;
    513    }
    514}
    515
    516/* FIXME: This is not thread-safe yet */
    517void
    518SDL_DelEventWatch(SDL_EventFilter filter, void *userdata)
    519{
    520    SDL_EventWatcher *prev = NULL;
    521    SDL_EventWatcher *curr;
    522
    523    for (curr = SDL_event_watchers; curr; prev = curr, curr = curr->next) {
    524        if (curr->callback == filter && curr->userdata == userdata) {
    525            if (prev) {
    526                prev->next = curr->next;
    527            } else {
    528                SDL_event_watchers = curr->next;
    529            }
    530            SDL_free(curr);
    531            break;
    532        }
    533    }
    534}
    535
    536void
    537SDL_FilterEvents(SDL_EventFilter filter, void *userdata)
    538{
    539    if (SDL_EventQ.lock && SDL_LockMutex(SDL_EventQ.lock) == 0) {
    540        SDL_EventEntry *entry, *next;
    541        for (entry = SDL_EventQ.head; entry; entry = next) {
    542            next = entry->next;
    543            if (!filter(userdata, &entry->event)) {
    544                SDL_CutEvent(entry);
    545            }
    546        }
    547        SDL_UnlockMutex(SDL_EventQ.lock);
    548    }
    549}
    550
    551Uint8
    552SDL_EventState(Uint32 type, int state)
    553{
    554    Uint8 current_state;
    555    Uint8 hi = ((type >> 8) & 0xff);
    556    Uint8 lo = (type & 0xff);
    557
    558    if (SDL_disabled_events[hi] &&
    559        (SDL_disabled_events[hi]->bits[lo/32] & (1 << (lo&31)))) {
    560        current_state = SDL_DISABLE;
    561    } else {
    562        current_state = SDL_ENABLE;
    563    }
    564
    565    if (state != current_state)
    566    {
    567        switch (state) {
    568        case SDL_DISABLE:
    569            /* Disable this event type and discard pending events */
    570            if (!SDL_disabled_events[hi]) {
    571                SDL_disabled_events[hi] = (SDL_DisabledEventBlock*) SDL_calloc(1, sizeof(SDL_DisabledEventBlock));
    572                if (!SDL_disabled_events[hi]) {
    573                    /* Out of memory, nothing we can do... */
    574                    break;
    575                }
    576            }
    577            SDL_disabled_events[hi]->bits[lo/32] |= (1 << (lo&31));
    578            SDL_FlushEvent(type);
    579            break;
    580        case SDL_ENABLE:
    581            SDL_disabled_events[hi]->bits[lo/32] &= ~(1 << (lo&31));
    582            break;
    583        default:
    584            /* Querying state... */
    585            break;
    586        }
    587    }
    588
    589    return current_state;
    590}
    591
    592Uint32
    593SDL_RegisterEvents(int numevents)
    594{
    595    Uint32 event_base;
    596
    597    if ((numevents > 0) && (SDL_userevents+numevents <= SDL_LASTEVENT)) {
    598        event_base = SDL_userevents;
    599        SDL_userevents += numevents;
    600    } else {
    601        event_base = (Uint32)-1;
    602    }
    603    return event_base;
    604}
    605
    606int
    607SDL_SendAppEvent(SDL_EventType eventType)
    608{
    609    int posted;
    610
    611    posted = 0;
    612    if (SDL_GetEventState(eventType) == SDL_ENABLE) {
    613        SDL_Event event;
    614        event.type = eventType;
    615        posted = (SDL_PushEvent(&event) > 0);
    616    }
    617    return (posted);
    618}
    619
    620int
    621SDL_SendSysWMEvent(SDL_SysWMmsg * message)
    622{
    623    int posted;
    624
    625    posted = 0;
    626    if (SDL_GetEventState(SDL_SYSWMEVENT) == SDL_ENABLE) {
    627        SDL_Event event;
    628        SDL_memset(&event, 0, sizeof(event));
    629        event.type = SDL_SYSWMEVENT;
    630        event.syswm.msg = message;
    631        posted = (SDL_PushEvent(&event) > 0);
    632    }
    633    /* Update internal event state */
    634    return (posted);
    635}
    636
    637/* vi: set ts=4 sw=4 expandtab: */