X-Git-Url: https://git.stderr.nl/gitweb?a=blobdiff_plain;f=src%2Fwindow.c;h=6ae9f554341092dd1ff75d19d05431708d3829a7;hb=8e48218aa3a9423cc103122a338269e158f542e9;hp=f533cc73da389cc5d5879b29571561fb53af648c;hpb=904fed6618b22e84597efd60c3784e57d44f3ef1;p=projects%2Fchimara%2Fchimara.git diff --git a/src/window.c b/src/window.c index f533cc7..6ae9f55 100644 --- a/src/window.c +++ b/src/window.c @@ -1,4 +1,5 @@ #include "window.h" +#include "magic.h" #include "chimara-glk-private.h" extern ChimaraGlkPrivate *glk_data; @@ -22,6 +23,8 @@ extern ChimaraGlkPrivate *glk_data; winid_t glk_window_iterate(winid_t win, glui32 *rockptr) { + VALID_WINDOW_OR_NULL(win, return NULL); + GNode *retnode; if(win == NULL) @@ -62,7 +65,7 @@ glk_window_iterate(winid_t win, glui32 *rockptr) glui32 glk_window_get_rock(winid_t win) { - g_return_val_if_fail(win != NULL, 0); + VALID_WINDOW(win, return 0); return win->rock; } @@ -78,7 +81,7 @@ glk_window_get_rock(winid_t win) glui32 glk_window_get_type(winid_t win) { - g_return_val_if_fail(win != NULL, 0); + VALID_WINDOW(win, return 0); return win->type; } @@ -96,7 +99,7 @@ glk_window_get_type(winid_t win) winid_t glk_window_get_parent(winid_t win) { - g_return_val_if_fail(win != NULL, NULL); + VALID_WINDOW(win, return NULL); /* Value will also be NULL if win is the root window */ return (winid_t)win->window_node->parent->data; } @@ -113,7 +116,7 @@ glk_window_get_parent(winid_t win) winid_t glk_window_get_sibling(winid_t win) { - g_return_val_if_fail(win != NULL, NULL); + VALID_WINDOW(win, return NULL); if(G_NODE_IS_ROOT(win->window_node)) return NULL; @@ -137,15 +140,6 @@ glk_window_get_root() return (winid_t)glk_data->root_window->data; } -/* Determine the size of a "0" character in pixels */ -static void -text_window_get_char_size(GtkWidget *textview, int *width, int *height) -{ - PangoLayout *zero = gtk_widget_create_pango_layout(textview, "0"); - pango_layout_get_pixel_size(zero, width, height); - g_object_unref(zero); -} - /** * glk_window_open: * @split: The window to split to create the new window. Must be 0 if there @@ -332,24 +326,19 @@ winid_t glk_window_open(winid_t split, glui32 method, glui32 size, glui32 wintype, glui32 rock) { - /* - if(split) - { - g_warning("glk_window_open: splitting of windows not implemented"); - return NULL; - } - */ + VALID_WINDOW_OR_NULL(split, return NULL); if(split == NULL && glk_data->root_window != NULL) { - g_warning("glk_window_open: there is already a root window"); + ILLEGAL("Tried to open a new root window, but there is already a root window"); return NULL; } gdk_threads_enter(); - /* We only create one window and don't support any more than that */ + /* Create the new window */ winid_t win = g_new0(struct glk_window_struct, 1); + win->magic = MAGIC_WINDOW; win->rock = rock; win->type = wintype; win->window_node = g_node_new(win); @@ -387,14 +376,16 @@ glk_window_open(winid_t split, glui32 method, glui32 size, glui32 wintype, gtk_widget_show_all(scrolledwindow); /* Set the window's font */ - /* TODO: Use Pango to pick out a monospace font on the system */ - PangoFontDescription *font = pango_font_description_from_string("Monospace"); - gtk_widget_modify_font(textview, font); - pango_font_description_free(font); + gtk_widget_modify_font(textview, glk_data->monospace_font_desc); win->widget = textview; win->frame = scrolledwindow; - text_window_get_char_size( textview, &(win->unit_width), &(win->unit_height) ); + + /* Determine the size of a "0" character in pixels */ + PangoLayout *zero = gtk_widget_create_pango_layout(textview, "0"); + pango_layout_set_font_description(zero, glk_data->monospace_font_desc); + pango_layout_get_pixel_size(zero, &(win->unit_width), &(win->unit_height)); + g_object_unref(zero); /* Set the other parameters (width and height are set later) */ win->window_stream = window_stream_new(win); @@ -415,15 +406,25 @@ glk_window_open(winid_t split, glui32 method, glui32 size, glui32 wintype, GtkWidget *textview = gtk_text_view_new(); GtkTextBuffer *textbuffer = gtk_text_view_get_buffer( GTK_TEXT_VIEW(textview) ); + gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW(scrolledwindow), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC ); + gtk_text_view_set_wrap_mode( GTK_TEXT_VIEW(textview), GTK_WRAP_WORD_CHAR ); gtk_text_view_set_editable( GTK_TEXT_VIEW(textview), FALSE ); gtk_container_add( GTK_CONTAINER(scrolledwindow), textview ); gtk_widget_show_all(scrolledwindow); + /* Set the window's font */ + gtk_widget_modify_font(textview, glk_data->default_font_desc); + win->widget = textview; win->frame = scrolledwindow; - text_window_get_char_size( textview, &(win->unit_width), &(win->unit_height) ); + + /* Determine the size of a "0" character in pixels */ + PangoLayout *zero = gtk_widget_create_pango_layout(textview, "0"); + pango_layout_set_font_description(zero, glk_data->default_font_desc); + pango_layout_get_pixel_size(zero, &(win->unit_width), &(win->unit_height)); + g_object_unref(zero); /* Set the other parameters */ win->window_stream = window_stream_new(win); @@ -452,7 +453,7 @@ glk_window_open(winid_t split, glui32 method, glui32 size, glui32 wintype, default: gdk_threads_leave(); - g_warning("%s: unsupported window type", __func__); + ILLEGAL_PARAM("Unknown window type: %u", wintype); g_free(win); g_node_destroy(glk_data->root_window); glk_data->root_window = NULL; @@ -464,14 +465,18 @@ glk_window_open(winid_t split, glui32 method, glui32 size, glui32 wintype, /* When splitting, construct a new parent window * copying most characteristics from the window that is being split */ winid_t pair = g_new0(struct glk_window_struct, 1); + pair->magic = MAGIC_WINDOW; pair->rock = 0; pair->type = wintype_Pair; pair->window_node = g_node_new(pair); - pair->unit_width = split->unit_width; - pair->unit_height = split->unit_height; pair->window_stream = NULL; pair->echo_stream = NULL; + /* The pair window must know about its children's split method */ + pair->key_window = win; + pair->split_method = method; + pair->constraint_size = size; + /* Insert the new window into the window tree */ if(split->window_node->parent == NULL) { @@ -480,58 +485,30 @@ glk_window_open(winid_t split, glui32 method, glui32 size, glui32 wintype, g_node_append(split->window_node->parent, pair->window_node); g_node_unlink(split->window_node); } - - /* Keep track of the parent widget of the window that is being split */ - GtkWidget* old_parent = gtk_widget_get_parent(split->frame); - gtk_widget_ref(split->frame); - gtk_widget_unparent(split->frame); - /* Place the windows in the correct order */ switch(method & winmethod_DirMask) { case winmethod_Left: - pair->widget = gtk_hbox_new(FALSE, 0); - gtk_box_pack_end(GTK_BOX(pair->widget), split->frame, TRUE, TRUE, 0); - gtk_box_pack_end(GTK_BOX(pair->widget), win->frame, TRUE, TRUE, 0); - g_node_append(pair->window_node, split->window_node); - g_node_append(pair->window_node, win->window_node); - break; - case winmethod_Right: - pair->widget = gtk_hbox_new(FALSE, 0); - gtk_box_pack_end(GTK_BOX(pair->widget), win->frame, TRUE, TRUE, 0); - gtk_box_pack_end(GTK_BOX(pair->widget), split->frame, TRUE, TRUE, 0); - g_node_append(pair->window_node, win->window_node); - g_node_append(pair->window_node, split->window_node); - break; case winmethod_Above: - pair->widget = gtk_vbox_new(FALSE, 0); - gtk_box_pack_end(GTK_BOX(pair->widget), split->frame, TRUE, TRUE, 0); - gtk_box_pack_end(GTK_BOX(pair->widget), win->frame, TRUE, TRUE, 0); - g_node_append(pair->window_node, split->window_node); g_node_append(pair->window_node, win->window_node); + g_node_append(pair->window_node, split->window_node); break; + case winmethod_Right: case winmethod_Below: - pair->widget = gtk_vbox_new(FALSE, 0); - gtk_box_pack_end(GTK_BOX(pair->widget), win->frame, TRUE, TRUE, 0); - gtk_box_pack_end(GTK_BOX(pair->widget), split->frame, TRUE, TRUE, 0); - g_node_append(pair->window_node, win->window_node); g_node_append(pair->window_node, split->window_node); + g_node_append(pair->window_node, win->window_node); break; } - gtk_widget_unref(split->frame); - - /* TODO: set the new size of the windows */ - pair->frame = pair->widget; - gtk_widget_set_parent(pair->widget, old_parent); - gtk_widget_show(pair->widget); } else { /* Set the window as root window */ glk_data->root_window = win->window_node; - gtk_widget_set_parent(win->frame, GTK_WIDGET(glk_data->self)); - gtk_widget_queue_resize(GTK_WIDGET(glk_data->self)); } + /* Set the window as a child of the Glk widget */ + gtk_widget_set_parent(win->frame, GTK_WIDGET(glk_data->self)); + gtk_widget_queue_resize(GTK_WIDGET(glk_data->self)); + /* For text grid windows, wait until GTK draws the window (see note in glk_window_get_size() ), calculate the size and fill the buffer with blanks. */ if(wintype == wintype_TextGrid) { @@ -556,9 +533,6 @@ glk_window_open(winid_t split, glui32 method, glui32 size, glui32 wintype, gdk_threads_leave(); glk_window_clear(win); gdk_threads_enter(); - - /* Apparently this only works after the window has been realized */ - gtk_text_view_set_overwrite( GTK_TEXT_VIEW(win->widget), TRUE ); } gdk_threads_leave(); @@ -613,68 +587,79 @@ glk_window_open(winid_t split, glui32 method, glui32 size, glui32 wintype, void glk_window_close(winid_t win, stream_result_t *result) { - GNode* parent_node; - - g_return_if_fail(win != NULL); - - gdk_threads_enter(); + VALID_WINDOW(win, return); + /* First close the window stream before trashing the window tree */ + stream_close_common(win->window_stream, result); + switch(win->type) { case wintype_Blank: - gtk_widget_destroy(win->widget); + gdk_threads_enter(); + gtk_widget_unparent(win->widget); + gdk_threads_leave(); break; case wintype_TextGrid: case wintype_TextBuffer: - gtk_widget_destroy(win->frame); + gdk_threads_enter(); + gtk_widget_unparent(win->frame); + gdk_threads_leave(); /* TODO: Cancel all input requests */ break; case wintype_Pair: { - GNode* left_child = g_node_first_child(win->window_node); - GNode* right_child = g_node_last_child(win->window_node); - - glk_window_close((winid_t) left_child->data, result); - glk_window_close((winid_t) right_child->data, result); - - gtk_widget_destroy(win->widget); + GNode *left = win->window_node->children; + GNode *right = win->window_node->children->next; + glk_window_close(left->data, NULL); + glk_window_close(right->data, NULL); } break; default: - g_warning("%s: unsupported window type", __func__); - gdk_threads_leave(); + ILLEGAL_PARAM("Unknown window type: %u", win->type); return; } - stream_close_common(win->window_stream, result); - - /* Parent window changes from a split window into the sibling window */ - if( (parent_node = win->window_node->parent) != NULL ) + /* Parent window changes from a split window into the sibling window */ + GNode *pair_node = win->window_node->parent; + g_node_destroy(win->window_node); + /* If win was not the root window, or was not unhooked from the tree: */ + if(pair_node != NULL) { - winid_t pair = (winid_t) parent_node->data; - if(parent_node->parent == NULL) + gboolean new_child_on_left = ( pair_node == g_node_first_sibling(pair_node) ); + GNode *sibling_node = pair_node->children; /* only one child left */ + GNode *new_parent_node = pair_node->parent; + g_node_unlink(pair_node); + g_node_unlink(sibling_node); + /* pair_node and sibling_node should now be totally unconnected to the tree */ + + if(new_parent_node == NULL) { - if(parent_node->next) - glk_data->root_window = parent_node->next; - else if(parent_node->prev) - glk_data->root_window = parent_node->prev; - } else { - if(parent_node->next) - g_node_append(parent_node->parent, parent_node->next); - else if(parent_node->prev) - g_node_append(parent_node->parent, parent_node->prev); + glk_data->root_window = sibling_node; + } + else + { + if(new_child_on_left) + g_node_prepend(new_parent_node, sibling_node); + else + g_node_append(new_parent_node, sibling_node); } - g_node_unlink(parent_node); + winid_t pair = (winid_t) pair_node->data; + g_node_destroy(pair_node); + + pair->magic = MAGIC_FREE; g_free(pair); } - g_node_destroy(win->window_node); + win->magic = MAGIC_FREE; g_free(win); + /* Schedule a redraw */ + gdk_threads_enter(); + gtk_widget_queue_resize( GTK_WIDGET(glk_data->self) ); gdk_threads_leave(); } @@ -718,7 +703,7 @@ glk_window_close(winid_t win, stream_result_t *result) void glk_window_clear(winid_t win) { - g_return_if_fail(win != NULL); + VALID_WINDOW(win, return); g_return_if_fail(win->input_request_type != INPUT_REQUEST_LINE && win->input_request_type != INPUT_REQUEST_LINE_UNICODE); switch(win->type) @@ -771,7 +756,7 @@ glk_window_clear(winid_t win) break; default: - g_warning("glk_window_clear: unsupported window type"); + ILLEGAL_PARAM("Unknown window type: %d", win->type); } } @@ -785,6 +770,7 @@ glk_window_clear(winid_t win) void glk_set_window(winid_t win) { + VALID_WINDOW_OR_NULL(win, return); glk_stream_set_current( glk_window_get_stream(win) ); } @@ -805,7 +791,7 @@ glk_set_window(winid_t win) */ strid_t glk_window_get_stream(winid_t win) { - g_return_val_if_fail(win != NULL, NULL); + VALID_WINDOW(win, return NULL); return win->window_stream; } @@ -826,7 +812,8 @@ strid_t glk_window_get_stream(winid_t win) void glk_window_set_echo_stream(winid_t win, strid_t str) { - g_return_if_fail(win != NULL); + VALID_WINDOW(win, return); + VALID_STREAM_OR_NULL(str, return); /* Test for an infinite loop */ strid_t next = str; @@ -834,7 +821,7 @@ glk_window_set_echo_stream(winid_t win, strid_t str) { if(next == win->window_stream) { - g_warning("%s: Infinite loop detected", __func__); + ILLEGAL("Infinite loop detected"); win->echo_stream = NULL; return; } @@ -855,7 +842,7 @@ glk_window_set_echo_stream(winid_t win, strid_t str) strid_t glk_window_get_echo_stream(winid_t win) { - g_return_val_if_fail(win != NULL, NULL); + VALID_WINDOW(win, return NULL); return win->echo_stream; } @@ -875,11 +862,12 @@ glk_window_get_echo_stream(winid_t win) void glk_window_get_size(winid_t win, glui32 *widthptr, glui32 *heightptr) { - g_return_if_fail(win != NULL); + VALID_WINDOW(win, return); switch(win->type) { case wintype_Blank: + case wintype_Pair: if(widthptr != NULL) *widthptr = 0; if(heightptr != NULL) @@ -923,7 +911,7 @@ glk_window_get_size(winid_t win, glui32 *widthptr, glui32 *heightptr) break; default: - g_warning("glk_window_get_size: Unsupported window type"); + ILLEGAL_PARAM("Unknown window type: %u", win->type); } } @@ -960,7 +948,7 @@ glk_window_get_size(winid_t win, glui32 *widthptr, glui32 *heightptr) void glk_window_move_cursor(winid_t win, glui32 xpos, glui32 ypos) { - g_return_if_fail(win != NULL); + VALID_WINDOW(win, return); g_return_if_fail(win->type == wintype_TextGrid); /* Calculate actual position if cursor is moved past the right edge */