Added missing buffer flush.
[rodin/chimara.git] / libchimara / event.c
index 4bbb391b597bb028dc7e5a75994de54ee188858f..4089b79eaa3205017e153642f0f54418a4105d01 100644 (file)
@@ -1,6 +1,8 @@
 #include "event.h"
 #include "magic.h"
 #include "glk.h"
+#include "window.h"
+#include "input.h"
 #include <string.h>
 
 #include "chimara-glk.h"
@@ -49,6 +51,84 @@ event_throw(ChimaraGlk *glk, glui32 type, winid_t win, glui32 val1, glui32 val2)
        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);
+       }
+}
+
 /**
  * glk_select:
  * @event: Pointer to an #event_t.
@@ -67,31 +147,28 @@ glk_select(event_t *event)
 {
        g_return_if_fail(event != NULL);
 
-       ChimaraGlkPrivate *glk_data = g_private_get(glk_data_key);
-       
-       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);
@@ -115,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 <link 
+ * %evtype_Timer event has occurred. (See <link 
  * linkend="chimara-Timer-Events">Timer Events</link>.)
  * 
  * At the moment, glk_select_poll() checks for %evtype_Timer, %evtype_Arrange,
@@ -190,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
+}