first.c compilet en draait!
authorPhilip Chimento <philip.chimento@gmail.com>
Tue, 19 Aug 2008 22:56:35 +0000 (22:56 +0000)
committerPhilip Chimento <philip.chimento@gmail.com>
Tue, 19 Aug 2008 22:56:35 +0000 (22:56 +0000)
git-svn-id: http://lassie.dyndns-server.com/svn/gargoyle-gtk@10 ddfedd41-794f-dd11-ae45-00112f111e67

18 files changed:
src/Makefile
src/callbacks.c
src/callbacks.h
src/event.c [new file with mode: 0644]
src/event.h [new file with mode: 0644]
src/fileref.c
src/gargoyle-gtk.glade
src/glk.c
src/input.c [new file with mode: 0644]
src/input.h [new file with mode: 0644]
src/main.c
src/model.c
src/stream.c
src/stream.h
src/strio.c
src/style.c [new file with mode: 0644]
src/window.c
src/window.h

index 60ca6f7a46dd046c4d882de6d0c542f1deb763e8..5c4103d8298834c59e45183a7fe4532a3099ca37 100644 (file)
@@ -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}`
index 34cd66ec2b20752b38fe971355adb36cc2adcfa0..6067526bde9fab7ed7848d83b90a7508d58d8e91 100644 (file)
  * 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();
+}
+
index 6fd524e23e1a570697a2c1b38eebcede6056d9df..313ca00268458b2114a22b6a0447eaf4ce2e1db6 100644 (file)
@@ -31,5 +31,9 @@
  */
 
 #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);
diff --git a/src/event.c b/src/event.c
new file mode 100644 (file)
index 0000000..0334e39
--- /dev/null
@@ -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 (file)
index 0000000..3acbdee
--- /dev/null
@@ -0,0 +1,19 @@
+#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
index 1b7cf57cfc435d1af8fea1092d2c619e841dac94..921997b08238da2315cc8306c5b34eab9226470f 100644 (file)
@@ -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;
 }
 
index cd1ada1b1c97efa312553584175b5f3fa71fd111..31623686cf18f0179e9c9b5da2a297f3f191848d 100644 (file)
@@ -1,12 +1,12 @@
 <?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>
@@ -22,7 +22,7 @@
                   <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>
index c41497f29f24f84477f7ea8ec3d48f0ca122a281..fc22682676d383f7f2aed2be6fdb435b77eeeed9 100644 (file)
--- a/src/glk.c
+++ b/src/glk.c
@@ -1,3 +1,4 @@
+#include <glib.h>
 #include <gtk/gtk.h>
 
 #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 (file)
index 0000000..caa1824
--- /dev/null
@@ -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 (file)
index 0000000..e961706
--- /dev/null
@@ -0,0 +1,15 @@
+#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
index 30a7bdfed65ee3ee4c4cab9663c2ec200ac9ccfd..1a1867f50357c398f3c6c323bd0fff74698a2937 100644 (file)
 #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"
 
 /*
@@ -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;
 }
index ce844bcb63e72ff1d911e5789b4563a093ec35a4..f0af53f839e0cc5aea9f15c6743079b13056402c 100644 (file)
@@ -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();
index f7bee3243db3a94061afeecf44f138b4d60f4571..b737f356f798766089dffbd097b06c4772fdc34a 100644 (file)
@@ -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);
 }
-
index 73c46d706de08048a536abc57eef55a608c884be..b5a1e6092edf7bed4c74eea92bbe2163cf09396c 100644 (file)
@@ -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
index 22a9dc3656de96561be4523d418b607d45546b1d..de6ccb48f5ed9057cb15dd5606078b7b527a1a77 100644 (file)
@@ -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 (file)
index 0000000..c4f51f9
--- /dev/null
@@ -0,0 +1,8 @@
+#include "glk.h"
+
+void
+glk_set_style(glui32 val)
+{
+       /* No nothing yet */
+       return;
+}
index 67fc15b0a393edc4f7bf19cc565d341d89d6f13e..c8d793c4e3396989a6eacd20138f2f22a3a1bb31 100644 (file)
@@ -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);
+}
index 954415e494ecd14fb1f2c7b22ef446ae3b0e352e..73583a352d902cb4e075f23082ad156396c6db0a 100644 (file)
@@ -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