This function attempts to redisplay a window by reusing parts of
its existing display. It finds and reuses the part that was not
- changed, and redraws the rest.
+ changed, and redraws the rest. (The "id" part in the function's
+ name stands for "insert/delete", not for "identification" or
+ somesuch.)
. try_window
optimizations were successful, redisplay calls redisplay_windows,
which performs a full redisplay of all windows.
+ Note that there's one more important optimization up Emacs's
+ sleeve, but it is related to actually redrawing the potentially
+ changed portions of the window/frame, not to reproducing the
+ desired matrices of those potentially changed portions. Namely,
+ the function update_frame and its subroutines, which you will find
+ in dispnew.c, compare the desired matrices with the current
+ matrices, and only redraw the portions that changed. So it could
+ happen that the functions in this file for some reason decide that
+ the entire desired matrix needs to be regenerated from scratch, and
+ still only parts of the Emacs display, or even nothing at all, will
+ be actually delivered to the glass, because update_frame has found
+ that the new and the old screen contents are similar or identical.
+
Desired matrices.
Desired matrices are always built per Emacs window. The function
/* Get the next character, maybe multibyte. */
p = BYTE_POS_ADDR (IT_BYTEPOS (*it));
- if (it->multibyte_p && !ASCII_BYTE_P (*p))
+ if (it->multibyte_p && !ASCII_CHAR_P (*p))
it->c = STRING_CHAR_AND_LENGTH (p, it->len);
else
it->c = *p, it->len = 1;
for (i = 0; i < nbytes; i += char_bytes)
{
c = string_char_and_length (msg + i, &char_bytes);
- work[0] = (ASCII_CHAR_P (c)
- ? c
- : multibyte_char_to_unibyte (c));
+ work[0] = CHAR_TO_BYTE8 (c);
insert_1_both (work, 1, 1, 1, 0, 0);
}
}
{
if (m)
{
- /* ENCODE_SYSTEM below can GC and/or relocate the Lisp
- String whose data pointer might be passed to us in M. So
- we use a local copy. */
- char *fmt = xstrdup (m);
+ /* ENCODE_SYSTEM below can GC and/or relocate the
+ Lisp data, so make sure we don't use it here. */
+ eassert (relocatable_string_data_p (m) != 1);
if (noninteractive_need_newline)
putc ('\n', stderr);
noninteractive_need_newline = 0;
- fprintf (stderr, fmt, SDATA (ENCODE_SYSTEM (string)));
+ fprintf (stderr, m, SDATA (ENCODE_SYSTEM (string)));
if (!cursor_in_echo_area)
fprintf (stderr, "\n");
fflush (stderr);
- xfree (fmt);
}
}
else if (INTERACTIVE)
{
int i, no_message_p, window_height_changed_p;
- /* Temporarily disable garbage collections while displaying the echo
- area. This is done because a GC can print a message itself.
- That message would modify the echo area buffer's contents while a
- redisplay of the buffer is going on, and seriously confuse
- redisplay. */
- ptrdiff_t count = inhibit_garbage_collection ();
-
/* If there is no message, we must call display_echo_area_1
nevertheless because it resizes the window. But we will have to
reset the echo_area_buffer in question to nil at the end because
if (no_message_p)
echo_area_buffer[i] = Qnil;
- unbind_to (count, Qnil);
return window_height_changed_p;
}
#ifdef HAVE_WINDOW_SYSTEM
-/* Tool-bar item index of the item on which a mouse button was pressed
- or -1. */
-
-int last_tool_bar_item;
-
/* Select `frame' temporarily without running all the code in
do_switch_frame.
FIXME: Maybe do_switch_frame should be trimmed down similarly
#endif /* !USE_GTK && !HAVE_NS */
-#if defined USE_GTK || defined HAVE_NS
-EXFUN (Ftool_bar_height, 2) ATTRIBUTE_CONST;
-EXFUN (Ftool_bar_lines_needed, 1) ATTRIBUTE_CONST;
-#endif
-
DEFUN ("tool-bar-height", Ftool_bar_height, Stool_bar_height,
0, 2, 0,
doc: /* Return the number of lines occupied by the tool bar of FRAME.
where the button was pressed, disregarding where it was
released. */
if (NILP (Vmouse_highlight) && !down_p)
- prop_idx = last_tool_bar_item;
+ prop_idx = f->last_tool_bar_item;
/* If item is disabled, do nothing. */
enabled_p = AREF (f->tool_bar_items, prop_idx + TOOL_BAR_ITEM_ENABLED_P);
/* Show item in pressed state. */
if (!NILP (Vmouse_highlight))
show_mouse_face (hlinfo, DRAW_IMAGE_SUNKEN);
- last_tool_bar_item = prop_idx;
+ f->last_tool_bar_item = prop_idx;
}
else
{
event.arg = key;
event.modifiers = modifiers;
kbd_buffer_store_event (&event);
- last_tool_bar_item = -1;
+ f->last_tool_bar_item = -1;
}
}
mouse_down_p = (x_mouse_grabbed (dpyinfo)
&& f == dpyinfo->last_mouse_frame);
- if (mouse_down_p
- && last_tool_bar_item != prop_idx)
+ if (mouse_down_p && f->last_tool_bar_item != prop_idx)
return;
draw = mouse_down_p ? DRAW_IMAGE_SUNKEN : DRAW_IMAGE_RAISED;
pos_after, 0);
if (prop_pos >= pos_before)
- bpos_max = prop_pos - 1;
+ bpos_max = prop_pos;
}
if (INTEGERP (chprop))
{
pos_after, 0);
if (prop_pos >= pos_before)
- bpos_max = prop_pos - 1;
+ bpos_max = prop_pos;
}
if (INTEGERP (chprop))
{
GLYPH_BEFORE and GLYPH_AFTER. */
if (!((row->reversed_p ? glyph > glyphs_end : glyph < glyphs_end)
&& BUFFERP (glyph->object) && glyph->charpos == pt_old)
- && !(bpos_max < pt_old && pt_old <= bpos_covered))
+ && !(bpos_max <= pt_old && pt_old <= bpos_covered))
{
/* An empty line has a single glyph whose OBJECT is zero and
whose CHARPOS is the position of a newline on that line.
return rc;
}
-#if !defined USE_TOOLKIT_SCROLL_BARS || defined USE_GTK
-static
-#endif
void
set_vertical_scroll_bar (struct window *w)
{
selected_window is redisplayed.
We can return without actually redisplaying the window if fonts has been
- changed on window's frame. In that case, redisplay_internal will retry. */
+ changed on window's frame. In that case, redisplay_internal will retry.
+
+ As one of the important parts of redisplaying a window, we need to
+ decide whether the previous window-start position (stored in the
+ window's w->start marker position) is still valid, and if it isn't,
+ recompute it. Some details about that:
+
+ . The previous window-start could be in a continuation line, in
+ which case we need to recompute it when the window width
+ changes. See compute_window_start_on_continuation_line and its
+ call below.
+
+ . The text that changed since last redisplay could include the
+ previous window-start position. In that case, we try to salvage
+ what we can from the current glyph matrix by calling
+ try_scrolling, which see.
+
+ . Some Emacs command could force us to use a specific window-start
+ position by setting the window's force_start flag, or gently
+ propose doing that by setting the window's optional_new_start
+ flag. In these cases, we try using the specified start point if
+ that succeeds (i.e. the window desired matrix is successfully
+ recomputed, and point location is within the window). In case
+ of optional_new_start, we first check if the specified start
+ position is feasible, i.e. if it will allow point to be
+ displayed in the window. If using the specified start point
+ fails, e.g., if new fonts are needed to be loaded, we abort the
+ redisplay cycle and leave it up to the next cycle to figure out
+ things.
+
+ . Note that the window's force_start flag is sometimes set by
+ redisplay itself, when it decides that the previous window start
+ point is fine and should be kept. Search for "goto force_start"
+ below to see the details. Like the values of window-start
+ specified outside of redisplay, these internally-deduced values
+ are tested for feasibility, and ignored if found to be
+ unfeasible.
+
+ . Note that the function try_window, used to completely redisplay
+ a window, accepts the window's start point as its argument.
+ This is used several times in the redisplay code to control
+ where the window start will be, according to user options such
+ as scroll-conservatively, and also to ensure the screen line
+ showing point will be fully (as opposed to partially) visible on
+ display. */
static void
redisplay_window (Lisp_Object window, bool just_this_one_p)
eassert (XMARKER (w->start)->buffer == buffer);
eassert (XMARKER (w->pointm)->buffer == buffer);
+ /* We come here again if we need to run window-text-change-functions
+ below. */
restart:
reconsider_clip_changes (w);
frame_line_height = default_line_pixel_height (w);
&& !current_buffer->prevent_redisplay_optimizations_p
&& !window_outdated (w));
- /* Run the window-bottom-change-functions
+ /* Run the window-text-change-functions
if it is possible that the text on the screen has changed
(either due to modification of the text, or any other reason). */
if (!current_matrix_up_to_date_p
&& !b->clip_changed
&& !b->prevent_redisplay_optimizations_p
&& !window_outdated (w)
+ /* We rely below on the cursor coordinates to be up to date, but
+ we cannot trust them if some command moved point since the
+ last complete redisplay. */
+ && w->last_point == BUF_PT (b)
&& w->cursor.vpos >= 0
&& w->cursor.vpos < w->current_matrix->nrows
&& (row = MATRIX_ROW (w->current_matrix, w->cursor.vpos))->enabled_p)
return decode_mode_spec_buf;
no_value:
{
- char* p = decode_mode_spec_buf;
+ char *p = decode_mode_spec_buf;
int pad = width - 2;
while (pad-- > 0)
*p++ = ' ';
case '@':
{
- ptrdiff_t count = inhibit_garbage_collection ();
Lisp_Object val = call1 (intern ("file-remote-p"),
BVAR (current_buffer, directory));
- unbind_to (count, Qnil);
if (NILP (val))
return "-";
return OK_PIXELS (WINDOW_SCROLL_BAR_AREA_WIDTH (it->w));
}
- prop = buffer_local_value_1 (prop, it->w->contents);
+ prop = buffer_local_value (prop, it->w->contents);
if (EQ (prop, Qunbound))
prop = Qnil;
}
return OK_PIXELS (pixels);
}
- car = buffer_local_value_1 (car, it->w->contents);
+ car = buffer_local_value (car, it->w->contents);
if (EQ (car, Qunbound))
car = Qnil;
}
#endif
{
eassert (face != NULL);
- PREPARE_FACE_FOR_DISPLAY (f, face);
+ prepare_face_for_display (f, face);
}
return face;
/* Make sure X resources of the face are allocated. */
eassert (face != NULL);
- PREPARE_FACE_FOR_DISPLAY (f, face);
+ prepare_face_for_display (f, face);
if (two_byte_p)
*two_byte_p = 0;
s->ybase += voffset;
/* The case that face->gc == 0 is handled when drawing the glyph
- string by calling PREPARE_FACE_FOR_DISPLAY. */
+ string by calling prepare_face_for_display. */
eassert (s->face);
return glyph - s->row->glyphs[s->area];
}
else
overlap_hl = DRAW_NORMAL_TEXT;
+ if (hl != overlap_hl)
+ clip_head = head;
j = i;
BUILD_GLYPH_STRINGS (j, start, h, t,
overlap_hl, dummy_x, last_x);
start = i;
compute_overhangs_and_x (t, head->x, 1);
prepend_glyph_string_lists (&head, &tail, h, t);
- clip_head = head;
+ if (clip_head == NULL)
+ clip_head = head;
}
/* Prepend glyph strings for glyphs in front of the first glyph
else
overlap_hl = DRAW_NORMAL_TEXT;
- clip_head = head;
+ if (hl == overlap_hl || clip_head == NULL)
+ clip_head = head;
BUILD_GLYPH_STRINGS (i, start, h, t,
overlap_hl, dummy_x, last_x);
for (s = h; s; s = s->next)
else
overlap_hl = DRAW_NORMAL_TEXT;
+ if (hl != overlap_hl)
+ clip_tail = tail;
BUILD_GLYPH_STRINGS (end, i, h, t,
overlap_hl, x, last_x);
/* Because BUILD_GLYPH_STRINGS updates the first argument,
we don't have `end = i;' here. */
compute_overhangs_and_x (h, tail->x + tail->width, 0);
append_glyph_string_lists (&head, &tail, h, t);
- clip_tail = tail;
+ if (clip_tail == NULL)
+ clip_tail = tail;
}
/* Append glyph strings for glyphs following the last glyph
else
overlap_hl = DRAW_NORMAL_TEXT;
- clip_tail = tail;
+ if (hl == overlap_hl || clip_tail == NULL)
+ clip_tail = tail;
i++; /* We must include the Ith glyph. */
BUILD_GLYPH_STRINGS (end, i, h, t,
overlap_hl, x, last_x);
face = FACE_FROM_ID (it->f, it->face_id);
eassert (face);
/* Make sure X resources of the face is loaded. */
- PREPARE_FACE_FOR_DISPLAY (it->f, face);
+ prepare_face_for_display (it->f, face);
if (it->image_id < 0)
{
{
struct face *face = FACE_FROM_ID (it->f, it->face_id);
font = face->font ? face->font : FRAME_FONT (it->f);
- PREPARE_FACE_FOR_DISPLAY (it->f, face);
+ prepare_face_for_display (it->f, face);
}
#endif
face = FACE_FROM_ID (it->f, face_id);
font = face->font ? face->font : FRAME_FONT (it->f);
- PREPARE_FACE_FOR_DISPLAY (it->f, face);
+ prepare_face_for_display (it->f, face);
if (it->glyphless_method == GLYPHLESS_DISPLAY_ACRONYM)
{
sprintf (buf, "%0*X", it->c < 0x10000 ? 4 : 6, it->c);
str = buf;
}
- for (len = 0; str[len] && ASCII_BYTE_P (str[len]) && len < 6; len++)
+ for (len = 0; str[len] && ASCII_CHAR_P (str[len]) && len < 6; len++)
code[len] = font->driver->encode_char (font, str[len]);
upper_len = (len + 1) / 2;
font->driver->text_extents (font, code, upper_len,
/* Erase the image of a cursor of window W from the screen. */
-#ifndef HAVE_NTGUI
-static
-#endif
void
erase_phys_cursor (struct window *w)
{
else if (area == ON_MODE_LINE)
{
Lisp_Object default_help
- = buffer_local_value_1 (Qmode_line_default_help_echo,
- w->contents);
+ = buffer_local_value (Qmode_line_default_help_echo,
+ w->contents);
if (STRINGP (default_help))
{
/* Allocate the buffer for frame titles.
Also used for `format-mode-line'. */
int size = 100;
- mode_line_noprop_buf = xmalloc (size);
+ mode_line_noprop_buf = xmalloc_atomic (size);
mode_line_noprop_buf_end = mode_line_noprop_buf + size;
mode_line_noprop_ptr = mode_line_noprop_buf;
mode_line_target = MODE_LINE_DISPLAY;