Eerste import.
authorPhilip Chimento <philip.chimento@gmail.com>
Sat, 12 Jul 2008 00:35:15 +0000 (00:35 +0000)
committerPhilip Chimento <philip.chimento@gmail.com>
Sat, 12 Jul 2008 00:35:15 +0000 (00:35 +0000)
Philip en Marijn zijn vet goed!

git-svn-id: http://lassie.dyndns-server.com/svn/gargoyle-gtk@1 ddfedd41-794f-dd11-ae45-00112f111e67

16 files changed:
.ignore [new file with mode: 0644]
src/Makefile [new file with mode: 0644]
src/callbacks.c [new file with mode: 0644]
src/callbacks.h [new file with mode: 0644]
src/error.c [new file with mode: 0644]
src/error.h [new file with mode: 0644]
src/first.c [new file with mode: 0644]
src/gargoyle-gtk.glade [new file with mode: 0644]
src/glk.c [new file with mode: 0644]
src/glk.h [new file with mode: 0644]
src/main.c [new file with mode: 0644]
src/model.c [new file with mode: 0644]
src/stream.c [new file with mode: 0644]
src/stream.h [new file with mode: 0644]
src/window.c [new file with mode: 0644]
src/window.h [new file with mode: 0644]

diff --git a/.ignore b/.ignore
new file mode 100644 (file)
index 0000000..6cef4eb
--- /dev/null
+++ b/.ignore
@@ -0,0 +1,4 @@
+*.o
+*.ui
+*.swp
+gargoyle-gtk
diff --git a/src/Makefile b/src/Makefile
new file mode 100644 (file)
index 0000000..f9ea8a6
--- /dev/null
@@ -0,0 +1,26 @@
+PKG_CONFIG = gtk+-2.0
+SOURCES = main.c \
+                 callbacks.c callbacks.h \
+                 error.c error.h \
+                 stream.c stream.h \
+                 window.c window.h \
+                 glk.c glk.h \
+                 model.c
+OBJECTS = main.o \
+                 callbacks.o \
+                 error.o \
+                 stream.o \
+                 window.o \
+                 glk.o \
+                 model.o
+
+CFLAGS = -g -Wall -O0 -export-dynamic `pkg-config --cflags ${PKG_CONFIG}`
+LIBS = -export-dynamic `pkg-config --libs ${PKG_CONFIG}`
+
+all: gargoyle-gtk gargoyle-gtk.ui
+
+gargoyle-gtk: ${OBJECTS}
+       ${CC} ${LIBS} -o gargoyle-gtk ${OBJECTS}
+
+gargoyle-gtk.ui: gargoyle-gtk.glade
+       gtk-builder-convert gargoyle-gtk.glade gargoyle-gtk.ui
diff --git a/src/callbacks.c b/src/callbacks.c
new file mode 100644 (file)
index 0000000..34cd66e
--- /dev/null
@@ -0,0 +1,41 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
+/*
+ * callbacks.c
+ * Copyright (C) Philip en Marijn 2008 <>
+ * 
+ * callbacks.c is free software copyrighted by Philip en Marijn.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name ``Philip en Marijn'' nor the name of any other
+ *    contributor may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ * 
+ * callbacks.c IS PROVIDED BY Philip en Marijn ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL Philip en Marijn OR ANY OTHER CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <gtk/gtk.h>
+#include "error.h"
+
+#include "callbacks.h"
+
+
+void on_save_tool_button_clicked(GtkToolButton *toolbutton, gpointer user_data) {
+       error_dialog( GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(toolbutton))), NULL, "Not implemented yet" );
+}
diff --git a/src/callbacks.h b/src/callbacks.h
new file mode 100644 (file)
index 0000000..6fd524e
--- /dev/null
@@ -0,0 +1,35 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
+/*
+ * callbacks.h
+ * Copyright (C) Philip en Marijn 2008 <>
+ * 
+ * callbacks.h is free software copyrighted by Philip en Marijn.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name ``Philip en Marijn'' nor the name of any other
+ *    contributor may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ * 
+ * callbacks.h IS PROVIDED BY Philip en Marijn ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL Philip en Marijn OR ANY OTHER CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <gtk/gtk.h>
+
+void on_save_tool_button_clicked(GtkToolButton *toolbutton, gpointer user_data);
diff --git a/src/error.c b/src/error.c
new file mode 100644 (file)
index 0000000..c9b6f08
--- /dev/null
@@ -0,0 +1,52 @@
+/*  Copyright 2006 P.F. Chimento
+ *  This file is part of GNOME Inform 7.
+ * 
+ *  GNOME Inform 7 is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GNOME Inform 7 is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with GNOME Inform 7; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+#include <gtk/gtk.h>
+#include <stdarg.h>
+
+#include "error.h"
+
+/* Create and display an error dialog box, with parent window parent, and
+message format string msg. If err is not NULL, tack the error message on to the
+end of the format string. */
+void 
+error_dialog(GtkWindow *parent, GError *err, const gchar *msg, ...) 
+{
+    va_list ap;
+    
+    va_start(ap, msg);
+    gchar buffer[1024];
+    g_vsnprintf(buffer, 1024, msg, ap);
+    va_end(ap);
+    
+    gchar *message;
+    if(err) {
+        message = g_strconcat(buffer, err->message, NULL);
+        g_error_free(err);
+    } else
+        message = g_strdup(buffer);
+    
+    GtkWidget *dialog = gtk_message_dialog_new(parent,
+          parent? GTK_DIALOG_DESTROY_WITH_PARENT : 0,
+          GTK_MESSAGE_ERROR,
+          GTK_BUTTONS_OK,
+          message);
+    gtk_dialog_run(GTK_DIALOG(dialog));
+    gtk_widget_destroy(dialog);
+    g_free(message);
+}
diff --git a/src/error.h b/src/error.h
new file mode 100644 (file)
index 0000000..bb05fbe
--- /dev/null
@@ -0,0 +1,27 @@
+/*  Copyright 2006 P.F. Chimento
+ *  This file is part of GNOME Inform 7.
+ * 
+ *  GNOME Inform 7 is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GNOME Inform 7 is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with GNOME Inform 7; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+#ifndef ERROR_H
+#define ERROR_H
+
+#include <stdarg.h>
+#include <gtk/gtk.h>
+
+void error_dialog(GtkWindow *parent, GError *err, const gchar *msg, ...);
+
+#endif
diff --git a/src/first.c b/src/first.c
new file mode 100644 (file)
index 0000000..3f004a8
--- /dev/null
@@ -0,0 +1,582 @@
+#include "glk.h"
+
+/* model.c: Model program for Glk API, version 0.5.
+    Designed by Andrew Plotkin <erkyrath@eblong.com>
+    http://www.eblong.com/zarf/glk/index.html
+    This program is in the public domain.
+*/
+
+/* This is a simple model of a text adventure which uses the Glk API.
+    It shows how to input a line of text, display results, maintain a
+    status window, write to a transcript file, and so on. */
+
+/* This is the cleanest possible form of a Glk program. It includes only
+    "glk.h", and doesn't call any functions outside Glk at all. We even
+    define our own str_eq() and str_len(), rather than relying on the
+    standard libraries. */
+
+/* We also define our own TRUE and FALSE and NULL. */
+#ifndef TRUE
+#define TRUE 1
+#endif
+#ifndef FALSE
+#define FALSE 0
+#endif
+#ifndef NULL
+#define NULL 0
+#endif
+
+/* The story, status, and quote windows. */
+static winid_t mainwin = NULL;
+static winid_t statuswin = NULL;
+static winid_t quotewin = NULL;
+
+/* A file reference for the transcript file. */
+static frefid_t scriptref = NULL;
+/* A stream for the transcript file, when it's open. */
+static strid_t scriptstr = NULL;
+
+/* Your location. This determines what appears in the status line. */
+static int current_room; 
+
+/* A flag indicating whether you should look around. */
+static int need_look; 
+
+/* Forward declarations */
+void glk_main(void);
+
+static void draw_statuswin(void);
+static int yes_or_no(void);
+
+static int str_eq(char *s1, char *s2);
+static int str_len(char *s1);
+
+static void verb_help(void);
+static void verb_jump(void);
+static void verb_yada(void);
+static void verb_quote(void);
+static void verb_move(void);
+static void verb_quit(void);
+static void verb_script(void);
+static void verb_unscript(void);
+static void verb_save(void);
+static void verb_restore(void);
+
+/* The glk_main() function is called by the Glk system; it's the main entry
+    point for your program. */
+void glk_main(void)
+{
+    /* Open the main window. */
+    mainwin = glk_window_open(0, 0, 0, wintype_TextBuffer, 1);
+    if (!mainwin) {
+        /* It's possible that the main window failed to open. There's
+            nothing we can do without it, so exit. */
+        return; 
+    }
+    
+    /* Set the current output stream to print to it. */
+    glk_set_window(mainwin);
+    
+    /* Open a second window: a text grid, above the main window, three lines
+        high. It is possible that this will fail also, but we accept that. */
+    statuswin = glk_window_open(mainwin, winmethod_Above | winmethod_Fixed, 
+        3, wintype_TextGrid, 0);
+
+    /* The third window, quotewin, isn't opened immediately. We'll do
+        that in verb_quote(). */
+
+    glk_put_string("Model Glk Program\nAn Interactive Model Glk Program\n");
+    glk_put_string("By Andrew Plotkin.\nRelease 7.\n");
+    glk_put_string("Type \"help\" for a list of commands.\n");
+
+    current_room = 0; /* Set initial location. */
+    need_look = TRUE;
+    
+    while (1) {
+        char commandbuf[256];
+        char *cx, *cmd;
+        int gotline, len;
+        event_t ev;
+        
+        draw_statuswin();
+        
+        if (need_look) {
+            need_look = FALSE;
+            glk_put_string("\n");
+            glk_set_style(style_Subheader);
+            if (current_room == 0)
+                glk_put_string("The Room\n");
+            else
+                glk_put_string("A Different Room\n");
+            glk_set_style(style_Normal);
+            glk_put_string("You're in a room of some sort.\n");
+        }
+        
+        glk_put_string("\n>");
+        /* We request up to 255 characters. The buffer can hold 256, but we
+            are going to stick a null character at the end, so we have to
+            leave room for that. Note that the Glk library does *not*
+            put on that null character. */
+        glk_request_line_event(mainwin, commandbuf, 255, 0);
+        
+        gotline = FALSE;
+        while (!gotline) {
+        
+            /* Grab an event. */
+            glk_select(&ev);
+            
+            switch (ev.type) {
+            
+                case evtype_LineInput:
+                    if (ev.win == mainwin) {
+                        gotline = TRUE;
+                        /* Really the event can *only* be from mainwin,
+                            because we never request line input from the
+                            status window. But we do a paranoia test,
+                            because commandbuf is only filled if the line
+                            event comes from the mainwin request. If the
+                            line event comes from anywhere else, we ignore
+                            it. */
+                    }
+                    break;
+                    
+                case evtype_Arrange:
+                    /* Windows have changed size, so we have to redraw the
+                        status window. */
+                    draw_statuswin();
+                    break;
+            }
+        }
+        
+        /* commandbuf now contains a line of input from the main window.
+            You would now run your parser and do something with it. */
+        
+        /* First, if there's a blockquote window open, let's close it. 
+            This ensures that quotes remain visible for exactly one
+            command. */
+        if (quotewin) {
+            glk_window_close(quotewin, NULL);
+            quotewin = 0;
+        }
+        
+        /* The line we have received in commandbuf is not null-terminated.
+            We handle that first. */
+        len = ev.val1; /* Will be between 0 and 255, inclusive. */
+        commandbuf[len] = '\0';
+        
+        /* Then squash to lower-case. */
+        for (cx = commandbuf; *cx; cx++) { 
+            *cx = glk_char_to_lower(*cx);
+        }
+        
+        /* Then trim whitespace before and after. */
+        
+        for (cx = commandbuf; *cx == ' '; cx++) { };
+        
+        cmd = cx;
+        
+        for (cx = commandbuf+len-1; cx >= cmd && *cx == ' '; cx--) { };
+        *(cx+1) = '\0';
+        
+        /* cmd now points to a nice null-terminated string. We'll do the
+            simplest possible parsing. */
+        if (str_eq(cmd, "")) {
+            glk_put_string("Excuse me?\n");
+        }
+        else if (str_eq(cmd, "help")) {
+            verb_help();
+        }
+        else if (str_eq(cmd, "move")) {
+            verb_move();
+        }
+        else if (str_eq(cmd, "jump")) {
+            verb_jump();
+        }
+        else if (str_eq(cmd, "yada")) {
+            verb_yada();
+        }
+        else if (str_eq(cmd, "quote")) {
+            verb_quote();
+        }
+        else if (str_eq(cmd, "quit")) {
+            verb_quit();
+        }
+        else if (str_eq(cmd, "save")) {
+            verb_save();
+        }
+        else if (str_eq(cmd, "restore")) {
+            verb_restore();
+        }
+        else if (str_eq(cmd, "script")) {
+            verb_script();
+        }
+        else if (str_eq(cmd, "unscript")) {
+            verb_unscript();
+        }
+        else {
+            glk_put_string("I don't understand the command \"");
+            glk_put_string(cmd);
+            glk_put_string("\".\n");
+        }
+    }
+}
+
+static void draw_statuswin(void)
+{
+    char *roomname;
+    glui32 width, height;
+    
+    if (!statuswin) {
+        /* It is possible that the window was not successfully 
+            created. If that's the case, don't try to draw it. */
+        return;
+    }
+    
+    if (current_room == 0)
+        roomname = "The Room";
+    else
+        roomname = "A Different Room";
+    
+    glk_set_window(statuswin);
+    glk_window_clear(statuswin);
+    
+    glk_window_get_size(statuswin, &width, &height);
+    
+    /* Print the room name, centered. */
+    glk_window_move_cursor(statuswin, (width - str_len(roomname)) / 2, 1);
+    glk_put_string(roomname);
+    
+    /* Draw a decorative compass rose in the upper right. */
+    glk_window_move_cursor(statuswin, width - 3, 0);
+    glk_put_string("\\|/");
+    glk_window_move_cursor(statuswin, width - 3, 1);
+    glk_put_string("-*-");
+    glk_window_move_cursor(statuswin, width - 3, 2);
+    glk_put_string("/|\\");
+    
+    glk_set_window(mainwin);
+}
+
+static int yes_or_no(void)
+{
+    char commandbuf[256];
+    char *cx;
+    int gotline, len;
+    event_t ev;
+    
+    draw_statuswin();
+    
+    /* This loop is identical to the main command loop in glk_main(). */
+    
+    while (1) {
+        glk_request_line_event(mainwin, commandbuf, 255, 0);
+        
+        gotline = FALSE;
+        while (!gotline) {
+        
+            glk_select(&ev);
+            
+            switch (ev.type) {
+                case evtype_LineInput:
+                    if (ev.win == mainwin) {
+                        gotline = TRUE;
+                    }
+                    break;
+                    
+                case evtype_Arrange:
+                    draw_statuswin();
+                    break;
+            }
+        }
+        
+        len = ev.val1;
+        commandbuf[len] = '\0';
+        for (cx = commandbuf; *cx == ' '; cx++) { };
+        
+        if (*cx == 'y' || *cx == 'Y')
+            return TRUE;
+        if (*cx == 'n' || *cx == 'N')
+            return FALSE;
+            
+        glk_put_string("Please enter \"yes\" or \"no\": ");
+    }
+    
+}
+
+static void verb_help(void)
+{
+    glk_put_string("This model only understands the following commands:\n");
+    glk_put_string("HELP: Display this list.\n");
+    glk_put_string("JUMP: A verb which just prints some text.\n");
+    glk_put_string("YADA: A verb which prints a very long stream of text.\n");
+    glk_put_string("MOVE: A verb which prints some text, and also changes the status line display.\n");
+    glk_put_string("QUOTE: A verb which displays a block quote in a temporary third window.\n");
+    glk_put_string("SCRIPT: Turn on transcripting, so that output will be echoed to a text file.\n");
+    glk_put_string("UNSCRIPT: Turn off transcripting.\n");
+    glk_put_string("SAVE: Write fake data to a save file.\n");
+    glk_put_string("RESTORE: Read it back in.\n");
+    glk_put_string("QUIT: Quit and exit.\n");
+}
+
+static void verb_jump(void)
+{
+    glk_put_string("You jump on the fruit, spotlessly.\n");
+}
+
+static void verb_yada(void)
+{
+    /* This is a goofy (and overly ornate) way to print a long paragraph. 
+        It just shows off line wrapping in the Glk implementation. */
+    #define NUMWORDS (13)
+    static char *wordcaplist[NUMWORDS] = {
+        "Ga", "Bo", "Wa", "Mu", "Bi", "Fo", "Za", "Mo", "Ra", "Po",
+            "Ha", "Ni", "Na"
+    };
+    static char *wordlist[NUMWORDS] = {
+        "figgle", "wob", "shim", "fleb", "moobosh", "fonk", "wabble",
+            "gazoon", "ting", "floo", "zonk", "loof", "lob",
+    };
+    static int wcount1 = 0;
+    static int wcount2 = 0;
+    static int wstep = 1;
+    static int jx = 0;
+    int ix;
+    int first = TRUE;
+    
+    for (ix=0; ix<85; ix++) {
+        if (ix > 0) {
+            glk_put_string(" ");
+        }
+                
+        if (first) {
+            glk_put_string(wordcaplist[(ix / 17) % NUMWORDS]);
+            first = FALSE;
+        }
+        
+        glk_put_string(wordlist[jx]);
+        jx = (jx + wstep) % NUMWORDS;
+        wcount1++;
+        if (wcount1 >= NUMWORDS) {
+            wcount1 = 0;
+            wstep++;
+            wcount2++;
+            if (wcount2 >= NUMWORDS-2) {
+                wcount2 = 0;
+                wstep = 1;
+            }
+        }
+        
+        if ((ix % 17) == 16) {
+            glk_put_string(".");
+            first = TRUE;
+        }
+    }
+    
+    glk_put_char('\n');
+}
+
+static void verb_quote(void)
+{
+    glk_put_string("Someone quotes some poetry.\n");
+
+    /* Open a third window, or clear it if it's already open. Actually,
+        since quotewin is closed right after line input, we know it
+        can't be open. But better safe, etc. */
+    if (!quotewin) {
+        /* A five-line window above the main window, fixed size. */
+        quotewin = glk_window_open(mainwin, winmethod_Above | winmethod_Fixed, 
+            5, wintype_TextBuffer, 0);
+        if (!quotewin) {
+            /* It's possible the quotewin couldn't be opened. In that
+                case, just give up. */
+            return;
+        }
+    }
+    else {
+        glk_window_clear(quotewin);
+    }
+    
+    /* Print some quote. */
+    glk_set_window(quotewin);
+    glk_set_style(style_BlockQuote);
+    glk_put_string("Tomorrow probably never rose or set\n"
+        "Or went out and bought cheese, or anything like that\n"
+        "And anyway, what light through yonder quote box breaks\n"
+        "Handle to my hand?\n");
+    glk_put_string("              -- Fred\n");
+    
+    glk_set_window(mainwin);
+}
+
+static void verb_move(void)
+{
+    current_room = (current_room+1) % 2;
+    need_look = TRUE;
+    
+    glk_put_string("You walk for a while.\n");
+}
+
+static void verb_quit(void)
+{
+    glk_put_string("Are you sure you want to quit? ");
+    if (yes_or_no()) {
+        glk_put_string("Thanks for playing.\n");
+        glk_exit();
+        /* glk_exit() actually stops the process; it does not return. */
+    }
+}
+
+static void verb_script(void)
+{
+    if (scriptstr) {
+        glk_put_string("Scripting is already on.\n");
+        return;
+    }
+    
+    /* If we've turned on scripting before, use the same file reference; 
+        otherwise, prompt the player for a file. */
+    if (!scriptref) {
+        scriptref = glk_fileref_create_by_prompt(
+            fileusage_Transcript | fileusage_TextMode, 
+            filemode_WriteAppend, 0);
+        if (!scriptref) {
+            glk_put_string("Unable to place script file.\n");
+            return;
+        }
+    }
+    
+    /* Open the file. */
+    scriptstr = glk_stream_open_file(scriptref, filemode_WriteAppend, 0);
+    if (!scriptstr) {
+        glk_put_string("Unable to write to script file.\n");
+        return;
+    }
+    glk_put_string("Scripting on.\n");
+    glk_window_set_echo_stream(mainwin, scriptstr);
+    glk_put_string_stream(scriptstr, 
+        "This is the beginning of a transcript.\n");
+}
+
+static void verb_unscript(void)
+{
+    if (!scriptstr) {
+        glk_put_string("Scripting is already off.\n");
+        return;
+    }
+    
+    /* Close the file. */
+    glk_put_string_stream(scriptstr, 
+        "This is the end of a transcript.\n\n");
+    glk_stream_close(scriptstr, NULL);
+    glk_put_string("Scripting off.\n");
+    scriptstr = NULL;
+}
+
+static void verb_save(void)
+{
+    int ix;
+    frefid_t saveref;
+    strid_t savestr;
+    
+    saveref = glk_fileref_create_by_prompt(
+        fileusage_SavedGame | fileusage_BinaryMode, 
+        filemode_Write, 0);
+    if (!saveref) {
+        glk_put_string("Unable to place save file.\n");
+        return;
+    }
+    
+    savestr = glk_stream_open_file(saveref, filemode_Write, 0);
+    if (!savestr) {
+        glk_put_string("Unable to write to save file.\n");
+        glk_fileref_destroy(saveref);
+        return;
+    }
+
+    glk_fileref_destroy(saveref); /* We're done with the file ref now. */
+    
+    /* Write some binary data. */
+    for (ix=0; ix<256; ix++) {
+        glk_put_char_stream(savestr, (unsigned char)ix);
+    }
+    
+    glk_stream_close(savestr, NULL);
+    
+    glk_put_string("Game saved.\n");
+}
+
+static void verb_restore(void)
+{
+    int ix;
+    int err;
+    glui32 ch;
+    frefid_t saveref;
+    strid_t savestr;
+    
+    saveref = glk_fileref_create_by_prompt(
+        fileusage_SavedGame | fileusage_BinaryMode, 
+        filemode_Read, 0);
+    if (!saveref) {
+        glk_put_string("Unable to find save file.\n");
+        return;
+    }
+    
+    savestr = glk_stream_open_file(saveref, filemode_Read, 0);
+    if (!savestr) {
+        glk_put_string("Unable to read from save file.\n");
+        glk_fileref_destroy(saveref);
+        return;
+    }
+
+    glk_fileref_destroy(saveref); /* We're done with the file ref now. */
+    
+    /* Read some binary data. */
+    err = FALSE;
+    
+    for (ix=0; ix<256; ix++) {
+        ch = glk_get_char_stream(savestr);
+        if (ch == (glui32)(-1)) {
+            glk_put_string("Unexpected end of file.\n");
+            err = TRUE;
+            break;
+        }
+        if (ch != (glui32)ix) {
+            glk_put_string("This does not appear to be a valid saved game.\n");
+            err = TRUE;
+            break;
+        }
+    }
+    
+    glk_stream_close(savestr, NULL);
+    
+    if (err) {
+        glk_put_string("Failed.\n");
+        return;
+    }
+    
+    glk_put_string("Game restored.\n");
+}
+
+/* simple string length test */
+static int str_len(char *s1)
+{
+    int len;
+    for (len = 0; *s1; s1++)
+        len++;
+    return len;
+}
+
+/* simple string comparison test */
+static int str_eq(char *s1, char *s2)
+{
+    for (; *s1 && *s2; s1++, s2++) {
+        if (*s1 != *s2)
+            return FALSE;
+    }
+    
+    if (*s1 || *s2)
+        return FALSE;
+    else
+        return TRUE;
+}
+
diff --git a/src/gargoyle-gtk.glade b/src/gargoyle-gtk.glade
new file mode 100644 (file)
index 0000000..cd1ada1
--- /dev/null
@@ -0,0 +1,205 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE glade-interface SYSTEM "glade-2.0.dtd">
+<!--Generated with glade3 3.4.4 on Sat Jul 12 00:47:27 2008 -->
+<glade-interface>
+  <widget class="GtkWindow" id="gargoyle-gtk">
+    <property name="width_request">300</property>
+    <property name="height_request">600</property>
+    <property name="title" translatable="yes">Gargoyle GTK</property>
+    <signal name="delete_event" handler="gtk_main_quit"/>
+    <child>
+      <widget class="GtkVBox" id="vbox">
+        <property name="visible">True</property>
+        <child>
+          <widget class="GtkMenuBar" id="menubar">
+            <property name="visible">True</property>
+            <child>
+              <widget class="GtkMenuItem" id="file_menu">
+                <property name="visible">True</property>
+                <property name="label" translatable="yes">_File</property>
+                <property name="use_underline">True</property>
+                <child>
+                  <widget class="GtkMenu" id="menu1">
+                    <property name="visible">True</property>
+                    <child>
+                      <widget class="GtkImageMenuItem" id="file_open_menu_item">
+                        <property name="visible">True</property>
+                        <property name="tooltip" translatable="yes">Opens an interactive fiction game</property>
+                        <property name="label" translatable="yes">gtk-open</property>
+                        <property name="use_underline">True</property>
+                        <property name="use_stock">True</property>
+                      </widget>
+                    </child>
+                    <child>
+                      <widget class="GtkSeparatorMenuItem" id="separatormenuitem1">
+                        <property name="visible">True</property>
+                      </widget>
+                    </child>
+                    <child>
+                      <widget class="GtkImageMenuItem" id="imagemenuitem5">
+                        <property name="visible">True</property>
+                        <property name="label" translatable="yes">gtk-quit</property>
+                        <property name="use_underline">True</property>
+                        <property name="use_stock">True</property>
+                        <signal name="activate" handler="gtk_main_quit"/>
+                      </widget>
+                    </child>
+                  </widget>
+                </child>
+              </widget>
+            </child>
+            <child>
+              <widget class="GtkMenuItem" id="edit_menu">
+                <property name="visible">True</property>
+                <property name="label" translatable="yes">_Edit</property>
+                <property name="use_underline">True</property>
+                <child>
+                  <widget class="GtkMenu" id="menu2">
+                    <property name="visible">True</property>
+                    <child>
+                      <widget class="GtkImageMenuItem" id="edit_cut_menu_item">
+                        <property name="visible">True</property>
+                        <property name="label" translatable="yes">gtk-cut</property>
+                        <property name="use_underline">True</property>
+                        <property name="use_stock">True</property>
+                      </widget>
+                    </child>
+                    <child>
+                      <widget class="GtkImageMenuItem" id="edit_copy_menu_item">
+                        <property name="visible">True</property>
+                        <property name="label" translatable="yes">gtk-copy</property>
+                        <property name="use_underline">True</property>
+                        <property name="use_stock">True</property>
+                      </widget>
+                    </child>
+                    <child>
+                      <widget class="GtkImageMenuItem" id="edit_paste_menu_item">
+                        <property name="visible">True</property>
+                        <property name="label" translatable="yes">gtk-paste</property>
+                        <property name="use_underline">True</property>
+                        <property name="use_stock">True</property>
+                      </widget>
+                    </child>
+                    <child>
+                      <widget class="GtkImageMenuItem" id="edit_delete_menu_item">
+                        <property name="visible">True</property>
+                        <property name="label" translatable="yes">gtk-delete</property>
+                        <property name="use_underline">True</property>
+                        <property name="use_stock">True</property>
+                      </widget>
+                    </child>
+                  </widget>
+                </child>
+              </widget>
+            </child>
+            <child>
+              <widget class="GtkMenuItem" id="game_menu">
+                <property name="visible">True</property>
+                <property name="label" translatable="yes">_Game</property>
+                <property name="use_underline">True</property>
+                <child>
+                  <widget class="GtkMenu" id="menu4">
+                    <property name="visible">True</property>
+                    <child>
+                      <widget class="GtkImageMenuItem" id="game_save_menu_item">
+                        <property name="visible">True</property>
+                        <property name="tooltip" translatable="yes">Saves your progress in the game</property>
+                        <property name="label" translatable="yes">_Save</property>
+                        <property name="use_underline">True</property>
+                        <child internal-child="image">
+                          <widget class="GtkImage" id="menu-item-image13">
+                            <property name="stock">gtk-save</property>
+                          </widget>
+                        </child>
+                      </widget>
+                    </child>
+                    <child>
+                      <widget class="GtkImageMenuItem" id="game_restore_menu_item">
+                        <property name="visible">True</property>
+                        <property name="tooltip" translatable="yes">Restores a previously saved game</property>
+                        <property name="label" translatable="yes">_Restore</property>
+                        <property name="use_underline">True</property>
+                        <child internal-child="image">
+                          <widget class="GtkImage" id="menu-item-image12">
+                            <property name="stock">gtk-open</property>
+                          </widget>
+                        </child>
+                      </widget>
+                    </child>
+                    <child>
+                      <widget class="GtkImageMenuItem" id="game_restart_menu_item">
+                        <property name="visible">True</property>
+                        <property name="tooltip" translatable="yes">Restart the game</property>
+                        <property name="label" translatable="yes">Res_tart</property>
+                        <property name="use_underline">True</property>
+                        <child internal-child="image">
+                          <widget class="GtkImage" id="menu-item-image11">
+                            <property name="visible">True</property>
+                            <property name="stock">gtk-refresh</property>
+                          </widget>
+                        </child>
+                      </widget>
+                    </child>
+                  </widget>
+                </child>
+              </widget>
+            </child>
+            <child>
+              <widget class="GtkMenuItem" id="help_menu">
+                <property name="visible">True</property>
+                <property name="label" translatable="yes">_Help</property>
+                <property name="use_underline">True</property>
+                <child>
+                  <widget class="GtkMenu" id="menu3">
+                    <property name="visible">True</property>
+                    <child>
+                      <widget class="GtkImageMenuItem" id="help_about_menu_item">
+                        <property name="visible">True</property>
+                        <property name="label" translatable="yes">gtk-about</property>
+                        <property name="use_underline">True</property>
+                        <property name="use_stock">True</property>
+                      </widget>
+                    </child>
+                  </widget>
+                </child>
+              </widget>
+            </child>
+          </widget>
+          <packing>
+            <property name="expand">False</property>
+          </packing>
+        </child>
+        <child>
+          <widget class="GtkToolbar" id="toolbar">
+            <property name="visible">True</property>
+            <child>
+              <widget class="GtkToolButton" id="save_tool_button">
+                <property name="visible">True</property>
+                <property name="label" translatable="yes">Save</property>
+                <property name="stock_id">gtk-save</property>
+                <signal name="clicked" handler="on_save_tool_button_clicked"/>
+              </widget>
+              <packing>
+                <property name="expand">False</property>
+              </packing>
+            </child>
+            <child>
+              <widget class="GtkToolButton" id="restore_tool_button">
+                <property name="visible">True</property>
+                <property name="label" translatable="yes">Restore</property>
+                <property name="stock_id">gtk-open</property>
+              </widget>
+              <packing>
+                <property name="expand">False</property>
+              </packing>
+            </child>
+          </widget>
+          <packing>
+            <property name="expand">False</property>
+            <property name="position">1</property>
+          </packing>
+        </child>
+      </widget>
+    </child>
+  </widget>
+</glade-interface>
diff --git a/src/glk.c b/src/glk.c
new file mode 100644 (file)
index 0000000..885f36f
--- /dev/null
+++ b/src/glk.c
@@ -0,0 +1,18 @@
+#include <gtk/gtk.h>
+
+#include "glk.h"
+
+void
+glk_exit(void)
+{
+       gtk_main();
+}
+
+void
+glk_select(event_t *event)
+{
+       gtk_main_iteration();
+}
+
+
+
diff --git a/src/glk.h b/src/glk.h
new file mode 100644 (file)
index 0000000..e9947b3
--- /dev/null
+++ b/src/glk.h
@@ -0,0 +1,350 @@
+#ifndef GLK_H
+#define GLK_H
+
+#include <gtk/gtk.h>
+
+/* glk.h: Header file for Glk API, version 0.7.0.
+    Designed by Andrew Plotkin <erkyrath@eblong.com>
+    http://www.eblong.com/zarf/glk/index.html
+
+    This file is copyright 1998-2004 by Andrew Plotkin. You may copy,
+    distribute, and incorporate it into your own programs, by any means
+    and under any conditions, as long as you do not modify it. You may
+    also modify this file, incorporate it into your own programs,
+    and distribute the modified version, as long as you retain a notice
+    in your program or documentation which mentions my name and the URL
+    shown above.
+*/
+
+/* You may have to edit the definition of glui32 to make sure it's really a
+    32-bit unsigned integer type, and glsi32 to make sure it's really a
+    32-bit signed integer type. If they're not, horrible things will happen. */
+typedef guint32 glui32;
+typedef gint32 glsi32;
+
+/* These are the compile-time conditionals that reveal various Glk optional
+    modules. */
+#define GLK_MODULE_UNICODE
+#define GLK_MODULE_IMAGE
+#define GLK_MODULE_SOUND
+#define GLK_MODULE_HYPERLINKS
+
+/* These types are opaque object identifiers. They're pointers to opaque
+    C structures, which are defined differently by each library. */
+typedef struct glk_window_struct  *winid_t;
+typedef struct glk_stream_struct  *strid_t;
+typedef struct glk_fileref_struct *frefid_t;
+typedef struct glk_schannel_struct *schanid_t;
+
+#define gestalt_Version (0)
+#define gestalt_CharInput (1)
+#define gestalt_LineInput (2)
+#define gestalt_CharOutput (3)
+#define   gestalt_CharOutput_CannotPrint (0)
+#define   gestalt_CharOutput_ApproxPrint (1)
+#define   gestalt_CharOutput_ExactPrint (2)
+#define gestalt_MouseInput (4)
+#define gestalt_Timer (5)
+#define gestalt_Graphics (6)
+#define gestalt_DrawImage (7)
+#define gestalt_Sound (8)
+#define gestalt_SoundVolume (9)
+#define gestalt_SoundNotify (10)
+#define gestalt_Hyperlinks (11)
+#define gestalt_HyperlinkInput (12)
+#define gestalt_SoundMusic (13)
+#define gestalt_GraphicsTransparency (14)
+#define gestalt_Unicode (15)
+
+#define evtype_None (0)
+#define evtype_Timer (1)
+#define evtype_CharInput (2)
+#define evtype_LineInput (3)
+#define evtype_MouseInput (4)
+#define evtype_Arrange (5)
+#define evtype_Redraw (6)
+#define evtype_SoundNotify (7)
+#define evtype_Hyperlink (8)
+
+typedef struct event_struct {
+    glui32 type;
+    winid_t win;
+    glui32 val1, val2;
+} event_t;
+
+#define keycode_Unknown  (0xffffffff)
+#define keycode_Left     (0xfffffffe)
+#define keycode_Right    (0xfffffffd)
+#define keycode_Up       (0xfffffffc)
+#define keycode_Down     (0xfffffffb)
+#define keycode_Return   (0xfffffffa)
+#define keycode_Delete   (0xfffffff9)
+#define keycode_Escape   (0xfffffff8)
+#define keycode_Tab      (0xfffffff7)
+#define keycode_PageUp   (0xfffffff6)
+#define keycode_PageDown (0xfffffff5)
+#define keycode_Home     (0xfffffff4)
+#define keycode_End      (0xfffffff3)
+#define keycode_Func1    (0xffffffef)
+#define keycode_Func2    (0xffffffee)
+#define keycode_Func3    (0xffffffed)
+#define keycode_Func4    (0xffffffec)
+#define keycode_Func5    (0xffffffeb)
+#define keycode_Func6    (0xffffffea)
+#define keycode_Func7    (0xffffffe9)
+#define keycode_Func8    (0xffffffe8)
+#define keycode_Func9    (0xffffffe7)
+#define keycode_Func10   (0xffffffe6)
+#define keycode_Func11   (0xffffffe5)
+#define keycode_Func12   (0xffffffe4)
+/* The last keycode is always (0x100000000 - keycode_MAXVAL) */
+#define keycode_MAXVAL   (28)
+
+#define style_Normal (0)
+#define style_Emphasized (1)
+#define style_Preformatted (2)
+#define style_Header (3)
+#define style_Subheader (4)
+#define style_Alert (5)
+#define style_Note (6)
+#define style_BlockQuote (7)
+#define style_Input (8)
+#define style_User1 (9)
+#define style_User2 (10)
+#define style_NUMSTYLES (11)
+
+typedef struct stream_result_struct {
+    glui32 readcount;
+    glui32 writecount;
+} stream_result_t;
+
+#define wintype_AllTypes (0)
+#define wintype_Pair (1)
+#define wintype_Blank (2)
+#define wintype_TextBuffer (3)
+#define wintype_TextGrid (4)
+#define wintype_Graphics (5)
+
+#define winmethod_Left  (0x00)
+#define winmethod_Right (0x01)
+#define winmethod_Above (0x02)
+#define winmethod_Below (0x03)
+#define winmethod_DirMask (0x0f)
+
+#define winmethod_Fixed (0x10)
+#define winmethod_Proportional (0x20)
+#define winmethod_DivisionMask (0xf0)
+
+#define fileusage_Data (0x00)
+#define fileusage_SavedGame (0x01)
+#define fileusage_Transcript (0x02)
+#define fileusage_InputRecord (0x03)
+#define fileusage_TypeMask (0x0f)
+
+#define fileusage_TextMode   (0x100)
+#define fileusage_BinaryMode (0x000)
+
+#define filemode_Write (0x01)
+#define filemode_Read (0x02)
+#define filemode_ReadWrite (0x03)
+#define filemode_WriteAppend (0x05)
+
+#define seekmode_Start (0)
+#define seekmode_Current (1)
+#define seekmode_End (2)
+
+#define stylehint_Indentation (0)
+#define stylehint_ParaIndentation (1)
+#define stylehint_Justification (2)
+#define stylehint_Size (3)
+#define stylehint_Weight (4)
+#define stylehint_Oblique (5)
+#define stylehint_Proportional (6)
+#define stylehint_TextColor (7)
+#define stylehint_BackColor (8)
+#define stylehint_ReverseColor (9)
+#define stylehint_NUMHINTS (10)
+
+#define   stylehint_just_LeftFlush (0)
+#define   stylehint_just_LeftRight (1)
+#define   stylehint_just_Centered (2)
+#define   stylehint_just_RightFlush (3)
+
+/* glk_main() is the top-level function which you define. The Glk library
+    calls it. */
+extern void glk_main(void);
+
+extern void glk_exit(void);
+extern void glk_set_interrupt_handler(void (*func)(void));
+extern void glk_tick(void);
+
+extern glui32 glk_gestalt(glui32 sel, glui32 val);
+extern glui32 glk_gestalt_ext(glui32 sel, glui32 val, glui32 *arr,
+    glui32 arrlen);
+
+extern unsigned char glk_char_to_lower(unsigned char ch);
+extern unsigned char glk_char_to_upper(unsigned char ch);
+
+extern winid_t glk_window_get_root(void);
+extern winid_t glk_window_open(winid_t split, glui32 method, glui32 size,
+    glui32 wintype, glui32 rock);
+extern void glk_window_close(winid_t win, stream_result_t *result);
+extern void glk_window_get_size(winid_t win, glui32 *widthptr,
+    glui32 *heightptr);
+extern void glk_window_set_arrangement(winid_t win, glui32 method,
+    glui32 size, winid_t keywin);
+extern void glk_window_get_arrangement(winid_t win, glui32 *methodptr,
+    glui32 *sizeptr, winid_t *keywinptr);
+extern winid_t glk_window_iterate(winid_t win, glui32 *rockptr);
+extern glui32 glk_window_get_rock(winid_t win);
+extern glui32 glk_window_get_type(winid_t win);
+extern winid_t glk_window_get_parent(winid_t win);
+extern winid_t glk_window_get_sibling(winid_t win);
+extern void glk_window_clear(winid_t win);
+extern void glk_window_move_cursor(winid_t win, glui32 xpos, glui32 ypos);
+
+extern strid_t glk_window_get_stream(winid_t win);
+extern void glk_window_set_echo_stream(winid_t win, strid_t str);
+extern strid_t glk_window_get_echo_stream(winid_t win);
+extern void glk_set_window(winid_t win);
+
+extern strid_t glk_stream_open_file(frefid_t fileref, glui32 fmode,
+    glui32 rock);
+extern strid_t glk_stream_open_memory(char *buf, glui32 buflen, glui32 fmode,
+    glui32 rock);
+extern void glk_stream_close(strid_t str, stream_result_t *result);
+extern strid_t glk_stream_iterate(strid_t str, glui32 *rockptr);
+extern glui32 glk_stream_get_rock(strid_t str);
+extern void glk_stream_set_position(strid_t str, glsi32 pos, glui32 seekmode);
+extern glui32 glk_stream_get_position(strid_t str);
+extern void glk_stream_set_current(strid_t str);
+extern strid_t glk_stream_get_current(void);
+
+extern void glk_put_char(unsigned char ch);
+extern void glk_put_char_stream(strid_t str, unsigned char ch);
+extern void glk_put_string(char *s);
+extern void glk_put_string_stream(strid_t str, char *s);
+extern void glk_put_buffer(char *buf, glui32 len);
+extern void glk_put_buffer_stream(strid_t str, char *buf, glui32 len);
+extern void glk_set_style(glui32 styl);
+extern void glk_set_style_stream(strid_t str, glui32 styl);
+
+extern glsi32 glk_get_char_stream(strid_t str);
+extern glui32 glk_get_line_stream(strid_t str, char *buf, glui32 len);
+extern glui32 glk_get_buffer_stream(strid_t str, char *buf, glui32 len);
+
+extern void glk_stylehint_set(glui32 wintype, glui32 styl, glui32 hint,
+    glsi32 val);
+extern void glk_stylehint_clear(glui32 wintype, glui32 styl, glui32 hint);
+extern glui32 glk_style_distinguish(winid_t win, glui32 styl1, glui32 styl2);
+extern glui32 glk_style_measure(winid_t win, glui32 styl, glui32 hint,
+    glui32 *result);
+
+extern frefid_t glk_fileref_create_temp(glui32 usage, glui32 rock);
+extern frefid_t glk_fileref_create_by_name(glui32 usage, char *name,
+    glui32 rock);
+extern frefid_t glk_fileref_create_by_prompt(glui32 usage, glui32 fmode,
+    glui32 rock);
+extern frefid_t glk_fileref_create_from_fileref(glui32 usage, frefid_t fref,
+    glui32 rock);
+extern void glk_fileref_destroy(frefid_t fref);
+extern frefid_t glk_fileref_iterate(frefid_t fref, glui32 *rockptr);
+extern glui32 glk_fileref_get_rock(frefid_t fref);
+extern void glk_fileref_delete_file(frefid_t fref);
+extern glui32 glk_fileref_does_file_exist(frefid_t fref);
+
+extern void glk_select(event_t *event);
+extern void glk_select_poll(event_t *event);
+
+extern void glk_request_timer_events(glui32 millisecs);
+
+extern void glk_request_line_event(winid_t win, char *buf, glui32 maxlen,
+    glui32 initlen);
+extern void glk_request_char_event(winid_t win);
+extern void glk_request_mouse_event(winid_t win);
+
+extern void glk_cancel_line_event(winid_t win, event_t *event);
+extern void glk_cancel_char_event(winid_t win);
+extern void glk_cancel_mouse_event(winid_t win);
+
+#ifdef GLK_MODULE_UNICODE
+
+extern glui32 glk_buffer_to_lower_case_uni(glui32 *buf, glui32 len,
+    glui32 numchars);
+extern glui32 glk_buffer_to_upper_case_uni(glui32 *buf, glui32 len,
+    glui32 numchars);
+extern glui32 glk_buffer_to_title_case_uni(glui32 *buf, glui32 len,
+    glui32 numchars, glui32 lowerrest);
+
+extern void glk_put_char_uni(glui32 ch);
+extern void glk_put_string_uni(glui32 *s);
+extern void glk_put_buffer_uni(glui32 *buf, glui32 len);
+extern void glk_put_char_stream_uni(strid_t str, glui32 ch);
+extern void glk_put_string_stream_uni(strid_t str, glui32 *s);
+extern void glk_put_buffer_stream_uni(strid_t str, glui32 *buf, glui32 len);
+
+extern glsi32 glk_get_char_stream_uni(strid_t str);
+extern glui32 glk_get_buffer_stream_uni(strid_t str, glui32 *buf, glui32 len);
+extern glui32 glk_get_line_stream_uni(strid_t str, glui32 *buf, glui32 len);
+
+extern strid_t glk_stream_open_file_uni(frefid_t fileref, glui32 fmode,
+    glui32 rock);
+extern strid_t glk_stream_open_memory_uni(glui32 *buf, glui32 buflen,
+    glui32 fmode, glui32 rock);
+
+extern void glk_request_char_event_uni(winid_t win);
+extern void glk_request_line_event_uni(winid_t win, glui32 *buf,
+    glui32 maxlen, glui32 initlen);
+
+#endif /* GLK_MODULE_UNICODE */
+
+#ifdef GLK_MODULE_IMAGE
+
+#define imagealign_InlineUp (0x01)
+#define imagealign_InlineDown (0x02)
+#define imagealign_InlineCenter (0x03)
+#define imagealign_MarginLeft (0x04)
+#define imagealign_MarginRight (0x05)
+
+extern glui32 glk_image_draw(winid_t win, glui32 image, glsi32 val1, glsi32 val2);
+extern glui32 glk_image_draw_scaled(winid_t win, glui32 image,
+    glsi32 val1, glsi32 val2, glui32 width, glui32 height);
+extern glui32 glk_image_get_info(glui32 image, glui32 *width, glui32 *height);
+
+extern void glk_window_flow_break(winid_t win);
+
+extern void glk_window_erase_rect(winid_t win,
+    glsi32 left, glsi32 top, glui32 width, glui32 height);
+extern void glk_window_fill_rect(winid_t win, glui32 color,
+    glsi32 left, glsi32 top, glui32 width, glui32 height);
+extern void glk_window_set_background_color(winid_t win, glui32 color);
+
+#endif /* GLK_MODULE_IMAGE */
+
+#ifdef GLK_MODULE_SOUND
+
+extern schanid_t glk_schannel_create(glui32 rock);
+extern void glk_schannel_destroy(schanid_t chan);
+extern schanid_t glk_schannel_iterate(schanid_t chan, glui32 *rockptr);
+extern glui32 glk_schannel_get_rock(schanid_t chan);
+
+extern glui32 glk_schannel_play(schanid_t chan, glui32 snd);
+extern glui32 glk_schannel_play_ext(schanid_t chan, glui32 snd, glui32 repeats,
+    glui32 notify);
+extern void glk_schannel_stop(schanid_t chan);
+extern void glk_schannel_set_volume(schanid_t chan, glui32 vol);
+
+extern void glk_sound_load_hint(glui32 snd, glui32 flag);
+
+#endif /* GLK_MODULE_SOUND */
+
+#ifdef GLK_MODULE_HYPERLINKS
+
+extern void glk_set_hyperlink(glui32 linkval);
+extern void glk_set_hyperlink_stream(strid_t str, glui32 linkval);
+extern void glk_request_hyperlink_event(winid_t win);
+extern void glk_cancel_hyperlink_event(winid_t win);
+
+#endif /* GLK_MODULE_HYPERLINKS */
+
+#endif /* GLK_H */
diff --git a/src/main.c b/src/main.c
new file mode 100644 (file)
index 0000000..30a7bdf
--- /dev/null
@@ -0,0 +1,117 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
+/*
+ * main.c
+ * Copyright (C) Philip en Marijn 2008 <>
+ * 
+ * main.c is free software copyrighted by Philip en Marijn.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name ``Philip en Marijn'' nor the name of any other
+ *    contributor may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ * 
+ * main.c IS PROVIDED BY Philip en Marijn ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL Philip en Marijn OR ANY OTHER CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdio.h>
+
+#include <gtk/gtk.h>
+
+#include "callbacks.h"
+#include "error.h"
+#include "glk.h"
+
+/*
+ * Standard gettext macros.
+ */
+#ifdef ENABLE_NLS
+#  include <libintl.h>
+#  undef _
+#  define _(String) dgettext (PACKAGE, String)
+#  ifdef gettext_noop
+#    define N_(String) gettext_noop (String)
+#  else
+#    define N_(String) (String)
+#  endif
+#else
+#  define textdomain(String) (String)
+#  define gettext(String) (String)
+#  define dgettext(Domain,Message) (Message)
+#  define dcgettext(Domain,Message,Type) (Message)
+#  define bindtextdomain(Domain,Directory) (Domain)
+#  define _(String) (String)
+#  define N_(String) (String)
+#endif
+
+#include "callbacks.h"
+
+/* The global builder object to be used to request handles to widgets */
+GtkBuilder *builder = NULL;
+       
+GtkWidget*
+create_window(void)
+{
+       GtkWidget *window;
+
+       if( (window = GTK_WIDGET(gtk_builder_get_object(builder, "gargoyle-gtk"))) == NULL ) {
+               error_dialog(NULL, NULL, "Error while getting main window object");
+               return NULL;
+       }
+
+       gtk_builder_connect_signals(builder, NULL);
+       
+       return window;
+}
+
+
+int
+main(int argc, char *argv[])
+{
+       GError *error = NULL;
+       GtkWidget *window;
+
+#ifdef ENABLE_NLS
+       bindtextdomain(GETTEXT_PACKAGE, PACKAGE_LOCALE_DIR);
+       bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8");
+       textdomain(GETTEXT_PACKAGE);
+#endif
+
+       gtk_set_locale();
+       gtk_init(&argc, &argv);
+
+       builder = gtk_builder_new();
+       if( !gtk_builder_add_from_file(builder, "gargoyle-gtk.ui", &error) ) {
+               error_dialog(NULL, error, "Error while building interface: ");  
+               return 1;
+       }
+
+       window = create_window();
+       gtk_widget_show(window);
+
+       glk_main();
+
+       g_object_unref( G_OBJECT(builder) );
+
+       return 0;
+}
diff --git a/src/model.c b/src/model.c
new file mode 100644 (file)
index 0000000..d3edd5c
--- /dev/null
@@ -0,0 +1,53 @@
+#include "glk.h"
+
+/* model.c: Model program for Glk API, version 0.5.
+    Designed by Andrew Plotkin <erkyrath@eblong.com>
+    http://www.eblong.com/zarf/glk/index.html
+    This program is in the public domain.
+*/
+
+/* This is a simple model of a text adventure which uses the Glk API.
+    It shows how to input a line of text, display results, maintain a
+    status window, write to a transcript file, and so on. */
+
+/* This is the cleanest possible form of a Glk program. It includes only
+    "glk.h", and doesn't call any functions outside Glk at all. We even
+    define our own str_eq() and str_len(), rather than relying on the
+    standard libraries. */
+
+/* We also define our own TRUE and FALSE and NULL. */
+#ifndef TRUE
+#define TRUE 1
+#endif
+#ifndef FALSE
+#define FALSE 0
+#endif
+#ifndef NULL
+#define NULL 0
+#endif
+
+static winid_t mainwin = NULL;
+
+/* Forward declarations */
+void glk_main(void);
+
+/* The glk_main() function is called by the Glk system; it's the main entry
+    point for your program. */
+void glk_main(void)
+{
+    /* Open the main window. */
+    mainwin = glk_window_open(0, 0, 0, wintype_TextBuffer, 1);
+    if (!mainwin) {
+        /* It's possible that the main window failed to open. There's
+            nothing we can do without it, so exit. */
+        return; 
+    }
+    
+    /* Set the current output stream to print to it. */
+    glk_set_window(mainwin);
+    
+    glk_put_string("Philip en Marijn zijn vet goed.\n");
+
+       /* Bye bye */
+       glk_exit();
+}
diff --git a/src/stream.c b/src/stream.c
new file mode 100644 (file)
index 0000000..e5a532a
--- /dev/null
@@ -0,0 +1,63 @@
+#include "stream.h"
+
+/* Global current stream */
+static strid_t current_stream = NULL;
+static GList *stream_list = NULL;
+
+strid_t
+window_stream_new(winid_t 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;
+
+       stream_list = g_list_prepend(stream_list, s);
+       s->stream_list = stream_list;
+
+       return s;
+}
+
+void
+glk_stream_set_current(strid_t stream)
+{
+       if(stream->file_mode != filemode_Write)
+       {
+               g_warning("glk_stream_set_current: Cannot set current stream to non output stream");
+               return;
+       }
+
+       current_stream = stream;
+}
+
+void
+glk_put_string(char *s)
+{
+       GError *error = NULL;
+       gchar *utf8;
+
+       switch(current_stream->stream_type)
+       {
+               case STREAM_TYPE_WINDOW:
+                       utf8 = g_convert(s, -1, "UTF-8", "ISO-8859-1", NULL, NULL, &error);
+
+                       if(utf8 == NULL)
+                       {
+                               g_warning("glk_put_string: Error during latin1->utf8 conversion: %s", error->message);
+                               g_error_free(error);
+                       }
+
+                       GtkTextBuffer *buffer = gtk_text_view_get_buffer( GTK_TEXT_VIEW(current_stream->window->widget) );
+
+                       GtkTextIter iter;
+                       gtk_text_buffer_get_end_iter(buffer, &iter);
+
+                       gtk_text_buffer_insert(buffer, &iter, utf8, -1);
+
+                       g_free(utf8);
+                       break;
+               default:
+                       g_warning("glk_put_string: Writing to this kind of stream unsupported.");       
+       }
+}
diff --git a/src/stream.h b/src/stream.h
new file mode 100644 (file)
index 0000000..fb7eb8f
--- /dev/null
@@ -0,0 +1,35 @@
+#ifndef STREAM_H
+#define STREAM_H
+
+#include <gtk/gtk.h>
+#include "glk.h"
+#include "window.h"
+
+enum StreamType
+{
+       STREAM_TYPE_WINDOW,
+       STREAM_TYPE_MEMORY,
+       STREAM_TYPE_FILE,
+       STREAM_TYPE_UNICODE_MEMORY,
+       STREAM_TYPE_UNICODE_FILE,
+};
+
+struct glk_stream_struct
+{
+       GList* stream_list;
+
+       glui32 rock;
+       glui32 file_mode;
+       glui32 read_count;
+       glui32 write_count;
+       enum StreamType stream_type;
+       winid_t window;
+       gchar *memory_buffer;
+       glui32 *memory_buffer_unicode;
+       glui32 buffer_len;
+};
+
+
+strid_t window_stream_new(winid_t window);
+
+#endif
diff --git a/src/window.c b/src/window.c
new file mode 100644 (file)
index 0000000..11e604d
--- /dev/null
@@ -0,0 +1,75 @@
+#include "window.h"
+
+/* Global list of all windows */
+static GNode *root_window = NULL;
+
+winid_t
+glk_window_open(winid_t split, glui32 method, glui32 size, glui32 wintype, glui32 rock)
+{
+       extern GtkBuilder *builder;
+
+       if(split)
+       {
+               g_warning("glk_window_open: splitting of windows not implemented");
+               return NULL;
+       }
+
+       if(root_window != NULL)
+       {
+               g_warning("glk_window_open: there is already a window");
+               return NULL;
+       }
+
+       winid_t new_window = g_new0(struct glk_window_struct, 1);
+       root_window = g_node_new(new_window);
+
+       new_window->rock = rock;
+       new_window->window_type = wintype;
+
+       GtkBox *vbox = GTK_BOX( gtk_builder_get_object(builder, "vbox") );                      
+       if(vbox == NULL)
+       {
+               error_dialog(NULL, NULL, "Could not find vbox");
+               return NULL;
+       }
+
+       switch(wintype)
+       {
+               case wintype_TextBuffer:
+               {
+                       GtkWidget *scroll_window = gtk_scrolled_window_new(NULL, NULL);
+                       GtkWidget *window = gtk_text_view_new();
+                       gtk_container_add( GTK_CONTAINER(scroll_window), window );
+                       gtk_box_pack_end(vbox, scroll_window, TRUE, TRUE, 0);
+                       gtk_widget_show_all(scroll_window);
+
+                       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;
+               }
+
+                       break;
+               default:
+                       g_warning("glk_window_open: unsupported window type");
+                       g_free(new_window);
+                       return NULL;
+       }
+
+       new_window->window_node = root_window;
+
+       return new_window;
+}
+
+void
+glk_set_window(winid_t window)
+{
+       glk_stream_set_current( glk_window_get_stream(window) );
+}
+
+strid_t glk_window_get_stream(winid_t window)
+{
+       return window->window_stream;
+}
diff --git a/src/window.h b/src/window.h
new file mode 100644 (file)
index 0000000..4e705f2
--- /dev/null
@@ -0,0 +1,34 @@
+#ifndef WINDOW_H
+#define WINDOW_H
+
+#include <gtk/gtk.h>
+#include "glk.h"
+
+#include "stream.h"
+#include "error.h"
+
+enum InputRequestType
+{
+       INPUT_REQUEST_NONE,
+       INPUT_REQUEST_CHARACTER,
+       INPUT_REQUEST_CHARACTER_UNICODE,
+       INPUT_REQUEST_LINE,
+       INPUT_REQUEST_LINE_UNICODE
+};
+
+struct glk_window_struct
+{
+       GNode *window_node;
+
+       glui32 rock;
+       glui32 window_type;
+       GtkWidget *widget;
+       strid_t window_stream;
+       strid_t echo_stream;
+       enum InputRequestType input_request_type;
+       gchar *line_input_buffer;
+       glui32 *line_input_buffer_unicode;
+       glui32 line_input_buffer_max_len;
+};
+
+#endif