From: fliep Date: Tue, 12 Jan 2010 20:42:40 +0000 (+0000) Subject: Fixed shutdown problems. Everything should properly shut down now. X-Git-Tag: v0.9~256 X-Git-Url: https://git.stderr.nl/gitweb?a=commitdiff_plain;h=1589fbfcd406df40d8da4f078dad3327c4862871;p=projects%2Fchimara%2Fchimara.git Fixed shutdown problems. Everything should properly shut down now. Added shutdown message when Glk plugin finishes normally. --- diff --git a/libchimara/abort.c b/libchimara/abort.c index 8399f05..28e33fa 100644 --- a/libchimara/abort.c +++ b/libchimara/abort.c @@ -43,7 +43,13 @@ abort_glk(void) ChimaraGlkPrivate *glk_data = g_private_get(glk_data_key); if(glk_data->interrupt_handler) (*(glk_data->interrupt_handler))(); - shutdown_glk(); + shutdown_glk_pre(); + shutdown_glk_post(); + /* If program is terminated by g_thread_exit() instead of returning from the + glk_main() function, then the line in glk_enter() where the "stopped" + signal is emitted will not be reached. So we have to emit it here. */ + if(!glk_data->in_startup) + g_signal_emit_by_name(glk_data->self, "stopped"); g_thread_exit(NULL); } @@ -61,15 +67,16 @@ check_for_abort(void) g_mutex_unlock(glk_data->abort_lock); } -/* Internal function: do any cleanup for shutting down the Glk library. */ +/* Internal function: shut down all requests and anything not necessary while + showing the last displayed configuration of windows. */ void -shutdown_glk(void) +shutdown_glk_pre(void) { ChimaraGlkPrivate *glk_data = g_private_get(glk_data_key); - + /* Stop any timers */ glk_request_timer_events(0); - + /* Cancel any pending input requests and flush all window buffers */ winid_t win; for(win = glk_window_iterate(NULL, NULL); win; win = glk_window_iterate(win, NULL)) @@ -86,33 +93,83 @@ shutdown_glk(void) break; case INPUT_REQUEST_NONE: default: - ; /* Handle mouse and hyperlink requests */ + ; /* TODO: Handle mouse and hyperlink requests */ } - + flush_window_buffer(win); } - + /* Close any open resource files */ if(glk_data->resource_map != NULL) { giblorb_destroy_map(glk_data->resource_map); + glk_data->resource_map = NULL; glk_stream_close(glk_data->resource_file, NULL); } - - /* Unref the input queues */ - g_async_queue_unref(glk_data->char_input_queue); - g_async_queue_unref(glk_data->line_input_queue); - + + /* Empty the input queues */ + while(g_async_queue_try_pop(glk_data->char_input_queue)) + ; + while(g_async_queue_try_pop(glk_data->line_input_queue)) + ; + /* Wait for any pending window rearrange */ g_mutex_lock(glk_data->arrange_lock); if(glk_data->needs_rearrange) g_cond_wait(glk_data->rearranged, glk_data->arrange_lock); g_mutex_unlock(glk_data->arrange_lock); +} - /* Default handler for 'stopped' unloads the plugin, so be absolutely sure - we're not calling any dispatch callbacks after this point */ - if(!glk_data->in_startup) - g_signal_emit_by_name(glk_data->self, "stopped"); +/* Internal function: do any Glk-thread cleanup for shutting down the Glk library. */ +void +shutdown_glk_post(void) +{ + ChimaraGlkPrivate *glk_data = g_private_get(glk_data_key); + + /* Free all opaque objects; can't iterate normally, because the objects are + being removed from the global iteration lists */ + if(glk_data->root_window) + glk_window_close(glk_data->root_window->data, NULL); + g_assert(glk_data->root_window == NULL); + strid_t str; + while( (str = glk_stream_iterate(NULL, NULL)) ) + glk_stream_close(str, NULL); + frefid_t fref; + while( (fref = glk_fileref_iterate(NULL, NULL)) ) + glk_fileref_destroy(fref); + schanid_t sch; + while( (sch = glk_schannel_iterate(NULL, NULL)) ) + glk_schannel_destroy(sch); + + /* Empty the event queue */ + g_mutex_lock(glk_data->event_lock); + g_queue_foreach(glk_data->event_queue, (GFunc)g_free, NULL); + g_queue_clear(glk_data->event_queue); + g_mutex_unlock(glk_data->event_lock); + + /* Reset the abort signaling mechanism */ + g_mutex_lock(glk_data->abort_lock); + glk_data->abort_signalled = FALSE; + g_mutex_unlock(glk_data->abort_lock); + + /* Reset arrangement mechanism */ + g_mutex_lock(glk_data->arrange_lock); + glk_data->needs_rearrange = FALSE; + glk_data->ignore_next_arrange_event = FALSE; + g_mutex_unlock(glk_data->arrange_lock); + + /* Unref input queues (they are not destroyed because the main thread stil holds a ref */ + g_async_queue_unref(glk_data->char_input_queue); + g_async_queue_unref(glk_data->line_input_queue); + + /* Reset other stuff */ + glk_data->interrupt_handler = NULL; + g_free(glk_data->current_dir); + glk_data->current_dir = NULL; + /* Remove the dispatch callbacks */ + glk_data->register_obj = NULL; + glk_data->unregister_obj = NULL; + glk_data->register_arr = NULL; + glk_data->unregister_arr = NULL; - _chimara_glk_free_nonwindow_private_data(glk_data); - glk_data->needs_reset = TRUE; + /* Leave the style_initialized flag as it is, since the CSS file is a widget property */ } diff --git a/libchimara/abort.h b/libchimara/abort.h index e6ac904..c583166 100644 --- a/libchimara/abort.h +++ b/libchimara/abort.h @@ -4,7 +4,8 @@ #include G_GNUC_INTERNAL void check_for_abort(void); -G_GNUC_INTERNAL void shutdown_glk(void); +G_GNUC_INTERNAL void shutdown_glk_pre(void); +G_GNUC_INTERNAL void shutdown_glk_post(void); #endif diff --git a/libchimara/chimara-glk-private.h b/libchimara/chimara-glk-private.h index b3c9085..903d353 100644 --- a/libchimara/chimara-glk-private.h +++ b/libchimara/chimara-glk-private.h @@ -34,6 +34,9 @@ struct _ChimaraGlkPrivate { /* Hashtable containing the default and current style */ struct StyleSet *default_styles; struct StyleSet *current_styles; + gboolean style_initialized; /* Have styles been initialized */ + /* Final message displayed when game exits */ + gchar *final_message; /* *** Threading data *** */ /* Whether program is running */ @@ -50,6 +53,9 @@ struct _ChimaraGlkPrivate { /* Abort mechanism */ GMutex *abort_lock; gboolean abort_signalled; + /* Key press after shutdown mechanism */ + GMutex *shutdown_lock; + GCond *shutdown_key_pressed; /* Window arrangement locks */ GMutex *arrange_lock; GCond *rearranged; @@ -81,10 +87,6 @@ struct _ChimaraGlkPrivate { void (*unregister_obj)(void *, glui32, gidispatch_rock_t); gidispatch_rock_t (*register_arr)(void *, glui32, char *); void (*unregister_arr)(void *, glui32, char *, gidispatch_rock_t); - /* Have styles been initialized */ - gboolean style_initialized; - /* Is widget still displaying windows from last run */ - gboolean needs_reset; /* *** Platform-dependent Glk library data *** */ /* Flag for functions to find out if they are being called from startup code */ @@ -96,8 +98,6 @@ struct _ChimaraGlkPrivate { #define CHIMARA_GLK_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), CHIMARA_TYPE_GLK, ChimaraGlkPrivate)) #define CHIMARA_GLK_USE_PRIVATE(o, n) ChimaraGlkPrivate *n = CHIMARA_GLK_PRIVATE(o) -G_GNUC_INTERNAL void _chimara_glk_free_nonwindow_private_data(ChimaraGlkPrivate *self); - G_END_DECLS #endif /* __CHIMARA_GLK_PRIVATE_H__ */ diff --git a/libchimara/chimara-glk.c b/libchimara/chimara-glk.c index a00ae65..8d1e655 100644 --- a/libchimara/chimara-glk.c +++ b/libchimara/chimara-glk.c @@ -55,7 +55,7 @@ enum { PROP_PROTECT, PROP_DEFAULT_FONT_DESCRIPTION, PROP_MONOSPACE_FONT_DESCRIPTION, - PROP_SPACING + PROP_SPACING, }; enum { @@ -88,6 +88,8 @@ chimara_glk_init(ChimaraGlk *self) priv->css_file = "style.css"; priv->default_styles = g_new0(StyleSet,1); priv->current_styles = g_new0(StyleSet,1); + priv->style_initialized = FALSE; + priv->final_message = g_strdup("[ The game has finished ]"); priv->running = FALSE; priv->program = NULL; priv->thread = NULL; @@ -97,6 +99,8 @@ chimara_glk_init(ChimaraGlk *self) priv->event_queue_not_full = g_cond_new(); priv->abort_lock = g_mutex_new(); priv->abort_signalled = FALSE; + priv->shutdown_lock = g_mutex_new(); + priv->shutdown_key_pressed = g_cond_new(); priv->arrange_lock = g_mutex_new(); priv->rearranged = g_cond_new(); priv->needs_rearrange = FALSE; @@ -110,8 +114,6 @@ chimara_glk_init(ChimaraGlk *self) priv->current_stream = NULL; priv->stream_list = NULL; priv->timer_id = 0; - priv->style_initialized = FALSE; - priv->needs_reset = FALSE; priv->in_startup = FALSE; priv->current_dir = NULL; } @@ -170,9 +172,23 @@ chimara_glk_get_property(GObject *object, guint prop_id, GValue *value, GParamSp } } -void -_chimara_glk_free_nonwindow_private_data(ChimaraGlkPrivate *priv) +static void +chimara_glk_finalize(GObject *object) { + ChimaraGlk *self = CHIMARA_GLK(object); + CHIMARA_GLK_USE_PRIVATE(self, priv); + + /* Free widget properties */ + pango_font_description_free(priv->default_font_desc); + pango_font_description_free(priv->monospace_font_desc); + g_free(priv->final_message); + /* Free styles */ + g_hash_table_destroy(priv->default_styles->text_buffer); + g_hash_table_destroy(priv->default_styles->text_grid); + g_hash_table_destroy(priv->current_styles->text_buffer); + g_hash_table_destroy(priv->current_styles->text_grid); + priv->style_initialized = FALSE; + /* Free the event queue */ g_mutex_lock(priv->event_lock); g_queue_foreach(priv->event_queue, (GFunc)g_free, NULL); @@ -182,86 +198,32 @@ _chimara_glk_free_nonwindow_private_data(ChimaraGlkPrivate *priv) priv->event_queue = NULL; g_mutex_unlock(priv->event_lock); g_mutex_free(priv->event_lock); - - /* Free the abort signaling mechanism */ + /* Free the abort signaling mechanism */ g_mutex_lock(priv->abort_lock); /* Make sure no other thread is busy with this */ g_mutex_unlock(priv->abort_lock); g_mutex_free(priv->abort_lock); priv->abort_lock = NULL; - - /* Unref input queues */ - g_async_queue_unref(priv->char_input_queue); - g_async_queue_unref(priv->line_input_queue); - - /* Free styles */ - pango_font_description_free(priv->default_font_desc); - pango_font_description_free(priv->monospace_font_desc); - - g_free(priv->current_dir); - g_hash_table_destroy(priv->default_styles->text_buffer); - g_hash_table_destroy(priv->default_styles->text_grid); - g_hash_table_destroy(priv->current_styles->text_buffer); - g_hash_table_destroy(priv->current_styles->text_grid); -} - -/* Internal function: main thread version of destroy_windows_below, only more - DESTRUCTO-MATIC! */ -static void -trash_windows_recursive(ChimaraGlkPrivate *priv, winid_t win) -{ - switch(win->type) - { - case wintype_Blank: - case wintype_TextGrid: - case wintype_TextBuffer: - gtk_widget_unparent(win->frame); - break; - - case wintype_Pair: - trash_windows_recursive(priv, win->window_node->children->data); - trash_windows_recursive(priv, win->window_node->children->next->data); - break; - - default: - ILLEGAL_PARAM("Unknown window type: %u", win->type); - return; - } - trash_stream_thread_independent(priv, win->window_stream); - trash_window_thread_independent(priv, win); -} - -void -_chimara_glk_free_window_private_data(ChimaraGlkPrivate *priv) -{ - /* Destroy the window tree */ - if(priv->root_window) { - trash_windows_recursive(priv, priv->root_window->data); - g_node_destroy(priv->root_window); - } - + /* Free the shutdown keypress signaling mechanism */ + g_mutex_lock(priv->shutdown_lock); + g_cond_free(priv->shutdown_key_pressed); + g_mutex_unlock(priv->shutdown_lock); + priv->shutdown_lock = NULL; /* Free the window arrangement signaling */ g_mutex_lock(priv->arrange_lock); g_cond_free(priv->rearranged); g_mutex_unlock(priv->arrange_lock); g_mutex_free(priv->arrange_lock); priv->arrange_lock = NULL; + /* Unref input queues (this should destroy them since any Glk thread has stopped by now */ + g_async_queue_unref(priv->char_input_queue); + g_async_queue_unref(priv->line_input_queue); + + /* Free other stuff */ + if(priv->current_dir) + g_free(priv->current_dir); - /* Remove the dispatch callbacks */ - priv->register_obj = NULL; - priv->unregister_obj = NULL; - priv->register_arr = NULL; - priv->unregister_arr = NULL; -} - -static void -chimara_glk_finalize(GObject *object) -{ - ChimaraGlk *self = CHIMARA_GLK(object); - CHIMARA_GLK_USE_PRIVATE(self, priv); - _chimara_glk_free_nonwindow_private_data(priv); - _chimara_glk_free_window_private_data(priv); - + /* Chain up to parent */ G_OBJECT_CLASS(chimara_glk_parent_class)->finalize(object); } @@ -603,19 +565,18 @@ static void chimara_glk_stopped(ChimaraGlk *self) { CHIMARA_GLK_USE_PRIVATE(self, priv); - printf("stopped signal received\n"); priv->running = FALSE; /* Free the plugin */ if( priv->program && !g_module_close(priv->program) ) g_warning( "Error closing module: %s", g_module_error() ); + priv->program = NULL; } static void chimara_glk_started(ChimaraGlk *self) { CHIMARA_GLK_USE_PRIVATE(self, priv); - printf("started signal received\n"); priv->running = TRUE; } @@ -1106,6 +1067,7 @@ glk_enter(struct StartupData *startup) extern GPrivate *glk_data_key; g_private_set(glk_data_key, startup->glk_data); + /* Acquire the Glk thread's references to the input queues */ g_async_queue_ref(startup->glk_data->char_input_queue); g_async_queue_ref(startup->glk_data->line_input_queue); @@ -1125,15 +1087,13 @@ glk_enter(struct StartupData *startup) } /* Run main function */ - g_signal_emit_by_name(startup->glk_data->self, "started"); - (startup->glk_main)(); - g_signal_emit_by_name(startup->glk_data->self, "stopped"); - /* FIXME: hack. should be done by the signal above but for some reason - * this doesn't work */ - chimara_glk_stopped(startup->glk_data->self); - + glk_main_t glk_main = startup->glk_main; g_slice_free(struct StartupData, startup); - return NULL; + g_signal_emit_by_name(startup->glk_data->self, "started"); + glk_main(); + glk_exit(); /* Run shutdown code in glk_exit() even if glk_main() returns normally */ + g_assert_not_reached(); /* because glk_exit() calls g_thread_exit() */ + return NULL; } /** @@ -1168,13 +1128,6 @@ chimara_glk_run(ChimaraGlk *glk, const gchar *plugin, int argc, char *argv[], GE ChimaraGlkPrivate *priv = CHIMARA_GLK_PRIVATE(glk); struct StartupData *startup = g_slice_new0(struct StartupData); - - /* If anything was left over from the previous run, destroy it */ - if(priv->needs_reset) { - _chimara_glk_free_window_private_data(priv); - priv->needs_reset = FALSE; - chimara_glk_init(glk); - } /* Open the module to run */ g_assert( g_module_supported() ); @@ -1228,7 +1181,6 @@ chimara_glk_stop(ChimaraGlk *glk) g_return_if_fail(glk || CHIMARA_IS_GLK(glk)); CHIMARA_GLK_USE_PRIVATE(glk, priv); - printf("stopping (%d)...\n", priv->running); /* Don't do anything if not running a program */ if(!priv->running) return; @@ -1239,6 +1191,10 @@ chimara_glk_stop(ChimaraGlk *glk) g_mutex_unlock(priv->abort_lock); /* Stop blocking on the event queue condition */ event_throw(glk, evtype_Abort, NULL, 0, 0); + /* Stop blocking on the shutdown key press condition */ + g_mutex_lock(priv->shutdown_lock); + g_cond_signal(priv->shutdown_key_pressed); + g_mutex_unlock(priv->shutdown_lock); } } @@ -1257,7 +1213,10 @@ chimara_glk_wait(ChimaraGlk *glk) /* Don't do anything if not running a program */ if(!priv->running) return; + /* Unlock GDK mutex, because the Glk program might need to use it for shutdown */ + gdk_threads_leave(); g_thread_join(priv->thread); + gdk_threads_enter(); } /** diff --git a/libchimara/glk.c b/libchimara/glk.c index 4304aef..58b9c00 100644 --- a/libchimara/glk.c +++ b/libchimara/glk.c @@ -5,6 +5,7 @@ #include "chimara-glk.h" #include "chimara-glk-private.h" #include "gi_blorb.h" +#include "window.h" G_GNUC_INTERNAL GPrivate *glk_data_key = NULL; @@ -42,7 +43,50 @@ G_GNUC_INTERNAL GPrivate *glk_data_key = NULL; void glk_exit(void) { - shutdown_glk(); + ChimaraGlkPrivate *glk_data = g_private_get(glk_data_key); + + shutdown_glk_pre(); + + /* Find the biggest text buffer window */ + winid_t win, largewin = NULL; + glui32 largearea = 0; + for(win = glk_window_iterate(NULL, NULL); win; win = glk_window_iterate(win, NULL)) { + if(win->type == wintype_TextBuffer) { + glui32 w, h; + if(!largewin) { + largewin = win; + glk_window_get_size(largewin, &w, &h); + largearea = w * h; + } else { + glk_window_get_size(win, &w, &h); + if(w * h > largearea) { + largewin = win; + largearea = w * h; + } + } + } + } + if(largewin) { + glk_set_window(largewin); + glk_set_style(style_Alert); + glk_put_string("\n"); + glk_put_string(glk_data->final_message); + glk_put_string("\n"); + flush_window_buffer(largewin); + } + + g_mutex_lock(glk_data->shutdown_lock); + for(win = glk_window_iterate(NULL, NULL); win; win = glk_window_iterate(win, NULL)) { + if(win->type == wintype_TextGrid || win->type == wintype_TextBuffer) + g_signal_handler_unblock(win->widget, win->shutdown_keypress_handler); + } + g_cond_wait(glk_data->shutdown_key_pressed, glk_data->shutdown_lock); + g_mutex_unlock(glk_data->shutdown_lock); + + shutdown_glk_post(); + + g_signal_emit_by_name(glk_data->self, "stopped"); + g_thread_exit(NULL); } diff --git a/libchimara/input.c b/libchimara/input.c index a2e0e4a..9e7eea0 100644 --- a/libchimara/input.c +++ b/libchimara/input.c @@ -392,6 +392,35 @@ glk_cancel_line_event(winid_t win, event_t *event) } } +/* Helper function: Turn off shutdown key-press-event signal handler */ +static gboolean +turn_off_handler(GNode *node) +{ + winid_t win = node->data; + g_signal_handler_block(win->widget, win->shutdown_keypress_handler); + return FALSE; /* don't stop */ +} + +/* Internal function: Callback for signal key-press-event while waiting for shutdown. */ +gboolean +on_shutdown_key_press_event(GtkWidget *widget, GdkEventKey *event, winid_t win) +{ + ChimaraGlk *glk = CHIMARA_GLK(gtk_widget_get_ancestor(widget, CHIMARA_TYPE_GLK)); + g_assert(glk); + CHIMARA_GLK_USE_PRIVATE(glk, priv); + + /* Turn off all the signal handlers */ + if(priv->root_window) + g_node_traverse(priv->root_window, G_IN_ORDER, G_TRAVERSE_LEAVES, -1, (GNodeTraverseFunc)turn_off_handler, NULL); + + /* Signal the Glk library that it can shut everything down now */ + g_mutex_lock(priv->shutdown_lock); + g_cond_signal(priv->shutdown_key_pressed); + g_mutex_unlock(priv->shutdown_lock); + + return TRUE; /* block the event */ +} + /* Internal function: General callback for signal key-press-event on a text buffer or text grid window. Used in character input on both text buffers and grids. Blocked when not in use. */ gboolean on_char_input_key_press_event(GtkWidget *widget, GdkEventKey *event, winid_t win) diff --git a/libchimara/input.h b/libchimara/input.h index fcba5a0..d93361c 100644 --- a/libchimara/input.h +++ b/libchimara/input.h @@ -10,6 +10,7 @@ #include "event.h" #include "strio.h" +G_GNUC_INTERNAL gboolean on_shutdown_key_press_event(GtkWidget *widget, GdkEventKey *event, winid_t win); G_GNUC_INTERNAL gboolean on_char_input_key_press_event(GtkWidget *widget, GdkEventKey *event, winid_t win); G_GNUC_INTERNAL gboolean on_line_input_key_press_event(GtkWidget *widget, GdkEventKey *event, winid_t win); G_GNUC_INTERNAL void after_window_insert_text(GtkTextBuffer *textbuffer, GtkTextIter *location, gchar *text, gint len, winid_t win); diff --git a/libchimara/stream.c b/libchimara/stream.c index f6abec6..afc55be 100644 --- a/libchimara/stream.c +++ b/libchimara/stream.c @@ -28,22 +28,6 @@ stream_new_common(glui32 rock) return str; } -/* Internal function: stream closing stuff that is safe to call from either the - main thread or the Glk thread. */ -void -trash_stream_thread_independent(ChimaraGlkPrivate *glk_data, strid_t str) -{ - /* Remove the stream from the global stream list */ - glk_data->stream_list = g_list_delete_link(glk_data->stream_list, str->stream_list); - - /* If it was the current output stream, set that to NULL */ - if(glk_data->current_stream == str) - glk_data->current_stream = NULL; - - str->magic = MAGIC_FREE; - g_free(str); -} - /* Internal function: Stuff to do upon closing any type of stream. Call only from Glk thread. */ void @@ -71,7 +55,15 @@ stream_close_common(strid_t str, stream_result_t *result) result->writecount = str->write_count; } - trash_stream_thread_independent(glk_data, str); + /* Remove the stream from the global stream list */ + glk_data->stream_list = g_list_delete_link(glk_data->stream_list, str->stream_list); + + /* If it was the current output stream, set that to NULL */ + if(glk_data->current_stream == str) + glk_data->current_stream = NULL; + + str->magic = MAGIC_FREE; + g_free(str); } /** diff --git a/libchimara/stream.h b/libchimara/stream.h index 87b8b7a..ef6b1f0 100644 --- a/libchimara/stream.h +++ b/libchimara/stream.h @@ -56,6 +56,5 @@ struct glk_stream_struct G_GNUC_INTERNAL strid_t file_stream_new(frefid_t fileref, glui32 fmode, glui32 rock, gboolean unicode); G_GNUC_INTERNAL strid_t stream_new_common(glui32 rock); G_GNUC_INTERNAL void stream_close_common(strid_t str, stream_result_t *result); -G_GNUC_INTERNAL void trash_stream_thread_independent(ChimaraGlkPrivate *glk_data, strid_t str); #endif diff --git a/libchimara/window.c b/libchimara/window.c index 31b157f..72643c3 100644 --- a/libchimara/window.c +++ b/libchimara/window.c @@ -37,24 +37,8 @@ window_new_common(glui32 rock) /* Initialise hyperlink table */ win->hyperlinks = g_hash_table_new_full(g_int_hash, g_direct_equal, g_free, g_object_unref); - - return win; -} - -/* Internal function: window closing stuff that is safe to call from either the - main thread or the Glk thread. */ -void -trash_window_thread_independent(ChimaraGlkPrivate *glk_data, winid_t win) -{ - win->magic = MAGIC_FREE; - g_list_foreach(win->history, (GFunc)g_free, NULL); - g_list_free(win->history); - - g_string_free(win->buffer, TRUE); - g_hash_table_destroy(win->hyperlinks); - g_free(win->current_hyperlink); - g_free(win); + return win; } /* Internal function: do all the stuff necessary to close a window. Call only @@ -73,7 +57,15 @@ window_close_common(winid_t win, gboolean destroy_node) if(destroy_node) g_node_destroy(win->window_node); - trash_window_thread_independent(glk_data, win); + win->magic = MAGIC_FREE; + + g_list_foreach(win->history, (GFunc)g_free, NULL); + g_list_free(win->history); + + g_string_free(win->buffer, TRUE); + g_hash_table_destroy(win->hyperlinks); + g_free(win->current_hyperlink); + g_free(win); } /** @@ -509,6 +501,8 @@ glk_window_open(winid_t split, glui32 method, glui32 size, glui32 wintype, g_signal_handler_block(textview, win->char_input_keypress_handler); win->line_input_keypress_handler = g_signal_connect(textview, "key-press-event", G_CALLBACK(on_line_input_key_press_event), win); g_signal_handler_block(textview, win->line_input_keypress_handler); + win->shutdown_keypress_handler = g_signal_connect(textview, "key-press-event", G_CALLBACK(on_shutdown_key_press_event), win); + g_signal_handler_block(textview, win->shutdown_keypress_handler); } break; @@ -547,11 +541,11 @@ glk_window_open(winid_t split, glui32 method, glui32 size, glui32 wintype, g_signal_handler_block(textview, win->char_input_keypress_handler); win->line_input_keypress_handler = g_signal_connect( textview, "key-press-event", G_CALLBACK(on_line_input_key_press_event), win ); g_signal_handler_block(textview, win->line_input_keypress_handler); - + win->shutdown_keypress_handler = g_signal_connect( textview, "key-press-event", G_CALLBACK(on_shutdown_key_press_event), win ); + g_signal_handler_block(textview, win->shutdown_keypress_handler); win->insert_text_handler = g_signal_connect_after( textbuffer, "insert-text", G_CALLBACK(after_window_insert_text), win ); g_signal_handler_block(textbuffer, win->insert_text_handler); - /* Create an editable tag to indicate uneditable parts of the window (for line input) */ gtk_text_buffer_create_tag(textbuffer, "uneditable", "editable", FALSE, "editable-set", TRUE, NULL); diff --git a/libchimara/window.h b/libchimara/window.h index 845550e..36bf257 100644 --- a/libchimara/window.h +++ b/libchimara/window.h @@ -72,6 +72,7 @@ struct glk_window_struct gulong line_input_keypress_handler; gulong insert_text_handler; gulong tag_event_handler; + gulong shutdown_keypress_handler; /* Window buffer */ GString *buffer; /* Hyperlinks */ @@ -79,6 +80,4 @@ struct glk_window_struct struct hyperlink *current_hyperlink; }; -G_GNUC_INTERNAL void trash_window_thread_independent(ChimaraGlkPrivate *glk_data, winid_t win); - #endif