workaround to allow safely unregistering event handlers from within event handlers
fixes #153
This commit is contained in:
parent
49b2a7c93d
commit
ebd8344382
2 changed files with 39 additions and 1 deletions
36
src/events.c
36
src/events.c
|
@ -23,6 +23,7 @@ typedef LIST_ANCHOR(EventHandlerContainer) EventHandlerList;
|
|||
|
||||
static hrtime_t keyrepeat_paused_until;
|
||||
static EventHandlerList global_handlers;
|
||||
static int global_handlers_lock = 0;
|
||||
|
||||
uint32_t sdl_first_user_event;
|
||||
|
||||
|
@ -68,6 +69,7 @@ void events_shutdown(void) {
|
|||
|
||||
static bool events_invoke_handler(SDL_Event *event, EventHandler *handler) {
|
||||
assert(handler->proc != NULL);
|
||||
assert(global_handlers_lock > 0);
|
||||
|
||||
if(!handler->event_type || handler->event_type == event->type) {
|
||||
bool result = handler->proc(event, handler->arg);
|
||||
|
@ -96,7 +98,7 @@ static EventHandlerContainer* ehandler_wrap_container(EventHandler *handler) {
|
|||
return c;
|
||||
}
|
||||
|
||||
static bool events_invoke_handlers(SDL_Event *event, EventHandlerContainer *h_list, EventHandler *h_array) {
|
||||
static bool _events_invoke_handlers(SDL_Event *event, EventHandlerContainer *h_list, EventHandler *h_array) {
|
||||
// invoke handlers from two sources (a list and an array) in the correct order according to priority
|
||||
// list items take precedence
|
||||
//
|
||||
|
@ -110,6 +112,10 @@ static bool events_invoke_handlers(SDL_Event *event, EventHandlerContainer *h_li
|
|||
// case 1 (simplest): we have a list and no custom handlers
|
||||
|
||||
for(EventHandlerContainer *c = h_list; c; c = c->next) {
|
||||
if(c->handler->_private.removal_pending) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if((result = events_invoke_handler(event, c->handler))) {
|
||||
break;
|
||||
}
|
||||
|
@ -141,6 +147,10 @@ static bool events_invoke_handlers(SDL_Event *event, EventHandlerContainer *h_li
|
|||
|
||||
// iterate over the merged list
|
||||
for(EventHandlerContainer *c = merged_list.first; c; c = c->next) {
|
||||
if(c->handler->_private.removal_pending) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if((result = events_invoke_handler(event, c->handler))) {
|
||||
break;
|
||||
}
|
||||
|
@ -166,6 +176,24 @@ static bool events_invoke_handlers(SDL_Event *event, EventHandlerContainer *h_li
|
|||
return result;
|
||||
}
|
||||
|
||||
static bool events_invoke_handlers(SDL_Event *event, EventHandlerContainer *h_list, EventHandler *h_array) {
|
||||
++global_handlers_lock;
|
||||
bool result = _events_invoke_handlers(event, h_list, h_array);
|
||||
|
||||
if(--global_handlers_lock == 0) {
|
||||
for(EventHandlerContainer *c = global_handlers.first, *next; c; c = next) {
|
||||
next = c->next;
|
||||
|
||||
if(c->handler->_private.removal_pending) {
|
||||
free(c->handler);
|
||||
free(alist_unlink(&global_handlers, c));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void events_register_handler(EventHandler *handler) {
|
||||
assert(handler->proc != NULL);
|
||||
EventHandler *handler_alloc = malloc(sizeof(EventHandler));
|
||||
|
@ -192,6 +220,12 @@ void events_unregister_handler(EventHandlerProc proc) {
|
|||
next = c->next;
|
||||
|
||||
if(h->proc == proc) {
|
||||
if(global_handlers_lock) {
|
||||
assert(global_handlers_lock > 0);
|
||||
c->handler->_private.removal_pending = true;
|
||||
return;
|
||||
}
|
||||
|
||||
free(c->handler);
|
||||
free(alist_unlink(&global_handlers, c));
|
||||
return;
|
||||
|
|
|
@ -82,6 +82,10 @@ typedef struct EventHandler {
|
|||
void *arg;
|
||||
EventPriority priority;
|
||||
uint32_t event_type; // if 0, this handler gets all events
|
||||
|
||||
struct {
|
||||
bool removal_pending;
|
||||
} _private;
|
||||
} EventHandler;
|
||||
|
||||
extern uint32_t sdl_first_user_event;
|
||||
|
|
Loading…
Reference in a new issue