X-Git-Url: https://git.stderr.nl/gitweb?a=blobdiff_plain;f=libchimara%2Fevent.c;fp=libchimara%2Fevent.c;h=d7cb6596cbdd61611536bfe981c5116351b750a5;hb=78652af29a2f39e626febd5f4213da57d3a13901;hp=0000000000000000000000000000000000000000;hpb=91214934fbcdfd363202a65c142194506604ff7b;p=projects%2Fchimara%2Fchimara.git diff --git a/libchimara/event.c b/libchimara/event.c new file mode 100644 index 0000000..d7cb659 --- /dev/null +++ b/libchimara/event.c @@ -0,0 +1,94 @@ +#include "event.h" +#include "magic.h" +#include "glk.h" +#include + +#include "chimara-glk-private.h" + +extern ChimaraGlkPrivate *glk_data; + +#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, EVENT_TIMEOUT_MICROSECONDS); + + g_mutex_lock(glk_data->event_lock); + + /* Wait for room in the event queue */ + 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(glk_data->event_queue, event); + + /* Signal that there is an event */ + g_cond_signal(glk_data->event_queue_not_empty); + + 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) +{ + g_return_if_fail(event != NULL); + + g_mutex_lock(glk_data->event_lock); + + /* Wait for an event */ + 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; + } + memcpy(event, retrieved_event, sizeof(event_t)); + g_free(retrieved_event); + + /* Signal that the event queue is no longer full */ + 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); +} +