X-Git-Url: https://git.stderr.nl/gitweb?a=blobdiff_plain;f=libchimara%2Fwindow.c;h=e302a1eedc06201a79dbf87f40815499db9e169f;hb=0cc686dee7c3d71457b409a097fbc7435709429a;hp=6272c67a8cad6f10f841b362ba73d74e8c0d6194;hpb=bf5bc4b0d129685482eefea499f39f874744e2fd;p=projects%2Fchimara%2Fchimara.git diff --git a/libchimara/window.c b/libchimara/window.c index 6272c67..e302a1e 100644 --- a/libchimara/window.c +++ b/libchimara/window.c @@ -33,6 +33,10 @@ window_new_common(glui32 rock) win->line_input_buffer = NULL; win->line_input_buffer_unicode = NULL; win->history = NULL; + win->echo_line_input = TRUE; + win->echo_current_line_input = TRUE; + win->extra_line_terminators = NULL; + win->current_extra_line_terminators = NULL; /* Initialise the buffer */ win->buffer = g_string_sized_new(1024); @@ -63,13 +67,15 @@ window_close_common(winid_t win, gboolean destroy_node) g_list_foreach(win->history, (GFunc)g_free, NULL); g_list_free(win->history); + g_slist_free(win->extra_line_terminators); + g_slist_free(win->current_extra_line_terminators); 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); + if(win->backing_store) + cairo_surface_destroy(win->backing_store); g_free(win); } @@ -196,8 +202,8 @@ glk_window_get_sibling(winid_t win) if(G_NODE_IS_ROOT(win->window_node)) return NULL; if(win->window_node->next) - return (winid_t)win->window_node->next; - return (winid_t)win->window_node->prev; + return (winid_t)win->window_node->next->data; + return (winid_t)win->window_node->prev->data; } /** @@ -223,7 +229,8 @@ glk_window_get_root() * @method: Position of the new window and method of size computation. One of * %winmethod_Above, %winmethod_Below, %winmethod_Left, or %winmethod_Right * OR'ed with %winmethod_Fixed or %winmethod_Proportional. If @wintype is - * %wintype_Blank, then %winmethod_Fixed is not allowed. + * %wintype_Blank, then %winmethod_Fixed is not allowed. May also be OR'ed with + * %winmethod_Border or %winmethod_NoBorder. * @size: Size of the new window, in percentage points if @method is * %winmethod_Proportional, otherwise in characters if @wintype is * %wintype_TextBuffer or %wintype_TextGrid, or pixels if @wintype is @@ -239,9 +246,13 @@ glk_window_get_root() * * If any windows exist, new windows must be created by splitting existing * ones. @split is the window you want to split; this must - * not be zero. @method is a mask of constants to specify the - * direction and the split method (see below). @size is the size of the split. - * @wintype is the type of window you're creating, and @rock is the rock. + * not be zero. @method specifies the direction and the split method + * (see below). @size is the size of the split. @wintype is the type of window + * you're creating, and @rock is the rock. + * + * The method argument must be the logical-or of a direction constant + * (%winmethod_Above, %winmethod_Below, %winmethod_Left, %winmethod_Right) and a + * split-method constant (%winmethod_Fixed, %winmethod_Proportional). * * Remember that it is possible that the library will be unable to create a new * window, in which case glk_window_open() will return %NULL. @@ -405,16 +416,16 @@ glk_window_get_root() * 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 - * doesn't care about key windows.) + * The initial window is A. After the first split, the new pair window (O1, + * which covers the whole screen) knows that its new child (B) is below A, and + * gets 50% of its own area. (B is the key window for this split, but a + * proportional split doesn't care about key windows.) * - * After the second split, all this remains true; O1 knows that its first child - * gets 50% of its space, and A is O1's key window. But now O1's first child is - * O2 instead of A. The newer pair window (O2) knows that its first child (C) - * is above the second, and gets a fixed size of two rows. (As measured in C's - * font, because C is O2's key window.) + * After the second split, all this remains true; O1 knows + * that its first child gets 50% of its space, and B is O1's key window. But + * now O1's first child is O2 instead of A. The newer pair window (O2) knows + * that its first child (C) is above the second, and gets a fixed size of two + * rows. (As measured in C's font, because C is O2's key window.) * * 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 @@ -451,8 +462,9 @@ glk_window_open(winid_t split, glui32 method, glui32 size, glui32 wintype, glui32 rock) { VALID_WINDOW_OR_NULL(split, return NULL); - g_return_val_if_fail(method == (method & (winmethod_DirMask | winmethod_DivisionMask)), NULL); - g_return_val_if_fail(!(((method & winmethod_DivisionMask) == winmethod_Proportional) && size > 100), NULL); + g_return_val_if_fail(!(((method & winmethod_DivisionMask) == winmethod_Proportional) && size > 100), NULL); + if(method != (method & (winmethod_DirMask | winmethod_DivisionMask | winmethod_BorderMask))) + WARNING("Unrecognized bits in method constant"); ChimaraGlkPrivate *glk_data = g_private_get(glk_data_key); @@ -521,12 +533,20 @@ glk_window_open(winid_t split, glui32 method, glui32 size, glui32 wintype, case wintype_TextBuffer: { + GtkWidget *overlay = gtk_overlay_new(); GtkWidget *scrolledwindow = gtk_scrolled_window_new(NULL, NULL); GtkWidget *textview = gtk_text_view_new(); + GtkWidget *pager = gtk_button_new_with_label("More"); + GtkWidget *image = gtk_image_new_from_stock(GTK_STOCK_GO_DOWN, GTK_ICON_SIZE_BUTTON); 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_button_set_image( GTK_BUTTON(pager), image ); + gtk_widget_set_halign(pager, GTK_ALIGN_END); + gtk_widget_set_valign(pager, GTK_ALIGN_END); + gtk_widget_set_no_show_all(pager, TRUE); + 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_text_view_set_pixels_inside_wrap( GTK_TEXT_VIEW(textview), 3 ); @@ -534,16 +554,19 @@ glk_window_open(winid_t split, glui32 method, glui32 size, glui32 wintype, gtk_text_view_set_right_margin( GTK_TEXT_VIEW(textview), 20 ); gtk_container_add( GTK_CONTAINER(scrolledwindow), textview ); - gtk_widget_show_all(scrolledwindow); + gtk_container_add( GTK_CONTAINER(overlay), scrolledwindow ); + gtk_overlay_add_overlay( GTK_OVERLAY(overlay), pager ); + gtk_widget_show_all(overlay); win->widget = textview; - win->frame = scrolledwindow; - + win->scrolledwindow = scrolledwindow; + win->pager = pager; + win->frame = overlay; + /* Create the styles available to the window stream */ style_init_textbuffer(textbuffer); - style_init_more_prompt(win); gtk_widget_modify_font( textview, get_current_font(wintype) ); - + /* Determine the size of a "0" character in pixels */ PangoLayout *zero = gtk_widget_create_pango_layout(textview, "0"); pango_layout_set_font_description( zero, get_current_font(wintype) ); @@ -553,9 +576,7 @@ glk_window_open(winid_t split, glui32 method, glui32 size, glui32 wintype, /* Connect signal handlers */ /* Pager */ - g_signal_connect_after( textview, "size-request", G_CALLBACK(pager_after_size_request), win ); - win->pager_expose_handler = g_signal_connect_after( textview, "expose-event", G_CALLBACK(pager_on_expose), win ); - g_signal_handler_block(textview, win->pager_expose_handler); + g_signal_connect_after( textview, "size-allocate", G_CALLBACK(pager_after_size_allocate), win ); win->pager_keypress_handler = g_signal_connect( textview, "key-press-event", G_CALLBACK(pager_on_key_press_event), win ); g_signal_handler_block(textview, win->pager_keypress_handler); GtkAdjustment *adj = gtk_scrolled_window_get_vadjustment(GTK_SCROLLED_WINDOW(scrolledwindow)); @@ -591,7 +612,7 @@ glk_window_open(winid_t split, glui32 method, glui32 size, glui32 wintype, case wintype_Graphics: { - GtkWidget *image = gtk_image_new_from_pixmap(NULL, NULL); + GtkWidget *image = gtk_drawing_area_new(); gtk_widget_show(image); win->unit_width = 1; @@ -599,13 +620,15 @@ glk_window_open(winid_t split, glui32 method, glui32 size, glui32 wintype, win->widget = image; win->frame = image; win->background_color = 0x00FFFFFF; - + win->backing_store = NULL; + /* Connect signal handlers */ win->button_press_event_handler = g_signal_connect(image, "button-press-event", G_CALLBACK(on_window_button_press), win); g_signal_handler_block(image, win->button_press_event_handler); win->shutdown_keypress_handler = g_signal_connect(image, "key-press-event", G_CALLBACK(on_shutdown_key_press_event), win); g_signal_handler_block(image, win->shutdown_keypress_handler); - win->size_allocate_handler = g_signal_connect(image, "size-allocate", G_CALLBACK(on_graphics_size_allocate), win); + g_signal_connect(image, "configure-event", G_CALLBACK(on_graphics_configure), win); + g_signal_connect(image, "draw", G_CALLBACK(on_graphics_draw), win); } break; @@ -890,8 +913,9 @@ glk_window_close(winid_t win, stream_result_t *result) * * Text grid * - * This will clear the window, filling all positions with blanks. The window - * cursor is moved to the top left corner (position 0,0). + * This will clear the window, filling all positions with blanks (in the + * normal style). The window cursor is moved to the top left corner (position + * 0,0). * * * @@ -995,13 +1019,19 @@ glk_window_clear(winid_t win) case wintype_Graphics: { + GtkAllocation allocation; + /* Wait for the window's size to be updated */ 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); - glk_window_erase_rect(win, 0, 0, win->widget->allocation.width, win->widget->allocation.height); + gdk_threads_enter(); + gtk_widget_get_allocation(win->widget, &allocation); + gdk_threads_leave(); + + glk_window_erase_rect(win, 0, 0, allocation.width, allocation.height); } break; @@ -1014,15 +1044,12 @@ glk_window_clear(winid_t win) * glk_set_window: * @win: A window, or %NULL. * - * Sets the current stream to @win's window stream. It is exactly equivalent to - * |[ glk_stream_set_current(glk_window_get_stream(win)) ]| + * Sets the current stream to @win's window stream. If @win is %NULL, it is + * equivalent to + * |[ glk_stream_set_current(NULL); ]| + * If @win is not %NULL, it is equivalent to + * |[ glk_stream_set_current(glk_window_get_stream(win)); ]| * See Streams. - * - * Chimara - * - * Although this is not mentioned in the specification, @win may also be - * %NULL, in which case the current stream is also set to %NULL. - * */ void glk_set_window(winid_t win) @@ -1124,6 +1151,7 @@ glk_window_get_size(winid_t win, glui32 *widthptr, glui32 *heightptr) { VALID_WINDOW(win, return); + GtkAllocation allocation; ChimaraGlkPrivate *glk_data = g_private_get(glk_data_key); switch(win->type) @@ -1144,9 +1172,10 @@ glk_window_get_size(winid_t win, glui32 *widthptr, glui32 *heightptr) g_mutex_unlock(glk_data->arrange_lock); gdk_threads_enter(); + gtk_widget_get_allocation(win->widget, &allocation); /* Cache the width and height */ - win->width = (glui32)(win->widget->allocation.width / win->unit_width); - win->height = (glui32)(win->widget->allocation.height / win->unit_height); + win->width = (glui32)(allocation.width / win->unit_width); + win->height = (glui32)(allocation.height / win->unit_height); gdk_threads_leave(); if(widthptr != NULL) @@ -1163,10 +1192,11 @@ glk_window_get_size(winid_t win, glui32 *widthptr, glui32 *heightptr) g_mutex_unlock(glk_data->arrange_lock); gdk_threads_enter(); + gtk_widget_get_allocation(win->widget, &allocation); if(widthptr != NULL) - *widthptr = (glui32)(win->widget->allocation.width / win->unit_width); + *widthptr = (glui32)(allocation.width / win->unit_width); if(heightptr != NULL) - *heightptr = (glui32)(win->widget->allocation.height / win->unit_height); + *heightptr = (glui32)(allocation.height / win->unit_height); gdk_threads_leave(); break; @@ -1178,10 +1208,11 @@ glk_window_get_size(winid_t win, glui32 *widthptr, glui32 *heightptr) g_mutex_unlock(glk_data->arrange_lock); gdk_threads_enter(); + gtk_widget_get_allocation(win->widget, &allocation); if(widthptr != NULL) - *widthptr = (glui32)(win->widget->allocation.width); + *widthptr = (glui32)(allocation.width); if(heightptr != NULL) - *heightptr = (glui32)(win->widget->allocation.height); + *heightptr = (glui32)(allocation.height); gdk_threads_leave(); break; @@ -1247,9 +1278,9 @@ glk_window_get_size(winid_t win, glui32 *widthptr, glui32 *heightptr) * Whatever constraint you set, glk_window_get_size() will tell you the actual * window size you got. * - * Note that you can resize windows, but you can't flip or rotate them. You - * can't move A above D, or change O2 to a vertical split where A is left or - * right of D. + * Note that you can resize windows, and alter the Border/NoBorder flag. But you + * can't flip or rotate them. You can't move A above D, or change O2 to a + * vertical split where A is left or right of D. * * To get this effect you could close one of the windows, and re-split the * other one with glk_window_open().