|
@@ -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; |
|
|
} |
|
|
|
|
|
entry->event = *event; |
|
|
if (event->type == SDL_SYSWMEVENT) { |
|
|
entry->msg = *event->syswm.msg; |
|
|
} |
|
|
return (added); |
|
|
|
|
|
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; |
|
|
if (entry->prev) { |
|
|
entry->prev->next = entry->next; |
|
|
} |
|
|
if (entry->next) { |
|
|
entry->next->prev = entry->prev; |
|
|
} |
|
|
|
|
|
/* 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 == 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; |
|
|
} |
|
|
/* NOTREACHED */ |
|
|
|
|
|
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,27 +271,55 @@ 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) { |
|
|
action = SDL_PEEKEVENT; |
|
|
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]; |
|
|
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) { |
|
|
spot = SDL_CutEvent(spot); |
|
|
} else { |
|
|
spot = (spot + 1) % MAXEVENTS; |
|
|
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 |
|
|