Use init and clear for GMutex and GCond
[projects/chimara/chimara.git] / libchimara / glk.c
index c4f395441de42e7331bdc3cb3bf4be1bc9236ee7..b86daed07971769f49f861c460f4ea8836b79258 100644 (file)
@@ -5,8 +5,9 @@
 #include "chimara-glk.h"
 #include "chimara-glk-private.h"
 #include "gi_blorb.h"
+#include "window.h"
 
-ChimaraGlkPrivate *glk_data = NULL;
+G_GNUC_INTERNAL GPrivate *glk_data_key = NULL;
 
 /**
  * glk_exit:
@@ -42,18 +43,50 @@ ChimaraGlkPrivate *glk_data = NULL;
 void
 glk_exit(void)
 {
-    g_signal_emit_by_name(glk_data->self, "stopped");
-
-       /* Stop any timers */
-       glk_request_timer_events(0);
+       ChimaraGlkPrivate *glk_data = g_private_get(glk_data_key);
+       
+       shutdown_glk_pre();
+       
+       /* Find the biggest text buffer window */
+       winid_t win, largewin = NULL;
+       glui32 largearea = 0;
+       for(win = glk_window_iterate(NULL, NULL); win; win = glk_window_iterate(win, NULL)) {
+               if(win->type == wintype_TextBuffer) {
+                       glui32 w, h;
+                       if(!largewin) {
+                               largewin = win;
+                               glk_window_get_size(largewin, &w, &h);
+                               largearea = w * h;
+                       } else {
+                               glk_window_get_size(win, &w, &h);
+                               if(w * h > largearea) {
+                                       largewin = win;
+                                       largearea = w * h;
+                               }
+                       }
+               }
+       }
+       if(largewin) {
+               glk_set_window(largewin);
+               glk_set_style(style_Alert);
+               glk_put_string("\n");
+               glk_put_string(glk_data->final_message);
+               glk_put_string("\n");
+               flush_window_buffer(largewin);
+       }
 
-       /* Close any open resource files */
-       if(glk_data->resource_map != NULL) {
-               giblorb_destroy_map(glk_data->resource_map);
-               glk_stream_close(glk_data->resource_file, NULL);
+       g_mutex_lock(&glk_data->shutdown_lock);
+       for(win = glk_window_iterate(NULL, NULL); win; win = glk_window_iterate(win, NULL)) {
+               if(win->type == wintype_TextGrid || win->type == wintype_TextBuffer)
+                       g_signal_handler_unblock(win->widget, win->shutdown_keypress_handler);
        }
+       g_cond_wait(&glk_data->shutdown_key_pressed, &glk_data->shutdown_lock);
+       g_mutex_unlock(&glk_data->shutdown_lock);
+
+       shutdown_glk_post();
 
-    glk_data = NULL;
+       g_signal_emit_by_name(glk_data->self, "stopped");
+       
        g_thread_exit(NULL);
 }
 
@@ -67,8 +100,10 @@ glk_exit(void)
  * all. So you can call it often.
  *
  * <note><para>
- *   In a virtual machine interpreter, once per opcode is appropriate. In a
- *   program with lots of computation, pick a comparable rate.
+ *   In a virtual machine interpreter, once per opcode is appropriate. A more
+ *   parsimonious approach would be once per branch and function call opcode;
+ *   this guarantees it will be called inside loops. In a program with lots of
+ *   computation, pick a comparable rate.
  * </para></note>
  * 
  * glk_tick() does not try to update the screen, or check for player input, or
@@ -89,8 +124,8 @@ glk_exit(void)
  *   loop, this is critical. In a C program, you can often eyeball it.
  *   </para>
  *   <para>But the next version of <filename>model.c</filename> will have a
- *   glk_tick() in the ornate printing loop of <function>verb_yada()</function>.
- *   Just to make the point.
+ *   glk_tick() in the ornate printing loop of 
+ *   <function>verb_yada&lpar;&rpar;</function>. Just to make the point.
  *   </para>
  * </note>
  */