Made the SDL event queue dynamically allocated so we don't ever drop events.
This commit is contained in:
parent
ad82c94c55
commit
e0fe2d1b2c
1 changed files with 161 additions and 84 deletions
|
@ -53,17 +53,30 @@ static SDL_DisabledEventBlock *SDL_disabled_events[256];
|
|||
static Uint32 SDL_userevents = SDL_USEREVENT;
|
||||
|
||||
/* Private data -- event queue */
|
||||
#define MAXEVENTS 128
|
||||
typedef struct _SDL_EventEntry
|
||||
{
|
||||
SDL_Event event;
|
||||
SDL_SysWMmsg msg;
|
||||
struct _SDL_EventEntry *prev;
|
||||
struct _SDL_EventEntry *next;
|
||||
} SDL_EventEntry;
|
||||
|
||||
typedef struct _SDL_SysWMEntry
|
||||
{
|
||||
SDL_SysWMmsg msg;
|
||||
struct _SDL_SysWMEntry *next;
|
||||
} SDL_SysWMEntry;
|
||||
|
||||
static struct
|
||||
{
|
||||
SDL_mutex *lock;
|
||||
int active;
|
||||
int head;
|
||||
int tail;
|
||||
SDL_Event event[MAXEVENTS];
|
||||
int wmmsg_next;
|
||||
struct SDL_SysWMmsg wmmsg[MAXEVENTS];
|
||||
} SDL_EventQ = { NULL, 1 };
|
||||
volatile SDL_bool active;
|
||||
SDL_EventEntry *head;
|
||||
SDL_EventEntry *tail;
|
||||
SDL_EventEntry *free;
|
||||
SDL_SysWMEntry *wmmsg_used;
|
||||
SDL_SysWMEntry *wmmsg_free;
|
||||
} SDL_EventQ = { NULL, SDL_TRUE };
|
||||
|
||||
|
||||
static __inline__ SDL_bool
|
||||
|
@ -85,18 +98,41 @@ void
|
|||
SDL_StopEventLoop(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
SDL_EventQ.active = 0;
|
||||
SDL_EventEntry *entry;
|
||||
SDL_SysWMEntry *wmmsg;
|
||||
|
||||
if (SDL_EventQ.lock) {
|
||||
SDL_DestroyMutex(SDL_EventQ.lock);
|
||||
SDL_EventQ.lock = NULL;
|
||||
SDL_LockMutex(SDL_EventQ.lock);
|
||||
}
|
||||
|
||||
SDL_EventQ.active = SDL_FALSE;
|
||||
|
||||
/* Clean out EventQ */
|
||||
SDL_EventQ.head = 0;
|
||||
SDL_EventQ.tail = 0;
|
||||
SDL_EventQ.wmmsg_next = 0;
|
||||
for (entry = SDL_EventQ.head; entry; ) {
|
||||
SDL_EventEntry *next = entry->next;
|
||||
SDL_free(entry);
|
||||
entry = next;
|
||||
}
|
||||
for (entry = SDL_EventQ.free; entry; ) {
|
||||
SDL_EventEntry *next = entry->next;
|
||||
SDL_free(entry);
|
||||
entry = next;
|
||||
}
|
||||
for (wmmsg = SDL_EventQ.wmmsg_used; wmmsg; ) {
|
||||
SDL_SysWMEntry *next = wmmsg->next;
|
||||
SDL_free(wmmsg);
|
||||
wmmsg = next;
|
||||
}
|
||||
for (wmmsg = SDL_EventQ.wmmsg_free; wmmsg; ) {
|
||||
SDL_SysWMEntry *next = wmmsg->next;
|
||||
SDL_free(wmmsg);
|
||||
wmmsg = next;
|
||||
}
|
||||
SDL_EventQ.head = NULL;
|
||||
SDL_EventQ.tail = NULL;
|
||||
SDL_EventQ.free = NULL;
|
||||
SDL_EventQ.wmmsg_used = NULL;
|
||||
SDL_EventQ.wmmsg_free = NULL;
|
||||
|
||||
/* Clear disabled event state */
|
||||
for (i = 0; i < SDL_arraysize(SDL_disabled_events); ++i) {
|
||||
|
@ -112,6 +148,12 @@ SDL_StopEventLoop(void)
|
|||
SDL_free(tmp);
|
||||
}
|
||||
SDL_EventOK = NULL;
|
||||
|
||||
if (SDL_EventQ.lock) {
|
||||
SDL_UnlockMutex(SDL_EventQ.lock);
|
||||
SDL_DestroyMutex(SDL_EventQ.lock);
|
||||
SDL_EventQ.lock = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* This function (and associated calls) may be called more than once */
|
||||
|
@ -139,7 +181,7 @@ SDL_StartEventLoop(void)
|
|||
SDL_EventState(SDL_TEXTEDITING, SDL_DISABLE);
|
||||
SDL_EventState(SDL_SYSWMEVENT, SDL_DISABLE);
|
||||
|
||||
SDL_EventQ.active = 1;
|
||||
SDL_EventQ.active = SDL_TRUE;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
@ -149,55 +191,61 @@ SDL_StartEventLoop(void)
|
|||
static int
|
||||
SDL_AddEvent(SDL_Event * event)
|
||||
{
|
||||
int tail, added;
|
||||
SDL_EventEntry *entry;
|
||||
|
||||
tail = (SDL_EventQ.tail + 1) % MAXEVENTS;
|
||||
if (tail == SDL_EventQ.head) {
|
||||
/* Overflow, drop event */
|
||||
added = 0;
|
||||
} else {
|
||||
SDL_EventQ.event[SDL_EventQ.tail] = *event;
|
||||
if (event->type == SDL_SYSWMEVENT) {
|
||||
/* Note that it's possible to lose an event */
|
||||
int next = SDL_EventQ.wmmsg_next;
|
||||
SDL_EventQ.wmmsg[next] = *event->syswm.msg;
|
||||
SDL_EventQ.event[SDL_EventQ.tail].syswm.msg =
|
||||
&SDL_EventQ.wmmsg[next];
|
||||
SDL_EventQ.wmmsg_next = (next + 1) % MAXEVENTS;
|
||||
if (SDL_EventQ.free == NULL) {
|
||||
entry = (SDL_EventEntry *)SDL_malloc(sizeof(*entry));
|
||||
if (!entry) {
|
||||
return 0;
|
||||
}
|
||||
SDL_EventQ.tail = tail;
|
||||
added = 1;
|
||||
} else {
|
||||
entry = SDL_EventQ.free;
|
||||
SDL_EventQ.free = entry->next;
|
||||
}
|
||||
return (added);
|
||||
|
||||
entry->event = *event;
|
||||
if (event->type == SDL_SYSWMEVENT) {
|
||||
entry->msg = *event->syswm.msg;
|
||||
}
|
||||
|
||||
if (SDL_EventQ.tail) {
|
||||
SDL_EventQ.tail->next = entry;
|
||||
entry->prev = SDL_EventQ.tail;
|
||||
SDL_EventQ.tail = entry;
|
||||
entry->next = NULL;
|
||||
} else {
|
||||
SDL_assert(!SDL_EventQ.head);
|
||||
SDL_EventQ.head = entry;
|
||||
SDL_EventQ.tail = entry;
|
||||
entry->prev = NULL;
|
||||
entry->next = NULL;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Cut an event, and return the next valid spot, or the tail */
|
||||
/* -- called with the queue locked */
|
||||
static int
|
||||
SDL_CutEvent(int spot)
|
||||
/* Remove an event from the queue -- called with the queue locked */
|
||||
static void
|
||||
SDL_CutEvent(SDL_EventEntry *entry)
|
||||
{
|
||||
if (spot == SDL_EventQ.head) {
|
||||
SDL_EventQ.head = (SDL_EventQ.head + 1) % MAXEVENTS;
|
||||
return (SDL_EventQ.head);
|
||||
} else if ((spot + 1) % MAXEVENTS == SDL_EventQ.tail) {
|
||||
SDL_EventQ.tail = spot;
|
||||
return (SDL_EventQ.tail);
|
||||
} else
|
||||
/* We cut the middle -- shift everything over */
|
||||
{
|
||||
int here, next;
|
||||
|
||||
/* This can probably be optimized with SDL_memcpy() -- careful! */
|
||||
if (--SDL_EventQ.tail < 0) {
|
||||
SDL_EventQ.tail = MAXEVENTS - 1;
|
||||
}
|
||||
for (here = spot; here != SDL_EventQ.tail; here = next) {
|
||||
next = (here + 1) % MAXEVENTS;
|
||||
SDL_EventQ.event[here] = SDL_EventQ.event[next];
|
||||
}
|
||||
return (spot);
|
||||
if (entry->prev) {
|
||||
entry->prev->next = entry->next;
|
||||
}
|
||||
/* NOTREACHED */
|
||||
if (entry->next) {
|
||||
entry->next->prev = entry->prev;
|
||||
}
|
||||
|
||||
if (entry == SDL_EventQ.head) {
|
||||
SDL_assert(entry->prev == NULL);
|
||||
SDL_EventQ.head = entry->next;
|
||||
}
|
||||
if (entry == SDL_EventQ.tail) {
|
||||
SDL_assert(entry->next == NULL);
|
||||
SDL_EventQ.tail = entry->prev;
|
||||
}
|
||||
|
||||
entry->next = SDL_EventQ.free;
|
||||
SDL_EventQ.free = entry;
|
||||
}
|
||||
|
||||
/* Lock the event queue, take a peep at it, and unlock it */
|
||||
|
@ -209,6 +257,10 @@ SDL_PeepEvents(SDL_Event * events, int numevents, SDL_eventaction action,
|
|||
|
||||
/* Don't look after we've quit */
|
||||
if (!SDL_EventQ.active) {
|
||||
/* We get a few spurious events at shutdown, so don't warn then */
|
||||
if (action != SDL_ADDEVENT) {
|
||||
SDL_SetError("The event system has been shut down");
|
||||
}
|
||||
return (-1);
|
||||
}
|
||||
/* Lock the event queue */
|
||||
|
@ -219,8 +271,10 @@ SDL_PeepEvents(SDL_Event * events, int numevents, SDL_eventaction action,
|
|||
used += SDL_AddEvent(&events[i]);
|
||||
}
|
||||
} else {
|
||||
SDL_EventEntry *entry, *next;
|
||||
SDL_SysWMEntry *wmmsg, *wmmsg_next;
|
||||
SDL_Event tmpevent;
|
||||
int spot;
|
||||
Uint32 type;
|
||||
|
||||
/* If 'events' is NULL, just see if they exist */
|
||||
if (events == NULL) {
|
||||
|
@ -228,18 +282,44 @@ SDL_PeepEvents(SDL_Event * events, int numevents, SDL_eventaction action,
|
|||
numevents = 1;
|
||||
events = &tmpevent;
|
||||
}
|
||||
spot = SDL_EventQ.head;
|
||||
while ((used < numevents) && (spot != SDL_EventQ.tail)) {
|
||||
Uint32 type = SDL_EventQ.event[spot].type;
|
||||
|
||||
/* Clean out any used wmmsg data
|
||||
FIXME: Do we want to retain the data for some period of time?
|
||||
*/
|
||||
for (wmmsg = SDL_EventQ.wmmsg_used; wmmsg; wmmsg = wmmsg_next) {
|
||||
wmmsg_next = wmmsg->next;
|
||||
wmmsg->next = SDL_EventQ.wmmsg_free;
|
||||
SDL_EventQ.wmmsg_free = wmmsg;
|
||||
}
|
||||
SDL_EventQ.wmmsg_used = NULL;
|
||||
|
||||
for (entry = SDL_EventQ.head; entry && used < numevents; entry = next) {
|
||||
next = entry->next;
|
||||
type = entry->event.type;
|
||||
if (minType <= type && type <= maxType) {
|
||||
events[used++] = SDL_EventQ.event[spot];
|
||||
if (action == SDL_GETEVENT) {
|
||||
spot = SDL_CutEvent(spot);
|
||||
} else {
|
||||
spot = (spot + 1) % MAXEVENTS;
|
||||
events[used] = entry->event;
|
||||
if (entry->event.type == SDL_SYSWMEVENT) {
|
||||
/* We need to copy the wmmsg somewhere safe.
|
||||
For now we'll guarantee it's valid at least until
|
||||
the next call to SDL_PeepEvents()
|
||||
*/
|
||||
SDL_SysWMEntry *wmmsg;
|
||||
if (SDL_EventQ.wmmsg_free) {
|
||||
wmmsg = SDL_EventQ.wmmsg_free;
|
||||
SDL_EventQ.wmmsg_free = wmmsg->next;
|
||||
} else {
|
||||
wmmsg = (SDL_SysWMEntry *)SDL_malloc(sizeof(*wmmsg));
|
||||
}
|
||||
wmmsg->msg = *entry->event.syswm.msg;
|
||||
wmmsg->next = SDL_EventQ.wmmsg_used;
|
||||
SDL_EventQ.wmmsg_used = wmmsg;
|
||||
events[used].syswm.msg = &wmmsg->msg;
|
||||
}
|
||||
++used;
|
||||
|
||||
if (action == SDL_GETEVENT) {
|
||||
SDL_CutEvent(entry);
|
||||
}
|
||||
} else {
|
||||
spot = (spot + 1) % MAXEVENTS;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -286,13 +366,13 @@ SDL_FlushEvents(Uint32 minType, Uint32 maxType)
|
|||
|
||||
/* Lock the event queue */
|
||||
if (SDL_LockMutex(SDL_EventQ.lock) == 0) {
|
||||
int spot = SDL_EventQ.head;
|
||||
while (spot != SDL_EventQ.tail) {
|
||||
Uint32 type = SDL_EventQ.event[spot].type;
|
||||
SDL_EventEntry *entry, *next;
|
||||
Uint32 type;
|
||||
for (entry = SDL_EventQ.head; entry; entry = next) {
|
||||
next = entry->next;
|
||||
type = entry->event.type;
|
||||
if (minType <= type && type <= maxType) {
|
||||
spot = SDL_CutEvent(spot);
|
||||
} else {
|
||||
spot = (spot + 1) % MAXEVENTS;
|
||||
SDL_CutEvent(entry);
|
||||
}
|
||||
}
|
||||
SDL_UnlockMutex(SDL_EventQ.lock);
|
||||
|
@ -448,18 +528,15 @@ void
|
|||
SDL_FilterEvents(SDL_EventFilter filter, void *userdata)
|
||||
{
|
||||
if (SDL_LockMutex(SDL_EventQ.lock) == 0) {
|
||||
int spot;
|
||||
|
||||
spot = SDL_EventQ.head;
|
||||
while (spot != SDL_EventQ.tail) {
|
||||
if (filter(userdata, &SDL_EventQ.event[spot])) {
|
||||
spot = (spot + 1) % MAXEVENTS;
|
||||
} else {
|
||||
spot = SDL_CutEvent(spot);
|
||||
SDL_EventEntry *entry, *next;
|
||||
for (entry = SDL_EventQ.head; entry; entry = next) {
|
||||
next = entry->next;
|
||||
if (!filter(userdata, &entry->event)) {
|
||||
SDL_CutEvent(entry);
|
||||
}
|
||||
}
|
||||
SDL_UnlockMutex(SDL_EventQ.lock);
|
||||
}
|
||||
SDL_UnlockMutex(SDL_EventQ.lock);
|
||||
}
|
||||
|
||||
Uint8
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue