/* 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.
#endif
#endif /* not __GNU_LIBRARY__ */
-#if defined (LINUX) && defined (HAVE_LIBNCURSES)
+#if defined(HAVE_TERM_H) && defined (LINUX) && defined (HAVE_LIBNCURSES)
#include <term.h> /* for tgetent */
#endif
\f
\f
/* Function prototypes. */
-static void save_or_restore_current_matrix P_ ((struct frame *, int));
+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));
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_left_x == XFASTINT (w->left)
- && 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;
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;
}
}
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;
}
}
-/* Save or restore the contents of frame F's current frame matrix.
- SAVE_P non-zero means save it. */
+/* 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 void
-save_or_restore_current_matrix (f, save_p)
+static struct glyph_matrix *
+save_current_matrix (f)
struct frame *f;
- int save_p;
{
- struct glyph_row *from, *to, *end;
+ int i;
+ struct glyph_matrix *saved;
- if (save_p)
- {
- from = f->current_matrix->rows;
- end = from + f->current_matrix->nrows;
- to = f->desired_matrix->rows;
- }
- else
+ 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)
{
- from = f->desired_matrix->rows;
- end = from + f->desired_matrix->nrows;
- to = f->current_matrix->rows;
+ 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];
}
-
- for (; from < end; ++from, ++to)
+
+ 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. */
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);
-
/* 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
&& matrix_dim.width == f->current_matrix->matrix_w
&& matrix_dim.height == f->current_matrix->matrix_h)
{
- save_or_restore_current_matrix (f, 1);
+ 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);
- save_or_restore_current_matrix (f, 0);
+ 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);
}
|| 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. */
|| (!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. */
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
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);
{
struct glyph_row *row, *end;
struct glyph_row *mode_line_row;
- struct glyph_row *header_line_row = NULL;
+ struct glyph_row *header_line_row;
int yb, changed_p = 0, mouse_face_overwritten_p = 0, n_updated;
rif->update_window_begin_hook (w);
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);
goto set_cursor;
}
else if (rc > 0)
+ /* We've scrolled the display. */
force_p = 1;
changed_p = 1;
}
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;
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;
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;
/* 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)
/* 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;
}
}
/* 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
/* 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;
}
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.
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;
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)
{
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;
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;
*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;
}
return Qnil;
if (initial_display)
- redisplay_preserve_echo_area ();
+ redisplay_preserve_echo_area (2);
if (sec == 0 && usec == 0)
return Qt;
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,