From: fliep <fliep@ddfedd41-794f-dd11-ae45-00112f111e67>
Date: Sun, 24 Aug 2008 00:37:04 +0000 (+0000)
Subject: Code opschonen, toevoegen documentatie
X-Git-Tag: v0.9~454
X-Git-Url: https://git.stderr.nl/gitweb?a=commitdiff_plain;h=5d71044dd816436be6c5d7a93bc87e53c94d9f31;p=projects%2Fchimara%2Fchimara.git

Code opschonen, toevoegen documentatie
---

diff --git a/src/case.c b/src/case.c
index ecb7862..9e73de1 100644
--- a/src/case.c
+++ b/src/case.c
@@ -35,8 +35,6 @@ glk_char_to_upper(unsigned char ch)
 	return ch;
 }
 
-#ifdef GLK_MODULE_UNICODE
-
 /**
  * glk_buffer_to_lower_case_uni:
  * @buf: A character array in UCS-4.
@@ -104,30 +102,28 @@ glk_buffer_to_upper_case_uni(glui32 *buf, glui32 len, glui32 numchars)
  * @buf: A character array in UCS-4.
  * @len: Available length of @buf.
  * @numchars: Number of characters in @buf.
- * @lowerrest: #TRUE if the rest of @buf should be lowercased, #FALSE 
+ * @lowerrest: %TRUE if the rest of @buf should be lowercased, %FALSE 
  * otherwise.
  *
  * Converts the first character of @buf to uppercase, if there is such a thing.
- * See glk_buffer_to_lower_case_uni(). If @lowerrest is #TRUE, then the
+ * See glk_buffer_to_lower_case_uni(). If @lowerrest is %TRUE, then the
  * remainder of @buf is lowercased.
  *
  * Returns: The number of characters after conversion.
  */
 glui32
-glk_buffer_to_title_case_uni(glui32 *buf, glui32 len, glui32 numchars, 
-                             glui32 lowerrest)
+glk_buffer_to_title_case_uni(glui32 *buf, glui32 len, glui32 numchars, glui32 lowerrest)
 {
 	g_return_val_if_fail(buf != NULL && (len > 0 || numchars > 0), 0);
 	g_return_val_if_fail(numchars <= len, 0);
 	
 	/* GLib has a function that converts _one_ UCS-4 character to _one_
-	uppercase UCS-4 character; so apparently we don't have to worry about the
+	titlecase UCS-4 character; so apparently we don't have to worry about the
 	string length changing... */
 	*buf = g_unichar_totitle(*buf);
 	/* Call lowercase on the rest of the string */
 	if(lowerrest)
-		return glk_buffer_to_lower_case_uni(buf + 1, len - 1, numchars - 1) +1;
+		return glk_buffer_to_lower_case_uni(buf + 1, len - 1, numchars - 1) + 1;
 	return numchars;
 }
 
-#endif /* GLK_MODULE_UNICODE */
diff --git a/src/event.c b/src/event.c
index 0334e39..76f8240 100644
--- a/src/event.c
+++ b/src/event.c
@@ -1,10 +1,13 @@
 #include "event.h"
+#include <string.h>
 
 static GQueue *event_queue = NULL;
 static GMutex *event_lock = NULL;
 static GCond *event_queue_not_empty = NULL;
 static GCond *event_queue_not_full = NULL;
 
+/* Internal function: initialize the event_queue, locking and signalling 
+objects. */
 void
 events_init()
 {
@@ -14,22 +17,20 @@ events_init()
 	event_queue_not_full = g_cond_new();
 }
 
-static void
-event_free(gpointer data, gpointer user_data)
-{
-	g_free(data);
-}
-
+/* Internal function: free the event queue and all the objects allocated in
+events_init(). */
 void
 events_free()
 {
-	g_queue_foreach(event_queue, event_free, NULL);
+	g_queue_foreach(event_queue, (GFunc)g_free, NULL);
 	g_queue_free(event_queue);
 	g_mutex_free(event_lock);
 	g_cond_free(event_queue_not_empty);
 	g_cond_free(event_queue_not_full);
 }
 
+/* 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. */
 void
 event_throw(glui32 type, winid_t win, glui32 val1, glui32 val2)
 {
@@ -37,22 +38,22 @@ event_throw(glui32 type, winid_t win, glui32 val1, glui32 val2)
 	g_get_current_time(&timeout);
 	g_time_val_add(&timeout, 3000000); /* 3 Seconds */
 
-	/* Wait for room in the event queue */
 	g_mutex_lock(event_lock);
-	if( g_queue_get_length(event_queue) >= EVENT_QUEUE_MAX_LENGTH ) {
-		if( !g_cond_timed_wait(event_queue_not_full, event_lock, &timeout) ) {
-			/* Drop the event */
+
+	/* Wait for room in the event queue */
+	if( g_queue_get_length(event_queue) >= EVENT_QUEUE_MAX_LENGTH )
+		if( !g_cond_timed_wait(event_queue_not_full, event_lock, &timeout) ) 
+		{
+			/* Drop the event after 3 seconds */
 			g_mutex_unlock(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(event_queue, event);
 
 	/* Signal that there is an event */
@@ -61,28 +62,38 @@ event_throw(glui32 type, winid_t win, glui32 val1, glui32 val2)
 	g_mutex_unlock(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)
 {
-	event_t *retrieved_event;
-
 	g_return_if_fail(event != NULL);
 
 	g_mutex_lock(event_lock);
 
 	/* Wait for an event */
-	if( g_queue_is_empty(event_queue) ) {
+	if( g_queue_is_empty(event_queue) )
 		g_cond_wait(event_queue_not_empty, event_lock);
-	}
-
-	retrieved_event = g_queue_pop_tail(event_queue);
-	g_return_if_fail(retrieved_event != NULL);
-
-	event->type = retrieved_event->type;
-	event->win = retrieved_event->win;
-	event->val1 = retrieved_event->val1;
-	event->val2 = retrieved_event->val2;
 
+	event_t *retrieved_event = g_queue_pop_tail(event_queue);
+	if(retrieved_event == NULL)
+	{
+		g_mutex_unlock(event_lock);
+		g_warning("%s: Retrieved NULL event from non-empty event queue", __func__);
+		return;
+	}
+	memcpy(event, retrieved_event, sizeof(event_t));
 	g_free(retrieved_event);
 
 	/* Signal that the event queue is no longer full */
@@ -90,7 +101,7 @@ glk_select(event_t *event)
 
 	g_mutex_unlock(event_lock);
 
-	/* Implementation defined events */
+	/* Implementation-defined events */
 	switch(event->type) {
 		case EVENT_TYPE_QUIT:
 			g_thread_exit(NULL);
diff --git a/src/event.h b/src/event.h
index 3acbdee..b17335c 100644
--- a/src/event.h
+++ b/src/event.h
@@ -4,9 +4,10 @@
 #include <glib.h>
 #include "glk.h"
 
-#define EVENT_QUEUE_MAX_LENGTH 100
+#define EVENT_QUEUE_MAX_LENGTH (100)
 
-#define EVENT_TYPE_QUIT -1
+/* Implementation-defined events */
+#define EVENT_TYPE_QUIT (-1)
 
 void events_init();
 void events_free();
diff --git a/src/gestalt.c b/src/gestalt.c
index 1bb7f7e..4a586ce 100644
--- a/src/gestalt.c
+++ b/src/gestalt.c
@@ -27,11 +27,38 @@ glk_gestalt(glui32 sel, glui32 val)
  * @sel: A selector, representing which capability to request information
  * about.
  * @val: Extra information, depending on the value of @sel.
- * @arr: Location of an array to store extra information in, or #NULL.
- * @arrlen: Length of @arr, or 0 if @arr is #NULL.
+ * @arr: Location of an array to store extra information in, or %NULL.
+ * @arrlen: Length of @arr, or 0 if @arr is %NULL.
  *
- * Calls the gestalt system to request information about selector @sel,
- * possibly returning information in @arr.
+ * Calls the gestalt system to request information about the capabilities of the
+ * API. The selector @sel tells which capability you are requesting information
+ * about; the other three arguments are additional information, which may or may
+ * not be meaningful. The @arr and @arrlen arguments are always optional; you
+ * may always pass %NULL and 0, if you do not want whatever information they
+ * represent. glk_gestalt() is simply a shortcut for this; glk_gestalt(x, y) is
+ * exactly the same as glk_gestalt_ext(x, y, NULL, 0).
+ *
+ * The critical point is that if the Glk library has never heard of the selector
+ * sel, it will return 0. It is always safe to call glk_gestalt(x, y) (or
+ * glk_gestalt_ext(x, y, NULL, 0)). Even if you are using an old library, which
+ * was compiled before the given capability was imagined, you can test for the
+ * capability by calling glk_gestalt(); the library will correctly indicate that
+ * it does not support it, by returning 0.
+ *
+ * <note><para>
+ *  It is also safe to call glk_gestalt_ext(x, y, z, zlen) for an unknown 
+ *  selector x, where z is not %NULL, as long as z points at an array of at 
+ *  least zlen elements. The selector will be careful not to write beyond that  
+ *  point in the array, if it writes to the array at all.
+ * </para></note>
+ *
+ * <note><para>
+ *  If a selector does not use the second argument, you should always pass 0; do
+ *  not assume that the second argument is simply ignored. This is because the
+ *  selector may be extended in the future. You will continue to get the current
+ *  behavior if you pass 0 as the second argument, but other values may produce
+ *  other behavior.
+ * </para></note>
  *
  * Returns: an integer, depending on what selector was called.
  */
@@ -54,6 +81,20 @@ glk_gestalt_ext(glui32 sel, glui32 val, glui32 *arr, glui32 arrlen)
 				return gestalt_CharOutput_CannotPrint;
 			/* Can print all other Latin-1 characters */
 			return gestalt_CharOutput_ExactPrint;
+		
+		/* Which characters can the player type in line input? */
+		case gestalt_LineInput:
+			/* Does not accept control chars */
+			if( val < 32 || (val >= 127 && val <= 159) )
+				return 0;
+			return 1;
+			
+		/* Which characters can the player type in char input? */
+		case gestalt_CharInput:
+			/* Does not accept control chars or unknown */
+			if( val < 32 || (val >= 127 && val <= 159) || val == keycode_Unknown )
+				return 0;
+			return 1;
 			
 		/* Selector not supported */	
 		default:
diff --git a/src/glk.c b/src/glk.c
index fc22682..dbec759 100644
--- a/src/glk.c
+++ b/src/glk.c
@@ -6,8 +6,19 @@
 /**
  * glk_exit:
  * 
- * End the Glk program. As far as the client program is concerned, this
- * function does not return.
+ * Shuts down the Glk program. This function does not return.
+ *
+ * If you print some text to a window and then shut down your program, you can
+ * assume that the player will be able to read it.
+ *
+ * <note><para>
+ *  You should only shut down your program with glk_exit() or by returning from
+ *  your glk_main() function. If you call the ANSI <function>exit()</function> 
+ *  function, bad things may happen. This Glk library is designed for multiple 
+ *  sessions, for example, and you would be cutting off all the sessions instead
+ *  of just yours. You would also prevent final text from being visible to the 
+ *  player.
+ * </para></note>
  */
 void
 glk_exit(void)
@@ -15,12 +26,3 @@ glk_exit(void)
 	g_thread_exit(NULL);
 }
 
-/*
-void
-glk_select(event_t *event)
-{
-	gtk_main_iteration();
-}
-*/
-
-
diff --git a/src/input.c b/src/input.c
index caa1824..d9b0965 100644
--- a/src/input.c
+++ b/src/input.c
@@ -1,59 +1,47 @@
 #include "input.h"
 
 /** glk_request_char_event:
- * @win: A window to request char events from Request
+ * @win: A window to request char events from.
  *
- * Request input of a Latin-1 character or special key. A window cannot have requests
- * for both character and line input at the same time. Nor can it have requests
- * for character input of both types (Latin-1 and Unicode). It is illegal to
- * call glk_request_char_event() if the window already has a pending request
- * for either character or line input. 
+ * Request input of a Latin-1 character or special key. A window cannot have 
+ * requests for both character and line input at the same time. Nor can it have
+ * requests for character input of both types (Latin-1 and Unicode). It is
+ * illegal to call glk_request_char_event() if the window already has a pending
+ * request for either character or line input. 
  */
 void
 glk_request_char_event(winid_t win)
 {
 	g_return_if_fail(win);
 	g_return_if_fail(win->input_request_type == INPUT_REQUEST_NONE);
-	g_return_if_fail(win->window_type != wintype_TextBuffer || win->window_type != wintype_TextGrid);
+	g_return_if_fail(win->type != wintype_TextBuffer || win->type != wintype_TextGrid);
 
 	win->input_request_type = INPUT_REQUEST_CHARACTER;
 	g_signal_handler_unblock( G_OBJECT(win->widget), win->keypress_handler );
 }
 
 /** glk_request_char_event_uni:
- * @win: A window to request char events from Request
+ * @win: A window to request char events from.
  *
- * Request input of a Unicode character or special key. A window cannot have requests
- * for both character and line input at the same time. Nor can it have requests
- * for character input of both types (Latin-1 and Unicode). It is illegal to
- * call glk_request_char_event_uni() if the window already has a pending request
- * for either character or line input. 
+ * Request input of a Unicode character or special key. See 
+ * glk_request_char_event().
  */
 void
 glk_request_char_event_uni(winid_t win)
 {
 	g_return_if_fail(win);
 	g_return_if_fail(win->input_request_type == INPUT_REQUEST_NONE);
-	g_return_if_fail(win->window_type != wintype_TextBuffer || win->window_type != wintype_TextGrid);
+	g_return_if_fail(win->type != wintype_TextBuffer || win->type != wintype_TextGrid);
 
 	win->input_request_type = INPUT_REQUEST_CHARACTER_UNICODE;
 	g_signal_handler_unblock( G_OBJECT(win->widget), win->keypress_handler );
 }
 
+/* Internal function: Request either latin-1 or unicode line input. */
 void
-glk_request_line_event(winid_t win, char* buf, glui32 maxlen, glui32 initlen)
+request_line_event_common(winid_t win, gboolean insert, gchar *inserttext)
 {
-	GtkTextBuffer *window_buffer;
-
-	g_return_if_fail(win);
-	g_return_if_fail(win->input_request_type == INPUT_REQUEST_NONE);
-	g_return_if_fail(win->window_type != wintype_TextBuffer || win->window_type != wintype_TextGrid);
-
-	window_buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(win->widget));
-
-	win->input_request_type = INPUT_REQUEST_LINE;
-	win->line_input_buffer = buf;
-	win->line_input_buffer_max_len = maxlen;
+	GtkTextBuffer *window_buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(win->widget));
 
 	/* Move the input_position mark to the end of the window_buffer */
 	GtkTextMark *input_position = gtk_text_buffer_get_mark(window_buffer, "input_position");
@@ -67,47 +55,92 @@ glk_request_line_event(winid_t win, char* buf, glui32 maxlen, glui32 initlen)
 	gtk_text_buffer_get_start_iter(window_buffer, &start_iter);
 	gtk_text_buffer_remove_tag_by_name(window_buffer, "uneditable", &start_iter, &end_iter);
 	gtk_text_buffer_apply_tag_by_name(window_buffer, "uneditable", &start_iter, &end_iter);
-
-	if(initlen > 0) {
-		gtk_text_buffer_insert(window_buffer, &end_iter, buf, initlen);
-	}
-
+	
+	/* Insert pre-entered text if needed */
+	if(insert)
+		gtk_text_buffer_insert(window_buffer, &end_iter, inserttext, -1);
+	
+	/* Scroll to input point */
 	gtk_text_view_scroll_mark_onscreen(GTK_TEXT_VIEW(win->widget), input_position);
 	g_signal_handler_unblock( G_OBJECT(window_buffer), win->insert_text_handler );
 	gtk_text_view_set_editable(GTK_TEXT_VIEW(win->widget), TRUE);
 }
 
+/**
+ * glk_request_line_event:
+ * @win: A text buffer or text grid window to request line input on.
+ * @buf: A buffer of at least @maxlen bytes.
+ * @maxlen: Length of the buffer.
+ * @initlen: The number of characters in @buf to pre-enter.
+ *
+ * Requests input of a line of Latin-1 characters. A window cannot have requests
+ * for both character and line input at the same time. Nor can it have requests
+ * for line input of both types (Latin-1 and Unicode). It is illegal to call
+ * glk_request_line_event() if the window already has a pending request for
+ * either character or line input.
+ * 
+ * The @buf argument is a pointer to space where the line input will be stored.
+ * (This may not be %NULL.) @maxlen is the length of this space, in bytes; the
+ * library will not accept more characters than this. If @initlen is nonzero,
+ * then the first @initlen bytes of @buf will be entered as pre-existing input
+ * -- just as if the player had typed them himself. (The player can continue
+ * composing after this pre-entered input, or delete it or edit as usual.)
+ * 
+ * The contents of the buffer are undefined until the input is completed (either
+ * by a line input event, or glk_cancel_line_event(). The library may or may not
+ * fill in the buffer as the player composes, while the input is still pending;
+ * it is illegal to change the contents of the buffer yourself. 
+ */
 void
-glk_request_line_event_uni(winid_t win, glui32 *buf, glui32 maxlen, glui32 initlen)
+glk_request_line_event(winid_t win, char* buf, glui32 maxlen, glui32 initlen)
 {
-	GtkTextBuffer *window_buffer;
-
 	g_return_if_fail(win);
+	g_return_if_fail(buf);
 	g_return_if_fail(win->input_request_type == INPUT_REQUEST_NONE);
-	g_return_if_fail(win->window_type != wintype_TextBuffer || win->window_type != wintype_TextGrid);
+	g_return_if_fail(win->type != wintype_TextBuffer || win->type != wintype_TextGrid);
+
+	win->input_request_type = INPUT_REQUEST_LINE;
+	win->line_input_buffer = buf;
+	win->line_input_buffer_max_len = maxlen;
+
+	gchar *inserttext = (initlen > 0)? g_strndup(buf, initlen) : g_strdup("");
+	request_line_event_common(win, (initlen > 0), inserttext);
+	g_free(inserttext);
+}
 
-	window_buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(win->widget));
+/**
+ * glk_request_line_event_uni:
+ * @win: A text buffer or text grid window to request line input on.
+ * @buf: A buffer of at least @maxlen characters.
+ * @maxlen: Length of the buffer.
+ * @initlen: The number of characters in @buf to pre-enter.
+ *
+ * Request input of a line of Unicode characters. This works the same as
+ * glk_request_line_event(), except the result is stored in an array of
+ * <type>glui32</type> values instead of an array of characters, and the values
+ * may be any valid Unicode code points.
+ * 
+ * The result will be in Unicode Normalization Form C. This basically means that
+ * composite characters will be single characters where possible, instead of
+ * sequences of base and combining marks. See 
+ * <ulink url="http://www.unicode.org/reports/tr15/">Unicode Standard Annex #15
+ * </ulink> for the details.
+ */
+void
+glk_request_line_event_uni(winid_t win, glui32 *buf, glui32 maxlen, glui32 initlen)
+{
+	g_return_if_fail(win);
+	g_return_if_fail(buf);
+	g_return_if_fail(win->input_request_type == INPUT_REQUEST_NONE);
+	g_return_if_fail(win->type != wintype_TextBuffer || win->type != wintype_TextGrid);
 
 	win->input_request_type = INPUT_REQUEST_LINE_UNICODE;
 	win->line_input_buffer_unicode = buf;
 	win->line_input_buffer_max_len = maxlen;
 
-	/* Move the input_position mark to the end of the window_buffer */
-	GtkTextMark *input_position = gtk_text_buffer_get_mark(window_buffer, "input_position");
-	GtkTextIter end_iter;
-	gtk_text_buffer_get_end_iter(window_buffer, &end_iter);
-	gtk_text_buffer_move_mark(window_buffer, input_position, &end_iter);
-
-	/* Set the entire contents of the window_buffer as uneditable
-	 * (so input can only be entered at the end) */
-	GtkTextIter start_iter;
-	gtk_text_buffer_get_start_iter(window_buffer, &start_iter);
-	gtk_text_buffer_remove_tag_by_name(window_buffer, "uneditable", &start_iter, &end_iter);
-	gtk_text_buffer_apply_tag_by_name(window_buffer, "uneditable", &start_iter, &end_iter);
-
+	gchar *utf8;
 	if(initlen > 0) {
 		GError *error = NULL;
-		gchar *utf8;
 		utf8 = g_ucs4_to_utf8(buf, initlen, NULL, NULL, &error);
 			
 		if(utf8 == NULL)
@@ -115,25 +148,22 @@ glk_request_line_event_uni(winid_t win, glui32 *buf, glui32 maxlen, glui32 initl
 			error_dialog(NULL, error, "Error during unicode->utf8 conversion: ");
 			return;
 		}
-
-		gtk_text_buffer_insert(window_buffer, &end_iter, utf8, -1);
-		g_free(utf8);
 	}
+	else
+		utf8 = g_strdup("");
 
-	gtk_text_view_scroll_mark_onscreen(GTK_TEXT_VIEW(win->widget), input_position);
-	g_signal_handler_unblock( G_OBJECT(window_buffer), win->insert_text_handler );
-	gtk_text_view_set_editable(GTK_TEXT_VIEW(win->widget), TRUE);
+	request_line_event_common(win, (initlen > 0), utf8);		
+	g_free(utf8);
 }
 
-
-
+/* Internal function: Callback for signal key-press-event on a text buffer 
+window. */
 gboolean
-on_window_key_press_event(GtkWidget *widget, GdkEventKey *event, winid_t window)
+on_window_key_press_event(GtkWidget *widget, GdkEventKey *event, winid_t win)
 {
-	if(window->input_request_type != INPUT_REQUEST_CHARACTER && 
-		window->input_request_type != INPUT_REQUEST_CHARACTER_UNICODE) {
+	if(win->input_request_type != INPUT_REQUEST_CHARACTER && 
+		win->input_request_type != INPUT_REQUEST_CHARACTER_UNICODE)
 		return FALSE;
-	}
 
 	int keycode;
 
@@ -146,13 +176,15 @@ on_window_key_press_event(GtkWidget *widget, GdkEventKey *event, winid_t window)
 		case GDK_KP_Left: keycode = keycode_Left; break;
 		case GDK_Right:
 		case GDK_KP_Right: keycode = keycode_Right; break;
+		case GDK_Linefeed:
 		case GDK_Return:
 		case GDK_KP_Enter: keycode = keycode_Return; break;
 		case GDK_Delete:
 		case GDK_BackSpace:
 		case GDK_KP_Delete: keycode = keycode_Delete; break;
 		case GDK_Escape: keycode = keycode_Escape; break;
-		case GDK_Tab: keycode = keycode_Tab; break;
+		case GDK_Tab: 
+		case GDK_KP_Tab: keycode = keycode_Tab; break;
 		case GDK_Page_Up:
 		case GDK_KP_Page_Up: keycode = keycode_PageUp; break;
 		case GDK_Page_Down:
@@ -161,10 +193,14 @@ on_window_key_press_event(GtkWidget *widget, GdkEventKey *event, winid_t window)
 		case GDK_KP_Home: keycode = keycode_Home; break;
 		case GDK_End:
 		case GDK_KP_End: keycode = keycode_End; break;
-		case GDK_F1: keycode = keycode_Func1; break;
-		case GDK_F2: keycode = keycode_Func2; break;
-		case GDK_F3: keycode = keycode_Func3; break;
-		case GDK_F4: keycode = keycode_Func4; break;
+		case GDK_F1: 
+		case GDK_KP_F1: keycode = keycode_Func1; break;
+		case GDK_F2: 
+		case GDK_KP_F2: keycode = keycode_Func2; break;
+		case GDK_F3: 
+		case GDK_KP_F3: keycode = keycode_Func3; break;
+		case GDK_F4: 
+		case GDK_KP_F4: keycode = keycode_Func4; break;
 		case GDK_F5: keycode = keycode_Func5; break;
 		case GDK_F6: keycode = keycode_Func6; break;
 		case GDK_F7: keycode = keycode_Func7; break;
@@ -175,30 +211,25 @@ on_window_key_press_event(GtkWidget *widget, GdkEventKey *event, winid_t window)
 		case GDK_F12: keycode = keycode_Func12; break;
 		default:
 			keycode = gdk_keyval_to_unicode(event->keyval);
+			/* If keycode is 0, then keyval was not recognized; also return
+			unknown if Latin-1 input was requested and the character is not in
+			Latin-1 */
+			if(keycode == 0 || (win->input_request_type == INPUT_REQUEST_CHARACTER && keycode > 255))
+				keycode = keycode_Unknown;	
 	}
 
-	if(window->input_request_type == INPUT_REQUEST_CHARACTER) {
-		if(keycode >= 1 || keycode <= 255) {
-			event_throw(evtype_CharInput, window, keycode, 0);
-		} else {
-			event_throw(evtype_CharInput, window, keycode_Unknown, 0);
-		}
-	} else {
-		if(keycode == 0) {
-			event_throw(evtype_CharInput, window, keycode_Unknown, 0);
-		} else {
-			event_throw(evtype_CharInput, window, keycode, 0);
-		}
-	}
-
+	event_throw(evtype_CharInput, win, keycode, 0);
+	
 	/* Only one keypress will be handled */
-	window->input_request_type = INPUT_REQUEST_NONE;
-	g_signal_handler_block( G_OBJECT(window->widget), window->keypress_handler );
+	win->input_request_type = INPUT_REQUEST_NONE;
+	g_signal_handler_block( G_OBJECT(win->widget), win->keypress_handler );
 
 	return TRUE;
 }
 
-void
+/* Internal function: Callback for signal insert-text on a text buffer window.
+Not used; cannot modify the text buffer from within the callback?? Segfault! */
+/*void
 on_window_insert_text(GtkTextBuffer *textbuffer, GtkTextIter *location, gchar *text, gint len, gpointer user_data) 
 {
 	gchar *newline_pos = strchr(text, '\n');
@@ -206,16 +237,19 @@ on_window_insert_text(GtkTextBuffer *textbuffer, GtkTextIter *location, gchar *t
 		printf("position: %d\n", newline_pos-text);
 		*newline_pos = 'a';
 	}
-}
+}*/
 
+/* Internal function: Callback for signal insert-text on a text buffer window.
+Runs after the default handler has already inserted the text.*/
 void
-after_window_insert_text(GtkTextBuffer *textbuffer, GtkTextIter *location, gchar *text, gint len, winid_t window) 
+after_window_insert_text(GtkTextBuffer *textbuffer, GtkTextIter *location, gchar *text, gint len, winid_t win) 
 {
-	if( strchr(text, '\n') != NULL) { 
+	if( strchr(text, '\n') != NULL ) 
+	{ 
 		/* Make the window uneditable again and remove signal handlers */
-		GtkTextBuffer *window_buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(window->widget));
-		gtk_text_view_set_editable(GTK_TEXT_VIEW(window->widget), FALSE);
-		g_signal_handler_block(window_buffer, window->insert_text_handler);
+		GtkTextBuffer *window_buffer = gtk_text_view_get_buffer( GTK_TEXT_VIEW(win->widget) );
+		gtk_text_view_set_editable(GTK_TEXT_VIEW(win->widget), FALSE);
+		g_signal_handler_block(window_buffer, win->insert_text_handler);
 
 		/* Retrieve the text that was input */
 		GtkTextMark *input_position = gtk_text_buffer_get_mark(window_buffer, "input_position");
@@ -225,9 +259,9 @@ after_window_insert_text(GtkTextBuffer *textbuffer, GtkTextIter *location, gchar
 		gtk_text_buffer_get_end_iter(window_buffer, &end_iter);
 		gchar *inserted_text = gtk_text_buffer_get_text(window_buffer, &start_iter, &end_iter, FALSE);
 
-
 		/* Convert the string from UTF-8 to Latin-1 or Unicode */
-		if(window->input_request_type == INPUT_REQUEST_LINE) {
+		if(win->input_request_type == INPUT_REQUEST_LINE) 
+		{
 			GError *error = NULL;
 			gchar *latin1;
 			gsize bytes_written;
@@ -237,20 +271,22 @@ after_window_insert_text(GtkTextBuffer *textbuffer, GtkTextIter *location, gchar
 			if(latin1 == NULL)
 			{
 				error_dialog(NULL, error, "Error during utf8->latin1 conversion: ");
-				event_throw(evtype_LineInput, window, 0, 0);
+				event_throw(evtype_LineInput, win, 0, 0);
 				return;
 			}
 
 			/* Place input in the echo stream */
-			if(window->echo_stream != NULL) 
-				glk_put_string_stream(window->echo_stream, latin1);
+			if(win->echo_stream != NULL) 
+				glk_put_string_stream(win->echo_stream, latin1);
 
 			/* Copy the string (but not the NULL at the end) */
-			memcpy(window->line_input_buffer, latin1, MIN(window->line_input_buffer_max_len, bytes_written-1));
+			int copycount = MIN(win->line_input_buffer_max_len, bytes_written - 1);
+			memcpy(win->line_input_buffer, latin1, copycount);
 			g_free(latin1);
-			event_throw(evtype_LineInput, window, MIN(window->line_input_buffer_max_len, bytes_written-1), 0);
+			event_throw(evtype_LineInput, win, copycount, 0);
 		}
-		else if(window->input_request_type == INPUT_REQUEST_LINE_UNICODE) {
+		else if(win->input_request_type == INPUT_REQUEST_LINE_UNICODE) 
+		{
 			gunichar *unicode;
 			glong items_written;
 			unicode = g_utf8_to_ucs4_fast(inserted_text, -1, &items_written);
@@ -259,24 +295,24 @@ after_window_insert_text(GtkTextBuffer *textbuffer, GtkTextIter *location, gchar
 			if(unicode == NULL)
 			{
 				error_dialog(NULL, NULL, "Error during utf8->unicode conversion");
-				event_throw(evtype_LineInput, window, 0, 0);
+				event_throw(evtype_LineInput, win, 0, 0);
 				return;
 			}
 
 			/* Place input in the echo stream */
-			// TODO: fixme
-			// if(window->echo_stream != NULL) 
-			// 	glk_put_string_stream_uni(window->echo_stream, unicode);
+			/* TODO: fixme
+			if(win->echo_stream != NULL) 
+				glk_put_string_stream_uni(window->echo_stream, unicode);*/
 
 			/* Copy the string (but not the NULL at the end) */
-			memcpy(window->line_input_buffer_unicode, unicode, MIN(window->line_input_buffer_max_len, items_written)*sizeof(gunichar));
+			int copycount = MIN(win->line_input_buffer_max_len, items_written);
+			memcpy(win->line_input_buffer_unicode, unicode, copycount * sizeof(gunichar));
 			g_free(unicode);
-			event_throw(evtype_LineInput, window, MIN(window->line_input_buffer_max_len, items_written), 0);
+			event_throw(evtype_LineInput, win, copycount, 0);
 		}
-		else {
+		else 
 			g_warning("%s: Wrong input request type.", __func__);
-		}
 
-		window->input_request_type = INPUT_REQUEST_NONE;
+		win->input_request_type = INPUT_REQUEST_NONE;
 	}
 }
diff --git a/src/input.h b/src/input.h
index e961706..7f1d322 100644
--- a/src/input.h
+++ b/src/input.h
@@ -9,7 +9,7 @@
 #include "window.h"
 #include "event.h"
 
-gboolean on_window_key_press_event(GtkWidget *widget, GdkEventKey *event, winid_t window);
+gboolean on_window_key_press_event(GtkWidget *widget, GdkEventKey *event, winid_t win);
 void on_window_insert_text(GtkTextBuffer *textbuffer, GtkTextIter *location, gchar *text, gint len, gpointer user_data);
-void after_window_insert_text(GtkTextBuffer *textbuffer, GtkTextIter *location, gchar *text, gint len, winid_t window);
+void after_window_insert_text(GtkTextBuffer *textbuffer, GtkTextIter *location, gchar *text, gint len, winid_t win);
 #endif
diff --git a/src/stream.c b/src/stream.c
index b737f35..abcf2dd 100644
--- a/src/stream.c
+++ b/src/stream.c
@@ -13,31 +13,32 @@ strid_t
 window_stream_new(winid_t window)
 {
 	/* Create stream and connect it to window */
-	strid_t s = g_new0(struct glk_stream_struct, 1);
-	s->file_mode = filemode_Write;
-	s->stream_type = STREAM_TYPE_WINDOW;
-	s->window = window;
+	strid_t str = g_new0(struct glk_stream_struct, 1);
+	str->file_mode = filemode_Write;
+	str->type = STREAM_TYPE_WINDOW;
+	str->window = window;
+	
 	/* Add it to the global stream list */
-	stream_list = g_list_prepend(stream_list, s);
-	s->stream_list = stream_list;
+	stream_list = g_list_prepend(stream_list, str);
+	str->stream_list = stream_list;
 
-	return s;
+	return str;
 }
 
 /**
  * glk_stream_iterate:
- * @str: A stream, or #NULL.
- * @rockptr: Return location for the next window's rock, or #NULL.
+ * @str: A stream, or %NULL.
+ * @rockptr: Return location for the next window's rock, or %NULL.
  *
- * Iterates over the list of streams; if @str is #NULL, it returns the first
+ * Iterates over the list of streams; if @str is %NULL, it returns the first
  * stream, otherwise the next stream after @str. If there are no more, it
- * returns #NULL. The stream's rock is stored in @rockptr. If you don't want
- * the rocks to be returned, you may set @rockptr to #NULL.
+ * returns %NULL. The stream's rock is stored in @rockptr. If you don't want
+ * the rocks to be returned, you may set @rockptr to %NULL.
  *
  * The order in which streams are returned is arbitrary. The order may change
  * every time you create or destroy a stream, invalidating the iteration.
  *
- * Returns: the next stream, or #NULL if there are no more.
+ * Returns: the next stream, or %NULL if there are no more.
  */
 strid_t
 glk_stream_iterate(strid_t str, glui32 *rockptr)
@@ -74,17 +75,18 @@ glk_stream_get_rock(strid_t str)
 
 /**
  * glk_stream_set_current:
- * @str: An output stream, or NULL.
+ * @str: An output stream, or %NULL.
  *
- * Sets the current stream to @str, or to nothing if @str is #NULL.
+ * Sets the current stream to @str, which must be an output stream. You may set
+ * the current stream to %NULL, which means the current stream is not set to
+ * anything. 
  */
 void
 glk_stream_set_current(strid_t str)
 {
 	if(str != NULL && str->file_mode == filemode_Read)
 	{
-		g_warning("glk_stream_set_current: "
-			"Cannot set current stream to non output stream");
+		g_warning("%s: Cannot set current stream to non output stream", __func__);
 		return;
 	}
 
@@ -94,7 +96,7 @@ glk_stream_set_current(strid_t str)
 /**
  * glk_stream_get_current:
  * 
- * Returns the current stream, or #NULL if there is none.
+ * Returns the current stream, or %NULL if there is none.
  *
  * Returns: A stream.
  */
@@ -108,12 +110,12 @@ glk_stream_get_current()
  * glk_put_char:
  * @ch: A character in Latin-1 encoding.
  *
- * Prints one character @ch to the current stream.
+ * Prints one character to the current stream. As with all basic functions, the
+ * character is assumed to be in the Latin-1 character encoding.
  */
 void
 glk_put_char(unsigned char ch)
 {
-	/* Illegal to print to the current stream if it is NULL */
 	g_return_if_fail(current_stream != NULL);
 	glk_put_char_stream(current_stream, ch);
 }
@@ -122,12 +124,17 @@ glk_put_char(unsigned char ch)
  * glk_put_string:
  * @s: A null-terminated string in Latin-1 encoding.
  *
- * Prints @s to the current stream.
+ * Prints a null-terminated string to the current stream. It is exactly
+ * equivalent to:
+ * <informalexample><programlisting>
+ * for (ptr = s; *ptr; ptr++)
+ * 	glk_put_char(*ptr);
+ * </programlisting></informalexample>
+ * However, it may be more efficient.
  */
 void
 glk_put_string(char *s)
 {
- 	/* Illegal to print to the current stream if it is NULL */
 	g_return_if_fail(current_stream != NULL);
 	glk_put_string_stream(current_stream, s);
 }
@@ -137,12 +144,17 @@ glk_put_string(char *s)
  * @buf: An array of characters in Latin-1 encoding.
  * @len: Length of @buf.
  *
- * Prints @buf to the current stream.
+ * Prints a block of characters to the current stream. It is exactly equivalent
+ * to:
+ * <informalexample><programlisting>
+ * for (i = 0; i < len; i++)
+ * 	glk_put_char(buf[i]);
+ * </programlisting></informalexample>
+ * However, it may be more efficient.
  */
 void
 glk_put_buffer(char *buf, glui32 len)
 {
-	/* Illegal to print to the current stream if it is NULL */
 	g_return_if_fail(current_stream != NULL);
 	glk_put_buffer_stream(current_stream, buf, len);
 }
@@ -176,8 +188,8 @@ glk_put_buffer(char *buf, glui32 len)
  * The data is written to the buffer exactly as it was passed to the printing
  * functions (glk_put_char(), etc.); input functions will read the data exactly
  * as it exists in memory. No platform-dependent cookery will be done on it.
- * [You can write a disk file in text mode, but a memory stream is effectively
- * always in binary mode.]
+ * (You can write a disk file in text mode, but a memory stream is effectively
+ * always in binary mode.)
  *
  * Unicode values (characters greater than 255) cannot be written to the buffer.
  * If you try, they will be stored as 0x3F ("?") characters.
@@ -192,20 +204,20 @@ glk_stream_open_memory(char *buf, glui32 buflen, glui32 fmode, glui32 rock)
 {
 	g_return_val_if_fail(fmode != filemode_WriteAppend, NULL);
 	
-	strid_t s = g_new0(struct glk_stream_struct, 1);
-	s->rock = rock;
-	s->file_mode = fmode;
-	s->stream_type = STREAM_TYPE_MEMORY;
-	s->buffer = buf;
-	s->mark = 0;
-	s->buflen = buflen;
-	s->unicode = FALSE;
+	strid_t str = g_new0(struct glk_stream_struct, 1);
+	str->rock = rock;
+	str->file_mode = fmode;
+	str->type = STREAM_TYPE_MEMORY;
+	str->buffer = buf;
+	str->mark = 0;
+	str->buflen = buflen;
+	str->unicode = FALSE;
 
 	/* Add it to the global stream list */
-	stream_list = g_list_prepend(stream_list, s);
-	s->stream_list = stream_list;
+	stream_list = g_list_prepend(stream_list, str);
+	str->stream_list = stream_list;
 
-	return s;
+	return str;
 }
 
 /**
@@ -222,25 +234,24 @@ glk_stream_open_memory(char *buf, glui32 buflen, glui32 fmode, glui32 rock)
  * bytes.
  */
 strid_t
-glk_stream_open_memory_uni(glui32 *buf, glui32 buflen, glui32 fmode, 
-	glui32 rock)
+glk_stream_open_memory_uni(glui32 *buf, glui32 buflen, glui32 fmode, glui32 rock)
 {
 	g_return_val_if_fail(fmode != filemode_WriteAppend, NULL);
 	
-	strid_t s = g_new0(struct glk_stream_struct, 1);
-	s->rock = rock;
-	s->file_mode = fmode;
-	s->stream_type = STREAM_TYPE_MEMORY;
-	s->ubuffer = buf;
-	s->mark = 0;
-	s->buflen = buflen;
-	s->unicode = TRUE;
+	strid_t str = g_new0(struct glk_stream_struct, 1);
+	str->rock = rock;
+	str->file_mode = fmode;
+	str->type = STREAM_TYPE_MEMORY;
+	str->ubuffer = buf;
+	str->mark = 0;
+	str->buflen = buflen;
+	str->unicode = TRUE;
 
 	/* Add it to the global stream list */
-	stream_list = g_list_prepend(stream_list, s);
-	s->stream_list = stream_list;
+	stream_list = g_list_prepend(stream_list, str);
+	str->stream_list = stream_list;
 
-	return s;
+	return str;
 }
 
 /* Internal function: create a stream using the given parameters. */
@@ -306,21 +317,21 @@ file_stream_new(frefid_t fileref, glui32 fmode, glui32 rock, gboolean unicode)
 		}
 	}
 	
-	strid_t s = g_new0(struct glk_stream_struct, 1);
-	s->rock = rock;
-	s->file_mode = fmode;
-	s->stream_type = STREAM_TYPE_FILE;
-	s->file_pointer = fp;
-	s->binary = binary;
-	s->unicode = unicode;
-	s->filename = g_filename_to_utf8(fileref->filename, -1, NULL, NULL, NULL);
-	if(s->filename == NULL)
-		s->filename = g_strdup("Unknown file name"); /* fail silently */
+	strid_t str = g_new0(struct glk_stream_struct, 1);
+	str->rock = rock;
+	str->file_mode = fmode;
+	str->type = STREAM_TYPE_FILE;
+	str->file_pointer = fp;
+	str->binary = binary;
+	str->unicode = unicode;
+	str->filename = g_filename_to_utf8(fileref->filename, -1, NULL, NULL, NULL);
+	if(str->filename == NULL)
+		str->filename = g_strdup("Unknown file name"); /* fail silently */
 	/* Add it to the global stream list */
-	stream_list = g_list_prepend(stream_list, s);
-	s->stream_list = stream_list;
+	stream_list = g_list_prepend(stream_list, str);
+	str->stream_list = stream_list;
 
-	return s;
+	return str;
 }
 
 /**
@@ -394,7 +405,7 @@ glk_stream_close(strid_t str, stream_result_t *result)
 	g_return_if_fail(str != NULL);
 	
 	/* Free resources associated with one specific type of stream */
-	switch(str->stream_type)
+	switch(str->type)
 	{
 		case STREAM_TYPE_WINDOW:
 			g_warning("%s: Attempted to close a window stream. Use glk_window_"
@@ -420,20 +431,24 @@ glk_stream_close(strid_t str, stream_result_t *result)
 	stream_close_common(str, result);
 }
 
+/* Internal function: Stuff to do upon closing any type of stream. */
 void
 stream_close_common(strid_t str, stream_result_t *result)
 {
 	/* Remove the stream from the global stream list */
 	stream_list = g_list_delete_link(stream_list, str->stream_list);
+	
 	/* If it was the current output stream, set that to NULL */
 	if(current_stream == str)
 		current_stream = NULL;
+		
 	/* If it was one or more windows' echo streams, set those to NULL */
 	winid_t win;
 	for(win = glk_window_iterate(NULL, NULL); win; 
 		win = glk_window_iterate(win, NULL))
 		if(win->echo_stream == str)
 			win->echo_stream = NULL;
+			
 	/* Return the character counts */
 	if(result) 
 	{
diff --git a/src/stream.h b/src/stream.h
index b5a1e60..04134f5 100644
--- a/src/stream.h
+++ b/src/stream.h
@@ -22,7 +22,7 @@ struct glk_stream_struct
 	glui32 file_mode;
 	glui32 read_count;
 	glui32 write_count;
-	enum StreamType stream_type;
+	enum StreamType type;
 	/* Specific to window stream: the window this stream is connected to */
 	winid_t window;
 	/* For memory and file streams */
diff --git a/src/strio.c b/src/strio.c
index de6ccb4..6b70dfa 100644
--- a/src/strio.c
+++ b/src/strio.c
@@ -4,8 +4,6 @@
 #include <glib.h>
 #include <glib/gstdio.h>
 
-#define min(x,y) ( (x > y)? y : x )
-
 /*
  *
  **************** WRITING FUNCTIONS ********************************************
@@ -71,15 +69,15 @@ write_utf8_to_window(winid_t win, gchar *s)
 	gdk_threads_leave();
 }
 
-/* Internal function: write a UTF-8 buffer with length to a stream. */
+/* Internal function: write a Latin-1 buffer with length to a stream. */
 static void
 write_buffer_to_stream(strid_t str, gchar *buf, glui32 len)
 {
-	switch(str->stream_type)
+	switch(str->type)
 	{
 		case STREAM_TYPE_WINDOW:
 			/* Each window type has a different way of printing to it */
-			switch(str->window->window_type)
+			switch(str->window->type)
 			{
 				/* Printing to these windows' streams does nothing */
 				case wintype_Blank:
@@ -100,8 +98,7 @@ write_buffer_to_stream(strid_t str, gchar *buf, glui32 len)
 					str->write_count += len;
 					break;
 				default:
-					g_warning("%s: Writing to this kind of window unsupported.",
-						__func__);
+					g_warning("%s: Writing to this kind of window unsupported.", __func__);
 			}
 			
 			/* Now write the same buffer to the window's echo stream */
@@ -119,7 +116,7 @@ write_buffer_to_stream(strid_t str, gchar *buf, glui32 len)
 			}
 			if(!str->unicode && str->buffer)
 			{
-				int copycount = min(len, str->buflen - str->mark);
+				int copycount = MIN(len, str->buflen - str->mark);
 				memmove(str->buffer + str->mark, buf, copycount);
 				str->mark += copycount;
 			}
@@ -155,8 +152,7 @@ write_buffer_to_stream(strid_t str, gchar *buf, glui32 len)
 			str->write_count += len;
 			break;
 		default:
-			g_warning("%s: Writing to this kind of stream unsupported.",
-				__func__);
+			g_warning("%s: Writing to this kind of stream unsupported.", __func__);
 	}
 }
 
@@ -299,10 +295,9 @@ glsi32
 glk_get_char_stream(strid_t str)
 {
 	g_return_val_if_fail(str != NULL, -1);
-	g_return_val_if_fail(str->file_mode == filemode_Read
-		|| str->file_mode == filemode_ReadWrite, -1);
+	g_return_val_if_fail(str->file_mode == filemode_Read || str->file_mode == filemode_ReadWrite, -1);
 	
-	switch(str->stream_type)
+	switch(str->type)
 	{
 		case STREAM_TYPE_MEMORY:
 			if(str->unicode)
@@ -354,8 +349,7 @@ glk_get_char_stream(strid_t str)
 				return (ch > 0xFF)? 0x3F : ch;
 			}
 		default:
-			g_warning("%s: Reading from this kind of stream unsupported.",
-				__func__);
+			g_warning("%s: Reading from this kind of stream unsupported.", __func__);
 			return -1;
 	}
 }
@@ -375,19 +369,17 @@ glui32
 glk_get_buffer_stream(strid_t str, char *buf, glui32 len)
 {
 	g_return_val_if_fail(str != NULL, 0);
-	g_return_val_if_fail(str->file_mode == filemode_Read
-		|| str->file_mode == filemode_ReadWrite, 0);
+	g_return_val_if_fail(str->file_mode == filemode_Read || str->file_mode == filemode_ReadWrite, 0);
 	g_return_val_if_fail(buf != NULL, 0);
 	
-	switch(str->stream_type)
+	switch(str->type)
 	{
 		case STREAM_TYPE_MEMORY:
 		{
 			int copycount = 0;
 			if(str->unicode)
 			{
-				while(copycount < len && str->ubuffer 
-					&& str->mark < str->buflen) 
+				while(copycount < len && str->ubuffer && str->mark < str->buflen) 
 				{
 					glui32 ch = str->ubuffer[str->mark++];
 					buf[copycount++] = (ch > 0xFF)? '?' : (char)ch;
@@ -396,7 +388,7 @@ glk_get_buffer_stream(strid_t str, char *buf, glui32 len)
 			else
 			{
 				if(str->buffer) /* if not, copycount stays 0 */
-					copycount = min(len, str->buflen - str->mark);
+					copycount = MIN(len, str->buflen - str->mark);
 				memmove(buf, str->buffer + str->mark, copycount);
 				str->mark += copycount;
 			}
@@ -411,14 +403,12 @@ glk_get_buffer_stream(strid_t str, char *buf, glui32 len)
 				{
 					/* Read len characters of 4 bytes each */
 					unsigned char *readbuffer = g_new0(unsigned char, 4 * len);
-					size_t count = fread(readbuffer, sizeof(unsigned char), 
-						4 * len, str->file_pointer);
+					size_t count = fread(readbuffer, sizeof(unsigned char), 4 * len, str->file_pointer);
 					/* If there was an incomplete character */
 					if(count % 4 != 0) 
 					{
 						count -= count % 4;
-						g_warning("%s: Incomplete character in binary Unicode "
-							"file.", __func__);
+						g_warning("%s: Incomplete character in binary Unicode file.", __func__);
 					}
 					
 					str->read_count += count / 4;
@@ -436,8 +426,7 @@ glk_get_buffer_stream(strid_t str, char *buf, glui32 len)
 				}
 				else /* Regular binary file */
 				{
-					size_t count = fread(buf, sizeof(char), len, 
-						str->file_pointer);
+					size_t count = fread(buf, sizeof(char), len, str->file_pointer);
 					str->read_count += count;
 					return count;
 				}
@@ -457,8 +446,7 @@ glk_get_buffer_stream(strid_t str, char *buf, glui32 len)
 				return foo;
 			}
 		default:
-			g_warning("%s: Reading from this kind of stream unsupported.",
-				__func__);
+			g_warning("%s: Reading from this kind of stream unsupported.", __func__);
 			return 0;
 	}
 }
@@ -484,11 +472,10 @@ glui32
 glk_get_line_stream(strid_t str, char *buf, glui32 len)
 {
 	g_return_val_if_fail(str != NULL, 0);
-	g_return_val_if_fail(str->file_mode == filemode_Read
-		|| str->file_mode == filemode_ReadWrite, 0);
+	g_return_val_if_fail(str->file_mode == filemode_Read || str->file_mode == filemode_ReadWrite, 0);
 	g_return_val_if_fail(buf != NULL, 0);
 
-	switch(str->stream_type)
+	switch(str->type)
 	{
 		case STREAM_TYPE_MEMORY:
 		{
@@ -496,14 +483,12 @@ glk_get_line_stream(strid_t str, char *buf, glui32 len)
 			if(str->unicode)
 			{
 				/* Do it character-by-character */
-				while(copycount < len - 1 && str->ubuffer 
-					&& str->mark < str->buflen) 
+				while(copycount < len - 1 && str->ubuffer && str->mark < str->buflen) 
 				{
 					glui32 ch = str->ubuffer[str->mark++];
 					/* Check for Unicode newline; slightly different than
 					in file streams */
-					if(ch == 0x0A || ch == 0x85 || ch == 0x0C || ch == 0x2028 
-						|| ch == 0x2029)
+					if(ch == 0x0A || ch == 0x85 || ch == 0x0C || ch == 0x2028 || ch == 0x2029)
 					{
 						buf[copycount++] = '\n';
 						break;
@@ -522,9 +507,8 @@ glk_get_line_stream(strid_t str, char *buf, glui32 len)
 			else
 			{
 				if(str->buffer) /* if not, copycount stays 0 */
-					copycount = min(len - 1, str->buflen - str->mark);
-				char *endptr = memccpy(buf, str->buffer + str->mark, '\n',
-					copycount);
+					copycount = MIN(len - 1, str->buflen - str->mark);
+				char *endptr = memccpy(buf, str->buffer + str->mark, '\n', copycount);
 				if(endptr) /* newline was found */
 					copycount = endptr - buf; /* Real copy count */
 				buf[copycount] = '\0';
@@ -543,8 +527,7 @@ glk_get_line_stream(strid_t str, char *buf, glui32 len)
 					int foo;
 					for(foo = 0; foo < len - 1; foo++)
 					{
-						glsi32 ch = 
-							read_ucs4be_char_from_file(str->file_pointer);
+						glsi32 ch = read_ucs4be_char_from_file(str->file_pointer);
 						if(ch == -1) 
 						{
 							buf[foo] = '\0';
@@ -594,8 +577,7 @@ glk_get_line_stream(strid_t str, char *buf, glui32 len)
 				return foo;
 			}
 		default:
-			g_warning("%s: Reading from this kind of stream unsupported.",
-				__func__);
+			g_warning("%s: Reading from this kind of stream unsupported.", __func__);
 			return 0;
 	}
 }
@@ -631,7 +613,7 @@ glk_stream_get_position(strid_t str)
 {
 	g_return_val_if_fail(str != NULL, 0);
 	
-	switch(str->stream_type)
+	switch(str->type)
 	{
 		case STREAM_TYPE_MEMORY:
 			return str->mark;
@@ -683,7 +665,7 @@ glk_stream_set_position(strid_t str, glsi32 pos, glui32 seekmode)
 	g_return_if_fail(!(seekmode == seekmode_Start && pos < 0));
 	g_return_if_fail(!(seekmode == seekmode_End || pos > 0));
 	
-	switch(str->stream_type)
+	switch(str->type)
 	{
 		case STREAM_TYPE_MEMORY:
 			switch(seekmode)
@@ -712,8 +694,7 @@ glk_stream_set_position(strid_t str, glsi32 pos, glui32 seekmode)
 			break;
 		}
 		default:
-			g_warning("%s: Seeking not supported on this type of stream.",
-				__func__);
+			g_warning("%s: Seeking not supported on this type of stream.", __func__);
 			return;
 	}
 }
diff --git a/src/style.c b/src/style.c
index c4f51f9..54b8aa2 100644
--- a/src/style.c
+++ b/src/style.c
@@ -1,5 +1,17 @@
 #include "glk.h"
 
+/**
+ * glk_set_style:
+ * @val: A style.
+ *
+ * Changes the style of the current output stream. @val should be one of 
+ * #style_Normal, #style_Emphasized, #style_Preformatted, #style_Header,
+ * #style_Subheader, #style_Alert, #style_Note, #style_BlockQuote, #style_Input,
+ * #style_User1, or #style_User2. However, any value is actually legal; if the
+ * library does not recognize the style value, it will treat it as
+ * #style_Normal. (This policy allows for the future definition of styles
+ * without breaking old Glk libraries.) 
+ */
 void
 glk_set_style(glui32 val)
 {
diff --git a/src/window.c b/src/window.c
index c8d793c..db0af1a 100644
--- a/src/window.c
+++ b/src/window.c
@@ -5,19 +5,19 @@ static GNode *root_window = NULL;
 
 /**
  * glk_window_iterate:
- * @win: A window, or #NULL.
- * @rockptr: Return location for the next window's rock, or #NULL.
+ * @win: A window, or %NULL.
+ * @rockptr: Return location for the next window's rock, or %NULL.
  *
- * Iterates over the list of windows; if @win is #NULL, it returns the first
+ * Iterates over the list of windows; if @win is %NULL, it returns the first
  * window, otherwise the next window after @win. If there are no more, it
  * returns #NULL. The window's rock is stored in @rockptr. If you don't want
- * the rocks to be returned, you may set @rockptr to #NULL.
+ * the rocks to be returned, you may set @rockptr to %NULL.
  *
  * The order in which windows are returned is arbitrary. The root window is
  * not necessarily first, nor is it necessarily last. The order may change
  * every time you create or destroy a window, invalidating the iteration.
  *
- * Returns: the next window, or #NULL if there are no more.
+ * Returns: the next window, or %NULL if there are no more.
  */
 winid_t
 glk_window_iterate(winid_t win, glui32 *rockptr)
@@ -54,7 +54,8 @@ glk_window_iterate(winid_t win, glui32 *rockptr)
  * glk_window_get_rock:
  * @win: A window.
  * 
- * Returns the window @win's rock value. Pair windows always have rock 0.
+ * Returns @win's rock value. Pair windows always have rock 0; all other windows
+ * have the rock value you created them with.
  *
  * Returns: A rock value.
  */
@@ -69,7 +70,7 @@ glk_window_get_rock(winid_t win)
  * glk_window_get_type:
  * @win: A window.
  *
- * Returns the window @win's type, one of #wintype_Blank, #wintype_Pair,
+ * Returns @win's type, one of #wintype_Blank, #wintype_Pair,
  * #wintype_TextBuffer, #wintype_TextGrid, or #wintype_Graphics.
  *
  * Returns: The window's type.
@@ -78,7 +79,7 @@ glui32
 glk_window_get_type(winid_t win)
 {
 	g_return_val_if_fail(win != NULL, 0);
-	return win->window_type;
+	return win->type;
 }
 
 /**
@@ -86,7 +87,7 @@ glk_window_get_type(winid_t win)
  * @win: A window.
  *
  * Returns the window @win's parent window. If @win is the root window, this
- * returns #NULL, since the root window has no parent. Remember that the parent
+ * returns %NULL, since the root window has no parent. Remember that the parent
  * of every window is a pair window; other window types are always childless.
  *
  * Returns: A window.
@@ -104,9 +105,9 @@ glk_window_get_parent(winid_t win)
  * @win: A window.
  *
  * Returns the other child of the window @win's parent. If @win is the
- * root window, this returns #NULL.
+ * root window, this returns %NULL.
  *
- * Returns: A window, or NULL.
+ * Returns: A window, or %NULL.
  */
 winid_t
 glk_window_get_sibling(winid_t win)
@@ -176,11 +177,11 @@ glk_window_open(winid_t split, glui32 method, glui32 size, glui32 wintype,
 		return NULL;
 	}
 	/* We only create one window and don't support any more than that */
-	winid_t new_window = g_new0(struct glk_window_struct, 1);
-	root_window = g_node_new(new_window);
+	winid_t win = g_new0(struct glk_window_struct, 1);
+	root_window = g_node_new(win);
 
-	new_window->rock = rock;
-	new_window->window_type = wintype;
+	win->rock = rock;
+	win->type = wintype;
 
 	gdk_threads_enter();
 
@@ -197,74 +198,87 @@ glk_window_open(winid_t split, glui32 method, glui32 size, glui32 wintype,
 		case wintype_Blank:
 		{
 			/* A blank window will be a label without any text */
-			GtkWidget *window = gtk_label_new("");
-			gtk_box_pack_end(vbox, window, TRUE, TRUE, 0);
-			gtk_widget_show(window);
+			GtkWidget *label = gtk_label_new("");
+			gtk_box_pack_end(vbox, label, TRUE, TRUE, 0);
+			gtk_widget_show(label);
 			
-			new_window->widget = window;
+			win->widget = label;
 			/* You can print to a blank window's stream, but it does nothing */
-			new_window->window_stream = window_stream_new(new_window);
-			new_window->echo_stream = NULL;
+			win->window_stream = window_stream_new(win);
+			win->echo_stream = NULL;
 		}
 			break;
 			
 		case wintype_TextBuffer:
 		{
-			GtkWidget *scroll_window = gtk_scrolled_window_new(NULL, NULL);
-			GtkWidget *window = gtk_text_view_new();
-			GtkTextBuffer *buffer = gtk_text_view_get_buffer( GTK_TEXT_VIEW(window) );
+			GtkWidget *scrolledwindow = gtk_scrolled_window_new(NULL, NULL);
+			GtkWidget *textview = gtk_text_view_new();
+			GtkTextBuffer *textbuffer = gtk_text_view_get_buffer( GTK_TEXT_VIEW(textview) );
 
-			gtk_text_view_set_wrap_mode( GTK_TEXT_VIEW(window), GTK_WRAP_WORD_CHAR );
-			gtk_text_view_set_editable( GTK_TEXT_VIEW(window), FALSE );
+			gtk_text_view_set_wrap_mode( GTK_TEXT_VIEW(textview), GTK_WRAP_WORD_CHAR );
+			gtk_text_view_set_editable( GTK_TEXT_VIEW(textview), FALSE );
 
-			gtk_container_add( GTK_CONTAINER(scroll_window), window );
-			gtk_box_pack_end(vbox, scroll_window, TRUE, TRUE, 0);
-			gtk_widget_show_all(scroll_window);
+			gtk_container_add( GTK_CONTAINER(scrolledwindow), textview );
+			gtk_box_pack_end(vbox, scrolledwindow, TRUE, TRUE, 0);
+			gtk_widget_show_all(scrolledwindow);
 
-			new_window->widget = window;
-			new_window->window_stream = window_stream_new(new_window);
-			new_window->echo_stream = NULL;
-			new_window->input_request_type = INPUT_REQUEST_NONE;
-			new_window->line_input_buffer = NULL;
-			new_window->line_input_buffer_unicode = NULL;
+			win->widget = textview;
+			win->window_stream = window_stream_new(win);
+			win->echo_stream = NULL;
+			win->input_request_type = INPUT_REQUEST_NONE;
+			win->line_input_buffer = NULL;
+			win->line_input_buffer_unicode = NULL;
 
 			/* Connect signal handlers */
-			new_window->keypress_handler = g_signal_connect( G_OBJECT(window), "key-press-event", G_CALLBACK(on_window_key_press_event), new_window );
-			g_signal_handler_block( G_OBJECT(window), new_window->keypress_handler );
+			win->keypress_handler = g_signal_connect( G_OBJECT(textview), "key-press-event", G_CALLBACK(on_window_key_press_event), win );
+			g_signal_handler_block( G_OBJECT(textview), win->keypress_handler );
 
-			new_window->insert_text_handler = g_signal_connect_after( G_OBJECT(buffer), "insert-text", G_CALLBACK(after_window_insert_text), new_window );
-			g_signal_handler_block( G_OBJECT(buffer), new_window->insert_text_handler );
+			win->insert_text_handler = g_signal_connect_after( G_OBJECT(textbuffer), "insert-text", G_CALLBACK(after_window_insert_text), win );
+			g_signal_handler_block( G_OBJECT(textbuffer), win->insert_text_handler );
 
-			/* Create an editable tag to indicate editable parts of the window (for line input) */
-			gtk_text_buffer_create_tag(buffer, "uneditable", "editable", FALSE, "editable-set", TRUE, NULL);
+			/* Create an editable tag to indicate uneditable parts of the window
+			(for line input) */
+			gtk_text_buffer_create_tag(textbuffer, "uneditable", "editable", FALSE, "editable-set", TRUE, NULL);
 
 			/* Mark the position where the user will input text */
-			GtkTextIter end_iter;
-			gtk_text_buffer_get_end_iter(buffer, &end_iter);
-			gtk_text_buffer_create_mark(buffer, "input_position", &end_iter, TRUE);
+			GtkTextIter end;
+			gtk_text_buffer_get_end_iter(textbuffer, &end);
+			gtk_text_buffer_create_mark(textbuffer, "input_position", &end, TRUE);
 		}
 			break;
 			
 		default:
-			g_warning("glk_window_open: unsupported window type");
-			g_free(new_window);
+			g_warning("%s: unsupported window type", __func__);
+			g_free(win);
 			gdk_threads_leave();
 			return NULL;
 	}
 
-	new_window->window_node = root_window;
+	win->window_node = root_window;
 
 	gdk_threads_leave();
 
-	return new_window;
+	return win;
 }
 
+/**
+ * glk_window_close:
+ * @win: Window to close.
+ * @result: Pointer to a #stream_result_t in which to store the write count.
+ *
+ * Closes @win, which is pretty much exactly the opposite of opening a window.
+ * It is legal to close all your windows, or to close the root window (which is
+ * the same thing.) 
+ *
+ * The @result argument is filled with the output character count of the window
+ * stream.
+ */
 void
 glk_window_close(winid_t win, stream_result_t *result)
 {
 	g_return_if_fail(win != NULL);
 
-	switch(win->window_type)
+	switch(win->type)
 	{
 		case wintype_TextBuffer:
 			gtk_widget_destroy( gtk_widget_get_parent(win->widget) );
@@ -288,14 +302,36 @@ glk_window_close(winid_t win, stream_result_t *result)
  * glk_window_clear:
  * @win: A window.
  *
- * Erases the window @win.
+ * Erases the window @win. The meaning of this depends on the window type.
+ *
+ * <itemizedlist>
+ *  <listitem><para>
+ *   Text buffer: This may do any number of things, such as delete all text in 
+ *   the window, or print enough blank lines to scroll all text beyond 
+ *   visibility, or insert a page-break marker which is treated specially by the
+ *   display part of the library.
+ *  </para></listitem>
+ *  <listitem><para>
+ *   Text grid: This will clear the window, filling all positions with blanks.
+ *   The window cursor is moved to the top left corner (position 0,0).
+ *  </para></listitem>
+ *  <listitem><para>
+ *   Graphics: Clears the entire window to its current background color.
+ *  </para></listitem>
+ *  <listitem><para>
+ *   Other window types: No effect. 
+ *  </para></listitem>
+ * </itemizedlist>
+ *
+ * It is illegal to erase a window which has line input pending. 
  */
 void
 glk_window_clear(winid_t win)
 {
 	g_return_if_fail(win != NULL);
+	g_return_if_fail(win->input_request_type != INPUT_REQUEST_LINE && win->input_request_type != INPUT_REQUEST_LINE_UNICODE);
 	
-	switch(win->window_type)
+	switch(win->type)
 	{
 		case wintype_Blank:
 			/* do nothing */
@@ -306,8 +342,7 @@ glk_window_clear(winid_t win)
 		{
 			gdk_threads_enter();
 
-			GtkTextBuffer *buffer = 
-				gtk_text_view_get_buffer( GTK_TEXT_VIEW(win->widget) );
+			GtkTextBuffer *buffer = gtk_text_view_get_buffer( GTK_TEXT_VIEW(win->widget) );
 			GtkTextIter start, end;
 			gtk_text_buffer_get_bounds(buffer, &start, &end);
 			gtk_text_buffer_delete(buffer, &start, &end);
@@ -325,7 +360,10 @@ glk_window_clear(winid_t win)
  * glk_set_window:
  * @win: A window.
  *
- * Sets the current stream to @win's window stream.
+ * Sets the current stream to @win's window stream. It is exactly equivalent to
+ * <informalexample><programlisting>
+ *  glk_stream_set_current(glk_window_get_stream(win))
+ * </programlisting></informalexample>
  */
 void
 glk_set_window(winid_t win)
@@ -337,7 +375,9 @@ glk_set_window(winid_t win)
  * glk_window_get_stream:
  * @win: A window.
  *
- * Gets the stream associated with @win.
+ * Returns the stream which is associated with @win. Every window has a stream
+ * which can be printed to, but this may not be useful, depending on the window
+ * type. (For example, printing to a blank window's stream has no effect.)
  *
  * Returns: The window stream.
  */
@@ -350,7 +390,7 @@ strid_t glk_window_get_stream(winid_t win)
 /**
  * glk_window_set_echo_stream:
  * @win: A window.
- * @str: A stream to attach to the window, or #NULL.
+ * @str: A stream to attach to the window, or %NULL.
  *
  * Attaches the stream @str to @win as a second stream. Any text printed to the
  * window is also echoed to this second stream, which is called the window's
@@ -368,7 +408,7 @@ strid_t glk_window_get_stream(winid_t win)
  * which would create an infinite loop. It is similarly illegal to create a
  * longer loop (two or more windows echoing to each other.)
  *
- * You can reset a window to stop echoing by setting @str to #NULL.
+ * You can reset a window to stop echoing by setting @str to %NULL.
  */
 void
 glk_window_set_echo_stream(winid_t win, strid_t str)
@@ -376,20 +416,18 @@ glk_window_set_echo_stream(winid_t win, strid_t str)
 	g_return_if_fail(win != NULL);
 	
 	/* Test for an infinite loop */
-	strid_t next_str;
-	for(next_str = str;
-		next_str != NULL && next_str->stream_type == STREAM_TYPE_WINDOW;
-		next_str = next_str->window->echo_stream)
+	strid_t next = str;
+	for(; next && next->type == STREAM_TYPE_WINDOW; next = next->window->echo_stream)
 	{
-		if(next_str == win->window_stream)
+		if(next == win->window_stream)
 		{
-			g_warning("glk_window_set_echo_stream: Infinite loop detected");
+			g_warning("%s: Infinite loop detected", __func__);
 			win->echo_stream = NULL;
 			return;
 		}
 	}
 	
-	win->echo_stream = str;	
+	win->echo_stream = str;
 }
 
 /**
@@ -397,9 +435,9 @@ glk_window_set_echo_stream(winid_t win, strid_t str)
  * @win: A window.
  *
  * Returns the echo stream of window @win. If the window has no echo stream (as
- * is initially the case) then this returns #NULL.
+ * is initially the case) then this returns %NULL.
  *
- * Returns: A stream, or #NULL.
+ * Returns: A stream, or %NULL.
  */
 strid_t
 glk_window_get_echo_stream(winid_t win)
@@ -408,11 +446,25 @@ glk_window_get_echo_stream(winid_t win)
 	return win->echo_stream;
 }
 
+/**
+ * glk_window_get_size:
+ * @win: A window.
+ * @widthptr: Pointer to a location to store the window's width, or %NULL.
+ * @heightptr: Pointer to a location to store the window's height, or %NULL.
+ *
+ * Simply returns the actual size of the window, in its measurement system.
+ * Either @widthptr or @heightptr can be %NULL, if you only want one 
+ * measurement. (Or, in fact, both, if you want to waste time.)
+ */
 void
 glk_window_get_size(winid_t win, glui32 *widthptr, glui32 *heightptr)
 {
 	g_return_if_fail(win != NULL);
 
+	/* TODO: Write this function */
+	/* For a text buffer window: Return the number of rows and columns which
+	would be available _if_ the window was filled with "0" (zero) characters in
+	the "normal" font. */
 	if(widthptr != NULL) {
 		*widthptr = 0;
 	}
@@ -422,8 +474,40 @@ glk_window_get_size(winid_t win, glui32 *widthptr, glui32 *heightptr)
 	}
 }
 
+/**
+ * glk_window_move_cursor:
+ * @win: A text grid window.
+ * @xpos: Horizontal cursor position.
+ * @ypos: Vertical cursor position.
+ * 
+ * Sets the cursor position. If you move the cursor right past the end of a 
+ * line, it wraps; the next character which is printed will appear at the
+ * beginning of the next line.
+ * 
+ * If you move the cursor below the last line, or when the cursor reaches the
+ * end of the last line, it goes "off the screen" and further output has no
+ * effect. You must call glk_window_move_cursor() or glk_window_clear() to move
+ * the cursor back into the visible region.
+ * 
+ * <note><para>
+ *  Note that the arguments of glk_window_move_cursor() are <type>unsigned 
+ *  int</type>s. This is okay, since there are no negative positions. If you try
+ *  to pass a negative value, Glk will interpret it as a huge positive value,
+ *  and it will wrap or go off the last line.
+ * </para></note>
+ *
+ * <note><para>
+ *  Also note that the output cursor is not necessarily visible. In particular,
+ *  when you are requesting line or character input in a grid window, you cannot
+ *  rely on the cursor position to prompt the player where input is indicated.
+ *  You should print some character prompt at that spot -- a ">" character, for
+ *  example.
+ * </para></note>
+ */
 void
 glk_window_move_cursor(winid_t win, glui32 xpos, glui32 ypos)
 {
 	g_return_if_fail(win != NULL);
+	g_return_if_fail(win->type == wintype_TextGrid);
+	/* TODO: write this function */
 }
diff --git a/src/window.h b/src/window.h
index 73583a3..1fb98ce 100644
--- a/src/window.h
+++ b/src/window.h
@@ -24,7 +24,7 @@ struct glk_window_struct
 	/* Pointer to the node in the global tree that contains this window */
 	GNode *window_node;
 	/* Window parameters */
-	glui32 window_type;
+	glui32 type;
 	GtkWidget *widget;
 	strid_t window_stream;
 	strid_t echo_stream;