+extern GPrivate *glk_data_key;
+
+static winid_t
+window_new_common(glui32 rock)
+{
+ ChimaraGlkPrivate *glk_data = g_private_get(glk_data_key);
+ winid_t win = g_new0(struct glk_window_struct, 1);
+
+ win->magic = MAGIC_WINDOW;
+ win->rock = rock;
+ if(glk_data->register_obj)
+ win->disprock = (*glk_data->register_obj)(win, gidisp_Class_Window);
+
+ win->window_node = g_node_new(win);
+
+ /* Every window has a window stream, but printing to it might have no effect */
+ win->window_stream = stream_new_common(0);
+ win->window_stream->file_mode = filemode_Write;
+ win->window_stream->type = STREAM_TYPE_WINDOW;
+ win->window_stream->window = win;
+ win->window_stream->style = "normal";
+
+ win->echo_stream = NULL;
+ win->input_request_type = INPUT_REQUEST_NONE;
+ win->line_input_buffer = NULL;
+ win->line_input_buffer_unicode = NULL;
+ win->history = NULL;
+
+ /* Initialise the buffer */
+ win->buffer = g_string_sized_new(1024);
+
+ /* 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: do all the stuff necessary to close a window. Call only
+ from Glk thread. */
+static void
+window_close_common(winid_t win, gboolean destroy_node)
+{
+ ChimaraGlkPrivate *glk_data = g_private_get(glk_data_key);
+
+ if(glk_data->unregister_obj)
+ {
+ (*glk_data->unregister_obj)(win, gidisp_Class_Window, win->disprock);
+ win->disprock.ptr = NULL;
+ }
+
+ if(destroy_node)
+ g_node_destroy(win->window_node);
+
+ 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);
+
+ if(win->pager_layout)
+ g_object_unref(win->pager_layout);
+
+ g_free(win);
+}