X-Git-Url: https://git.stderr.nl/gitweb?a=blobdiff_plain;f=libchimara%2Fevent.c;h=4089b79eaa3205017e153642f0f54418a4105d01;hb=5b51dfd3050c65677e3d13eb7585202c8e1664ef;hp=1a24f28d9792ec7b9f1f82136e4aab92f980f9db;hpb=634959c3b160ea688522577e5e55e05686fd57d4;p=rodin%2Fchimara.git diff --git a/libchimara/event.c b/libchimara/event.c index 1a24f28..4089b79 100644 --- a/libchimara/event.c +++ b/libchimara/event.c @@ -1,11 +1,14 @@ #include "event.h" #include "magic.h" #include "glk.h" +#include "window.h" +#include "input.h" #include +#include "chimara-glk.h" #include "chimara-glk-private.h" -extern ChimaraGlkPrivate *glk_data; +extern GPrivate *glk_data_key; #define EVENT_TIMEOUT_MICROSECONDS (3000000) @@ -13,23 +16,25 @@ extern ChimaraGlkPrivate *glk_data; 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) +event_throw(ChimaraGlk *glk, glui32 type, winid_t win, glui32 val1, glui32 val2) { - if(!glk_data->event_queue) + ChimaraGlkPrivate *priv = CHIMARA_GLK_PRIVATE(glk); + + if(!priv->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); + g_mutex_lock(priv->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) ) + while( g_queue_get_length(priv->event_queue) >= EVENT_QUEUE_MAX_LENGTH ) + if( !g_cond_timed_wait(priv->event_queue_not_full, priv->event_lock, &timeout) ) { /* Drop the event after 3 seconds */ - g_mutex_unlock(glk_data->event_lock); + g_mutex_unlock(priv->event_lock); return; } @@ -38,12 +43,90 @@ event_throw(glui32 type, winid_t win, glui32 val1, glui32 val2) event->win = win; event->val1 = val1; event->val2 = val2; - g_queue_push_head(glk_data->event_queue, event); + g_queue_push_head(priv->event_queue, event); /* Signal that there is an event */ - g_cond_signal(glk_data->event_queue_not_empty); + g_cond_signal(priv->event_queue_not_empty); + + g_mutex_unlock(priv->event_lock); +} + +/* Helper function: Wait for an event in the event queue. If it is a forced + * input event, but no windows have an input request of that type, then wait + * for the next event and put the forced input event back on top of the queue. + */ +static void +get_appropriate_event(event_t *event) +{ + ChimaraGlkPrivate *glk_data = g_private_get(glk_data_key); + + g_mutex_lock(glk_data->event_lock); + + event_t *retrieved_event = NULL; + + /* Wait for an event */ + if( g_queue_is_empty(glk_data->event_queue) ) + g_cond_wait(glk_data->event_queue_not_empty, glk_data->event_lock); + retrieved_event = g_queue_pop_tail(glk_data->event_queue); + + /* 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); + + if(retrieved_event->type == evtype_ForcedCharInput) + { + /* Check for forced character input in the queue */ + winid_t win; + for(win = glk_window_iterate(NULL, NULL); win; win = glk_window_iterate(win, NULL)) + if(win->input_request_type == INPUT_REQUEST_CHARACTER || win->input_request_type == INPUT_REQUEST_CHARACTER_UNICODE) + break; + if(win) + { + force_char_input_from_queue(win, event); + g_free(retrieved_event); + } + else + { + get_appropriate_event(event); + g_mutex_lock(glk_data->event_lock); + g_queue_push_tail(glk_data->event_queue, retrieved_event); + g_cond_signal(glk_data->event_queue_not_empty); + g_mutex_unlock(glk_data->event_lock); + } + } + else if(retrieved_event->type == evtype_ForcedLineInput) + { + /* Check for forced line input in the queue */ + winid_t win; + for(win = glk_window_iterate(NULL, NULL); win; win = glk_window_iterate(win, NULL)) + if(win->input_request_type == INPUT_REQUEST_LINE || win->input_request_type == INPUT_REQUEST_LINE_UNICODE) + break; + if(win) + { + force_line_input_from_queue(win, event); + g_free(retrieved_event); + } + else + { + get_appropriate_event(event); + g_mutex_lock(glk_data->event_lock); + g_queue_push_tail(glk_data->event_queue, retrieved_event); + g_cond_signal(glk_data->event_queue_not_empty); + g_mutex_unlock(glk_data->event_lock); + } + } + else + { + if(retrieved_event == NULL) + { + WARNING("Retrieved NULL event from non-empty event queue"); + return; + } + memcpy(event, retrieved_event, sizeof(event_t)); + g_free(retrieved_event); + } } /** @@ -64,29 +147,28 @@ 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; + /* Flush all window buffers */ + winid_t win; + for(win = glk_window_iterate(NULL, NULL); win != NULL; win = glk_window_iterate(win, NULL)) { + if(win->type == wintype_TextBuffer || win->type == wintype_TextGrid) + flush_window_buffer(win); } - 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); + ChimaraGlkPrivate *glk_data = g_private_get(glk_data_key); + + get_appropriate_event(event); - g_mutex_unlock(glk_data->event_lock); - /* Check for interrupt */ glk_tick(); + + /* If the event was a line input event, the library must release the buffer */ + if(event->type == evtype_LineInput && glk_data->unregister_arr) + { + if(event->win->input_request_type == INPUT_REQUEST_LINE_UNICODE) + (*glk_data->unregister_arr)(event->win->line_input_buffer_unicode, event->win->line_input_buffer_max_len, "&+#!Iu", event->win->buffer_rock); + else + (*glk_data->unregister_arr)(event->win->line_input_buffer, event->win->line_input_buffer_max_len, "&+#!Cn", event->win->buffer_rock); + } /* If an abort event was generated, the thread should have exited by now */ g_assert(event->type != evtype_Abort); @@ -110,7 +192,7 @@ glk_select(event_t *event) * intended for you to test conditions which may have occurred while you are * computing, and not interfacing with the player. For example, time may pass * during slow computations; you can use glk_select_poll() to see if a - * %evtype_Timer event has occured. (See Timer Events.) * * At the moment, glk_select_poll() checks for %evtype_Timer, %evtype_Arrange, @@ -154,6 +236,8 @@ glk_select_poll(event_t *event) { g_return_if_fail(event != NULL); + ChimaraGlkPrivate *glk_data = g_private_get(glk_data_key); + event->type = evtype_None; g_mutex_lock(glk_data->event_lock); @@ -183,4 +267,4 @@ glk_select_poll(event_t *event) /* If an abort event was generated, the thread should have exited by now */ g_assert(event->type != evtype_Abort); -} \ No newline at end of file +}