From 65fae93f40acb49a7d18202bbf7fdac05cb12a19 Mon Sep 17 00:00:00 2001 From: fliep Date: Sat, 12 Jul 2008 00:35:15 +0000 Subject: [PATCH 1/1] Eerste import. Philip en Marijn zijn vet goed! --- .ignore | 4 + src/Makefile | 26 ++ src/callbacks.c | 41 +++ src/callbacks.h | 35 +++ src/error.c | 52 ++++ src/error.h | 27 ++ src/first.c | 582 +++++++++++++++++++++++++++++++++++++++++ src/gargoyle-gtk.glade | 205 +++++++++++++++ src/glk.c | 18 ++ src/glk.h | 350 +++++++++++++++++++++++++ src/main.c | 117 +++++++++ src/model.c | 53 ++++ src/stream.c | 63 +++++ src/stream.h | 35 +++ src/window.c | 75 ++++++ src/window.h | 34 +++ 16 files changed, 1717 insertions(+) create mode 100644 .ignore create mode 100644 src/Makefile create mode 100644 src/callbacks.c create mode 100644 src/callbacks.h create mode 100644 src/error.c create mode 100644 src/error.h create mode 100644 src/first.c create mode 100644 src/gargoyle-gtk.glade create mode 100644 src/glk.c create mode 100644 src/glk.h create mode 100644 src/main.c create mode 100644 src/model.c create mode 100644 src/stream.c create mode 100644 src/stream.h create mode 100644 src/window.c create mode 100644 src/window.h diff --git a/.ignore b/.ignore new file mode 100644 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 index 0000000..f9ea8a6 --- /dev/null +++ b/src/Makefile @@ -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 index 0000000..34cd66e --- /dev/null +++ b/src/callbacks.c @@ -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 +#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 index 0000000..6fd524e --- /dev/null +++ b/src/callbacks.h @@ -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 + +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 index 0000000..c9b6f08 --- /dev/null +++ b/src/error.c @@ -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 +#include + +#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 index 0000000..bb05fbe --- /dev/null +++ b/src/error.h @@ -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 +#include + +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 index 0000000..3f004a8 --- /dev/null +++ b/src/first.c @@ -0,0 +1,582 @@ +#include "glk.h" + +/* model.c: Model program for Glk API, version 0.5. + Designed by Andrew Plotkin + 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 index 0000000..cd1ada1 --- /dev/null +++ b/src/gargoyle-gtk.glade @@ -0,0 +1,205 @@ + + + + + + 300 + 600 + Gargoyle GTK + + + + True + + + True + + + True + _File + True + + + True + + + True + Opens an interactive fiction game + gtk-open + True + True + + + + + True + + + + + True + gtk-quit + True + True + + + + + + + + + + True + _Edit + True + + + True + + + True + gtk-cut + True + True + + + + + True + gtk-copy + True + True + + + + + True + gtk-paste + True + True + + + + + True + gtk-delete + True + True + + + + + + + + + True + _Game + True + + + True + + + True + Saves your progress in the game + _Save + True + + + gtk-save + + + + + + + True + Restores a previously saved game + _Restore + True + + + gtk-open + + + + + + + True + Restart the game + Res_tart + True + + + True + gtk-refresh + + + + + + + + + + + True + _Help + True + + + True + + + True + gtk-about + True + True + + + + + + + + + False + + + + + True + + + True + Save + gtk-save + + + + False + + + + + True + Restore + gtk-open + + + False + + + + + False + 1 + + + + + + diff --git a/src/glk.c b/src/glk.c new file mode 100644 index 0000000..885f36f --- /dev/null +++ b/src/glk.c @@ -0,0 +1,18 @@ +#include + +#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 index 0000000..e9947b3 --- /dev/null +++ b/src/glk.h @@ -0,0 +1,350 @@ +#ifndef GLK_H +#define GLK_H + +#include + +/* glk.h: Header file for Glk API, version 0.7.0. + Designed by Andrew Plotkin + 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 index 0000000..30a7bdf --- /dev/null +++ b/src/main.c @@ -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 +#include +#include +#include +#include + +#include + +#include "callbacks.h" +#include "error.h" +#include "glk.h" + +/* + * Standard gettext macros. + */ +#ifdef ENABLE_NLS +# include +# 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 index 0000000..d3edd5c --- /dev/null +++ b/src/model.c @@ -0,0 +1,53 @@ +#include "glk.h" + +/* model.c: Model program for Glk API, version 0.5. + Designed by Andrew Plotkin + 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 index 0000000..e5a532a --- /dev/null +++ b/src/stream.c @@ -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 index 0000000..fb7eb8f --- /dev/null +++ b/src/stream.h @@ -0,0 +1,35 @@ +#ifndef STREAM_H +#define STREAM_H + +#include +#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 index 0000000..11e604d --- /dev/null +++ b/src/window.c @@ -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 index 0000000..4e705f2 --- /dev/null +++ b/src/window.h @@ -0,0 +1,34 @@ +#ifndef WINDOW_H +#define WINDOW_H + +#include +#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 -- 2.30.2