Code opschonen, toevoegen documentatie
authorPhilip Chimento <philip.chimento@gmail.com>
Sun, 24 Aug 2008 00:37:04 +0000 (00:37 +0000)
committerPhilip Chimento <philip.chimento@gmail.com>
Sun, 24 Aug 2008 00:37:04 +0000 (00:37 +0000)
git-svn-id: http://lassie.dyndns-server.com/svn/gargoyle-gtk@11 ddfedd41-794f-dd11-ae45-00112f111e67

13 files changed:
src/case.c
src/event.c
src/event.h
src/gestalt.c
src/glk.c
src/input.c
src/input.h
src/stream.c
src/stream.h
src/strio.c
src/style.c
src/window.c
src/window.h

index ecb7862bd7291e3866edee3aea5eff982c26d7ae..9e73de10240413aa315dae16a94e27c8887ab89c 100644 (file)
@@ -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 */
index 0334e3925129618a3b21d1a747a04a44c656d119..76f82409ad5bcddf4201fa2e17b60b23c20c7796 100644 (file)
@@ -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);
index 3acbdee90a2bc0c6be8223b1bccb28e5d1b17de9..b17335c0fd1a4ab2a8a31b550637764f78948140 100644 (file)
@@ -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();
index 1bb7f7e9c5bda60308a37c6b10e818ac5609562a..4a586ce1d192cce9b2a470e0b20c2b7b753dfaa1 100644 (file)
@@ -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:
index fc22682676d383f7f2aed2be6fdb435b77eeeed9..dbec7596f581f478af528bc8473699e1b1820e5f 100644 (file)
--- 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();
-}
-*/
-
-
index caa1824c5d92e75b4c54fce70fa23ff1f9dcfb09..d9b0965bd3f9e1d4666cbd5e7ef90294889d4d01 100644 (file)
@@ -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;
        }
 }
index e961706a3e961000424c0f9c0c285a91833b146c..7f1d322d391e92b6a224c6548030d1c198374757 100644 (file)
@@ -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
index b737f356f798766089dffbd097b06c4772fdc34a..abcf2dda5e9016553a6aa1229f5173fb2849877c 100644 (file)
@@ -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) 
        {
index b5a1e6092edf7bed4c74eea92bbe2163cf09396c..04134f5807f307b592adc5779eaca1208743bc00 100644 (file)
@@ -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 */
index de6ccb48f5ed9057cb15dd5606078b7b527a1a77..6b70dfa3bd3ce904530df6a577c7fbe2c02ba02d 100644 (file)
@@ -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;
        }
 }
index c4f51f9a7ca81ffa89e439a10ca7a9c03d6e873d..54b8aa2d687a47c93f76936cf7e58b809e9ecf9b 100644 (file)
@@ -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)
 {
index c8d793c4e3396989a6eacd20138f2f22a3a1bb31..db0af1a23b6a171c5c453d808f53e73d0e3956e4 100644 (file)
@@ -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 */
 }
index 73583a352d902cb4e075f23082ad156396c6db0a..1fb98ce2a7cbc6dac20c7b6e9a2ab8f6b1a135ae 100644 (file)
@@ -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;