You should have received a copy of the GNU General Public License
along with GNU Emacs; see the file COPYING. If not, write to
-the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA. */
+the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+Boston, MA 02110-1301, USA. */
/* New redisplay written by Gerd Moellmann <gerd@gnu.org>.
/* Non-nil means escape non-break space and hyphens. */
-Lisp_Object Vshow_nonbreak_escape;
+Lisp_Object Vnobreak_char_display;
#ifdef HAVE_WINDOW_SYSTEM
extern Lisp_Object Voverflow_newline_into_fringe;
/* Name and number of the face used to highlight non-breaking spaces. */
-Lisp_Object Qno_break_space;
+Lisp_Object Qnobreak_space;
/* The symbol `image' which is the car of the lists used to represent
images in Lisp. */
int *heightp;
{
struct frame *f = XFRAME (WINDOW_FRAME (w));
- int x, y, wd, h, h0, y0;
+ int 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
init_iterator (it, w, CHARPOS (pos), BYTEPOS (pos), row, DEFAULT_FACE_ID);
it->first_vpos = first_vpos;
- if (!it->truncate_lines_p)
+ /* Don't reseat to previous visible line start if current start
+ position is in a string or image. */
+ if (it->method == GET_FROM_BUFFER && !it->truncate_lines_p)
{
int start_at_line_beg_p;
int first_y = it->current_y;
? ((it->c >= 127
&& it->len == 1)
|| !CHAR_PRINTABLE_P (it->c)
- || (!NILP (Vshow_nonbreak_escape)
+ || (!NILP (Vnobreak_char_display)
&& (it->c == 0x8a0 || it->c == 0x8ad
|| it->c == 0x920 || it->c == 0x92d
|| it->c == 0xe20 || it->c == 0xe2d
int face_id, lface_id = 0 ;
GLYPH escape_glyph;
+ /* Handle control characters with ^. */
+
if (it->c < 128 && it->ctl_arrow_p)
{
g = '^'; /* default glyph for Control */
goto display_control;
}
- escape_glyph = '\\'; /* default for Octal display */
+ /* Handle non-break space in the mode where it only gets
+ highlighting. */
+
+ if (EQ (Vnobreak_char_display, Qt)
+ && (it->c == 0x8a0 || it->c == 0x920
+ || it->c == 0xe20 || it->c == 0xf20))
+ {
+ /* Merge the no-break-space face into the current face. */
+ face_id = merge_faces (it->f, Qnobreak_space, 0,
+ it->face_id);
+
+ g = it->c = ' ';
+ XSETINT (it->ctl_chars[0], g);
+ ctl_len = 1;
+ goto display_control;
+ }
+
+ /* Handle sequences that start with the "escape glyph". */
+
+ /* the default escape glyph is \. */
+ escape_glyph = '\\';
+
if (it->dp
&& INTEGERP (DISP_ESCAPE_GLYPH (it->dp))
&& GLYPH_CHAR_VALID_P (XFASTINT (DISP_ESCAPE_GLYPH (it->dp))))
}
if (lface_id)
{
+ /* The display table specified a face.
+ Merge it into face_id and also into escape_glyph. */
escape_glyph = FAST_GLYPH_CHAR (escape_glyph);
face_id = merge_faces (it->f, Qt, lface_id,
it->face_id);
it->face_id);
}
- if (it->c == 0x8a0 || it->c == 0x920
- || it->c == 0xe20 || it->c == 0xf20)
- {
- /* Merge the no-break-space face into the current face. */
- face_id = merge_faces (it->f, Qno_break_space, 0,
- it->face_id);
+ /* Handle soft hyphens in the mode where they only get
+ highlighting. */
- g = it->c;
+ if (EQ (Vnobreak_char_display, Qt)
+ && (it->c == 0x8ad || it->c == 0x92d
+ || it->c == 0xe2d || it->c == 0xf2d))
+ {
+ g = it->c = '-';
XSETINT (it->ctl_chars[0], g);
ctl_len = 1;
goto display_control;
}
- if (it->c == 0x8ad || it->c == 0x92d
- || it->c == 0xe2d || it->c == 0xf2d)
+ /* Handle non-break space and soft hyphen
+ with the escape glyph. */
+
+ if (it->c == 0x8a0 || it->c == 0x8ad
+ || it->c == 0x920 || it->c == 0x92d
+ || it->c == 0xe20 || it->c == 0xe2d
+ || it->c == 0xf20 || it->c == 0xf2d)
{
- g = it->c;
- XSETINT (it->ctl_chars[0], g);
- ctl_len = 1;
+ XSETINT (it->ctl_chars[0], escape_glyph);
+ g = it->c = ((it->c & 0xf) == 0 ? ' ' : '-');
+ XSETINT (it->ctl_chars[1], g);
+ ctl_len = 2;
goto display_control;
}
Moving an iterator without producing glyphs
***********************************************************************/
+/* Check if iterator is at a position corresponding to a valid buffer
+ position after some move_it_ call. */
+
+#define IT_POS_VALID_AFTER_MOVE_P(it) \
+ ((it)->method == GET_FROM_STRING \
+ ? IT_STRING_CHARPOS (*it) == 0 \
+ : 1)
+
+
/* Move iterator IT to a specified buffer or X position within one
line on the display without producing glyphs.
y-distance. */
it2 = *it;
it2.max_ascent = it2.max_descent = 0;
- move_it_to (&it2, start_pos, -1, -1, it2.vpos + 1,
- MOVE_TO_POS | MOVE_TO_VPOS);
+ do
+ {
+ move_it_to (&it2, start_pos, -1, -1, it2.vpos + 1,
+ MOVE_TO_POS | MOVE_TO_VPOS);
+ }
+ while (!IT_POS_VALID_AFTER_MOVE_P (&it2));
xassert (IT_CHARPOS (*it) >= BEGV);
it3 = it2;
last_height = 0;
}
else if (dvpos > 0)
- move_it_to (it, -1, -1, -1, it->vpos + dvpos, MOVE_TO_VPOS);
+ {
+ move_it_to (it, -1, -1, -1, it->vpos + dvpos, MOVE_TO_VPOS);
+ if (!IT_POS_VALID_AFTER_MOVE_P (it))
+ move_it_to (it, IT_CHARPOS (*it) + 1, -1, -1, -1, MOVE_TO_POS);
+ }
else
{
struct it it2;
int start_charpos, i;
/* Start at the beginning of the screen line containing IT's
- position. */
+ position. This may actually move vertically backwards,
+ in case of overlays, so adjust dvpos accordingly. */
+ dvpos += it->vpos;
move_it_vertically_backward (it, 0);
+ dvpos -= it->vpos;
/* Go back -DVPOS visible lines and reseat the iterator there. */
start_charpos = IT_CHARPOS (*it);
- for (i = -dvpos; i && IT_CHARPOS (*it) > BEGV; --i)
+ for (i = -dvpos; i > 0 && IT_CHARPOS (*it) > BEGV; --i)
back_to_previous_visible_line_start (it);
reseat (it, it->current.pos, 1);
+
+ /* Move further back if we end up in a string or an image. */
+ while (!IT_POS_VALID_AFTER_MOVE_P (it))
+ {
+ /* First try to move to start of display line. */
+ dvpos += it->vpos;
+ move_it_vertically_backward (it, 0);
+ dvpos -= it->vpos;
+ if (IT_POS_VALID_AFTER_MOVE_P (it))
+ break;
+ /* If start of line is still in string or image,
+ move further back. */
+ back_to_previous_visible_line_start (it);
+ reseat (it, it->current.pos, 1);
+ dvpos--;
+ }
+
it->current_x = it->hpos = 0;
/* Above call may have moved too far if continuation lines
clear_glyph_matrix (w->desired_matrix);
XSETWINDOW (window, w);
SET_TEXT_POS (start, BEG, BEG_BYTE);
- try_window (window, start);
+ try_window (window, start, 0);
return window_height_changed_p;
}
format_mode_line_unwind_data (obuf)
struct buffer *obuf;
{
- int i = 0;
Lisp_Object vector;
/* Reduce consing by keeping one vector in
Lisp_Object tail, frame;
int count = SPECPDL_INDEX ();
- record_unwind_protect (Fset_match_data, Fmatch_data (Qnil, Qnil));
+ record_unwind_save_match_data ();
FOR_EACH_FRAME (tail, frame)
{
set_buffer_internal_1 (XBUFFER (w->buffer));
if (save_match_data)
- record_unwind_protect (Fset_match_data, Fmatch_data (Qnil, Qnil));
+ record_unwind_save_match_data ();
if (NILP (Voverriding_local_map_menu_flag))
{
specbind (Qoverriding_terminal_local_map, Qnil);
/* Save match data, if we must. */
if (save_match_data)
- record_unwind_protect (Fset_match_data, Fmatch_data (Qnil, Qnil));
+ record_unwind_save_match_data ();
/* Make sure that we don't accidentally use bogus keymaps. */
if (NILP (Voverriding_local_map_menu_flag))
(BUFFER_LOCAL_VALUEP (val)
|| SOME_BUFFER_LOCAL_VALUEP (val)))
&& XBUFFER_LOCAL_VALUE (val)->check_frame)
- Fsymbol_value (sym);
+ /* Use find_symbol_value rather than Fsymbol_value
+ to avoid an error if it is void. */
+ find_symbol_value (sym);
for (tail = XFRAME (old)->param_alist; CONSP (tail); tail = XCDR (tail))
if (CONSP (XCAR (tail))
(BUFFER_LOCAL_VALUEP (val)
|| SOME_BUFFER_LOCAL_VALUEP (val)))
&& XBUFFER_LOCAL_VALUE (val)->check_frame)
- Fsymbol_value (sym);
+ find_symbol_value (sym);
}
++redisplaying_p;
specbind (Qinhibit_free_realized_faces, Qnil);
+ {
+ Lisp_Object tail, frame;
+
+ FOR_EACH_FRAME (tail, frame)
+ {
+ struct frame *f = XFRAME (frame);
+ f->already_hscrolled_p = 0;
+ }
+ }
+
retry:
pause = 0;
reconsider_clip_changes (w, current_buffer);
if (FRAME_VISIBLE_P (f) && !FRAME_OBSCURED_P (f))
{
/* See if we have to hscroll. */
- if (hscroll_windows (f->root_window))
- goto retry;
+ if (!f->already_hscrolled_p)
+ {
+ f->already_hscrolled_p = 1;
+ if (hscroll_windows (f->root_window))
+ goto retry;
+ }
/* Prevent various kinds of signals during display
update. stdio is not robust about handling
window_height = window_box_height (w);
if (row->height >= window_height)
{
- if (!force_p || w->vscroll)
+ if (!force_p || MINI_WINDOW_P (w) || w->vscroll)
return 1;
}
return 0;
/* Display the window. Give up if new fonts are loaded, or if point
doesn't appear. */
- if (!try_window (window, startp))
+ if (!try_window (window, startp, 0))
rc = SCROLLING_NEED_LARGER_MATRICES;
else if (w->cursor.vpos < 0)
{
while (!row->mode_line_p
&& (MATRIX_ROW_START_CHARPOS (row) > PT
|| (MATRIX_ROW_START_CHARPOS (row) == PT
- && MATRIX_ROW_STARTS_IN_MIDDLE_OF_CHAR_P (row)))
+ && (MATRIX_ROW_STARTS_IN_MIDDLE_OF_CHAR_P (row)
+ || (/* STARTS_IN_MIDDLE_OF_STRING_P (row) */
+ row > w->current_matrix->rows
+ && (row-1)->ends_in_newline_from_string_p))))
&& (row->y > top_scroll_margin
|| CHARPOS (startp) == BEGV))
{
{
/* We set this later on if we have to adjust point. */
int new_vpos = -1;
+ int val;
w->force_start = Qnil;
w->vscroll = 0;
/* Redisplay, then check if cursor has been set during the
redisplay. Give up if new fonts were loaded. */
- if (!try_window (window, startp))
+ val = try_window (window, startp, 1);
+ if (!val)
{
w->force_start = Qt;
clear_glyph_matrix (w->desired_matrix);
goto need_larger_matrices;
}
+ /* Point was outside the scroll margins. */
+ if (val < 0)
+ new_vpos = window_box_height (w) / 2;
if (w->cursor.vpos < 0 && !w->frozen_window_start_p)
{
&& !NILP (current_buffer->mark_active))
{
clear_glyph_matrix (w->desired_matrix);
- if (!try_window (window, startp))
+ if (!try_window (window, startp, 0))
goto need_larger_matrices;
}
}
= try_window_reusing_current_matrix (w)))
{
IF_DEBUG (debug_method_add (w, "1"));
- try_window (window, startp);
+ if (try_window (window, startp, 1) < 0)
+ /* -1 means we need to scroll.
+ 0 means we need new matrices, but fonts_changed_p
+ is set in that case, so we will detect it below. */
+ goto try_to_scroll;
}
if (fonts_changed_p)
|| MINI_WINDOW_P (w)
|| !(used_current_matrix_p
= try_window_reusing_current_matrix (w)))
- try_window (window, startp);
+ try_window (window, startp, 0);
/* If new fonts have been loaded (due to fontsets), give up. We
have to start a new redisplay since we need to re-adjust glyph
{
clear_glyph_matrix (w->desired_matrix);
move_it_by_lines (&it, 1, 0);
- try_window (window, it.current.pos);
+ try_window (window, it.current.pos, 0);
}
else if (PT < IT_CHARPOS (it))
{
clear_glyph_matrix (w->desired_matrix);
move_it_by_lines (&it, -1, 0);
- try_window (window, it.current.pos);
+ try_window (window, it.current.pos, 0);
}
else
{
/* Build the complete desired matrix of WINDOW with a window start
- buffer position POS. Value is non-zero if successful. It is zero
- if fonts were loaded during redisplay which makes re-adjusting
- glyph matrices necessary. */
+ buffer position POS.
+
+ Value is 1 if successful. It is zero if fonts were loaded during
+ redisplay which makes re-adjusting glyph matrices necessary, and -1
+ if point would appear in the scroll margins.
+ (We check that only if CHECK_MARGINS is nonzero. */
int
-try_window (window, pos)
+try_window (window, pos, check_margins)
Lisp_Object window;
struct text_pos pos;
+ int check_margins;
{
struct window *w = XWINDOW (window);
struct it it;
return 0;
}
+ /* Don't let the cursor end in the scroll margins. */
+ if (check_margins
+ && !MINI_WINDOW_P (w))
+ {
+ int this_scroll_margin, cursor_height;
+
+ this_scroll_margin = max (0, scroll_margin);
+ this_scroll_margin = min (this_scroll_margin, WINDOW_TOTAL_LINES (w) / 4);
+ this_scroll_margin *= FRAME_LINE_HEIGHT (it.f);
+ cursor_height = MATRIX_ROW (w->desired_matrix, w->cursor.vpos)->height;
+
+ if ((w->cursor.y < this_scroll_margin
+ && CHARPOS (pos) > BEGV)
+ /* rms: considering make_cursor_line_fully_visible_p here
+ seems to give wrong results. We don't want to recenter
+ when the last line is partly visible, we want to allow
+ that case to be handled in the usual way. */
+ || (w->cursor.y + 1) > it.last_visible_y)
+ {
+ w->cursor.vpos = -1;
+ clear_glyph_matrix (w->desired_matrix);
+ return -1;
+ }
+ }
+
/* If bottom moved off end of frame, change mode line percentage. */
if (XFASTINT (w->window_end_pos) <= 0
&& Z != IT_CHARPOS (it))
if (PT == MATRIX_ROW_END_CHARPOS (row))
{
/* If the row ends with a newline from a string, we don't want
- the cursor there (if the row is continued it doesn't end in a
- newline). */
+ 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. */
if (CHARPOS (row->end.string_pos) >= 0)
- cursor_row_p = row->continued_p;
+ cursor_row_p = (row->continued_p
+ || PT >= MATRIX_ROW_START_CHARPOS (row));
else if (MATRIX_ROW_ENDS_IN_MIDDLE_OF_CHAR_P (row))
{
/* If the row ends in middle of a real character,
struct it *it;
Lisp_Object prop;
{
- Lisp_Object position, val;
+ Lisp_Object position;
if (STRINGP (it->object))
position = make_number (IT_STRING_CHARPOS (*it));
else
{
Lisp_Object spacing;
- int total = 0;
it->phys_ascent = it->ascent;
it->phys_descent = it->descent;
int ignore;
int vpos, hpos;
-
+
b = Fprevious_single_property_change (make_number (charpos + 1),
Qmouse_face, string, Qnil);
if (NILP (b))
hpos = (area == ON_MODE_LINE
? (w->current_matrix)->nrows - 1
: 0);
-
+
/* If the re-rendering position is included in the last
re-rendering area, we should do nothing. */
- if ( window == dpyinfo->mouse_face_window
+ if ( EQ (window, dpyinfo->mouse_face_window)
&& dpyinfo->mouse_face_beg_col <= vpos
&& vpos < dpyinfo->mouse_face_end_col
&& dpyinfo->mouse_face_beg_row == hpos )
return;
-
+
if (clear_mouse_face (dpyinfo))
cursor = No_Cursor;
-
+
dpyinfo->mouse_face_beg_col = vpos;
dpyinfo->mouse_face_beg_row = hpos;
if (NILP (pointer))
pointer = Qhand;
}
+ else if ((area == ON_MODE_LINE) || (area == ON_HEADER_LINE))
+ clear_mouse_face (dpyinfo);
}
-
define_frame_cursor1 (f, cursor, pointer);
}
/* If we were displaying active text in another window, clear that.
Also clear if we move out of text area in same window. */
if (! EQ (window, dpyinfo->mouse_face_window)
- || (part != ON_TEXT && part != ON_MODE_LINE && part != ON_HEADER_LINE
+ || (part != ON_TEXT && part != ON_MODE_LINE && part != ON_HEADER_LINE
&& !NILP (dpyinfo->mouse_face_window)))
clear_mouse_face (dpyinfo);
window_box_edges (w, -1, &x0, &y0, &x1, &y1);
y1 -= 1;
+ if (WINDOW_LEFT_FRINGE_WIDTH (w) == 0)
+ x1 -= 1;
+
rif->draw_vertical_window_border (w, x1, y0, y1);
}
else if (!WINDOW_LEFTMOST_P (w)
window_box_edges (w, -1, &x0, &y0, &x1, &y1);
y1 -= 1;
+ if (WINDOW_LEFT_FRINGE_WIDTH (w) == 0)
+ x0 -= 1;
+
rif->draw_vertical_window_border (w, x0, y0, y1);
}
}
staticpro (&Qtrailing_whitespace);
Qescape_glyph = intern ("escape-glyph");
staticpro (&Qescape_glyph);
- Qno_break_space = intern ("no-break-space");
- staticpro (&Qno_break_space);
+ Qnobreak_space = intern ("nobreak-space");
+ staticpro (&Qnobreak_space);
Qimage = intern ("image");
staticpro (&Qimage);
QCmap = intern (":map");
The face used for trailing whitespace is `trailing-whitespace'. */);
Vshow_trailing_whitespace = Qnil;
- DEFVAR_LISP ("show-nonbreak-escape", &Vshow_nonbreak_escape,
- doc: /* *Non-nil means display escape character before non-break space and hyphen. */);
- Vshow_nonbreak_escape = Qt;
+ DEFVAR_LISP ("nobreak-char-display", &Vnobreak_char_display,
+ doc: /* *Control highlighting of nobreak space and soft hyphen.
+A value of t means highlight the character itself (for nobreak space,
+use face `nobreak-space').
+A value of nil means no highlighting.
+Other values mean display the escape glyph followed by an ordinary
+space or ordinary hyphen. */);
+ Vnobreak_char_display = Qt;
DEFVAR_LISP ("void-text-area-pointer", &Vvoid_text_area_pointer,
doc: /* *The pointer shape to show in void text areas.
-Nil means to show the text pointer. Other options are `arrow', `text',
-`hand', `vdrag', `hdrag', `modeline', and `hourglass'. */);
+A value of nil means to show the text pointer. Other options are `arrow',
+`text', `hand', `vdrag', `hdrag', `modeline', and `hourglass'. */);
Vvoid_text_area_pointer = Qarrow;
DEFVAR_LISP ("inhibit-redisplay", &Vinhibit_redisplay,