X-Git-Url: https://code.delx.au/gnu-emacs/blobdiff_plain/89f2614d96b5cf84f01c4903652a6a2b5b23d3d3..2a205424e771703217ce8c6b4252d810d3310cd2:/src/xdisp.c diff --git a/src/xdisp.c b/src/xdisp.c index 3a44cc808c..d7de7dbe82 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -16,8 +16,8 @@ GNU General Public License for more details. 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 . @@ -231,7 +231,7 @@ extern Lisp_Object Qhelp_echo; Lisp_Object Qoverriding_local_map, Qoverriding_terminal_local_map; Lisp_Object Qwindow_scroll_functions, Vwindow_scroll_functions; -Lisp_Object Qredisplay_end_trigger_functions; +Lisp_Object Qredisplay_end_trigger_functions, Vredisplay_end_trigger_functions; Lisp_Object Qinhibit_point_motion_hooks; Lisp_Object QCeval, QCfile, QCdata, QCpropertize; Lisp_Object Qfontified; @@ -320,7 +320,7 @@ Lisp_Object Vshow_trailing_whitespace; /* 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; @@ -352,7 +352,7 @@ Lisp_Object Qescape_glyph; /* 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. */ @@ -1898,7 +1898,7 @@ get_phys_cursor_geometry (w, row, glyph, heightp) 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 @@ -2408,7 +2408,9 @@ start_display (it, w, pos) 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; @@ -5097,7 +5099,7 @@ get_next_display_element (it) ? ((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 @@ -5152,12 +5154,12 @@ get_next_display_element (it) /* Handle non-break space in the mode where it only gets highlighting. */ - if (! EQ (Vshow_nonbreak_escape, Qt) + 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, Qno_break_space, 0, + face_id = merge_faces (it->f, Qnobreak_space, 0, it->face_id); g = it->c = ' '; @@ -5196,7 +5198,7 @@ get_next_display_element (it) /* Handle soft hyphens in the mode where they only get highlighting. */ - if (! EQ (Vshow_nonbreak_escape, Qt) + if (EQ (Vnobreak_char_display, Qt) && (it->c == 0x8ad || it->c == 0x92d || it->c == 0xe2d || it->c == 0xf2d)) { @@ -5871,6 +5873,15 @@ next_element_from_composition (it) 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. @@ -6379,8 +6390,12 @@ move_it_vertically_backward (it, dy) 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; @@ -6578,21 +6593,45 @@ move_it_by_lines (it, dvpos, need_y_p) 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 @@ -7592,7 +7631,7 @@ display_echo_area_1 (a1, a2, a3, a4) 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; } @@ -8252,7 +8291,6 @@ static Lisp_Object format_mode_line_unwind_data (obuf) struct buffer *obuf; { - int i = 0; Lisp_Object vector; /* Reduce consing by keeping one vector in @@ -10047,7 +10085,9 @@ select_frame_for_redisplay (frame) (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)) @@ -10058,7 +10098,7 @@ select_frame_for_redisplay (frame) (BUFFER_LOCAL_VALUEP (val) || SOME_BUFFER_LOCAL_VALUEP (val))) && XBUFFER_LOCAL_VALUE (val)->check_frame) - Fsymbol_value (sym); + find_symbol_value (sym); } @@ -10132,6 +10172,16 @@ redisplay_internal (preserve_echo_area) ++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); @@ -10566,8 +10616,12 @@ redisplay_internal (preserve_echo_area) 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 @@ -11295,7 +11349,7 @@ cursor_row_fully_visible_p (w, force_p, current_matrix_p) 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; @@ -11571,7 +11625,7 @@ try_scrolling (window, just_this_one_p, scroll_conservatively, /* 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) { @@ -11825,7 +11879,10 @@ try_cursor_movement (window, startp, scroll_step) 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)) { @@ -12174,6 +12231,7 @@ redisplay_window (window, just_this_one_p) { /* We set this later on if we have to adjust point. */ int new_vpos = -1; + int val; w->force_start = Qnil; w->vscroll = 0; @@ -12207,12 +12265,16 @@ redisplay_window (window, just_this_one_p) /* 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) { @@ -12255,7 +12317,7 @@ redisplay_window (window, just_this_one_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; } } @@ -12345,7 +12407,11 @@ redisplay_window (window, just_this_one_p) = 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) @@ -12475,7 +12541,7 @@ redisplay_window (window, just_this_one_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 @@ -12495,13 +12561,13 @@ redisplay_window (window, just_this_one_p) { 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 { @@ -12684,14 +12750,18 @@ redisplay_window (window, just_this_one_p) /* 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; @@ -12716,6 +12786,31 @@ try_window (window, pos) 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)) @@ -14958,10 +15053,12 @@ cursor_row_p (w, row) 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, @@ -19201,7 +19298,7 @@ get_line_height_property (it, prop) struct it *it; Lisp_Object prop; { - Lisp_Object position, val; + Lisp_Object position; if (STRINGP (it->object)) position = make_number (IT_STRING_CHARPOS (*it)); @@ -19552,7 +19649,6 @@ x_produce_glyphs (it) else { Lisp_Object spacing; - int total = 0; it->phys_ascent = it->ascent; it->phys_descent = it->descent; @@ -21523,7 +21619,7 @@ note_mode_line_or_margin_highlight (window, x, y, area) int ignore; int vpos, hpos; - + b = Fprevious_single_property_change (make_number (charpos + 1), Qmouse_face, string, Qnil); if (NILP (b)) @@ -21571,18 +21667,18 @@ note_mode_line_or_margin_highlight (window, x, y, area) 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; @@ -21607,8 +21703,9 @@ note_mode_line_or_margin_highlight (window, x, y, area) 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); } @@ -21661,7 +21758,7 @@ note_mouse_highlight (f, x, y) /* 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); @@ -22364,6 +22461,9 @@ x_draw_vertical_border (w) 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) @@ -22374,6 +22474,9 @@ x_draw_vertical_border (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); } } @@ -22777,8 +22880,8 @@ syms_of_xdisp () 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"); @@ -22884,18 +22987,19 @@ wide as that tab on the display. */); The face used for trailing whitespace is `trailing-whitespace'. */); Vshow_trailing_whitespace = Qnil; - DEFVAR_LISP ("show-nonbreak-escape", &Vshow_nonbreak_escape, - doc: /* *Control highlighting of non-break space and soft hyphen. -t means highlight the character itself (for non-break space, -use face `non-break-space'. -nil means no highlighting. -other values mean display the escape glyph before the character. */); - 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, @@ -23032,6 +23136,12 @@ and its new display-start position. Note that the value of `window-end' is not valid when these functions are called. */); Vwindow_scroll_functions = Qnil; + DEFVAR_LISP ("redisplay-end-trigger-functions", &Vredisplay_end_trigger_functions, + doc: /* Functions called when redisplay of a window reaches the end trigger. +Each function is called with two arguments, the window and the end trigger value. +See `set-window-redisplay-end-trigger'. */); + Vredisplay_end_trigger_functions = Qnil; + DEFVAR_BOOL ("mouse-autoselect-window", &mouse_autoselect_window, doc: /* *Non-nil means autoselect window with mouse pointer. */); mouse_autoselect_window = 0;