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
wset_redisplay (struct window *w)
{
/* Beware: selected_window can be nil during early stages. */
- if (!EQ (make_lisp_ptr (w, Lisp_Vectorlike), selected_window))
+ if (!EQ (w->header.self, selected_window))
redisplay_other_windows ();
w->redisplay = true;
}
struct it it;
struct text_pos pt;
struct window *w = XWINDOW (selected_window);
+ struct buffer *old_buffer = NULL;
+ Lisp_Object result;
+ if (XBUFFER (w->contents) != current_buffer)
+ {
+ old_buffer = current_buffer;
+ set_buffer_internal_1 (XBUFFER (w->contents));
+ }
SET_TEXT_POS (pt, PT, PT_BYTE);
start_display (&it, w, pt);
it.vpos = it.current_y = 0;
last_height = 0;
- return make_number (line_bottom_y (&it));
+ result = make_number (line_bottom_y (&it));
+ if (old_buffer)
+ set_buffer_internal_1 (old_buffer);
+
+ return result;
}
/* Return the default pixel height of text lines in window W. The
following. Return the result, or nil if something went
wrong. Prevent redisplay during the evaluation. */
-Lisp_Object
-safe_call (ptrdiff_t nargs, Lisp_Object func, ...)
+static Lisp_Object
+safe__call (bool inhibit_quit, ptrdiff_t nargs, Lisp_Object func, va_list ap)
{
Lisp_Object val;
val = Qnil;
else
{
- va_list ap;
ptrdiff_t i;
- ptrdiff_t count = SPECPDL_INDEX ();
+ dynwind_begin ();
struct gcpro gcpro1;
Lisp_Object *args = alloca (nargs * word_size);
args[0] = func;
- va_start (ap, func);
for (i = 1; i < nargs; i++)
args[i] = va_arg (ap, Lisp_Object);
- va_end (ap);
GCPRO1 (args[0]);
gcpro1.nvars = nargs;
specbind (Qinhibit_redisplay, Qt);
+ if (inhibit_quit)
+ specbind (Qinhibit_quit, Qt);
/* Use Qt to ensure debugger does not run,
so there is no possibility of wanting to redisplay. */
val = internal_condition_case_n (Ffuncall, nargs, args, Qt,
safe_eval_handler);
UNGCPRO;
- val = unbind_to (count, val);
+ dynwind_end ();
}
return val;
}
+Lisp_Object
+safe_call (ptrdiff_t nargs, Lisp_Object func, ...)
+{
+ Lisp_Object retval;
+ va_list ap;
+
+ va_start (ap, func);
+ retval = safe__call (false, nargs, func, ap);
+ va_end (ap);
+ return retval;
+}
/* Call function FN with one argument ARG.
Return the result, or nil if something went wrong. */
return safe_call (2, fn, arg);
}
+static Lisp_Object
+safe__call1 (bool inhibit_quit, Lisp_Object fn, ...)
+{
+ Lisp_Object retval;
+ va_list ap;
+
+ va_start (ap, fn);
+ retval = safe__call (inhibit_quit, 2, fn, ap);
+ va_end (ap);
+ return retval;
+}
+
static Lisp_Object Qeval;
Lisp_Object
safe_eval (Lisp_Object sexpr)
{
- return safe_call1 (Qeval, sexpr);
+ return safe__call1 (false, Qeval, sexpr);
+}
+
+static Lisp_Object
+safe__eval (bool inhibit_quit, Lisp_Object sexpr)
+{
+ return safe__call1 (inhibit_quit, Qeval, sexpr);
}
/* Call function FN with two arguments ARG1 and ARG2.
no amount of fontifying will be able to change it. */
NILP (prop) && IT_CHARPOS (*it) < Z))
{
- ptrdiff_t count = SPECPDL_INDEX ();
+ dynwind_begin ();
Lisp_Object val;
struct buffer *obuf = current_buffer;
ptrdiff_t begv = BEGV, zv = ZV;
UNGCPRO;
}
- unbind_to (count, Qnil);
+ dynwind_end ();
/* Fontification functions routinely call `save-restriction'.
Normally, this tags clip_changed, which can confuse redisplay
if (!NILP (form) && !EQ (form, Qt))
{
- ptrdiff_t count = SPECPDL_INDEX ();
+ dynwind_begin ();
struct gcpro gcpro1;
/* Bind `object' to the object having the `display' property, a
GCPRO1 (form);
form = safe_eval (form);
UNGCPRO;
- unbind_to (count, Qnil);
+ dynwind_end ();
}
if (NILP (form))
{
/* Evaluate IT->font_height with `height' bound to the
current specified height to get the new height. */
- ptrdiff_t count = SPECPDL_INDEX ();
+ dynwind_begin ();
specbind (Qheight, face->lface[LFACE_HEIGHT_INDEX]);
value = safe_eval (it->font_height);
- unbind_to (count, Qnil);
+ dynwind_end ();
if (NUMBERP (value))
new_height = XFLOATINT (value);
/* 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;
}
else
{
- if (it->line_wrap == WORD_WRAP)
+ if (it->line_wrap == WORD_WRAP && it->area == TEXT_AREA)
{
if (IT_DISPLAYING_WHITESPACE (it))
may_wrap = 1;
if (closest_pos < ZV)
{
RESTORE_IT (it, &ppos_it, ppos_data);
- move_it_in_display_line_to (it, closest_pos, -1,
- MOVE_TO_POS);
+ /* Don't recurse if closest_pos is equal to
+ to_charpos, since we have just tried that. */
+ if (closest_pos != to_charpos)
+ move_it_in_display_line_to (it, closest_pos, -1,
+ MOVE_TO_POS);
result = MOVE_POS_MATCH_OR_ZV;
}
else
&& !at_eob_p && closest_pos < ZV)
{
RESTORE_IT (it, &ppos_it, ppos_data);
- move_it_in_display_line_to (it, closest_pos, -1,
- MOVE_TO_POS);
+ if (closest_pos != to_charpos)
+ move_it_in_display_line_to (it, closest_pos, -1,
+ MOVE_TO_POS);
}
result = MOVE_POS_MATCH_OR_ZV;
break;
if (closest_pos < ZV)
{
RESTORE_IT (it, &ppos_it, ppos_data);
- move_it_in_display_line_to (it, closest_pos, -1, MOVE_TO_POS);
+ if (closest_pos != to_charpos)
+ move_it_in_display_line_to (it, closest_pos, -1,
+ MOVE_TO_POS);
}
result = MOVE_POS_MATCH_OR_ZV;
break;
ptrdiff_t start_charpos, i;
int nchars_per_row
= (it->last_visible_x - it->first_visible_x) / FRAME_COLUMN_WIDTH (it->f);
+ bool hit_pos_limit = false;
ptrdiff_t pos_limit;
/* Start at the beginning of the screen line containing IT's
pos_limit = BEGV;
else
pos_limit = max (start_charpos + dvpos * nchars_per_row, BEGV);
+
for (i = -dvpos; i > 0 && IT_CHARPOS (*it) > pos_limit; --i)
back_to_previous_visible_line_start (it);
+ if (i > 0 && IT_CHARPOS (*it) <= pos_limit)
+ hit_pos_limit = true;
reseat (it, it->current.pos, 1);
/* Move further back if we end up in a string or an image. */
else
bidi_unshelve_cache (it2data, 1);
}
+ else if (hit_pos_limit && pos_limit > BEGV
+ && dvpos < 0 && it2.vpos < -dvpos)
+ {
+ /* If we hit the limit, but still didn't make it far enough
+ back, that means there's a display string with a newline
+ covering a large chunk of text, and that caused
+ back_to_previous_visible_line_start try to go too far.
+ Punish those who commit such atrocities by going back
+ until we've reached DVPOS, after lifting the limit, which
+ could make it slow for very long lines. "If it hurts,
+ don't do that!" */
+ dvpos += it2.vpos;
+ RESTORE_IT (it, it, it2data);
+ for (i = -dvpos; i > 0; --i)
+ {
+ back_to_previous_visible_line_start (it);
+ it->vpos--;
+ }
+ }
else
RESTORE_IT (it, it, it2data);
}
defaults to the maximum accessible position of the buffer. If TO is t,
use the maximum accessible position that is not a newline character.
-The optional argument X_LIMIT, if non-nil, specifies the maximum text
-width that can be returned. X_LIMIT nil or omitted, means to use the
+The optional argument X-LIMIT, if non-nil, specifies the maximum text
+width that can be returned. X-LIMIT nil or omitted, means to use the
pixel-width of WINDOW's body; use this if you do not intend to change
the width of WINDOW. Use the maximum width WINDOW may assume if you
-intend to change WINDOW's width.
+intend to change WINDOW's width. In any case, text whose x-coordinate
+is beyond X-LIMIT is ignored. Since calculating the width of long lines
+can take some time, it's always a good idea to make this argument as
+small as possible; in particular, if the buffer contains long lines that
+shall be truncated anyway.
-The optional argument Y_LIMIT, if non-nil, specifies the maximum text
+The optional argument Y-LIMIT, if non-nil, specifies the maximum text
height that can be returned. Text lines whose y-coordinate is beyond
-Y_LIMIT are ignored. Since calculating the text height of a large
+Y-LIMIT are ignored. Since calculating the text height of a large
buffer can take some time, it makes sense to specify this argument if
the size of the buffer is unknown.
-Optional argument MODE_AND_HEADER_LINE nil or omitted means do not
+Optional argument MODE-AND-HEADER-LINE nil or omitted means do not
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,
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)
{
Lisp_Object buffer;
int this_one, the_other, clear_buffer_p, rc;
- ptrdiff_t count = SPECPDL_INDEX ();
+ dynwind_begin ();
/* If buffers aren't live, make new ones. */
ensure_echo_area_buffers ();
eassert (BEGV >= BEG);
eassert (ZV <= Z && ZV >= BEGV);
- unbind_to (count, Qnil);
+ dynwind_end ();
return rc;
}
if (Z > BEG)
{
- ptrdiff_t count = SPECPDL_INDEX ();
+ dynwind_begin ();
specbind (Qinhibit_read_only, Qt);
/* Note that undo recording is always disabled. */
del_range (BEG, Z);
- unbind_to (count, Qnil);
+ dynwind_end ();
}
TEMP_SET_PT_BOTH (BEG, BEG_BYTE);
{
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;
}
/* Must update other windows. Likewise as in other
cases, don't let this update be interrupted by
pending input. */
- ptrdiff_t count = SPECPDL_INDEX ();
+ dynwind_begin ();
specbind (Qredisplay_dont_pause, Qt);
windows_or_buffers_changed = 44;
redisplay_internal ();
- unbind_to (count, Qnil);
+ dynwind_end ();
}
else if (FRAME_WINDOW_P (f) && n == 0)
{
char *title;
ptrdiff_t len;
struct it it;
- ptrdiff_t count = SPECPDL_INDEX ();
+ dynwind_begin ();
FOR_EACH_FRAME (tail, other_frame)
{
display_mode_element (&it, 0, -1, -1, fmt, Qnil, 0);
len = MODE_LINE_NOPROP_LEN (title_start);
title = mode_line_noprop_buf + title_start;
- unbind_to (count, Qnil);
+ dynwind_end ();
/* Set the title only if it's changed. This avoids consing in
the common case where it hasn't. (If it turns out that we've
}
}
}
- safe_call1 (Vpre_redisplay_function, windows);
+ safe__call1 (true, Vpre_redisplay_function, windows);
}
/* Update all frame titles based on their buffer names, etc. We do
if (all_windows)
{
Lisp_Object tail, frame;
- ptrdiff_t count = SPECPDL_INDEX ();
+ dynwind_begin ();
/* 1 means that update_menu_bar has run its hooks
so any further calls to update_menu_bar shouldn't do so again. */
int menu_bar_hooks_run = 0;
UNGCPRO;
}
- unbind_to (count, Qnil);
+ dynwind_end ();
}
else
{
|| window_buffer_changed (w))
{
struct buffer *prev = current_buffer;
- ptrdiff_t count = SPECPDL_INDEX ();
+ dynwind_begin ();
specbind (Qinhibit_menubar_update, Qt);
w->update_mode_line = 1;
#endif /* ! (USE_X_TOOLKIT || HAVE_NTGUI || HAVE_NS || USE_GTK) */
- unbind_to (count, Qnil);
+ dynwind_end ();
set_buffer_internal_1 (prev);
}
}
#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
|| window_buffer_changed (w))
{
struct buffer *prev = current_buffer;
- ptrdiff_t count = SPECPDL_INDEX ();
+ dynwind_begin ();
Lisp_Object frame, new_tool_bar;
int new_n_tool_bar;
struct gcpro gcpro1;
UNGCPRO;
- unbind_to (count, Qnil);
+ dynwind_end ();
set_buffer_internal_1 (prev);
}
}
#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;
}
}
-#define STOP_POLLING \
-do { if (! polling_stopped_here) stop_polling (); \
- polling_stopped_here = 1; } while (0)
-
-#define RESUME_POLLING \
-do { if (polling_stopped_here) start_polling (); \
- polling_stopped_here = 0; } while (0)
-
-
/* Perhaps in the future avoid recentering windows if it
is not necessary; currently that causes some problems. */
/* Record a function that clears redisplaying_p
when we leave this function. */
- count = SPECPDL_INDEX ();
+ dynwind_begin ();
record_unwind_protect_void (unwind_redisplay);
redisplaying_p = 1;
specbind (Qinhibit_free_realized_faces, Qnil);
signals, which can cause an apparent I/O error. */
if (interrupt_input)
unrequest_sigio ();
- STOP_POLLING;
pending |= update_frame (f, 0, 0);
f->cursor_type_changed = 0;
which can cause an apparent I/O error. */
if (interrupt_input)
unrequest_sigio ();
- STOP_POLLING;
if (FRAME_VISIBLE_P (sf) && !FRAME_OBSCURED_P (sf))
{
But it is much hairier to try to do anything about that. */
if (interrupt_input)
request_sigio ();
- RESUME_POLLING;
/* If a frame has become visible which was not before, redisplay
again, so that we display it. Expose events for such a frame
if (interrupt_input && interrupts_deferred)
request_sigio ();
- unbind_to (count, Qnil);
- RESUME_POLLING;
+ dynwind_end ();
}
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)
It indicates that the buffer contents and narrowing are unchanged. */
bool buffer_unchanged_p = false;
int temp_scroll_step = 0;
- ptrdiff_t count = SPECPDL_INDEX ();
+ dynwind_begin ();
int rc;
int centering_position = -1;
int last_line_misfit = 0;
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
/* Consider the following case: Window starts at BEGV, there is
invisible, intangible text at BEGV, so that display starts at
some point START > BEGV. It can happen that we are called with
- PT somewhere between BEGV and START. Try to handle that case. */
+ PT somewhere between BEGV and START. Try to handle that case,
+ and similar ones. */
if (w->cursor.vpos < 0)
{
- struct glyph_row *row = w->current_matrix->rows;
- if (row->mode_line_p)
- ++row;
+ /* First, try locating the proper glyph row for PT. */
+ struct glyph_row *row =
+ row_containing_pos (w, PT, w->current_matrix->rows, NULL, 0);
+
+ /* Sometimes point is at the beginning of invisible text that is
+ before the 1st character displayed in the row. In that case,
+ row_containing_pos fails to find the row, because no glyphs
+ with appropriate buffer positions are present in the row.
+ Therefore, we next try to find the row which shows the 1st
+ position after the invisible text. */
+ if (!row)
+ {
+ Lisp_Object val =
+ get_char_property_and_overlay (make_number (PT), Qinvisible,
+ Qnil, NULL);
+
+ if (TEXT_PROP_MEANS_INVISIBLE (val))
+ {
+ ptrdiff_t alt_pos;
+ Lisp_Object invis_end =
+ Fnext_single_char_property_change (make_number (PT), Qinvisible,
+ Qnil, Qnil);
+
+ if (NATNUMP (invis_end))
+ alt_pos = XFASTINT (invis_end);
+ else
+ alt_pos = ZV;
+ row = row_containing_pos (w, alt_pos, w->current_matrix->rows,
+ NULL, 0);
+ }
+ }
+ /* Finally, fall back on the first row of the window after the
+ header line (if any). This is slightly better than not
+ displaying the cursor at all. */
+ if (!row)
+ {
+ row = w->current_matrix->rows;
+ if (row->mode_line_p)
+ ++row;
+ }
set_cursor_from_row (w, row, w->current_matrix, 0, 0, 0, 0);
}
if (CHARPOS (lpoint) <= ZV)
TEMP_SET_PT_BOTH (CHARPOS (lpoint), BYTEPOS (lpoint));
- unbind_to (count, Qnil);
+ dynwind_end ();
}
truncate_it.current_x = 0;
truncate_it.face_id = DEFAULT_FACE_ID;
truncate_it.glyph_row = &scratch_glyph_row;
+ truncate_it.area = TEXT_AREA;
truncate_it.glyph_row->used[TEXT_AREA] = 0;
CHARPOS (truncate_it.position) = BYTEPOS (truncate_it.position) = -1;
truncate_it.object = make_number (0);
&& !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)
SAVE_IT (it2, it, it_data);
move_it_in_display_line_to (&it, ZV, target_x,
MOVE_TO_POS | MOVE_TO_X);
- target_x = it.current_x - 1;
+ /* If we arrived at target_x, that _is_ the last
+ character on the previous line. */
+ if (it.current_x != target_x)
+ target_x = it.current_x - 1;
RESTORE_IT (&it, &it2, it_data);
}
}
{
struct it it;
struct face *face;
- ptrdiff_t count = SPECPDL_INDEX ();
+ dynwind_begin ();
init_iterator (&it, w, -1, -1, NULL, face_id);
/* Don't extend on a previously drawn mode-line.
display_mode_element (&it, 0, 0, 0, format, Qnil, 0);
pop_kboard ();
- unbind_to (count, Qnil);
+ dynwind_end ();
/* Fill up with spaces. */
display_string (" ", Qnil, Qnil, 0, 0, &it, 10000, -1, -1, 0);
if (CONSP (XCDR (elt)))
{
Lisp_Object spec;
- spec = safe_eval (XCAR (XCDR (elt)));
+ spec = safe__eval (true, XCAR (XCDR (elt)));
n += display_mode_element (it, depth, field_width - n,
precision - n, spec, props,
risky);
struct buffer *old_buffer = NULL;
int face_id;
int no_props = INTEGERP (face);
- ptrdiff_t count = SPECPDL_INDEX ();
+ dynwind_begin ();
Lisp_Object str;
int string_start = 0;
/* Make formatting the modeline a non-op when noninteractive, otherwise
there will be problems later caused by a partially initialized frame. */
- if (NILP (format) || noninteractive)
+ if (NILP (format) || noninteractive) {
+ dynwind_end ();
return empty_unibyte_string;
+ }
if (no_props)
face = Qnil;
empty_unibyte_string);
}
- unbind_to (count, Qnil);
+ dynwind_end ();
return str;
}
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)
{
if (/* If window is in the process of being destroyed, don't bother
to do anything. */
w->current_matrix != NULL
- /* Don't update mouse highlight if hidden */
+ /* Don't update mouse highlight if hidden. */
&& (draw != DRAW_MOUSE_FACE || !hlinfo->mouse_face_hidden)
/* Recognize when we are called to operate on rows that don't exist
anymore. This can happen when a window is split. */
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))
{
void
syms_of_xdisp (void)
{
+#include "xdisp.x"
+
Vwith_echo_area_save_vector = Qnil;
staticpro (&Vwith_echo_area_save_vector);
message_dolog_marker3 = Fmake_marker ();
staticpro (&message_dolog_marker3);
-#ifdef GLYPH_DEBUG
- defsubr (&Sdump_frame_glyph_matrix);
- defsubr (&Sdump_glyph_matrix);
- defsubr (&Sdump_glyph_row);
- defsubr (&Sdump_tool_bar_row);
- defsubr (&Strace_redisplay);
- defsubr (&Strace_to_stderr);
-#endif
-#ifdef HAVE_WINDOW_SYSTEM
- defsubr (&Stool_bar_height);
- defsubr (&Slookup_image_map);
-#endif
- defsubr (&Sline_pixel_height);
- defsubr (&Sformat_mode_line);
- defsubr (&Sinvisible_p);
- defsubr (&Scurrent_bidi_paragraph_direction);
- defsubr (&Swindow_text_pixel_size);
- defsubr (&Smove_point_visually);
-
DEFSYM (Qmenu_bar_update_hook, "menu-bar-update-hook");
DEFSYM (Qoverriding_terminal_local_map, "overriding-terminal-local-map");
DEFSYM (Qoverriding_local_map, "overriding-local-map");
/* 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;