#define CLEAR_FACE_CACHE_COUNT 500
static int clear_face_cache_count;
+/* Similarly for the image cache. */
+
+#ifdef HAVE_WINDOW_SYSTEM
+#define CLEAR_IMAGE_CACHE_COUNT 101
+static int clear_image_cache_count;
+#endif
+
/* Record the previous terminal frame we displayed. */
static struct frame *previous_terminal_frame;
static int invisible_text_between_p P_ ((struct it *, int, int));
#endif
-static int next_element_from_ellipsis P_ ((struct it *));
static void pint2str P_ ((char *, int, int));
static void pint2hrstr P_ ((char *, int, int));
static struct text_pos run_window_scroll_functions P_ ((Lisp_Object,
Lisp_Object));
static void extend_face_to_end_of_line P_ ((struct it *));
static int append_space_for_newline P_ ((struct it *, int));
-static int make_cursor_line_fully_visible P_ ((struct window *, int));
+static int cursor_row_fully_visible_p P_ ((struct window *, int, int));
static int try_scrolling P_ ((Lisp_Object, int, EMACS_INT, EMACS_INT, int, int));
static int try_cursor_movement P_ ((Lisp_Object, struct text_pos, int *));
static int trailing_whitespace_p P_ ((int));
static void back_to_previous_visible_line_start P_ ((struct it *));
void reseat_at_previous_visible_line_start P_ ((struct it *));
static void reseat_at_next_visible_line_start P_ ((struct it *, int));
+static int next_element_from_ellipsis P_ ((struct it *));
static int next_element_from_display_vector P_ ((struct it *));
static int next_element_from_string P_ ((struct it *));
static int next_element_from_c_string P_ ((struct it *));
}
-/* Return 1 if position CHARPOS is visible in window W. Set *FULLY to
- 1 if POS is visible and the line containing POS is fully visible.
+/* Return 1 if position CHARPOS is visible in window W.
+ If visible, set *X and *Y to pixel coordinates of top left corner.
+ Set *RTOP and *RBOT to pixel height of an invisible area of glyph at POS.
EXACT_MODE_LINE_HEIGHTS_P non-zero means compute exact mode-line
and header-lines heights. */
int
-pos_visible_p (w, charpos, fully, x, y, exact_mode_line_heights_p)
+pos_visible_p (w, charpos, x, y, rtop, rbot, exact_mode_line_heights_p)
struct window *w;
- int charpos, *fully, *x, *y, exact_mode_line_heights_p;
+ int charpos, *x, *y, *rtop, *rbot, exact_mode_line_heights_p;
{
struct it it;
struct text_pos top;
- int visible_p;
+ int visible_p = 0;
struct buffer *old_buffer = NULL;
+ if (noninteractive)
+ return visible_p;
+
if (XBUFFER (w->buffer) != current_buffer)
{
old_buffer = current_buffer;
set_buffer_internal_1 (XBUFFER (w->buffer));
}
- *fully = visible_p = 0;
SET_TEXT_POS_FROM_MARKER (top, w->start);
/* Compute exact mode line heights, if requested. */
}
start_display (&it, w, top);
- move_it_to (&it, charpos, 0, it.last_visible_y, -1,
- MOVE_TO_POS | MOVE_TO_X | MOVE_TO_Y);
+ move_it_to (&it, charpos, -1, it.last_visible_y, -1,
+ MOVE_TO_POS | MOVE_TO_Y);
/* Note that we may overshoot because of invisible text. */
if (IT_CHARPOS (it) >= charpos)
{
int top_y = it.current_y;
- int bottom_y = line_bottom_y (&it);
+ int bottom_y = (last_height = 0, line_bottom_y (&it));
int window_top_y = WINDOW_HEADER_LINE_HEIGHT (w);
if (top_y < window_top_y)
visible_p = bottom_y > window_top_y;
else if (top_y < it.last_visible_y)
- {
visible_p = 1;
- *fully = bottom_y <= it.last_visible_y;
- }
if (visible_p && x)
{
*x = it.current_x;
- *y = max (top_y + it.max_ascent - it.ascent, window_top_y);
+ *y = max (top_y + max (0, it.max_ascent - it.ascent), window_top_y);
+ if (rtop)
+ {
+ *rtop = max (0, window_top_y - top_y);
+ *rbot = max (0, bottom_y - it.last_visible_y);
+ }
}
}
- else if (it.current_y + it.max_ascent + it.max_descent > it.last_visible_y)
+ else
{
struct it it2;
it2 = it;
- move_it_by_lines (&it, 1, 0);
+ if (IT_CHARPOS (it) < ZV && FETCH_BYTE (IT_BYTEPOS (it)) != '\n')
+ move_it_by_lines (&it, 1, 0);
if (charpos < IT_CHARPOS (it))
{
visible_p = 1;
move_it_to (&it2, charpos, -1, -1, -1, MOVE_TO_POS);
*x = it2.current_x;
*y = it2.current_y + it2.max_ascent - it2.ascent;
+ if (rtop)
+ {
+ *rtop = max (0, -it2.current_y);
+ *rbot = max (0, ((it2.current_y + it2.max_ascent + it2.max_descent)
+ - it.last_visible_y));
+ }
}
}
}
r.height = s->row->visible_height;
}
+ if (s->clip_head)
+ if (r.x < s->clip_head->x)
+ {
+ if (r.width >= s->clip_head->x - r.x)
+ r.width -= s->clip_head->x - r.x;
+ else
+ r.width = 0;
+ r.x = s->clip_head->x;
+ }
+ if (s->clip_tail)
+ if (r.x + r.width > s->clip_tail->x + s->clip_tail->background_width)
+ {
+ if (s->clip_tail->x + s->clip_tail->background_width >= r.x)
+ r.width = s->clip_tail->x + s->clip_tail->background_width - r.x;
+ else
+ r.width = 0;
+ }
+
/* If S draws overlapping rows, it's sufficient to use the top and
bottom of the window for clipping because this glyph string
intentionally draws over other lines. */
if (s->hl == DRAW_CURSOR)
{
struct glyph *glyph = s->first_glyph;
- int height;
+ int height, max_y;
if (s->x > r.x)
{
}
r.width = min (r.width, glyph->pixel_width);
- /* Don't draw cursor glyph taller than our actual glyph. */
- height = max (FRAME_LINE_HEIGHT (s->f), glyph->ascent + glyph->descent);
- if (height < r.height)
+ /* If r.y is below window bottom, ensure that we still see a cursor. */
+ height = min (glyph->ascent + glyph->descent,
+ min (FRAME_LINE_HEIGHT (s->f), s->row->visible_height));
+ max_y = window_text_bottom_y (s->w) - height;
+ max_y = WINDOW_TO_FRAME_PIXEL_Y (s->w, max_y);
+ if (s->ybase - glyph->ascent > max_y)
{
- int max_y = r.y + r.height;
- r.y = min (max_y, s->ybase + glyph->descent - height);
- r.height = min (max_y - r.y, height);
+ r.y = max_y;
+ r.height = height;
+ }
+ else
+ {
+ /* Don't draw cursor glyph taller than our actual glyph. */
+ height = max (FRAME_LINE_HEIGHT (s->f), glyph->ascent + glyph->descent);
+ if (height < r.height)
+ {
+ max_y = r.y + r.height;
+ r.y = min (max_y, max (r.y, s->ybase + glyph->descent - height));
+ r.height = min (max_y - r.y, height);
+ }
}
}
#endif
}
+
+/* EXPORT:
+ Return the position and height of the phys cursor in window W.
+ Set w->phys_cursor_width to width of phys cursor.
+*/
+
+int
+get_phys_cursor_geometry (w, row, glyph, heightp)
+ struct window *w;
+ struct glyph_row *row;
+ struct glyph *glyph;
+ int *heightp;
+{
+ struct frame *f = XFRAME (WINDOW_FRAME (w));
+ int x, y, wd, h, h0, y0;
+
+ /* Compute the width of the rectangle to draw. If on a stretch
+ glyph, and `x-stretch-block-cursor' is nil, don't draw a
+ rectangle as wide as the glyph, but use a canonical character
+ width instead. */
+ wd = glyph->pixel_width - 1;
+#ifdef HAVE_NTGUI
+ wd++; /* Why? */
+#endif
+ if (glyph->type == STRETCH_GLYPH
+ && !x_stretch_cursor_p)
+ wd = min (FRAME_COLUMN_WIDTH (f), wd);
+ w->phys_cursor_width = wd;
+
+ y = w->phys_cursor.y + row->ascent - glyph->ascent;
+
+ /* If y is below window bottom, ensure that we still see a cursor. */
+ h0 = min (FRAME_LINE_HEIGHT (f), row->visible_height);
+
+ h = max (h0, glyph->ascent + glyph->descent);
+ h0 = min (h0, glyph->ascent + glyph->descent);
+
+ y0 = WINDOW_HEADER_LINE_HEIGHT (w);
+ if (y < y0)
+ {
+ h = max (h - (y0 - y) + 1, h0);
+ y = y0 - 1;
+ }
+ else
+ {
+ y0 = window_text_bottom_y (w) - h0;
+ if (y > y0)
+ {
+ h += y - y0;
+ y = y0;
+ }
+ }
+
+ *heightp = h - 1;
+ return WINDOW_TO_FRAME_PIXEL_Y (w, y);
+}
+
+
#endif /* HAVE_WINDOW_SYSTEM */
\f
check_it (it)
struct it *it;
{
- if (it->method == next_element_from_string)
+ if (it->method == GET_FROM_STRING)
{
xassert (STRINGP (it->string));
xassert (IT_STRING_CHARPOS (*it) >= 0);
else
{
xassert (IT_STRING_CHARPOS (*it) < 0);
- if (it->method == next_element_from_buffer)
+ if (it->method == GET_FROM_BUFFER)
{
/* Check that character and byte positions agree. */
xassert (IT_CHARPOS (*it) == BYTE_TO_CHAR (IT_BYTEPOS (*it)));
after-string. */
init_iterator (it, w, charpos, bytepos, NULL, DEFAULT_FACE_ID);
- for (i = 0; i < it->n_overlay_strings; ++i)
+ /* This only scans the current chunk -- it should scan all chunks.
+ However, OVERLAY_STRING_CHUNK_SIZE has been increased from 3 in 21.1
+ to 16 in 22.1 to make this a lesser problem. */
+ for (i = 0; i < it->n_overlay_strings && i < OVERLAY_STRING_CHUNK_SIZE; ++i)
{
const char *s = SDATA (it->overlay_strings[i]);
const char *e = s + SBYTES (it->overlay_strings[i]);
property for an image, the iterator will be set up for that
image, and we have to undo that setup first before we can
correct the overlay string index. */
- if (it->method == next_element_from_image)
+ if (it->method == GET_FROM_IMAGE)
pop_it (it);
/* We already have the first chunk of overlay strings in
it->string = it->overlay_strings[relative_index];
xassert (STRINGP (it->string));
it->current.string_pos = pos->string_pos;
- it->method = next_element_from_string;
+ it->method = GET_FROM_STRING;
}
#if 0 /* This is bogus because POS not having an overlay string
while (it->sp)
pop_it (it);
it->current.overlay_string_index = -1;
- it->method = next_element_from_buffer;
+ it->method = GET_FROM_BUFFER;
if (CHARPOS (pos->pos) == ZV)
it->overlay_strings_at_end_processed_p = 1;
}
{
/* Don't check for overlay strings below when set to deliver
characters from a display vector. */
- if (it->method == next_element_from_display_vector)
+ if (it->method == GET_FROM_DISPLAY_VECTOR)
handle_overlay_change_p = 0;
/* Handle overlay changes. */
/* Remember the current face id in case glyphs specify faces.
IT's face is restored in set_iterator_to_next. */
it->saved_face_id = it->face_id;
- it->method = next_element_from_display_vector;
+ it->method = GET_FROM_DISPLAY_VECTOR;
it->ellipsis_p = 1;
}
it->image_id = -1; /* no image */
it->position = start_pos;
it->object = NILP (object) ? it->w->buffer : object;
- it->method = next_element_from_image;
+ it->method = GET_FROM_IMAGE;
it->face_id = face_id;
/* Say that we haven't consumed the characters with
it->current.overlay_string_index = -1;
IT_STRING_CHARPOS (*it) = IT_STRING_BYTEPOS (*it) = 0;
it->end_charpos = it->string_nchars = SCHARS (it->string);
- it->method = next_element_from_string;
+ it->method = GET_FROM_STRING;
it->stop_charpos = 0;
it->string_from_display_prop_p = 1;
/* Say that we haven't consumed the characters with
}
else if (CONSP (value) && EQ (XCAR (value), Qspace))
{
- it->method = next_element_from_stretch;
+ it->method = GET_FROM_STRETCH;
it->object = value;
it->current.pos = it->position = start_pos;
}
it->image_id = lookup_image (it->f, value);
it->position = start_pos;
it->object = NILP (object) ? it->w->buffer : object;
- it->method = next_element_from_image;
+ it->method = GET_FROM_IMAGE;
/* Say that we haven't consumed the characters with
`display' property yet. The call to pop_it in
if (id >= 0)
{
- it->method = next_element_from_composition;
+ it->method = GET_FROM_COMPOSITION;
it->cmp_id = id;
it->cmp_len = COMPOSITION_LENGTH (prop);
/* For a terminal, draw only the first character of the
it->current.overlay_string_index = -1;
SET_TEXT_POS (it->current.string_pos, -1, -1);
it->n_overlay_strings = 0;
- it->method = next_element_from_buffer;
+ it->method = GET_FROM_BUFFER;
/* If we're at the end of the buffer, record that we have
processed the overlay strings there already, so that
it->string = it->overlay_strings[i];
it->multibyte_p = STRING_MULTIBYTE (it->string);
SET_TEXT_POS (it->current.string_pos, 0, 0);
- it->method = next_element_from_string;
+ it->method = GET_FROM_STRING;
it->stop_charpos = 0;
}
xassert (STRINGP (it->string));
it->end_charpos = SCHARS (it->string);
it->multibyte_p = STRING_MULTIBYTE (it->string);
- it->method = next_element_from_string;
+ it->method = GET_FROM_STRING;
}
else
{
it->string = Qnil;
it->current.overlay_string_index = -1;
- it->method = next_element_from_buffer;
+ it->method = GET_FROM_BUFFER;
}
CHECK_IT (it);
back_to_previous_visible_line_start (it)
struct it *it;
{
- int visible_p = 0;
-
- /* Go back one newline if not on BEGV already. */
- if (IT_CHARPOS (*it) > BEGV)
- back_to_previous_line_start (it);
-
- /* Move over lines that are invisible because of selective display
- or text properties. */
- while (IT_CHARPOS (*it) > BEGV
- && !visible_p)
+ while (IT_CHARPOS (*it) > BEGV)
{
- visible_p = 1;
+ back_to_previous_line_start (it);
+ if (IT_CHARPOS (*it) <= BEGV)
+ break;
/* If selective > 0, then lines indented more than that values
are invisible. */
if (it->selective > 0
&& indented_beyond_p (IT_CHARPOS (*it), IT_BYTEPOS (*it),
(double) it->selective)) /* iftc */
- visible_p = 0;
- else
- {
- Lisp_Object prop;
+ continue;
- /* Check the newline before point for invisibility. */
- prop = Fget_char_property (make_number (IT_CHARPOS (*it) - 1),
+ /* Check the newline before point for invisibility. */
+ {
+ Lisp_Object prop;
+ prop = Fget_char_property (make_number (IT_CHARPOS (*it) - 1),
Qinvisible, it->window);
- if (TEXT_PROP_MEANS_INVISIBLE (prop))
- visible_p = 0;
- }
+ if (TEXT_PROP_MEANS_INVISIBLE (prop))
+ continue;
+ }
-#if 0
- /* Commenting this out fixes the bug described in
- http://www.math.ku.dk/~larsh/emacs/emacs-loops-on-large-images/test-case.txt. */
- if (visible_p)
+ /* If newline has a display property that replaces the newline with something
+ else (image or text), find start of overlay or interval and continue search
+ from that point. */
+ if (IT_CHARPOS (*it) > BEGV)
{
struct it it2 = *it;
-
- if (handle_display_prop (&it2) == HANDLED_RETURN)
- visible_p = 0;
+ int pos;
+ int beg, end;
+ Lisp_Object val, overlay;
+
+ pos = --IT_CHARPOS (it2);
+ --IT_BYTEPOS (it2);
+ it2.sp = 0;
+ if (handle_display_prop (&it2) == HANDLED_RETURN
+ && !NILP (val = get_char_property_and_overlay
+ (make_number (pos), Qdisplay, Qnil, &overlay))
+ && (OVERLAYP (overlay)
+ ? (beg = OVERLAY_POSITION (OVERLAY_START (overlay)))
+ : get_property_and_range (pos, Qdisplay, &val, &beg, &end, Qnil)))
+ {
+ if (beg < BEGV)
+ beg = BEGV;
+ IT_CHARPOS (*it) = beg;
+ IT_BYTEPOS (*it) = buf_charpos_to_bytepos (current_buffer, beg);
+ continue;
+ }
}
-#endif
- /* Back one more newline if the current one is invisible. */
- if (!visible_p)
- back_to_previous_line_start (it);
+ break;
}
xassert (IT_CHARPOS (*it) >= BEGV);
IT_STRING_CHARPOS (*it) = -1;
IT_STRING_BYTEPOS (*it) = -1;
it->string = Qnil;
- it->method = next_element_from_buffer;
+ it->method = GET_FROM_BUFFER;
/* RMS: I added this to fix a bug in move_it_vertically_backward
where it->area continued to relate to the starting point
for the backward motion. Bug report from
it->string = string;
it->s = NULL;
it->end_charpos = it->string_nchars = SCHARS (string);
- it->method = next_element_from_string;
+ it->method = GET_FROM_STRING;
it->current.string_pos = string_pos (charpos, string);
}
else
it->end_charpos = it->string_nchars = strlen (s);
}
- it->method = next_element_from_c_string;
+ it->method = GET_FROM_C_STRING;
}
/* PRECISION > 0 means don't return more than PRECISION characters
Iteration
***********************************************************************/
+/* Map enum it_method value to corresponding next_element_from_* function. */
+
+static int (* get_next_element[NUM_IT_METHODS]) P_ ((struct it *it)) =
+{
+ next_element_from_buffer,
+ next_element_from_display_vector,
+ next_element_from_composition,
+ next_element_from_string,
+ next_element_from_c_string,
+ next_element_from_image,
+ next_element_from_stretch
+};
+
+
/* Load IT's display element fields with information about the next
display element from the current position of IT. Value is zero if
end of buffer (or C string) is reached. */
int success_p;
get_next:
- success_p = (*it->method) (it);
+ success_p = (*get_next_element[it->method]) (it);
if (it->what == IT_CHARACTER)
{
it->current.dpvec_index = 0;
it->dpvec_face_id = -1;
it->saved_face_id = it->face_id;
- it->method = next_element_from_display_vector;
+ it->method = GET_FROM_DISPLAY_VECTOR;
it->ellipsis_p = 0;
}
else
else if ((it->c < ' '
&& (it->area != TEXT_AREA
/* In mode line, treat \n like other crl chars. */
- || (it->c != '\n'
+ || (it->c != '\t'
&& it->glyph_row && it->glyph_row->mode_line_p)
|| (it->c != '\n' && it->c != '\t')))
|| (it->multibyte_p
display. Then, set IT->dpvec to these glyphs. */
GLYPH g;
int ctl_len;
- int face_id, lface_id;
+ int face_id, lface_id = 0 ;
GLYPH escape_glyph;
if (it->c < 128 && it->ctl_arrow_p)
{
+ g = '^'; /* default glyph for Control */
/* Set IT->ctl_chars[0] to the glyph for `^'. */
if (it->dp
&& INTEGERP (DISP_CTRL_GLYPH (it->dp))
{
g = XINT (DISP_CTRL_GLYPH (it->dp));
lface_id = FAST_GLYPH_FACE (g);
- if (lface_id)
- {
- g = FAST_GLYPH_CHAR (g);
- face_id = merge_faces (it->f, Qt, lface_id,
- it->face_id);
- }
+ }
+ if (lface_id)
+ {
+ g = FAST_GLYPH_CHAR (g);
+ face_id = merge_faces (it->f, Qt, lface_id,
+ it->face_id);
}
else
{
/* Merge the escape-glyph face into the current face. */
face_id = merge_faces (it->f, Qescape_glyph, 0,
it->face_id);
- g = '^';
}
XSETINT (it->ctl_chars[0], g);
goto display_control;
}
+ escape_glyph = '\\'; /* default for Octal display */
if (it->dp
&& INTEGERP (DISP_ESCAPE_GLYPH (it->dp))
&& GLYPH_CHAR_VALID_P (XFASTINT (DISP_ESCAPE_GLYPH (it->dp))))
{
escape_glyph = XFASTINT (DISP_ESCAPE_GLYPH (it->dp));
lface_id = FAST_GLYPH_FACE (escape_glyph);
- if (lface_id)
- {
- escape_glyph = FAST_GLYPH_CHAR (escape_glyph);
- face_id = merge_faces (it->f, Qt, lface_id,
- it->face_id);
- }
+ }
+ if (lface_id)
+ {
+ escape_glyph = FAST_GLYPH_CHAR (escape_glyph);
+ face_id = merge_faces (it->f, Qt, lface_id,
+ it->face_id);
}
else
{
/* Merge the escape-glyph face into the current face. */
face_id = merge_faces (it->f, Qescape_glyph, 0,
it->face_id);
- escape_glyph = '\\';
}
if (it->c == 0x8a0 || it->c == 0x8ad)
it->current.dpvec_index = 0;
it->dpvec_face_id = face_id;
it->saved_face_id = it->face_id;
- it->method = next_element_from_display_vector;
+ it->method = GET_FROM_DISPLAY_VECTOR;
it->ellipsis_p = 0;
goto get_next;
}
moving the iterator to a new position might set them. */
it->start_of_box_run_p = it->end_of_box_run_p = 0;
- if (it->method == next_element_from_buffer)
+ switch (it->method)
{
+ case GET_FROM_BUFFER:
/* The current display element of IT is a character from
current_buffer. Advance in the buffer, and maybe skip over
invisible lines that are so because of selective display. */
IT_CHARPOS (*it) += 1;
xassert (IT_BYTEPOS (*it) == CHAR_TO_BYTE (IT_CHARPOS (*it)));
}
- }
- else if (it->method == next_element_from_composition)
- {
- xassert (it->cmp_id >= 0 && it ->cmp_id < n_compositions);
+ break;
+
+ case GET_FROM_COMPOSITION:
+ xassert (it->cmp_id >= 0 && it->cmp_id < n_compositions);
if (STRINGP (it->string))
{
IT_STRING_BYTEPOS (*it) += it->len;
IT_STRING_CHARPOS (*it) += it->cmp_len;
- it->method = next_element_from_string;
+ it->method = GET_FROM_STRING;
goto consider_string_end;
}
else
{
IT_BYTEPOS (*it) += it->len;
IT_CHARPOS (*it) += it->cmp_len;
- it->method = next_element_from_buffer;
+ it->method = GET_FROM_BUFFER;
}
- }
- else if (it->method == next_element_from_c_string)
- {
+ break;
+
+ case GET_FROM_C_STRING:
/* Current display element of IT is from a C string. */
IT_BYTEPOS (*it) += it->len;
IT_CHARPOS (*it) += 1;
- }
- else if (it->method == next_element_from_display_vector)
- {
+ break;
+
+ case GET_FROM_DISPLAY_VECTOR:
/* Current display element of IT is from a display table entry.
Advance in the display table definition. Reset it to null if
end reached, and continue with characters from buffers/
if (it->dpvec + it->current.dpvec_index == it->dpend)
{
if (it->s)
- it->method = next_element_from_c_string;
+ it->method = GET_FROM_C_STRING;
else if (STRINGP (it->string))
- it->method = next_element_from_string;
+ it->method = GET_FROM_STRING;
else
- it->method = next_element_from_buffer;
+ it->method = GET_FROM_BUFFER;
it->dpvec = NULL;
it->current.dpvec_index = -1;
/* Recheck faces after display vector */
it->stop_charpos = IT_CHARPOS (*it);
}
- }
- else if (it->method == next_element_from_string)
- {
+ break;
+
+ case GET_FROM_STRING:
/* Current display element is a character from a Lisp string. */
xassert (it->s == NULL && STRINGP (it->string));
IT_STRING_BYTEPOS (*it) += it->len;
&& it->sp > 0)
{
pop_it (it);
- if (!STRINGP (it->string))
- it->method = next_element_from_buffer;
- else
+ if (STRINGP (it->string))
goto consider_string_end;
+ it->method = GET_FROM_BUFFER;
}
}
- }
- else if (it->method == next_element_from_image
- || it->method == next_element_from_stretch)
- {
+ break;
+
+ case GET_FROM_IMAGE:
+ case GET_FROM_STRETCH:
/* The position etc with which we have to proceed are on
the stack. The position may be at the end of a string,
if the `display' property takes up the whole string. */
+ xassert (it->sp > 0);
pop_it (it);
it->image_id = 0;
if (STRINGP (it->string))
{
- it->method = next_element_from_string;
+ it->method = GET_FROM_STRING;
goto consider_string_end;
}
- else
- it->method = next_element_from_buffer;
+ it->method = GET_FROM_BUFFER;
+ break;
+
+ default:
+ /* There are no other methods defined, so this should be a bug. */
+ abort ();
}
- else
- /* There are no other methods defined, so this should be a bug. */
- abort ();
- xassert (it->method != next_element_from_string
+ xassert (it->method != GET_FROM_STRING
|| (STRINGP (it->string)
&& IT_STRING_CHARPOS (*it) >= 0));
}
was in IT->saved_face_id, and signal that it's there by
setting face_before_selective_p. */
it->saved_face_id = it->face_id;
- it->method = next_element_from_buffer;
+ it->method = GET_FROM_BUFFER;
reseat_at_next_visible_line_start (it, 1);
it->face_before_selective_p = 1;
}
saved_glyph_row = it->glyph_row;
it->glyph_row = NULL;
-#define BUFFER_POS_REACHED_P() \
- ((op & MOVE_TO_POS) != 0 \
- && BUFFERP (it->object) \
- && IT_CHARPOS (*it) >= to_charpos \
- && it->method == next_element_from_buffer)
+#define BUFFER_POS_REACHED_P() \
+ ((op & MOVE_TO_POS) != 0 \
+ && BUFFERP (it->object) \
+ && IT_CHARPOS (*it) >= to_charpos \
+ && (it->method == GET_FROM_BUFFER \
+ || (it->method == GET_FROM_DISPLAY_VECTOR \
+ && it->dpvec + it->current.dpvec_index + 1 >= it->dpend)))
+
while (1)
{
value of nlines is > 0 if continuation lines were involved. */
if (nlines > 0)
move_it_by_lines (it, nlines, 1);
+#if 0
+ /* I think this assert is bogus if buffer contains
+ invisible text or images. KFS. */
xassert (IT_CHARPOS (*it) <= start_pos);
+#endif
}
else
{
a line height of 13 pixels each, recentering with point
on the bottom line will try to move -39/2 = 19 pixels
backward. Try to avoid moving into the first line. */
- && it->current_y - target_y > line_height * 2 / 3
+ && (it->current_y - target_y
+ > min (window_box_height (it->w), line_height * 2 / 3))
&& IT_CHARPOS (*it) > BEGV)
{
TRACE_MOVE ((stderr, " not far enough -> move_vert %d\n",
while (target_y >= line_bottom_y (it) && IT_CHARPOS (*it) < ZV);
}
+#if 0
+ /* I think this assert is bogus if buffer contains
+ invisible text or images. KFS. */
xassert (IT_CHARPOS (*it) >= BEGV);
+#endif
}
}
}
it->current_y -= it2.current_y;
it->current_x = it->hpos = 0;
- /* If we moved too far, move IT some lines forward. */
+ /* If we moved too far back, move IT some lines forward. */
if (it2.vpos > -dvpos)
{
int delta = it2.vpos + dvpos;
+ it2 = *it;
move_it_to (it, -1, -1, -1, it->vpos + delta, MOVE_TO_VPOS);
+ /* Move back again if we got too far ahead. */
+ if (IT_CHARPOS (*it) >= start_charpos)
+ *it = it2;
}
}
}
in_display_vector_p (it)
struct it *it;
{
- return (it->method == next_element_from_display_vector
+ return (it->method == GET_FROM_DISPLAY_VECTOR
&& it->current.dpvec_index > 0
&& it->dpvec + it->current.dpvec_index != it->dpend);
}
/* Last displayed message is now the current message. */
echo_area_buffer[1] = echo_area_buffer[0];
+ /* Inform read_char that we're not echoing. */
+ echo_message_buffer = Qnil;
/* Prevent redisplay optimization in redisplay_internal by resetting
this_line_start_pos. This is done because the mini-buffer now
CHARPOS (this_line_start_pos) = 0;
consider_all_windows_p |= buffer_shared > 1;
++clear_face_cache_count;
-
+#ifdef HAVE_WINDOW_SYSTEM
+ ++clear_image_cache_count;
+#endif
/* Build desired matrices, and update the display. If
consider_all_windows_p is non-zero, do it for all windows on all
struct frame **updated
= (struct frame **) alloca (size * sizeof *updated);
- /* Clear the face cache eventually. */
- if (clear_face_cache_count > CLEAR_FACE_CACHE_COUNT)
- {
- clear_face_cache (0);
- clear_face_cache_count = 0;
- }
-
/* Recompute # windows showing selected buffer. This will be
incremented each time such a window is displayed. */
buffer_shared = 0;
variables. */
select_frame_for_redisplay (frame);
-#ifdef HAVE_WINDOW_SYSTEM
- if (clear_face_cache_count % 50 == 0
- && FRAME_WINDOW_P (f))
- clear_image_cache (f, 0);
-#endif /* HAVE_WINDOW_SYSTEM */
-
/* Mark all the scroll bars to be removed; we'll redeem
the ones we want when we redisplay their windows. */
if (condemn_scroll_bars_hook)
if (windows_or_buffers_changed && !pause)
goto retry;
+ /* Clear the face cache eventually. */
+ if (consider_all_windows_p)
+ {
+ if (clear_face_cache_count > CLEAR_FACE_CACHE_COUNT)
+ {
+ clear_face_cache (0);
+ clear_face_cache_count = 0;
+ }
+#ifdef HAVE_WINDOW_SYSTEM
+ if (clear_image_cache_count > CLEAR_IMAGE_CACHE_COUNT)
+ {
+ Lisp_Object tail, frame;
+ FOR_EACH_FRAME (tail, frame)
+ {
+ struct frame *f = XFRAME (frame);
+ if (FRAME_WINDOW_P (f))
+ clear_image_cache (f, 0);
+ }
+ clear_image_cache_count = 0;
+ }
+#endif /* HAVE_WINDOW_SYSTEM */
+ }
+
end_of_redisplay:
unbind_to (count, Qnil);
RESUME_POLLING;
as if point had gone off the screen. */
static int
-make_cursor_line_fully_visible (w, force_p)
+cursor_row_fully_visible_p (w, force_p, current_matrix_p)
struct window *w;
int force_p;
{
if (w->cursor.vpos < 0)
return 1;
- matrix = w->desired_matrix;
+ matrix = current_matrix_p ? w->current_matrix : w->desired_matrix;
row = MATRIX_ROW (matrix, w->cursor.vpos);
/* If the cursor row is not partially visible, there's nothing to do. */
/* If cursor ends up on a partially visible line,
treat that as being off the bottom of the screen. */
- if (! make_cursor_line_fully_visible (w, extra_scroll_margin_lines <= 1))
+ if (! cursor_row_fully_visible_p (w, extra_scroll_margin_lines <= 1, 0))
{
clear_glyph_matrix (w->desired_matrix);
++extra_scroll_margin_lines;
&& CHARPOS (startp) != BEGV)
scroll_p = 1;
}
+ else
+ {
+ /* Cursor did not move. So don't scroll even if cursor line
+ is partially visible, as it was so before. */
+ rc = CURSOR_MOVEMENT_SUCCESS;
+ }
if (PT < MATRIX_ROW_START_CHARPOS (row)
|| PT > MATRIX_ROW_END_CHARPOS (row))
/* if PT is not in the glyph row, give up. */
rc = CURSOR_MOVEMENT_MUST_SCROLL;
}
- else if (MATRIX_ROW_PARTIALLY_VISIBLE_P (w, row)
+ else if (rc != CURSOR_MOVEMENT_SUCCESS
+ && MATRIX_ROW_PARTIALLY_VISIBLE_P (w, row)
&& make_cursor_line_fully_visible_p)
{
if (PT == MATRIX_ROW_END_CHARPOS (row)
else
{
set_cursor_from_row (w, row, w->current_matrix, 0, 0, 0, 0);
- if (!make_cursor_line_fully_visible (w, 0))
+ if (!cursor_row_fully_visible_p (w, 0, 1))
rc = CURSOR_MOVEMENT_MUST_SCROLL;
else
rc = CURSOR_MOVEMENT_SUCCESS;
int temp_scroll_step = 0;
int count = SPECPDL_INDEX ();
int rc;
- int centering_position;
+ int centering_position = -1;
int last_line_misfit = 0;
SET_TEXT_POS (lpoint, PT, PT_BYTE);
new_vpos = window_box_height (w) / 2;
}
- if (!make_cursor_line_fully_visible (w, 0))
+ if (!cursor_row_fully_visible_p (w, 0, 0))
{
/* Point does appear, but on a line partly visible at end of window.
Move it back to a fully-visible line. */
/* Forget any recorded base line for line number display. */
w->base_line_number = Qnil;
- if (!make_cursor_line_fully_visible (w, 1))
+ if (!cursor_row_fully_visible_p (w, 1, 0))
{
clear_glyph_matrix (w->desired_matrix);
last_line_misfit = 1;
/* Finally, just choose place to start which centers point */
recenter:
- centering_position = window_box_height (w) / 2;
-
- point_at_top:
- /* Jump here with centering_position already set to 0. */
+ if (centering_position < 0)
+ centering_position = window_box_height (w) / 2;
#if GLYPH_DEBUG
debug_method_add (w, "recenter");
{
init_iterator (&it, w, PT, PT_BYTE, NULL, DEFAULT_FACE_ID);
move_it_vertically_backward (&it, 0);
+#if 0
+ /* I think this assert is bogus if buffer contains
+ invisible text or images. KFS. */
xassert (IT_CHARPOS (it) <= PT);
+#endif
it.current_y = 0;
}
set_cursor_from_row (w, row, w->current_matrix, 0, 0, 0, 0);
}
- if (!make_cursor_line_fully_visible (w, centering_position > 0))
+ if (!cursor_row_fully_visible_p (w, 0, 0))
{
/* If vscroll is enabled, disable it and try again. */
if (w->vscroll)
/* If centering point failed to make the whole line visible,
put point at the top instead. That has to make the whole line
visible, if it can be done. */
+ if (centering_position == 0)
+ goto done;
+
clear_glyph_matrix (w->desired_matrix);
centering_position = 0;
- goto point_at_top;
+ goto recenter;
}
done:
starts at a minimum position >= last_unchanged_pos_old. */
for (; row > first_text_row; --row)
{
+ /* This used to abort, but it can happen.
+ It is ok to just stop the search instead here. KFS. */
if (!row->enabled_p || !MATRIX_ROW_DISPLAYS_TEXT_P (row))
- abort ();
+ break;
if (MATRIX_ROW_START_CHARPOS (row) >= last_unchanged_pos_old)
row_found = row;
bottom_vpos, dy);
if (first_unchanged_at_end_row)
- first_unchanged_at_end_row += dvpos;
+ {
+ first_unchanged_at_end_row += dvpos;
+ if (first_unchanged_at_end_row->y >= it.last_visible_y
+ || !MATRIX_ROW_DISPLAYS_TEXT_P (first_unchanged_at_end_row))
+ first_unchanged_at_end_row = NULL;
+ }
/* If scrolling up, there may be some lines to display at the end of
the window. */
/* Update window_end_pos and window_end_vpos. */
if (first_unchanged_at_end_row
- && first_unchanged_at_end_row->y < it.last_visible_y
&& !last_text_row_at_end)
{
/* Window end line if one of the preserved rows from the current
/* Record whether this row ends inside an ellipsis. */
row->ends_in_ellipsis_p
- = (it->method == next_element_from_display_vector
+ = (it->method == GET_FROM_DISPLAY_VECTOR
&& it->ellipsis_p);
/* Save fringe bitmaps in this row. */
{
struct glyph_string *head, *tail;
struct glyph_string *s;
+ struct glyph_string *clip_head = NULL, *clip_tail = NULL;
int last_x, area_width;
int x_reached;
int i, j;
start = i;
compute_overhangs_and_x (t, head->x, 1);
prepend_glyph_string_lists (&head, &tail, h, t);
+ clip_head = head;
}
/* Prepend glyph strings for glyphs in front of the first glyph
i = left_overwriting (head);
if (i >= 0)
{
+ clip_head = head;
BUILD_GLYPH_STRINGS (i, start, h, t,
DRAW_NORMAL_TEXT, dummy_x, last_x);
for (s = h; s; s = s->next)
DRAW_NORMAL_TEXT, x, last_x);
compute_overhangs_and_x (h, tail->x + tail->width, 0);
append_glyph_string_lists (&head, &tail, h, t);
+ clip_tail = tail;
}
/* Append glyph strings for glyphs following the last glyph
i = right_overwriting (tail);
if (i >= 0)
{
+ clip_tail = tail;
BUILD_GLYPH_STRINGS (end, i, h, t,
DRAW_NORMAL_TEXT, x, last_x);
for (s = h; s; s = s->next)
compute_overhangs_and_x (h, tail->x + tail->width, 0);
append_glyph_string_lists (&head, &tail, h, t);
}
+ if (clip_head || clip_tail)
+ for (s = head; s; s = s->next)
+ {
+ s->clip_head = clip_head;
+ s->clip_tail = clip_tail;
+ }
}
/* Draw all strings. */
completely. */
&& !overlaps_p)
{
- int x0 = head ? head->x : x;
- int x1 = tail ? tail->x + tail->background_width : x;
+ int x0 = clip_head ? clip_head->x : (head ? head->x : x);
+ int x1 = (clip_tail ? clip_tail->x + clip_tail->background_width
+ : (tail ? tail->x + tail->background_width : x));
int text_left = window_box_left (w, TEXT_AREA);
x0 -= text_left;
if (area != TEXT_AREA)
return;
- row = w->current_matrix->rows + w->phys_cursor.vpos;
- if (!row->displays_text_p)
+ if (w->phys_cursor.vpos < 0
+ || w->phys_cursor.vpos >= w->current_matrix->nrows
+ || (row = w->current_matrix->rows + w->phys_cursor.vpos,
+ !(row->enabled_p && row->displays_text_p)))
return;
if (row->cursor_in_fringe_p)
past_end = 1;
}
+ /* If whole rows or last part of a row came from a display overlay,
+ row_containing_pos will skip over such rows because their end pos
+ equals the start pos of the overlay or interval.
+
+ Move back if we have a STOP object and previous row's
+ end glyph came from STOP. */
+ if (!NILP (stop))
+ {
+ struct glyph_row *prev;
+ while ((prev = row - 1, prev >= first)
+ && MATRIX_ROW_END_CHARPOS (prev) == charpos
+ && prev->used[TEXT_AREA] > 0)
+ {
+ struct glyph *beg = prev->glyphs[TEXT_AREA];
+ glyph = beg + prev->used[TEXT_AREA];
+ while (--glyph >= beg
+ && INTEGERP (glyph->object));
+ if (glyph < beg
+ || !EQ (stop, glyph->object))
+ break;
+ row = prev;
+ }
+ }
+
*x = row->x;
*y = row->y;
*vpos = MATRIX_ROW_VPOS (row, w->current_matrix);
help_echo_pos = charpos;
}
}
- if (NILP (pointer))
- pointer = Fsafe_plist_get (XCDR (object), QCpointer);
}
+ if (NILP (pointer))
+ pointer = Fsafe_plist_get (XCDR (object), QCpointer);
}
if (STRINGP (string))
|| (r.y >= y0 && r.y < y1)
|| (r.y + r.height > y0 && r.y + r.height < y1))
{
- if (row->overlapping_p)
+ /* A header line may be overlapping, but there is no need
+ to fix overlapping areas for them. KFS 2005-02-12 */
+ if (row->overlapping_p && !row->mode_line_p)
{
if (first_overlapping_row == NULL)
first_overlapping_row = row;
message_truncate_lines = 0;
DEFVAR_LISP ("menu-bar-update-hook", &Vmenu_bar_update_hook,
- doc: /* Normal hook run for clicks on menu bar, before displaying a submenu.
-Can be used to update submenus whose contents should vary. */);
+ doc: /* Normal hook run to update the menu bar definitions.
+Redisplay runs this hook before it redisplays the menu bar.
+This is used to update submenus such as Buffers,
+whose contents depend on various data. */);
Vmenu_bar_update_hook = Qnil;
DEFVAR_BOOL ("inhibit-menubar-update", &inhibit_menubar_update,