Use init and clear for GMutex and GCond
[projects/chimara/chimara.git] / libchimara / event.c
index ca5e21aac58a874dd7a28a1ebc968601e925deab..7c916c073b5b8e4eef94b41dd387389f876c653c 100644 (file)
@@ -2,6 +2,7 @@
 #include "magic.h"
 #include "glk.h"
 #include "window.h"
+#include "input.h"
 #include <string.h>
 
 #include "chimara-glk.h"
@@ -26,14 +27,14 @@ event_throw(ChimaraGlk *glk, glui32 type, winid_t win, glui32 val1, glui32 val2)
        g_get_current_time(&timeout);
        g_time_val_add(&timeout, EVENT_TIMEOUT_MICROSECONDS);
 
-       g_mutex_lock(priv->event_lock);
+       g_mutex_lock(&priv->event_lock);
 
        /* Wait for room in the event queue */
        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) ) 
+               if( !g_cond_timed_wait(&priv->event_queue_not_full, &priv->event_lock, &timeout) ) 
                {
                        /* Drop the event after 3 seconds */
-                       g_mutex_unlock(priv->event_lock);
+                       g_mutex_unlock(&priv->event_lock);
                        return;
                }
 
@@ -45,9 +46,87 @@ event_throw(ChimaraGlk *glk, glui32 type, winid_t win, glui32 val1, glui32 val2)
        g_queue_push_head(priv->event_queue, event);
 
        /* Signal that there is an event */
-       g_cond_signal(priv->event_queue_not_empty);
+       g_cond_signal(&priv->event_queue_not_empty);
 
-       g_mutex_unlock(priv->event_lock);
+       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);
+       }
 }
 
 /**
@@ -68,29 +147,17 @@ 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();
 
@@ -125,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,
@@ -172,9 +239,12 @@ glk_select_poll(event_t *event)
        ChimaraGlkPrivate *glk_data = g_private_get(glk_data_key);
        
        event->type = evtype_None;
-       
-       g_mutex_lock(glk_data->event_lock);
-       
+       event->win = NULL;
+       event->val1 = 0;
+       event->val2 = 0;
+
+       g_mutex_lock(&glk_data->event_lock);
+
        if( !g_queue_is_empty(glk_data->event_queue) )
        {
                GList *link;
@@ -187,17 +257,17 @@ glk_select_poll(event_t *event)
                                memcpy(event, link->data, sizeof(event_t));
                                g_free(link->data);
                                g_queue_delete_link(glk_data->event_queue, link);
-                               g_cond_signal(glk_data->event_queue_not_full);
+                               g_cond_signal(&glk_data->event_queue_not_full);
                                break;
                        }
                }
        }
-       
-       g_mutex_unlock(glk_data->event_lock);
-       
+
+       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);
-}
\ No newline at end of file
+}