From 49eca40060b04105343874714fa67976b9430def Mon Sep 17 00:00:00 2001 From: Philip Chimento Date: Tue, 19 Aug 2008 22:56:35 +0000 Subject: [PATCH] first.c compilet en draait! git-svn-id: http://lassie.dyndns-server.com/svn/gargoyle-gtk@10 ddfedd41-794f-dd11-ae45-00112f111e67 --- src/Makefile | 16 ++- src/callbacks.c | 14 +- src/callbacks.h | 4 + src/event.c | 98 ++++++++++++++ src/event.h | 19 +++ src/fileref.c | 23 +++- src/gargoyle-gtk.glade | 10 +- src/glk.c | 3 +- src/input.c | 282 +++++++++++++++++++++++++++++++++++++++++ src/input.h | 15 +++ src/main.c | 39 +++++- src/model.c | 34 ++++- src/stream.c | 20 ++- src/stream.h | 2 +- src/strio.c | 4 + src/style.c | 8 ++ src/window.c | 74 +++++++++++ src/window.h | 4 + 18 files changed, 637 insertions(+), 32 deletions(-) create mode 100644 src/event.c create mode 100644 src/event.h create mode 100644 src/input.c create mode 100644 src/input.h create mode 100644 src/style.c diff --git a/src/Makefile b/src/Makefile index 60ca6f7..5c4103d 100644 --- a/src/Makefile +++ b/src/Makefile @@ -1,4 +1,4 @@ -PKG_CONFIG = gtk+-2.0 +PKG_CONFIG = gtk+-2.0 gthread-2.0 SOURCES = main.c \ callbacks.c callbacks.h \ error.c error.h \ @@ -8,8 +8,11 @@ SOURCES = main.c \ 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 \ @@ -19,8 +22,11 @@ OBJECTS = main.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}` diff --git a/src/callbacks.c b/src/callbacks.c index 34cd66e..6067526 100644 --- a/src/callbacks.c +++ b/src/callbacks.c @@ -30,12 +30,18 @@ * 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" ); } + +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(); +} + diff --git a/src/callbacks.h b/src/callbacks.h index 6fd524e..313ca00 100644 --- a/src/callbacks.h +++ b/src/callbacks.h @@ -31,5 +31,9 @@ */ #include +#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); diff --git a/src/event.c b/src/event.c new file mode 100644 index 0000000..0334e39 --- /dev/null +++ b/src/event.c @@ -0,0 +1,98 @@ +#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); + } +} diff --git a/src/event.h b/src/event.h new file mode 100644 index 0000000..3acbdee --- /dev/null +++ b/src/event.h @@ -0,0 +1,19 @@ +#ifndef EVENT_H +#define EVENT_H + +#include +#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 diff --git a/src/fileref.c b/src/fileref.c index 1b7cf57..921997b 100644 --- a/src/fileref.c +++ b/src/fileref.c @@ -144,10 +144,13 @@ glk_fileref_create_by_prompt(glui32 usage, glui32 fmode, glui32 rock) /* 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, @@ -156,9 +159,7 @@ glk_fileref_create_by_prompt(glui32 usage, glui32 fmode, glui32 rock) 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, @@ -168,14 +169,26 @@ glk_fileref_create_by_prompt(glui32 usage, glui32 fmode, glui32 rock) 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 = @@ -183,6 +196,8 @@ glk_fileref_create_by_prompt(glui32 usage, glui32 fmode, glui32 rock) frefid_t f = fileref_new(filename, rock, usage, fmode); g_free(filename); gtk_widget_destroy(chooser); + + gdk_threads_leave(); return f; } diff --git a/src/gargoyle-gtk.glade b/src/gargoyle-gtk.glade index cd1ada1..3162368 100644 --- a/src/gargoyle-gtk.glade +++ b/src/gargoyle-gtk.glade @@ -1,12 +1,12 @@ - + 300 600 Gargoyle GTK - + True @@ -22,7 +22,7 @@ True - + True Opens an interactive fiction game gtk-open @@ -36,12 +36,12 @@ - + True gtk-quit True True - + diff --git a/src/glk.c b/src/glk.c index c41497f..fc22682 100644 --- a/src/glk.c +++ b/src/glk.c @@ -1,3 +1,4 @@ +#include #include #include "glk.h" @@ -11,7 +12,7 @@ void glk_exit(void) { - gtk_main(); + g_thread_exit(NULL); } /* diff --git a/src/input.c b/src/input.c new file mode 100644 index 0000000..caa1824 --- /dev/null +++ b/src/input.c @@ -0,0 +1,282 @@ +#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; + } +} diff --git a/src/input.h b/src/input.h new file mode 100644 index 0000000..e961706 --- /dev/null +++ b/src/input.h @@ -0,0 +1,15 @@ +#ifndef INPUT_H +#define INPUT_H + +#include +#include +#include +#include + +#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 diff --git a/src/main.c b/src/main.c index 30a7bdf..1a1867f 100644 --- a/src/main.c +++ b/src/main.c @@ -36,10 +36,12 @@ #include #include +#include #include #include "callbacks.h" #include "error.h" +#include "event.h" #include "glk.h" /* @@ -69,7 +71,7 @@ /* The global builder object to be used to request handles to widgets */ GtkBuilder *builder = NULL; -GtkWidget* +static GtkWidget* create_window(void) { GtkWidget *window; @@ -84,12 +86,25 @@ create_window(void) 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); @@ -97,6 +112,11 @@ main(int argc, char *argv[]) textdomain(GETTEXT_PACKAGE); #endif + if( !g_thread_supported() ) + g_thread_init(NULL); + + gdk_threads_init(); + gtk_set_locale(); gtk_init(&argc, &argv); @@ -109,9 +129,24 @@ main(int argc, char *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; } diff --git a/src/model.c b/src/model.c index ce844bc..f0af53f 100644 --- a/src/model.c +++ b/src/model.c @@ -12,18 +12,19 @@ void glk_main(void) 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'); @@ -45,9 +46,28 @@ void glk_main(void) 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(); diff --git a/src/stream.c b/src/stream.c index f7bee32..b737f35 100644 --- a/src/stream.c +++ b/src/stream.c @@ -269,7 +269,11 @@ file_stream_new(frefid_t fileref, glui32 fmode, glui32 rock, gboolean unicode) 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"); @@ -286,11 +290,16 @@ file_stream_new(frefid_t fileref, glui32 fmode, glui32 rock, gboolean unicode) /* 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; @@ -407,7 +416,13 @@ glk_stream_close(strid_t str, stream_result_t *result) __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 */ @@ -427,4 +442,3 @@ glk_stream_close(strid_t str, stream_result_t *result) } g_free(str); } - diff --git a/src/stream.h b/src/stream.h index 73c46d7..b5a1e60 100644 --- a/src/stream.h +++ b/src/stream.h @@ -39,5 +39,5 @@ struct glk_stream_struct }; strid_t window_stream_new(winid_t window); - +void stream_close_common(strid_t str, stream_result_t *result); #endif diff --git a/src/strio.c b/src/strio.c index 22a9dc3..de6ccb4 100644 --- a/src/strio.c +++ b/src/strio.c @@ -59,12 +59,16 @@ convert_latin1_to_utf8(gchar *s, gsize len) 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. */ diff --git a/src/style.c b/src/style.c new file mode 100644 index 0000000..c4f51f9 --- /dev/null +++ b/src/style.c @@ -0,0 +1,8 @@ +#include "glk.h" + +void +glk_set_style(glui32 val) +{ + /* No nothing yet */ + return; +} diff --git a/src/window.c b/src/window.c index 67fc15b..c8d793c 100644 --- a/src/window.c +++ b/src/window.c @@ -182,10 +182,13 @@ glk_window_open(winid_t split, glui32 method, glui32 size, glui32 wintype, 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; } @@ -209,6 +212,11 @@ glk_window_open(winid_t split, glui32 method, glui32 size, glui32 wintype, { 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); @@ -219,20 +227,63 @@ glk_window_open(winid_t split, glui32 method, glui32 size, glui32 wintype, 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. @@ -253,11 +304,15 @@ glk_window_clear(winid_t win) 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; @@ -353,3 +408,22 @@ glk_window_get_echo_stream(winid_t win) 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); +} diff --git a/src/window.h b/src/window.h index 954415e..73583a3 100644 --- a/src/window.h +++ b/src/window.h @@ -6,6 +6,8 @@ #include "stream.h" #include "error.h" +#include "callbacks.h" +#include "input.h" enum InputRequestType { @@ -32,6 +34,8 @@ struct glk_window_struct glui32 *line_input_buffer_unicode; glui32 line_input_buffer_max_len; gboolean mouse_input_requested; + gulong keypress_handler; + gulong insert_text_handler; }; #endif -- 2.30.2