X-Git-Url: https://code.delx.au/gnu-emacs/blobdiff_plain/5b4879885e61279efd5a779369deeddfeea8c1fd..95797ede756b9aa12fbbd5a64949071cd428032a:/src/xdisp.c diff --git a/src/xdisp.c b/src/xdisp.c index e3e1048aae..b4ebd59563 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -1,6 +1,7 @@ /* Display generation from window structure and buffer text. - Copyright (C) 1985, 1986, 1987, 1988, 1993, 1994, 1995, 1997, 1998, 1999, - 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc. + Copyright (C) 1985, 1986, 1987, 1988, 1993, 1994, 1995, + 1997, 1998, 1999, 2000, 2001, 2002, 2003, + 2004, 2005, 2006 Free Software Foundation, Inc. This file is part of GNU Emacs. @@ -16,8 +17,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 +232,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; @@ -268,6 +269,12 @@ int auto_raise_tool_bar_buttons_p; int make_cursor_line_fully_visible_p; +/* Margin below tool bar in pixels. 0 or nil means no margin. + If value is `internal-border-width' or `border-width', + the corresponding frame parameter is used. */ + +Lisp_Object Vtool_bar_border; + /* Margin around tool bar buttons in pixels. */ Lisp_Object Vtool_bar_button_margin; @@ -320,7 +327,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 +357,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. */ @@ -567,12 +578,21 @@ Lisp_Object Vmessage_log_max; static Lisp_Object Vmessages_buffer_name; -/* Current, index 0, and last displayed echo area message. Either - buffers from echo_buffers, or nil to indicate no message. */ +/* Index 0 is the buffer that holds the current (desired) echo area message, + or nil if none is desired right now. + + Index 1 is the buffer that holds the previously displayed echo area message, + or nil to indicate no message. This is normally what's on the screen now. + + These two can point to the same buffer. That happens when the last + message output by the user (or made by echoing) has been displayed. */ Lisp_Object echo_area_buffer[2]; -/* The buffers referenced from echo_area_buffer. */ +/* Permanent pointers to the two buffers that are used for echo area + purposes. Once the two buffers are made, and their pointers are + placed here, these two slots remain unchanged unless those buffers + need to be created afresh. */ static Lisp_Object echo_buffer[2]; @@ -612,12 +632,6 @@ Lisp_Object Qmessage_truncate_lines; static int message_cleared_p; -/* Non-zero means we want a hollow cursor in windows that are not - selected. Zero means there's no cursor in such windows. */ - -Lisp_Object Vcursor_in_non_selected_windows; -Lisp_Object Qcursor_in_non_selected_windows; - /* How to blink the default frame cursor off. */ Lisp_Object Vblink_cursor_alist; @@ -840,11 +854,11 @@ 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 *)); +static int tool_bar_lines_needed P_ ((struct frame *, int *)); static int single_display_spec_intangible_p P_ ((Lisp_Object)); static void ensure_echo_area_buffers P_ ((void)); static Lisp_Object unwind_with_echo_area_buffer P_ ((Lisp_Object)); @@ -955,7 +969,7 @@ static int in_ellipses_for_invisible_text_p P_ ((struct display_pos *, static void update_tool_bar P_ ((struct frame *, int)); static void build_desired_tool_bar_string P_ ((struct frame *f)); static int redisplay_tool_bar P_ ((struct frame *)); -static void display_tool_bar_line P_ ((struct it *)); +static void display_tool_bar_line P_ ((struct it *, int)); static void notice_overwritten_cursor P_ ((struct window *, enum glyph_row_area, int, int, int, int)); @@ -1339,6 +1353,9 @@ pos_visible_p (w, charpos, x, y, rtop, rbot, exact_mode_line_heights_p) current_header_line_height = current_mode_line_height = -1; + if (visible_p && XFASTINT (w->hscroll) > 0) + *x -= XFASTINT (w->hscroll) * WINDOW_FRAME_COLUMN_WIDTH (w); + return visible_p; } @@ -1757,15 +1774,20 @@ frame_to_window_pixel_xy (w, x, y) } /* EXPORT: - Return in *R the clipping rectangle for glyph string S. */ + Return in RECTS[] at most N clipping rectangles for glyph string S. + Return the number of stored rectangles. */ -void -get_glyph_string_clip_rect (s, nr) +int +get_glyph_string_clip_rects (s, rects, n) struct glyph_string *s; - NativeRectangle *nr; + NativeRectangle *rects; + int n; { XRectangle r; + if (n <= 0) + return 0; + if (s->row->full_width_p) { /* Draw full-width. X coordinates are relative to S->w->left_col. */ @@ -1808,10 +1830,27 @@ get_glyph_string_clip_rect (s, nr) /* If S draws overlapping rows, it's sufficient to use the top and bottom of the window for clipping because this glyph string intentionally draws over other lines. */ - if (s->for_overlaps_p) + if (s->for_overlaps) { r.y = WINDOW_HEADER_LINE_HEIGHT (s->w); r.height = window_text_bottom_y (s->w) - r.y; + + /* Alas, the above simple strategy does not work for the + environments with anti-aliased text: if the same text is + drawn onto the same place multiple times, it gets thicker. + If the overlap we are processing is for the erased cursor, we + take the intersection with the rectagle of the cursor. */ + if (s->for_overlaps & OVERLAPS_ERASED_CURSOR) + { + XRectangle rc, r_save = r; + + rc.x = WINDOW_TEXT_TO_FRAME_PIXEL_X (s->w, s->w->phys_cursor.x); + rc.y = s->w->phys_cursor.y; + rc.width = s->w->phys_cursor_width; + rc.height = s->w->phys_cursor_height; + + x_intersect_rectangles (&r_save, &rc, &r); + } } else { @@ -1870,11 +1909,75 @@ get_glyph_string_clip_rect (s, nr) } } + if ((s->for_overlaps & OVERLAPS_BOTH) == 0 + || ((s->for_overlaps & OVERLAPS_BOTH) == OVERLAPS_BOTH && n == 1)) + { +#ifdef CONVERT_FROM_XRECT + CONVERT_FROM_XRECT (r, *rects); +#else + *rects = r; +#endif + return 1; + } + else + { + /* If we are processing overlapping and allowed to return + multiple clipping rectangles, we exclude the row of the glyph + string from the clipping rectangle. This is to avoid drawing + the same text on the environment with anti-aliasing. */ #ifdef CONVERT_FROM_XRECT - CONVERT_FROM_XRECT (r, *nr); + XRectangle rs[2]; #else - *nr = r; + XRectangle *rs = rects; +#endif + int i = 0, row_y = WINDOW_TO_FRAME_PIXEL_Y (s->w, s->row->y); + + if (s->for_overlaps & OVERLAPS_PRED) + { + rs[i] = r; + if (r.y + r.height > row_y) + { + if (r.y < row_y) + rs[i].height = row_y - r.y; + else + rs[i].height = 0; + } + i++; + } + if (s->for_overlaps & OVERLAPS_SUCC) + { + rs[i] = r; + if (r.y < row_y + s->row->visible_height) + { + if (r.y + r.height > row_y + s->row->visible_height) + { + rs[i].y = row_y + s->row->visible_height; + rs[i].height = r.y + r.height - rs[i].y; + } + else + rs[i].height = 0; + } + i++; + } + + n = i; +#ifdef CONVERT_FROM_XRECT + for (i = 0; i < n; i++) + CONVERT_FROM_XRECT (rs[i], rects[i]); #endif + return n; + } +} + +/* EXPORT: + Return in *NR the clipping rectangle for glyph string S. */ + +void +get_glyph_string_clip_rect (s, nr) + struct glyph_string *s; + NativeRectangle *nr; +{ + get_glyph_string_clip_rects (s, nr, 1); } @@ -1891,7 +1994,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 @@ -1930,10 +2033,202 @@ get_phys_cursor_geometry (w, row, glyph, heightp) } } - *heightp = h - 1; + *heightp = h; return WINDOW_TO_FRAME_PIXEL_Y (w, y); } +/* + * Remember which glyph the mouse is over. + */ + +void +remember_mouse_glyph (f, gx, gy, rect) + struct frame *f; + int gx, gy; + NativeRectangle *rect; +{ + Lisp_Object window; + struct window *w; + struct glyph_row *r, *gr, *end_row; + enum window_part part; + enum glyph_row_area area; + int x, y, width, height; + + /* Try to determine frame pixel position and size of the glyph under + frame pixel coordinates X/Y on frame F. */ + + window = window_from_coordinates (f, gx, gy, &part, &x, &y, 0); + if (NILP (window)) + { + width = FRAME_SMALLEST_CHAR_WIDTH (f); + height = FRAME_SMALLEST_FONT_HEIGHT (f); + goto virtual_glyph; + } + + w = XWINDOW (window); + width = WINDOW_FRAME_COLUMN_WIDTH (w); + height = WINDOW_FRAME_LINE_HEIGHT (w); + + r = MATRIX_FIRST_TEXT_ROW (w->current_matrix); + end_row = MATRIX_BOTTOM_TEXT_ROW (w->current_matrix, w); + + if (w->pseudo_window_p) + { + area = TEXT_AREA; + part = ON_MODE_LINE; /* Don't adjust margin. */ + goto text_glyph; + } + + switch (part) + { + case ON_LEFT_MARGIN: + area = LEFT_MARGIN_AREA; + goto text_glyph; + + case ON_RIGHT_MARGIN: + area = RIGHT_MARGIN_AREA; + goto text_glyph; + + case ON_HEADER_LINE: + case ON_MODE_LINE: + gr = (part == ON_HEADER_LINE + ? MATRIX_HEADER_LINE_ROW (w->current_matrix) + : MATRIX_MODE_LINE_ROW (w->current_matrix)); + gy = gr->y; + area = TEXT_AREA; + goto text_glyph_row_found; + + case ON_TEXT: + area = TEXT_AREA; + + text_glyph: + gr = 0; gy = 0; + for (; r <= end_row && r->enabled_p; ++r) + if (r->y + r->height > y) + { + gr = r; gy = r->y; + break; + } + + text_glyph_row_found: + if (gr && gy <= y) + { + struct glyph *g = gr->glyphs[area]; + struct glyph *end = g + gr->used[area]; + + height = gr->height; + for (gx = gr->x; g < end; gx += g->pixel_width, ++g) + if (gx + g->pixel_width > x) + break; + + if (g < end) + { + if (g->type == IMAGE_GLYPH) + { + /* Don't remember when mouse is over image, as + image may have hot-spots. */ + STORE_NATIVE_RECT (*rect, 0, 0, 0, 0); + return; + } + width = g->pixel_width; + } + else + { + /* Use nominal char spacing at end of line. */ + x -= gx; + gx += (x / width) * width; + } + + if (part != ON_MODE_LINE && part != ON_HEADER_LINE) + gx += window_box_left_offset (w, area); + } + else + { + /* Use nominal line height at end of window. */ + gx = (x / width) * width; + y -= gy; + gy += (y / height) * height; + } + break; + + case ON_LEFT_FRINGE: + gx = (WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (w) + ? WINDOW_LEFT_SCROLL_BAR_AREA_WIDTH (w) + : window_box_right_offset (w, LEFT_MARGIN_AREA)); + width = WINDOW_LEFT_FRINGE_WIDTH (w); + goto row_glyph; + + case ON_RIGHT_FRINGE: + gx = (WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (w) + ? window_box_right_offset (w, RIGHT_MARGIN_AREA) + : window_box_right_offset (w, TEXT_AREA)); + width = WINDOW_RIGHT_FRINGE_WIDTH (w); + goto row_glyph; + + case ON_SCROLL_BAR: + gx = (WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_LEFT (w) + ? 0 + : (window_box_right_offset (w, RIGHT_MARGIN_AREA) + + (WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (w) + ? WINDOW_RIGHT_FRINGE_WIDTH (w) + : 0))); + width = WINDOW_SCROLL_BAR_AREA_WIDTH (w); + + row_glyph: + gr = 0, gy = 0; + for (; r <= end_row && r->enabled_p; ++r) + if (r->y + r->height > y) + { + gr = r; gy = r->y; + break; + } + + if (gr && gy <= y) + height = gr->height; + else + { + /* Use nominal line height at end of window. */ + y -= gy; + gy += (y / height) * height; + } + break; + + default: + ; + virtual_glyph: + /* If there is no glyph under the mouse, then we divide the screen + into a grid of the smallest glyph in the frame, and use that + as our "glyph". */ + + /* Arrange for the division in FRAME_PIXEL_X_TO_COL etc. to + round down even for negative values. */ + if (gx < 0) + gx -= width - 1; + if (gy < 0) + gy -= height - 1; + + gx = (gx / width) * width; + gy = (gy / height) * height; + + goto store_rect; + } + + gx += WINDOW_LEFT_EDGE_X (w); + gy += WINDOW_TOP_EDGE_Y (w); + + store_rect: + STORE_NATIVE_RECT (*rect, gx, gy, width, height); + + /* Visible feedback for debugging. */ +#if 0 +#if HAVE_X_WINDOWS + XDrawRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), + f->output_data.x->normal_gc, + gx, gy, width, height); +#endif +#endif +} + #endif /* HAVE_WINDOW_SYSTEM */ @@ -2401,7 +2696,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; @@ -2691,11 +2988,17 @@ handle_stop (it) struct it *it; { enum prop_handled handled; - int handle_overlay_change_p = 1; + int handle_overlay_change_p; struct props *p; it->dpvec = NULL; it->current.dpvec_index = -1; + handle_overlay_change_p = !it->ignore_overlay_strings_at_pos_p; + it->ignore_overlay_strings_at_pos_p = 0; + + /* Use face of preceding text for ellipsis (if invisible) */ + if (it->selective_display_ellipsis_p) + it->saved_face_id = it->face_id; do { @@ -2885,6 +3188,9 @@ handle_fontified_prop (it) Lisp_Object prop, pos; enum prop_handled handled = HANDLED_NORMALLY; + if (!NILP (Vmemory_full)) + return handled; + /* Get the value of the `fontified' property at IT's current buffer position. (The `fontified' property doesn't have a special meaning in strings.) If the value is nil, call functions from @@ -3318,6 +3624,11 @@ handle_invisible_prop (it) skip starting with next_stop. */ if (invis_p) IT_CHARPOS (*it) = next_stop; + + /* If there are adjacent invisible texts, don't lose the + second one's ellipsis. */ + if (invis_p == 2) + display_ellipsis_p = 1; } while (invis_p); @@ -3338,7 +3649,26 @@ handle_invisible_prop (it) it->stack[it->sp - 1].display_ellipsis_p = display_ellipsis_p; } else if (display_ellipsis_p) - setup_for_ellipsis (it, 0); + { + /* Make sure that the glyphs of the ellipsis will get + correct `charpos' values. If we would not update + it->position here, the glyphs would belong to the + last visible character _before_ the invisible + text, which confuses `set_cursor_from_row'. + + We use the last invisible position instead of the + first because this way the cursor is always drawn on + the first "." of the ellipsis, whenever PT is inside + the invisible text. Otherwise the cursor would be + placed _after_ the ellipsis when the point is after the + first invisible character. */ + if (!STRINGP (it->object)) + { + it->position.charpos = IT_CHARPOS (*it) - 1; + it->position.bytepos = CHAR_TO_BYTE (it->position.charpos); + } + setup_for_ellipsis (it, 0); + } } } @@ -3374,8 +3704,11 @@ setup_for_ellipsis (it, len) it->dpvec_face_id = -1; /* Remember the current face id in case glyphs specify faces. - IT's face is restored in set_iterator_to_next. */ - it->saved_face_id = it->face_id; + IT's face is restored in set_iterator_to_next. + saved_face_id was set to preceding char's face in handle_stop. */ + if (it->saved_face_id < 0 || it->saved_face_id != it->face_id) + it->saved_face_id = it->face_id = DEFAULT_FACE_ID; + it->method = GET_FROM_DISPLAY_VECTOR; it->ellipsis_p = 1; } @@ -3408,7 +3741,7 @@ handle_display_prop (it) } else { - object = it->w->buffer; + XSETWINDOW (object, it->w); position = &it->current.pos; } @@ -3429,6 +3762,9 @@ handle_display_prop (it) if (NILP (prop)) return HANDLED_NORMALLY; + if (!STRINGP (it->string)) + object = it->w->buffer; + if (CONSP (prop) /* Simple properties. */ && !EQ (XCAR (prop), Qimage) @@ -3461,7 +3797,10 @@ handle_display_prop (it) } else { - if (handle_single_display_spec (it, prop, object, position, 0)) + int ret = handle_single_display_spec (it, prop, object, position, 0); + if (ret < 0) /* Replaced by "", i.e. nothing. */ + return HANDLED_RECOMPUTE_PROPS; + if (ret) display_replaced_p = 1; } @@ -3505,7 +3844,8 @@ display_prop_end (it, object, start_pos) property ends. Value is non-zero if something was found which replaces the display - of buffer or string text. */ + of buffer or string text. Specifically, the value is -1 if that + "something" is "nothing". */ static int handle_single_display_spec (it, spec, object, position, @@ -3820,6 +4160,11 @@ handle_single_display_spec (it, spec, object, position, if (STRINGP (value)) { + if (SCHARS (value) == 0) + { + pop_it (it); + return -1; /* Replaced by "", i.e. nothing. */ + } it->string = value; it->multibyte_p = STRING_MULTIBYTE (it->string); it->current.overlay_string_index = -1; @@ -3837,7 +4182,7 @@ handle_single_display_spec (it, spec, object, position, { it->method = GET_FROM_STRETCH; it->object = value; - it->current.pos = it->position = start_pos; + *position = it->position = start_pos; } #ifdef HAVE_WINDOW_SYSTEM else @@ -4775,7 +5120,8 @@ reseat_at_next_visible_line_start (it, on_newline_p) && indented_beyond_p (IT_CHARPOS (*it), IT_BYTEPOS (*it), (double) it->selective)) /* iftc */ { - xassert (FETCH_BYTE (IT_BYTEPOS (*it) - 1) == '\n'); + xassert (IT_BYTEPOS (*it) == BEGV + || FETCH_BYTE (IT_BYTEPOS (*it) - 1) == '\n'); newline_found_p = forward_to_next_line_start (it, &skipped_p); } @@ -4996,6 +5342,10 @@ static int (* get_next_element[NUM_IT_METHODS]) P_ ((struct it *it)) = display element from the current position of IT. Value is zero if end of buffer (or C string) is reached. */ +static struct frame *last_escape_glyph_frame = NULL; +static unsigned last_escape_glyph_face_id = (1 << FACE_ID_BITS); +static int last_escape_glyph_merged_face_id = 0; + int get_next_display_element (it) struct it *it; @@ -5074,9 +5424,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))))) @@ -5091,6 +5443,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 */ @@ -5108,11 +5462,19 @@ get_next_display_element (it) face_id = merge_faces (it->f, Qt, lface_id, it->face_id); } + else if (it->f == last_escape_glyph_frame + && it->face_id == last_escape_glyph_face_id) + { + face_id = last_escape_glyph_merged_face_id; + } else { /* Merge the escape-glyph face into the current face. */ face_id = merge_faces (it->f, Qescape_glyph, 0, it->face_id); + last_escape_glyph_frame = it->f; + last_escape_glyph_face_id = it->face_id; + last_escape_glyph_merged_face_id = face_id; } XSETINT (it->ctl_chars[0], g); @@ -5122,7 +5484,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)))) @@ -5132,22 +5515,50 @@ 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); } + else if (it->f == last_escape_glyph_frame + && it->face_id == last_escape_glyph_face_id) + { + face_id = last_escape_glyph_merged_face_id; + } else { /* Merge the escape-glyph face into the current face. */ face_id = merge_faces (it->f, Qescape_glyph, 0, it->face_id); + last_escape_glyph_frame = it->f; + last_escape_glyph_face_id = it->face_id; + last_escape_glyph_merged_face_id = 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; @@ -5316,6 +5727,8 @@ set_iterator_to_next (it, reseat_p) if (it->dpvec + it->current.dpvec_index == it->dpend) { + int recheck_faces = it->ellipsis_p; + if (it->s) it->method = GET_FROM_C_STRING; else if (STRINGP (it->string)) @@ -5331,12 +5744,16 @@ set_iterator_to_next (it, reseat_p) reseat_at_next_visible_line_start (it, 1); else if (it->dpvec_char_len > 0) { + if (it->method == GET_FROM_STRING + && it->n_overlay_strings > 0) + it->ignore_overlay_strings_at_pos_p = 1; it->len = it->dpvec_char_len; set_iterator_to_next (it, reseat_p); } - /* Recheck faces after display vector */ - it->stop_charpos = IT_CHARPOS (*it); + /* Maybe recheck faces after display vector */ + if (recheck_faces) + it->stop_charpos = IT_CHARPOS (*it); } break; @@ -5414,6 +5831,8 @@ next_element_from_display_vector (it) /* Precondition. */ xassert (it->dpvec && it->current.dpvec_index >= 0); + it->face_id = it->saved_face_id; + if (INTEGERP (*it->dpvec) && GLYPH_CHAR_VALID_P (XFASTINT (*it->dpvec))) { @@ -5801,6 +6220,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. @@ -5859,6 +6287,16 @@ move_it_in_display_line_to (it, to_charpos, to_x, op) { int x, i, ascent = 0, descent = 0; + /* Stop if we move beyond TO_CHARPOS (after an image or stretch glyph). */ + if ((op & MOVE_TO_POS) != 0 + && BUFFERP (it->object) + && it->method == GET_FROM_BUFFER + && IT_CHARPOS (*it) > to_charpos) + { + result = MOVE_POS_MATCH_OR_ZV; + break; + } + /* Stop when ZV reached. We used to stop here when TO_CHARPOS reached as well, but that is too soon if this glyph does not fit on this line. So we handle it @@ -5917,6 +6355,8 @@ move_it_in_display_line_to (it, to_charpos, to_x, op) glyphs have the same width. */ int single_glyph_width = it->pixel_width / it->nglyphs; int new_x; + int x_before_this_char = x; + int hpos_before_this_char = it->hpos; for (i = 0; i < it->nglyphs; ++i, x = new_x) { @@ -5948,8 +6388,22 @@ move_it_in_display_line_to (it, to_charpos, to_x, op) { ++it->hpos; it->current_x = new_x; + + /* The character's last glyph just barely fits + in this row. */ if (i == it->nglyphs - 1) { + /* If this is the destination position, + return a position *before* it in this row, + now that we know it fits in this row. */ + if (BUFFER_POS_REACHED_P ()) + { + it->hpos = hpos_before_this_char; + it->current_x = x_before_this_char; + result = MOVE_POS_MATCH_OR_ZV; + break; + } + set_iterator_to_next (it, 1); #ifdef HAVE_WINDOW_SYSTEM if (IT_OVERFLOW_NEWLINE_INTO_FRINGE (it)) @@ -6299,8 +6753,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; @@ -6407,6 +6865,7 @@ move_it_vertically (it, dy) /* If buffer ends in ZV without a newline, move to the start of the line to satisfy the post-condition. */ if (IT_CHARPOS (*it) == ZV + && ZV > BEGV && FETCH_BYTE (IT_BYTEPOS (*it) - 1) != '\n') move_it_by_lines (it, 0, 0); } @@ -6498,21 +6957,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 @@ -6608,7 +7091,10 @@ message_log_maybe_newline () terminated with a newline when NLFLAG is non-zero. MULTIBYTE, if nonzero, means interpret the contents of M as multibyte. This function calls low-level routines in order to bypass text property - hooks, etc. which might not be safe to run. */ + hooks, etc. which might not be safe to run. + + This may GC (insert may run before/after change hooks), + so the buffer M must NOT point to a Lisp string. */ void message_dolog (m, nbytes, nlflag, multibyte) @@ -6819,10 +7305,7 @@ message_log_check_duplicate (prev_bol, prev_bol_byte, this_bol, this_bol_byte) out any existing message, and let the mini-buffer text show through. - The buffer M must continue to exist until after the echo area gets - cleared or some other message gets displayed there. This means do - not pass text that is stored in a Lisp string; do not pass text in - a buffer that was alloca'd. */ + This may GC, so the buffer M must NOT point to a Lisp string. */ void message2 (m, nbytes, multibyte) @@ -6900,7 +7383,9 @@ message2_nolog (m, nbytes, multibyte) /* Display an echo area message M with a specified length of NBYTES bytes. The string may include null characters. If M is not a string, clear out any existing message, and let the mini-buffer - text show through. */ + text show through. + + This function cancels echoing. */ void message3 (m, nbytes, multibyte) @@ -6912,18 +7397,30 @@ message3 (m, nbytes, multibyte) GCPRO1 (m); clear_message (1,1); + cancel_echoing (); /* First flush out any partial line written with print. */ message_log_maybe_newline (); if (STRINGP (m)) - message_dolog (SDATA (m), nbytes, 1, multibyte); + { + char *buffer; + USE_SAFE_ALLOCA; + + SAFE_ALLOCA (buffer, char *, nbytes); + bcopy (SDATA (m), buffer, nbytes); + message_dolog (buffer, nbytes, 1, multibyte); + SAFE_FREE (); + } message3_nolog (m, nbytes, multibyte); UNGCPRO; } -/* The non-logging version of message3. */ +/* The non-logging version of message3. + This does not cancel echoing, because it is used for echoing. + Perhaps we need to make a separate function for echoing + and make this cancel echoing. */ void message3_nolog (m, nbytes, multibyte) @@ -6971,6 +7468,9 @@ message3_nolog (m, nbytes, multibyte) set_message (NULL, m, nbytes, multibyte); if (minibuffer_auto_raise) Fraise_frame (frame); + /* Assume we are not echoing. + (If we are, echo_now will override this.) */ + echo_message_buffer = Qnil; } else clear_message (1, 1); @@ -7217,10 +7717,6 @@ ensure_echo_area_buffers () WHICH > 0 means use echo_area_buffer[1]. If that is nil, choose a suitable buffer from echo_buffer[] and clear it. - If WHICH < 0, set echo_area_buffer[1] to echo_area_buffer[0], so - that the current message becomes the last displayed one, make - choose a suitable buffer for echo_area_buffer[0], and clear it. - Value is what FN returns. */ static int @@ -7245,17 +7741,6 @@ with_echo_area_buffer (w, which, fn, a1, a2, a3, a4) this_one = 0, the_other = 1; else if (which > 0) this_one = 1, the_other = 0; - else - { - this_one = 0, the_other = 1; - clear_buffer_p = 1; - - /* We need a fresh one in case the current echo buffer equals - the one containing the last displayed echo area message. */ - if (!NILP (echo_area_buffer[this_one]) - && EQ (echo_area_buffer[this_one], echo_area_buffer[the_other])) - echo_area_buffer[this_one] = Qnil; - } /* Choose a suitable buffer from echo_buffer[] is we don't have one. */ @@ -7514,14 +7999,17 @@ display_echo_area_1 (a1, a2, a3, a4) int window_height_changed_p = 0; /* Do this before displaying, so that we have a large enough glyph - matrix for the display. */ + matrix for the display. If we can't get enough space for the + whole text, display the last N lines. That works by setting w->start. */ window_height_changed_p = resize_mini_window (w, 0); + /* Use the starting position chosen by resize_mini_window. */ + SET_TEXT_POS_FROM_MARKER (start, w->start); + /* Display. */ 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; } @@ -7576,8 +8064,14 @@ resize_mini_window_1 (a1, exactly, a3, a4) /* Resize mini-window W to fit the size of its contents. EXACT:P means size the window exactly to the size needed. Otherwise, it's - only enlarged until W's buffer is empty. Value is non-zero if - the window height has been changed. */ + only enlarged until W's buffer is empty. + + Set W->start to the right place to begin display. If the whole + contents fit, start at the beginning. Otherwise, start so as + to make the end of the contents appear. This is particularly + important for y-or-n-p, but seems desirable generally. + + Value is non-zero if the window height has been changed. */ int resize_mini_window (w, exact_p) @@ -7589,6 +8083,11 @@ resize_mini_window (w, exact_p) xassert (MINI_WINDOW_P (w)); + /* By default, start display at the beginning. */ + set_marker_both (w->start, w->buffer, + BUF_BEGV (XBUFFER (w->buffer)), + BUF_BEGV_BYTE (XBUFFER (w->buffer))); + /* Don't resize windows while redisplaying a window; it would confuse redisplay functions when the size of the window they are displaying changes from under them. Such a resizing can happen, @@ -7652,7 +8151,7 @@ resize_mini_window (w, exact_p) if (height > max_height) { height = max_height; - init_iterator (&it, w, PT, PT_BYTE, NULL, DEFAULT_FACE_ID); + init_iterator (&it, w, ZV, ZV_BYTE, NULL, DEFAULT_FACE_ID); move_it_vertically_backward (&it, (height - 1) * unit); start = it.current.pos; } @@ -7863,7 +8362,11 @@ truncate_message_1 (nchars, a2, a3, a4) If S is not null, set the message to the first LEN bytes of S. LEN zero means use the whole string. MULTIBYTE_P non-zero means S is - multibyte. Display the message multibyte in that case. */ + multibyte. Display the message multibyte in that case. + + Doesn't GC, as with_echo_area_buffer binds Qinhibit_modification_hooks + to t before calling set_message_1 (which calls insert). + */ void set_message (s, string, nbytes, multibyte_p) @@ -7875,7 +8378,7 @@ set_message (s, string, nbytes, multibyte_p) = ((s && multibyte_p) || (STRINGP (string) && STRING_MULTIBYTE (string))); - with_echo_area_buffer (0, -1, set_message_1, + with_echo_area_buffer (0, 0, set_message_1, (EMACS_INT) s, string, nbytes, multibyte_p); message_buf_print = 0; help_echo_showing_p = 0; @@ -7896,8 +8399,6 @@ set_message_1 (a1, a2, nbytes, multibyte_p) const char *s = (const char *) a1; Lisp_Object string = a2; - xassert (BEG == Z); - /* Change multibyteness of the echo buffer appropriately. */ if (message_enable_multibyte != !NILP (current_buffer->enable_multibyte_characters)) @@ -7907,6 +8408,7 @@ set_message_1 (a1, a2, nbytes, multibyte_p) /* Insert new message at BEG. */ TEMP_SET_PT_BOTH (BEG, BEG_BYTE); + Ferase_buffer (); if (STRINGP (string)) { @@ -8123,10 +8625,8 @@ echo_area_display (update_frame_p) else if (!EQ (mini_window, selected_window)) windows_or_buffers_changed++; - /* Last displayed message is now the current message. */ + /* The current message is now also the last one displayed. */ echo_area_buffer[1] = echo_area_buffer[0]; - /* Inform read_char that we're not echoing. */ - echo_message_buffer = Qnil; /* Prevent redisplay optimization in redisplay_internal by resetting this_line_start_pos. This is done because the mini-buffer now @@ -8140,52 +8640,126 @@ 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; -static char *frame_title_buf_end; -static char *frame_title_ptr; +/* 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, save_proptrans) + 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); -/* Store a single character C for the frame title in frame_title_buf. - Re-allocate frame_title_buf if necessary. */ + 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) = (save_proptrans ? mode_line_proptrans_alist : Qt); + 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 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); + if (! EQ (AREF (vector, 3), Qt)) + 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 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 @@ -8193,7 +8767,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; { @@ -8204,19 +8778,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 @@ -8236,9 +8814,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)) { @@ -8257,18 +8837,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, 0)); + 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 @@ -8277,8 +8861,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); } } @@ -8337,7 +8921,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) { @@ -8460,7 +9044,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); @@ -8481,14 +9065,15 @@ update_menu_bar (f, save_match_data) /* Redisplay the menu bar in case we changed it. */ #if defined (USE_X_TOOLKIT) || defined (HAVE_NTGUI) || defined (MAC_OS) \ || defined (USE_GTK) - if (FRAME_WINDOW_P (f) -#if defined (MAC_OS) - /* All frames on Mac OS share the same menubar. So only the - selected frame should be allowed to set it. */ - && f == SELECTED_FRAME () + if (FRAME_WINDOW_P (f)) + { +#ifdef MAC_OS + /* All frames on Mac OS share the same menubar. So only + the selected frame should be allowed to set it. */ + if (f == SELECTED_FRAME ()) #endif - ) - set_frame_menubar (f, 0, 0); + set_frame_menubar (f, 0, 0); + } else /* On a terminal screen, the menu bar is an ordinary screen line, and this makes it get updated. */ @@ -8651,7 +9236,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)) @@ -8852,11 +9437,22 @@ build_desired_tool_bar_string (f) } -/* Display one line of the tool-bar of frame IT->f. */ +/* Display one line of the tool-bar of frame IT->f. + + HEIGHT specifies the desired height of the tool-bar line. + If the actual height of the glyph row is less than HEIGHT, the + row's height is increased to HEIGHT, and the icons are centered + vertically in the new height. + + If HEIGHT is -1, we are counting needed tool-bar lines, so don't + count a final empty row in case the tool-bar width exactly matches + the window width. +*/ static void -display_tool_bar_line (it) +display_tool_bar_line (it, height) struct it *it; + int height; { struct glyph_row *row = it->glyph_row; int max_x = it->last_visible_x; @@ -8875,7 +9471,12 @@ display_tool_bar_line (it) /* Get the next display element. */ if (!get_next_display_element (it)) - break; + { + /* Don't count empty row if we are counting needed tool-bar lines. */ + if (height < 0 && !it->hpos) + return; + break; + } /* Produce glyphs. */ x_before = it->current_x; @@ -8912,11 +9513,22 @@ display_tool_bar_line (it) out:; row->displays_text_p = row->used[TEXT_AREA] != 0; + /* Use default face for the border below the tool bar. */ + if (!row->displays_text_p) + it->face_id = DEFAULT_FACE_ID; extend_face_to_end_of_line (it); last = row->glyphs[TEXT_AREA] + row->used[TEXT_AREA] - 1; last->right_box_line_p = 1; if (last == row->glyphs[TEXT_AREA]) last->left_box_line_p = 1; + + /* Make line the desired height and center it vertically. */ + if ((height -= it->max_ascent + it->max_descent) > 0) + { + it->max_ascent += height / 2; + it->max_descent += (height + 1) / 2; + } + compute_line_metrics (it); /* If line is empty, make it occupy the rest of the tool-bar. */ @@ -8940,11 +9552,13 @@ display_tool_bar_line (it) /* Value is the number of screen lines needed to make all tool-bar - items of frame F visible. */ + items of frame F visible. The number of actual rows needed is + returned in *N_ROWS if non-NULL. */ static int -tool_bar_lines_needed (f) +tool_bar_lines_needed (f, n_rows) struct frame *f; + int *n_rows; { struct window *w = XWINDOW (f->tool_bar_window); struct it it; @@ -8960,9 +9574,13 @@ tool_bar_lines_needed (f) { it.glyph_row = w->desired_matrix->rows; clear_glyph_row (it.glyph_row); - display_tool_bar_line (&it); + display_tool_bar_line (&it, -1); } + /* f->n_tool_bar_rows == 0 means "unknown"; -1 means no tool-bar. */ + if (n_rows) + *n_rows = it.vpos > 0 ? it.vpos : -1; + return (it.current_y + FRAME_LINE_HEIGHT (f) - 1) / FRAME_LINE_HEIGHT (f); } @@ -8991,7 +9609,7 @@ DEFUN ("tool-bar-lines-needed", Ftool_bar_lines_needed, Stool_bar_lines_needed, if (f->n_tool_bar_items) { build_desired_tool_bar_string (f); - nlines = tool_bar_lines_needed (f); + nlines = tool_bar_lines_needed (f, NULL); } } @@ -9036,9 +9654,46 @@ redisplay_tool_bar (f) build_desired_tool_bar_string (f); reseat_to_string (&it, NULL, f->desired_tool_bar_string, 0, 0, 0, -1); + if (f->n_tool_bar_rows == 0) + (void)tool_bar_lines_needed (f, &f->n_tool_bar_rows); + /* Display as many lines as needed to display all tool-bar items. */ - while (it.current_y < it.last_visible_y) - display_tool_bar_line (&it); + + if (f->n_tool_bar_rows > 0) + { + int border, rows, height, extra; + + if (INTEGERP (Vtool_bar_border)) + border = XINT (Vtool_bar_border); + else if (EQ (Vtool_bar_border, Qinternal_border_width)) + border = FRAME_INTERNAL_BORDER_WIDTH (f); + else if (EQ (Vtool_bar_border, Qborder_width)) + border = f->border_width; + else + border = 0; + if (border < 0) + border = 0; + + rows = f->n_tool_bar_rows; + height = (it.last_visible_y - border) / rows; + extra = it.last_visible_y - border - height * rows; + + while (it.current_y < it.last_visible_y) + { + int h = 0; + if (extra > 0 && rows-- > 0) + { + h = (extra + rows - 1) / rows; + extra -= h; + } + display_tool_bar_line (&it, height + h); + } + } + else + { + while (it.current_y < it.last_visible_y) + display_tool_bar_line (&it, 0); + } /* It doesn't make much sense to try scrolling in the tool-bar window, so don't do it. */ @@ -9071,7 +9726,7 @@ redisplay_tool_bar (f) /* Resize windows as needed by changing the `tool-bar-lines' frame parameter. */ if (change_height_p - && (nlines = tool_bar_lines_needed (f), + && (nlines = tool_bar_lines_needed (f, &f->n_tool_bar_rows), nlines != WINDOW_TOTAL_LINES (w))) { extern Lisp_Object Qtool_bar_lines; @@ -9650,22 +10305,14 @@ redisplay () static Lisp_Object -overlay_arrow_string_or_property (var, pbitmap) +overlay_arrow_string_or_property (var) Lisp_Object var; - int *pbitmap; { - Lisp_Object pstr = Fget (var, Qoverlay_arrow_string); - Lisp_Object bitmap; + Lisp_Object val; - if (pbitmap) - { - *pbitmap = 0; - if (bitmap = Fget (var, Qoverlay_arrow_bitmap), INTEGERP (bitmap)) - *pbitmap = XINT (bitmap); - } + if (val = Fget (var, Qoverlay_arrow_string), STRINGP (val)) + return val; - if (!NILP (pstr)) - return pstr; return Voverlay_arrow_string; } @@ -9715,7 +10362,7 @@ overlay_arrows_changed_p () continue; if (! EQ (COERCE_MARKER (val), Fget (var, Qlast_arrow_position)) - || ! (pstr = overlay_arrow_string_or_property (var, 0), + || ! (pstr = overlay_arrow_string_or_property (var), EQ (pstr, Fget (var, Qlast_arrow_string)))) return 1; } @@ -9745,7 +10392,7 @@ update_overlay_arrows (up_to_date) Fput (var, Qlast_arrow_position, COERCE_MARKER (val)); Fput (var, Qlast_arrow_string, - overlay_arrow_string_or_property (var, 0)); + overlay_arrow_string_or_property (var)); } else if (up_to_date < 0 || !NILP (Fget (var, Qlast_arrow_position))) @@ -9758,14 +10405,13 @@ update_overlay_arrows (up_to_date) /* Return overlay arrow string to display at row. - Return t if display as bitmap in left fringe. + Return integer (bitmap number) for arrow bitmap in left fringe. Return nil if no overlay arrow. */ static Lisp_Object -overlay_arrow_at_row (it, row, pbitmap) +overlay_arrow_at_row (it, row) struct it *it; struct glyph_row *row; - int *pbitmap; { Lisp_Object vlist; @@ -9785,17 +10431,23 @@ overlay_arrow_at_row (it, row, pbitmap) && current_buffer == XMARKER (val)->buffer && (MATRIX_ROW_START_CHARPOS (row) == marker_position (val))) { - val = overlay_arrow_string_or_property (var, pbitmap); if (FRAME_WINDOW_P (it->f) && WINDOW_LEFT_FRINGE_WIDTH (it->w) > 0) - return Qt; - if (STRINGP (val)) - return val; - break; + { +#ifdef HAVE_WINDOW_SYSTEM + if (val = Fget (var, Qoverlay_arrow_bitmap), SYMBOLP (val)) + { + int fringe_bitmap; + if ((fringe_bitmap = lookup_fringe_bitmap (val)) != 0) + return make_number (fringe_bitmap); + } +#endif + return make_number (-1); /* Use default arrow bitmap */ + } + return overlay_arrow_string_or_property (var); } } - *pbitmap = 0; return Qnil; } @@ -9900,7 +10552,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)) @@ -9911,7 +10565,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); } @@ -9985,9 +10639,21 @@ 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); + last_escape_glyph_frame = NULL; + last_escape_glyph_face_id = (1 << FACE_ID_BITS); /* If new fonts have been loaded that make a glyph matrix adjustment necessary, do it. */ @@ -10044,7 +10710,8 @@ redisplay_internal (preserve_echo_area) clear_garbaged_frames (); /* Build menubar and tool-bar items. */ - prepare_menu_bars (); + if (NILP (Vmemory_full)) + prepare_menu_bars (); if (windows_or_buffers_changed) update_mode_lines++; @@ -10378,9 +11045,9 @@ redisplay_internal (preserve_echo_area) if (consider_all_windows_p) { Lisp_Object tail, frame; - int i, n = 0, size = 50; - struct frame **updated - = (struct frame **) alloca (size * sizeof *updated); + + FOR_EACH_FRAME (tail, frame) + XFRAME (frame)->updated_p = 0; /* Recompute # windows showing selected buffer. This will be incremented each time such a window is displayed. */ @@ -10419,8 +11086,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 @@ -10438,15 +11109,7 @@ redisplay_internal (preserve_echo_area) break; #endif - if (n == size) - { - int nbytes = size * sizeof *updated; - struct frame **p = (struct frame **) alloca (2 * nbytes); - bcopy (updated, p, nbytes); - size *= 2; - } - - updated[n++] = f; + f->updated_p = 1; } } } @@ -10456,12 +11119,15 @@ redisplay_internal (preserve_echo_area) /* Do the mark_window_display_accurate after all windows have been redisplayed because this call resets flags in buffers which are needed for proper redisplay. */ - for (i = 0; i < n; ++i) + FOR_EACH_FRAME (tail, frame) { - struct frame *f = updated[i]; - mark_window_display_accurate (f->root_window, 1); - if (frame_up_to_date_hook) - frame_up_to_date_hook (f); + struct frame *f = XFRAME (frame); + if (f->updated_p) + { + mark_window_display_accurate (f->root_window, 1); + if (frame_up_to_date_hook) + frame_up_to_date_hook (f); + } } } } @@ -10942,7 +11608,7 @@ set_cursor_from_row (w, row, matrix, delta, delta_bytes, dy, dvpos) x += glyph->pixel_width; ++glyph; if (cursor_from_overlay_pos - && last_pos > cursor_from_overlay_pos) + && last_pos >= cursor_from_overlay_pos) { cursor_from_overlay_pos = 0; cursor = 0; @@ -10956,10 +11622,12 @@ set_cursor_from_row (w, row, matrix, delta, delta_bytes, dy, dvpos) /* Skip all glyphs from string. */ do { + Lisp_Object cprop; int pos; if ((cursor == NULL || glyph > cursor) - && !NILP (Fget_char_property (make_number ((glyph)->charpos), - Qcursor, (glyph)->object)) + && (cprop = Fget_char_property (make_number ((glyph)->charpos), + Qcursor, (glyph)->object), + !NILP (cprop)) && (pos = string_buffer_position (w, glyph->object, string_before_pos), (pos == 0 /* From overlay */ @@ -10970,14 +11638,15 @@ set_cursor_from_row (w, row, matrix, delta, delta_bytes, dy, dvpos) Add 1 to last_pos so that if point corresponds to the glyph right after the overlay, we still use a 'cursor' property found in that overlay. */ - cursor_from_overlay_pos = pos == 0 ? last_pos+1 : 0; + cursor_from_overlay_pos = (pos ? 0 : last_pos + + (INTEGERP (cprop) ? XINT (cprop) : 0)); cursor = glyph; cursor_x = x; } x += glyph->pixel_width; ++glyph; } - while (glyph < end && STRINGP (glyph->object)); + while (glyph < end && EQ (glyph->object, string_start->object)); } } @@ -11123,6 +11792,7 @@ static int cursor_row_fully_visible_p (w, force_p, current_matrix_p) struct window *w; int force_p; + int current_matrix_p; { struct glyph_matrix *matrix; struct glyph_row *row; @@ -11148,7 +11818,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; @@ -11424,7 +12094,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) { @@ -11678,7 +12348,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)) { @@ -12016,8 +12689,6 @@ redisplay_window (window, just_this_one_p) /* IT may overshoot PT if text at PT is invisible. */ else if (IT_CHARPOS (it) > PT && CHARPOS (startp) <= PT) w->force_start = Qt; - - } /* Handle case where place to start displaying has been specified, @@ -12027,6 +12698,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; @@ -12060,12 +12732,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) { @@ -12108,7 +12784,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; } } @@ -12182,6 +12858,35 @@ redisplay_window (window, just_this_one_p) || (XFASTINT (w->last_modified) >= MODIFF && XFASTINT (w->last_overlay_modified) >= OVERLAY_MODIFF))) { + + /* If first window line is a continuation line, and window start + is inside the modified region, but the first change is before + current window start, we must select a new window start.*/ + if (NILP (w->start_at_line_beg)) + { + /* 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; + } + } + #if GLYPH_DEBUG debug_method_add (w, "same window start"); #endif @@ -12198,7 +12903,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) @@ -12328,7 +13037,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 @@ -12348,13 +13057,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 { @@ -12495,10 +13204,9 @@ redisplay_window (window, just_this_one_p) #ifdef HAVE_WINDOW_SYSTEM if (FRAME_WINDOW_P (f) - && update_window_fringes (w, 0) - && !just_this_one_p - && (used_current_matrix_p || overlay_arrow_seen) - && !w->pseudo_window_p) + && update_window_fringes (w, (just_this_one_p + || (!used_current_matrix_p && !overlay_arrow_seen) + || w->pseudo_window_p))) { update_begin (f); BLOCK_INPUT; @@ -12537,14 +13245,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; @@ -12569,6 +13281,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; + + 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); + + if ((w->cursor.y < this_scroll_margin + && CHARPOS (pos) > BEGV + && IT_CHARPOS (it) < ZV) + /* 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)) @@ -12804,7 +13541,7 @@ try_window_reusing_current_matrix (w) /* Disable lines in the current matrix which are now below the window. */ for (++row; row < bottom_row; ++row) - row->enabled_p = 0; + row->enabled_p = row->mode_line_p = 0; } /* Update window_end_pos etc.; last_reused_text_row is the last @@ -14158,10 +14895,10 @@ dump_glyph_row (row, vpos, glyphs) { if (glyphs != 1) { - fprintf (stderr, "Row Start End Used oEI><\\CTZFesm X Y W H V A P\n"); + fprintf (stderr, "======================================================================\n"); - fprintf (stderr, "%3d %5d %5d %4d %1.1d%1.1d%1.1d%1.1d%1.1d\ + fprintf (stderr, "%3d %5d %5d %4d %1.1d%1.1d%1.1d%1.1d\ %1.1d%1.1d%1.1d%1.1d%1.1d%1.1d%1.1d%1.1d %4d %4d %4d %4d %4d %4d %4d\n", vpos, MATRIX_ROW_START_CHARPOS (row), @@ -14171,7 +14908,6 @@ dump_glyph_row (row, vpos, glyphs) row->enabled_p, row->truncated_on_left_p, row->truncated_on_right_p, - row->overlay_arrow_p, row->continued_p, MATRIX_ROW_CONTINUATION_LINE_P (row), row->displays_text_p, @@ -14663,6 +15399,7 @@ extend_face_to_end_of_line (it) face = FACE_FROM_ID (f, it->face_id); if (FRAME_WINDOW_P (f) + && it->glyph_row->displays_text_p && face->box == FACE_NO_BOX && face->background == FRAME_BACKGROUND_PIXEL (f) && !face->stipple) @@ -14812,10 +15549,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, @@ -14853,7 +15592,6 @@ display_line (it) struct it *it; { struct glyph_row *row = it->glyph_row; - int overlay_arrow_bitmap; Lisp_Object overlay_arrow_string; /* We always start displaying at hpos zero even if hscrolled. */ @@ -15107,7 +15845,9 @@ display_line (it) produce_special_glyphs (it, IT_CONTINUATION); row->continued_p = 1; + it->current_x = x_before; it->continuation_lines_width += x; + extend_face_to_end_of_line (it); if (nglyphs > 1 && i > 0) { @@ -15261,9 +16001,9 @@ display_line (it) mark this glyph row as the one containing the overlay arrow. This is clearly a mess with variable size fonts. It would be better to let it be displayed like cursors under X. */ - if ((overlay_arrow_string - = overlay_arrow_at_row (it, row, &overlay_arrow_bitmap), - !NILP (overlay_arrow_string))) + if ((row->displays_text_p || !overlay_arrow_seen) + && (overlay_arrow_string = overlay_arrow_at_row (it, row), + !NILP (overlay_arrow_string))) { /* Overlay arrow in window redisplay is a fringe bitmap. */ if (STRINGP (overlay_arrow_string)) @@ -15293,8 +16033,8 @@ display_line (it) } else { - it->w->overlay_arrow_bitmap = overlay_arrow_bitmap; - row->overlay_arrow_p = 1; + xassert (INTEGERP (overlay_arrow_string)); + row->overlay_arrow_bitmap = XINT (overlay_arrow_string); } overlay_arrow_seen = 1; } @@ -15580,6 +16320,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); @@ -15590,6 +16331,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, 0)); + + 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. */ @@ -15597,6 +16343,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); @@ -15619,17 +16367,43 @@ 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; +/* Move element ELT in LIST to the front of LIST. + Return the updated list. */ -/* List of strings making up the mode-line. */ -Lisp_Object mode_line_string_list; +static Lisp_Object +move_elt_to_front (elt, list) + Lisp_Object elt, list; +{ + register Lisp_Object tail, prev; + register Lisp_Object tem; -/* Base face property when building propertized mode line string. */ -static Lisp_Object mode_line_string_face; -static Lisp_Object mode_line_string_face_prop; + tail = list; + prev = Qnil; + while (CONSP (tail)) + { + tem = XCAR (tail); + + if (EQ (elt, tem)) + { + /* Splice out the link TAIL. */ + if (NILP (prev)) + list = XCDR (tail); + else + Fsetcdr (prev, XCDR (tail)); + + /* Now make it the first. */ + Fsetcdr (tail, list); + return tail; + } + else + prev = tail; + tail = XCDR (tail); + QUIT; + } + /* Not found--return unchanged LIST. */ + return list; +} /* Contribute ELT to the mode line for window IT->w. How it translates into text depends on its data type. @@ -15651,8 +16425,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) @@ -15677,9 +16452,10 @@ display_mode_element (it, depth, field_width, precision, elt, props, risky) { /* A string: output it and check for %-constructs within it. */ unsigned char c; - const unsigned char *this, *lisp_string; + int offset = 0; - if (!NILP (props) || risky) + if (SCHARS (elt) > 0 + && (!NILP (props) || risky)) { Lisp_Object oprops, aelt; oprops = Ftext_properties_at (make_number (0), elt); @@ -15710,14 +16486,22 @@ display_mode_element (it, depth, field_width, precision, elt, props, risky) aelt = Fassoc (elt, mode_line_proptrans_alist); if (! NILP (aelt) && !NILP (Fequal (props, XCDR (aelt)))) { - mode_line_proptrans_alist - = Fcons (aelt, Fdelq (aelt, mode_line_proptrans_alist)); + /* AELT is what we want. Move it to the front + without consing. */ elt = XCAR (aelt); + mode_line_proptrans_alist + = move_elt_to_front (aelt, mode_line_proptrans_alist); } else { Lisp_Object tem; + /* If AELT has the wrong props, it is useless. + so get rid of it. */ + if (! NILP (aelt)) + mode_line_proptrans_alist + = Fdelq (aelt, mode_line_proptrans_alist); + elt = Fcopy_sequence (elt); Fset_text_properties (make_number (0), Flength (elt), props, elt); @@ -15735,80 +16519,97 @@ display_mode_element (it, depth, field_width, precision, elt, props, risky) } } - this = SDATA (elt); - lisp_string = this; + offset = 0; 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; } + /* Handle the non-literal case. */ + while ((precision <= 0 || n < precision) - && *this - && (frame_title_ptr - || !NILP (mode_line_string_list) + && SREF (elt, offset) != 0 + && (mode_line_target != MODE_LINE_DISPLAY || it->current_x < it->last_visible_x)) { - const unsigned char *last = this; + int last_offset = offset; /* Advance to end of string or next format specifier. */ - while ((c = *this++) != '\0' && c != '%') + while ((c = SREF (elt, offset++)) != '\0' && c != '%') ; - if (this - 1 != last) + if (offset - 1 != last_offset) { int nchars, nbytes; /* Output to end of string or up to '%'. Field width is length of string. Don't output more than PRECISION allows us. */ - --this; + offset--; - prec = c_string_width (last, this - last, precision - n, + prec = c_string_width (SDATA (elt) + last_offset, + offset - last_offset, precision - n, &nchars, &nbytes); - if (frame_title_ptr) - n += store_frame_title (last, 0, prec); - else if (!NILP (mode_line_string_list)) - { - 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 + switch (mode_line_target) { - 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 (SDATA (elt) + last_offset, 0, prec); + break; + case MODE_LINE_STRING: + { + int bytepos = last_offset; + int charpos = string_byte_to_char (elt, bytepos); + int endpos = (precision <= 0 + ? string_byte_to_char (elt, offset) + : 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_offset; + int charpos = string_byte_to_char (elt, bytepos); + + if (precision <= 0) + nchars = string_byte_to_char (elt, offset) - charpos; + n += display_string (NULL, elt, Qnil, 0, charpos, + it, 0, nchars, 0, + STRING_MULTIBYTE (elt)); + } + break; } } else /* c == '%' */ { - const unsigned char *percent_position = this; + int percent_position = offset; /* Get the specified minimum width. Zero means don't pad. */ field = 0; - while ((c = *this++) >= '0' && c <= '9') + while ((c = SREF (elt, offset++)) >= '0' && c <= '9') field = field * 10 + c - '0'; /* Don't pad beyond the total padding allowed. */ @@ -15828,7 +16629,7 @@ display_mode_element (it, depth, field_width, precision, elt, props, risky) int bytepos, charpos; unsigned char *spec; - bytepos = percent_position - lisp_string; + bytepos = percent_position; charpos = (STRING_MULTIBYTE (elt) ? string_byte_to_char (elt, bytepos) : bytepos); @@ -15836,44 +16637,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 */ @@ -16021,7 +16829,12 @@ display_mode_element (it, depth, field_width, precision, elt, props, risky) && --limit > 0 && (precision <= 0 || n < precision)) { - n += display_mode_element (it, depth, field_width - n, + n += display_mode_element (it, depth, + /* Do padding only after the last + element in the list. */ + (! CONSP (XCDR (elt)) + ? field_width - n + : 0), precision - n, XCAR (elt), props, risky); elt = XCDR (elt); @@ -16039,13 +16852,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; @@ -16092,7 +16912,7 @@ store_mode_line_string (string, lisp_string, copy_string, field_width, precision props = mode_line_string_face_prop; else if (!NILP (mode_line_string_face)) { - Lisp_Object face = Fsafe_plist_get (props, Qface); + Lisp_Object face = Fplist_get (props, Qface); props = Fcopy_sequence (props); if (NILP (face)) face = mode_line_string_face; @@ -16117,7 +16937,7 @@ store_mode_line_string (string, lisp_string, copy_string, field_width, precision Lisp_Object face; if (NILP (props)) props = Ftext_properties_at (make_number (0), lisp_string); - face = Fsafe_plist_get (props, Qface); + face = Fplist_get (props, Qface); if (NILP (face)) face = mode_line_string_face; else @@ -16177,6 +16997,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; @@ -16204,64 +17027,53 @@ 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; + + /* Save things including mode_line_proptrans_alist, + and set that to nil so that we don't alter the outer value. */ + record_unwind_protect (unwind_format_mode_line, + format_mode_line_unwind_data (old_buffer, 1)); + mode_line_proptrans_alist = Qnil; + + 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 @@ -16579,7 +17391,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)) @@ -16605,6 +17418,18 @@ decode_mode_spec (w, c, field_width, precision, multibyte) return decode_mode_spec_buf; } + case 'e': +#ifndef SYSTEM_MALLOC + { + if (NILP (Vmemory_full)) + return ""; + else + return "!MEM FULL! "; + } +#else + return ""; +#endif + case 'F': /* %F displays the frame name. */ if (!NILP (f->title)) @@ -17020,7 +17845,7 @@ display_count_lines (start, start_byte, limit_byte, count, byte_pos_ptr) display them, and < 0 means obey the current buffer's value of enable_multibyte_characters. - Value is the number of glyphs produced. */ + Value is the number of columns displayed. */ static int display_string (string, lisp_string, face_string, face_string_pos, @@ -17354,6 +18179,15 @@ calc_pixel_width_or_height (res, it, prop, font, width_p, align_to) if (pixels > 0) { double ppi; +#ifdef HAVE_WINDOW_SYSTEM + if (FRAME_WINDOW_P (it->f) + && (ppi = (width_p + ? FRAME_X_DISPLAY_INFO (it->f)->resx + : FRAME_X_DISPLAY_INFO (it->f)->resy), + ppi > 0)) + return OK_PIXELS (ppi / pixels); +#endif + if ((ppi = NUMVAL (Vdisplay_pixels_per_inch), ppi > 0) || (CONSP (Vdisplay_pixels_per_inch) && (ppi = (width_p @@ -17701,22 +18535,23 @@ get_glyph_face_and_encoding (f, glyph, char2b, two_byte_p) FACES is an array of faces for all components of this composition. S->gidx is the index of the first component for S. - OVERLAPS_P non-zero means S should draw the foreground only, and - use its physical height for clipping. + + OVERLAPS non-zero means S should draw the foreground only, and use + its physical height for clipping. See also draw_glyphs. Value is the index of a component not in S. */ static int -fill_composite_glyph_string (s, faces, overlaps_p) +fill_composite_glyph_string (s, faces, overlaps) struct glyph_string *s; struct face **faces; - int overlaps_p; + int overlaps; { int i; xassert (s); - s->for_overlaps_p = overlaps_p; + s->for_overlaps = overlaps; s->face = faces[s->gidx]; s->font = s->face->font; @@ -17760,16 +18595,16 @@ fill_composite_glyph_string (s, faces, overlaps_p) FACE_ID is the face id of the string. START is the index of the first glyph to consider, END is the index of the last + 1. - OVERLAPS_P non-zero means S should draw the foreground only, and - use its physical height for clipping. + OVERLAPS non-zero means S should draw the foreground only, and use + its physical height for clipping. See also draw_glyphs. Value is the index of the first glyph not in S. */ static int -fill_glyph_string (s, face_id, start, end, overlaps_p) +fill_glyph_string (s, face_id, start, end, overlaps) struct glyph_string *s; int face_id; - int start, end, overlaps_p; + int start, end, overlaps; { struct glyph *glyph, *last; int voffset; @@ -17779,7 +18614,7 @@ fill_glyph_string (s, face_id, start, end, overlaps_p) xassert (s->nchars == 0); xassert (start >= 0 && end > start); - s->for_overlaps_p = overlaps_p, + s->for_overlaps = overlaps, glyph = s->row->glyphs[s->area] + start; last = s->row->glyphs[s->area] + end; voffset = glyph->voffset; @@ -18114,19 +18949,15 @@ set_glyph_string_background_width (s, start, last_x) { /* If the face of this glyph string has to be drawn to the end of the drawing area, set S->extends_to_end_of_line_p. */ - struct face *default_face = FACE_FROM_ID (s->f, DEFAULT_FACE_ID); if (start == s->row->used[s->area] && s->area == TEXT_AREA - && ((s->hl == DRAW_NORMAL_TEXT - && (s->row->fill_line_p - || s->face->background != default_face->background - || s->face->stipple != default_face->stipple - || s->row->mouse_face_p)) - || s->hl == DRAW_MOUSE_FACE - || ((s->hl == DRAW_IMAGE_RAISED || s->hl == DRAW_IMAGE_SUNKEN) - && s->row->fill_line_p))) - s->extends_to_end_of_line_p = 1; + && ((s->row->fill_line_p + && (s->hl == DRAW_NORMAL_TEXT + || s->hl == DRAW_IMAGE_RAISED + || s->hl == DRAW_IMAGE_SUNKEN)) + || s->hl == DRAW_MOUSE_FACE)) + s->extends_to_end_of_line_p = 1; /* If S extends its face to the end of the line, set its background_width to the distance to the right edge of the drawing @@ -18256,7 +19087,7 @@ compute_overhangs_and_x (s, x, backward_p) INIT_GLYPH_STRING (s, char2b, w, row, area, START, HL); \ append_glyph_string (&HEAD, &TAIL, s); \ s->x = (X); \ - START = fill_glyph_string (s, face_id, START, END, overlaps_p); \ + START = fill_glyph_string (s, face_id, START, END, overlaps); \ } \ while (0) @@ -18309,7 +19140,7 @@ compute_overhangs_and_x (s, x, backward_p) if (n == 0) \ first_s = s; \ \ - n = fill_composite_glyph_string (s, faces, overlaps_p); \ + n = fill_composite_glyph_string (s, faces, overlaps); \ } \ \ ++START; \ @@ -18378,20 +19209,26 @@ compute_overhangs_and_x (s, x, backward_p) DRAW_IMAGE_SUNKEN draw an image with a sunken relief around it DRAW_IMAGE_RAISED draw an image with a raised relief around it - If OVERLAPS_P is non-zero, draw only the foreground of characters - and clip to the physical height of ROW. + If OVERLAPS is non-zero, draw only the foreground of characters and + clip to the physical height of ROW. Non-zero value also defines + the overlapping part to be drawn: + + OVERLAPS_PRED overlap with preceding rows + OVERLAPS_SUCC overlap with succeeding rows + OVERLAPS_BOTH overlap with both preceding/succeeding rows + OVERLAPS_ERASED_CURSOR overlap with erased cursor area Value is the x-position reached, relative to AREA of W. */ static int -draw_glyphs (w, x, row, area, start, end, hl, overlaps_p) +draw_glyphs (w, x, row, area, start, end, hl, overlaps) struct window *w; int x; struct glyph_row *row; enum glyph_row_area area; int start, end; enum draw_glyphs_face hl; - int overlaps_p; + int overlaps; { struct glyph_string *head, *tail; struct glyph_string *s; @@ -18440,7 +19277,7 @@ draw_glyphs (w, x, row, area, start, end, hl, overlaps_p) /* If there are any glyphs with lbearing < 0 or rbearing > width in the row, redraw some glyphs in front or following the glyph strings built above. */ - if (head && !overlaps_p && row->contains_overlapping_glyphs_p) + if (head && !overlaps && row->contains_overlapping_glyphs_p) { int dummy_x = 0; struct glyph_string *h, *t; @@ -18533,7 +19370,7 @@ draw_glyphs (w, x, row, area, start, end, hl, overlaps_p) /* When drawing overlapping rows, only the glyph strings' foreground is drawn, which doesn't erase a cursor completely. */ - && !overlaps_p) + && !overlaps) { int x0 = clip_head ? clip_head->x : (head ? head->x : x); int x1 = (clip_tail ? clip_tail->x + clip_tail->background_width @@ -18920,14 +19757,14 @@ produce_stretch_glyph (it) plist = XCDR (it->object); /* Compute the width of the stretch. */ - if ((prop = Fsafe_plist_get (plist, QCwidth), !NILP (prop)) + if ((prop = Fplist_get (plist, QCwidth), !NILP (prop)) && calc_pixel_width_or_height (&tem, it, prop, font, 1, 0)) { /* Absolute width `:width WIDTH' specified and valid. */ zero_width_ok_p = 1; width = (int)tem; } - else if (prop = Fsafe_plist_get (plist, QCrelative_width), + else if (prop = Fplist_get (plist, QCrelative_width), NUMVAL (prop) > 0) { /* Relative width `:relative-width FACTOR' specified and valid. @@ -18951,7 +19788,7 @@ produce_stretch_glyph (it) x_produce_glyphs (&it2); width = NUMVAL (prop) * it2.pixel_width; } - else if ((prop = Fsafe_plist_get (plist, QCalign_to), !NILP (prop)) + else if ((prop = Fplist_get (plist, QCalign_to), !NILP (prop)) && calc_pixel_width_or_height (&tem, it, prop, font, 1, &align_to)) { if (it->glyph_row == NULL || !it->glyph_row->mode_line_p) @@ -18971,13 +19808,13 @@ produce_stretch_glyph (it) width = 1; /* Compute height. */ - if ((prop = Fsafe_plist_get (plist, QCheight), !NILP (prop)) + if ((prop = Fplist_get (plist, QCheight), !NILP (prop)) && calc_pixel_width_or_height (&tem, it, prop, font, 0, 0)) { height = (int)tem; zero_height_ok_p = 1; } - else if (prop = Fsafe_plist_get (plist, QCrelative_height), + else if (prop = Fplist_get (plist, QCrelative_height), NUMVAL (prop) > 0) height = FONT_HEIGHT (font) * NUMVAL (prop); else @@ -18989,7 +19826,7 @@ produce_stretch_glyph (it) /* Compute percentage of height used for ascent. If `:ascent ASCENT' is present and valid, use that. Otherwise, derive the ascent from the font in use. */ - if (prop = Fsafe_plist_get (plist, QCascent), + if (prop = Fplist_get (plist, QCascent), NUMVAL (prop) > 0 && NUMVAL (prop) <= 100) ascent = height * NUMVAL (prop) / 100.0; else if (!NILP (prop) @@ -18998,6 +19835,10 @@ produce_stretch_glyph (it) else ascent = (height * FONT_BASE (font)) / FONT_HEIGHT (font); + if (width > 0 && !it->truncate_lines_p + && it->current_x + width > it->last_visible_x) + width = it->last_visible_x - it->current_x - 1; + if (width > 0 && height > 0 && it->glyph_row) { Lisp_Object object = it->stack[it->sp - 1].string; @@ -19037,7 +19878,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)); @@ -19138,8 +19979,8 @@ calc_line_height_property (it, val, font, boff, override) /* RIF: Produce glyphs/get display metrics for the display element IT is - loaded with. See the description of struct display_iterator in - dispextern.h for an overview of struct display_iterator. */ + loaded with. See the description of struct it in dispextern.h + for an overview of struct it. */ void x_produce_glyphs (it) @@ -19388,7 +20229,6 @@ x_produce_glyphs (it) else { Lisp_Object spacing; - int total = 0; it->phys_ascent = it->ascent; it->phys_descent = it->descent; @@ -20100,8 +20940,13 @@ get_window_cursor_type (w, glyph, width, active_cursor) { if (w == XWINDOW (echo_area_window)) { - *width = FRAME_CURSOR_WIDTH (f); - return FRAME_DESIRED_CURSOR (f); + if (EQ (b->cursor_type, Qt) || NILP (b->cursor_type)) + { + *width = FRAME_CURSOR_WIDTH (f); + return FRAME_DESIRED_CURSOR (f); + } + else + return get_specified_cursor_type (b->cursor_type, width); } *active_cursor = 0; @@ -20130,7 +20975,7 @@ get_window_cursor_type (w, glyph, width, active_cursor) /* Use cursor-in-non-selected-windows for non-selected window or frame. */ if (non_selected) { - alt_cursor = Fbuffer_local_value (Qcursor_in_non_selected_windows, w->buffer); + alt_cursor = b->cursor_in_non_selected_windows; return get_specified_cursor_type (alt_cursor, width); } @@ -20267,13 +21112,15 @@ notice_overwritten_cursor (w, area, x0, x1, y0, y1) #ifdef HAVE_WINDOW_SYSTEM /* EXPORT for RIF: - Fix the display of area AREA of overlapping row ROW in window W. */ + Fix the display of area AREA of overlapping row ROW in window W + with respect to the overlapping part OVERLAPS. */ void -x_fix_overlapping_area (w, row, area) +x_fix_overlapping_area (w, row, area, overlaps) struct window *w; struct glyph_row *row; enum glyph_row_area area; + int overlaps; { int i, x; @@ -20296,7 +21143,7 @@ x_fix_overlapping_area (w, row, area) draw_glyphs (w, start_x, row, area, start, i, - DRAW_NORMAL_TEXT, 1); + DRAW_NORMAL_TEXT, overlaps); } else { @@ -20338,13 +21185,17 @@ draw_phys_cursor_glyph (w, row, hl) are redrawn. */ else if (hl == DRAW_NORMAL_TEXT && row->overlapped_p) { + w->phys_cursor_width = x1 - w->phys_cursor.x; + if (row > w->current_matrix->rows && MATRIX_ROW_OVERLAPS_SUCC_P (row - 1)) - x_fix_overlapping_area (w, row - 1, TEXT_AREA); + x_fix_overlapping_area (w, row - 1, TEXT_AREA, + OVERLAPS_ERASED_CURSOR); if (MATRIX_ROW_BOTTOM_Y (row) < window_text_bottom_y (w) && MATRIX_ROW_OVERLAPS_PRED_P (row + 1)) - x_fix_overlapping_area (w, row + 1, TEXT_AREA); + x_fix_overlapping_area (w, row + 1, TEXT_AREA, + OVERLAPS_ERASED_CURSOR); } } } @@ -20659,7 +21510,11 @@ show_mouse_face (dpyinfo, draw) if (row == last) end_hpos = dpyinfo->mouse_face_end_col; else - end_hpos = row->used[TEXT_AREA]; + { + end_hpos = row->used[TEXT_AREA]; + if (draw == DRAW_NORMAL_TEXT) + row->fill_line_p = 1; /* Clear to end of line */ + } if (end_hpos > start_hpos) { @@ -21219,11 +22074,12 @@ define_frame_cursor1 (f, cursor, pointer) position relative to the start of the mode line. */ static void -note_mode_line_or_margin_highlight (w, x, y, area) - struct window *w; +note_mode_line_or_margin_highlight (window, x, y, area) + Lisp_Object window; int x, y; enum window_part area; { + struct window *w = XWINDOW (window); struct frame *f = XFRAME (w->frame); Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (f); Cursor cursor = FRAME_X_OUTPUT (f)->nontext_cursor; @@ -21232,9 +22088,38 @@ note_mode_line_or_margin_highlight (w, x, y, area) Lisp_Object string, object = Qnil; Lisp_Object pos, help; + Lisp_Object mouse_face; + int original_x_pixel = x; + struct glyph * glyph = NULL; + struct glyph_row *row; + if (area == ON_MODE_LINE || area == ON_HEADER_LINE) - string = mode_line_string (w, area, &x, &y, &charpos, - &object, &dx, &dy, &width, &height); + { + int x0; + struct glyph *end; + + string = mode_line_string (w, area, &x, &y, &charpos, + &object, &dx, &dy, &width, &height); + + row = (area == ON_MODE_LINE + ? MATRIX_MODE_LINE_ROW (w->current_matrix) + : MATRIX_HEADER_LINE_ROW (w->current_matrix)); + + /* Find glyph */ + if (row->mode_line_p && row->enabled_p) + { + glyph = row->glyphs[TEXT_AREA]; + end = glyph + row->used[TEXT_AREA]; + + for (x0 = original_x_pixel; + glyph < end && x0 >= glyph->pixel_width; + ++glyph) + x0 -= glyph->pixel_width; + + if (glyph >= end) + glyph = NULL; + } + } else { x -= WINDOW_LEFT_SCROLL_BAR_AREA_WIDTH (w); @@ -21247,7 +22132,7 @@ note_mode_line_or_margin_highlight (w, x, y, area) if (IMAGEP (object)) { Lisp_Object image_map, hotspot; - if ((image_map = Fsafe_plist_get (XCDR (object), QCmap), + if ((image_map = Fplist_get (XCDR (object), QCmap), !NILP (image_map)) && (hotspot = find_hot_spot (image_map, dx, dy), CONSP (hotspot)) @@ -21263,10 +22148,10 @@ note_mode_line_or_margin_highlight (w, x, y, area) if (CONSP (hotspot) && (plist = XCAR (hotspot), CONSP (plist))) { - pointer = Fsafe_plist_get (plist, Qpointer); + pointer = Fplist_get (plist, Qpointer); if (NILP (pointer)) pointer = Qhand; - help = Fsafe_plist_get (plist, Qhelp_echo); + help = Fplist_get (plist, Qhelp_echo); if (!NILP (help)) { help_echo_string = help; @@ -21278,7 +22163,7 @@ note_mode_line_or_margin_highlight (w, x, y, area) } } if (NILP (pointer)) - pointer = Fsafe_plist_get (XCDR (object), QCpointer); + pointer = Fplist_get (XCDR (object), QCpointer); } if (STRINGP (string)) @@ -21312,8 +22197,110 @@ note_mode_line_or_margin_highlight (w, x, y, area) if (!KEYMAPP (map)) cursor = dpyinfo->vertical_scroll_bar_cursor; } - } + /* Change the mouse face according to what is under X/Y. */ + mouse_face = Fget_text_property (pos, Qmouse_face, string); + if (!NILP (mouse_face) + && ((area == ON_MODE_LINE) || (area == ON_HEADER_LINE)) + && glyph) + { + Lisp_Object b, e; + + struct glyph * tmp_glyph; + + int gpos; + int gseq_length; + int total_pixel_width; + int ignore; + + int vpos, hpos; + + b = Fprevious_single_property_change (make_number (charpos + 1), + Qmouse_face, string, Qnil); + if (NILP (b)) + b = make_number (0); + + e = Fnext_single_property_change (pos, Qmouse_face, string, Qnil); + if (NILP (e)) + e = make_number (SCHARS (string)); + + /* Calculate the position(glyph position: GPOS) of GLYPH in + displayed string. GPOS is different from CHARPOS. + + CHARPOS is the position of glyph in internal string + object. A mode line string format has structures which + is converted to a flatten by emacs lisp interpreter. + The internal string is an element of the structures. + The displayed string is the flatten string. */ + for (tmp_glyph = glyph - 1, gpos = 0; + tmp_glyph->charpos >= XINT (b); + tmp_glyph--, gpos++) + { + if (!EQ (tmp_glyph->object, glyph->object)) + break; + } + + /* Calculate the lenght(glyph sequence length: GSEQ_LENGTH) of + displayed string holding GLYPH. + + GSEQ_LENGTH is different from SCHARS (STRING). + SCHARS (STRING) returns the length of the internal string. */ + for (tmp_glyph = glyph, gseq_length = gpos; + tmp_glyph->charpos < XINT (e); + tmp_glyph++, gseq_length++) + { + if (!EQ (tmp_glyph->object, glyph->object)) + break; + } + + total_pixel_width = 0; + for (tmp_glyph = glyph - gpos; tmp_glyph != glyph; tmp_glyph++) + total_pixel_width += tmp_glyph->pixel_width; + + /* 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 = vpos + gseq_length; + dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_beg_row; + + dpyinfo->mouse_face_end_x = 0; + dpyinfo->mouse_face_end_y = 0; + + dpyinfo->mouse_face_past_end = 0; + dpyinfo->mouse_face_window = window; + + dpyinfo->mouse_face_face_id = face_at_string_position (w, string, + charpos, + 0, 0, 0, &ignore, + glyph->face_id, 1); + show_mouse_face (dpyinfo, DRAW_MOUSE_FACE); + + 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); } @@ -21366,7 +22353,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. */ @@ -21392,12 +22380,15 @@ note_mouse_highlight (f, x, y) if (part == ON_MODE_LINE || part == ON_HEADER_LINE || part == ON_LEFT_MARGIN || part == ON_RIGHT_MARGIN) { - note_mode_line_or_margin_highlight (w, x, y, part); + note_mode_line_or_margin_highlight (window, x, y, part); return; } if (part == ON_VERTICAL_BORDER) - cursor = FRAME_X_OUTPUT (f)->horizontal_drag_cursor; + { + cursor = FRAME_X_OUTPUT (f)->horizontal_drag_cursor; + help_echo_string = build_string ("drag-mouse-1: resize"); + } else if (part == ON_LEFT_FRINGE || part == ON_RIGHT_FRINGE || part == ON_SCROLL_BAR) cursor = FRAME_X_OUTPUT (f)->nontext_cursor; @@ -21431,7 +22422,7 @@ note_mouse_highlight (f, x, y) if (img != NULL && IMAGEP (img->spec)) { Lisp_Object image_map, hotspot; - if ((image_map = Fsafe_plist_get (XCDR (img->spec), QCmap), + if ((image_map = Fplist_get (XCDR (img->spec), QCmap), !NILP (image_map)) && (hotspot = find_hot_spot (image_map, glyph->slice.x + dx, @@ -21449,10 +22440,10 @@ note_mouse_highlight (f, x, y) if (CONSP (hotspot) && (plist = XCAR (hotspot), CONSP (plist))) { - pointer = Fsafe_plist_get (plist, Qpointer); + pointer = Fplist_get (plist, Qpointer); if (NILP (pointer)) pointer = Qhand; - help_echo_string = Fsafe_plist_get (plist, Qhelp_echo); + help_echo_string = Fplist_get (plist, Qhelp_echo); if (!NILP (help_echo_string)) { help_echo_window = window; @@ -21462,7 +22453,7 @@ note_mouse_highlight (f, x, y) } } if (NILP (pointer)) - pointer = Fsafe_plist_get (XCDR (img->spec), QCpointer); + pointer = Fplist_get (XCDR (img->spec), QCpointer); } } @@ -21652,6 +22643,7 @@ note_mouse_highlight (f, x, y) b = make_number (0); if (NILP (e)) e = make_number (SCHARS (object) - 1); + fast_find_string_pos (w, XINT (b), object, &dpyinfo->mouse_face_beg_col, &dpyinfo->mouse_face_beg_row, @@ -22001,13 +22993,13 @@ expose_overlaps (w, first_overlapping_row, last_overlapping_row) xassert (row->enabled_p && !row->mode_line_p); if (row->used[LEFT_MARGIN_AREA]) - x_fix_overlapping_area (w, row, LEFT_MARGIN_AREA); + x_fix_overlapping_area (w, row, LEFT_MARGIN_AREA, OVERLAPS_BOTH); if (row->used[TEXT_AREA]) - x_fix_overlapping_area (w, row, TEXT_AREA); + x_fix_overlapping_area (w, row, TEXT_AREA, OVERLAPS_BOTH); if (row->used[RIGHT_MARGIN_AREA]) - x_fix_overlapping_area (w, row, RIGHT_MARGIN_AREA); + x_fix_overlapping_area (w, row, RIGHT_MARGIN_AREA, OVERLAPS_BOTH); } } @@ -22067,6 +23059,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) @@ -22077,6 +23072,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); } } @@ -22480,6 +23478,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"); @@ -22494,8 +23494,6 @@ syms_of_xdisp () staticpro (&Qpoly); Qmessage_truncate_lines = intern ("message-truncate-lines"); staticpro (&Qmessage_truncate_lines); - Qcursor_in_non_selected_windows = intern ("cursor-in-non-selected-windows"); - staticpro (&Qcursor_in_non_selected_windows); Qgrow_only = intern ("grow-only"); staticpro (&Qgrow_only); Qinhibit_menubar_update = intern ("inhibit-menubar-update"); @@ -22555,9 +23553,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); @@ -22582,14 +23585,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, @@ -22639,7 +23647,7 @@ of the top or bottom of the window. */); scroll_margin = 0; DEFVAR_LISP ("display-pixels-per-inch", &Vdisplay_pixels_per_inch, - doc: /* Pixels per inch on current display. + doc: /* Pixels per inch value for non-window system displays. Value is a number or a cons (WIDTH-DPI . HEIGHT-DPI). */); Vdisplay_pixels_per_inch = make_float (72.0); @@ -22726,6 +23734,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; @@ -22745,6 +23759,14 @@ otherwise. */); doc: /* *Non-nil means to scroll (recenter) cursor line if it is not fully visible. */); make_cursor_line_fully_visible_p = 1; + DEFVAR_LISP ("tool-bar-border", &Vtool_bar_border, + doc: /* *Border below tool-bar in pixels. +If an integer, use it as the height of the border. +If it is one of `internal-border-width' or `border-width', use the +value of the corresponding frame parameter. +Otherwise, no border is added below the tool-bar. */); + Vtool_bar_border = Qinternal_border_width; + DEFVAR_LISP ("tool-bar-button-margin", &Vtool_bar_button_margin, doc: /* *Margin around tool-bar buttons in pixels. If an integer, use that for both horizontal and vertical margins. @@ -22789,18 +23811,16 @@ only, until their display becomes empty, at which point the windows go back to their normal size. */); Vresize_mini_windows = Qgrow_only; - DEFVAR_LISP ("cursor-in-non-selected-windows", - &Vcursor_in_non_selected_windows, - doc: /* *Cursor type to display in non-selected windows. -t means to use hollow box cursor. See `cursor-type' for other values. */); - Vcursor_in_non_selected_windows = Qt; - DEFVAR_LISP ("blink-cursor-alist", &Vblink_cursor_alist, doc: /* Alist specifying how to blink the cursor off. Each element has the form (ON-STATE . OFF-STATE). Whenever the `cursor-type' frame-parameter or variable equals ON-STATE, comparing using `equal', Emacs uses OFF-STATE to specify -how to blink it off. */); +how to blink it off. ON-STATE and OFF-STATE are values for +the `cursor-type' frame parameter. + +If a frame's ON-STATE has no entry in this list, +the frame's other specifications determine how to blink the cursor off. */); Vblink_cursor_alist = Qnil; DEFVAR_BOOL ("auto-hscroll-mode", &automatic_hscrolling_p, @@ -22814,7 +23834,7 @@ before automatic hscrolling will horizontally scroll the window. */); DEFVAR_LISP ("hscroll-step", &Vhscroll_step, doc: /* *How many columns to scroll the window when point gets too close to the edge. -When point is less than `automatic-hscroll-margin' columns from the window +When point is less than `hscroll-margin' columns from the window edge, automatic hscrolling will scroll the window by the amount of columns determined by this variable. If its value is a positive integer, scroll that many columns. If it's a positive floating-point number, it specifies the @@ -22913,9 +23933,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;