/* Display generation from window structure and buffer text.
-Copyright (C) 1985-1988, 1993-1995, 1997-2013 Free Software Foundation, Inc.
+Copyright (C) 1985-1988, 1993-1995, 1997-2014 Free Software Foundation,
+Inc.
This file is part of GNU Emacs.
/* Ascent and height of the last line processed by move_it_to. */
-static int last_max_ascent, last_height;
+static int last_height;
/* Non-zero if there's a help-echo in the echo area. */
it->redisplay_end_trigger_charpos
= marker_position (w->redisplay_end_trigger);
else if (INTEGERP (w->redisplay_end_trigger))
- it->redisplay_end_trigger_charpos =
- clip_to_bounds (PTRDIFF_MIN, XINT (w->redisplay_end_trigger), PTRDIFF_MAX);
+ it->redisplay_end_trigger_charpos
+ = clip_to_bounds (PTRDIFF_MIN, XINT (w->redisplay_end_trigger),
+ PTRDIFF_MAX);
it->tab_width = SANE_TAB_WIDTH (current_buffer);
it->bidi_it.string.s = NULL;
it->bidi_it.string.lstring = Qnil;
it->bidi_it.string.bufpos = 0;
+ it->bidi_it.string.from_disp_str = 0;
it->bidi_it.string.unibyte = 0;
it->bidi_it.w = it->w;
}
it->current_y += it->max_ascent + it->max_descent;
++it->vpos;
last_height = it->max_ascent + it->max_descent;
- last_max_ascent = it->max_ascent;
it->max_ascent = it->max_descent = 0;
}
it->current_y += it->max_ascent + it->max_descent;
++it->vpos;
last_height = it->max_ascent + it->max_descent;
- last_max_ascent = it->max_ascent;
}
if (backup_data)
include the height of the mode- or header-line of WINDOW in the return
value. If it is either the symbol `mode-line' or `header-line', include
only the height of that line, if present, in the return value. If t,
-include the height of any of these lines in the return value. */)
+include the height of both, if present, in the return value. */)
(Lisp_Object window, Lisp_Object from, Lisp_Object to, Lisp_Object x_limit, Lisp_Object y_limit,
Lisp_Object mode_and_header_line)
{
SET_TEXT_POS (startp, start, CHAR_TO_BYTE (start));
start_display (&it, w, startp);
- /** move_it_vertically_backward (&it, 0); **/
if (NILP (x_limit))
x = move_it_to (&it, end, -1, max_y, -1, MOVE_TO_POS | MOVE_TO_Y);
else
MOVE_TO_POS | MOVE_TO_X | MOVE_TO_Y);
}
- if (start == end)
- y = it.current_y;
- else
- {
- /* Count last line. */
- last_height = 0;
- y = line_bottom_y (&it); /* - y; */
- }
+ y = it.current_y + it.max_ascent + it.max_descent;
if (!EQ (mode_and_header_line, Qheader_line)
&& !EQ (mode_and_header_line, Qt))
incrementing windows_or_buffers_changed even if *Messages* is
shown in some window. So we must manually set
windows_or_buffers_changed here to make up for that. */
- windows_or_buffers_changed = old_windows_or_buffers_changed;
+ windows_or_buffers_changed = old_windows_or_buffers_changed;
bset_redisplay (current_buffer);
set_buffer_internal (oldbuf);
/* Compute a suitable window start. */
if (height > max_height)
{
- height = max_height;
+ height = (max_height / unit) * unit;
init_iterator (&it, w, ZV, ZV_BYTE, NULL, DEFAULT_FACE_ID);
- move_it_vertically_backward (&it, height);
+ move_it_vertically_backward (&it, height - unit);
start = it.current.pos;
}
else
#define MAX_FRAME_TOOL_BAR_HEIGHT(f) \
((FRAME_LINE_HEIGHT (f) * FRAME_LINES (f)))
-/* Value is the number of screen lines needed to make all tool-bar
- items of frame F visible. The number of actual rows needed is
+/* Value is the number of pixels needed to make all tool-bar items of
+ frame F visible. The actual number of glyph rows needed is
returned in *N_ROWS if non-NULL. */
static int
F->desired_tool_bar_string in the tool-bar window of frame F. */
init_iterator (&it, w, -1, -1, temp_row, TOOL_BAR_FACE_ID);
it.first_visible_x = 0;
- /* PXW: Use FRAME_PIXEL_WIDTH (f) here? */
- it.last_visible_x = FRAME_TOTAL_COLS (f) * FRAME_COLUMN_WIDTH (f);
+ it.last_visible_x = WINDOW_PIXEL_WIDTH (w);
reseat_to_string (&it, NULL, f->desired_tool_bar_string, 0, 0, 0, -1);
it.paragraph_embedding = L2R;
0, 2, 0,
doc: /* Return the number of lines occupied by the tool bar of FRAME.
If FRAME is nil or omitted, use the selected frame. Optional argument
-PIXELWISE non-nil means return the height of the tool bar inpixels. */)
+PIXELWISE non-nil means return the height of the tool bar in pixels. */)
(Lisp_Object frame, Lisp_Object pixelwise)
{
int height = 0;
&& it.current_y < max_tool_bar_height)
change_height_p = 1;
+ /* We subtract 1 because display_tool_bar_line advances the
+ glyph_row pointer before returning to its caller. We want to
+ examine the last glyph row produced by
+ display_tool_bar_line. */
row = it.glyph_row - 1;
/* If there are blank lines at the end, except for a partially
if (change_height_p)
{
+ /* Current size of the tool-bar window in canonical line
+ units. */
+ int old_lines = WINDOW_TOTAL_LINES (w);
+ /* Required size of the tool-bar window in canonical
+ line units. */
int new_lines = ((new_height + FRAME_LINE_HEIGHT (f) - 1)
/ FRAME_LINE_HEIGHT (f));
-
- XSETFRAME (frame, f);
- Fmodify_frame_parameters (frame,
- list1 (Fcons (Qtool_bar_lines,
- make_number (new_lines))));
- /* Always do that now. */
- clear_glyph_matrix (w->desired_matrix);
- f->n_tool_bar_rows = nrows;
- f->fonts_changed = 1;
- return 1;
+ /* Maximum size of the tool-bar window in canonical line
+ units that this frame can allow. */
+ int max_lines =
+ WINDOW_TOTAL_LINES (XWINDOW (FRAME_ROOT_WINDOW (f))) - 1;
+
+ /* Don't try to change the tool-bar window size and set
+ the fonts_changed flag unless really necessary. That
+ flag causes redisplay to give up and retry
+ redisplaying the frame from scratch, so setting it
+ unnecessarily can lead to nasty redisplay loops. */
+ if (new_lines <= max_lines
+ && eabs (new_lines - old_lines) >= 1)
+ {
+ XSETFRAME (frame, f);
+ Fmodify_frame_parameters (frame,
+ list1 (Fcons (Qtool_bar_lines,
+ make_number (new_lines))));
+ clear_glyph_matrix (w->desired_matrix);
+ f->n_tool_bar_rows = nrows;
+ f->fonts_changed = 1;
+ return 1;
+ }
}
}
}
{
int h_margin;
int text_area_width;
- struct glyph_row *current_cursor_row
- = MATRIX_ROW (w->current_matrix, w->cursor.vpos);
- struct glyph_row *desired_cursor_row
- = MATRIX_ROW (w->desired_matrix, w->cursor.vpos);
- struct glyph_row *cursor_row
- = (desired_cursor_row->enabled_p
- ? desired_cursor_row
- : current_cursor_row);
- int row_r2l_p = cursor_row->reversed_p;
+ struct glyph_row *cursor_row;
+ struct glyph_row *bottom_row;
+ int row_r2l_p;
+
+ bottom_row = MATRIX_BOTTOM_TEXT_ROW (w->desired_matrix, w);
+ if (w->cursor.vpos < bottom_row - w->desired_matrix->rows)
+ cursor_row = MATRIX_ROW (w->desired_matrix, w->cursor.vpos);
+ else
+ cursor_row = bottom_row - 1;
+
+ if (!cursor_row->enabled_p)
+ {
+ bottom_row = MATRIX_BOTTOM_TEXT_ROW (w->current_matrix, w);
+ if (w->cursor.vpos < bottom_row - w->current_matrix->rows)
+ cursor_row = MATRIX_ROW (w->current_matrix, w->cursor.vpos);
+ else
+ cursor_row = bottom_row - 1;
+ }
+ row_r2l_p = cursor_row->reversed_p;
text_area_width = window_box_width (w, TEXT_AREA);
&& REDISPLAY_SOME_P ()
&& !w->redisplay
&& !f->redisplay
- && !buffer->text->redisplay)
+ && !buffer->text->redisplay
+ && BUF_PT (buffer) == w->last_point)
return;
/* Make sure that both W's markers are valid. */
this may be a bit late to catch such changes, but the rest of
redisplay goes (non-fatally) haywire when the display table is
changed, so why should we worry about doing any better? */
- if (current_buffer->width_run_cache)
+ if (current_buffer->width_run_cache
+ || (current_buffer->base_buffer
+ && current_buffer->base_buffer->width_run_cache))
{
struct Lisp_Char_Table *disptab = buffer_display_table ();
if (! disptab_matches_widthtab
(disptab, XVECTOR (BVAR (current_buffer, width_table))))
{
- invalidate_region_cache (current_buffer,
- current_buffer->width_run_cache,
- BEG, Z);
+ struct buffer *buf = current_buffer;
+
+ if (buf->base_buffer)
+ buf = buf->base_buffer;
+ invalidate_region_cache (buf, buf->width_run_cache, BEG, Z);
recompute_width_table (current_buffer, disptab);
}
}
Value is
- 1 if display has been updated
- 0 if otherwise unsuccessful
+ >= 1 if successful, i.e. display has been updated
+ specifically:
+ 1 means the changes were in front of a newline that precedes
+ the window start, and the whole current matrix was reused
+ 2 means the changes were after the last position displayed
+ in the window, and the whole current matrix was reused
+ 3 means portions of the current matrix were reused, while
+ some of the screen lines were redrawn
-1 if redisplay with same window start is known not to succeed
+ 0 if otherwise unsuccessful
The following steps are performed:
if (windows_or_buffers_changed || f->cursor_type_changed)
GIVE_UP (2);
+ /* This function's optimizations cannot be used if overlays have
+ changed in the buffer displayed by the window, so give up if they
+ have. */
+ if (w->last_overlay_modified != OVERLAY_MODIFF)
+ GIVE_UP (21);
+
/* Verify that narrowing has not changed.
Also verify that we were not told to prevent redisplay optimizations.
It would be nice to further
1-``pixel'' wide, so they hit the equality too early. This grace
is needed only for R2L rows that are not continued, to produce
one extra blank where we could display the cursor. */
- if (it->current_x >= it->last_visible_x
- + (!FRAME_WINDOW_P (f)
- && it->glyph_row->reversed_p
- && !it->glyph_row->continued_p))
+ if ((it->current_x >= it->last_visible_x
+ + (!FRAME_WINDOW_P (f)
+ && it->glyph_row->reversed_p
+ && !it->glyph_row->continued_p))
+ /* If the window has display margins, we will need to extend
+ their face even if the text area is filled. */
+ && !(WINDOW_LEFT_MARGIN_WIDTH (it->w) > 0
+ || WINDOW_RIGHT_MARGIN_WIDTH (it->w) > 0))
return;
/* The default face, possibly remapped. */
it->glyph_row->glyphs[TEXT_AREA][0].face_id = face->id;
it->glyph_row->used[TEXT_AREA] = 1;
}
+ /* Mode line and the header line don't have margins, and
+ likewise the frame's tool-bar window, if there is any. */
+ if (!(it->glyph_row->mode_line_p
+#if defined (HAVE_WINDOW_SYSTEM) && ! defined (USE_GTK) && ! defined (HAVE_NS)
+ || (WINDOWP (f->tool_bar_window)
+ && it->w == XWINDOW (f->tool_bar_window))
+#endif
+ ))
+ {
+ if (WINDOW_LEFT_MARGIN_WIDTH (it->w) > 0
+ && it->glyph_row->used[LEFT_MARGIN_AREA] == 0)
+ {
+ it->glyph_row->glyphs[LEFT_MARGIN_AREA][0] = space_glyph;
+ it->glyph_row->glyphs[LEFT_MARGIN_AREA][0].face_id =
+ default_face->id;
+ it->glyph_row->used[LEFT_MARGIN_AREA] = 1;
+ }
+ if (WINDOW_RIGHT_MARGIN_WIDTH (it->w) > 0
+ && it->glyph_row->used[RIGHT_MARGIN_AREA] == 0)
+ {
+ it->glyph_row->glyphs[RIGHT_MARGIN_AREA][0] = space_glyph;
+ it->glyph_row->glyphs[RIGHT_MARGIN_AREA][0].face_id =
+ default_face->id;
+ it->glyph_row->used[RIGHT_MARGIN_AREA] = 1;
+ }
+ }
#ifdef HAVE_WINDOW_SYSTEM
if (it->glyph_row->reversed_p)
{
it->object = make_number (0);
it->c = it->char_to_display = ' ';
it->len = 1;
+
+ if (WINDOW_LEFT_MARGIN_WIDTH (it->w) > 0
+ && (it->glyph_row->used[LEFT_MARGIN_AREA]
+ < WINDOW_LEFT_MARGIN_WIDTH (it->w))
+ && !it->glyph_row->mode_line_p
+ && default_face->background != FRAME_BACKGROUND_PIXEL (f))
+ {
+ struct glyph *g = it->glyph_row->glyphs[LEFT_MARGIN_AREA];
+ struct glyph *e = g + it->glyph_row->used[LEFT_MARGIN_AREA];
+
+ for (it->current_x = 0; g < e; g++)
+ it->current_x += g->pixel_width;
+
+ it->area = LEFT_MARGIN_AREA;
+ it->face_id = default_face->id;
+ while (it->glyph_row->used[LEFT_MARGIN_AREA]
+ < WINDOW_LEFT_MARGIN_WIDTH (it->w))
+ {
+ PRODUCE_GLYPHS (it);
+ /* term.c:produce_glyphs advances it->current_x only for
+ TEXT_AREA. */
+ it->current_x += it->pixel_width;
+ }
+
+ it->current_x = saved_x;
+ it->area = TEXT_AREA;
+ }
+
/* The last row's blank glyphs should get the default face, to
avoid painting the rest of the window with the region face,
if the region ends at ZV. */
it->face_id = default_face->id;
else
it->face_id = face->id;
-
PRODUCE_GLYPHS (it);
while (it->current_x <= it->last_visible_x)
PRODUCE_GLYPHS (it);
+ if (WINDOW_RIGHT_MARGIN_WIDTH (it->w) > 0
+ && (it->glyph_row->used[RIGHT_MARGIN_AREA]
+ < WINDOW_RIGHT_MARGIN_WIDTH (it->w))
+ && !it->glyph_row->mode_line_p
+ && default_face->background != FRAME_BACKGROUND_PIXEL (f))
+ {
+ struct glyph *g = it->glyph_row->glyphs[RIGHT_MARGIN_AREA];
+ struct glyph *e = g + it->glyph_row->used[RIGHT_MARGIN_AREA];
+
+ for ( ; g < e; g++)
+ it->current_x += g->pixel_width;
+
+ it->area = RIGHT_MARGIN_AREA;
+ it->face_id = default_face->id;
+ while (it->glyph_row->used[RIGHT_MARGIN_AREA]
+ < WINDOW_RIGHT_MARGIN_WIDTH (it->w))
+ {
+ PRODUCE_GLYPHS (it);
+ it->current_x += it->pixel_width;
+ }
+
+ it->area = TEXT_AREA;
+ }
+
/* Don't count these blanks really. It would let us insert a left
truncation glyph below and make us set the cursor on them, maybe. */
it->current_x = saved_x;
}
else if (it->bidi_p)
RECORD_MAX_MIN_POS (it);
+ if (WINDOW_LEFT_MARGIN_WIDTH (it->w) > 0
+ || WINDOW_RIGHT_MARGIN_WIDTH (it->w) > 0)
+ extend_face_to_end_of_line (it);
}
else if (CHAR_GLYPH_PADDING_P (*glyph)
&& !FRAME_WINDOW_P (it->f))
it->max_descent = descent;
it->max_phys_ascent = phys_ascent;
it->max_phys_descent = phys_descent;
+ if (WINDOW_LEFT_MARGIN_WIDTH (it->w) > 0
+ || WINDOW_RIGHT_MARGIN_WIDTH (it->w) > 0)
+ extend_face_to_end_of_line (it);
}
else if (wrap_row_used > 0)
{
row->continued_p = 1;
glyph->pixel_width = it->last_visible_x - x;
it->starts_in_middle_of_char_p = 1;
+ if (WINDOW_LEFT_MARGIN_WIDTH (it->w) > 0
+ || WINDOW_RIGHT_MARGIN_WIDTH (it->w) > 0)
+ extend_face_to_end_of_line (it);
}
else
{
itb.string.s = NULL;
itb.string.lstring = Qnil;
itb.string.bufpos = 0;
+ itb.string.from_disp_str = 0;
itb.string.unibyte = 0;
/* We have no window to use here for ignoring window-specific
overlays. Using NULL for window pointer will cause
SET_TEXT_POS (pt, PT, PT_BYTE);
start_display (&it, w, pt);
- if ((it.cmp_it.id < 0
- && it.method == GET_FROM_STRING
- && it.area == TEXT_AREA
- && it.string_from_display_prop_p
- && (it.sp > 0 && it.stack[it.sp - 1].method == GET_FROM_BUFFER))
- || it.method == GET_FROM_DISPLAY_VECTOR)
+ if (it.cmp_it.id < 0
+ && it.method == GET_FROM_STRING
+ && it.area == TEXT_AREA
+ && it.string_from_display_prop_p
+ && (it.sp > 0 && it.stack[it.sp - 1].method == GET_FROM_BUFFER))
overshoot_expected = true;
/* Find the X coordinate of point. We start from the beginning
of this or previous line to make sure we are before point in
the logical order (since the move_it_* functions can only
move forward). */
+ reseat:
reseat_at_previous_visible_line_start (&it);
it.current_x = it.hpos = it.current_y = it.vpos = 0;
if (IT_CHARPOS (it) != PT)
- move_it_to (&it, overshoot_expected ? PT - 1 : PT,
- -1, -1, -1, MOVE_TO_POS);
+ {
+ move_it_to (&it, overshoot_expected ? PT - 1 : PT,
+ -1, -1, -1, MOVE_TO_POS);
+ /* If we missed point because the character there is
+ displayed out of a display vector that has more than one
+ glyph, retry expecting overshoot. */
+ if (it.method == GET_FROM_DISPLAY_VECTOR
+ && it.current.dpvec_index > 0
+ && !overshoot_expected)
+ {
+ overshoot_expected = true;
+ goto reseat;
+ }
+ else if (IT_CHARPOS (it) != PT && !overshoot_expected)
+ move_it_in_display_line (&it, PT, -1, MOVE_TO_POS);
+ }
pt_x = it.current_x;
pt_vpos = it.vpos;
if (dir > 0 || overshoot_expected)
else if (pixel_width <= 0)
pixel_width = 1;
- /* If there's a display string at point, we are actually at the
- glyph to the left of point, so we need to correct the X
- coordinate. */
+ /* If there's a display string (or something similar) at point,
+ we are actually at the glyph to the left of point, so we need
+ to correct the X coordinate. */
if (overshoot_expected)
{
if (it.bidi_p)
character at point. */
if (FRAME_WINDOW_P (it.f) && dir < 0)
{
- struct text_pos new_pos = it.current.pos;
+ struct text_pos new_pos;
enum move_it_result rc = MOVE_X_REACHED;
+ if (it.current_x == 0)
+ get_next_display_element (&it);
+ if (it.what == IT_COMPOSITION)
+ {
+ new_pos.charpos = it.cmp_it.charpos;
+ new_pos.bytepos = -1;
+ }
+ else
+ new_pos = it.current.pos;
+
while (it.current_x + it.pixel_width <= target_x
&& rc == MOVE_X_REACHED)
{
int new_x = it.current_x + it.pixel_width;
- new_pos = it.current.pos;
+ /* For composed characters, we want the position of the
+ first character in the grapheme cluster (usually, the
+ composition's base character), whereas it.current
+ might give us the position of the _last_ one, e.g. if
+ the composition is rendered in reverse due to bidi
+ reordering. */
+ if (it.what == IT_COMPOSITION)
+ {
+ new_pos.charpos = it.cmp_it.charpos;
+ new_pos.bytepos = -1;
+ }
+ else
+ new_pos = it.current.pos;
if (new_x == it.current_x)
new_x++;
rc = move_it_in_display_line_to (&it, ZV, new_x,
if (ITERATOR_AT_END_OF_LINE_P (&it) && !target_is_eol_p)
break;
}
- /* If we ended up on a composed character inside
- bidi-reordered text (e.g., Hebrew text with diacritics),
- the iterator gives us the buffer position of the last (in
- logical order) character of the composed grapheme cluster,
- which is not what we want. So we cheat: we compute the
- character position of the character that follows (in the
- logical order) the one where the above loop stopped. That
- character will appear on display to the left of point. */
- if (it.bidi_p
- && it.bidi_it.scan_dir == -1
- && new_pos.charpos - IT_CHARPOS (it) > 1)
- {
- new_pos.charpos = IT_CHARPOS (it) + 1;
- new_pos.bytepos = CHAR_TO_BYTE (new_pos.charpos);
- }
+ /* The previous position we saw in the loop is the one we
+ want. */
+ if (new_pos.bytepos == -1)
+ new_pos.bytepos = CHAR_TO_BYTE (new_pos.charpos);
it.current.pos = new_pos;
}
else
eassert (!FRAME_WINDOW_P (f));
init_iterator (&it, w, -1, -1, f->desired_matrix->rows, MENU_FACE_ID);
it.first_visible_x = 0;
- /* PXW: Use FRAME_PIXEL_WIDTH (f) here? */
- it.last_visible_x = FRAME_TOTAL_COLS (f) * FRAME_COLUMN_WIDTH (f);
+ it.last_visible_x = FRAME_PIXEL_WIDTH (f);
#elif defined (HAVE_X_WINDOWS) /* X without toolkit. */
if (FRAME_WINDOW_P (f))
{
init_iterator (&it, menu_w, -1, -1, menu_w->desired_matrix->rows,
MENU_FACE_ID);
it.first_visible_x = 0;
- /* PXW: Use FRAME_PIXEL_WIDTH (f) here? */
- it.last_visible_x = FRAME_TOTAL_COLS (f) * FRAME_COLUMN_WIDTH (f);
+ it.last_visible_x = FRAME_PIXEL_WIDTH (f);
}
else
#endif /* not USE_X_TOOLKIT and not USE_GTK */
the drawing area, set S->extends_to_end_of_line_p. */
if (start == s->row->used[s->area]
- && s->area == TEXT_AREA
&& ((s->row->fill_line_p
&& (s->hl == DRAW_NORMAL_TEXT
|| s->hl == DRAW_IMAGE_RAISED
int x0 = WINDOW_RIGHT_EDGE_X (w) - WINDOW_RIGHT_DIVIDER_WIDTH (w);
int x1 = WINDOW_RIGHT_EDGE_X (w);
int y0 = WINDOW_TOP_EDGE_Y (w);
- int y1 = WINDOW_BOTTOM_EDGE_Y (w);
+ /* The bottom divider prevails. */
+ int y1 = WINDOW_BOTTOM_EDGE_Y (w) - WINDOW_BOTTOM_DIVIDER_WIDTH (w);
FRAME_RIF (f)->draw_window_divider (w, x0, x1, y0, y1);
}