X-Git-Url: https://git.stderr.nl/gitweb?a=blobdiff_plain;f=src%2Fevent.c;h=d7cb6596cbdd61611536bfe981c5116351b750a5;hb=753658fb32fd78c0887e018892a0ad91b424e728;hp=0334e3925129618a3b21d1a747a04a44c656d119;hpb=49eca40060b04105343874714fa67976b9430def;p=rodin%2Fchimara.git diff --git a/src/event.c b/src/event.c index 0334e39..d7cb659 100644 --- a/src/event.c +++ b/src/event.c @@ -1,98 +1,94 @@ #include "event.h" +#include "magic.h" +#include "glk.h" +#include -static GQueue *event_queue = NULL; -static GMutex *event_lock = NULL; -static GCond *event_queue_not_empty = NULL; -static GCond *event_queue_not_full = NULL; +#include "chimara-glk-private.h" -void -events_init() -{ - event_queue = g_queue_new(); - event_lock = g_mutex_new(); - event_queue_not_empty = g_cond_new(); - event_queue_not_full = g_cond_new(); -} +extern ChimaraGlkPrivate *glk_data; -static void -event_free(gpointer data, gpointer user_data) -{ - g_free(data); -} - -void -events_free() -{ - g_queue_foreach(event_queue, event_free, NULL); - g_queue_free(event_queue); - g_mutex_free(event_lock); - g_cond_free(event_queue_not_empty); - g_cond_free(event_queue_not_full); -} +#define EVENT_TIMEOUT_MICROSECONDS (3000000) +/* Internal function: push an event onto the event queue. If the event queue is +full, wait for max three seconds and then drop the event. If the event queue is +NULL, i.e. freed, then fail silently. */ void event_throw(glui32 type, winid_t win, glui32 val1, glui32 val2) { + if(!glk_data->event_queue) + return; + GTimeVal timeout; g_get_current_time(&timeout); - g_time_val_add(&timeout, 3000000); /* 3 Seconds */ + g_time_val_add(&timeout, EVENT_TIMEOUT_MICROSECONDS); + + g_mutex_lock(glk_data->event_lock); /* Wait for room in the event queue */ - g_mutex_lock(event_lock); - if( g_queue_get_length(event_queue) >= EVENT_QUEUE_MAX_LENGTH ) { - if( !g_cond_timed_wait(event_queue_not_full, event_lock, &timeout) ) { - /* Drop the event */ - g_mutex_unlock(event_lock); + while( g_queue_get_length(glk_data->event_queue) >= EVENT_QUEUE_MAX_LENGTH ) + if( !g_cond_timed_wait(glk_data->event_queue_not_full, glk_data->event_lock, &timeout) ) + { + /* Drop the event after 3 seconds */ + g_mutex_unlock(glk_data->event_lock); return; } - } event_t *event = g_new0(event_t, 1); event->type = type; event->win = win; event->val1 = val1; event->val2 = val2; - - g_queue_push_head(event_queue, event); + g_queue_push_head(glk_data->event_queue, event); /* Signal that there is an event */ - g_cond_signal(event_queue_not_empty); + g_cond_signal(glk_data->event_queue_not_empty); - g_mutex_unlock(event_lock); + g_mutex_unlock(glk_data->event_lock); } +/** + * glk_select: + * @event: Pointer to an #event_t. + * + * Causes the program to wait for an event, and then store it in the structure + * pointed to by @event. Unlike most Glk functions that take pointers, the + * argument of glk_select() may not be %NULL. + * + * Most of the time, you only get the events that you request. However, there + * are some events which can arrive at any time. This is why you must always + * call glk_select() in a loop, and continue the loop until you get the event + * you really want. + */ void glk_select(event_t *event) { - event_t *retrieved_event; - g_return_if_fail(event != NULL); - g_mutex_lock(event_lock); + g_mutex_lock(glk_data->event_lock); /* Wait for an event */ - if( g_queue_is_empty(event_queue) ) { - g_cond_wait(event_queue_not_empty, event_lock); + while( g_queue_is_empty(glk_data->event_queue) ) + g_cond_wait(glk_data->event_queue_not_empty, glk_data->event_lock); + + event_t *retrieved_event = g_queue_pop_tail(glk_data->event_queue); + if(retrieved_event == NULL) + { + g_mutex_unlock(glk_data->event_lock); + WARNING("Retrieved NULL event from non-empty event queue"); + return; } - - retrieved_event = g_queue_pop_tail(event_queue); - g_return_if_fail(retrieved_event != NULL); - - event->type = retrieved_event->type; - event->win = retrieved_event->win; - event->val1 = retrieved_event->val1; - event->val2 = retrieved_event->val2; - + memcpy(event, retrieved_event, sizeof(event_t)); g_free(retrieved_event); /* Signal that the event queue is no longer full */ - g_cond_signal(event_queue_not_full); - - g_mutex_unlock(event_lock); - - /* Implementation defined events */ - switch(event->type) { - case EVENT_TYPE_QUIT: - g_thread_exit(NULL); - } + g_cond_signal(glk_data->event_queue_not_full); + + g_mutex_unlock(glk_data->event_lock); + + /* Check for interrupt */ + glk_tick(); + + /* If an abort event was generated, the thread should have exited by now */ + g_assert(event->type != evtype_Abort); } +