X-Git-Url: http://git.hcoop.net/bpt/emacs.git/blobdiff_plain/2b4ec4d7cb3af8b048a7ef20be9ef6a36b61501f..6206f8ce21442d8003ecb68b930d908bc690a7f4:/src/dispnew.c diff --git a/src/dispnew.c b/src/dispnew.c index f16933b69b..abc41ad2a2 100644 --- a/src/dispnew.c +++ b/src/dispnew.c @@ -1,5 +1,5 @@ /* Updating of data structures for redisplay. - Copyright (C) 1985, 86, 87, 88, 93, 94, 95, 97, 98, 1999, 2000 + Copyright (C) 1985, 86, 87, 88, 93, 94, 95, 97, 98, 1999, 2000, 2001 Free Software Foundation, Inc. This file is part of GNU Emacs. @@ -104,7 +104,7 @@ Boston, MA 02111-1307, USA. */ #endif #endif /* not __GNU_LIBRARY__ */ -#if defined (LINUX) && defined (HAVE_LIBNCURSES) +#if defined(HAVE_TERM_H) && defined (LINUX) && defined (HAVE_LIBNCURSES) #include /* for tgetent */ #endif @@ -120,6 +120,9 @@ struct dim /* Function prototypes. */ +static struct glyph_matrix *save_current_matrix P_ ((struct frame *)); +static void restore_current_matrix P_ ((struct frame *, struct glyph_matrix *)); +static void fake_current_matrices P_ ((Lisp_Object)); static void redraw_overlapping_rows P_ ((struct window *, int)); static void redraw_overlapped_rows P_ ((struct window *, int)); static int count_blanks P_ ((struct glyph *, int)); @@ -139,7 +142,7 @@ static void adjust_glyph_matrix P_ ((struct window *, struct glyph_matrix *, int, int, struct dim)); static void change_frame_size_1 P_ ((struct frame *, int, int, int, int, int)); static void swap_glyph_pointers P_ ((struct glyph_row *, struct glyph_row *)); -#ifdef GLYPH_DEBUG +#if GLYPH_DEBUG static int glyph_row_slice_p P_ ((struct glyph_row *, struct glyph_row *)); #endif static void fill_up_frame_row_with_spaces P_ ((struct glyph_row *, int)); @@ -185,7 +188,6 @@ static int margin_glyphs_to_reserve P_ ((struct window *, int, Lisp_Object)); static void sync_window_with_frame_matrix_rows P_ ((struct window *)); struct window *frame_row_to_window P_ ((struct window *, int)); - /* Non-zero means don't pause redisplay for pending input. (This is for debugging and for a future implementation of EDT-like @@ -329,6 +331,105 @@ static int window_to_frame_hpos P_ ((struct window *, int)); #define WINDOW_TO_FRAME_VPOS(W, VPOS) window_to_frame_vpos ((W), (VPOS)) #define WINDOW_TO_FRAME_HPOS(W, HPOS) window_to_frame_hpos ((W), (HPOS)) +/* One element of the ring buffer containing redisplay history + information. */ + +struct redisplay_history +{ + char trace[512 + 100]; +}; + +/* The size of the history buffer. */ + +#define REDISPLAY_HISTORY_SIZE 30 + +/* The redisplay history buffer. */ + +static struct redisplay_history redisplay_history[REDISPLAY_HISTORY_SIZE]; + +/* Next free entry in redisplay_history. */ + +static int history_idx; + +/* A tick that's incremented each time something is added to the + history. */ + +static unsigned history_tick; + +static void add_frame_display_history P_ ((struct frame *, int)); +static void add_window_display_history P_ ((struct window *, char *, int)); + + +/* Add to the redisplay history how window W has been displayed. + MSG is a trace containing the information how W's glyph matrix + has been contructed. PAUSED_P non-zero means that the update + has been interrupted for pending input. */ + +static void +add_window_display_history (w, msg, paused_p) + struct window *w; + char *msg; + int paused_p; +{ + char *buf; + + if (history_idx >= REDISPLAY_HISTORY_SIZE) + history_idx = 0; + buf = redisplay_history[history_idx].trace; + ++history_idx; + + sprintf (buf, "%d: window %p (`%s')%s\n", + history_tick++, + w, + ((BUFFERP (w->buffer) + && STRINGP (XBUFFER (w->buffer)->name)) + ? (char *) XSTRING (XBUFFER (w->buffer)->name)->data + : "???"), + paused_p ? " ***paused***" : ""); + strcat (buf, msg); +} + + +/* Add to the redisplay history that frame F has been displayed. + PAUSED_P non-zero means that the update has been interrupted for + pending input. */ + +static void +add_frame_display_history (f, paused_p) + struct frame *f; + int paused_p; +{ + char *buf; + + if (history_idx >= REDISPLAY_HISTORY_SIZE) + history_idx = 0; + buf = redisplay_history[history_idx].trace; + ++history_idx; + + sprintf (buf, "%d: update frame %p%s", + history_tick++, + f, paused_p ? " ***paused***" : ""); +} + + +DEFUN ("dump-redisplay-history", Fdump_redisplay_history, + Sdump_redisplay_history, 0, 0, "", + "Dump redisplay history to stderr.") + () +{ + int i; + + for (i = history_idx - 1; i != history_idx; --i) + { + if (i < 0) + i = REDISPLAY_HISTORY_SIZE - 1; + fprintf (stderr, "%s\n", redisplay_history[i].trace); + } + + return Qnil; +} + + #else /* GLYPH_DEBUG == 0 */ #define WINDOW_TO_FRAME_VPOS(W, VPOS) ((VPOS) + XFASTINT ((W)->top)) @@ -550,6 +651,7 @@ adjust_glyph_matrix (w, matrix, x, y, dim) if (!marginal_areas_changed_p && !fonts_changed_p && !header_line_changed_p + && matrix->window_left_x == XFASTINT (w->left) && matrix->window_top_y == XFASTINT (w->top) && matrix->window_height == window_height && matrix->window_vscroll == w->vscroll @@ -673,43 +775,62 @@ adjust_glyph_matrix (w, matrix, x, y, dim) matrix->nrows = dim.height; xassert (matrix->nrows >= 0); - /* Mark rows in a current matrix of a window as not having valid - contents. It's important to not do this for desired matrices. - When Emacs starts, it may already be building desired matrices - when this function runs. */ - if (w && matrix == w->current_matrix) + if (w) { - if (window_width < 0) - window_width = window_box_width (w, -1); - - /* Optimize the case that only the height has changed (C-x 2, - upper window). Invalidate all rows that are no longer part - of the window. */ - if (!marginal_areas_changed_p - && matrix->window_top_y == XFASTINT (w->top) - && matrix->window_width == window_box_width (w, -1)) + if (matrix == w->current_matrix) { - i = 0; - while (matrix->rows[i].enabled_p - && (MATRIX_ROW_BOTTOM_Y (matrix->rows + i) - < matrix->window_height)) - ++i; - - /* Window end is invalid, if inside of the rows that - are invalidated. */ - if (INTEGERP (w->window_end_vpos) - && XFASTINT (w->window_end_vpos) >= i) - w->window_end_valid = Qnil; + /* Mark rows in a current matrix of a window as not having + valid contents. It's important to not do this for + desired matrices. When Emacs starts, it may already be + building desired matrices when this function runs. */ + if (window_width < 0) + window_width = window_box_width (w, -1); + + /* Optimize the case that only the height has changed (C-x 2, + upper window). Invalidate all rows that are no longer part + of the window. */ + if (!marginal_areas_changed_p + && !header_line_changed_p + && new_rows == 0 + && dim.width == matrix->matrix_w + && matrix->window_left_x == XFASTINT (w->left) + && matrix->window_top_y == XFASTINT (w->top) + && matrix->window_width == window_width) + { + /* Find the last row in the window. */ + for (i = 0; i < matrix->nrows && matrix->rows[i].enabled_p; ++i) + if (MATRIX_ROW_BOTTOM_Y (matrix->rows + i) >= window_height) + { + ++i; + break; + } + + /* Window end is invalid, if inside of the rows that + are invalidated below. */ + if (INTEGERP (w->window_end_vpos) + && XFASTINT (w->window_end_vpos) >= i) + w->window_end_valid = Qnil; - while (i < matrix->nrows) - matrix->rows[i++].enabled_p = 0; + while (i < matrix->nrows) + matrix->rows[i++].enabled_p = 0; + } + else + { + for (i = 0; i < matrix->nrows; ++i) + matrix->rows[i].enabled_p = 0; + } } - else + else if (matrix == w->desired_matrix) { + /* Rows in desired matrices always have to be cleared; + redisplay expects this is the case when it runs, so it + had better be the case when we adjust matrices between + redisplays. */ for (i = 0; i < matrix->nrows; ++i) matrix->rows[i].enabled_p = 0; } } + /* Remember last values to be able to optimize frame redraws. */ matrix->matrix_x = x; @@ -721,6 +842,7 @@ adjust_glyph_matrix (w, matrix, x, y, dim) was last adjusted. This is used to optimize redisplay above. */ if (w) { + matrix->window_left_x = XFASTINT (w->left); matrix->window_top_y = XFASTINT (w->top); matrix->window_height = window_height; matrix->window_width = window_width; @@ -872,13 +994,12 @@ shift_glyph_matrix (w, matrix, start, end, dy) struct glyph_row *row = &matrix->rows[start]; row->y += dy; + row->visible_height = row->height; if (row->y < min_y) - row->visible_height = row->height - (min_y - row->y); - else if (row->y + row->height > max_y) - row->visible_height = row->height - (row->y + row->height - max_y); - else - row->visible_height = row->height; + row->visible_height -= min_y - row->y; + if (row->y + row->height > max_y) + row->visible_height -= row->y + row->height - max_y; } } @@ -1032,13 +1153,12 @@ blank_row (w, row, y) row->y = y; row->ascent = row->phys_ascent = 0; row->height = row->phys_height = CANON_Y_UNIT (XFRAME (w->frame)); - + row->visible_height = row->height; + if (row->y < min_y) - row->visible_height = row->height - (min_y - row->y); - else if (row->y + row->height > max_y) - row->visible_height = row->height - (row->y + row->height - max_y); - else - row->visible_height = row->height; + row->visible_height -= min_y - row->y; + if (row->y + row->height > max_y) + row->visible_height -= row->y + row->height - max_y; row->enabled_p = 1; } @@ -1201,7 +1321,7 @@ assign_row (to, from) is non-zero if the glyph memory of WINDOW_ROW is part of the glyph memory of FRAME_ROW. */ -#ifdef GLYPH_DEBUG +#if GLYPH_DEBUG static int glyph_row_slice_p (window_row, frame_row) @@ -1998,6 +2118,115 @@ adjust_frame_glyphs (f) } +/* In the window tree with root W, build current matrices of leaf + windows from the frame's current matrix. */ + +static void +fake_current_matrices (window) + Lisp_Object window; +{ + struct window *w; + + for (; !NILP (window); window = w->next) + { + w = XWINDOW (window); + + if (!NILP (w->hchild)) + fake_current_matrices (w->hchild); + else if (!NILP (w->vchild)) + fake_current_matrices (w->vchild); + else + { + int i; + struct frame *f = XFRAME (w->frame); + struct glyph_matrix *m = w->current_matrix; + struct glyph_matrix *fm = f->current_matrix; + + xassert (m->matrix_h == XFASTINT (w->height)); + xassert (m->matrix_w == XFASTINT (w->width)); + + for (i = 0; i < m->matrix_h; ++i) + { + struct glyph_row *r = m->rows + i; + struct glyph_row *fr = fm->rows + i + XFASTINT (w->top); + + xassert (r->glyphs[TEXT_AREA] >= fr->glyphs[TEXT_AREA] + && r->glyphs[LAST_AREA] <= fr->glyphs[LAST_AREA]); + + r->enabled_p = fr->enabled_p; + if (r->enabled_p) + { + r->used[LEFT_MARGIN_AREA] = m->left_margin_glyphs; + r->used[RIGHT_MARGIN_AREA] = m->right_margin_glyphs; + r->used[TEXT_AREA] = (m->matrix_w + - r->used[LEFT_MARGIN_AREA] + - r->used[RIGHT_MARGIN_AREA]); + r->mode_line_p = 0; + r->inverse_p = fr->inverse_p; + } + } + } + } +} + + +/* Save away the contents of frame F's current frame matrix. Value is + a glyph matrix holding the contents of F's current frame matrix. '*/ + +static struct glyph_matrix * +save_current_matrix (f) + struct frame *f; +{ + int i; + struct glyph_matrix *saved; + + saved = (struct glyph_matrix *) xmalloc (sizeof *saved); + bzero (saved, sizeof *saved); + saved->nrows = f->current_matrix->nrows; + saved->rows = (struct glyph_row *) xmalloc (saved->nrows + * sizeof *saved->rows); + bzero (saved->rows, saved->nrows * sizeof *saved->rows); + + for (i = 0; i < saved->nrows; ++i) + { + struct glyph_row *from = f->current_matrix->rows + i; + struct glyph_row *to = saved->rows + i; + size_t nbytes = from->used[TEXT_AREA] * sizeof (struct glyph); + to->glyphs[TEXT_AREA] = (struct glyph *) xmalloc (nbytes); + bcopy (from->glyphs[TEXT_AREA], to->glyphs[TEXT_AREA], nbytes); + to->used[TEXT_AREA] = from->used[TEXT_AREA]; + } + + return saved; +} + + +/* Restore the contents of frame F's current frame matrix from SAVED, + and free memory associated with SAVED. */ + +static void +restore_current_matrix (f, saved) + struct frame *f; + struct glyph_matrix *saved; +{ + int i; + + for (i = 0; i < saved->nrows; ++i) + { + struct glyph_row *from = saved->rows + i; + struct glyph_row *to = f->current_matrix->rows + i; + size_t nbytes = from->used[TEXT_AREA] * sizeof (struct glyph); + bcopy (from->glyphs[TEXT_AREA], to->glyphs[TEXT_AREA], nbytes); + to->used[TEXT_AREA] = from->used[TEXT_AREA]; + xfree (from->glyphs[TEXT_AREA]); + } + + xfree (saved->rows); + xfree (saved); +} + + + /* Allocate/reallocate glyph matrices of a single frame F for frame-based redisplay. */ @@ -2033,7 +2262,7 @@ adjust_frame_glyphs_for_frame_redisplay (f) f->desired_matrix = new_glyph_matrix (f->desired_pool); f->current_matrix = new_glyph_matrix (f->current_pool); } - + /* Compute window glyph matrices. (This takes the mini-buffer window into account). The result is the size of the frame glyph matrix needed. The variable window_change_flags is set to a bit @@ -2069,14 +2298,32 @@ adjust_frame_glyphs_for_frame_redisplay (f) xassert (matrix_dim.width == FRAME_WIDTH (f) && matrix_dim.height == FRAME_HEIGHT (f)); - /* Resize frame matrices. */ - adjust_glyph_matrix (NULL, f->desired_matrix, 0, 0, matrix_dim); - adjust_glyph_matrix (NULL, f->current_matrix, 0, 0, matrix_dim); - - /* Since location and size of sub-matrices within the pool may - have changed, and current matrices don't have meaningful - contents anymore, mark the frame garbaged. */ - SET_FRAME_GARBAGED (f); + /* Pointers to glyph memory in glyph rows are exchanged during + the update phase of redisplay, which means in general that a + frame's current matrix consists of pointers into both the + desired and current glyph pool of the frame. Adjusting a + matrix sets the frame matrix up so that pointers are all into + the same pool. If we want to preserve glyph contents of the + current matrix over a call to adjust_glyph_matrix, we must + make a copy of the current glyphs, and restore the current + matrix' contents from that copy. */ + if (display_completed + && !FRAME_GARBAGED_P (f) + && matrix_dim.width == f->current_matrix->matrix_w + && matrix_dim.height == f->current_matrix->matrix_h) + { + struct glyph_matrix *copy = save_current_matrix (f); + adjust_glyph_matrix (NULL, f->desired_matrix, 0, 0, matrix_dim); + adjust_glyph_matrix (NULL, f->current_matrix, 0, 0, matrix_dim); + restore_current_matrix (f, copy); + fake_current_matrices (FRAME_ROOT_WINDOW (f)); + } + else + { + adjust_glyph_matrix (NULL, f->desired_matrix, 0, 0, matrix_dim); + adjust_glyph_matrix (NULL, f->current_matrix, 0, 0, matrix_dim); + SET_FRAME_GARBAGED (f); + } } } @@ -2505,29 +2752,6 @@ build_frame_matrix_from_leaf_window (frame_matrix, w) SET_CHAR_GLYPH_FROM_GLYPH (*border, right_border_glyph); } -#if 0 /* This shouldn't be necessary. Let's check it. */ - /* Due to hooks installed, it normally doesn't happen that - window rows and frame rows of the same matrix are out of - sync, i.e. have a different understanding of where to - find glyphs for the row. The following is a safety-belt - that doesn't cost much and makes absolutely sure that - window and frame matrices are in sync. */ - if (!glyph_row_slice_p (window_row, frame_row)) - { - /* Find the row in the window being a slice. There - should exist one from program logic. */ - struct glyph_row *slice_row - = find_glyph_row_slice (window_matrix, frame_matrix, frame_y); - xassert (slice_row != 0); - - /* Exchange glyphs between both window rows. */ - swap_glyphs_in_rows (window_row, slice_row); - - /* Exchange pointers between both rows. */ - swap_glyph_pointers (window_row, slice_row); - } -#endif - /* Window row window_y must be a slice of frame row frame_y. */ xassert (glyph_row_slice_p (window_row, frame_row)); @@ -2537,6 +2761,7 @@ build_frame_matrix_from_leaf_window (frame_matrix, w) #if GLYPH_DEBUG strcpy (w->current_matrix->method, w->desired_matrix->method); + add_window_display_history (w, w->current_matrix->method, 0); #endif } @@ -3177,8 +3402,10 @@ direct_output_for_insert (g) || !display_completed /* Give up if buffer appears in two places. */ || buffer_shared > 1 - /* Give up if w is mini-buffer and a message is being displayed there */ - || (MINI_WINDOW_P (w) && !NILP (echo_area_buffer[0])) + /* Give up if currently displaying a message instead of the + minibuffer contents. */ + || (EQ (selected_window, minibuf_window) + && EQ (minibuf_window, echo_area_window)) /* Give up for hscrolled mini-buffer because display of the prompt is handled specially there (see display_line). */ || (MINI_WINDOW_P (w) && XFASTINT (w->hscroll)) @@ -3192,6 +3419,10 @@ direct_output_for_insert (g) || g == '\r' /* Give up if unable to display the cursor in the window. */ || w->cursor.vpos < 0 + /* Give up if we are showing a message or just cleared the message + because we might need to resize the echo area window. */ + || !NILP (echo_area_buffer[0]) + || !NILP (echo_area_buffer[1]) || (glyph_row = MATRIX_ROW (w->current_matrix, w->cursor.vpos), /* Can't do it in a continued line because continuation lines would change. */ @@ -3206,6 +3437,12 @@ direct_output_for_insert (g) || (!window_redisplay_p && !WINDOW_FULL_WIDTH_P (w))) return 0; + /* If we can't insert glyphs, we can use this method only + at the end of a line. */ + if (!char_ins_del_ok) + if (PT != ZV && FETCH_BYTE (PT_BYTE) != '\n') + return 0; + /* Set up a display iterator structure for W. Glyphs will be produced in scratch_glyph_row. Current position is W's cursor position. */ @@ -3245,6 +3482,7 @@ direct_output_for_insert (g) it.current_y = w->cursor.y; it.end_charpos = PT; it.stop_charpos = min (PT, it.stop_charpos); + it.stop_charpos = max (IT_CHARPOS (it), it.stop_charpos); /* More than one display element may be returned for PT - 1 if (i) it's a control character which is translated into `\003' or @@ -3349,12 +3587,16 @@ direct_output_for_insert (g) implemented for X frames. The implementation uses updated_window and updated_row. */ updated_row = glyph_row; + updated_area = TEXT_AREA; update_begin (f); if (rif) { rif->update_window_begin_hook (w); - if (glyphs == end - n) + if (glyphs == end - n + /* In front of a space added by append_space. */ + || (glyphs == end - n - 1 + && (end - n)->charpos <= 0)) rif->write_glyphs (glyphs, n); else rif->insert_glyphs (glyphs, n); @@ -3587,7 +3829,10 @@ update_frame (f, force_p, inhibit_hairy_id_p) fflush (stdout); /* Check window matrices for lost pointers. */ - IF_DEBUG (check_window_matrix_pointers (root_window)); +#if GLYPH_DEBUG + check_window_matrix_pointers (root_window); + add_frame_display_history (f, paused_p); +#endif } /* Reset flags indicating that a window should be updated. */ @@ -3751,6 +3996,31 @@ redraw_overlapping_rows (w, yb) } +#ifdef GLYPH_DEBUG + +/* Check that no row in the current matrix of window W is enabled + which is below what's displayed in the window. */ + +void +check_current_matrix_flags (w) + struct window *w; +{ + int last_seen_p = 0; + int i, yb = window_text_bottom_y (w); + + for (i = 0; i < w->current_matrix->nrows - 1; ++i) + { + struct glyph_row *row = MATRIX_ROW (w->current_matrix, i); + if (!last_seen_p && MATRIX_ROW_BOTTOM_Y (row) >= yb) + last_seen_p = 1; + else if (last_seen_p && row->enabled_p) + abort (); + } +} + +#endif /* GLYPH_DEBUG */ + + /* Update display of window W. FORCE_P non-zero means that we should not stop when detecting pending input. */ @@ -3763,6 +4033,7 @@ update_window (w, force_p) int paused_p; int preempt_count = baud_rate / 2400 + 1; extern int input_pending; + extern Lisp_Object do_mouse_tracking; #if GLYPH_DEBUG struct frame *f = XFRAME (WINDOW_FRAME (w)); extern struct frame *updating_frame; @@ -3780,12 +4051,12 @@ update_window (w, force_p) /* If forced to complete the update, or if no input is pending, do the update. */ - if (force_p || !input_pending) + if (force_p || !input_pending || !NILP (do_mouse_tracking)) { struct glyph_row *row, *end; struct glyph_row *mode_line_row; - struct glyph_row *header_line_row = NULL; - int yb, changed_p = 0, mouse_face_overwritten_p = 0; + struct glyph_row *header_line_row; + int yb, changed_p = 0, mouse_face_overwritten_p = 0, n_updated; rif->update_window_begin_hook (w); yb = window_text_bottom_y (w); @@ -3794,8 +4065,14 @@ update_window (w, force_p) Adjust y-positions of other rows by the top line height. */ row = desired_matrix->rows; end = row + desired_matrix->nrows - 1; + if (row->mode_line_p) - header_line_row = row++; + { + header_line_row = row; + ++row; + } + else + header_line_row = NULL; /* Update the mode line, if necessary. */ mode_line_row = MATRIX_MODE_LINE_ROW (desired_matrix); @@ -3825,6 +4102,7 @@ update_window (w, force_p) goto set_cursor; } else if (rc > 0) + /* We've scrolled the display. */ force_p = 1; changed_p = 1; } @@ -3840,7 +4118,7 @@ update_window (w, force_p) } /* Update the rest of the lines. */ - for (; row < end && (force_p || !input_pending); ++row) + for (n_updated = 0; row < end && (force_p || !input_pending); ++row) if (row->enabled_p) { int vpos = MATRIX_ROW_VPOS (row, desired_matrix); @@ -3850,7 +4128,7 @@ update_window (w, force_p) detect_input_pending. If it's done too often, scrolling large windows with repeated scroll-up commands will too quickly pause redisplay. */ - if (!force_p && vpos % preempt_count == 0) + if (!force_p && ++n_updated % preempt_count == 0) detect_input_pending (); changed_p |= update_window_line (w, vpos, @@ -3898,12 +4176,20 @@ update_window (w, force_p) strcpy (w->current_matrix->method, w->desired_matrix->method); #endif - /* End of update of window W. */ - rif->update_window_end_hook (w, 1, mouse_face_overwritten_p); + /* End the update of window W. Don't set the cursor if we + paused updating the display because in this case, + set_window_cursor_after_update hasn't been called, and + output_cursor doesn't contain the cursor location. */ + rif->update_window_end_hook (w, !paused_p, mouse_face_overwritten_p); } else paused_p = 1; +#if GLYPH_DEBUG + /* check_current_matrix_flags (w); */ + add_window_display_history (w, w->current_matrix->method, paused_p); +#endif + clear_glyph_matrix (desired_matrix); return paused_p; @@ -3978,18 +4264,20 @@ update_text_area (w, vpos) struct glyph *current_glyph = current_row->glyphs[TEXT_AREA]; struct glyph *desired_glyph = desired_row->glyphs[TEXT_AREA]; int overlapping_glyphs_p = current_row->contains_overlapping_glyphs_p; + int desired_stop_pos = desired_row->used[TEXT_AREA]; /* If the desired row extends its face to the text area end, make sure we write at least one glyph, so that the face extension actually takes place. */ - int desired_stop_pos = (desired_row->used[TEXT_AREA] - - (MATRIX_ROW_EXTENDS_FACE_P (desired_row) - ? 1 : 0)); + if (MATRIX_ROW_EXTENDS_FACE_P (desired_row)) + --desired_stop_pos; stop = min (current_row->used[TEXT_AREA], desired_stop_pos); i = 0; x = desired_row->x; - + + /* Loop over glyphs that current and desired row may have + in common. */ while (i < stop) { int can_skip_p = 1; @@ -4252,22 +4540,21 @@ set_window_cursor_after_update (w) int yb = window_text_bottom_y (w); last_row = NULL; - for (row = MATRIX_ROW (w->current_matrix, 0); - row->enabled_p; - ++row) + row = w->current_matrix->rows; + while (row->enabled_p + && (last_row == NULL + || MATRIX_ROW_BOTTOM_Y (row) <= yb)) { if (row->used[TEXT_AREA] && row->glyphs[TEXT_AREA][0].charpos >= 0) last_row = row; - - if (MATRIX_ROW_BOTTOM_Y (row) >= yb) - break; + ++row; } if (last_row) { - struct glyph *start = row->glyphs[TEXT_AREA]; - struct glyph *last = start + row->used[TEXT_AREA] - 1; + struct glyph *start = last_row->glyphs[TEXT_AREA]; + struct glyph *last = start + last_row->used[TEXT_AREA] - 1; while (last > start && last->charpos < 0) --last; @@ -4496,9 +4783,15 @@ scrolling_window (w, header_line_p) we plan to reuse part of the display even if other parts are disabled. */ i = first_old + 1; - while (i < current_matrix->nrows - 1 - && MATRIX_ROW_BOTTOM_Y (MATRIX_ROW (current_matrix, i)) <= yb) - ++i; + while (i < current_matrix->nrows - 1) + { + int bottom = MATRIX_ROW_BOTTOM_Y (MATRIX_ROW (current_matrix, i)); + if (bottom <= yb) + ++i; + if (bottom >= yb) + break; + } + last_old = i; /* Skip over rows equal at the bottom. */ @@ -5060,20 +5353,20 @@ extern int *char_ins_del_vector; /* Perform a frame-based update on line VPOS in frame FRAME. */ static void -update_frame_line (frame, vpos) - register struct frame *frame; +update_frame_line (f, vpos) + struct frame *f; int vpos; { struct glyph *obody, *nbody, *op1, *op2, *np1, *nend; int tem; int osp, nsp, begmatch, endmatch, olen, nlen; - struct glyph_matrix *current_matrix = frame->current_matrix; - struct glyph_matrix *desired_matrix = frame->desired_matrix; + struct glyph_matrix *current_matrix = f->current_matrix; + struct glyph_matrix *desired_matrix = f->desired_matrix; struct glyph_row *current_row = MATRIX_ROW (current_matrix, vpos); struct glyph_row *desired_row = MATRIX_ROW (desired_matrix, vpos); int must_write_whole_line_p; int write_spaces_p = must_write_spaces; - int colored_spaces_p = (FACE_FROM_ID (frame, DEFAULT_FACE_ID)->background + int colored_spaces_p = (FACE_FROM_ID (f, DEFAULT_FACE_ID)->background != FACE_TTY_DEFAULT_BG_COLOR); if (colored_spaces_p) @@ -5114,7 +5407,7 @@ update_frame_line (frame, vpos) /* For an inverse-video line, make sure it's filled with spaces all the way to the frame edge so that the reverse video extends all the way across. */ - while (olen < FRAME_WIDTH (frame) - 1) + while (olen < FRAME_WIDTH (f) - 1) obody[olen++] = space_glyph; } } @@ -5152,10 +5445,10 @@ update_frame_line (frame, vpos) /* Don't call clear_end_of_line if we already wrote the whole line. The cursor will not be at the right margin in that case but in the line below. */ - if (nlen < FRAME_WINDOW_WIDTH (frame)) + if (nlen < FRAME_WINDOW_WIDTH (f)) { cursor_to (vpos, nlen); - clear_end_of_line (FRAME_WINDOW_WIDTH (frame)); + clear_end_of_line (FRAME_WINDOW_WIDTH (f)); } else /* Make sure we are in the right row, otherwise cursor movement @@ -5179,7 +5472,7 @@ update_frame_line (frame, vpos) /* For an inverse-video line, give it extra trailing spaces all the way to the frame edge so that the reverse video extends all the way across. */ - while (nlen < FRAME_WIDTH (frame) - 1) + while (nlen < FRAME_WIDTH (f) - 1) nbody[nlen++] = space_glyph; } @@ -5289,7 +5582,7 @@ update_frame_line (frame, vpos) tem = (nlen - nsp) - (olen - osp); if (endmatch && tem - && (!char_ins_del_ok || endmatch <= char_ins_del_cost (frame)[tem])) + && (!char_ins_del_ok || endmatch <= char_ins_del_cost (f)[tem])) endmatch = 0; /* nsp - osp is the distance to insert or delete. @@ -5299,7 +5592,7 @@ update_frame_line (frame, vpos) if (nsp != osp && (!char_ins_del_ok - || begmatch + endmatch <= char_ins_del_cost (frame)[nsp - osp])) + || begmatch + endmatch <= char_ins_del_cost (f)[nsp - osp])) { begmatch = 0; endmatch = 0; @@ -5333,16 +5626,23 @@ update_frame_line (frame, vpos) tem = nsp + begmatch + endmatch; if (nlen != tem || olen != tem) { - cursor_to (vpos, nsp + begmatch); if (!endmatch || nlen == olen) { - /* If new text being written reaches right margin, - there is no need to do clear-to-eol at the end. - (and it would not be safe, since cursor is not - going to be "at the margin" after the text is done) */ - if (nlen == FRAME_WINDOW_WIDTH (frame)) + /* If new text being written reaches right margin, there is + no need to do clear-to-eol at the end of this function + (and it would not be safe, since cursor is not going to + be "at the margin" after the text is done). */ + if (nlen == FRAME_WINDOW_WIDTH (f)) olen = 0; - write_glyphs (nbody + nsp + begmatch, nlen - tem); + + /* Function write_glyphs is prepared to do nothing + if passed a length <= 0. Check it here to avoid + unnecessary cursor movement. */ + if (nlen - tem > 0) + { + cursor_to (vpos, nsp + begmatch); + write_glyphs (nbody + nsp + begmatch, nlen - tem); + } } else if (nlen > olen) { @@ -5356,18 +5656,25 @@ update_frame_line (frame, vpos) int out = olen - tem; /* Columns to be overwritten originally. */ int del; + cursor_to (vpos, nsp + begmatch); + /* Calculate columns we can actually overwrite. */ - while (CHAR_GLYPH_PADDING_P (nbody[nsp + begmatch + out])) out--; + while (CHAR_GLYPH_PADDING_P (nbody[nsp + begmatch + out])) + out--; write_glyphs (nbody + nsp + begmatch, out); + /* If we left columns to be overwritten, we must delete them. */ del = olen - tem - out; - if (del > 0) delete_glyphs (del); + if (del > 0) + delete_glyphs (del); + /* At last, we insert columns not yet written out. */ insert_glyphs (nbody + nsp + begmatch + out, nlen - olen + del); olen = nlen; } else if (olen > nlen) { + cursor_to (vpos, nsp + begmatch); write_glyphs (nbody + nsp + begmatch, nlen - tem); delete_glyphs (olen - nlen); olen = nlen; @@ -5392,14 +5699,17 @@ update_frame_line (frame, vpos) X/Y Position -> Buffer Position ***********************************************************************/ -/* Return the character position of the character at window relative - pixel position (*X, *Y). *X and *Y are adjusted to character - boundaries. */ +/* Determine what's under window-relative pixel position (*X, *Y). + Return in *OBJECT the object (string or buffer) that's there. + Return in *POS the position in that object. Adjust *X and *Y + to character boundaries. */ -int -buffer_posn_from_coords (w, x, y) +void +buffer_posn_from_coords (w, x, y, object, pos) struct window *w; int *x, *y; + Lisp_Object *object; + struct display_pos *pos; { struct it it; struct buffer *old_current_buffer = current_buffer; @@ -5419,7 +5729,9 @@ buffer_posn_from_coords (w, x, y) *x = it.current_x - it.first_visible_x + left_area_width; *y = it.current_y; current_buffer = old_current_buffer; - return IT_CHARPOS (it); + + *object = STRINGP (it.string) ? it.string : w->buffer; + *pos = it.current; } @@ -5888,7 +6200,7 @@ sit_for (sec, usec, reading, display, initial_display) return Qnil; if (initial_display) - redisplay_preserve_echo_area (); + redisplay_preserve_echo_area (2); if (sec == 0 && usec == 0) return Qt; @@ -6288,6 +6600,10 @@ syms_of_display () defsubr (&Sinternal_show_cursor); defsubr (&Sinternal_show_cursor_p); +#if GLYPH_DEBUG + defsubr (&Sdump_redisplay_history); +#endif + frame_and_buffer_state = Fmake_vector (make_number (20), Qlambda); staticpro (&frame_and_buffer_state); @@ -6331,8 +6647,9 @@ If not nil, this is a vector indexed by glyph code to define the glyph.\n\ Each element can be:\n\ integer: a glyph code which this glyph is an alias for.\n\ string: output this glyph using that string (not impl. in X windows).\n\ - nil: this glyph mod 256 is char code to output,\n\ - and this glyph / 256 is face code for X windows (see `face-id')."); + nil: this glyph mod 524288 is the code of a character to output,\n\ + and this glyph / 524288 is the face number (see `face-id') to use\n\ + while outputting it."); Vglyph_table = Qnil; DEFVAR_LISP ("standard-display-table", &Vstandard_display_table,