Mercurial > hg > xemacs-beta
diff src/redisplay.c @ 398:74fd4e045ea6 r21-2-29
Import from CVS: tag r21-2-29
author | cvs |
---|---|
date | Mon, 13 Aug 2007 11:13:30 +0200 |
parents | bbff43aa5eb7 |
children | a86b2b5e0111 |
line wrap: on
line diff
--- a/src/redisplay.c Mon Aug 13 11:12:06 2007 +0200 +++ b/src/redisplay.c Mon Aug 13 11:13:30 2007 +0200 @@ -51,6 +51,7 @@ #include "faces.h" #include "frame.h" #include "glyphs.h" +#include "gutter.h" #include "insdel.h" #include "menubar.h" #include "objects.h" @@ -107,6 +108,9 @@ /* This information is normally filled in by the create_*_block routines and is used by the add_*_rune routines. */ Lisp_Object window; + /* if we are working with strings rather than buffers we need a + handle to the string */ + Lisp_Object string; struct device *d; struct display_block *db; struct display_line *dl; @@ -150,6 +154,10 @@ (those off the left side of the screen) need to be skipped before anything is displayed. */ Bytind bi_start_col_enabled; + int start_col_xoffset; /* Number of pixels that still need to + be skipped. This is used for + horizontal scrolling of glyphs, where we want + to be able to scroll over part of the glyph. */ int hscroll_glyph_width_adjust; /* how much the width of the hscroll glyph differs from space_width (w). @@ -238,25 +246,19 @@ } prop_block_dynarr; -static void generate_formatted_string_db (Lisp_Object format_str, - Lisp_Object result_str, - struct window *w, - struct display_line *dl, - struct display_block *db, - face_index findex, int min_pixpos, - int max_pixpos, int type); static Charcount generate_fstring_runes (struct window *w, pos_data *data, Charcount pos, Charcount min_pos, Charcount max_pos, Lisp_Object elt, int depth, int max_pixsize, - face_index findex, int type); + face_index findex, int type, + Charcount *offset, + Lisp_Object cur_ext); static prop_block_dynarr *add_glyph_rune (pos_data *data, struct glyph_block *gb, int pos_type, int allow_cursor, struct glyph_cachel *cachel); static Bytind create_text_block (struct window *w, struct display_line *dl, - Bytind bi_start_pos, int start_col, - prop_block_dynarr **prop, + Bytind bi_start_pos, prop_block_dynarr **prop, int type); static int create_overlay_glyph_block (struct window *w, struct display_line *dl); @@ -293,10 +295,6 @@ isn't any reason we need more than a single set. */ display_line_dynarr *cmotion_display_lines; -/* Used by generate_formatted_string. Global because they get used so - much that the dynamic allocation time adds up. */ -Emchar_dynarr *formatted_string_emchar_dynarr; -struct display_line formatted_string_display_line; /* We store the extents that we need to generate in a Dynarr and then frob them all on at the end of generating the string. We do it this way rather than adding them as we generate the string because @@ -304,9 +302,9 @@ (to avoid having to resize the string multiple times), and we don't want to go around adding extents to a string when the extents might stretch off the end of the string. */ -EXTENT_dynarr *formatted_string_extent_dynarr; -Bytecount_dynarr *formatted_string_extent_start_dynarr; -Bytecount_dynarr *formatted_string_extent_end_dynarr; +static EXTENT_dynarr *formatted_string_extent_dynarr; +static Bytecount_dynarr *formatted_string_extent_start_dynarr; +static Bytecount_dynarr *formatted_string_extent_end_dynarr; /* #### probably temporary */ @@ -331,7 +329,7 @@ int horizontal_clip; /* Set if currently inside update_line_start_cache. */ -int updating_line_start_cache; +static int updating_line_start_cache; /* Nonzero means reading single-character input with prompt so put cursor on minibuffer after the prompt. */ @@ -371,6 +369,11 @@ int subwindows_changed; int subwindows_changed_set; +/* non-zero if any displayed subwindow is in need of updating + somewhere. */ +int subwindows_state_changed; +int subwindows_state_changed_set; + /* This variable is 1 if the icon has to be updated. It is set to 1 when `frame-icon-glyph' changes. */ int icon_changed; @@ -401,6 +404,10 @@ int toolbar_changed; int toolbar_changed_set; +/* non-nil if any gutter has changed */ +int gutter_changed; +int gutter_changed_set; + /* non-nil if any window has changed since the last time redisplay completed */ int windows_changed; @@ -412,7 +419,6 @@ Lisp_Object Vbar_cursor; Lisp_Object Qbar_cursor; - int visible_bell; /* If true and the terminal will support it then the frame will flash instead of beeping when an error occurs */ @@ -442,7 +448,7 @@ Lisp_Object Voverlay_arrow_string; Lisp_Object Vwindow_size_change_functions; -Lisp_Object Qwindow_scroll_functions, Vwindow_scroll_functions; +Lisp_Object Vwindow_scroll_functions; Lisp_Object Qredisplay_end_trigger_functions, Vredisplay_end_trigger_functions; #define INHIBIT_REDISPLAY_HOOKS /* #### Until we've thought about @@ -454,7 +460,7 @@ Lisp_Object Qpre_redisplay_hook, Qpost_redisplay_hook; #endif /* INHIBIT_REDISPLAY_HOOKS */ -int last_display_warning_tick, display_warning_tick; +static int last_display_warning_tick, display_warning_tick; Lisp_Object Qdisplay_warning_buffer; int inhibit_warning_display; @@ -464,6 +470,10 @@ Lisp_Object Vtext_cursor_visible_p; int column_number_start_at_one; + +#define WINDOW_SCROLLED(w) \ +(w->hscroll > 0 || w->left_xoffset) + /***************************************************************************/ /* */ @@ -633,8 +643,8 @@ int pix_tab_width = tab_pix_width (w); /* Adjust n_pos for any hscrolling which has happened. */ - if (w->hscroll > 1) - n_pos -= space_width (w) * (w->hscroll - 1); + if (WINDOW_SCROLLED (w)) + n_pos -= space_width (w) * (w->hscroll - 1) + w->left_xoffset; while (n_pos <= start_pixpos) n_pos += pix_tab_width; @@ -686,8 +696,7 @@ static Bufpos generate_display_line (struct window *w, struct display_line *dl, int bounds, - Bufpos start_pos, int start_col, - prop_block_dynarr **prop, + Bufpos start_pos, prop_block_dynarr **prop, int type) { Bufpos ret_bufpos; @@ -720,7 +729,7 @@ /* #### urk urk urk!!! Chuck fix this shit! */ Bytind hacked_up_bytind = create_text_block (w, dl, bufpos_to_bytind (b, start_pos), - start_col, prop, type); + prop, type); if (hacked_up_bytind > BI_BUF_ZV (b)) ret_bufpos = BUF_ZV (b) + 1; else @@ -850,7 +859,7 @@ Lisp_Object font_instance = ensure_face_cachel_contains_charset (cachel, data->window, charset); - struct Lisp_Font_Instance *fi; + Lisp_Font_Instance *fi; if (EQ (font_instance, Vthe_null_font_instance)) { @@ -902,9 +911,15 @@ crb->xpos = data->pixpos; crb->width = width; if (data->bi_bufpos) - crb->bufpos = - bytind_to_bufpos (XBUFFER (WINDOW_BUFFER (XWINDOW (data->window))), - data->bi_bufpos); + { + if (NILP (data->string)) + crb->bufpos = + bytind_to_bufpos (XBUFFER (WINDOW_BUFFER (XWINDOW (data->window))), + data->bi_bufpos); + else + crb->bufpos = + bytecount_to_charcount (XSTRING_DATA (data->string), data->bi_bufpos); + } else if (data->is_modeline) crb->bufpos = data->modeline_charpos; else @@ -1326,7 +1341,7 @@ prop_block_dynarr *prop = NULL; if (VECTORP (entry)) { - struct Lisp_Vector *de = XVECTOR (entry); + Lisp_Vector *de = XVECTOR (entry); EMACS_INT len = vector_length (de); int elt; @@ -1509,6 +1524,16 @@ { struct window *w = XWINDOW (data->window); + /* If window faces changed, and glyph instance is text, then + glyph sizes might have changed too */ + invalidate_glyph_geometry_maybe (gb->glyph, w); + + /* This makes sure the glyph is in the cachels. + + #### We need to change this so that we hold onto the glyph_index + here, not the glyph itself. */ + get_glyph_cachel_index (w, gb->glyph); + /* A nil extent indicates a special glyph (ex. truncator). */ if (NILP (gb->extent) || (pos_type == BEGIN_GLYPHS && @@ -1526,12 +1551,12 @@ if (cachel) width = cachel->width; else - width = glyph_width (gb->glyph, Qnil, data->findex, data->window); + width = glyph_width (gb->glyph, data->window); if (!width) return NULL; - if (data->start_col) + if (data->start_col || data->start_col_xoffset) { prop_block_dynarr *retval; int glyph_char_width = width / space_width (w); @@ -1589,9 +1614,8 @@ } else { - ascent = glyph_ascent (gb->glyph, Qnil, data->findex, data->window); - descent = glyph_descent (gb->glyph, Qnil, data->findex, - data->window); + ascent = glyph_ascent (gb->glyph, data->window); + descent = glyph_descent (gb->glyph, data->window); } baseline = glyph_baseline (gb->glyph, data->window); @@ -1765,8 +1789,7 @@ static Bytind create_text_block (struct window *w, struct display_line *dl, - Bytind bi_start_pos, int start_col, - prop_block_dynarr **prop, + Bytind bi_start_pos, prop_block_dynarr **prop, int type) { struct frame *f = XFRAME (w->frame); @@ -1791,7 +1814,7 @@ after a ^M is invisible. */ int selective = (INTP (b->selective_display) ? XINT (b->selective_display) - : ((!NILP (b->selective_display) ? -1 : 0))); + : (!NILP (b->selective_display) ? -1 : 0)); /* The variable ctl-arrow allows the user to specify what characters can actually be displayed and which octal should be used for. @@ -1866,6 +1889,7 @@ them to this structure for ease of passing. */ data.d = d; XSETWINDOW (data.window, w); + data.string = Qnil; data.db = db; data.dl = dl; @@ -1909,6 +1933,7 @@ data.cursor_x = -1; data.start_col = w->hscroll; + data.start_col_xoffset = w->left_xoffset; data.bi_start_col_enabled = (w->hscroll ? bi_start_pos : 0); data.hscroll_glyph_width_adjust = 0; @@ -2228,6 +2253,7 @@ data.blank_width = DEVMETH (d, eol_cursor_width, ()); data.findex = DEFAULT_INDEX; data.start_col = 0; + data.start_col_xoffset = 0; data.bi_start_col_enabled = 0; add_emchar_rune (&data); @@ -2261,7 +2287,8 @@ int prop_width = 0; if (data.start_col > 1) - tab_start_pixpos -= (space_width (w) * (data.start_col - 1)); + tab_start_pixpos -= (space_width (w) * (data.start_col - 1)) + + data.start_col_xoffset; next_tab_start = next_tab_position (w, tab_start_pixpos, @@ -2468,6 +2495,7 @@ data.blank_width = DEVMETH (d, eol_cursor_width, ()); data.findex = DEFAULT_INDEX; data.start_col = 0; + data.start_col_xoffset = 0; data.bi_start_col_enabled = 0; data.max_pixpos += data.blank_width; @@ -2643,6 +2671,7 @@ data.last_charset = Qunbound; data.last_findex = DEFAULT_INDEX; data.result_str = Qnil; + data.string = Qnil; Dynarr_reset (data.db->runes); @@ -2747,8 +2776,8 @@ unsigned short ascent, descent; Lisp_Object baseline = glyph_baseline (gb->glyph, window); - ascent = glyph_ascent (gb->glyph, Qnil, gb->findex, window); - descent = glyph_descent (gb->glyph, Qnil, gb->findex, window); + ascent = glyph_ascent (gb->glyph, window); + descent = glyph_descent (gb->glyph, window); /* A pixmap that has not had a baseline explicitly set. We use the existing ascent / descent ratio of the @@ -2862,7 +2891,7 @@ { int width; - width = glyph_width (gb->glyph, Qnil, gb->findex, window); + width = glyph_width (gb->glyph, window); if (white_in_start - width >= left_in_end) { @@ -2913,7 +2942,7 @@ if (extent_begin_glyph_layout (XEXTENT (gb->extent)) == GL_INSIDE_MARGIN) { - gb->width = glyph_width (gb->glyph, Qnil, gb->findex, window); + gb->width = glyph_width (gb->glyph, window); used_in += gb->width; Dynarr_add (ib, *gb); } @@ -2982,7 +3011,7 @@ if (extent_begin_glyph_layout (XEXTENT (gb->extent)) == GL_INSIDE_MARGIN) { - int width = glyph_width (gb->glyph, Qnil, gb->findex, window); + int width = glyph_width (gb->glyph, window); if (used_out) { @@ -3024,7 +3053,7 @@ if (extent_begin_glyph_layout (XEXTENT (gb->extent)) == GL_OUTSIDE_MARGIN) { - int width = glyph_width (gb->glyph, Qnil, gb->findex, window); + int width = glyph_width (gb->glyph, window); if (out_end + width <= in_out_start) { @@ -3181,7 +3210,7 @@ if (extent_end_glyph_layout (XEXTENT (gb->extent)) == GL_WHITESPACE) { - int width = glyph_width (gb->glyph, Qnil, gb->findex, window); + int width = glyph_width (gb->glyph, window); if (white_in_end + width <= dl->bounds.right_in) { @@ -3231,7 +3260,7 @@ if (extent_end_glyph_layout (XEXTENT (gb->extent)) == GL_INSIDE_MARGIN) { - gb->width = glyph_width (gb->glyph, Qnil, gb->findex, window); + gb->width = glyph_width (gb->glyph, window); used_in += gb->width; Dynarr_add (ib, *gb); } @@ -3295,7 +3324,7 @@ if (extent_end_glyph_layout (XEXTENT (gb->extent)) == GL_INSIDE_MARGIN) { - int width = glyph_width (gb->glyph, Qnil, gb->findex, window); + int width = glyph_width (gb->glyph, window); if (used_out) { @@ -3336,7 +3365,7 @@ if (extent_end_glyph_layout (XEXTENT (gb->extent)) == GL_OUTSIDE_MARGIN) { - int width = glyph_width (gb->glyph, Qnil, gb->findex, window); + int width = glyph_width (gb->glyph, window); if (out_start - width >= in_out_end) { @@ -3452,103 +3481,8 @@ /* */ /***************************************************************************/ -/* Ensure that the given display line DL accurately represents the - modeline for the given window. */ - -static void -generate_modeline (struct window *w, struct display_line *dl, int type) -{ - struct buffer *b = XBUFFER (w->buffer); - struct frame *f = XFRAME (w->frame); - struct device *d = XDEVICE (f->device); - - /* Unlike display line and rune pointers, this one can't change underneath - our feet. */ - struct display_block *db = get_display_block_from_line (dl, TEXT); - int max_pixpos, min_pixpos, ypos_adj; - Lisp_Object font_inst; - - /* This will actually determine incorrect inside boundaries for the - modeline since it ignores the margins. However being aware of this fact - we never use those values anywhere so it doesn't matter. */ - dl->bounds = calculate_display_line_boundaries (w, 1); - - /* We are generating a modeline. */ - dl->modeline = 1; - dl->cursor_elt = -1; - - /* Reset the runes on the modeline. */ - Dynarr_reset (db->runes); - - if (!WINDOW_HAS_MODELINE_P (w)) - { - struct rune rb; - - /* If there is a horizontal scrollbar, don't add anything. */ - if (window_scrollbar_height (w)) - return; - - dl->ascent = DEVMETH (d, divider_height, ()); - dl->descent = 0; - /* The modeline is at the bottom of the gutters. */ - dl->ypos = WINDOW_BOTTOM (w); - - rb.findex = MODELINE_INDEX; - rb.xpos = dl->bounds.left_out; - rb.width = dl->bounds.right_out - dl->bounds.left_out; - rb.bufpos = 0; - rb.endpos = 0; - rb.type = RUNE_HLINE; - rb.object.hline.thickness = 1; - rb.object.hline.yoffset = 0; - rb.cursor_type = NO_CURSOR; - - if (!EQ (Qzero, w->modeline_shadow_thickness) - && FRAME_WIN_P (f)) - { - int shadow_thickness = MODELINE_SHADOW_THICKNESS (w); - - dl->ypos -= shadow_thickness; - rb.xpos += shadow_thickness; - rb.width -= 2 * shadow_thickness; - } - - Dynarr_add (db->runes, rb); - return; - } - - /* !!#### not right; needs to compute the max height of - all the charsets */ - font_inst = WINDOW_FACE_CACHEL_FONT (w, MODELINE_INDEX, Vcharset_ascii); - - dl->ascent = XFONT_INSTANCE (font_inst)->ascent; - dl->descent = XFONT_INSTANCE (font_inst)->descent; - - min_pixpos = dl->bounds.left_out; - max_pixpos = dl->bounds.right_out; - - if (!EQ (Qzero, w->modeline_shadow_thickness) && FRAME_WIN_P (f)) - { - int shadow_thickness = MODELINE_SHADOW_THICKNESS (w); - - ypos_adj = shadow_thickness; - min_pixpos += shadow_thickness; - max_pixpos -= shadow_thickness; - } - else - ypos_adj = 0; - - generate_formatted_string_db (b->modeline_format, - b->generated_modeline_string, w, dl, db, - MODELINE_INDEX, min_pixpos, max_pixpos, type); - - /* The modeline is at the bottom of the gutters. We have to wait to - set this until we've generated the modeline in order to account - for any embedded faces. */ - dl->ypos = WINDOW_BOTTOM (w) - dl->descent - ypos_adj; -} - -static void +/* This function is also used in frame.c by `generate_title_string' */ +void generate_formatted_string_db (Lisp_Object format_str, Lisp_Object result_str, struct window *w, struct display_line *dl, struct display_block *db, face_index findex, @@ -3559,6 +3493,7 @@ pos_data data; int c_pixpos; + Charcount offset = 0; xzero (data); data.d = d; @@ -3572,15 +3507,21 @@ data.last_findex = DEFAULT_INDEX; data.result_str = result_str; data.is_modeline = 1; + data.string = Qnil; XSETWINDOW (data.window, w); Dynarr_reset (formatted_string_extent_dynarr); Dynarr_reset (formatted_string_extent_start_dynarr); Dynarr_reset (formatted_string_extent_end_dynarr); - /* This recursively builds up the modeline. */ + /* result_str is nil when we're building a frame or icon title. Otherwise, + we're building a modeline, so the offset starts at the modeline + horizontal scrolling ammount */ + if (! NILP (result_str)) + offset = w->modeline_hscroll; generate_fstring_runes (w, &data, 0, 0, -1, format_str, 0, - max_pixpos - min_pixpos, findex, type); + max_pixpos - min_pixpos, findex, type, &offset, + Qnil); if (Dynarr_length (db->runes)) { @@ -3651,13 +3592,115 @@ } } +/* Ensure that the given display line DL accurately represents the + modeline for the given window. */ +static void +generate_modeline (struct window *w, struct display_line *dl, int type) +{ + struct buffer *b = XBUFFER (w->buffer); + struct frame *f = XFRAME (w->frame); + struct device *d = XDEVICE (f->device); + + /* Unlike display line and rune pointers, this one can't change underneath + our feet. */ + struct display_block *db = get_display_block_from_line (dl, TEXT); + int max_pixpos, min_pixpos, ypos_adj; + Lisp_Object font_inst; + + /* This will actually determine incorrect inside boundaries for the + modeline since it ignores the margins. However being aware of this fact + we never use those values anywhere so it doesn't matter. */ + dl->bounds = calculate_display_line_boundaries (w, 1); + + /* We are generating a modeline. */ + dl->modeline = 1; + dl->cursor_elt = -1; + + /* Reset the runes on the modeline. */ + Dynarr_reset (db->runes); + + if (!WINDOW_HAS_MODELINE_P (w)) + { + struct rune rb; + + /* If there is a horizontal scrollbar, don't add anything. */ + if (window_scrollbar_height (w)) + return; + + dl->ascent = DEVMETH (d, divider_height, ()); + dl->descent = 0; + /* The modeline is at the bottom of the gutters. */ + dl->ypos = WINDOW_BOTTOM (w); + + /* adjust for the bottom gutter */ + if (window_is_lowest (w)) + dl->ypos -= FRAME_BOTTOM_GUTTER_BOUNDS (f); + + rb.findex = MODELINE_INDEX; + rb.xpos = dl->bounds.left_out; + rb.width = dl->bounds.right_out - dl->bounds.left_out; + rb.bufpos = 0; + rb.endpos = 0; + rb.type = RUNE_HLINE; + rb.object.hline.thickness = 1; + rb.object.hline.yoffset = 0; + rb.cursor_type = NO_CURSOR; + + if (!EQ (Qzero, w->modeline_shadow_thickness) + && FRAME_WIN_P (f)) + { + int shadow_thickness = MODELINE_SHADOW_THICKNESS (w); + + dl->ypos -= shadow_thickness; + rb.xpos += shadow_thickness; + rb.width -= 2 * shadow_thickness; + } + + Dynarr_add (db->runes, rb); + return; + } + + /* !!#### not right; needs to compute the max height of + all the charsets */ + font_inst = WINDOW_FACE_CACHEL_FONT (w, MODELINE_INDEX, Vcharset_ascii); + + dl->ascent = XFONT_INSTANCE (font_inst)->ascent; + dl->descent = XFONT_INSTANCE (font_inst)->descent; + + min_pixpos = dl->bounds.left_out; + max_pixpos = dl->bounds.right_out; + + if (!EQ (Qzero, w->modeline_shadow_thickness) && FRAME_WIN_P (f)) + { + int shadow_thickness = MODELINE_SHADOW_THICKNESS (w); + + ypos_adj = shadow_thickness; + min_pixpos += shadow_thickness; + max_pixpos -= shadow_thickness; + } + else + ypos_adj = 0; + + generate_formatted_string_db (b->modeline_format, + b->generated_modeline_string, w, dl, db, + MODELINE_INDEX, min_pixpos, max_pixpos, type); + + /* The modeline is at the bottom of the gutters. We have to wait to + set this until we've generated the modeline in order to account + for any embedded faces. */ + dl->ypos = WINDOW_BOTTOM (w) - dl->descent - ypos_adj; + /* adjust for the bottom gutter */ + if (window_is_lowest (w)) + dl->ypos -= FRAME_BOTTOM_GUTTER_BOUNDS (f); +} + static Charcount -add_string_to_fstring_db_runes (pos_data *data, CONST Bufbyte *str, +add_string_to_fstring_db_runes (pos_data *data, const Bufbyte *str, Charcount pos, Charcount min_pos, Charcount max_pos) { /* This function has been Mule-ized. */ Charcount end; - CONST Bufbyte *cur_pos = str; + const Bufbyte *cur_pos = str; struct display_block *db = data->db; data->blank_width = space_width (XWINDOW (data->window)); @@ -3665,13 +3708,13 @@ add_blank_rune (data, NULL, 0); end = (Dynarr_length (db->runes) + - bytecount_to_charcount (str, strlen ((CONST char *) str))); + bytecount_to_charcount (str, strlen ((const char *) str))); if (max_pos != -1) end = min (max_pos, end); while (pos < end && *cur_pos) { - CONST Bufbyte *old_cur_pos = cur_pos; + const Bufbyte *old_cur_pos = cur_pos; int succeeded; data->ch = charptr_emchar (cur_pos); @@ -3696,7 +3739,8 @@ modeline extents. */ static Charcount add_glyph_to_fstring_db_runes (pos_data *data, Lisp_Object glyph, - Charcount pos, Charcount min_pos, Charcount max_pos) + Charcount pos, Charcount min_pos, + Charcount max_pos, Lisp_Object extent) { /* This function has been Mule-ized. */ Charcount end; @@ -3712,7 +3756,7 @@ end = min (max_pos, end); gb.glyph = glyph; - gb.extent = Qnil; + gb.extent = extent; add_glyph_rune (data, &gb, BEGIN_GLYPHS, 0, 0); pos++; @@ -3739,7 +3783,8 @@ generate_fstring_runes (struct window *w, pos_data *data, Charcount pos, Charcount min_pos, Charcount max_pos, Lisp_Object elt, int depth, int max_pixsize, - face_index findex, int type) + face_index findex, int type, Charcount *offset, + Lisp_Object cur_ext) { /* This function has been Mule-ized. */ /* #### The other losing things in this function are: @@ -3771,13 +3816,22 @@ if (this != last) { - /* The string is just a string. */ + /* No %-construct */ Charcount size = - bytecount_to_charcount (last, this - last) + pos; - Charcount tmp_max = (max_pos == -1 ? size : min (size, max_pos)); - - pos = add_string_to_fstring_db_runes (data, last, pos, pos, - tmp_max); + bytecount_to_charcount (last, this - last); + + if (size <= *offset) + *offset -= size; + else + { + Charcount tmp_max = (max_pos == -1 ? pos + size - *offset : + min (pos + size - *offset, max_pos)); + const Bufbyte *tmp_last = charptr_n_addr (last, *offset); + + pos = add_string_to_fstring_db_runes (data, tmp_last, + pos, pos, tmp_max); + *offset = 0; + } } else /* *this == '%' */ { @@ -3802,7 +3856,7 @@ pos = generate_fstring_runes (w, data, pos, spec_width, max_pos, Vglobal_mode_string, depth, max_pixsize, findex, - type); + type, offset, cur_ext); } else if (*this == '-') { @@ -3829,17 +3883,35 @@ while (num_to_add--) pos = add_string_to_fstring_db_runes - (data, (CONST Bufbyte *) "-", pos, pos, max_pos); + (data, (const Bufbyte *) "-", pos, pos, max_pos); } else if (*this != 0) { + Emchar ch = charptr_emchar (this); Bufbyte *str; - Emchar ch = charptr_emchar (this); + Charcount size; + decode_mode_spec (w, ch, type); str = Dynarr_atp (mode_spec_bufbyte_string, 0); - pos = add_string_to_fstring_db_runes (data,str, pos, pos, - max_pos); + size = bytecount_to_charcount + /* Skip the null character added by `decode_mode_spec' */ + (str, Dynarr_length (mode_spec_bufbyte_string)) - 1; + + if (size <= *offset) + *offset -= size; + else + { + const Bufbyte *tmp_str = charptr_n_addr (str, *offset); + + /* #### NOTE: I don't understand why a tmp_max is not + computed and used here as in the plain string case + above. -- dv */ + pos = add_string_to_fstring_db_runes (data, tmp_str, + pos, pos, + max_pos); + *offset = 0; + } } /* NOT this++. There could be any sort of character at @@ -3865,13 +3937,26 @@ if (!UNBOUNDP (tem)) { - /* If value is a string, output that string literally: + /* If value is a string, output that string literally: don't check for % within it. */ if (STRINGP (tem)) { - pos = - add_string_to_fstring_db_runes - (data, XSTRING_DATA (tem), pos, min_pos, max_pos); + Bufbyte *str = XSTRING_DATA (tem); + Charcount size = XSTRING_CHAR_LENGTH (tem); + + if (size <= *offset) + *offset -= size; + else + { + const Bufbyte *tmp_str = charptr_n_addr (str, *offset); + + /* #### NOTE: I don't understand why a tmp_max is not + computed and used here as in the plain string case + above. -- dv */ + pos = add_string_to_fstring_db_runes (data, tmp_str, pos, + min_pos, max_pos); + *offset = 0; + } } /* Give up right away for nil or t. */ else if (!EQ (tem, elt)) @@ -3896,50 +3981,53 @@ else if (CONSP (elt)) { /* A cons cell: four distinct cases. - * If first element is a string or a cons, process all the elements - * and effectively concatenate them. - * If first element is a negative number, truncate displaying cdr to - * at most that many characters. If positive, pad (with spaces) - * to at least that many characters. - * If first element is a symbol, process the cadr or caddr recursively - * according to whether the symbol's value is non-nil or nil. - * If first element is a face, process the cdr recursively - * without altering the depth. + * - If first element is a string or a cons, process all the elements + * and effectively concatenate them. + * - If first element is a negative number, truncate displaying cdr to + * at most that many characters. If positive, pad (with spaces) + * to at least that many characters. + * - If first element is another symbol, process the cadr or caddr + * recursively according to whether the symbol's value is non-nil or + * nil. + * - If first element is a face, process the cdr recursively + * without altering the depth. */ + Lisp_Object car, tem; car = XCAR (elt); if (SYMBOLP (car)) - { - elt = XCDR (elt); - if (!CONSP (elt)) - goto invalid; - tem = symbol_value_in_buffer (car, w->buffer); - /* elt is now the cdr, and we know it is a cons cell. - Use its car if CAR has a non-nil value. */ - if (!UNBOUNDP (tem)) - { - if (!NILP (tem)) - { - elt = XCAR (elt); - goto tail_recurse; - } - } - /* Symbol's value is nil (or symbol is unbound) - * Get the cddr of the original list - * and if possible find the caddr and use that. - */ - elt = XCDR (elt); - if (NILP (elt)) - ; - else if (!CONSP (elt)) - goto invalid; - else - { - elt = XCAR (elt); - goto tail_recurse; - } - } + { + elt = XCDR (elt); + if (!CONSP (elt)) + goto invalid; + + tem = symbol_value_in_buffer (car, w->buffer); + /* elt is now the cdr, and we know it is a cons cell. + Use its car if CAR has a non-nil value. */ + if (!UNBOUNDP (tem)) + { + if (!NILP (tem)) + { + elt = XCAR (elt); + goto tail_recurse; + } + } + /* Symbol's value is nil (or symbol is unbound) + * Get the cddr of the original list + * and if possible find the caddr and use that. + */ + elt = XCDR (elt); + if (NILP (elt)) + ; + else if (!CONSP (elt)) + goto invalid; + else + { + elt = XCAR (elt); + goto tail_recurse; + } + } else if (INTP (car)) { Charcount lim = XINT (car); @@ -3978,13 +4066,14 @@ else if (STRINGP (car) || CONSP (car)) { int limit = 50; + /* LIMIT is to protect against circular lists. */ while (CONSP (elt) && --limit > 0 && (pos < max_pos || max_pos == -1)) { pos = generate_fstring_runes (w, data, pos, pos, max_pos, - XCAR (elt), depth, - max_pixsize, findex, type); + XCAR (elt), depth, max_pixsize, + findex, type, offset, cur_ext); elt = XCDR (elt); } } @@ -4023,7 +4112,8 @@ data->findex = new_findex; pos = generate_fstring_runes (w, data, pos, pos, max_pos, XCDR (elt), depth - 1, - max_pixsize, new_findex, type); + max_pixsize, new_findex, type, + offset, car); data->findex = old_findex; Dynarr_add (formatted_string_extent_dynarr, ext); Dynarr_add (formatted_string_extent_start_dynarr, start); @@ -4033,57 +4123,46 @@ } else if (GLYPHP (elt)) { - pos = add_glyph_to_fstring_db_runes (data, elt, pos, pos, max_pos); + /* Glyphs are considered as one character with respect to the modeline + horizontal scrolling facility. -- dv */ + if (*offset > 0) + *offset -= 1; + else + pos = add_glyph_to_fstring_db_runes (data, elt, pos, pos, max_pos, + cur_ext); } else { invalid: - pos = - add_string_to_fstring_db_runes - (data, (CONST Bufbyte *) GETTEXT ("*invalid*"), pos, min_pos, - max_pos); + { + char *str = GETTEXT ("*invalid*"); + Charcount size = (Charcount) strlen (str); /* is this ok ?? -- dv */ + + if (size <= *offset) + *offset -= size; + else + { + const Bufbyte *tmp_str = + charptr_n_addr ((const Bufbyte *) str, *offset); + + /* #### NOTE: I don't understand why a tmp_max is not computed and + used here as in the plain string case above. -- dv */ + pos = add_string_to_fstring_db_runes (data, tmp_str, pos, + min_pos, max_pos); + *offset = 0; + } + } } if (min_pos > pos) { - add_string_to_fstring_db_runes (data, (CONST Bufbyte *) "", pos, min_pos, - -1); + add_string_to_fstring_db_runes (data, (const Bufbyte *) "", pos, + min_pos, -1); } return pos; } -/* The caller is responsible for freeing the returned string. */ -Bufbyte * -generate_formatted_string (struct window *w, Lisp_Object format_str, - Lisp_Object result_str, face_index findex, int type) -{ - struct display_line *dl; - struct display_block *db; - int elt = 0; - - dl = &formatted_string_display_line; - db = get_display_block_from_line (dl, TEXT); - Dynarr_reset (db->runes); - - generate_formatted_string_db (format_str, result_str, w, dl, db, findex, 0, - -1, type); - - Dynarr_reset (formatted_string_emchar_dynarr); - while (elt < Dynarr_length (db->runes)) - { - if (Dynarr_atp (db->runes, elt)->type == RUNE_CHAR) - Dynarr_add (formatted_string_emchar_dynarr, - Dynarr_atp (db->runes, elt)->object.chr.ch); - elt++; - } - - return - convert_emchar_string_into_malloced_string - ( Dynarr_atp (formatted_string_emchar_dynarr, 0), - Dynarr_length (formatted_string_emchar_dynarr), 0); -} - /* Update just the modeline. Assumes the desired display structs. If they do not have a modeline block, it does nothing. */ static void @@ -4178,6 +4257,834 @@ /***************************************************************************/ +/* */ +/* displayable string routines */ +/* */ +/***************************************************************************/ + +/* Given a position for a string in a window, ensure that the given + display line DL accurately represents the text on a line starting + at the given position. + + Yes, this is duplicating the code of create_text_block, but it + looked just too hard to change create_text_block to handle strings + *and* buffers. We already make a distinction between the two + elsewhere in the code so I think unifying them would require a + complete MULE rewrite. Besides, the other distinction is that these + functions cover text that the user *cannot edit* so we can remove + everything to do with cursors, minibuffers etc. Eventually the + modeline routines should be modified to use this code as it copes + with many more types of display situation. */ + +static Bufpos +create_string_text_block (struct window *w, Lisp_Object disp_string, + struct display_line *dl, + Bufpos start_pos, + prop_block_dynarr **prop, + face_index default_face) +{ + struct frame *f = XFRAME (w->frame); + /* Note that a lot of the buffer controlled stuff has been left in + because you might well want to make use of it (selective display + etc), its just the buffer text that we do not use. However, it + seems to be possible for buffer to be nil sometimes so protect + against this case. */ + struct buffer *b = BUFFERP (w->buffer) ? XBUFFER (w->buffer) : 0; + struct device *d = XDEVICE (f->device); + Lisp_String* s = XSTRING (disp_string); + + /* we're working with these a lot so precalculate them */ + Bytecount slen = XSTRING_LENGTH (disp_string); + Bytecount bi_string_zv = slen; + Bytind bi_start_pos = charcount_to_bytecount (string_data (s), start_pos); + + pos_data data; + + int truncate_win = b ? window_truncation_on (w) : 0; + int end_glyph_width = 0; + + /* we're going to ditch selective display for static text, its an + FSF thing and invisble extents are the way to go + here. Implementing it also relies on a number of buffer-specific + functions that we don't have the luxury of being able to use + here. */ + + /* The variable ctl-arrow allows the user to specify what characters + can actually be displayed and which octal should be used for. + #### This variable should probably have some rethought done to + it. + + #### It would also be really nice if you could specify that + the characters come out in hex instead of in octal. Mule + does that by adding a ctl-hexa variable similar to ctl-arrow, + but that's bogus -- we need a more general solution. I + think you need to extend the concept of display tables + into a more general conversion mechanism. Ideally you + could specify a Lisp function that converts characters, + but this violates the Second Golden Rule and besides would + make things way way way way slow. + + So instead, we extend the display-table concept, which was + historically limited to 256-byte vectors, to one of the + following: + + a) A 256-entry vector, for backward compatibility; + b) char-table, mapping characters to values; + c) range-table, mapping ranges of characters to values; + d) a list of the above. + + The (d) option allows you to specify multiple display tables + instead of just one. Each display table can specify conversions + for some characters and leave others unchanged. The way the + character gets displayed is determined by the first display table + with a binding for that character. This way, you could call a + function `enable-hex-display' that adds a hex display-table to + the list of display tables for the current buffer. + + #### ...not yet implemented... Also, we extend the concept of + "mapping" to include a printf-like spec. Thus you can make all + extended characters show up as hex with a display table like + this: + + #s(range-table data ((256 524288) (format "%x"))) + + Since more than one display table is possible, you have + great flexibility in mapping ranges of characters. */ + Emchar printable_min = b ? (CHAR_OR_CHAR_INTP (b->ctl_arrow) + ? XCHAR_OR_CHAR_INT (b->ctl_arrow) + : ((EQ (b->ctl_arrow, Qt) || EQ (b->ctl_arrow, Qnil)) + ? 255 : 160)) : 255; + + Lisp_Object face_dt, window_dt; + + /* The text display block for this display line. */ + struct display_block *db = get_display_block_from_line (dl, TEXT); + + /* The first time through the main loop we need to force the glyph + data to be updated. */ + int initial = 1; + + /* Apparently the new extent_fragment_update returns an end position + equal to the position passed in if there are no more runs to be + displayed. */ + int no_more_frags = 0; + + dl->used_prop_data = 0; + dl->num_chars = 0; + + /* set up faces to use for clearing areas, used by + output_display_line */ + dl->default_findex = default_face; + if (default_face) + { + dl->left_margin_findex = default_face; + dl->right_margin_findex = default_face; + } + else + { + dl->left_margin_findex = + get_builtin_face_cache_index (w, Vleft_margin_face); + dl->right_margin_findex = + get_builtin_face_cache_index (w, Vright_margin_face); + } + + xzero (data); + data.ef = extent_fragment_new (disp_string, f); + + /* These values are used by all of the rune addition routines. We add + them to this structure for ease of passing. */ + data.d = d; + XSETWINDOW (data.window, w); + data.db = db; + data.dl = dl; + + data.bi_bufpos = bi_start_pos; + data.pixpos = dl->bounds.left_in; + data.last_charset = Qunbound; + data.last_findex = default_face; + data.result_str = Qnil; + data.string = disp_string; + + /* Set the right boundary adjusting it to take into account any end + glyph. Save the width of the end glyph for later use. */ + data.max_pixpos = dl->bounds.right_in; +#if 0 + if (truncate_win) + end_glyph_width = GLYPH_CACHEL_WIDTH (w, TRUN_GLYPH_INDEX); + else + end_glyph_width = GLYPH_CACHEL_WIDTH (w, CONT_GLYPH_INDEX); +#endif + data.max_pixpos -= end_glyph_width; + + data.cursor_type = NO_CURSOR; + data.cursor_x = -1; + + data.start_col = 0; + /* I don't think we want this, string areas should not scroll with + the window + data.start_col = w->hscroll; + data.bi_start_col_enabled = (w->hscroll ? bi_start_pos : 0); + */ + data.bi_start_col_enabled = 0; + data.hscroll_glyph_width_adjust = 0; + + /* We regenerate the line from the very beginning. */ + Dynarr_reset (db->runes); + + /* Why is this less than or equal and not just less than? If the + starting position is already equal to the maximum we can't add + anything else, right? Wrong. We might still have a newline to + add. A newline can use the room allocated for an end glyph since + if we add it we know we aren't going to be adding any end + glyph. */ + + /* #### Chuck -- I think this condition should be while (1). + Otherwise if (e.g.) there is one begin-glyph and one end-glyph + and the begin-glyph ends exactly at the end of the window, the + end-glyph and text might not be displayed. while (1) ensures + that the loop terminates only when either (a) there is + propagation data or (b) the end-of-line or end-of-buffer is hit. + + #### Also I think you need to ensure that the operation + "add begin glyphs; add end glyphs; add text" is atomic and + can't get interrupted in the middle. If you run off the end + of the line during that operation, then you keep accumulating + propagation data until you're done. Otherwise, if the (e.g.) + there's a begin glyph at a particular position and attempting + to display that glyph results in window-end being hit and + propagation data being generated, then the character at that + position won't be displayed. + + #### See also the comment after the end of this loop, below. + */ + while (data.pixpos <= data.max_pixpos) + { + /* #### This check probably should not be necessary. */ + if (data.bi_bufpos > bi_string_zv) + { + /* #### urk! More of this lossage! */ + data.bi_bufpos--; + goto done; + } + + /* Check for face changes. */ + if (initial || (!no_more_frags && data.bi_bufpos == data.ef->end)) + { + /* Now compute the face and begin/end-glyph information. */ + data.findex = + /* Remember that the extent-fragment routines deal in Bytind's. */ + extent_fragment_update (w, data.ef, data.bi_bufpos); + /* This is somewhat cheesy but the alternative is to + propagate default_face into extent_fragment_update. */ + if (data.findex == DEFAULT_INDEX) + data.findex = default_face; + + get_display_tables (w, data.findex, &face_dt, &window_dt); + + if (data.bi_bufpos == data.ef->end) + no_more_frags = 1; + } + initial = 0; + + /* Determine what is next to be displayed. We first handle any + glyphs returned by glyphs_at_bufpos. If there are no glyphs to + display then we determine what to do based on the character at the + current buffer position. */ + + /* If the current position is covered by an invisible extent, do + nothing (except maybe add some ellipses). + + #### The behavior of begin and end-glyphs at the edge of an + invisible extent should be investigated further. This is + fairly low priority though. */ + if (data.ef->invisible) + { + /* #### Chuck, perhaps you could look at this code? I don't + really know what I'm doing. */ + if (*prop) + { + Dynarr_free (*prop); + *prop = 0; + } + + /* The extent fragment code only sets this when we should + really display the ellipses. It makes sure the ellipses + don't get displayed more than once in a row. */ + if (data.ef->invisible_ellipses) + { + struct glyph_block gb; + + data.ef->invisible_ellipses_already_displayed = 1; + data.ef->invisible_ellipses = 0; + gb.extent = Qnil; + gb.glyph = Vinvisible_text_glyph; + *prop = add_glyph_rune (&data, &gb, BEGIN_GLYPHS, 0, + GLYPH_CACHEL (w, INVIS_GLYPH_INDEX)); + /* Perhaps they shouldn't propagate if the very next thing + is to display a newline (for compatibility with + selective-display-ellipses)? Maybe that's too + abstruse. */ + if (*prop) + goto done; + } + + /* #### What if we we're dealing with a display table? */ + if (data.start_col) + data.start_col--; + + if (data.bi_bufpos == bi_string_zv) + goto done; + else + INC_CHARBYTIND (string_data (s), data.bi_bufpos); + } + + /* If there is propagation data, then it represents the current + buffer position being displayed. Add them and advance the + position counter. This might also add the minibuffer + prompt. */ + else if (*prop) + { + dl->used_prop_data = 1; + *prop = add_propagation_runes (prop, &data); + + if (*prop) + goto done; /* gee, a really narrow window */ + else if (data.bi_bufpos == bi_string_zv) + goto done; + else if (data.bi_bufpos < 0) + /* #### urk urk urk! Aborts are not very fun! Fix this please! */ + data.bi_bufpos = 0; + else + INC_CHARBYTIND (string_data (s), data.bi_bufpos); + } + + /* If there are end glyphs, add them to the line. These are + the end glyphs for the previous run of text. We add them + here rather than doing them at the end of handling the + previous run so that glyphs at the beginning and end of + a line are handled correctly. */ + else if (Dynarr_length (data.ef->end_glyphs) > 0) + { + *prop = add_glyph_runes (&data, END_GLYPHS); + if (*prop) + goto done; + } + + /* If there are begin glyphs, add them to the line. */ + else if (Dynarr_length (data.ef->begin_glyphs) > 0) + { + *prop = add_glyph_runes (&data, BEGIN_GLYPHS); + if (*prop) + goto done; + } + + /* If at end-of-buffer, we've already processed begin and + end-glyphs at this point and there's no text to process, + so we're done. */ + else if (data.bi_bufpos == bi_string_zv) + goto done; + + else + { + Lisp_Object entry = Qnil; + /* Get the character at the current buffer position. */ + data.ch = string_char (s, data.bi_bufpos); + if (!NILP (face_dt) || !NILP (window_dt)) + entry = display_table_entry (data.ch, face_dt, window_dt); + + /* If there is a display table entry for it, hand it off to + add_disp_table_entry_runes and let it worry about it. */ + if (!NILP (entry) && !EQ (entry, make_char (data.ch))) + { + *prop = add_disp_table_entry_runes (&data, entry); + + if (*prop) + goto done; + } + + /* Check if we have hit a newline character. If so, add a marker + to the line and end this loop. */ + else if (data.ch == '\n') + { + /* We aren't going to be adding an end glyph so give its + space back in order to make sure that the cursor can + fit. */ + data.max_pixpos += end_glyph_width; + goto done; + } + + /* If the current character is considered to be printable, then + just add it. */ + else if (data.ch >= printable_min) + { + *prop = add_emchar_rune (&data); + if (*prop) + goto done; + } + + /* If the current character is a tab, determine the next tab + starting position and add a blank rune which extends from the + current pixel position to that starting position. */ + else if (data.ch == '\t') + { + int tab_start_pixpos = data.pixpos; + int next_tab_start; + int char_tab_width; + int prop_width = 0; + + if (data.start_col > 1) + tab_start_pixpos -= (space_width (w) * (data.start_col - 1)); + + next_tab_start = + next_tab_position (w, tab_start_pixpos, + dl->bounds.left_in + + data.hscroll_glyph_width_adjust); + if (next_tab_start > data.max_pixpos) + { + prop_width = next_tab_start - data.max_pixpos; + next_tab_start = data.max_pixpos; + } + data.blank_width = next_tab_start - data.pixpos; + char_tab_width = + (next_tab_start - tab_start_pixpos) / space_width (w); + + *prop = add_blank_rune (&data, w, char_tab_width); + + /* add_blank_rune is only supposed to be called with + sizes guaranteed to fit in the available space. */ + assert (!(*prop)); + + if (prop_width) + { + struct prop_block pb; + *prop = Dynarr_new (prop_block); + + pb.type = PROP_BLANK; + pb.data.p_blank.width = prop_width; + pb.data.p_blank.findex = data.findex; + Dynarr_add (*prop, pb); + + goto done; + } + } + + /* If character is a control character, pass it off to + add_control_char_runes. + + The is_*() routines have undefined results on + arguments outside of the range [-1, 255]. (This + often bites people who carelessly use `char' instead + of `unsigned char'.) + */ + else if (data.ch < 0x100 && iscntrl ((Bufbyte) data.ch)) + { + *prop = add_control_char_runes (&data, b); + + if (*prop) + goto done; + } + + /* If the character is above the ASCII range and we have not + already handled it, then print it as an octal number. */ + else if (data.ch >= 0200) + { + *prop = add_octal_runes (&data); + + if (*prop) + goto done; + } + + /* Assume the current character is considered to be printable, + then just add it. */ + else + { + *prop = add_emchar_rune (&data); + if (*prop) + goto done; + } + + INC_CHARBYTIND (string_data (s), data.bi_bufpos); + } + } + +done: + + /* Determine the starting point of the next line if we did not hit the + end of the buffer. */ + if (data.bi_bufpos < bi_string_zv) + { + /* #### This check is not correct. If the line terminated + due to a begin-glyph or end-glyph hitting window-end, then + data.ch will not point to the character at data.bi_bufpos. If + you make the two changes mentioned at the top of this loop, + you should be able to say '(if (*prop))'. That should also + make it possible to eliminate the data.bi_bufpos < BI_BUF_ZV (b) + check. */ + + /* The common case is that the line ended because we hit a newline. + In that case, the next character is just the next buffer + position. */ + if (data.ch == '\n') + { + INC_CHARBYTIND (string_data (s), data.bi_bufpos); + } + + /* Otherwise we have a buffer line which cannot fit on one display + line. */ + else + { + struct glyph_block gb; + struct glyph_cachel *cachel; + + /* If the line is to be truncated then we actually have to look + for the next newline. We also add the end-of-line glyph which + we know will fit because we adjusted the right border before + we starting laying out the line. */ + data.max_pixpos += end_glyph_width; + data.findex = default_face; + gb.extent = Qnil; + + if (truncate_win) + { + Bytind bi_pos; + + /* Now find the start of the next line. */ + bi_pos = bi_find_next_emchar_in_string (s, '\n', data.bi_bufpos, 1); + + data.cursor_type = NO_CURSOR; + data.bi_bufpos = bi_pos; + gb.glyph = Vtruncation_glyph; + cachel = GLYPH_CACHEL (w, TRUN_GLYPH_INDEX); + } + else + { + /* The cursor can never be on the continuation glyph. */ + data.cursor_type = NO_CURSOR; + + /* data.bi_bufpos is already at the start of the next line. */ + + gb.glyph = Vcontinuation_glyph; + cachel = GLYPH_CACHEL (w, CONT_GLYPH_INDEX); + } + + if (end_glyph_width) + add_glyph_rune (&data, &gb, BEGIN_GLYPHS, 0, cachel); + + if (truncate_win && data.bi_bufpos == bi_string_zv) + { + const Bufbyte* endb = charptr_n_addr (string_data (s), bi_string_zv); + DEC_CHARPTR (endb); + if (charptr_emchar (endb) != '\n') + { + /* #### Damn this losing shit. */ + data.bi_bufpos++; + } + } + } + } + else if (data.bi_bufpos == bi_string_zv) + { + /* create_text_block () adds a bogus \n marker here which screws + up subwindow display. Since we never have a cursor in the + gutter we can safely ignore it. */ + } + /* Calculate left whitespace boundary. */ + { + int elt = 0; + + /* Whitespace past a newline is considered right whitespace. */ + while (elt < Dynarr_length (db->runes)) + { + struct rune *rb = Dynarr_atp (db->runes, elt); + + if ((rb->type == RUNE_CHAR && rb->object.chr.ch == ' ') + || rb->type == RUNE_BLANK) + { + dl->bounds.left_white += rb->width; + elt++; + } + else + elt = Dynarr_length (db->runes); + } + } + + /* Calculate right whitespace boundary. */ + { + int elt = Dynarr_length (db->runes) - 1; + int done = 0; + + while (!done && elt >= 0) + { + struct rune *rb = Dynarr_atp (db->runes, elt); + + if (!(rb->type == RUNE_CHAR && rb->object.chr.ch < 0x100 + && isspace (rb->object.chr.ch)) + && !rb->type == RUNE_BLANK) + { + dl->bounds.right_white = rb->xpos + rb->width; + done = 1; + } + + elt--; + + } + + /* The line is blank so everything is considered to be right + whitespace. */ + if (!done) + dl->bounds.right_white = dl->bounds.left_in; + } + + /* Set the display blocks bounds. */ + db->start_pos = dl->bounds.left_in; + if (Dynarr_length (db->runes)) + { + struct rune *rb = Dynarr_atp (db->runes, Dynarr_length (db->runes) - 1); + + db->end_pos = rb->xpos + rb->width; + } + else + db->end_pos = dl->bounds.right_white; + + /* update line height parameters */ + if (!data.new_ascent && !data.new_descent) + { + /* We've got a blank line so initialize these values from the default + face. */ + default_face_font_info (data.window, &data.new_ascent, + &data.new_descent, 0, 0, 0); + } + + if (data.max_pixmap_height) + { + int height = data.new_ascent + data.new_descent; + int pix_ascent, pix_descent; + + pix_descent = data.max_pixmap_height * data.new_descent / height; + pix_ascent = data.max_pixmap_height - pix_descent; + + data.new_ascent = max (data.new_ascent, pix_ascent); + data.new_descent = max (data.new_descent, pix_descent); + } + + dl->ascent = data.new_ascent; + dl->descent = data.new_descent; + + { + unsigned short ascent = (unsigned short) XINT (w->minimum_line_ascent); + + if (dl->ascent < ascent) + dl->ascent = ascent; + } + { + unsigned short descent = (unsigned short) XINT (w->minimum_line_descent); + + if (dl->descent < descent) + dl->descent = descent; + } + + dl->cursor_elt = data.cursor_x; + /* #### lossage lossage lossage! Fix this shit! */ + if (data.bi_bufpos > bi_string_zv) + dl->end_bufpos = buffer_or_string_bytind_to_bufpos (disp_string, bi_string_zv); + else + dl->end_bufpos = buffer_or_string_bytind_to_bufpos (disp_string, data.bi_bufpos) - 1; + if (truncate_win) + data.dl->num_chars = + string_column_at_point (s, dl->end_bufpos, b ? XINT (b->tab_width) : 8); + else + /* This doesn't correctly take into account tabs and control + characters but if the window isn't being truncated then this + value isn't going to end up being used anyhow. */ + data.dl->num_chars = dl->end_bufpos - dl->bufpos; + + /* #### handle horizontally scrolled line with text none of which + was actually laid out. */ + + /* #### handle any remainder of overlay arrow */ + + if (*prop == ADD_FAILED) + *prop = NULL; + + if (truncate_win && *prop) + { + Dynarr_free (*prop); + *prop = NULL; + } + + extent_fragment_delete (data.ef); + + /* #### If we started at EOB, then make sure we return a value past + it so that regenerate_window will exit properly. This is bogus. + The main loop should get fixed so that it isn't necessary to call + this function if we are already at EOB. */ + + if (data.bi_bufpos == bi_string_zv && bi_start_pos == bi_string_zv) + return bytecount_to_charcount (string_data (s), data.bi_bufpos) + 1; /* Yuck! */ + else + return bytecount_to_charcount (string_data (s), data.bi_bufpos); +} + +/* Given a display line and a starting position, ensure that the + contents of the display line accurately represent the visual + representation of the buffer contents starting from the given + position when displayed in the given window. The display line ends + when the contents of the line reach the right boundary of the given + window. + + This is very similar to generate_display_line but with the same + limitations as create_string_text_block. I have taken the liberty + of fixing the bytind stuff though.*/ + +static Bufpos +generate_string_display_line (struct window *w, Lisp_Object disp_string, + struct display_line *dl, + Bufpos start_pos, + prop_block_dynarr **prop, + face_index default_face) +{ + Bufpos ret_bufpos; + + /* you must set bounds before calling this. */ + + /* Reset what this line is using. */ + if (dl->display_blocks) + Dynarr_reset (dl->display_blocks); + if (dl->left_glyphs) + { + Dynarr_free (dl->left_glyphs); + dl->left_glyphs = 0; + } + if (dl->right_glyphs) + { + Dynarr_free (dl->right_glyphs); + dl->right_glyphs = 0; + } + + /* We aren't generating a modeline at the moment. */ + dl->modeline = 0; + + /* Create a display block for the text region of the line. */ + ret_bufpos = create_string_text_block (w, disp_string, dl, start_pos, + prop, default_face); + dl->bufpos = start_pos; + if (dl->end_bufpos < dl->bufpos) + dl->end_bufpos = dl->bufpos; + + /* If there are left glyphs associated with any character in the + text block, then create a display block to handle them. */ + if (dl->left_glyphs != NULL && Dynarr_length (dl->left_glyphs)) + create_left_glyph_block (w, dl, 0); + + /* If there are right glyphs associated with any character in the + text block, then create a display block to handle them. */ + if (dl->right_glyphs != NULL && Dynarr_length (dl->right_glyphs)) + create_right_glyph_block (w, dl); + + return ret_bufpos; +} + +/* This is ripped off from regenerate_window. All we want to do is + loop through elements in the string creating display lines until we + have covered the provided area. Simple really. */ +void +generate_displayable_area (struct window *w, Lisp_Object disp_string, + int xpos, int ypos, int width, int height, + display_line_dynarr* dla, + Bufpos start_pos, + face_index default_face) +{ + int yend = ypos + height; + Charcount s_zv; + + prop_block_dynarr *prop = 0; + layout_bounds bounds; + assert (dla); + + Dynarr_reset (dla); + /* if there's nothing to do then do nothing. code after this assumes + there is something to do. */ + if (NILP (disp_string)) + return; + + s_zv = XSTRING_CHAR_LENGTH (disp_string); + + bounds.left_out = xpos; + bounds.right_out = xpos + width; + /* The inner boundaries mark where the glyph margins are located. */ + bounds.left_in = bounds.left_out + window_left_margin_width (w); + bounds.right_in = bounds.right_out - window_right_margin_width (w); + /* We cannot fully calculate the whitespace boundaries as they + depend on the contents of the line being displayed. */ + bounds.left_white = bounds.left_in; + bounds.right_white = bounds.right_in; + + while (ypos < yend) + { + struct display_line dl; + struct display_line *dlp; + Bufpos next_pos; + int local; + + if (Dynarr_length (dla) < Dynarr_largest (dla)) + { + dlp = Dynarr_atp (dla, Dynarr_length (dla)); + local = 0; + } + else + { + + xzero (dl); + dlp = &dl; + local = 1; + } + + dlp->bounds = bounds; + dlp->offset = 0; + next_pos = generate_string_display_line (w, disp_string, dlp, start_pos, + &prop, default_face); + /* we need to make sure that we continue along the line if there + is more left to display otherwise we just end up redisplaying + the same chunk over and over again. */ + if (next_pos == start_pos && next_pos < s_zv) + start_pos++; + else + start_pos = next_pos; + + dlp->ypos = ypos + dlp->ascent; + ypos = dlp->ypos + dlp->descent; + + if (ypos > yend) + { + int visible_height = dlp->ascent + dlp->descent; + + dlp->clip = (ypos - yend); + visible_height -= dlp->clip; + + if (visible_height < VERTICAL_CLIP (w, 1)) + { + if (local) + free_display_line (dlp); + break; + } + } + else + dlp->clip = 0; + + Dynarr_add (dla, *dlp); + + /* #### This type of check needs to be done down in the + generate_display_line call. */ + if (start_pos >= s_zv) + break; + } + + if (prop) + Dynarr_free (prop); +} + + +/***************************************************************************/ /* */ /* window-regeneration routines */ /* */ @@ -4196,6 +5103,7 @@ struct buffer *b = XBUFFER (w->buffer); int ypos = WINDOW_TEXT_TOP (w); int yend; /* set farther down */ + int yclip = WINDOW_TEXT_TOP_CLIP (w); prop_block_dynarr *prop; layout_bounds bounds; @@ -4262,6 +5170,7 @@ } else { + xzero (dl); dlp = &dl; local = 1; @@ -4269,17 +5178,37 @@ dlp->bounds = bounds; dlp->offset = 0; - start_pos = generate_display_line (w, dlp, 1, start_pos, - w->hscroll, &prop, type); - dlp->ypos = ypos + dlp->ascent; + start_pos = generate_display_line (w, dlp, 1, start_pos, &prop, type); + + if (yclip > dlp->ascent) + { + /* this should never happen, but if it does just display the + whole line */ + yclip = 0; + } + + dlp->ypos = (ypos + dlp->ascent) - yclip; ypos = dlp->ypos + dlp->descent; + /* See if we've been asked to start midway through a line, for + partial display line scrolling. */ + if (yclip) + { + dlp->top_clip = yclip; + yclip = 0; + } + else + dlp->top_clip = 0; + if (ypos > yend) { int visible_height = dlp->ascent + dlp->descent; dlp->clip = (ypos - yend); - visible_height -= dlp->clip; + /* Although this seems strange we could have a single very + tall line visible for which we need to account for both + the top clip and the bottom clip. */ + visible_height -= (dlp->clip + dlp->top_clip); if (visible_height < VERTICAL_CLIP (w, 1)) { @@ -4522,7 +5451,7 @@ return 0; new_start = generate_display_line (w, ddl, 0, ddl->bufpos + ddl->offset, - w->hscroll, &prop, DESIRED_DISP); + &prop, DESIRED_DISP); ddl->offset = 0; /* #### If there is propagated stuff the fail. We could @@ -4541,6 +5470,7 @@ if (cdl->ypos != ddl->ypos || cdl->ascent != ddl->ascent || cdl->descent != ddl->descent + || cdl->top_clip != ddl->top_clip || (cdl->cursor_elt != -1 && ddl->cursor_elt == -1) || (cdl->cursor_elt == -1 && ddl->cursor_elt != -1) || old_start != ddl->bufpos @@ -4684,7 +5614,7 @@ return 0; new_start = generate_display_line (w, ddl, 0, ddl->bufpos + ddl->offset, - w->hscroll, &prop, DESIRED_DISP); + &prop, DESIRED_DISP); ddl->offset = 0; /* If there is propagated stuff then it is pretty much a @@ -4714,6 +5644,7 @@ if (cdl->ypos != ddl->ypos || cdl->ascent != ddl->ascent || cdl->descent != ddl->descent + || cdl->top_clip != ddl->top_clip || (cdl->cursor_elt != -1 && ddl->cursor_elt == -1) || (cdl->cursor_elt == -1 && ddl->cursor_elt != -1)) { @@ -4997,7 +5928,7 @@ } Fset_marker (w->pointm[DESIRED_DISP], make_int (pointm), the_buffer); - /* If the buffer has changed we have to invalid all of our face + /* If the buffer has changed we have to invalidate all of our face cache elements. */ if ((!echo_active && b != window_display_buffer (w)) || !Dynarr_length (w->face_cachels) @@ -5006,10 +5937,11 @@ else mark_face_cachels_as_not_updated (w); - /* Ditto the glyph cache elements. */ + /* Ditto the glyph cache elements, although we do *not* invalidate + the cache purely because glyphs have changed - this is now + handled by the dirty flag.*/ if ((!echo_active && b != window_display_buffer (w)) - || !Dynarr_length (w->glyph_cachels) - || f->glyphs_changed) + || !Dynarr_length (w->glyph_cachels) || f->faces_changed) reset_glyph_cachels (w); else mark_glyph_cachels_as_not_updated (w); @@ -5095,6 +6027,7 @@ && !f->faces_changed && !f->glyphs_changed && !f->subwindows_changed + && !f->subwindows_state_changed && !f->point_changed && !f->windows_structure_changed) { @@ -5116,6 +6049,7 @@ && !f->faces_changed && !f->glyphs_changed && !f->subwindows_changed + && !f->subwindows_state_changed && !f->windows_structure_changed) { if (point_visible (w, pointm, CURRENT_DISP) @@ -5174,6 +6108,7 @@ && !f->faces_changed && !f->glyphs_changed && !f->subwindows_changed + && !f->subwindows_state_changed && !f->windows_structure_changed && !f->frame_changed && !truncation_changed @@ -5253,8 +6188,9 @@ Bufpos end = (w->window_end_pos[DESIRED_DISP] == -1 ? BUF_ZV (b) : BUF_Z (b) - w->window_end_pos[DESIRED_DISP] - 1); - - update_line_start_cache (w, start, end, pointm, 1); + /* Don't pollute the cache if not sure if we are correct */ + if (w->start_at_line_beg) + update_line_start_cache (w, start, end, pointm, 1); redisplay_output_window (w); /* * If we just displayed the echo area, the line start cache is @@ -5269,6 +6205,12 @@ somewhere else once tty updates occur on a per-frame basis. */ mark_face_cachels_as_clean (w); + /* The glyph cachels only get dirty if someone changed something. + Since redisplay has now effectively ended we can reset the dirty + flag since everything must be up-to-date. */ + if (glyphs_changed) + mark_glyph_cachels_as_clean (w); + w->windows_changed = 0; } @@ -5400,6 +6342,31 @@ update_frame_toolbars (f); #endif /* HAVE_TOOLBARS */ + /* If we clear the frame we have to force its contents to be redrawn. */ + if (f->clear) + f->frame_changed = 1; + + /* invalidate the subwindow cache. We use subwindows_changed here to + cause subwindows to get instantiated. This is because + subwindows_state_changed is less strict - dealing with things + like the clicked state of button. We have to do this before + redisplaying the gutters as subwindows get unmapped in the + process.*/ + if (!Dynarr_length (f->subwindow_cachels) + || f->subwindows_changed + || f->faces_changed + || f->frame_changed) + { + reset_subwindow_cachels (f); + /* we have to do this so the gutter gets regenerated. */ + reset_gutter_display_lines (f); + } + else + mark_subwindow_cachels_as_not_updated (f); + /* We can now update the gutters, safe in the knowledge that our + efforts won't get undone. */ + update_frame_gutters (f); + hold_frame_size_changes (); /* ----------------- BEGIN CRITICAL REDISPLAY SECTION ---------------- */ @@ -5426,27 +6393,12 @@ #### If a frame-size change does occur we should probably actually be preempting redisplay. */ - /* If we clear the frame we have to force its contents to be redrawn. */ - if (f->clear) - f->frame_changed = 1; - /* Erase the frame before outputting its contents. */ if (f->clear) { DEVMETH (d, clear_frame, (f)); } - /* invalidate the subwindow cache. we are going to reuse the glyphs - flag here to cause subwindows to get instantiated. This is - because subwindows changed is less strict - dealing with things - like the clicked state of button. */ - if (!Dynarr_length (f->subwindow_cachels) - || f->glyphs_changed - || f->frame_changed) - reset_subwindow_cachels (f); - else - mark_subwindow_cachels_as_not_updated (f); - /* Do the selected window first. */ redisplay_window (FRAME_SELECTED_WINDOW (f), 0); @@ -5461,23 +6413,9 @@ update_frame_title (f); - f->buffers_changed = 0; - f->clip_changed = 0; - f->extents_changed = 0; - f->faces_changed = 0; - f->frame_changed = 0; - f->glyphs_changed = 0; - f->subwindows_changed = 0; - f->icon_changed = 0; - f->menubar_changed = 0; - f->modeline_changed = 0; - f->point_changed = 0; - f->toolbar_changed = 0; - f->windows_changed = 0; - f->windows_structure_changed = 0; + CLASS_RESET_CHANGED_FLAGS (f); f->window_face_cache_reset = 0; f->echo_area_garbaged = 0; - f->clear = 0; if (!f->size_change_pending) @@ -5494,16 +6432,27 @@ return 0; } -/* Ensure that all frames on the given device are correctly displayed. */ +/* Ensure that all frames on the given device are correctly displayed. + If AUTOMATIC is non-zero, and the device implementation indicates + no automatic redisplay, as printers do, then the device is not + redisplayed. AUTOMATIC is set to zero when called from lisp + functions (redraw-device) and (redisplay-device), and to non-zero + when called from "lazy" redisplay(); +*/ static int -redisplay_device (struct device *d) +redisplay_device (struct device *d, int automatic) { Lisp_Object frame, frmcons; int preempted = 0; int size_change_failed = 0; struct frame *f; + if (automatic + && (MAYBE_INT_DEVMETH (d, device_implementation_flags, ()) + & XDEVIMPF_NO_AUTO_REDISPLAY)) + return 0; + if (DEVICE_STREAM_P (d)) /* nothing to do */ return 0; @@ -5527,11 +6476,7 @@ if (FRAME_REPAINT_P (f)) { - if (f->buffers_changed || f->clip_changed || f->extents_changed || - f->faces_changed || f->frame_changed || f->menubar_changed || - f->modeline_changed || f->point_changed || f->size_changed || - f->toolbar_changed || f->windows_changed || f->size_slipped || - f->windows_structure_changed || f->glyphs_changed || f->subwindows_changed) + if (CLASS_REDISPLAY_FLAGS_CHANGEDP(f)) { preempted = redisplay_frame (f, 0); } @@ -5561,12 +6506,7 @@ if (FRAME_REPAINT_P (f)) { - if (f->buffers_changed || f->clip_changed || f->extents_changed || - f->faces_changed || f->frame_changed || f->menubar_changed || - f->modeline_changed || f->point_changed || f->size_changed || - f->toolbar_changed || f->windows_changed || - f->windows_structure_changed || - f->glyphs_changed || f->subwindows_changed) + if (CLASS_REDISPLAY_FLAGS_CHANGEDP (f)) { preempted = redisplay_frame (f, 0); } @@ -5581,20 +6521,7 @@ /* If we get here then we redisplayed all of our frames without getting preempted so mark ourselves as clean. */ - d->buffers_changed = 0; - d->clip_changed = 0; - d->extents_changed = 0; - d->faces_changed = 0; - d->frame_changed = 0; - d->glyphs_changed = 0; - d->subwindows_changed = 0; - d->icon_changed = 0; - d->menubar_changed = 0; - d->modeline_changed = 0; - d->point_changed = 0; - d->toolbar_changed = 0; - d->windows_changed = 0; - d->windows_structure_changed = 0; + CLASS_RESET_CHANGED_FLAGS (d); if (!size_change_failed) d->size_changed = 0; @@ -5629,13 +6556,8 @@ if (asynch_device_change_pending) handle_asynch_device_change (); - if (!buffers_changed && !clip_changed && !extents_changed && - !faces_changed && !frame_changed && !icon_changed && - !menubar_changed && !modeline_changed && !point_changed && - !size_changed && !toolbar_changed && !windows_changed && - !glyphs_changed && !subwindows_changed && - !windows_structure_changed && !disable_preemption && - preemption_count < max_preempts) + if (!GLOBAL_REDISPLAY_FLAGS_CHANGEDP && + !disable_preemption && preemption_count < max_preempts) goto done; DEVICE_LOOP_NO_BREAK (devcons, concons) @@ -5643,14 +6565,9 @@ struct device *d = XDEVICE (XCAR (devcons)); int preempted; - if (d->buffers_changed || d->clip_changed || d->extents_changed || - d->faces_changed || d->frame_changed || d->icon_changed || - d->menubar_changed || d->modeline_changed || d->point_changed || - d->size_changed || d->toolbar_changed || d->windows_changed || - d->windows_structure_changed || - d->glyphs_changed || d->subwindows_changed) - { - preempted = redisplay_device (d); + if (CLASS_REDISPLAY_FLAGS_CHANGEDP (d)) + { + preempted = redisplay_device (d, 1); if (preempted) { @@ -5667,19 +6584,7 @@ preemption_count = 0; /* Mark redisplay as accurate */ - buffers_changed = 0; - clip_changed = 0; - extents_changed = 0; - frame_changed = 0; - glyphs_changed = 0; - subwindows_changed = 0; - icon_changed = 0; - menubar_changed = 0; - modeline_changed = 0; - point_changed = 0; - toolbar_changed = 0; - windows_changed = 0; - windows_structure_changed = 0; + GLOBAL_RESET_CHANGED_FLAGS; RESET_CHANGED_SET_FLAGS; if (faces_changed) @@ -5776,7 +6681,7 @@ decode_mode_spec (struct window *w, Emchar spec, int type) { Lisp_Object obj = Qnil; - CONST char *str = NULL; + const char *str = NULL; struct buffer *b = XBUFFER (w->buffer); Dynarr_reset (mode_spec_bufbyte_string); @@ -5805,7 +6710,7 @@ long_to_string (buf, col); Dynarr_add_many (mode_spec_bufbyte_string, - (CONST Bufbyte *) buf, strlen (buf)); + (const Bufbyte *) buf, strlen (buf)); goto decode_mode_spec_done; } @@ -5910,7 +6815,6 @@ case 'p': { Bufpos pos = marker_position (w->start[type]); - Charcount total = BUF_ZV (b) - BUF_BEGV (b); /* This had better be while the desired lines are being done. */ if (w->window_end_pos[type] <= BUF_Z (b) - BUF_ZV (b)) @@ -5927,15 +6831,20 @@ /* This hard limit is ok since the string it will hold has a fixed maximum length of 3. But just to be safe... */ char buf[10]; - - total = ((pos - BUF_BEGV (b)) * 100 + total - 1) / total; + Charcount chars = pos - BUF_BEGV (b); + Charcount total = BUF_ZV (b) - BUF_BEGV (b); + + /* Avoid overflow on big buffers */ + int percent = total > LONG_MAX/200 ? + (chars + total/200) / (total / 100) : + (chars * 100 + total/2) / total; /* We can't normally display a 3-digit number, so get us a 2-digit number that is close. */ - if (total == 100) - total = 99; - - sprintf (buf, "%2d%%", total); + if (percent == 100) + percent = 99; + + sprintf (buf, "%d%%", percent); Dynarr_add_many (mode_spec_bufbyte_string, (Bufbyte *) buf, strlen (buf)); @@ -5950,7 +6859,6 @@ { Bufpos toppos = marker_position (w->start[type]); Bufpos botpos = BUF_Z (b) - w->window_end_pos[type]; - Charcount total = BUF_ZV (b) - BUF_BEGV (b); /* botpos is only accurate as of the last redisplay, so we can only treat it as a hint. In particular, after erase-buffer, @@ -5970,18 +6878,23 @@ /* This hard limit is ok since the string it will hold has a fixed maximum length of around 6. But just to be safe... */ char buf[10]; - - total = ((botpos - BUF_BEGV (b)) * 100 + total - 1) / total; + Charcount chars = botpos - BUF_BEGV (b); + Charcount total = BUF_ZV (b) - BUF_BEGV (b); + + /* Avoid overflow on big buffers */ + int percent = total > LONG_MAX/200 ? + (chars + total/200) / (total / 100) : + (chars * 100 + total/2) / max (total, 1); /* We can't normally display a 3-digit number, so get us a 2-digit number that is close. */ - if (total == 100) - total = 99; + if (percent == 100) + percent = 99; if (toppos <= BUF_BEGV (b)) - sprintf (buf, "Top%2d%%", total); + sprintf (buf, "Top%d%%", percent); else - sprintf (buf, "%2d%%", total); + sprintf (buf, "%d%%", percent); Dynarr_add_many (mode_spec_bufbyte_string, (Bufbyte *) buf, strlen (buf)); @@ -6084,7 +6997,7 @@ /* Given an array of display lines, free them and all data structures contained within them. */ -static void +void free_display_lines (display_line_dynarr *dla) { int line; @@ -6117,7 +7030,7 @@ static void -mark_glyph_block_dynarr (glyph_block_dynarr *gba, void (*markobj) (Lisp_Object)) +mark_glyph_block_dynarr (glyph_block_dynarr *gba) { if (gba) { @@ -6127,15 +7040,15 @@ for (; gb < gb_last; gb++) { if (!NILP (gb->glyph)) - markobj (gb->glyph); + mark_object (gb->glyph); if (!NILP (gb->extent)) - markobj (gb->extent); + mark_object (gb->extent); } } } static void -mark_redisplay_structs (display_line_dynarr *dla, void (*markobj) (Lisp_Object)) +mark_redisplay_structs (display_line_dynarr *dla) { display_line *dl = Dynarr_atp (dla, 0); display_line *dl_last = Dynarr_atp (dla, Dynarr_length (dla)); @@ -6157,35 +7070,35 @@ if (r->type == RUNE_DGLYPH) { if (!NILP (r->object.dglyph.glyph)) - markobj (r->object.dglyph.glyph); + mark_object (r->object.dglyph.glyph); if (!NILP (r->object.dglyph.extent)) - markobj (r->object.dglyph.extent); + mark_object (r->object.dglyph.extent); } } } - mark_glyph_block_dynarr (dl->left_glyphs, markobj); - mark_glyph_block_dynarr (dl->right_glyphs, markobj); + mark_glyph_block_dynarr (dl->left_glyphs); + mark_glyph_block_dynarr (dl->right_glyphs); } } static void -mark_window_mirror (struct window_mirror *mir, void (*markobj)(Lisp_Object)) -{ - mark_redisplay_structs (mir->current_display_lines, markobj); - mark_redisplay_structs (mir->desired_display_lines, markobj); +mark_window_mirror (struct window_mirror *mir) +{ + mark_redisplay_structs (mir->current_display_lines); + mark_redisplay_structs (mir->desired_display_lines); if (mir->next) - mark_window_mirror (mir->next, markobj); + mark_window_mirror (mir->next); if (mir->hchild) - mark_window_mirror (mir->hchild, markobj); + mark_window_mirror (mir->hchild); else if (mir->vchild) - mark_window_mirror (mir->vchild, markobj); + mark_window_mirror (mir->vchild); } void -mark_redisplay (void (*markobj)(Lisp_Object)) +mark_redisplay (void) { Lisp_Object frmcons, devcons, concons; @@ -6193,7 +7106,7 @@ { struct frame *f = XFRAME (XCAR (frmcons)); update_frame_window_mirror (f); - mark_window_mirror (f->root_mirror, markobj); + mark_window_mirror (f->root_mirror); } } @@ -6257,7 +7170,7 @@ /* This will get used quite a bit so we don't want to be constantly allocating and freeing it. */ -line_start_cache_dynarr *internal_cache; +static line_start_cache_dynarr *internal_cache; /* Makes internal_cache represent the TYPE display structs and only the TYPE display structs. */ @@ -6551,7 +7464,7 @@ point_would_be_visible (struct window *w, Bufpos startp, Bufpos point) { struct buffer *b = XBUFFER (w->buffer); - int pixpos = 0; + int pixpos = -WINDOW_TEXT_TOP_CLIP(w); int bottom = WINDOW_TEXT_HEIGHT (w); int start_elt; @@ -6776,7 +7689,7 @@ } cur_elt--; - if (cur_elt < 0) + while (cur_elt < 0) { Bufpos from, to; int win_char_height; @@ -6796,7 +7709,20 @@ update_line_start_cache (w, from, to, point, 0); cur_elt = point_in_line_start_cache (w, cur_pos, 2) - 1; - assert (cur_elt >= 0); + assert (cur_elt >= -1); + /* This used to be cur_elt>=0 under the assumption that if + point is in the top line and not at BUF_BEGV, then + setting the window_start to a newline before the start of + the first line will always cause scrolling. + + However in my (jv) opinion this is wrong. That new line + can be hidden in various ways: invisible extents, an + explicit window-start not at a newline character etc. + The existence of those are indeed known to create crashes + on that assert. So we have no option but to continue the + search if we found point at the top of the line_start_cache + again. */ + cur_pos = Dynarr_atp (w->line_start_cache,0)->start; } prev_pos = cur_pos; } @@ -8013,7 +8939,7 @@ { XFRAME (XCAR (frmcons))->clear = 1; } - redisplay_device (d); + redisplay_device (d, 0); return unbind_to (count, Qnil); } @@ -8040,7 +8966,7 @@ disable_preemption++; } - redisplay_device (d); + redisplay_device (d, 0); return unbind_to (count, Qnil); } @@ -8092,6 +9018,8 @@ return 0; } +/* This is called if the built-in glyphs have their properties + changed. */ void redisplay_glyph_changed (Lisp_Object glyph, Lisp_Object property, Lisp_Object locale) @@ -8214,16 +9142,22 @@ preemption_count = 0; max_preempts = INIT_MAX_PREEMPTS; +#ifndef PDUMP if (!initialized) - { - cmotion_display_lines = Dynarr_new (display_line); - mode_spec_bufbyte_string = Dynarr_new (Bufbyte); - formatted_string_emchar_dynarr = Dynarr_new (Emchar); - formatted_string_extent_dynarr = Dynarr_new (EXTENT); - formatted_string_extent_start_dynarr = Dynarr_new (Bytecount); - formatted_string_extent_end_dynarr = Dynarr_new (Bytecount); - internal_cache = Dynarr_new (line_start_cache); - xzero (formatted_string_display_line); +#endif + { + if (!cmotion_display_lines) + cmotion_display_lines = Dynarr_new (display_line); + if (!mode_spec_bufbyte_string) + mode_spec_bufbyte_string = Dynarr_new (Bufbyte); + if (!formatted_string_extent_dynarr) + formatted_string_extent_dynarr = Dynarr_new (EXTENT); + if (!formatted_string_extent_start_dynarr) + formatted_string_extent_start_dynarr = Dynarr_new (Bytecount); + if (!formatted_string_extent_end_dynarr) + formatted_string_extent_end_dynarr = Dynarr_new (Bytecount); + if (!internal_cache) + internal_cache = Dynarr_new (line_start_cache); } /* window system is nil when in -batch mode */ @@ -8294,7 +9228,6 @@ #endif /* INHIBIT_REDISPLAY_HOOKS */ defsymbol (&Qdisplay_warning_buffer, "display-warning-buffer"); defsymbol (&Qbar_cursor, "bar-cursor"); - defsymbol (&Qwindow_scroll_functions, "window-scroll-functions"); defsymbol (&Qredisplay_end_trigger_functions, "redisplay-end-trigger-functions"); @@ -8308,8 +9241,16 @@ } void +reinit_vars_of_redisplay (void) +{ + updating_line_start_cache = 0; +} + +void vars_of_redisplay (void) { + reinit_vars_of_redisplay (); + #if 0 staticpro (&last_arrow_position); staticpro (&last_arrow_string); @@ -8317,8 +9258,6 @@ last_arrow_string = Qnil; #endif /* 0 */ - updating_line_start_cache = 0; - /* #### Probably temporary */ DEFVAR_INT ("redisplay-cache-adjustment", &cache_adjustment /* \(Temporary) Setting this will impact the performance of the internal @@ -8403,7 +9342,7 @@ Vwindow_system = Qnil; /* #### Temporary shit until window-system is eliminated. */ - DEFVAR_LISP ("initial-window-system", &Vinitial_window_system /* + DEFVAR_CONST_LISP ("initial-window-system", &Vinitial_window_system /* DON'T TOUCH */ ); Vinitial_window_system = Qnil; @@ -8502,9 +9441,9 @@ Vleft_margin_width = Fmake_specifier (Qnatnum); set_specifier_fallback (Vleft_margin_width, list1 (Fcons (Qnil, Qzero))); set_specifier_caching (Vleft_margin_width, - slot_offset (struct window, left_margin_width), + offsetof (struct window, left_margin_width), some_window_value_changed, - slot_offset (struct frame, left_margin_width), + offsetof (struct frame, left_margin_width), margin_width_changed_in_frame); DEFVAR_SPECIFIER ("right-margin-width", &Vright_margin_width /* @@ -8514,9 +9453,9 @@ Vright_margin_width = Fmake_specifier (Qnatnum); set_specifier_fallback (Vright_margin_width, list1 (Fcons (Qnil, Qzero))); set_specifier_caching (Vright_margin_width, - slot_offset (struct window, right_margin_width), + offsetof (struct window, right_margin_width), some_window_value_changed, - slot_offset (struct frame, right_margin_width), + offsetof (struct frame, right_margin_width), margin_width_changed_in_frame); DEFVAR_SPECIFIER ("minimum-line-ascent", &Vminimum_line_ascent /* @@ -8526,7 +9465,7 @@ Vminimum_line_ascent = Fmake_specifier (Qnatnum); set_specifier_fallback (Vminimum_line_ascent, list1 (Fcons (Qnil, Qzero))); set_specifier_caching (Vminimum_line_ascent, - slot_offset (struct window, minimum_line_ascent), + offsetof (struct window, minimum_line_ascent), some_window_value_changed, 0, 0); @@ -8537,7 +9476,7 @@ Vminimum_line_descent = Fmake_specifier (Qnatnum); set_specifier_fallback (Vminimum_line_descent, list1 (Fcons (Qnil, Qzero))); set_specifier_caching (Vminimum_line_descent, - slot_offset (struct window, minimum_line_descent), + offsetof (struct window, minimum_line_descent), some_window_value_changed, 0, 0); @@ -8549,7 +9488,7 @@ Vuse_left_overflow = Fmake_specifier (Qboolean); set_specifier_fallback (Vuse_left_overflow, list1 (Fcons (Qnil, Qnil))); set_specifier_caching (Vuse_left_overflow, - slot_offset (struct window, use_left_overflow), + offsetof (struct window, use_left_overflow), some_window_value_changed, 0, 0); @@ -8561,7 +9500,7 @@ Vuse_right_overflow = Fmake_specifier (Qboolean); set_specifier_fallback (Vuse_right_overflow, list1 (Fcons (Qnil, Qnil))); set_specifier_caching (Vuse_right_overflow, - slot_offset (struct window, use_right_overflow), + offsetof (struct window, use_right_overflow), some_window_value_changed, 0, 0); @@ -8572,7 +9511,7 @@ Vtext_cursor_visible_p = Fmake_specifier (Qboolean); set_specifier_fallback (Vtext_cursor_visible_p, list1 (Fcons (Qnil, Qt))); set_specifier_caching (Vtext_cursor_visible_p, - slot_offset (struct window, text_cursor_visible_p), + offsetof (struct window, text_cursor_visible_p), text_cursor_visible_p_changed, 0, 0);