X-Git-Url: https://git.stderr.nl/gitweb?a=blobdiff_plain;f=src%2Fwindow.c;h=aa894c6a9f84b7d511170872069b8ef353d824a1;hb=4c3e3df47c07d1c4d4a8fe03c315fb5a55ef08c9;hp=45054e0765fba3d537b4cb6f7643ea0a5829e341;hpb=27bed8aa9bf21a0c42defacee957ab513807c726;p=rodin%2Fchimara.git diff --git a/src/window.c b/src/window.c index 45054e0..aa894c6 100644 --- a/src/window.c +++ b/src/window.c @@ -237,8 +237,17 @@ glk_window_get_root() * What happens when there is a conflict? The rules are simple. Size control * always flows down the tree, and the player is at the top. Let's bring out an * example: - * Screen shot 5 - * + * + * + * + * + * O + * / \ + * O B + * / \ + * A C + * + * * * First we split A into A and B, with a 50% proportional split. Then we split * A into A and C, with C above, C being a text grid window, and C gets a fixed @@ -246,8 +255,8 @@ glk_window_get_root() * of the 50% it had before. * * Now the player stretches the window vertically. - * Screen shot 6 - * + * + * * * The library figures: the topmost split, the original A/B split, is 50-50. So * B gets half the screen space, and the pair window next to it (the lower @@ -255,8 +264,18 @@ glk_window_get_root() * O. C gets two rows; A gets the rest. All done. * * Then the user maliciously starts squeezing the window down, in stages: - * - * Screen shot 7 + * + * + * + * + * + * + * + * + * + * + * + * * * The logic remains the same. B always gets half the space. At stage 3, * there's no room left for A, so it winds up with zero height. Nothing @@ -290,8 +309,29 @@ glk_window_get_root() * is stored by a window's parent, not the window itself; and a constraint * consists of a pointer to a key window plus a size value. * - * Screen shot 8 - * + * + * + * + * + * A + * + * + * + * + * O1 + * / \ + * A B + * + * + * + * + * O1 + * / \ + * O2 B + * / \ + * A C + * + * * After the first split, the new pair window (O1, which covers the whole * screen) knows that its first child (A) is above the second, and gets 50% of * its own area. (A is the key window for this split, but a proportional split @@ -306,8 +346,19 @@ glk_window_get_root() * If we split C, now, the resulting pair will still be two C-font rows high * — that is, tall enough for two lines of whatever font C displays. For * the sake of example, we'll do this vertically. - * Screen shot 9 - * + * + * + * + * + * O1 + * / \ + * O2 B + * / \ + * A O3 + * / \ + * C D + * + * * * O3 now knows that its children have a 50-50 left-right split. O2 is still * committed to giving its upper child, O3, two C-font rows. Again, this is @@ -366,7 +417,7 @@ glk_window_open(winid_t split, glui32 method, glui32 size, glui32 wintype, { GtkWidget *textview = gtk_text_view_new(); - gtk_text_view_set_wrap_mode( GTK_TEXT_VIEW(textview), GTK_WRAP_CHAR ); + gtk_text_view_set_wrap_mode( GTK_TEXT_VIEW(textview), GTK_WRAP_NONE ); gtk_text_view_set_editable( GTK_TEXT_VIEW(textview), FALSE ); gtk_widget_show(textview); @@ -458,6 +509,7 @@ glk_window_open(winid_t split, glui32 method, glui32 size, glui32 wintype, /* Set the minimum size to "as small as possible" so it doesn't depend on the size of the window contents */ gtk_widget_set_size_request(win->widget, 0, 0); + gtk_widget_set_size_request(win->frame, 0, 0); if(split) { @@ -514,12 +566,15 @@ glk_window_open(winid_t split, glui32 method, glui32 size, glui32 wintype, gdk_threads_leave(); - /* 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. */ + /* For blank or pair windows, this is almost a no-op. For text grid and + text buffer windows, this will wait for GTK to draw the window. Otherwise, + opening a window and getting its size immediately will give you the wrong + size. */ + glk_window_get_size(win, NULL, NULL); + + /* For text grid windows, fill the buffer with blanks. */ if(wintype == wintype_TextGrid) { - /* Force the window to be drawn and cache its size */ - glk_window_get_size(win, NULL, NULL); - /* Create the cursor position mark */ gdk_threads_enter(); GtkTextIter begin; @@ -535,6 +590,17 @@ glk_window_open(winid_t split, glui32 method, glui32 size, glui32 wintype, return win; } +/* Internal function: if node's key window is closing_win or one of its + children, set node's key window to NULL. */ +static gboolean +remove_key_windows(GNode *node, winid_t closing_win) +{ + winid_t win = (winid_t)node->data; + if(win->key_window && (win->key_window == closing_win || g_node_is_ancestor(closing_win->window_node, win->key_window->window_node))) + win->key_window = NULL; + return FALSE; /* Don't stop the traversal */ +} + /* Internal function: destroy this window's GTK widgets, window streams, and those of all its children */ static void @@ -596,8 +662,17 @@ free_winids_below(winid_t win) * When you close a window (and it is not the root window), the other window * in its pair takes over all the freed-up area. Let's close D, in the current * example: - * Screen shot 10 - * + * + * + * + * + * O1 + * / \ + * O2 B + * / \ + * A C + * + * * * Notice what has happened. D is gone. O3 is gone, and its 50-50 left-right * split has gone with it. The other size constraints are unchanged; O2 is @@ -607,8 +682,17 @@ free_winids_below(winid_t win) * to the way it was before we created D. * * But what if we had closed C instead of D? We would have gotten this: - * Screen shot 11 - * + * + * + * + * + * O1 + * / \ + * O2 B + * / \ + * A D + * + * * * Again, O3 is gone. But D has collapsed to zero height. This is because its * height is controlled by O2, and O2's key window was C, and C is now gone. O2 @@ -629,7 +713,11 @@ glk_window_close(winid_t win, stream_result_t *result) { VALID_WINDOW(win, return); - /* First close all the window streams and destroy the widgets of this window + /* If any pair windows have this window or its children as a key window, + set their key window to NULL */ + g_node_traverse(glk_data->root_window, G_IN_ORDER, G_TRAVERSE_NON_LEAVES, -1, (GNodeTraverseFunc)remove_key_windows, win); + + /* Close all the window streams and destroy the widgets of this window and below, before trashing the window tree */ destroy_windows_below(win, result);