src/events/SDL_events.c
author Sam Lantinga <slouken@libsdl.org>
Sat, 22 Feb 2014 15:27:11 -0800
changeset 8234 80c193c7c8c8
parent 8149 681eb46b8ac4
child 8583 fb2933ca805f
permissions -rw-r--r--
Fixed bug 2414 - Execute event watchers in the order they were added

Leonardo

Event watchers are being executed on the inverse order they are added because they are added to the head of the SDL_event_watchers list.

Since watchers are allowed to change events before they are reported (they shouldn't, imo), this breaks code that rely on watcher execution order (such as distributed event handling).

An easy scenario to see this behaving weird to the user is if you add an event watcher to check mouse coordinates and check them again in your event loop. If you add the watcher after renderer's one (which always happens after you have initialized renderer), you get the same event but different coordinates.

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