GNU Emacs is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2, or (at your option)
+the Free Software Foundation; either version 3, or (at your option)
any later version.
GNU Emacs is distributed in the hope that it will be useful,
static int face_before_or_after_it_pos P_ ((struct it *, int));
static int next_overlay_change P_ ((int));
static int handle_single_display_spec P_ ((struct it *, Lisp_Object,
- Lisp_Object, struct text_pos *,
- int));
+ Lisp_Object, Lisp_Object,
+ struct text_pos *, int));
static int underlying_face_id P_ ((struct it *));
static int in_ellipses_for_invisible_text_p P_ ((struct display_pos *,
struct window *));
if (it->method == GET_FROM_DISPLAY_VECTOR)
handle_overlay_change_p = 0;
- /* Handle overlay changes. */
+ /* Handle overlay changes.
+ This sets HANDLED to HANDLED_RECOMPUTE_PROPS
+ if it finds overlays. */
if (handle_overlay_change_p)
handled = handle_overlay_change (it);
-
- /* Determine where to stop next. */
- if (handled == HANDLED_NORMALLY)
- compute_stop_pos (it);
}
}
while (handled == HANDLED_RECOMPUTE_PROPS);
+
+ /* Determine where to stop next. */
+ if (handled == HANDLED_NORMALLY)
+ compute_stop_pos (it);
}
else
{
int base_face_id, bufpos;
+ int i;
+ Lisp_Object from_overlay
+ = (it->current.overlay_string_index >= 0
+ ? it->string_overlays[it->current.overlay_string_index]
+ : Qnil);
+
+ /* See if we got to this string directly or indirectly from
+ an overlay property. That includes the before-string or
+ after-string of an overlay, strings in display properties
+ provided by an overlay, their text properties, etc.
+
+ FROM_OVERLAY is the overlay that brought us here, or nil if none. */
+ if (! NILP (from_overlay))
+ for (i = it->sp - 1; i >= 0; i--)
+ {
+ if (it->stack[i].current.overlay_string_index >= 0)
+ from_overlay
+ = it->string_overlays[it->stack[i].current.overlay_string_index];
+ else if (! NILP (it->stack[i].from_overlay))
+ from_overlay = it->stack[i].from_overlay;
- if (it->current.overlay_string_index >= 0)
- bufpos = IT_CHARPOS (*it);
+ if (!NILP (from_overlay))
+ break;
+ }
+
+ if (! NILP (from_overlay))
+ {
+ bufpos = IT_CHARPOS (*it);
+ /* For a string from an overlay, the base face depends
+ only on text properties and ignores overlays. */
+ base_face_id
+ = face_for_overlay_string (it->w,
+ IT_CHARPOS (*it),
+ it->region_beg_charpos,
+ it->region_end_charpos,
+ &next_stop,
+ (IT_CHARPOS (*it)
+ + TEXT_PROP_DISTANCE_LIMIT),
+ 0,
+ from_overlay);
+ }
else
- bufpos = 0;
+ {
+ bufpos = 0;
- /* For strings from a buffer, i.e. overlay strings or strings
- from a `display' property, use the face at IT's current
- buffer position as the base face to merge with, so that
- overlay strings appear in the same face as surrounding
- text, unless they specify their own faces. */
- base_face_id = underlying_face_id (it);
+ /* For strings from a `display' property, use the face at
+ IT's current buffer position as the base face to merge
+ with, so that overlay strings appear in the same face as
+ surrounding text, unless they specify their own
+ faces. */
+ base_face_id = underlying_face_id (it);
+ }
new_face_id = face_at_string_position (it->w,
it->string,
it->position.bytepos = CHAR_TO_BYTE (it->position.charpos);
}
setup_for_ellipsis (it, 0);
+ /* Let the ellipsis display before
+ considering any properties of the following char.
+ Fixes jasonr@gnu.org 01 Oct 07 bug. */
+ handled = HANDLED_RETURN;
}
}
}
handle_display_prop (it)
struct it *it;
{
- Lisp_Object prop, object;
+ Lisp_Object prop, object, overlay;
struct text_pos *position;
/* Nonzero if some property replaces the display of the text itself. */
int display_replaced_p = 0;
if (!it->string_from_display_prop_p)
it->area = TEXT_AREA;
- prop = Fget_char_property (make_number (position->charpos),
- Qdisplay, object);
+ prop = get_char_property_and_overlay (make_number (position->charpos),
+ Qdisplay, object, &overlay);
if (NILP (prop))
return HANDLED_NORMALLY;
+ /* Now OVERLAY is the overlay that gave us this property, or nil
+ if it was a text property. */
if (!STRINGP (it->string))
object = it->w->buffer;
{
for (; CONSP (prop); prop = XCDR (prop))
{
- if (handle_single_display_spec (it, XCAR (prop), object,
+ if (handle_single_display_spec (it, XCAR (prop), object, overlay,
position, display_replaced_p))
- display_replaced_p = 1;
+ {
+ display_replaced_p = 1;
+ /* If some text in a string is replaced, `position' no
+ longer points to the position of `object'. */
+ if (STRINGP (object))
+ break;
+ }
}
}
else if (VECTORP (prop))
{
int i;
for (i = 0; i < ASIZE (prop); ++i)
- if (handle_single_display_spec (it, AREF (prop, i), object,
+ if (handle_single_display_spec (it, AREF (prop, i), object, overlay,
position, display_replaced_p))
- display_replaced_p = 1;
+ {
+ display_replaced_p = 1;
+ /* If some text in a string is replaced, `position' no
+ longer points to the position of `object'. */
+ if (STRINGP (object))
+ break;
+ }
}
else
{
- int ret = handle_single_display_spec (it, prop, object, position, 0);
+ int ret = handle_single_display_spec (it, prop, object, overlay,
+ position, 0);
if (ret < 0) /* Replaced by "", i.e. nothing. */
return HANDLED_RECOMPUTE_PROPS;
if (ret)
replaced text display with something else, for example an image;
we ignore such properties after the first one has been processed.
+ OVERLAY is the overlay this `display' property came from,
+ or nil if it was a text property.
+
If PROP is a `space' or `image' specification, and in some other
cases too, set *POSITION to the position where the `display'
property ends.
"something" is "nothing". */
static int
-handle_single_display_spec (it, spec, object, position,
+handle_single_display_spec (it, spec, object, overlay, position,
display_replaced_before_p)
struct it *it;
Lisp_Object spec;
Lisp_Object object;
+ Lisp_Object overlay;
struct text_pos *position;
int display_replaced_before_p;
{
return 0;
}
- /* Handle `(space_width WIDTH)'. */
+ /* Handle `(space-width WIDTH)'. */
if (CONSP (spec)
&& EQ (XCAR (spec), Qspace_width)
&& CONSP (XCDR (spec)))
it->position = start_pos;
it->object = NILP (object) ? it->w->buffer : object;
it->method = GET_FROM_IMAGE;
+ it->from_overlay = Qnil;
it->face_id = face_id;
/* Say that we haven't consumed the characters with
it->position = *position;
push_it (it);
it->position = save_pos;
+ it->from_overlay = overlay;
if (NILP (location))
it->area = TEXT_AREA;
/* Say that we haven't consumed the characters with
`display' property yet. The call to pop_it in
set_iterator_to_next will clean this up. */
- *position = start_pos;
+ if (BUFFERP (object))
+ it->current.pos = start_pos;
}
else if (CONSP (value) && EQ (XCAR (value), Qspace))
{
it->method = GET_FROM_STRETCH;
it->object = value;
- *position = it->position = start_pos;
+ it->position = start_pos;
+ if (BUFFERP (object))
+ it->current.pos = start_pos;
}
#ifdef HAVE_WINDOW_SYSTEM
else
/* Say that we haven't consumed the characters with
`display' property yet. The call to pop_it in
set_iterator_to_next will clean this up. */
- *position = start_pos;
+ if (BUFFERP (object))
+ it->current.pos = start_pos;
}
#endif /* HAVE_WINDOW_SYSTEM */
i = 0;
j = it->current.overlay_string_index;
while (i < OVERLAY_STRING_CHUNK_SIZE && j < n)
- it->overlay_strings[i++] = entries[j++].string;
+ {
+ it->overlay_strings[i] = entries[j].string;
+ it->string_overlays[i++] = entries[j++].overlay;
+ }
CHECK_IT (it);
}
string. */
IT_STRING_CHARPOS (*it) = IT_STRING_BYTEPOS (*it) = 0;
it->string = it->overlay_strings[0];
+ it->from_overlay = Qnil;
it->stop_charpos = 0;
xassert (STRINGP (it->string));
it->end_charpos = SCHARS (it->string);
p->face_id = it->face_id;
p->string = it->string;
p->method = it->method;
+ p->from_overlay = it->from_overlay;
switch (p->method)
{
case GET_FROM_IMAGE:
it->current = p->current;
it->position = p->position;
it->string = p->string;
+ it->from_overlay = p->from_overlay;
if (NILP (it->string))
SET_TEXT_POS (it->current.string_pos, -1, -1);
it->method = p->method;
it->c = *p, it->len = 1;
/* Record what we have and where it came from. */
- it->what = IT_CHARACTER;;
+ it->what = IT_CHARACTER;
it->object = it->w->buffer;
it->position = it->current.pos;
{
struct position pos;
- if (!FRAME_WINDOW_P (it->f))
+ /* The commented-out optimization uses vmotion on terminals. This
+ gives bad results, because elements like it->what, on which
+ callers such as pos_visible_p rely, aren't updated. */
+ /* if (!FRAME_WINDOW_P (it->f))
{
struct text_pos textpos;
- /* We can use vmotion on frames without proportional fonts. */
pos = *vmotion (IT_CHARPOS (*it), dvpos, it->w);
SET_TEXT_POS (textpos, pos.bufpos, pos.bytepos);
reseat (it, textpos, 1);
it->vpos += pos.vpos;
it->current_y += pos.vpos;
}
- else if (dvpos == 0)
+ else */
+
+ if (dvpos == 0)
{
/* DVPOS == 0 means move to the start of the screen line. */
move_it_vertically_backward (it, 0);
int must_finish = 0;
struct text_pos tlbufpos, tlendpos;
int number_of_visible_frames;
- int count;
+ int count, count1;
struct frame *sf;
int polling_stopped_here = 0;
update_mode_lines++;
}
+ /* Avoid invocation of point motion hooks by `current_column' below. */
+ count1 = SPECPDL_INDEX ();
+ specbind (Qinhibit_point_motion_hooks, Qt);
+
/* If %c is in the mode line, update it if needed. */
if (!NILP (w->column_number_displayed)
/* This alternative quickly identifies a common case
!= (int) current_column ())) /* iftc */
w->update_mode_line = Qt;
+ unbind_to (count1, Qnil);
+
FRAME_SCROLL_BOTTOM_VPOS (XFRAME (w->frame)) = -1;
/* The variable buffer_shared is set in redisplay_window and
int rc;
int centering_position = -1;
int last_line_misfit = 0;
+ int save_beg_unchanged, save_end_unchanged;
SET_TEXT_POS (lpoint, PT, PT_BYTE);
opoint = lpoint;
set_buffer_internal_1 (XBUFFER (w->buffer));
SET_TEXT_POS (opoint, PT, PT_BYTE);
+ save_beg_unchanged = BEG_UNCHANGED;
+ save_end_unchanged = END_UNCHANGED;
+
current_matrix_up_to_date_p
= (!NILP (w->window_end_valid)
&& !current_buffer->clip_changed
w->force_start = Qt;
}
+ force_start:
+
/* Handle case where place to start displaying has been specified,
unless the specified location is outside the accessible range. */
if (!NILP (w->force_start)
than a simple mouse-click. */
if (NILP (w->start_at_line_beg)
&& NILP (do_mouse_tracking)
- && CHARPOS (startp) > BEGV)
- {
- /* Make sure beg_unchanged and end_unchanged are up to date.
- Do it only if buffer has really changed. This may or may
- not have been done by try_window_id (see which) already. */
- if (MODIFF > SAVE_MODIFF
- /* This seems to happen sometimes after saving a buffer. */
- || BEG_UNCHANGED + END_UNCHANGED > Z_BYTE)
- {
- if (GPT - BEG < BEG_UNCHANGED)
- BEG_UNCHANGED = GPT - BEG;
- if (Z - GPT < END_UNCHANGED)
- END_UNCHANGED = Z - GPT;
- }
-
- if (CHARPOS (startp) > BEG + BEG_UNCHANGED
- && CHARPOS (startp) <= Z - END_UNCHANGED)
- {
- /* There doesn't seems to be a simple way to find a new
- window start that is near the old window start, so
- we just recenter. */
- goto recenter;
- }
+ && CHARPOS (startp) > BEGV
+ && CHARPOS (startp) > BEG + save_beg_unchanged
+ && CHARPOS (startp) <= Z - save_end_unchanged)
+ {
+ w->force_start = Qt;
+ if (XMARKER (w->start)->buffer == current_buffer)
+ compute_window_start_on_continuation_line (w);
+ SET_TEXT_POS_FROM_MARKER (startp, w->start);
+ goto force_start;
}
#if GLYPH_DEBUG
/* Restore current_buffer and value of point in it. */
TEMP_SET_PT_BOTH (CHARPOS (opoint), BYTEPOS (opoint));
set_buffer_internal_1 (old);
- TEMP_SET_PT_BOTH (CHARPOS (lpoint), BYTEPOS (lpoint));
+ /* Avoid an abort in TEMP_SET_PT_BOTH if the buffer has become
+ shorter. This can be caused by log truncation in *Messages*. */
+ if (CHARPOS (lpoint) <= ZV)
+ TEMP_SET_PT_BOTH (CHARPOS (lpoint), BYTEPOS (lpoint));
unbind_to (count, Qnil);
}
nrows_scrolled);
/* Disable lines that must be updated. */
- for (i = 0; i < it.vpos; ++i)
+ for (i = 0; i < nrows_scrolled; ++i)
(start_row + i)->enabled_p = 0;
/* Re-compute Y positions. */
if (PT == MATRIX_ROW_END_CHARPOS (row))
{
- /* If the row ends with a newline from a string, we don't want
- the cursor there, but we still want it at the start of the
- string if the string starts in this row.
- If the row is continued it doesn't end in a newline. */
+ /* Suppose the row ends on a string.
+ Unless the row is continued, that means it ends on a newline
+ in the string. If it's anything other than a display string
+ (e.g. a before-string from an overlay), we don't want the
+ cursor there. (This heuristic seems to give the optimal
+ behavior for the various types of multi-line strings.) */
if (CHARPOS (row->end.string_pos) >= 0)
- cursor_row_p = (row->continued_p
- || PT >= MATRIX_ROW_START_CHARPOS (row));
+ {
+ if (row->continued_p)
+ cursor_row_p = 1;
+ else
+ {
+ /* Check for `display' property. */
+ struct glyph *beg = row->glyphs[TEXT_AREA];
+ struct glyph *end = beg + row->used[TEXT_AREA] - 1;
+ struct glyph *glyph;
+
+ cursor_row_p = 0;
+ for (glyph = end; glyph >= beg; --glyph)
+ if (STRINGP (glyph->object))
+ {
+ Lisp_Object prop
+ = Fget_char_property (make_number (PT),
+ Qdisplay, Qnil);
+ cursor_row_p =
+ (!NILP (prop)
+ && display_prop_string_p (prop, glyph->object));
+ break;
+ }
+ }
+ }
else if (MATRIX_ROW_ENDS_IN_MIDDLE_OF_CHAR_P (row))
{
/* If the row ends in middle of a real character,
buffer = w->buffer;
CHECK_BUFFER (buffer);
- if (NILP (format))
+ /* 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)
return build_string ("");
if (no_props)
non_selected = 1;
}
- /* Nonselected window or nonselected frame. */
+ /* Detect a nonselected window or nonselected frame. */
else if (w != XWINDOW (f->selected_window)
#ifdef HAVE_WINDOW_SYSTEM
|| f != FRAME_X_DISPLAY_INFO (f)->x_highlight_frame
if (NILP (b->cursor_type))
return NO_CURSOR;
- /* Use cursor-in-non-selected-windows for non-selected window or frame. */
- if (non_selected)
- {
- alt_cursor = b->cursor_in_non_selected_windows;
- return get_specified_cursor_type (alt_cursor, width);
- }
-
/* Get the normal cursor type for this window. */
if (EQ (b->cursor_type, Qt))
{
else
cursor_type = get_specified_cursor_type (b->cursor_type, width);
+ /* Use cursor-in-non-selected-windows instead
+ for non-selected window or frame. */
+ if (non_selected)
+ {
+ alt_cursor = b->cursor_in_non_selected_windows;
+ if (!EQ (Qt, alt_cursor))
+ return get_specified_cursor_type (alt_cursor, width);
+ /* t means modify the normal cursor type. */
+ if (cursor_type == FILLED_BOX_CURSOR)
+ cursor_type = HOLLOW_BOX_CURSOR;
+ else if (cursor_type == BAR_CURSOR && *width > 1)
+ --*width;
+ return cursor_type;
+ }
+
/* Use normal cursor if not blinked off. */
if (!w->cursor_off_p)
{
{
XRectangle cr, result;
struct glyph *cursor_glyph;
+ struct glyph_row *row;
+
+ if (w->phys_cursor.vpos >= 0
+ && w->phys_cursor.vpos < w->current_matrix->nrows
+ && (row = MATRIX_ROW (w->current_matrix, w->phys_cursor.vpos),
+ row->enabled_p)
+ && row->cursor_in_fringe_p)
+ {
+ /* Cursor is in the fringe. */
+ cr.x = window_box_right_offset (w,
+ (WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (w)
+ ? RIGHT_MARGIN_AREA
+ : TEXT_AREA));
+ cr.y = row->y;
+ cr.width = WINDOW_RIGHT_FRINGE_WIDTH (w);
+ cr.height = row->height;
+ return x_intersect_rectangles (&cr, r, &result);
+ }
cursor_glyph = get_phys_cursor_glyph (w);
if (cursor_glyph)
DEFVAR_INT ("scroll-conservatively", &scroll_conservatively,
doc: /* *Scroll up to this many lines, to bring point back on screen.
-A value of zero means to scroll the text to center point vertically
-in the window. */);
+If point moves off-screen, redisplay will scroll by up to
+`scroll-conservatively' lines in order to bring point just barely
+onto the screen again. If that cannot be done, then redisplay
+recenters point as usual.
+
+A value of zero means always recenter point if it moves off screen. */);
scroll_conservatively = 0;
DEFVAR_INT ("scroll-margin", &scroll_margin,
mouse pointer enters it.
Autoselection selects the minibuffer only if it is active, and never
-unselects the minibuffer if it is active. */);
+unselects the minibuffer if it is active.
+
+When customizing this variable make sure that the actual value of
+`focus-follows-mouse' matches the behavior of your window manager. */);
Vmouse_autoselect_window = Qnil;
DEFVAR_LISP ("auto-resize-tool-bars", &Vauto_resize_tool_bars,
This dynamically changes the tool-bar's height to the minimum height
that is needed to make all tool-bar items visible.
If value is `grow-only', the tool-bar's height is only increased
-automatically; to decreace the tool-bar height, use \\[recenter]. */);
+automatically; to decrease the tool-bar height, use \\[recenter]. */);
Vauto_resize_tool_bars = Qt;
DEFVAR_BOOL ("auto-raise-tool-bar-buttons", &auto_raise_tool_bar_buttons_p,