-PKG_CONFIG = gtk+-2.0
+PKG_CONFIG = gtk+-2.0 gthread-2.0
SOURCES = main.c \
callbacks.c callbacks.h \
error.c error.h \
gestalt.c \
fileref.c fileref.h \
case.c \
- model.c \
- strio.c
+ strio.c \
+ event.c event.h \
+ input.c input.h \
+ style.c \
+ first.c
OBJECTS = main.o \
callbacks.o \
error.o \
gestalt.o \
fileref.o \
case.o \
- model.o \
- strio.o
+ strio.o \
+ event.o \
+ input.o \
+ style.o \
+ first.o
CFLAGS = -g -Wall -O0 -export-dynamic `pkg-config --cflags ${PKG_CONFIG}`
LIBS = -export-dynamic `pkg-config --libs ${PKG_CONFIG}`
* 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" );
}
+
+gboolean on_window_delete_event(GtkWidget *widget, GdkEvent *event, gpointer user_data) {
+ gtk_main_quit();
+ return TRUE;
+}
+
+void on_file_quit_activate(GtkMenuItem *menuitem, gpointer user_data) {
+ gtk_main_quit();
+}
+
*/
#include <gtk/gtk.h>
+#include "error.h"
+#include "event.h"
void on_save_tool_button_clicked(GtkToolButton *toolbutton, gpointer user_data);
+gboolean on_window_delete_event(GtkWidget *widget, GdkEvent *event, gpointer user_data);
+void on_file_quit_activate(GtkMenuItem *menuitem, gpointer user_data);
--- /dev/null
+#include "event.h"
+
+static GQueue *event_queue = NULL;
+static GMutex *event_lock = NULL;
+static GCond *event_queue_not_empty = NULL;
+static GCond *event_queue_not_full = NULL;
+
+void
+events_init()
+{
+ event_queue = g_queue_new();
+ event_lock = g_mutex_new();
+ event_queue_not_empty = g_cond_new();
+ event_queue_not_full = g_cond_new();
+}
+
+static void
+event_free(gpointer data, gpointer user_data)
+{
+ g_free(data);
+}
+
+void
+events_free()
+{
+ g_queue_foreach(event_queue, event_free, NULL);
+ g_queue_free(event_queue);
+ g_mutex_free(event_lock);
+ g_cond_free(event_queue_not_empty);
+ g_cond_free(event_queue_not_full);
+}
+
+void
+event_throw(glui32 type, winid_t win, glui32 val1, glui32 val2)
+{
+ GTimeVal timeout;
+ g_get_current_time(&timeout);
+ g_time_val_add(&timeout, 3000000); /* 3 Seconds */
+
+ /* Wait for room in the event queue */
+ g_mutex_lock(event_lock);
+ if( g_queue_get_length(event_queue) >= EVENT_QUEUE_MAX_LENGTH ) {
+ if( !g_cond_timed_wait(event_queue_not_full, event_lock, &timeout) ) {
+ /* Drop the event */
+ g_mutex_unlock(event_lock);
+ return;
+ }
+ }
+
+ event_t *event = g_new0(event_t, 1);
+ event->type = type;
+ event->win = win;
+ event->val1 = val1;
+ event->val2 = val2;
+
+ g_queue_push_head(event_queue, event);
+
+ /* Signal that there is an event */
+ g_cond_signal(event_queue_not_empty);
+
+ g_mutex_unlock(event_lock);
+}
+
+void
+glk_select(event_t *event)
+{
+ event_t *retrieved_event;
+
+ g_return_if_fail(event != NULL);
+
+ g_mutex_lock(event_lock);
+
+ /* Wait for an event */
+ if( g_queue_is_empty(event_queue) ) {
+ g_cond_wait(event_queue_not_empty, event_lock);
+ }
+
+ retrieved_event = g_queue_pop_tail(event_queue);
+ g_return_if_fail(retrieved_event != NULL);
+
+ event->type = retrieved_event->type;
+ event->win = retrieved_event->win;
+ event->val1 = retrieved_event->val1;
+ event->val2 = retrieved_event->val2;
+
+ g_free(retrieved_event);
+
+ /* Signal that the event queue is no longer full */
+ g_cond_signal(event_queue_not_full);
+
+ g_mutex_unlock(event_lock);
+
+ /* Implementation defined events */
+ switch(event->type) {
+ case EVENT_TYPE_QUIT:
+ g_thread_exit(NULL);
+ }
+}
--- /dev/null
+#ifndef EVENT_H
+#define EVENT_H
+
+#include <glib.h>
+#include "glk.h"
+
+#define EVENT_QUEUE_MAX_LENGTH 100
+
+#define EVENT_TYPE_QUIT -1
+
+void events_init();
+void events_free();
+
+void get_event_lock();
+void release_event_lock();
+
+void event_throw(glui32 type, winid_t win, glui32 val1, glui32 val2);
+
+#endif
/* TODO: Remember current working directory and last used filename
for each usage */
GtkWidget *chooser;
+
+ gdk_threads_enter();
+
switch(fmode)
{
case filemode_Read:
- chooser = gtk_file_chooser_dialog_new("Select a file", NULL,
+ chooser = gtk_file_chooser_dialog_new("Select a file to open", NULL,
GTK_FILE_CHOOSER_ACTION_OPEN,
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
GTK_FILE_CHOOSER_ACTION_OPEN);
break;
case filemode_Write:
- case filemode_ReadWrite:
- case filemode_WriteAppend:
- chooser = gtk_file_chooser_dialog_new("Select a file", NULL,
+ chooser = gtk_file_chooser_dialog_new("Select a file to save to", NULL,
GTK_FILE_CHOOSER_ACTION_SAVE,
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
gtk_file_chooser_set_do_overwrite_confirmation(
GTK_FILE_CHOOSER(chooser), TRUE);
break;
+ case filemode_ReadWrite:
+ case filemode_WriteAppend:
+ chooser = gtk_file_chooser_dialog_new("Select a file to save to", NULL,
+ GTK_FILE_CHOOSER_ACTION_SAVE,
+ GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+ GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
+ NULL);
+ gtk_file_chooser_set_action(GTK_FILE_CHOOSER(chooser),
+ GTK_FILE_CHOOSER_ACTION_SAVE);
+ break;
default:
g_warning("glk_fileref_create_by_prompt: Unsupported mode");
+ gdk_threads_leave();
return NULL;
}
if(gtk_dialog_run( GTK_DIALOG(chooser) ) != GTK_RESPONSE_ACCEPT)
{
gtk_widget_destroy(chooser);
+ gdk_threads_leave();
return NULL;
}
gchar *filename =
frefid_t f = fileref_new(filename, rock, usage, fmode);
g_free(filename);
gtk_widget_destroy(chooser);
+
+ gdk_threads_leave();
return f;
}
<?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 -->
+<!--Generated with glade3 3.4.4 on Tue Aug 19 20:15:34 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"/>
+ <signal name="delete_event" handler="on_window_delete_event"/>
<child>
<widget class="GtkVBox" id="vbox">
<property name="visible">True</property>
<widget class="GtkMenu" id="menu1">
<property name="visible">True</property>
<child>
- <widget class="GtkImageMenuItem" id="file_open_menu_item">
+ <widget class="GtkImageMenuItem" id="file_open">
<property name="visible">True</property>
<property name="tooltip" translatable="yes">Opens an interactive fiction game</property>
<property name="label" translatable="yes">gtk-open</property>
</widget>
</child>
<child>
- <widget class="GtkImageMenuItem" id="imagemenuitem5">
+ <widget class="GtkImageMenuItem" id="file_quit">
<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"/>
+ <signal name="activate" handler="on_file_quit_activate"/>
</widget>
</child>
</widget>
+#include <glib.h>
#include <gtk/gtk.h>
#include "glk.h"
void
glk_exit(void)
{
- gtk_main();
+ g_thread_exit(NULL);
}
/*
--- /dev/null
+#include "input.h"
+
+/** glk_request_char_event:
+ * @win: A window to request char events from Request
+ *
+ * Request input of a Latin-1 character or special key. A window cannot have requests
+ * for both character and line input at the same time. Nor can it have requests
+ * for character input of both types (Latin-1 and Unicode). It is illegal to
+ * call glk_request_char_event() if the window already has a pending request
+ * for either character or line input.
+ */
+void
+glk_request_char_event(winid_t win)
+{
+ g_return_if_fail(win);
+ g_return_if_fail(win->input_request_type == INPUT_REQUEST_NONE);
+ g_return_if_fail(win->window_type != wintype_TextBuffer || win->window_type != wintype_TextGrid);
+
+ win->input_request_type = INPUT_REQUEST_CHARACTER;
+ g_signal_handler_unblock( G_OBJECT(win->widget), win->keypress_handler );
+}
+
+/** glk_request_char_event_uni:
+ * @win: A window to request char events from Request
+ *
+ * Request input of a Unicode character or special key. A window cannot have requests
+ * for both character and line input at the same time. Nor can it have requests
+ * for character input of both types (Latin-1 and Unicode). It is illegal to
+ * call glk_request_char_event_uni() if the window already has a pending request
+ * for either character or line input.
+ */
+void
+glk_request_char_event_uni(winid_t win)
+{
+ g_return_if_fail(win);
+ g_return_if_fail(win->input_request_type == INPUT_REQUEST_NONE);
+ g_return_if_fail(win->window_type != wintype_TextBuffer || win->window_type != wintype_TextGrid);
+
+ win->input_request_type = INPUT_REQUEST_CHARACTER_UNICODE;
+ g_signal_handler_unblock( G_OBJECT(win->widget), win->keypress_handler );
+}
+
+void
+glk_request_line_event(winid_t win, char* buf, glui32 maxlen, glui32 initlen)
+{
+ GtkTextBuffer *window_buffer;
+
+ g_return_if_fail(win);
+ g_return_if_fail(win->input_request_type == INPUT_REQUEST_NONE);
+ g_return_if_fail(win->window_type != wintype_TextBuffer || win->window_type != wintype_TextGrid);
+
+ window_buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(win->widget));
+
+ win->input_request_type = INPUT_REQUEST_LINE;
+ win->line_input_buffer = buf;
+ win->line_input_buffer_max_len = maxlen;
+
+ /* Move the input_position mark to the end of the window_buffer */
+ GtkTextMark *input_position = gtk_text_buffer_get_mark(window_buffer, "input_position");
+ GtkTextIter end_iter;
+ gtk_text_buffer_get_end_iter(window_buffer, &end_iter);
+ gtk_text_buffer_move_mark(window_buffer, input_position, &end_iter);
+
+ /* Set the entire contents of the window_buffer as uneditable
+ * (so input can only be entered at the end) */
+ GtkTextIter start_iter;
+ gtk_text_buffer_get_start_iter(window_buffer, &start_iter);
+ gtk_text_buffer_remove_tag_by_name(window_buffer, "uneditable", &start_iter, &end_iter);
+ gtk_text_buffer_apply_tag_by_name(window_buffer, "uneditable", &start_iter, &end_iter);
+
+ if(initlen > 0) {
+ gtk_text_buffer_insert(window_buffer, &end_iter, buf, initlen);
+ }
+
+ gtk_text_view_scroll_mark_onscreen(GTK_TEXT_VIEW(win->widget), input_position);
+ g_signal_handler_unblock( G_OBJECT(window_buffer), win->insert_text_handler );
+ gtk_text_view_set_editable(GTK_TEXT_VIEW(win->widget), TRUE);
+}
+
+void
+glk_request_line_event_uni(winid_t win, glui32 *buf, glui32 maxlen, glui32 initlen)
+{
+ GtkTextBuffer *window_buffer;
+
+ g_return_if_fail(win);
+ g_return_if_fail(win->input_request_type == INPUT_REQUEST_NONE);
+ g_return_if_fail(win->window_type != wintype_TextBuffer || win->window_type != wintype_TextGrid);
+
+ window_buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(win->widget));
+
+ win->input_request_type = INPUT_REQUEST_LINE_UNICODE;
+ win->line_input_buffer_unicode = buf;
+ win->line_input_buffer_max_len = maxlen;
+
+ /* Move the input_position mark to the end of the window_buffer */
+ GtkTextMark *input_position = gtk_text_buffer_get_mark(window_buffer, "input_position");
+ GtkTextIter end_iter;
+ gtk_text_buffer_get_end_iter(window_buffer, &end_iter);
+ gtk_text_buffer_move_mark(window_buffer, input_position, &end_iter);
+
+ /* Set the entire contents of the window_buffer as uneditable
+ * (so input can only be entered at the end) */
+ GtkTextIter start_iter;
+ gtk_text_buffer_get_start_iter(window_buffer, &start_iter);
+ gtk_text_buffer_remove_tag_by_name(window_buffer, "uneditable", &start_iter, &end_iter);
+ gtk_text_buffer_apply_tag_by_name(window_buffer, "uneditable", &start_iter, &end_iter);
+
+ if(initlen > 0) {
+ GError *error = NULL;
+ gchar *utf8;
+ utf8 = g_ucs4_to_utf8(buf, initlen, NULL, NULL, &error);
+
+ if(utf8 == NULL)
+ {
+ error_dialog(NULL, error, "Error during unicode->utf8 conversion: ");
+ return;
+ }
+
+ gtk_text_buffer_insert(window_buffer, &end_iter, utf8, -1);
+ g_free(utf8);
+ }
+
+ gtk_text_view_scroll_mark_onscreen(GTK_TEXT_VIEW(win->widget), input_position);
+ g_signal_handler_unblock( G_OBJECT(window_buffer), win->insert_text_handler );
+ gtk_text_view_set_editable(GTK_TEXT_VIEW(win->widget), TRUE);
+}
+
+
+
+gboolean
+on_window_key_press_event(GtkWidget *widget, GdkEventKey *event, winid_t window)
+{
+ if(window->input_request_type != INPUT_REQUEST_CHARACTER &&
+ window->input_request_type != INPUT_REQUEST_CHARACTER_UNICODE) {
+ return FALSE;
+ }
+
+ int keycode;
+
+ switch(event->keyval) {
+ case GDK_Up:
+ case GDK_KP_Up: keycode = keycode_Up; break;
+ case GDK_Down:
+ case GDK_KP_Down: keycode = keycode_Down; break;
+ case GDK_Left:
+ case GDK_KP_Left: keycode = keycode_Left; break;
+ case GDK_Right:
+ case GDK_KP_Right: keycode = keycode_Right; break;
+ case GDK_Return:
+ case GDK_KP_Enter: keycode = keycode_Return; break;
+ case GDK_Delete:
+ case GDK_BackSpace:
+ case GDK_KP_Delete: keycode = keycode_Delete; break;
+ case GDK_Escape: keycode = keycode_Escape; break;
+ case GDK_Tab: keycode = keycode_Tab; break;
+ case GDK_Page_Up:
+ case GDK_KP_Page_Up: keycode = keycode_PageUp; break;
+ case GDK_Page_Down:
+ case GDK_KP_Page_Down: keycode = keycode_PageDown; break;
+ case GDK_Home:
+ case GDK_KP_Home: keycode = keycode_Home; break;
+ case GDK_End:
+ case GDK_KP_End: keycode = keycode_End; break;
+ case GDK_F1: keycode = keycode_Func1; break;
+ case GDK_F2: keycode = keycode_Func2; break;
+ case GDK_F3: keycode = keycode_Func3; break;
+ case GDK_F4: keycode = keycode_Func4; break;
+ case GDK_F5: keycode = keycode_Func5; break;
+ case GDK_F6: keycode = keycode_Func6; break;
+ case GDK_F7: keycode = keycode_Func7; break;
+ case GDK_F8: keycode = keycode_Func8; break;
+ case GDK_F9: keycode = keycode_Func9; break;
+ case GDK_F10: keycode = keycode_Func10; break;
+ case GDK_F11: keycode = keycode_Func11; break;
+ case GDK_F12: keycode = keycode_Func12; break;
+ default:
+ keycode = gdk_keyval_to_unicode(event->keyval);
+ }
+
+ if(window->input_request_type == INPUT_REQUEST_CHARACTER) {
+ if(keycode >= 1 || keycode <= 255) {
+ event_throw(evtype_CharInput, window, keycode, 0);
+ } else {
+ event_throw(evtype_CharInput, window, keycode_Unknown, 0);
+ }
+ } else {
+ if(keycode == 0) {
+ event_throw(evtype_CharInput, window, keycode_Unknown, 0);
+ } else {
+ event_throw(evtype_CharInput, window, keycode, 0);
+ }
+ }
+
+ /* Only one keypress will be handled */
+ window->input_request_type = INPUT_REQUEST_NONE;
+ g_signal_handler_block( G_OBJECT(window->widget), window->keypress_handler );
+
+ return TRUE;
+}
+
+void
+on_window_insert_text(GtkTextBuffer *textbuffer, GtkTextIter *location, gchar *text, gint len, gpointer user_data)
+{
+ gchar *newline_pos = strchr(text, '\n');
+ if(newline_pos != NULL) {
+ printf("position: %d\n", newline_pos-text);
+ *newline_pos = 'a';
+ }
+}
+
+void
+after_window_insert_text(GtkTextBuffer *textbuffer, GtkTextIter *location, gchar *text, gint len, winid_t window)
+{
+ if( strchr(text, '\n') != NULL) {
+ /* Make the window uneditable again and remove signal handlers */
+ GtkTextBuffer *window_buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(window->widget));
+ gtk_text_view_set_editable(GTK_TEXT_VIEW(window->widget), FALSE);
+ g_signal_handler_block(window_buffer, window->insert_text_handler);
+
+ /* Retrieve the text that was input */
+ GtkTextMark *input_position = gtk_text_buffer_get_mark(window_buffer, "input_position");
+ GtkTextIter start_iter;
+ GtkTextIter end_iter;
+ gtk_text_buffer_get_iter_at_mark(window_buffer, &start_iter, input_position);
+ gtk_text_buffer_get_end_iter(window_buffer, &end_iter);
+ gchar *inserted_text = gtk_text_buffer_get_text(window_buffer, &start_iter, &end_iter, FALSE);
+
+
+ /* Convert the string from UTF-8 to Latin-1 or Unicode */
+ if(window->input_request_type == INPUT_REQUEST_LINE) {
+ GError *error = NULL;
+ gchar *latin1;
+ gsize bytes_written;
+ latin1 = g_convert_with_fallback(inserted_text, -1, "ISO-8859-1", "UTF-8", "?", NULL, &bytes_written, &error);
+ g_free(inserted_text);
+
+ if(latin1 == NULL)
+ {
+ error_dialog(NULL, error, "Error during utf8->latin1 conversion: ");
+ event_throw(evtype_LineInput, window, 0, 0);
+ return;
+ }
+
+ /* Place input in the echo stream */
+ if(window->echo_stream != NULL)
+ glk_put_string_stream(window->echo_stream, latin1);
+
+ /* Copy the string (but not the NULL at the end) */
+ memcpy(window->line_input_buffer, latin1, MIN(window->line_input_buffer_max_len, bytes_written-1));
+ g_free(latin1);
+ event_throw(evtype_LineInput, window, MIN(window->line_input_buffer_max_len, bytes_written-1), 0);
+ }
+ else if(window->input_request_type == INPUT_REQUEST_LINE_UNICODE) {
+ gunichar *unicode;
+ glong items_written;
+ unicode = g_utf8_to_ucs4_fast(inserted_text, -1, &items_written);
+ g_free(inserted_text);
+
+ if(unicode == NULL)
+ {
+ error_dialog(NULL, NULL, "Error during utf8->unicode conversion");
+ event_throw(evtype_LineInput, window, 0, 0);
+ return;
+ }
+
+ /* Place input in the echo stream */
+ // TODO: fixme
+ // if(window->echo_stream != NULL)
+ // glk_put_string_stream_uni(window->echo_stream, unicode);
+
+ /* Copy the string (but not the NULL at the end) */
+ memcpy(window->line_input_buffer_unicode, unicode, MIN(window->line_input_buffer_max_len, items_written)*sizeof(gunichar));
+ g_free(unicode);
+ event_throw(evtype_LineInput, window, MIN(window->line_input_buffer_max_len, items_written), 0);
+ }
+ else {
+ g_warning("%s: Wrong input request type.", __func__);
+ }
+
+ window->input_request_type = INPUT_REQUEST_NONE;
+ }
+}
--- /dev/null
+#ifndef INPUT_H
+#define INPUT_H
+
+#include <glib.h>
+#include <gtk/gtk.h>
+#include <gdk/gdkkeysyms.h>
+#include <string.h>
+
+#include "window.h"
+#include "event.h"
+
+gboolean on_window_key_press_event(GtkWidget *widget, GdkEventKey *event, winid_t window);
+void on_window_insert_text(GtkTextBuffer *textbuffer, GtkTextIter *location, gchar *text, gint len, gpointer user_data);
+void after_window_insert_text(GtkTextBuffer *textbuffer, GtkTextIter *location, gchar *text, gint len, winid_t window);
+#endif
#include <string.h>
#include <stdio.h>
+#include <glib.h>
#include <gtk/gtk.h>
#include "callbacks.h"
#include "error.h"
+#include "event.h"
#include "glk.h"
/*
/* The global builder object to be used to request handles to widgets */
GtkBuilder *builder = NULL;
-GtkWidget*
+static GtkWidget*
create_window(void)
{
GtkWidget *window;
return window;
}
+/**
+ * glk_enter:
+ *
+ * Is called to create a new thread in which glk_main() runs.
+ */
+static gpointer
+glk_enter(gpointer data)
+{
+ glk_main();
+ return NULL;
+}
+
int
main(int argc, char *argv[])
{
GError *error = NULL;
GtkWidget *window;
+ GThread *glk_thread;
#ifdef ENABLE_NLS
bindtextdomain(GETTEXT_PACKAGE, PACKAGE_LOCALE_DIR);
textdomain(GETTEXT_PACKAGE);
#endif
+ if( !g_thread_supported() )
+ g_thread_init(NULL);
+
+ gdk_threads_init();
+
gtk_set_locale();
gtk_init(&argc, &argv);
window = create_window();
gtk_widget_show(window);
- glk_main();
+ events_init();
+
+ /* In een aparte thread of proces */
+ if( (glk_thread = g_thread_create(glk_enter, NULL, TRUE, &error)) == NULL ) {
+ error_dialog(NULL, error, "Error while creating glk thread: ");
+ g_object_unref( G_OBJECT(builder) );
+ return 1;
+ }
+
+ gdk_threads_enter();
+ gtk_main();
+ gdk_threads_leave();
+
+ event_throw(EVENT_TYPE_QUIT, NULL, 0, 0);
+ g_thread_join(glk_thread);
g_object_unref( G_OBJECT(builder) );
+ events_free();
return 0;
}
return;
}
+ /*
char buffer[256];
int i;
for(i = 0; i < 256; i++)
buffer[i] = (char)glk_char_to_upper(i);
- /*frefid_t f = glk_fileref_create_temp(fileusage_BinaryMode, 0);
+ */
+ /*
+ frefid_t f = glk_fileref_create_by_prompt(fileusage_BinaryMode, filemode_ReadWrite, 0);
if(f)
- {*/
+ {
- char memorybuffer[100];
-
- strid_t s = glk_stream_open_memory(memorybuffer, 100,
+ strid_t s = glk_stream_open_file(f,
filemode_ReadWrite, 0);
glk_stream_set_current(s);
glk_put_char('X');
g_printerr("Read count: %d\nWrite count: %d\n", result.readcount,
result.writecount);
-/*
glk_fileref_destroy(f);
- }*/
+ }
+ */
+
+ glk_set_window(mainwin);
+
+ gchar buffer[256] = "blaat";
+ event_t ev;
+ while(1) {
+ glk_put_string("prompt> ");
+ glk_request_line_event(mainwin, buffer, 256, 5);
+ glk_select(&ev);
+ switch(ev.type) {
+ default:
+ printf("Received event:\n");
+ printf("Type: %d\n", ev.type);
+ printf("Win: %d\n", glk_window_get_rock(ev.win));
+ printf("Var1: %d\n", ev.val1);
+ printf("Var2: %d\n", ev.val2);
+ }
+ }
+
/* Bye bye */
glk_exit();
modestr = g_strdup(binary? "ab" : "a");
break;
case filemode_ReadWrite:
- modestr = g_strdup(binary? "r+b" : "r+");
+ if( g_file_test(fileref->filename, G_FILE_TEST_EXISTS) ) {
+ modestr = g_strdup(binary? "r+b" : "r+");
+ } else {
+ modestr = g_strdup(binary? "w+b" : "w+");
+ }
break;
default:
g_warning("glk_stream_open_file: Invalid file mode");
/* If they opened a file in write mode but didn't specifically get
permission to do so, complain if the file already exists */
if(fileref->orig_filemode == filemode_Read && fmode != filemode_Read) {
+ gdk_threads_enter();
+
GtkWidget *dialog = gtk_message_dialog_new(NULL, 0,
GTK_MESSAGE_QUESTION, GTK_BUTTONS_YES_NO,
"File %s already exists. Overwrite?", fileref->filename);
gint response = gtk_dialog_run(GTK_DIALOG(dialog));
gtk_widget_destroy(dialog);
+
+ gdk_threads_leave();
+
if(response != GTK_RESPONSE_YES) {
fclose(fp);
return NULL;
__func__);
return;
}
-
+
+ stream_close_common(str, result);
+}
+
+void
+stream_close_common(strid_t str, stream_result_t *result)
+{
/* Remove the stream from the global stream list */
stream_list = g_list_delete_link(stream_list, str->stream_list);
/* If it was the current output stream, set that to NULL */
}
g_free(str);
}
-
};
strid_t window_stream_new(winid_t window);
-
+void stream_close_common(strid_t str, stream_result_t *result);
#endif
static void
write_utf8_to_window(winid_t win, gchar *s)
{
+ gdk_threads_enter();
+
GtkTextBuffer *buffer =
gtk_text_view_get_buffer( GTK_TEXT_VIEW(win->widget) );
GtkTextIter iter;
gtk_text_buffer_get_end_iter(buffer, &iter);
gtk_text_buffer_insert(buffer, &iter, s, -1);
+
+ gdk_threads_leave();
}
/* Internal function: write a UTF-8 buffer with length to a stream. */
--- /dev/null
+#include "glk.h"
+
+void
+glk_set_style(glui32 val)
+{
+ /* No nothing yet */
+ return;
+}
new_window->rock = rock;
new_window->window_type = wintype;
+ gdk_threads_enter();
+
GtkBox *vbox = GTK_BOX( gtk_builder_get_object(builder, "vbox") );
if(vbox == NULL)
{
error_dialog(NULL, NULL, "Could not find vbox");
+ gdk_threads_leave();
return NULL;
}
{
GtkWidget *scroll_window = gtk_scrolled_window_new(NULL, NULL);
GtkWidget *window = gtk_text_view_new();
+ GtkTextBuffer *buffer = gtk_text_view_get_buffer( GTK_TEXT_VIEW(window) );
+
+ gtk_text_view_set_wrap_mode( GTK_TEXT_VIEW(window), GTK_WRAP_WORD_CHAR );
+ gtk_text_view_set_editable( GTK_TEXT_VIEW(window), FALSE );
+
gtk_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->input_request_type = INPUT_REQUEST_NONE;
new_window->line_input_buffer = NULL;
new_window->line_input_buffer_unicode = NULL;
+
+ /* Connect signal handlers */
+ new_window->keypress_handler = g_signal_connect( G_OBJECT(window), "key-press-event", G_CALLBACK(on_window_key_press_event), new_window );
+ g_signal_handler_block( G_OBJECT(window), new_window->keypress_handler );
+
+ new_window->insert_text_handler = g_signal_connect_after( G_OBJECT(buffer), "insert-text", G_CALLBACK(after_window_insert_text), new_window );
+ g_signal_handler_block( G_OBJECT(buffer), new_window->insert_text_handler );
+
+ /* Create an editable tag to indicate editable parts of the window (for line input) */
+ gtk_text_buffer_create_tag(buffer, "uneditable", "editable", FALSE, "editable-set", TRUE, NULL);
+
+ /* Mark the position where the user will input text */
+ GtkTextIter end_iter;
+ gtk_text_buffer_get_end_iter(buffer, &end_iter);
+ gtk_text_buffer_create_mark(buffer, "input_position", &end_iter, TRUE);
}
break;
default:
g_warning("glk_window_open: unsupported window type");
g_free(new_window);
+ gdk_threads_leave();
return NULL;
}
new_window->window_node = root_window;
+ gdk_threads_leave();
+
return new_window;
}
+void
+glk_window_close(winid_t win, stream_result_t *result)
+{
+ g_return_if_fail(win != NULL);
+
+ switch(win->window_type)
+ {
+ case wintype_TextBuffer:
+ gtk_widget_destroy( gtk_widget_get_parent(win->widget) );
+ /* TODO: Cancel all input requests */
+ break;
+
+ case wintype_Blank:
+ gtk_widget_destroy(win->widget);
+ break;
+ }
+
+ stream_close_common(win->window_stream, result);
+
+ g_node_destroy(win->window_node);
+ /* TODO: iterate over child windows, closing them */
+
+ g_free(win);
+}
+
/**
* glk_window_clear:
* @win: A window.
case wintype_TextBuffer:
/* delete all text in the window */
{
+ gdk_threads_enter();
+
GtkTextBuffer *buffer =
gtk_text_view_get_buffer( GTK_TEXT_VIEW(win->widget) );
GtkTextIter start, end;
gtk_text_buffer_get_bounds(buffer, &start, &end);
gtk_text_buffer_delete(buffer, &start, &end);
+
+ gdk_threads_leave();
}
break;
return win->echo_stream;
}
+void
+glk_window_get_size(winid_t win, glui32 *widthptr, glui32 *heightptr)
+{
+ g_return_if_fail(win != NULL);
+
+ if(widthptr != NULL) {
+ *widthptr = 0;
+ }
+
+ if(heightptr != NULL) {
+ *heightptr = 0;
+ }
+}
+
+void
+glk_window_move_cursor(winid_t win, glui32 xpos, glui32 ypos)
+{
+ g_return_if_fail(win != NULL);
+}
#include "stream.h"
#include "error.h"
+#include "callbacks.h"
+#include "input.h"
enum InputRequestType
{
glui32 *line_input_buffer_unicode;
glui32 line_input_buffer_max_len;
gboolean mouse_input_requested;
+ gulong keypress_handler;
+ gulong insert_text_handler;
};
#endif