X-Git-Url: https://code.delx.au/gnu-emacs/blobdiff_plain/edfaeb4ee9abb4bed5d8fe723cc123c3299252e8..d562f8abe78b39316a84c6dc5d96de858b7331f4:/src/xdisp.c diff --git a/src/xdisp.c b/src/xdisp.c index b20c4815ab..09cf8a7f5d 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 . @@ -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; @@ -350,6 +350,10 @@ Lisp_Object Qtrailing_whitespace; Lisp_Object Qescape_glyph; +/* Name and number of the face used to highlight non-breaking spaces. */ + +Lisp_Object Qnobreak_space; + /* The symbol `image' which is the car of the lists used to represent images in Lisp. */ @@ -843,8 +847,8 @@ static struct text_pos run_window_scroll_functions P_ ((Lisp_Object, struct text_pos)); static void reconsider_clip_changes P_ ((struct window *, struct buffer *)); static int text_outside_line_unchanged_p P_ ((struct window *, int, int)); -static void store_frame_title_char P_ ((char)); -static int store_frame_title P_ ((const unsigned char *, int, int)); +static void store_mode_line_noprop_char P_ ((char)); +static int store_mode_line_noprop P_ ((const unsigned char *, int, int)); static void x_consider_frame_title P_ ((Lisp_Object)); static void handle_stop P_ ((struct it *)); static int tool_bar_lines_needed P_ ((struct frame *)); @@ -1894,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 @@ -2404,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; @@ -5093,9 +5099,11 @@ get_next_display_element (it) ? ((it->c >= 127 && it->len == 1) || !CHAR_PRINTABLE_P (it->c) - || (!NILP (Vshow_nonbreak_escape) - && (it->c == 0x8ad || it->c == 0x8a0 - || it->c == 0xf2d || it->c == 0xf20))) + || (!NILP (Vnobreak_char_display) + && (it->c == 0x8a0 || it->c == 0x8ad + || it->c == 0x920 || it->c == 0x92d + || it->c == 0xe20 || it->c == 0xe2d + || it->c == 0xf20 || it->c == 0xf2d))) : (it->c >= 127 && (!unibyte_display_via_language_environment || it->c == unibyte_char_to_multibyte (it->c))))) @@ -5110,6 +5118,8 @@ get_next_display_element (it) 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 */ @@ -5141,7 +5151,28 @@ get_next_display_element (it) 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)))) @@ -5151,6 +5182,8 @@ get_next_display_element (it) } 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); @@ -5162,11 +5195,29 @@ get_next_display_element (it) it->face_id); } + /* Handle soft hyphens in the mode where they only get + highlighting. */ + + 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; + } + + /* 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) { XSETINT (it->ctl_chars[0], escape_glyph); - g = it->c; + g = it->c = ((it->c & 0xf) == 0 ? ' ' : '-'); XSETINT (it->ctl_chars[1], g); ctl_len = 2; goto display_control; @@ -5822,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. @@ -6330,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; @@ -6529,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 @@ -7543,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; } @@ -8159,52 +8247,125 @@ echo_area_display (update_frame_p) /*********************************************************************** - Frame Titles + Mode Lines and Frame Titles ***********************************************************************/ +/* A buffer for constructing non-propertized mode-line strings and + frame titles in it; allocated from the heap in init_xdisp and + resized as needed in store_mode_line_noprop_char. */ + +static char *mode_line_noprop_buf; -/* The frame title buffering code is also used by Fformat_mode_line. - So it is not conditioned by HAVE_WINDOW_SYSTEM. */ +/* The buffer's end, and a current output position in it. */ -/* A buffer for constructing frame titles in it; allocated from the - heap in init_xdisp and resized as needed in store_frame_title_char. */ +static char *mode_line_noprop_buf_end; +static char *mode_line_noprop_ptr; -static char *frame_title_buf; +#define MODE_LINE_NOPROP_LEN(start) \ + ((mode_line_noprop_ptr - mode_line_noprop_buf) - start) -/* The buffer's end, and a current output position in it. */ +static enum { + MODE_LINE_DISPLAY = 0, + MODE_LINE_TITLE, + MODE_LINE_NOPROP, + MODE_LINE_STRING +} mode_line_target; + +/* Alist that caches the results of :propertize. + Each element is (PROPERTIZED-STRING . PROPERTY-LIST). */ +static Lisp_Object mode_line_proptrans_alist; + +/* List of strings making up the mode-line. */ +static Lisp_Object mode_line_string_list; + +/* Base face property when building propertized mode line string. */ +static Lisp_Object mode_line_string_face; +static Lisp_Object mode_line_string_face_prop; + + +/* Unwind data for mode line strings */ + +static Lisp_Object Vmode_line_unwind_vector; + +static Lisp_Object +format_mode_line_unwind_data (obuf) + struct buffer *obuf; +{ + Lisp_Object vector; + + /* Reduce consing by keeping one vector in + Vwith_echo_area_save_vector. */ + vector = Vmode_line_unwind_vector; + Vmode_line_unwind_vector = Qnil; + + if (NILP (vector)) + vector = Fmake_vector (make_number (7), Qnil); + + AREF (vector, 0) = make_number (mode_line_target); + AREF (vector, 1) = make_number (MODE_LINE_NOPROP_LEN (0)); + AREF (vector, 2) = mode_line_string_list; + AREF (vector, 3) = mode_line_proptrans_alist; + AREF (vector, 4) = mode_line_string_face; + AREF (vector, 5) = mode_line_string_face_prop; + + if (obuf) + XSETBUFFER (AREF (vector, 6), obuf); + else + AREF (vector, 6) = Qnil; + + return vector; +} -static char *frame_title_buf_end; -static char *frame_title_ptr; +static Lisp_Object +unwind_format_mode_line (vector) + Lisp_Object vector; +{ + mode_line_target = XINT (AREF (vector, 0)); + mode_line_noprop_ptr = mode_line_noprop_buf + XINT (AREF (vector, 1)); + mode_line_string_list = AREF (vector, 2); + mode_line_proptrans_alist = AREF (vector, 3); + mode_line_string_face = AREF (vector, 4); + mode_line_string_face_prop = AREF (vector, 5); + if (!NILP (AREF (vector, 6))) + { + set_buffer_internal_1 (XBUFFER (AREF (vector, 6))); + AREF (vector, 6) = Qnil; + } + + Vmode_line_unwind_vector = vector; + return Qnil; +} -/* Store a single character C for the frame title in frame_title_buf. - Re-allocate frame_title_buf if necessary. */ + +/* Store a single character C for the frame title in mode_line_noprop_buf. + Re-allocate mode_line_noprop_buf if necessary. */ static void #ifdef PROTOTYPES -store_frame_title_char (char c) +store_mode_line_noprop_char (char c) #else -store_frame_title_char (c) +store_mode_line_noprop_char (c) char c; #endif { /* If output position has reached the end of the allocated buffer, double the buffer's size. */ - if (frame_title_ptr == frame_title_buf_end) + if (mode_line_noprop_ptr == mode_line_noprop_buf_end) { - int len = frame_title_ptr - frame_title_buf; - int new_size = 2 * len * sizeof *frame_title_buf; - frame_title_buf = (char *) xrealloc (frame_title_buf, new_size); - frame_title_buf_end = frame_title_buf + new_size; - frame_title_ptr = frame_title_buf + len; + int len = MODE_LINE_NOPROP_LEN (0); + int new_size = 2 * len * sizeof *mode_line_noprop_buf; + mode_line_noprop_buf = (char *) xrealloc (mode_line_noprop_buf, new_size); + mode_line_noprop_buf_end = mode_line_noprop_buf + new_size; + mode_line_noprop_ptr = mode_line_noprop_buf + len; } - *frame_title_ptr++ = c; + *mode_line_noprop_ptr++ = c; } -/* Store part of a frame title in frame_title_buf, beginning at - frame_title_ptr. STR is the string to store. Do not copy +/* Store part of a frame title in mode_line_noprop_buf, beginning at + mode_line_noprop_ptr. STR is the string to store. Do not copy characters that yield more columns than PRECISION; PRECISION <= 0 means copy the whole string. Pad with spaces until FIELD_WIDTH number of characters have been copied; FIELD_WIDTH <= 0 means don't @@ -8212,7 +8373,7 @@ store_frame_title_char (c) frame title. */ static int -store_frame_title (str, field_width, precision) +store_mode_line_noprop (str, field_width, precision) const unsigned char *str; int field_width, precision; { @@ -8223,19 +8384,23 @@ store_frame_title (str, field_width, precision) nbytes = strlen (str); n += c_string_width (str, nbytes, precision, &dummy, &nbytes); while (nbytes--) - store_frame_title_char (*str++); + store_mode_line_noprop_char (*str++); /* Fill up with spaces until FIELD_WIDTH reached. */ while (field_width > 0 && n < field_width) { - store_frame_title_char (' '); + store_mode_line_noprop_char (' '); ++n; } return n; } +/*********************************************************************** + Frame Titles + ***********************************************************************/ + #ifdef HAVE_WINDOW_SYSTEM /* Set the title of FRAME, if it has changed. The title format is @@ -8255,9 +8420,11 @@ x_consider_frame_title (frame) /* Do we have more than one visible frame on this X display? */ Lisp_Object tail; Lisp_Object fmt; - struct buffer *obuf; + int title_start; + char *title; int len; struct it it; + int count = SPECPDL_INDEX (); for (tail = Vframe_list; CONSP (tail); tail = XCDR (tail)) { @@ -8276,18 +8443,22 @@ x_consider_frame_title (frame) multiple_frames = CONSP (tail); /* Switch to the buffer of selected window of the frame. Set up - frame_title_ptr so that display_mode_element will output into it; - then display the title. */ - obuf = current_buffer; + mode_line_target so that display_mode_element will output into + mode_line_noprop_buf; then display the title. */ + record_unwind_protect (unwind_format_mode_line, + format_mode_line_unwind_data (current_buffer)); + set_buffer_internal_1 (XBUFFER (XWINDOW (f->selected_window)->buffer)); fmt = FRAME_ICONIFIED_P (f) ? Vicon_title_format : Vframe_title_format; - frame_title_ptr = frame_title_buf; + + mode_line_target = MODE_LINE_TITLE; + title_start = MODE_LINE_NOPROP_LEN (0); init_iterator (&it, XWINDOW (f->selected_window), -1, -1, NULL, DEFAULT_FACE_ID); display_mode_element (&it, 0, -1, -1, fmt, Qnil, 0); - len = frame_title_ptr - frame_title_buf; - frame_title_ptr = NULL; - set_buffer_internal_1 (obuf); + len = MODE_LINE_NOPROP_LEN (title_start); + title = mode_line_noprop_buf + title_start; + unbind_to (count, Qnil); /* 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 @@ -8296,8 +8467,8 @@ x_consider_frame_title (frame) higher level than this.) */ if (! STRINGP (f->name) || SBYTES (f->name) != len - || bcmp (frame_title_buf, SDATA (f->name), len) != 0) - x_implicitly_set_name (f, make_string (frame_title_buf, len), Qnil); + || bcmp (title, SDATA (f->name), len) != 0) + x_implicitly_set_name (f, make_string (title, len), Qnil); } } @@ -8356,7 +8527,7 @@ prepare_menu_bars () 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) { @@ -8479,7 +8650,7 @@ update_menu_bar (f, save_match_data) 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); @@ -8670,7 +8841,7 @@ update_tool_bar (f, save_match_data) /* 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)) @@ -9914,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)) @@ -9925,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); } @@ -9999,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); @@ -10433,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 @@ -11162,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; @@ -11438,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) { @@ -11692,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)) { @@ -12041,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; @@ -12074,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) { @@ -12122,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; } } @@ -12212,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) @@ -12342,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 @@ -12362,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 { @@ -12551,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; @@ -12583,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)) @@ -14825,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, @@ -15592,6 +15822,7 @@ display_mode_line (w, face_id, format) { struct it it; struct face *face; + int count = SPECPDL_INDEX (); init_iterator (&it, w, -1, -1, NULL, face_id); prepare_desired_row (it.glyph_row); @@ -15602,6 +15833,11 @@ display_mode_line (w, face_id, format) /* Force the mode-line to be displayed in the default face. */ it.base_face_id = it.face_id = DEFAULT_FACE_ID; + record_unwind_protect (unwind_format_mode_line, + format_mode_line_unwind_data (NULL)); + + mode_line_target = MODE_LINE_DISPLAY; + /* Temporarily make frame's keyboard the current kboard so that kboard-local variables in the mode_line_format will get the right values. */ @@ -15609,6 +15845,8 @@ display_mode_line (w, face_id, format) display_mode_element (&it, 0, 0, 0, format, Qnil, 0); pop_frame_kboard (); + unbind_to (count, Qnil); + /* Fill up with spaces. */ display_string (" ", Qnil, Qnil, 0, 0, &it, 10000, -1, -1, 0); @@ -15631,18 +15869,6 @@ display_mode_line (w, face_id, format) return it.glyph_row->height; } -/* Alist that caches the results of :propertize. - Each element is (PROPERTIZED-STRING . PROPERTY-LIST). */ -Lisp_Object mode_line_proptrans_alist; - -/* List of strings making up the mode-line. */ -Lisp_Object mode_line_string_list; - -/* Base face property when building propertized mode line string. */ -static Lisp_Object mode_line_string_face; -static Lisp_Object mode_line_string_face_prop; - - /* Contribute ELT to the mode line for window IT->w. How it translates into text depends on its data type. @@ -15663,8 +15889,9 @@ static Lisp_Object mode_line_string_face_prop; If RISKY is nonzero, remove (disregard) any properties in any string we encounter, and ignore :eval and :propertize. - If the global variable `frame_title_ptr' is non-NULL, then the output - is passed to `store_frame_title' instead of `display_string'. */ + The global variable `mode_line_target' determines whether the + output is passed to `store_mode_line_noprop', + `store_mode_line_string', or `display_string'. */ static int display_mode_element (it, depth, field_width, precision, elt, props, risky) @@ -15753,21 +15980,27 @@ display_mode_element (it, depth, field_width, precision, elt, props, risky) if (literal) { prec = precision - n; - if (frame_title_ptr) - n += store_frame_title (SDATA (elt), -1, prec); - else if (!NILP (mode_line_string_list)) - n += store_mode_line_string (NULL, elt, 1, 0, prec, Qnil); - else - n += display_string (NULL, elt, Qnil, 0, 0, it, - 0, prec, 0, STRING_MULTIBYTE (elt)); + switch (mode_line_target) + { + case MODE_LINE_NOPROP: + case MODE_LINE_TITLE: + n += store_mode_line_noprop (SDATA (elt), -1, prec); + break; + case MODE_LINE_STRING: + n += store_mode_line_string (NULL, elt, 1, 0, prec, Qnil); + break; + case MODE_LINE_DISPLAY: + n += display_string (NULL, elt, Qnil, 0, 0, it, + 0, prec, 0, STRING_MULTIBYTE (elt)); + break; + } break; } while ((precision <= 0 || n < precision) && *this - && (frame_title_ptr - || !NILP (mode_line_string_list) + && (mode_line_target != MODE_LINE_DISPLAY || it->current_x < it->last_visible_x)) { const unsigned char *last = this; @@ -15788,29 +16021,36 @@ display_mode_element (it, depth, field_width, precision, elt, props, risky) prec = c_string_width (last, this - last, precision - n, &nchars, &nbytes); - if (frame_title_ptr) - n += store_frame_title (last, 0, prec); - else if (!NILP (mode_line_string_list)) + switch (mode_line_target) { - int bytepos = last - lisp_string; - int charpos = string_byte_to_char (elt, bytepos); - int endpos = (precision <= 0 - ? string_byte_to_char (elt, - this - lisp_string) - : charpos + nchars); - - n += store_mode_line_string (NULL, - Fsubstring (elt, make_number (charpos), - make_number (endpos)), - 0, 0, 0, Qnil); - } - else - { - int bytepos = last - lisp_string; - int charpos = string_byte_to_char (elt, bytepos); - n += display_string (NULL, elt, Qnil, 0, charpos, - it, 0, prec, 0, - STRING_MULTIBYTE (elt)); + case MODE_LINE_NOPROP: + case MODE_LINE_TITLE: + n += store_mode_line_noprop (last, 0, prec); + break; + case MODE_LINE_STRING: + { + int bytepos = last - lisp_string; + int charpos = string_byte_to_char (elt, bytepos); + int endpos = (precision <= 0 + ? string_byte_to_char (elt, + this - lisp_string) + : charpos + nchars); + + n += store_mode_line_string (NULL, + Fsubstring (elt, make_number (charpos), + make_number (endpos)), + 0, 0, 0, Qnil); + } + break; + case MODE_LINE_DISPLAY: + { + int bytepos = last - lisp_string; + int charpos = string_byte_to_char (elt, bytepos); + n += display_string (NULL, elt, Qnil, 0, charpos, + it, 0, prec, 0, + STRING_MULTIBYTE (elt)); + } + break; } } else /* c == '%' */ @@ -15848,44 +16088,51 @@ display_mode_element (it, depth, field_width, precision, elt, props, risky) spec = decode_mode_spec (it->w, c, field, prec, &multibyte); - if (frame_title_ptr) - n += store_frame_title (spec, field, prec); - else if (!NILP (mode_line_string_list)) + switch (mode_line_target) { - int len = strlen (spec); - Lisp_Object tem = make_string (spec, len); - props = Ftext_properties_at (make_number (charpos), elt); - /* Should only keep face property in props */ - n += store_mode_line_string (NULL, tem, 0, field, prec, props); - } - else - { - int nglyphs_before, nwritten; - - nglyphs_before = it->glyph_row->used[TEXT_AREA]; - nwritten = display_string (spec, Qnil, elt, - charpos, 0, it, - field, prec, 0, - multibyte); - - /* Assign to the glyphs written above the - string where the `%x' came from, position - of the `%'. */ - if (nwritten > 0) - { - struct glyph *glyph - = (it->glyph_row->glyphs[TEXT_AREA] - + nglyphs_before); - int i; - - for (i = 0; i < nwritten; ++i) - { - glyph[i].object = elt; - glyph[i].charpos = charpos; - } - - n += nwritten; - } + case MODE_LINE_NOPROP: + case MODE_LINE_TITLE: + n += store_mode_line_noprop (spec, field, prec); + break; + case MODE_LINE_STRING: + { + int len = strlen (spec); + Lisp_Object tem = make_string (spec, len); + props = Ftext_properties_at (make_number (charpos), elt); + /* Should only keep face property in props */ + n += store_mode_line_string (NULL, tem, 0, field, prec, props); + } + break; + case MODE_LINE_DISPLAY: + { + int nglyphs_before, nwritten; + + nglyphs_before = it->glyph_row->used[TEXT_AREA]; + nwritten = display_string (spec, Qnil, elt, + charpos, 0, it, + field, prec, 0, + multibyte); + + /* Assign to the glyphs written above the + string where the `%x' came from, position + of the `%'. */ + if (nwritten > 0) + { + struct glyph *glyph + = (it->glyph_row->glyphs[TEXT_AREA] + + nglyphs_before); + int i; + + for (i = 0; i < nwritten; ++i) + { + glyph[i].object = elt; + glyph[i].charpos = charpos; + } + + n += nwritten; + } + } + break; } } else /* c == 0 */ @@ -16056,13 +16303,20 @@ display_mode_element (it, depth, field_width, precision, elt, props, risky) /* Pad to FIELD_WIDTH. */ if (field_width > 0 && n < field_width) { - if (frame_title_ptr) - n += store_frame_title ("", field_width - n, 0); - else if (!NILP (mode_line_string_list)) - n += store_mode_line_string ("", Qnil, 0, field_width - n, 0, Qnil); - else - n += display_string ("", Qnil, Qnil, 0, 0, it, field_width - n, - 0, 0, 0); + switch (mode_line_target) + { + case MODE_LINE_NOPROP: + case MODE_LINE_TITLE: + n += store_mode_line_noprop ("", field_width - n, 0); + break; + case MODE_LINE_STRING: + n += store_mode_line_string ("", Qnil, 0, field_width - n, 0, Qnil); + break; + case MODE_LINE_DISPLAY: + n += display_string ("", Qnil, Qnil, 0, 0, it, field_width - n, + 0, 0, 0); + break; + } } return n; @@ -16194,6 +16448,9 @@ are the selected window and the window's buffer). */) struct buffer *old_buffer = NULL; int face_id = -1; int no_props = INTEGERP (face); + int count = SPECPDL_INDEX (); + Lisp_Object str; + int string_start = 0; if (NILP (window)) window = selected_window; @@ -16221,64 +16478,50 @@ are the selected window and the window's buffer). */) face_id = DEFAULT_FACE_ID; if (XBUFFER (buffer) != current_buffer) - { - old_buffer = current_buffer; - set_buffer_internal_1 (XBUFFER (buffer)); - } + old_buffer = current_buffer; + + record_unwind_protect (unwind_format_mode_line, + format_mode_line_unwind_data (old_buffer)); + + if (old_buffer) + set_buffer_internal_1 (XBUFFER (buffer)); init_iterator (&it, w, -1, -1, NULL, face_id); - if (!no_props) + if (no_props) { - mode_line_string_face = face; - mode_line_string_face_prop - = (NILP (face) ? Qnil : Fcons (Qface, Fcons (face, Qnil))); - - /* We need a dummy last element in mode_line_string_list to - indicate we are building the propertized mode-line string. - Using mode_line_string_face_prop here GC protects it. */ - mode_line_string_list - = Fcons (mode_line_string_face_prop, Qnil); - frame_title_ptr = NULL; + mode_line_target = MODE_LINE_NOPROP; + mode_line_string_face_prop = Qnil; + mode_line_string_list = Qnil; + string_start = MODE_LINE_NOPROP_LEN (0); } else { - mode_line_string_face_prop = Qnil; + mode_line_target = MODE_LINE_STRING; mode_line_string_list = Qnil; - frame_title_ptr = frame_title_buf; + mode_line_string_face = face; + mode_line_string_face_prop + = (NILP (face) ? Qnil : Fcons (Qface, Fcons (face, Qnil))); } push_frame_kboard (it.f); display_mode_element (&it, 0, 0, 0, format, Qnil, 0); pop_frame_kboard (); - if (old_buffer) - set_buffer_internal_1 (old_buffer); - - if (!no_props) + if (no_props) { - Lisp_Object str; - mode_line_string_list = Fnreverse (mode_line_string_list); - str = Fmapconcat (intern ("identity"), XCDR (mode_line_string_list), - make_string ("", 0)); - mode_line_string_face_prop = Qnil; - mode_line_string_list = Qnil; - return str; + len = MODE_LINE_NOPROP_LEN (string_start); + str = make_string (mode_line_noprop_buf + string_start, len); } - - len = frame_title_ptr - frame_title_buf; - if (len > 0 && frame_title_ptr[-1] == '-') + else { - /* Mode lines typically ends with numerous dashes; reduce to two dashes. */ - while (frame_title_ptr > frame_title_buf && *--frame_title_ptr == '-') - ; - frame_title_ptr += 3; /* restore last non-dash + two dashes */ - if (len > frame_title_ptr - frame_title_buf) - len = frame_title_ptr - frame_title_buf; + mode_line_string_list = Fnreverse (mode_line_string_list); + str = Fmapconcat (intern ("identity"), mode_line_string_list, + make_string ("", 0)); } - frame_title_ptr = NULL; - return make_string (frame_title_buf, len); + unbind_to (count, Qnil); + return str; } /* Write a null-terminated, right justified decimal representation of @@ -16596,7 +16839,8 @@ decode_mode_spec (w, c, field_width, precision, multibyte) register int i; /* Let lots_of_dashes be a string of infinite length. */ - if (!NILP (mode_line_string_list)) + if (mode_line_target == MODE_LINE_NOPROP || + mode_line_target == MODE_LINE_STRING) return "--"; if (field_width <= 0 || field_width > sizeof (lots_of_dashes)) @@ -19054,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)); @@ -19405,7 +19649,6 @@ x_produce_glyphs (it) else { Lisp_Object spacing; - int total = 0; it->phys_ascent = it->ascent; it->phys_descent = it->descent; @@ -21375,9 +21618,7 @@ note_mode_line_or_margin_highlight (window, x, y, area) int total_pixel_width; int ignore; - - if (clear_mouse_face (dpyinfo)) - cursor = No_Cursor; + int vpos, hpos; b = Fprevious_single_property_change (make_number (charpos + 1), Qmouse_face, string, Qnil); @@ -21400,7 +21641,7 @@ note_mode_line_or_margin_highlight (window, x, y, area) tmp_glyph->charpos >= XINT (b); tmp_glyph--, gpos++) { - if (tmp_glyph->object != glyph->object) + if (!EQ (tmp_glyph->object, glyph->object)) break; } @@ -21413,7 +21654,7 @@ note_mode_line_or_margin_highlight (window, x, y, area) tmp_glyph->charpos < XINT (e); tmp_glyph++, gseq_length++) { - if (tmp_glyph->object != glyph->object) + if (!EQ (tmp_glyph->object, glyph->object)) break; } @@ -21421,15 +21662,30 @@ note_mode_line_or_margin_highlight (window, x, y, area) for (tmp_glyph = glyph - gpos; tmp_glyph != glyph; tmp_glyph++) total_pixel_width += tmp_glyph->pixel_width; - dpyinfo->mouse_face_beg_col = (x - gpos); - dpyinfo->mouse_face_beg_row = (area == ON_MODE_LINE - ? (w->current_matrix)->nrows - 1 - : 0); + /* Pre calculation of re-rendering position */ + vpos = (x - gpos); + 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 ( 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; dpyinfo->mouse_face_beg_x = original_x_pixel - (total_pixel_width + dx); dpyinfo->mouse_face_beg_y = 0; - dpyinfo->mouse_face_end_col = (x - gpos) + gseq_length; + dpyinfo->mouse_face_end_col = vpos + gseq_length; dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_beg_row; dpyinfo->mouse_face_end_x = 0; @@ -21447,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); } @@ -21501,7 +21758,8 @@ 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 && !NILP (dpyinfo->mouse_face_window))) + || (part != ON_TEXT && part != ON_MODE_LINE && part != ON_HEADER_LINE + && !NILP (dpyinfo->mouse_face_window))) clear_mouse_face (dpyinfo); /* Not on a window -> return. */ @@ -22203,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) @@ -22213,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); } } @@ -22616,6 +22880,8 @@ syms_of_xdisp () staticpro (&Qtrailing_whitespace); Qescape_glyph = intern ("escape-glyph"); staticpro (&Qescape_glyph); + Qnobreak_space = intern ("nobreak-space"); + staticpro (&Qnobreak_space); Qimage = intern ("image"); staticpro (&Qimage); QCmap = intern (":map"); @@ -22689,9 +22955,14 @@ syms_of_xdisp () mode_line_proptrans_alist = Qnil; staticpro (&mode_line_proptrans_alist); - mode_line_string_list = Qnil; staticpro (&mode_line_string_list); + mode_line_string_face = Qnil; + staticpro (&mode_line_string_face); + mode_line_string_face_prop = Qnil; + staticpro (&mode_line_string_face_prop); + Vmode_line_unwind_vector = Qnil; + staticpro (&Vmode_line_unwind_vector); help_echo_string = Qnil; staticpro (&help_echo_string); @@ -22716,14 +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: /* *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, @@ -23041,9 +23317,10 @@ init_xdisp () /* Allocate the buffer for frame titles. Also used for `format-mode-line'. */ int size = 100; - frame_title_buf = (char *) xmalloc (size); - frame_title_buf_end = frame_title_buf + size; - frame_title_ptr = NULL; + mode_line_noprop_buf = (char *) xmalloc (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; } help_echo_showing_p = 0;