emacs-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Emacs-diffs] Changes to emacs/src/xdisp.c [emacs-unicode-2]


From: Kenichi Handa
Subject: [Emacs-diffs] Changes to emacs/src/xdisp.c [emacs-unicode-2]
Date: Mon, 08 Sep 2003 08:49:36 -0400

Index: emacs/src/xdisp.c
diff -c /dev/null emacs/src/xdisp.c:1.843.2.1
*** /dev/null   Mon Sep  8 08:49:36 2003
--- emacs/src/xdisp.c   Mon Sep  8 08:48:15 2003
***************
*** 0 ****
--- 1,21071 ----
+ /* Display generation from window structure and buffer text.
+    Copyright (C) 1985,86,87,88,93,94,95,97,98,99,2000,01,02,03
+    Free Software Foundation, Inc.
+ 
+ This file is part of GNU Emacs.
+ 
+ GNU Emacs is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+ 
+ GNU Emacs is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ 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.  */
+ 
+ /* New redisplay written by Gerd Moellmann <address@hidden>.
+ 
+    Redisplay.
+ 
+    Emacs separates the task of updating the display from code
+    modifying global state, e.g. buffer text.  This way functions
+    operating on buffers don't also have to be concerned with updating
+    the display.
+ 
+    Updating the display is triggered by the Lisp interpreter when it
+    decides it's time to do it.  This is done either automatically for
+    you as part of the interpreter's command loop or as the result of
+    calling Lisp functions like `sit-for'.  The C function `redisplay'
+    in xdisp.c is the only entry into the inner redisplay code.  (Or,
+    let's say almost---see the description of direct update
+    operations, below.)
+ 
+    The following diagram shows how redisplay code is invoked.  As you
+    can see, Lisp calls redisplay and vice versa.  Under window systems
+    like X, some portions of the redisplay code are also called
+    asynchronously during mouse movement or expose events.  It is very
+    important that these code parts do NOT use the C library (malloc,
+    free) because many C libraries under Unix are not reentrant.  They
+    may also NOT call functions of the Lisp interpreter which could
+    change the interpreter's state.  If you don't follow these rules,
+    you will encounter bugs which are very hard to explain.
+ 
+            (Direct functions, see below)
+              direct_output_for_insert,
+              direct_forward_char (dispnew.c)
+         +---------------------------------+
+           |                                 |
+         |                                 V
+    +--------------+   redisplay     +----------------+
+    | Lisp machine |---------------->| Redisplay code |<--+
+    +--------------+   (xdisp.c)     +----------------+   |
+         ^                                  |           |
+         +----------------------------------+           |
+           Don't use this path when called              |
+           asynchronously!                              |
+                                                          |
+                            expose_window (asynchronous)  |
+                                                          |
+                                  X expose events  -----+
+ 
+    What does redisplay do?  Obviously, it has to figure out somehow what
+    has been changed since the last time the display has been updated,
+    and to make these changes visible.  Preferably it would do that in
+    a moderately intelligent way, i.e. fast.
+ 
+    Changes in buffer text can be deduced from window and buffer
+    structures, and from some global variables like `beg_unchanged' and
+    `end_unchanged'.  The contents of the display are additionally
+    recorded in a `glyph matrix', a two-dimensional matrix of glyph
+    structures.  Each row in such a matrix corresponds to a line on the
+    display, and each glyph in a row corresponds to a column displaying
+    a character, an image, or what else.  This matrix is called the
+    `current glyph matrix' or `current matrix' in redisplay
+    terminology.
+ 
+    For buffer parts that have been changed since the last update, a
+    second glyph matrix is constructed, the so called `desired glyph
+    matrix' or short `desired matrix'.  Current and desired matrix are
+    then compared to find a cheap way to update the display, e.g. by
+    reusing part of the display by scrolling lines.
+ 
+ 
+    Direct operations.
+ 
+    You will find a lot of redisplay optimizations when you start
+    looking at the innards of redisplay.  The overall goal of all these
+    optimizations is to make redisplay fast because it is done
+    frequently.
+ 
+    Two optimizations are not found in xdisp.c.  These are the direct
+    operations mentioned above.  As the name suggests they follow a
+    different principle than the rest of redisplay.  Instead of
+    building a desired matrix and then comparing it with the current
+    display, they perform their actions directly on the display and on
+    the current matrix.
+ 
+    One direct operation updates the display after one character has
+    been entered.  The other one moves the cursor by one position
+    forward or backward.  You find these functions under the names
+    `direct_output_for_insert' and `direct_output_forward_char' in
+    dispnew.c.
+ 
+ 
+    Desired matrices.
+ 
+    Desired matrices are always built per Emacs window.  The function
+    `display_line' is the central function to look at if you are
+    interested.  It constructs one row in a desired matrix given an
+    iterator structure containing both a buffer position and a
+    description of the environment in which the text is to be
+    displayed.  But this is too early, read on.
+ 
+    Characters and pixmaps displayed for a range of buffer text depend
+    on various settings of buffers and windows, on overlays and text
+    properties, on display tables, on selective display.  The good news
+    is that all this hairy stuff is hidden behind a small set of
+    interface functions taking an iterator structure (struct it)
+    argument.
+ 
+    Iteration over things to be displayed is then simple.  It is
+    started by initializing an iterator with a call to init_iterator.
+    Calls to get_next_display_element fill the iterator structure with
+    relevant information about the next thing to display.  Calls to
+    set_iterator_to_next move the iterator to the next thing.
+ 
+    Besides this, an iterator also contains information about the
+    display environment in which glyphs for display elements are to be
+    produced.  It has fields for the width and height of the display,
+    the information whether long lines are truncated or continued, a
+    current X and Y position, and lots of other stuff you can better
+    see in dispextern.h.
+ 
+    Glyphs in a desired matrix are normally constructed in a loop
+    calling get_next_display_element and then produce_glyphs.  The call
+    to produce_glyphs will fill the iterator structure with pixel
+    information about the element being displayed and at the same time
+    produce glyphs for it.  If the display element fits on the line
+    being displayed, set_iterator_to_next is called next, otherwise the
+    glyphs produced are discarded.
+ 
+ 
+    Frame matrices.
+ 
+    That just couldn't be all, could it?  What about terminal types not
+    supporting operations on sub-windows of the screen?  To update the
+    display on such a terminal, window-based glyph matrices are not
+    well suited.  To be able to reuse part of the display (scrolling
+    lines up and down), we must instead have a view of the whole
+    screen.  This is what `frame matrices' are for.  They are a trick.
+ 
+    Frames on terminals like above have a glyph pool.  Windows on such
+    a frame sub-allocate their glyph memory from their frame's glyph
+    pool.  The frame itself is given its own glyph matrices.  By
+    coincidence---or maybe something else---rows in window glyph
+    matrices are slices of corresponding rows in frame matrices.  Thus
+    writing to window matrices implicitly updates a frame matrix which
+    provides us with the view of the whole screen that we originally
+    wanted to have without having to move many bytes around.  To be
+    honest, there is a little bit more done, but not much more.  If you
+    plan to extend that code, take a look at dispnew.c.  The function
+    build_frame_matrix is a good starting point.  */
+ 
+ #include <config.h>
+ #include <stdio.h>
+ 
+ #include "lisp.h"
+ #include "keyboard.h"
+ #include "frame.h"
+ #include "window.h"
+ #include "termchar.h"
+ #include "dispextern.h"
+ #include "buffer.h"
+ #include "character.h"
+ #include "charset.h"
+ #include "indent.h"
+ #include "commands.h"
+ #include "keymap.h"
+ #include "macros.h"
+ #include "disptab.h"
+ #include "termhooks.h"
+ #include "intervals.h"
+ #include "coding.h"
+ #include "process.h"
+ #include "region-cache.h"
+ #include "fontset.h"
+ #include "blockinput.h"
+ 
+ #ifdef HAVE_X_WINDOWS
+ #include "xterm.h"
+ #endif
+ #ifdef WINDOWSNT
+ #include "w32term.h"
+ #endif
+ #ifdef MAC_OS
+ #include "macterm.h"
+ 
+ Cursor No_Cursor;
+ #endif
+ 
+ #ifndef FRAME_X_OUTPUT
+ #define FRAME_X_OUTPUT(f) ((f)->output_data.x)
+ #endif
+ 
+ #define INFINITY 10000000
+ 
+ #if defined (USE_X_TOOLKIT) || defined (HAVE_NTGUI) || defined (MAC_OS) \
+     || defined (USE_GTK)
+ extern void set_frame_menubar P_ ((struct frame *f, int, int));
+ extern int pending_menu_activation;
+ #endif
+ 
+ extern int interrupt_input;
+ extern int command_loop_level;
+ 
+ extern int minibuffer_auto_raise;
+ extern Lisp_Object Vminibuffer_list;
+ 
+ extern Lisp_Object Qface;
+ extern Lisp_Object Qmode_line, Qmode_line_inactive, Qheader_line;
+ 
+ extern Lisp_Object Voverriding_local_map;
+ extern Lisp_Object Voverriding_local_map_menu_flag;
+ extern Lisp_Object Qmenu_item;
+ extern Lisp_Object Qwhen;
+ 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 Qinhibit_point_motion_hooks;
+ Lisp_Object QCeval, QCfile, QCdata, QCpropertize;
+ Lisp_Object Qfontified;
+ Lisp_Object Qgrow_only;
+ Lisp_Object Qinhibit_eval_during_redisplay;
+ Lisp_Object Qbuffer_position, Qposition, Qobject;
+ 
+ /* Cursor shapes */
+ Lisp_Object Qbar, Qhbar, Qbox, Qhollow;
+ 
+ Lisp_Object Qrisky_local_variable;
+ 
+ /* Holds the list (error).  */
+ Lisp_Object list_of_error;
+ 
+ /* Functions called to fontify regions of text.  */
+ 
+ Lisp_Object Vfontification_functions;
+ Lisp_Object Qfontification_functions;
+ 
+ /* Non-zero means automatically select any window when the mouse
+    cursor moves into it.  */
+ int mouse_autoselect_window;
+ 
+ /* Non-zero means draw tool bar buttons raised when the mouse moves
+    over them.  */
+ 
+ int auto_raise_tool_bar_buttons_p;
+ 
+ /* Margin around tool bar buttons in pixels.  */
+ 
+ Lisp_Object Vtool_bar_button_margin;
+ 
+ /* Thickness of shadow to draw around tool bar buttons.  */
+ 
+ EMACS_INT tool_bar_button_relief;
+ 
+ /* Non-zero means automatically resize tool-bars so that all tool-bar
+    items are visible, and no blank lines remain.  */
+ 
+ int auto_resize_tool_bars_p;
+ 
+ /* Non-zero means draw block and hollow cursor as wide as the glyph
+    under it.  For example, if a block cursor is over a tab, it will be
+    drawn as wide as that tab on the display.  */
+ 
+ int x_stretch_cursor_p;
+ 
+ /* Non-nil means don't actually do any redisplay.  */
+ 
+ Lisp_Object Vinhibit_redisplay, Qinhibit_redisplay;
+ 
+ /* Non-zero means Lisp evaluation during redisplay is inhibited.  */
+ 
+ int inhibit_eval_during_redisplay;
+ 
+ /* Names of text properties relevant for redisplay.  */
+ 
+ Lisp_Object Qdisplay, Qrelative_width, Qalign_to;
+ extern Lisp_Object Qface, Qinvisible, Qwidth;
+ 
+ /* Symbols used in text property values.  */
+ 
+ Lisp_Object Qspace, QCalign_to, QCrelative_width, QCrelative_height;
+ Lisp_Object Qleft_margin, Qright_margin, Qspace_width, Qraise;
+ Lisp_Object Qmargin;
+ extern Lisp_Object Qheight;
+ extern Lisp_Object QCwidth, QCheight, QCascent;
+ 
+ /* Non-nil means highlight trailing whitespace.  */
+ 
+ Lisp_Object Vshow_trailing_whitespace;
+ 
+ /* Name of the face used to highlight trailing whitespace.  */
+ 
+ Lisp_Object Qtrailing_whitespace;
+ 
+ /* The symbol `image' which is the car of the lists used to represent
+    images in Lisp.  */
+ 
+ Lisp_Object Qimage;
+ 
+ /* Non-zero means print newline to stdout before next mini-buffer
+    message.  */
+ 
+ int noninteractive_need_newline;
+ 
+ /* Non-zero means print newline to message log before next message.  */
+ 
+ static int message_log_need_newline;
+ 
+ /* Three markers that message_dolog uses.
+    It could allocate them itself, but that causes trouble
+    in handling memory-full errors.  */
+ static Lisp_Object message_dolog_marker1;
+ static Lisp_Object message_dolog_marker2;
+ static Lisp_Object message_dolog_marker3;
+ 
+ /* The buffer position of the first character appearing entirely or
+    partially on the line of the selected window which contains the
+    cursor; <= 0 if not known.  Set by set_cursor_from_row, used for
+    redisplay optimization in redisplay_internal.  */
+ 
+ static struct text_pos this_line_start_pos;
+ 
+ /* Number of characters past the end of the line above, including the
+    terminating newline.  */
+ 
+ static struct text_pos this_line_end_pos;
+ 
+ /* The vertical positions and the height of this line.  */
+ 
+ static int this_line_vpos;
+ static int this_line_y;
+ static int this_line_pixel_height;
+ 
+ /* X position at which this display line starts.  Usually zero;
+    negative if first character is partially visible.  */
+ 
+ static int this_line_start_x;
+ 
+ /* Buffer that this_line_.* variables are referring to.  */
+ 
+ static struct buffer *this_line_buffer;
+ 
+ /* Nonzero means truncate lines in all windows less wide than the
+    frame.  */
+ 
+ int truncate_partial_width_windows;
+ 
+ /* A flag to control how to display unibyte 8-bit character.  */
+ 
+ int unibyte_display_via_language_environment;
+ 
+ /* Nonzero means we have more than one non-mini-buffer-only frame.
+    Not guaranteed to be accurate except while parsing
+    frame-title-format.  */
+ 
+ int multiple_frames;
+ 
+ Lisp_Object Vglobal_mode_string;
+ 
+ /* Marker for where to display an arrow on top of the buffer text.  */
+ 
+ Lisp_Object Voverlay_arrow_position;
+ 
+ /* String to display for the arrow.  Only used on terminal frames.  */
+ 
+ Lisp_Object Voverlay_arrow_string;
+ 
+ /* Values of those variables at last redisplay.  However, if
+    Voverlay_arrow_position is a marker, last_arrow_position is its
+    numerical position.  */
+ 
+ static Lisp_Object last_arrow_position, last_arrow_string;
+ 
+ /* Like mode-line-format, but for the title bar on a visible frame.  */
+ 
+ Lisp_Object Vframe_title_format;
+ 
+ /* Like mode-line-format, but for the title bar on an iconified frame.  */
+ 
+ Lisp_Object Vicon_title_format;
+ 
+ /* List of functions to call when a window's size changes.  These
+    functions get one arg, a frame on which one or more windows' sizes
+    have changed.  */
+ 
+ static Lisp_Object Vwindow_size_change_functions;
+ 
+ Lisp_Object Qmenu_bar_update_hook, Vmenu_bar_update_hook;
+ 
+ /* Nonzero if overlay arrow has been displayed once in this window.  */
+ 
+ static int overlay_arrow_seen;
+ 
+ /* Nonzero means highlight the region even in nonselected windows.  */
+ 
+ int highlight_nonselected_windows;
+ 
+ /* If cursor motion alone moves point off frame, try scrolling this
+    many lines up or down if that will bring it back.  */
+ 
+ static EMACS_INT scroll_step;
+ 
+ /* Nonzero means scroll just far enough to bring point back on the
+    screen, when appropriate.  */
+ 
+ static EMACS_INT scroll_conservatively;
+ 
+ /* Recenter the window whenever point gets within this many lines of
+    the top or bottom of the window.  This value is translated into a
+    pixel value by multiplying it with FRAME_LINE_HEIGHT, which means
+    that there is really a fixed pixel height scroll margin.  */
+ 
+ EMACS_INT scroll_margin;
+ 
+ /* Number of windows showing the buffer of the selected window (or
+    another buffer with the same base buffer).  keyboard.c refers to
+    this.  */
+ 
+ int buffer_shared;
+ 
+ /* Vector containing glyphs for an ellipsis `...'.  */
+ 
+ static Lisp_Object default_invis_vector[3];
+ 
+ /* Zero means display the mode-line/header-line/menu-bar in the default face
+    (this slightly odd definition is for compatibility with previous versions
+    of emacs), non-zero means display them using their respective faces.
+ 
+    This variable is deprecated.  */
+ 
+ int mode_line_inverse_video;
+ 
+ /* Prompt to display in front of the mini-buffer contents.  */
+ 
+ Lisp_Object minibuf_prompt;
+ 
+ /* Width of current mini-buffer prompt.  Only set after display_line
+    of the line that contains the prompt.  */
+ 
+ int minibuf_prompt_width;
+ 
+ /* This is the window where the echo area message was displayed.  It
+    is always a mini-buffer window, but it may not be the same window
+    currently active as a mini-buffer.  */
+ 
+ Lisp_Object echo_area_window;
+ 
+ /* List of pairs (MESSAGE . MULTIBYTE).  The function save_message
+    pushes the current message and the value of
+    message_enable_multibyte on the stack, the function restore_message
+    pops the stack and displays MESSAGE again.  */
+ 
+ Lisp_Object Vmessage_stack;
+ 
+ /* Nonzero means multibyte characters were enabled when the echo area
+    message was specified.  */
+ 
+ int message_enable_multibyte;
+ 
+ /* Nonzero if we should redraw the mode lines on the next redisplay.  */
+ 
+ int update_mode_lines;
+ 
+ /* Nonzero if window sizes or contents have changed since last
+    redisplay that finished.  */
+ 
+ int windows_or_buffers_changed;
+ 
+ /* Nonzero means a frame's cursor type has been changed.  */
+ 
+ int cursor_type_changed;
+ 
+ /* Nonzero after display_mode_line if %l was used and it displayed a
+    line number.  */
+ 
+ int line_number_displayed;
+ 
+ /* Maximum buffer size for which to display line numbers.  */
+ 
+ Lisp_Object Vline_number_display_limit;
+ 
+ /* Line width to consider when repositioning for line number display.  */
+ 
+ static EMACS_INT line_number_display_limit_width;
+ 
+ /* Number of lines to keep in the message log buffer.  t means
+    infinite.  nil means don't log at all.  */
+ 
+ Lisp_Object Vmessage_log_max;
+ 
+ /* The name of the *Messages* buffer, a string.  */
+ 
+ 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.  */
+ 
+ Lisp_Object echo_area_buffer[2];
+ 
+ /* The buffers referenced from echo_area_buffer.  */
+ 
+ static Lisp_Object echo_buffer[2];
+ 
+ /* A vector saved used in with_area_buffer to reduce consing.  */
+ 
+ static Lisp_Object Vwith_echo_area_save_vector;
+ 
+ /* Non-zero means display_echo_area should display the last echo area
+    message again.  Set by redisplay_preserve_echo_area.  */
+ 
+ static int display_last_displayed_message_p;
+ 
+ /* Nonzero if echo area is being used by print; zero if being used by
+    message.  */
+ 
+ int message_buf_print;
+ 
+ /* The symbol `inhibit-menubar-update' and its DEFVAR_BOOL variable.  */
+ 
+ Lisp_Object Qinhibit_menubar_update;
+ int inhibit_menubar_update;
+ 
+ /* Maximum height for resizing mini-windows.  Either a float
+    specifying a fraction of the available height, or an integer
+    specifying a number of lines.  */
+ 
+ Lisp_Object Vmax_mini_window_height;
+ 
+ /* Non-zero means messages should be displayed with truncated
+    lines instead of being continued.  */
+ 
+ int message_truncate_lines;
+ Lisp_Object Qmessage_truncate_lines;
+ 
+ /* Set to 1 in clear_message to make redisplay_internal aware
+    of an emptied echo area.   */
+ 
+ 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;
+ 
+ /* A scratch glyph row with contents used for generating truncation
+    glyphs.  Also used in direct_output_for_insert.  */
+ 
+ #define MAX_SCRATCH_GLYPHS 100
+ struct glyph_row scratch_glyph_row;
+ static struct glyph scratch_glyphs[MAX_SCRATCH_GLYPHS];
+ 
+ /* Ascent and height of the last line processed by move_it_to.  */
+ 
+ static int last_max_ascent, last_height;
+ 
+ /* Non-zero if there's a help-echo in the echo area.  */
+ 
+ int help_echo_showing_p;
+ 
+ /* If >= 0, computed, exact values of mode-line and header-line height
+    to use in the macros CURRENT_MODE_LINE_HEIGHT and
+    CURRENT_HEADER_LINE_HEIGHT.  */
+ 
+ int current_mode_line_height, current_header_line_height;
+ 
+ /* The maximum distance to look ahead for text properties.  Values
+    that are too small let us call compute_char_face and similar
+    functions too often which is expensive.  Values that are too large
+    let us call compute_char_face and alike too often because we
+    might not be interested in text properties that far away.  */
+ 
+ #define TEXT_PROP_DISTANCE_LIMIT 100
+ 
+ #if GLYPH_DEBUG
+ 
+ /* Variables to turn off display optimizations from Lisp.  */
+ 
+ int inhibit_try_window_id, inhibit_try_window_reusing;
+ int inhibit_try_cursor_movement;
+ 
+ /* Non-zero means print traces of redisplay if compiled with
+    GLYPH_DEBUG != 0.  */
+ 
+ int trace_redisplay_p;
+ 
+ #endif /* GLYPH_DEBUG */
+ 
+ #ifdef DEBUG_TRACE_MOVE
+ /* Non-zero means trace with TRACE_MOVE to stderr.  */
+ int trace_move;
+ 
+ #define TRACE_MOVE(x) if (trace_move) fprintf x; else (void) 0
+ #else
+ #define TRACE_MOVE(x) (void) 0
+ #endif
+ 
+ /* Non-zero means automatically scroll windows horizontally to make
+    point visible.  */
+ 
+ int automatic_hscrolling_p;
+ 
+ /* How close to the margin can point get before the window is scrolled
+    horizontally.  */
+ EMACS_INT hscroll_margin;
+ 
+ /* How much to scroll horizontally when point is inside the above margin.  */
+ Lisp_Object Vhscroll_step;
+ 
+ /* A list of symbols, one for each supported image type.  */
+ 
+ Lisp_Object Vimage_types;
+ 
+ /* The variable `resize-mini-windows'.  If nil, don't resize
+    mini-windows.  If t, always resize them to fit the text they
+    display.  If `grow-only', let mini-windows grow only until they
+    become empty.  */
+ 
+ Lisp_Object Vresize_mini_windows;
+ 
+ /* Buffer being redisplayed -- for redisplay_window_error.  */
+ 
+ struct buffer *displayed_buffer;
+ 
+ /* Value returned from text property handlers (see below).  */
+ 
+ enum prop_handled
+ {
+   HANDLED_NORMALLY,
+   HANDLED_RECOMPUTE_PROPS,
+   HANDLED_OVERLAY_STRING_CONSUMED,
+   HANDLED_RETURN
+ };
+ 
+ /* A description of text properties that redisplay is interested
+    in.  */
+ 
+ struct props
+ {
+   /* The name of the property.  */
+   Lisp_Object *name;
+ 
+   /* A unique index for the property.  */
+   enum prop_idx idx;
+ 
+   /* A handler function called to set up iterator IT from the property
+      at IT's current position.  Value is used to steer handle_stop.  */
+   enum prop_handled (*handler) P_ ((struct it *it));
+ };
+ 
+ static enum prop_handled handle_face_prop P_ ((struct it *));
+ static enum prop_handled handle_invisible_prop P_ ((struct it *));
+ static enum prop_handled handle_display_prop P_ ((struct it *));
+ static enum prop_handled handle_composition_prop P_ ((struct it *));
+ static enum prop_handled handle_overlay_change P_ ((struct it *));
+ static enum prop_handled handle_fontified_prop P_ ((struct it *));
+ static enum prop_handled handle_auto_composed_prop P_ ((struct it *));
+ 
+ /* Properties handled by iterators.  */
+ 
+ static struct props it_props[] =
+ {
+   {&Qauto_composed,   AUTO_COMPOSED_PROP_IDX, handle_auto_composed_prop},
+   {&Qfontified,               FONTIFIED_PROP_IDX,     handle_fontified_prop},
+   /* Handle `face' before `display' because some sub-properties of
+      `display' need to know the face.  */
+   {&Qface,            FACE_PROP_IDX,          handle_face_prop},
+   {&Qdisplay,         DISPLAY_PROP_IDX,       handle_display_prop},
+   {&Qinvisible,               INVISIBLE_PROP_IDX,     handle_invisible_prop},
+   {&Qcomposition,     COMPOSITION_PROP_IDX,   handle_composition_prop},
+   {NULL,              0,                      NULL}
+ };
+ 
+ /* Value is the position described by X.  If X is a marker, value is
+    the marker_position of X.  Otherwise, value is X.  */
+ 
+ #define COERCE_MARKER(X) (MARKERP ((X)) ? Fmarker_position (X) : (X))
+ 
+ /* Enumeration returned by some move_it_.* functions internally.  */
+ 
+ enum move_it_result
+ {
+   /* Not used.  Undefined value.  */
+   MOVE_UNDEFINED,
+ 
+   /* Move ended at the requested buffer position or ZV.  */
+   MOVE_POS_MATCH_OR_ZV,
+ 
+   /* Move ended at the requested X pixel position.  */
+   MOVE_X_REACHED,
+ 
+   /* Move within a line ended at the end of a line that must be
+      continued.  */
+   MOVE_LINE_CONTINUED,
+ 
+   /* Move within a line ended at the end of a line that would
+      be displayed truncated.  */
+   MOVE_LINE_TRUNCATED,
+ 
+   /* Move within a line ended at a line end.  */
+   MOVE_NEWLINE_OR_CR
+ };
+ 
+ /* This counter is used to clear the face cache every once in a while
+    in redisplay_internal.  It is incremented for each redisplay.
+    Every CLEAR_FACE_CACHE_COUNT full redisplays, the face cache is
+    cleared.  */
+ 
+ #define CLEAR_FACE_CACHE_COUNT        500
+ static int clear_face_cache_count;
+ 
+ /* Record the previous terminal frame we displayed.  */
+ 
+ static struct frame *previous_terminal_frame;
+ 
+ /* Non-zero while redisplay_internal is in progress.  */
+ 
+ int redisplaying_p;
+ 
+ /* Non-zero means don't free realized faces.  Bound while freeing
+    realized faces is dangerous because glyph matrices might still
+    reference them.  */
+ 
+ int inhibit_free_realized_faces;
+ Lisp_Object Qinhibit_free_realized_faces;
+ 
+ /* If a string, XTread_socket generates an event to display that string.
+    (The display is done in read_char.)  */
+ 
+ Lisp_Object help_echo_string;
+ Lisp_Object help_echo_window;
+ Lisp_Object help_echo_object;
+ int help_echo_pos;
+ 
+ /* Temporary variable for XTread_socket.  */
+ 
+ Lisp_Object previous_help_echo_string;
+ 
+ 
+ 
+ /* Function prototypes.  */
+ 
+ static void setup_for_ellipsis P_ ((struct it *));
+ static void mark_window_display_accurate_1 P_ ((struct window *, int));
+ static int single_display_prop_string_p P_ ((Lisp_Object, Lisp_Object));
+ static int display_prop_string_p P_ ((Lisp_Object, Lisp_Object));
+ static int cursor_row_p P_ ((struct window *, struct glyph_row *));
+ static int redisplay_mode_lines P_ ((Lisp_Object, int));
+ static char *decode_mode_spec_coding P_ ((Lisp_Object, char *, int));
+ 
+ #if 0
+ static int invisible_text_between_p P_ ((struct it *, int, int));
+ #endif
+ 
+ static int next_element_from_ellipsis P_ ((struct it *));
+ static void pint2str P_ ((char *, int, int));
+ 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 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 single_display_prop_intangible_p P_ ((Lisp_Object));
+ static void ensure_echo_area_buffers P_ ((void));
+ static Lisp_Object unwind_with_echo_area_buffer P_ ((Lisp_Object));
+ static Lisp_Object with_echo_area_buffer_unwind_data P_ ((struct window *));
+ static int with_echo_area_buffer P_ ((struct window *, int,
+                                     int (*) (EMACS_INT, Lisp_Object, 
EMACS_INT, EMACS_INT),
+                                     EMACS_INT, Lisp_Object, EMACS_INT, 
EMACS_INT));
+ static void clear_garbaged_frames P_ ((void));
+ static int current_message_1 P_ ((EMACS_INT, Lisp_Object, EMACS_INT, 
EMACS_INT));
+ static int truncate_message_1 P_ ((EMACS_INT, Lisp_Object, EMACS_INT, 
EMACS_INT));
+ static int set_message_1 P_ ((EMACS_INT, Lisp_Object, EMACS_INT, EMACS_INT));
+ static int display_echo_area P_ ((struct window *));
+ static int display_echo_area_1 P_ ((EMACS_INT, Lisp_Object, EMACS_INT, 
EMACS_INT));
+ static int resize_mini_window_1 P_ ((EMACS_INT, Lisp_Object, EMACS_INT, 
EMACS_INT));
+ static Lisp_Object unwind_redisplay P_ ((Lisp_Object));
+ static int string_char_and_length P_ ((const unsigned char *, int, int *));
+ static struct text_pos display_prop_end P_ ((struct it *, Lisp_Object,
+                                            struct text_pos));
+ static int compute_window_start_on_continuation_line P_ ((struct window *));
+ static Lisp_Object safe_eval_handler P_ ((Lisp_Object));
+ static void insert_left_trunc_glyphs P_ ((struct it *));
+ static struct glyph_row *get_overlay_arrow_glyph_row P_ ((struct window *));
+ static void extend_face_to_end_of_line P_ ((struct it *));
+ static int append_space P_ ((struct it *, int));
+ static int make_cursor_line_fully_visible P_ ((struct window *));
+ static int try_scrolling P_ ((Lisp_Object, int, EMACS_INT, EMACS_INT, int, 
int));
+ static int try_cursor_movement P_ ((Lisp_Object, struct text_pos, int *));
+ static int trailing_whitespace_p P_ ((int));
+ static int message_log_check_duplicate P_ ((int, int, int, int));
+ static void push_it P_ ((struct it *));
+ static void pop_it P_ ((struct it *));
+ static void sync_frame_with_window_matrix_rows P_ ((struct window *));
+ static void redisplay_internal P_ ((int));
+ static int echo_area_display P_ ((int));
+ static void redisplay_windows P_ ((Lisp_Object));
+ static void redisplay_window P_ ((Lisp_Object, int));
+ static Lisp_Object redisplay_window_error ();
+ static Lisp_Object redisplay_window_0 P_ ((Lisp_Object));
+ static Lisp_Object redisplay_window_1 P_ ((Lisp_Object));
+ static void update_menu_bar P_ ((struct frame *, int));
+ static int try_window_reusing_current_matrix P_ ((struct window *));
+ static int try_window_id P_ ((struct window *));
+ static int display_line P_ ((struct it *));
+ static int display_mode_lines P_ ((struct window *));
+ static int display_mode_line P_ ((struct window *, enum face_id, 
Lisp_Object));
+ static int display_mode_element P_ ((struct it *, int, int, int, Lisp_Object, 
Lisp_Object, int));
+ static int store_mode_line_string P_ ((char *, Lisp_Object, int, int, int, 
Lisp_Object));
+ static char *decode_mode_spec P_ ((struct window *, int, int, int, int *));
+ static void display_menu_bar P_ ((struct window *));
+ static int display_count_lines P_ ((int, int, int, int, int *));
+ static int display_string P_ ((unsigned char *, Lisp_Object, Lisp_Object,
+                              int, int, struct it *, int, int, int, int));
+ static void compute_line_metrics P_ ((struct it *));
+ static void run_redisplay_end_trigger_hook P_ ((struct it *));
+ static int get_overlay_strings P_ ((struct it *, int));
+ static void next_overlay_string P_ ((struct it *));
+ static void reseat P_ ((struct it *, struct text_pos, int));
+ static void reseat_1 P_ ((struct it *, struct text_pos, int));
+ static void back_to_previous_visible_line_start P_ ((struct it *));
+ static void reseat_at_previous_visible_line_start P_ ((struct it *));
+ static void reseat_at_next_visible_line_start P_ ((struct it *, int));
+ static int next_element_from_display_vector P_ ((struct it *));
+ static int next_element_from_string P_ ((struct it *));
+ static int next_element_from_c_string P_ ((struct it *));
+ static int next_element_from_buffer P_ ((struct it *));
+ static int next_element_from_composition P_ ((struct it *));
+ static int next_element_from_image P_ ((struct it *));
+ static int next_element_from_stretch P_ ((struct it *));
+ static void load_overlay_strings P_ ((struct it *, int));
+ static int init_from_display_pos P_ ((struct it *, struct window *,
+                                     struct display_pos *));
+ static void reseat_to_string P_ ((struct it *, unsigned char *,
+                                 Lisp_Object, int, int, int, int));
+ static enum move_it_result move_it_in_display_line_to P_ ((struct it *,
+                                                          int, int, int));
+ void move_it_vertically_backward P_ ((struct it *, int));
+ static void init_to_row_start P_ ((struct it *, struct window *,
+                                  struct glyph_row *));
+ static int init_to_row_end P_ ((struct it *, struct window *,
+                               struct glyph_row *));
+ static void back_to_previous_line_start P_ ((struct it *));
+ static int forward_to_next_line_start P_ ((struct it *, int *));
+ static struct text_pos string_pos_nchars_ahead P_ ((struct text_pos,
+                                                   Lisp_Object, int));
+ static struct text_pos string_pos P_ ((int, Lisp_Object));
+ static struct text_pos c_string_pos P_ ((int, unsigned char *, int));
+ static int number_of_chars P_ ((unsigned char *, int));
+ static void compute_stop_pos P_ ((struct it *));
+ static void compute_string_pos P_ ((struct text_pos *, struct text_pos,
+                                   Lisp_Object));
+ static int face_before_or_after_it_pos P_ ((struct it *, int));
+ static int next_overlay_change P_ ((int));
+ static int handle_single_display_prop P_ ((struct it *, Lisp_Object,
+                                          Lisp_Object, struct text_pos *,
+                                          int));
+ static int underlying_face_id P_ ((struct it *));
+ static int in_ellipses_for_invisible_text_p P_ ((struct display_pos *,
+                                                struct window *));
+ 
+ #define face_before_it_pos(IT) face_before_or_after_it_pos ((IT), 1)
+ #define face_after_it_pos(IT)  face_before_or_after_it_pos ((IT), 0)
+ 
+ #ifdef HAVE_WINDOW_SYSTEM
+ 
+ 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 notice_overwritten_cursor P_ ((struct window *,
+                                          enum glyph_row_area,
+                                          int, int, int, int));
+ 
+ 
+ 
+ #endif /* HAVE_WINDOW_SYSTEM */
+ 
+ 
+ /***********************************************************************
+                     Window display dimensions
+  ***********************************************************************/
+ 
+ /* Return the bottom boundary y-position for text lines in window W.
+    This is the first y position at which a line cannot start.
+    It is relative to the top of the window.
+ 
+    This is the height of W minus the height of a mode line, if any.  */
+ 
+ INLINE int
+ window_text_bottom_y (w)
+      struct window *w;
+ {
+   int height = WINDOW_TOTAL_HEIGHT (w);
+ 
+   if (WINDOW_WANTS_MODELINE_P (w))
+     height -= CURRENT_MODE_LINE_HEIGHT (w);
+   return height;
+ }
+ 
+ /* Return the pixel width of display area AREA of window W.  AREA < 0
+    means return the total width of W, not including fringes to
+    the left and right of the window.  */
+ 
+ INLINE int
+ window_box_width (w, area)
+      struct window *w;
+      int area;
+ {
+   int cols = XFASTINT (w->total_cols);
+   int pixels = 0;
+ 
+   if (!w->pseudo_window_p)
+     {
+       cols -= WINDOW_SCROLL_BAR_COLS (w);
+ 
+       if (area == TEXT_AREA)
+       {
+         if (INTEGERP (w->left_margin_cols))
+           cols -= XFASTINT (w->left_margin_cols);
+         if (INTEGERP (w->right_margin_cols))
+           cols -= XFASTINT (w->right_margin_cols);
+         pixels = -WINDOW_TOTAL_FRINGE_WIDTH (w);
+       }
+       else if (area == LEFT_MARGIN_AREA)
+       {
+         cols = (INTEGERP (w->left_margin_cols)
+                  ? XFASTINT (w->left_margin_cols) : 0);
+         pixels = 0;
+       }
+       else if (area == RIGHT_MARGIN_AREA)
+       {
+         cols = (INTEGERP (w->right_margin_cols)
+                  ? XFASTINT (w->right_margin_cols) : 0);
+         pixels = 0;
+       }
+     }
+ 
+   return cols * WINDOW_FRAME_COLUMN_WIDTH (w) + pixels;
+ }
+ 
+ 
+ /* Return the pixel height of the display area of window W, not
+    including mode lines of W, if any.  */
+ 
+ INLINE int
+ window_box_height (w)
+      struct window *w;
+ {
+   struct frame *f = XFRAME (w->frame);
+   int height = WINDOW_TOTAL_HEIGHT (w);
+ 
+   xassert (height >= 0);
+ 
+   /* Note: the code below that determines the mode-line/header-line
+      height is essentially the same as that contained in the macro
+      CURRENT_{MODE,HEADER}_LINE_HEIGHT, except that it checks whether
+      the appropriate glyph row has its `mode_line_p' flag set,
+      and if it doesn't, uses estimate_mode_line_height instead.  */
+ 
+   if (WINDOW_WANTS_MODELINE_P (w))
+     {
+       struct glyph_row *ml_row
+       = (w->current_matrix && w->current_matrix->rows
+          ? MATRIX_MODE_LINE_ROW (w->current_matrix)
+          : 0);
+       if (ml_row && ml_row->mode_line_p)
+       height -= ml_row->height;
+       else
+       height -= estimate_mode_line_height (f, CURRENT_MODE_LINE_FACE_ID (w));
+     }
+ 
+   if (WINDOW_WANTS_HEADER_LINE_P (w))
+     {
+       struct glyph_row *hl_row
+       = (w->current_matrix && w->current_matrix->rows
+          ? MATRIX_HEADER_LINE_ROW (w->current_matrix)
+          : 0);
+       if (hl_row && hl_row->mode_line_p)
+       height -= hl_row->height;
+       else
+       height -= estimate_mode_line_height (f, HEADER_LINE_FACE_ID);
+     }
+ 
+   /* With a very small font and a mode-line that's taller than
+      default, we might end up with a negative height.  */
+   return max (0, height);
+ }
+ 
+ /* Return the window-relative coordinate of the left edge of display
+    area AREA of window W.  AREA < 0 means return the left edge of the
+    whole window, to the right of the left fringe of W.  */
+ 
+ INLINE int
+ window_box_left_offset (w, area)
+      struct window *w;
+      int area;
+ {
+   int x;
+ 
+   if (w->pseudo_window_p)
+     return 0;
+ 
+   x = WINDOW_LEFT_SCROLL_BAR_AREA_WIDTH (w);
+ 
+   if (area == TEXT_AREA)
+     x += (WINDOW_LEFT_FRINGE_WIDTH (w)
+         + window_box_width (w, LEFT_MARGIN_AREA));
+   else if (area == RIGHT_MARGIN_AREA)
+     x += (WINDOW_LEFT_FRINGE_WIDTH (w)
+         + window_box_width (w, LEFT_MARGIN_AREA)
+         + window_box_width (w, TEXT_AREA)
+         + (WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (w)
+            ? 0
+            : WINDOW_RIGHT_FRINGE_WIDTH (w)));
+   else if (area == LEFT_MARGIN_AREA
+          && WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (w))
+     x += WINDOW_LEFT_FRINGE_WIDTH (w);
+ 
+   return x;
+ }
+ 
+ 
+ /* Return the window-relative coordinate of the right edge of display
+    area AREA of window W.  AREA < 0 means return the left edge of the
+    whole window, to the left of the right fringe of W.  */
+ 
+ INLINE int
+ window_box_right_offset (w, area)
+      struct window *w;
+      int area;
+ {
+   return window_box_left_offset (w, area) + window_box_width (w, area);
+ }
+ 
+ /* Return the frame-relative coordinate of the left edge of display
+    area AREA of window W.  AREA < 0 means return the left edge of the
+    whole window, to the right of the left fringe of W.  */
+ 
+ INLINE int
+ window_box_left (w, area)
+      struct window *w;
+      int area;
+ {
+   struct frame *f = XFRAME (w->frame);
+   int x;
+ 
+   if (w->pseudo_window_p)
+     return FRAME_INTERNAL_BORDER_WIDTH (f);
+ 
+   x = (WINDOW_LEFT_EDGE_X (w)
+        + window_box_left_offset (w, area));
+ 
+   return x;
+ }
+ 
+ 
+ /* Return the frame-relative coordinate of the right edge of display
+    area AREA of window W.  AREA < 0 means return the left edge of the
+    whole window, to the left of the right fringe of W.  */
+ 
+ INLINE int
+ window_box_right (w, area)
+      struct window *w;
+      int area;
+ {
+   return window_box_left (w, area) + window_box_width (w, area);
+ }
+ 
+ /* Get the bounding box of the display area AREA of window W, without
+    mode lines, in frame-relative coordinates.  AREA < 0 means the
+    whole window, not including the left and right fringes of
+    the window.  Return in *BOX_X and *BOX_Y the frame-relative pixel
+    coordinates of the upper-left corner of the box.  Return in
+    *BOX_WIDTH, and *BOX_HEIGHT the pixel width and height of the box.  */
+ 
+ INLINE void
+ window_box (w, area, box_x, box_y, box_width, box_height)
+      struct window *w;
+      int area;
+      int *box_x, *box_y, *box_width, *box_height;
+ {
+   if (box_width)
+     *box_width = window_box_width (w, area);
+   if (box_height)
+     *box_height = window_box_height (w);
+   if (box_x)
+     *box_x = window_box_left (w, area);
+   if (box_y)
+     {
+       *box_y = WINDOW_TOP_EDGE_Y (w);
+       if (WINDOW_WANTS_HEADER_LINE_P (w))
+       *box_y += CURRENT_HEADER_LINE_HEIGHT (w);
+     }
+ }
+ 
+ 
+ /* Get the bounding box of the display area AREA of window W, without
+    mode lines.  AREA < 0 means the whole window, not including the
+    left and right fringe of the window.  Return in *TOP_LEFT_X
+    and TOP_LEFT_Y the frame-relative pixel coordinates of the
+    upper-left corner of the box.  Return in *BOTTOM_RIGHT_X, and
+    *BOTTOM_RIGHT_Y the coordinates of the bottom-right corner of the
+    box.  */
+ 
+ INLINE void
+ window_box_edges (w, area, top_left_x, top_left_y,
+                 bottom_right_x, bottom_right_y)
+      struct window *w;
+      int area;
+      int *top_left_x, *top_left_y, *bottom_right_x, *bottom_right_y;
+ {
+   window_box (w, area, top_left_x, top_left_y, bottom_right_x,
+             bottom_right_y);
+   *bottom_right_x += *top_left_x;
+   *bottom_right_y += *top_left_y;
+ }
+ 
+ 
+ 
+ /***********************************************************************
+                             Utilities
+  ***********************************************************************/
+ 
+ /* Return the bottom y-position of the line the iterator IT is in.
+    This can modify IT's settings.  */
+ 
+ int
+ line_bottom_y (it)
+      struct it *it;
+ {
+   int line_height = it->max_ascent + it->max_descent;
+   int line_top_y = it->current_y;
+ 
+   if (line_height == 0)
+     {
+       if (last_height)
+       line_height = last_height;
+       else if (IT_CHARPOS (*it) < ZV)
+       {
+         move_it_by_lines (it, 1, 1);
+         line_height = (it->max_ascent || it->max_descent
+                        ? it->max_ascent + it->max_descent
+                        : last_height);
+       }
+       else
+       {
+         struct glyph_row *row = it->glyph_row;
+ 
+         /* Use the default character height.  */
+         it->glyph_row = NULL;
+         it->what = IT_CHARACTER;
+         it->c = ' ';
+         it->len = 1;
+         PRODUCE_GLYPHS (it);
+         line_height = it->ascent + it->descent;
+         it->glyph_row = row;
+       }
+     }
+ 
+   return line_top_y + line_height;
+ }
+ 
+ 
+ /* Return 1 if position CHARPOS is visible in window W.  Set *FULLY to
+    1 if POS is visible and the line containing POS is fully visible.
+    EXACT_MODE_LINE_HEIGHTS_P non-zero means compute exact mode-line
+    and header-lines heights.  */
+ 
+ int
+ pos_visible_p (w, charpos, fully, exact_mode_line_heights_p)
+      struct window *w;
+      int charpos, *fully, exact_mode_line_heights_p;
+ {
+   struct it it;
+   struct text_pos top;
+   int visible_p;
+   struct buffer *old_buffer = NULL;
+ 
+   if (XBUFFER (w->buffer) != current_buffer)
+     {
+       old_buffer = current_buffer;
+       set_buffer_internal_1 (XBUFFER (w->buffer));
+     }
+ 
+   *fully = visible_p = 0;
+   SET_TEXT_POS_FROM_MARKER (top, w->start);
+ 
+   /* Compute exact mode line heights, if requested.  */
+   if (exact_mode_line_heights_p)
+     {
+       if (WINDOW_WANTS_MODELINE_P (w))
+       current_mode_line_height
+         = display_mode_line (w, CURRENT_MODE_LINE_FACE_ID (w),
+                              current_buffer->mode_line_format);
+ 
+       if (WINDOW_WANTS_HEADER_LINE_P (w))
+       current_header_line_height
+         = display_mode_line (w, HEADER_LINE_FACE_ID,
+                              current_buffer->header_line_format);
+     }
+ 
+   start_display (&it, w, top);
+   move_it_to (&it, charpos, 0, it.last_visible_y, -1,
+             MOVE_TO_POS | MOVE_TO_X | MOVE_TO_Y);
+ 
+   /* Note that we may overshoot because of invisible text.  */
+   if (IT_CHARPOS (it) >= charpos)
+     {
+       int top_y = it.current_y;
+       int bottom_y = line_bottom_y (&it);
+       int window_top_y = WINDOW_HEADER_LINE_HEIGHT (w);
+ 
+       if (top_y < window_top_y)
+       visible_p = bottom_y > window_top_y;
+       else if (top_y < it.last_visible_y)
+       {
+         visible_p = 1;
+         *fully = bottom_y <= it.last_visible_y;
+       }
+     }
+   else if (it.current_y + it.max_ascent + it.max_descent > it.last_visible_y)
+     {
+       move_it_by_lines (&it, 1, 0);
+       if (charpos < IT_CHARPOS (it))
+       {
+         visible_p = 1;
+         *fully  = 0;
+       }
+     }
+ 
+   if (old_buffer)
+     set_buffer_internal_1 (old_buffer);
+ 
+   current_header_line_height = current_mode_line_height = -1;
+   return visible_p;
+ }
+ 
+ 
+ /* Return the next character from STR which is MAXLEN bytes long.
+    Return in *LEN the length of the character.  This is like
+    STRING_CHAR_AND_LENGTH but never returns an invalid character.  If
+    we find one, we return a `?', but with the length of the invalid
+    character.  */
+ 
+ static INLINE int
+ string_char_and_length (str, maxlen, len)
+      const unsigned char *str;
+      int maxlen, *len;
+ {
+   int c;
+ 
+   c = STRING_CHAR_AND_LENGTH (str, maxlen, *len);
+   if (!CHAR_VALID_P (c, 1))
+     /* We may not change the length here because other places in Emacs
+        don't use this function, i.e. they silently accept invalid
+        characters.  */
+     c = '?';
+ 
+   return c;
+ }
+ 
+ 
+ 
+ /* Given a position POS containing a valid character and byte position
+    in STRING, return the position NCHARS ahead (NCHARS >= 0).  */
+ 
+ static struct text_pos
+ string_pos_nchars_ahead (pos, string, nchars)
+      struct text_pos pos;
+      Lisp_Object string;
+      int nchars;
+ {
+   xassert (STRINGP (string) && nchars >= 0);
+ 
+   if (STRING_MULTIBYTE (string))
+     {
+       int rest = SBYTES (string) - BYTEPOS (pos);
+       const unsigned char *p = SDATA (string) + BYTEPOS (pos);
+       int len;
+ 
+       while (nchars--)
+       {
+         string_char_and_length (p, rest, &len);
+         p += len, rest -= len;
+         xassert (rest >= 0);
+         CHARPOS (pos) += 1;
+         BYTEPOS (pos) += len;
+       }
+     }
+   else
+     SET_TEXT_POS (pos, CHARPOS (pos) + nchars, BYTEPOS (pos) + nchars);
+ 
+   return pos;
+ }
+ 
+ 
+ /* Value is the text position, i.e. character and byte position,
+    for character position CHARPOS in STRING.  */
+ 
+ static INLINE struct text_pos
+ string_pos (charpos, string)
+      int charpos;
+      Lisp_Object string;
+ {
+   struct text_pos pos;
+   xassert (STRINGP (string));
+   xassert (charpos >= 0);
+   SET_TEXT_POS (pos, charpos, string_char_to_byte (string, charpos));
+   return pos;
+ }
+ 
+ 
+ /* Value is a text position, i.e. character and byte position, for
+    character position CHARPOS in C string S.  MULTIBYTE_P non-zero
+    means recognize multibyte characters.  */
+ 
+ static struct text_pos
+ c_string_pos (charpos, s, multibyte_p)
+      int charpos;
+      unsigned char *s;
+      int multibyte_p;
+ {
+   struct text_pos pos;
+ 
+   xassert (s != NULL);
+   xassert (charpos >= 0);
+ 
+   if (multibyte_p)
+     {
+       int rest = strlen (s), len;
+ 
+       SET_TEXT_POS (pos, 0, 0);
+       while (charpos--)
+       {
+         string_char_and_length (s, rest, &len);
+         s += len, rest -= len;
+         xassert (rest >= 0);
+         CHARPOS (pos) += 1;
+         BYTEPOS (pos) += len;
+       }
+     }
+   else
+     SET_TEXT_POS (pos, charpos, charpos);
+ 
+   return pos;
+ }
+ 
+ 
+ /* Value is the number of characters in C string S.  MULTIBYTE_P
+    non-zero means recognize multibyte characters.  */
+ 
+ static int
+ number_of_chars (s, multibyte_p)
+      unsigned char *s;
+      int multibyte_p;
+ {
+   int nchars;
+ 
+   if (multibyte_p)
+     {
+       int rest = strlen (s), len;
+       unsigned char *p = (unsigned char *) s;
+ 
+       for (nchars = 0; rest > 0; ++nchars)
+       {
+         string_char_and_length (p, rest, &len);
+         rest -= len, p += len;
+       }
+     }
+   else
+     nchars = strlen (s);
+ 
+   return nchars;
+ }
+ 
+ 
+ /* Compute byte position NEWPOS->bytepos corresponding to
+    NEWPOS->charpos.  POS is a known position in string STRING.
+    NEWPOS->charpos must be >= POS.charpos.  */
+ 
+ static void
+ compute_string_pos (newpos, pos, string)
+      struct text_pos *newpos, pos;
+      Lisp_Object string;
+ {
+   xassert (STRINGP (string));
+   xassert (CHARPOS (*newpos) >= CHARPOS (pos));
+ 
+   if (STRING_MULTIBYTE (string))
+     *newpos = string_pos_nchars_ahead (pos, string,
+                                      CHARPOS (*newpos) - CHARPOS (pos));
+   else
+     BYTEPOS (*newpos) = CHARPOS (*newpos);
+ }
+ 
+ /* EXPORT:
+    Return an estimation of the pixel height of mode or top lines on
+    frame F.  FACE_ID specifies what line's height to estimate.  */
+ 
+ int
+ estimate_mode_line_height (f, face_id)
+      struct frame *f;
+      enum face_id face_id;
+ {
+ #ifdef HAVE_WINDOW_SYSTEM
+   if (FRAME_WINDOW_P (f))
+     {
+       int height = FONT_HEIGHT (FRAME_FONT (f));
+ 
+       /* This function is called so early when Emacs starts that the face
+        cache and mode line face are not yet initialized.  */
+       if (FRAME_FACE_CACHE (f))
+       {
+         struct face *face = FACE_FROM_ID (f, face_id);
+         if (face)
+           {
+             if (face->font)
+               height = FONT_HEIGHT (face->font);
+             if (face->box_line_width > 0)
+               height += 2 * face->box_line_width;
+           }
+       }
+ 
+       return height;
+     }
+ #endif
+ 
+   return 1;
+ }
+ 
+ /* Given a pixel position (PIX_X, PIX_Y) on frame F, return glyph
+    co-ordinates in (*X, *Y).  Set *BOUNDS to the rectangle that the
+    glyph at X, Y occupies, if BOUNDS != 0.  If NOCLIP is non-zero, do
+    not force the value into range.  */
+ 
+ void
+ pixel_to_glyph_coords (f, pix_x, pix_y, x, y, bounds, noclip)
+      FRAME_PTR f;
+      register int pix_x, pix_y;
+      int *x, *y;
+      NativeRectangle *bounds;
+      int noclip;
+ {
+ 
+ #ifdef HAVE_WINDOW_SYSTEM
+   if (FRAME_WINDOW_P (f))
+     {
+       /* Arrange for the division in FRAME_PIXEL_X_TO_COL etc. to round down
+        even for negative values.  */
+       if (pix_x < 0)
+       pix_x -= FRAME_COLUMN_WIDTH (f) - 1;
+       if (pix_y < 0)
+       pix_y -= FRAME_LINE_HEIGHT (f) - 1;
+ 
+       pix_x = FRAME_PIXEL_X_TO_COL (f, pix_x);
+       pix_y = FRAME_PIXEL_Y_TO_LINE (f, pix_y);
+ 
+       if (bounds)
+       STORE_NATIVE_RECT (*bounds,
+                          FRAME_COL_TO_PIXEL_X (f, pix_x),
+                          FRAME_LINE_TO_PIXEL_Y (f, pix_y),
+                          FRAME_COLUMN_WIDTH (f) - 1,
+                          FRAME_LINE_HEIGHT (f) - 1);
+ 
+       if (!noclip)
+       {
+         if (pix_x < 0)
+           pix_x = 0;
+         else if (pix_x > FRAME_TOTAL_COLS (f))
+           pix_x = FRAME_TOTAL_COLS (f);
+ 
+         if (pix_y < 0)
+           pix_y = 0;
+         else if (pix_y > FRAME_LINES (f))
+           pix_y = FRAME_LINES (f);
+       }
+     }
+ #endif
+ 
+   *x = pix_x;
+   *y = pix_y;
+ }
+ 
+ 
+ /* Given HPOS/VPOS in the current matrix of W, return corresponding
+    frame-relative pixel positions in *FRAME_X and *FRAME_Y.  If we
+    can't tell the positions because W's display is not up to date,
+    return 0.  */
+ 
+ int
+ glyph_to_pixel_coords (w, hpos, vpos, frame_x, frame_y)
+      struct window *w;
+      int hpos, vpos;
+      int *frame_x, *frame_y;
+ {
+ #ifdef HAVE_WINDOW_SYSTEM
+   if (FRAME_WINDOW_P (XFRAME (WINDOW_FRAME (w))))
+     {
+       int success_p;
+ 
+       xassert (hpos >= 0 && hpos < w->current_matrix->matrix_w);
+       xassert (vpos >= 0 && vpos < w->current_matrix->matrix_h);
+ 
+       if (display_completed)
+       {
+         struct glyph_row *row = MATRIX_ROW (w->current_matrix, vpos);
+         struct glyph *glyph = row->glyphs[TEXT_AREA];
+         struct glyph *end = glyph + min (hpos, row->used[TEXT_AREA]);
+ 
+         hpos = row->x;
+         vpos = row->y;
+         while (glyph < end)
+           {
+             hpos += glyph->pixel_width;
+             ++glyph;
+           }
+ 
+         success_p = 1;
+       }
+       else
+       {
+         hpos = vpos = 0;
+         success_p = 0;
+       }
+ 
+       *frame_x = WINDOW_TO_FRAME_PIXEL_X (w, hpos);
+       *frame_y = WINDOW_TO_FRAME_PIXEL_Y (w, vpos);
+       return success_p;
+     }
+ #endif
+ 
+   *frame_x = hpos;
+   *frame_y = vpos;
+   return 1;
+ }
+ 
+ 
+ #ifdef HAVE_WINDOW_SYSTEM
+ 
+ /* Find the glyph under window-relative coordinates X/Y in window W.
+    Consider only glyphs from buffer text, i.e. no glyphs from overlay
+    strings.  Return in *HPOS and *VPOS the row and column number of
+    the glyph found.  Return in *AREA the glyph area containing X.
+    Value is a pointer to the glyph found or null if X/Y is not on
+    text, or we can't tell because W's current matrix is not up to
+    date.  */
+ 
+ static struct glyph *
+ x_y_to_hpos_vpos (w, x, y, hpos, vpos, area, buffer_only_p)
+      struct window *w;
+      int x, y;
+      int *hpos, *vpos, *area;
+      int buffer_only_p;
+ {
+   struct glyph *glyph, *end;
+   struct glyph_row *row = NULL;
+   int x0, i;
+ 
+   /* Find row containing Y.  Give up if some row is not enabled.  */
+   for (i = 0; i < w->current_matrix->nrows; ++i)
+     {
+       row = MATRIX_ROW (w->current_matrix, i);
+       if (!row->enabled_p)
+       return NULL;
+       if (y >= row->y && y < MATRIX_ROW_BOTTOM_Y (row))
+       break;
+     }
+ 
+   *vpos = i;
+   *hpos = 0;
+ 
+   /* Give up if Y is not in the window.  */
+   if (i == w->current_matrix->nrows)
+     return NULL;
+ 
+   /* Get the glyph area containing X.  */
+   if (w->pseudo_window_p)
+     {
+       *area = TEXT_AREA;
+       x0 = 0;
+     }
+   else
+     {
+       if (x < window_box_left_offset (w, TEXT_AREA))
+       {
+         *area = LEFT_MARGIN_AREA;
+         x0 = window_box_left_offset (w, LEFT_MARGIN_AREA);
+       }
+       else if (x < window_box_right_offset (w, TEXT_AREA))
+       {
+         *area = TEXT_AREA;
+         x0 = window_box_left_offset (w, TEXT_AREA);
+       }
+       else
+       {
+         *area = RIGHT_MARGIN_AREA;
+         x0 = window_box_left_offset (w, RIGHT_MARGIN_AREA);
+       }
+     }
+ 
+   /* Find glyph containing X.  */
+   glyph = row->glyphs[*area];
+   end = glyph + row->used[*area];
+   while (glyph < end)
+     {
+       if (x < x0 + glyph->pixel_width)
+       {
+         if (w->pseudo_window_p)
+           break;
+         else if (!buffer_only_p || BUFFERP (glyph->object))
+           break;
+       }
+ 
+       x0 += glyph->pixel_width;
+       ++glyph;
+     }
+ 
+   if (glyph == end)
+     return NULL;
+ 
+   *hpos = glyph - row->glyphs[*area];
+   return glyph;
+ }
+ 
+ 
+ /* EXPORT:
+    Convert frame-relative x/y to coordinates relative to window W.
+    Takes pseudo-windows into account.  */
+ 
+ void
+ frame_to_window_pixel_xy (w, x, y)
+      struct window *w;
+      int *x, *y;
+ {
+   if (w->pseudo_window_p)
+     {
+       /* A pseudo-window is always full-width, and starts at the
+        left edge of the frame, plus a frame border.  */
+       struct frame *f = XFRAME (w->frame);
+       *x -= FRAME_INTERNAL_BORDER_WIDTH (f);
+       *y = FRAME_TO_WINDOW_PIXEL_Y (w, *y);
+     }
+   else
+     {
+       *x -= WINDOW_LEFT_EDGE_X (w);
+       *y = FRAME_TO_WINDOW_PIXEL_Y (w, *y);
+     }
+ }
+ 
+ /* EXPORT:
+    Return in *R the clipping rectangle for glyph string S.  */
+ 
+ void
+ get_glyph_string_clip_rect (s, nr)
+      struct glyph_string *s;
+      NativeRectangle *nr;
+ {
+   XRectangle r;
+ 
+   if (s->row->full_width_p)
+     {
+       /* Draw full-width.  X coordinates are relative to S->w->left_col.  */
+       r.x = WINDOW_LEFT_EDGE_X (s->w);
+       r.width = WINDOW_TOTAL_WIDTH (s->w);
+ 
+       /* Unless displaying a mode or menu bar line, which are always
+        fully visible, clip to the visible part of the row.  */
+       if (s->w->pseudo_window_p)
+       r.height = s->row->visible_height;
+       else
+       r.height = s->height;
+     }
+   else
+     {
+       /* This is a text line that may be partially visible.  */
+       r.x = window_box_left (s->w, s->area);
+       r.width = window_box_width (s->w, s->area);
+       r.height = s->row->visible_height;
+     }
+ 
+   /* 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)
+     {
+       r.y = WINDOW_HEADER_LINE_HEIGHT (s->w);
+       r.height = window_text_bottom_y (s->w) - r.y;
+     }
+   else
+     {
+       /* Don't use S->y for clipping because it doesn't take partially
+        visible lines into account.  For example, it can be negative for
+        partially visible lines at the top of a window.  */
+       if (!s->row->full_width_p
+         && MATRIX_ROW_PARTIALLY_VISIBLE_AT_TOP_P (s->w, s->row))
+       r.y = WINDOW_HEADER_LINE_HEIGHT (s->w);
+       else
+       r.y = max (0, s->row->y);
+ 
+       /* If drawing a tool-bar window, draw it over the internal border
+        at the top of the window.  */
+       if (s->w == XWINDOW (s->f->tool_bar_window))
+       r.y -= FRAME_INTERNAL_BORDER_WIDTH (s->f);
+     }
+ 
+   r.y = WINDOW_TO_FRAME_PIXEL_Y (s->w, r.y);
+ 
+ #ifdef HAVE_NTGUI
+   /* ++KFS: From W32 port, but it looks ok for all platforms to me.  */
+   /* If drawing the cursor, don't let glyph draw outside its
+      advertised boundaries. Cleartype does this under some circumstances.  */
+   if (s->hl == DRAW_CURSOR)
+     {
+       if (s->x > r.x)
+       {
+         r.width -= s->x - r.x;
+         r.x = s->x;
+       }
+       r.width = min (r.width, s->first_glyph->pixel_width);
+     }
+ #endif
+ 
+ #ifdef CONVERT_FROM_XRECT
+   CONVERT_FROM_XRECT (r, *nr);
+ #else
+   *nr = r;
+ #endif
+ }
+ 
+ #endif /* HAVE_WINDOW_SYSTEM */
+ 
+ 
+ /***********************************************************************
+                       Lisp form evaluation
+  ***********************************************************************/
+ 
+ /* Error handler for safe_eval and safe_call.  */
+ 
+ static Lisp_Object
+ safe_eval_handler (arg)
+      Lisp_Object arg;
+ {
+   add_to_log ("Error during redisplay: %s", arg, Qnil);
+   return Qnil;
+ }
+ 
+ 
+ /* Evaluate SEXPR and return the result, or nil if something went
+    wrong.  Prevent redisplay during the evaluation.  */
+ 
+ Lisp_Object
+ safe_eval (sexpr)
+      Lisp_Object sexpr;
+ {
+   Lisp_Object val;
+ 
+   if (inhibit_eval_during_redisplay)
+     val = Qnil;
+   else
+     {
+       int count = SPECPDL_INDEX ();
+       struct gcpro gcpro1;
+ 
+       GCPRO1 (sexpr);
+       specbind (Qinhibit_redisplay, Qt);
+       /* Use Qt to ensure debugger does not run,
+        so there is no possibility of wanting to redisplay.  */
+       val = internal_condition_case_1 (Feval, sexpr, Qt,
+                                      safe_eval_handler);
+       UNGCPRO;
+       val = unbind_to (count, val);
+     }
+ 
+   return val;
+ }
+ 
+ 
+ /* Call function ARGS[0] with arguments ARGS[1] to ARGS[NARGS - 1].
+    Return the result, or nil if something went wrong.  Prevent
+    redisplay during the evaluation.  */
+ 
+ Lisp_Object
+ safe_call (nargs, args)
+      int nargs;
+      Lisp_Object *args;
+ {
+   Lisp_Object val;
+ 
+   if (inhibit_eval_during_redisplay)
+     val = Qnil;
+   else
+     {
+       int count = SPECPDL_INDEX ();
+       struct gcpro gcpro1;
+ 
+       GCPRO1 (args[0]);
+       gcpro1.nvars = nargs;
+       specbind (Qinhibit_redisplay, Qt);
+       /* Use Qt to ensure debugger does not run,
+        so there is no possibility of wanting to redisplay.  */
+       val = internal_condition_case_2 (Ffuncall, nargs, args, Qt,
+                                      safe_eval_handler);
+       UNGCPRO;
+       val = unbind_to (count, val);
+     }
+ 
+   return val;
+ }
+ 
+ 
+ /* Call function FN with one argument ARG.
+    Return the result, or nil if something went wrong.  */
+ 
+ Lisp_Object
+ safe_call1 (fn, arg)
+      Lisp_Object fn, arg;
+ {
+   Lisp_Object args[2];
+   args[0] = fn;
+   args[1] = arg;
+   return safe_call (2, args);
+ }
+ 
+ 
+ 
+ /***********************************************************************
+                             Debugging
+  ***********************************************************************/
+ 
+ #if 0
+ 
+ /* Define CHECK_IT to perform sanity checks on iterators.
+    This is for debugging.  It is too slow to do unconditionally.  */
+ 
+ static void
+ check_it (it)
+      struct it *it;
+ {
+   if (it->method == next_element_from_string)
+     {
+       xassert (STRINGP (it->string));
+       xassert (IT_STRING_CHARPOS (*it) >= 0);
+     }
+   else if (it->method == next_element_from_buffer)
+     {
+       /* Check that character and byte positions agree.  */
+       xassert (IT_CHARPOS (*it) == BYTE_TO_CHAR (IT_BYTEPOS (*it)));
+     }
+ 
+   if (it->dpvec)
+     xassert (it->current.dpvec_index >= 0);
+   else
+     xassert (it->current.dpvec_index < 0);
+ }
+ 
+ #define CHECK_IT(IT)  check_it ((IT))
+ 
+ #else /* not 0 */
+ 
+ #define CHECK_IT(IT)  (void) 0
+ 
+ #endif /* not 0 */
+ 
+ 
+ #if GLYPH_DEBUG
+ 
+ /* Check that the window end of window W is what we expect it
+    to be---the last row in the current matrix displaying text.  */
+ 
+ static void
+ check_window_end (w)
+      struct window *w;
+ {
+   if (!MINI_WINDOW_P (w)
+       && !NILP (w->window_end_valid))
+     {
+       struct glyph_row *row;
+       xassert ((row = MATRIX_ROW (w->current_matrix,
+                                 XFASTINT (w->window_end_vpos)),
+               !row->enabled_p
+               || MATRIX_ROW_DISPLAYS_TEXT_P (row)
+               || MATRIX_ROW_VPOS (row, w->current_matrix) == 0));
+     }
+ }
+ 
+ #define CHECK_WINDOW_END(W)   check_window_end ((W))
+ 
+ #else /* not GLYPH_DEBUG */
+ 
+ #define CHECK_WINDOW_END(W)   (void) 0
+ 
+ #endif /* not GLYPH_DEBUG */
+ 
+ 
+ 
+ /***********************************************************************
+                      Iterator initialization
+  ***********************************************************************/
+ 
+ /* Initialize IT for displaying current_buffer in window W, starting
+    at character position CHARPOS.  CHARPOS < 0 means that no buffer
+    position is specified which is useful when the iterator is assigned
+    a position later.  BYTEPOS is the byte position corresponding to
+    CHARPOS.  BYTEPOS < 0 means compute it from CHARPOS.
+ 
+    If ROW is not null, calls to produce_glyphs with IT as parameter
+    will produce glyphs in that row.
+ 
+    BASE_FACE_ID is the id of a base face to use.  It must be one of
+    DEFAULT_FACE_ID for normal text, MODE_LINE_FACE_ID,
+    MODE_LINE_INACTIVE_FACE_ID, or HEADER_LINE_FACE_ID for displaying
+    mode lines, or TOOL_BAR_FACE_ID for displaying the tool-bar.
+ 
+    If ROW is null and BASE_FACE_ID is equal to MODE_LINE_FACE_ID,
+    MODE_LINE_INACTIVE_FACE_ID, or HEADER_LINE_FACE_ID, the iterator
+    will be initialized to use the corresponding mode line glyph row of
+    the desired matrix of W.  */
+ 
+ void
+ init_iterator (it, w, charpos, bytepos, row, base_face_id)
+      struct it *it;
+      struct window *w;
+      int charpos, bytepos;
+      struct glyph_row *row;
+      enum face_id base_face_id;
+ {
+   int highlight_region_p;
+ 
+   /* Some precondition checks.  */
+   xassert (w != NULL && it != NULL);
+   xassert (charpos < 0 || (charpos >= BUF_BEG (current_buffer)
+                          && charpos <= ZV));
+ 
+   /* If face attributes have been changed since the last redisplay,
+      free realized faces now because they depend on face definitions
+      that might have changed.  Don't free faces while there might be
+      desired matrices pending which reference these faces.  */
+   if (face_change_count && !inhibit_free_realized_faces)
+     {
+       face_change_count = 0;
+       free_all_realized_faces (Qnil);
+     }
+ 
+   /* Use one of the mode line rows of W's desired matrix if
+      appropriate.  */
+   if (row == NULL)
+     {
+       if (base_face_id == MODE_LINE_FACE_ID
+         || base_face_id == MODE_LINE_INACTIVE_FACE_ID)
+       row = MATRIX_MODE_LINE_ROW (w->desired_matrix);
+       else if (base_face_id == HEADER_LINE_FACE_ID)
+       row = MATRIX_HEADER_LINE_ROW (w->desired_matrix);
+     }
+ 
+   /* Clear IT.  */
+   bzero (it, sizeof *it);
+   it->current.overlay_string_index = -1;
+   it->current.dpvec_index = -1;
+   it->base_face_id = base_face_id;
+ 
+   /* The window in which we iterate over current_buffer:  */
+   XSETWINDOW (it->window, w);
+   it->w = w;
+   it->f = XFRAME (w->frame);
+ 
+   /* Extra space between lines (on window systems only).  */
+   if (base_face_id == DEFAULT_FACE_ID
+       && FRAME_WINDOW_P (it->f))
+     {
+       if (NATNUMP (current_buffer->extra_line_spacing))
+       it->extra_line_spacing = XFASTINT (current_buffer->extra_line_spacing);
+       else if (it->f->extra_line_spacing > 0)
+       it->extra_line_spacing = it->f->extra_line_spacing;
+     }
+ 
+   /* If realized faces have been removed, e.g. because of face
+      attribute changes of named faces, recompute them.  When running
+      in batch mode, the face cache of Vterminal_frame is null.  If
+      we happen to get called, make a dummy face cache.  */
+   if (
+ #ifndef WINDOWSNT
+       noninteractive &&
+ #endif
+       FRAME_FACE_CACHE (it->f) == NULL)
+     init_frame_faces (it->f);
+   if (FRAME_FACE_CACHE (it->f)->used == 0)
+     recompute_basic_faces (it->f);
+ 
+   /* Current value of the `space-width', and 'height' properties.  */
+   it->space_width = Qnil;
+   it->font_height = Qnil;
+ 
+   /* Are control characters displayed as `^C'?  */
+   it->ctl_arrow_p = !NILP (current_buffer->ctl_arrow);
+ 
+   /* -1 means everything between a CR and the following line end
+      is invisible.  >0 means lines indented more than this value are
+      invisible.  */
+   it->selective = (INTEGERP (current_buffer->selective_display)
+                  ? XFASTINT (current_buffer->selective_display)
+                  : (!NILP (current_buffer->selective_display)
+                     ? -1 : 0));
+   it->selective_display_ellipsis_p
+     = !NILP (current_buffer->selective_display_ellipses);
+ 
+   /* Display table to use.  */
+   it->dp = window_display_table (w);
+ 
+   /* Are multibyte characters enabled in current_buffer?  */
+   it->multibyte_p = !NILP (current_buffer->enable_multibyte_characters);
+ 
+   /* Non-zero if we should highlight the region.  */
+   highlight_region_p
+     = (!NILP (Vtransient_mark_mode)
+        && !NILP (current_buffer->mark_active)
+        && XMARKER (current_buffer->mark)->buffer != 0);
+ 
+   /* Set IT->region_beg_charpos and IT->region_end_charpos to the
+      start and end of a visible region in window IT->w.  Set both to
+      -1 to indicate no region.  */
+   if (highlight_region_p
+       /* Maybe highlight only in selected window.  */
+       && (/* Either show region everywhere.  */
+         highlight_nonselected_windows
+         /* Or show region in the selected window.  */
+         || w == XWINDOW (selected_window)
+         /* Or show the region if we are in the mini-buffer and W is
+            the window the mini-buffer refers to.  */
+         || (MINI_WINDOW_P (XWINDOW (selected_window))
+             && WINDOWP (minibuf_selected_window)
+             && w == XWINDOW (minibuf_selected_window))))
+     {
+       int charpos = marker_position (current_buffer->mark);
+       it->region_beg_charpos = min (PT, charpos);
+       it->region_end_charpos = max (PT, charpos);
+     }
+   else
+     it->region_beg_charpos = it->region_end_charpos = -1;
+ 
+   /* Get the position at which the redisplay_end_trigger hook should
+      be run, if it is to be run at all.  */
+   if (MARKERP (w->redisplay_end_trigger)
+       && XMARKER (w->redisplay_end_trigger)->buffer != 0)
+     it->redisplay_end_trigger_charpos
+       = marker_position (w->redisplay_end_trigger);
+   else if (INTEGERP (w->redisplay_end_trigger))
+     it->redisplay_end_trigger_charpos = XINT (w->redisplay_end_trigger);
+ 
+   /* Correct bogus values of tab_width.  */
+   it->tab_width = XINT (current_buffer->tab_width);
+   if (it->tab_width <= 0 || it->tab_width > 1000)
+     it->tab_width = 8;
+ 
+   /* Are lines in the display truncated?  */
+   it->truncate_lines_p
+     = (base_face_id != DEFAULT_FACE_ID
+        || XINT (it->w->hscroll)
+        || (truncate_partial_width_windows
+          && !WINDOW_FULL_WIDTH_P (it->w))
+        || !NILP (current_buffer->truncate_lines));
+ 
+   /* Get dimensions of truncation and continuation glyphs.  These are
+      displayed as fringe bitmaps under X, so we don't need them for such
+      frames.  */
+   if (!FRAME_WINDOW_P (it->f))
+     {
+       if (it->truncate_lines_p)
+       {
+         /* We will need the truncation glyph.  */
+         xassert (it->glyph_row == NULL);
+         produce_special_glyphs (it, IT_TRUNCATION);
+         it->truncation_pixel_width = it->pixel_width;
+       }
+       else
+       {
+         /* We will need the continuation glyph.  */
+         xassert (it->glyph_row == NULL);
+         produce_special_glyphs (it, IT_CONTINUATION);
+         it->continuation_pixel_width = it->pixel_width;
+       }
+ 
+       /* Reset these values to zero because the produce_special_glyphs
+        above has changed them.  */
+       it->pixel_width = it->ascent = it->descent = 0;
+       it->phys_ascent = it->phys_descent = 0;
+     }
+ 
+   /* Set this after getting the dimensions of truncation and
+      continuation glyphs, so that we don't produce glyphs when calling
+      produce_special_glyphs, above.  */
+   it->glyph_row = row;
+   it->area = TEXT_AREA;
+ 
+   /* Get the dimensions of the display area.  The display area
+      consists of the visible window area plus a horizontally scrolled
+      part to the left of the window.  All x-values are relative to the
+      start of this total display area.  */
+   if (base_face_id != DEFAULT_FACE_ID)
+     {
+       /* Mode lines, menu bar in terminal frames.  */
+       it->first_visible_x = 0;
+       it->last_visible_x = WINDOW_TOTAL_WIDTH (w);
+     }
+   else
+     {
+       it->first_visible_x
+       = XFASTINT (it->w->hscroll) * FRAME_COLUMN_WIDTH (it->f);
+       it->last_visible_x = (it->first_visible_x
+                           + window_box_width (w, TEXT_AREA));
+ 
+       /* If we truncate lines, leave room for the truncator glyph(s) at
+        the right margin.  Otherwise, leave room for the continuation
+        glyph(s).  Truncation and continuation glyphs are not inserted
+        for window-based redisplay.  */
+       if (!FRAME_WINDOW_P (it->f))
+       {
+         if (it->truncate_lines_p)
+           it->last_visible_x -= it->truncation_pixel_width;
+         else
+           it->last_visible_x -= it->continuation_pixel_width;
+       }
+ 
+       it->header_line_p = WINDOW_WANTS_HEADER_LINE_P (w);
+       it->current_y = WINDOW_HEADER_LINE_HEIGHT (w) + w->vscroll;
+     }
+ 
+   /* Leave room for a border glyph.  */
+   if (!FRAME_WINDOW_P (it->f)
+       && !WINDOW_RIGHTMOST_P (it->w))
+     it->last_visible_x -= 1;
+ 
+   it->last_visible_y = window_text_bottom_y (w);
+ 
+   /* For mode lines and alike, arrange for the first glyph having a
+      left box line if the face specifies a box.  */
+   if (base_face_id != DEFAULT_FACE_ID)
+     {
+       struct face *face;
+ 
+       it->face_id = base_face_id;
+ 
+       /* If we have a boxed mode line, make the first character appear
+        with a left box line.  */
+       face = FACE_FROM_ID (it->f, base_face_id);
+       if (face->box != FACE_NO_BOX)
+       it->start_of_box_run_p = 1;
+     }
+ 
+   /* If a buffer position was specified, set the iterator there,
+      getting overlays and face properties from that position.  */
+   if (charpos >= BUF_BEG (current_buffer))
+     {
+       it->end_charpos = ZV;
+       it->face_id = -1;
+       IT_CHARPOS (*it) = charpos;
+ 
+       /* Compute byte position if not specified.  */
+       if (bytepos < charpos)
+       IT_BYTEPOS (*it) = CHAR_TO_BYTE (charpos);
+       else
+       IT_BYTEPOS (*it) = bytepos;
+ 
+       /* Compute faces etc.  */
+       reseat (it, it->current.pos, 1);
+     }
+ 
+   CHECK_IT (it);
+ }
+ 
+ 
+ /* Initialize IT for the display of window W with window start POS.  */
+ 
+ void
+ start_display (it, w, pos)
+      struct it *it;
+      struct window *w;
+      struct text_pos pos;
+ {
+   struct glyph_row *row;
+   int first_vpos = WINDOW_WANTS_HEADER_LINE_P (w) ? 1 : 0;
+ 
+   row = w->desired_matrix->rows + first_vpos;
+   init_iterator (it, w, CHARPOS (pos), BYTEPOS (pos), row, DEFAULT_FACE_ID);
+ 
+   if (!it->truncate_lines_p)
+     {
+       int start_at_line_beg_p;
+       int first_y = it->current_y;
+ 
+       /* If window start is not at a line start, skip forward to POS to
+        get the correct continuation lines width.  */
+       start_at_line_beg_p = (CHARPOS (pos) == BEGV
+                            || FETCH_BYTE (BYTEPOS (pos) - 1) == '\n');
+       if (!start_at_line_beg_p)
+       {
+         int new_x;
+ 
+         reseat_at_previous_visible_line_start (it);
+         move_it_to (it, CHARPOS (pos), -1, -1, -1, MOVE_TO_POS);
+ 
+         new_x = it->current_x + it->pixel_width;
+ 
+         /* If lines are continued, this line may end in the middle
+            of a multi-glyph character (e.g. a control character
+            displayed as \003, or in the middle of an overlay
+            string).  In this case move_it_to above will not have
+            taken us to the start of the continuation line but to the
+            end of the continued line.  */
+         if (it->current_x > 0
+             && !it->truncate_lines_p /* Lines are continued.  */
+             && (/* And glyph doesn't fit on the line.  */
+                 new_x > it->last_visible_x
+                 /* Or it fits exactly and we're on a window
+                    system frame.  */
+                 || (new_x == it->last_visible_x
+                     && FRAME_WINDOW_P (it->f))))
+           {
+             if (it->current.dpvec_index >= 0
+                 || it->current.overlay_string_index >= 0)
+               {
+                 set_iterator_to_next (it, 1);
+                 move_it_in_display_line_to (it, -1, -1, 0);
+               }
+ 
+             it->continuation_lines_width += it->current_x;
+           }
+ 
+         /* We're starting a new display line, not affected by the
+            height of the continued line, so clear the appropriate
+            fields in the iterator structure.  */
+         it->max_ascent = it->max_descent = 0;
+         it->max_phys_ascent = it->max_phys_descent = 0;
+ 
+         it->current_y = first_y;
+         it->vpos = 0;
+         it->current_x = it->hpos = 0;
+       }
+     }
+ 
+ #if 0 /* Don't assert the following because start_display is sometimes
+          called intentionally with a window start that is not at a
+        line start.  Please leave this code in as a comment.  */
+ 
+   /* Window start should be on a line start, now.  */
+   xassert (it->continuation_lines_width
+          || IT_CHARPOS (it) == BEGV
+          || FETCH_BYTE (IT_BYTEPOS (it) - 1) == '\n');
+ #endif /* 0 */
+ }
+ 
+ 
+ /* Return 1 if POS is a position in ellipses displayed for invisible
+    text.  W is the window we display, for text property lookup.  */
+ 
+ static int
+ in_ellipses_for_invisible_text_p (pos, w)
+      struct display_pos *pos;
+      struct window *w;
+ {
+   Lisp_Object prop, window;
+   int ellipses_p = 0;
+   int charpos = CHARPOS (pos->pos);
+ 
+   /* If POS specifies a position in a display vector, this might
+      be for an ellipsis displayed for invisible text.  We won't
+      get the iterator set up for delivering that ellipsis unless
+      we make sure that it gets aware of the invisible text.  */
+   if (pos->dpvec_index >= 0
+       && pos->overlay_string_index < 0
+       && CHARPOS (pos->string_pos) < 0
+       && charpos > BEGV
+       && (XSETWINDOW (window, w),
+         prop = Fget_char_property (make_number (charpos),
+                                    Qinvisible, window),
+         !TEXT_PROP_MEANS_INVISIBLE (prop)))
+     {
+       prop = Fget_char_property (make_number (charpos - 1), Qinvisible,
+                                window);
+       ellipses_p = 2 == TEXT_PROP_MEANS_INVISIBLE (prop);
+     }
+ 
+   return ellipses_p;
+ }
+ 
+ 
+ /* Initialize IT for stepping through current_buffer in window W,
+    starting at position POS that includes overlay string and display
+    vector/ control character translation position information.  Value
+    is zero if there are overlay strings with newlines at POS.  */
+ 
+ static int
+ init_from_display_pos (it, w, pos)
+      struct it *it;
+      struct window *w;
+      struct display_pos *pos;
+ {
+   int charpos = CHARPOS (pos->pos), bytepos = BYTEPOS (pos->pos);
+   int i, overlay_strings_with_newlines = 0;
+ 
+   /* If POS specifies a position in a display vector, this might
+      be for an ellipsis displayed for invisible text.  We won't
+      get the iterator set up for delivering that ellipsis unless
+      we make sure that it gets aware of the invisible text.  */
+   if (in_ellipses_for_invisible_text_p (pos, w))
+     {
+       --charpos;
+       bytepos = 0;
+     }
+ 
+   /* Keep in mind: the call to reseat in init_iterator skips invisible
+      text, so we might end up at a position different from POS.  This
+      is only a problem when POS is a row start after a newline and an
+      overlay starts there with an after-string, and the overlay has an
+      invisible property.  Since we don't skip invisible text in
+      display_line and elsewhere immediately after consuming the
+      newline before the row start, such a POS will not be in a string,
+      but the call to init_iterator below will move us to the
+      after-string.  */
+   init_iterator (it, w, charpos, bytepos, NULL, DEFAULT_FACE_ID);
+ 
+   for (i = 0; i < it->n_overlay_strings; ++i)
+     {
+       const char *s = SDATA (it->overlay_strings[i]);
+       const char *e = s + SBYTES (it->overlay_strings[i]);
+ 
+       while (s < e && *s != '\n')
+       ++s;
+ 
+       if (s < e)
+       {
+         overlay_strings_with_newlines = 1;
+         break;
+       }
+     }
+ 
+   /* If position is within an overlay string, set up IT to the right
+      overlay string.  */
+   if (pos->overlay_string_index >= 0)
+     {
+       int relative_index;
+ 
+       /* If the first overlay string happens to have a `display'
+        property for an image, the iterator will be set up for that
+        image, and we have to undo that setup first before we can
+        correct the overlay string index.  */
+       if (it->method == next_element_from_image)
+       pop_it (it);
+ 
+       /* We already have the first chunk of overlay strings in
+        IT->overlay_strings.  Load more until the one for
+        pos->overlay_string_index is in IT->overlay_strings.  */
+       if (pos->overlay_string_index >= OVERLAY_STRING_CHUNK_SIZE)
+       {
+         int n = pos->overlay_string_index / OVERLAY_STRING_CHUNK_SIZE;
+         it->current.overlay_string_index = 0;
+         while (n--)
+           {
+             load_overlay_strings (it, 0);
+             it->current.overlay_string_index += OVERLAY_STRING_CHUNK_SIZE;
+           }
+       }
+ 
+       it->current.overlay_string_index = pos->overlay_string_index;
+       relative_index = (it->current.overlay_string_index
+                       % OVERLAY_STRING_CHUNK_SIZE);
+       it->string = it->overlay_strings[relative_index];
+       xassert (STRINGP (it->string));
+       it->current.string_pos = pos->string_pos;
+       it->method = next_element_from_string;
+     }
+ 
+ #if 0 /* This is bogus because POS not having an overlay string
+        position does not mean it's after the string.  Example: A
+        line starting with a before-string and initialization of IT
+        to the previous row's end position.  */
+   else if (it->current.overlay_string_index >= 0)
+     {
+       /* If POS says we're already after an overlay string ending at
+        POS, make sure to pop the iterator because it will be in
+        front of that overlay string.  When POS is ZV, we've thereby
+        also ``processed'' overlay strings at ZV.  */
+       while (it->sp)
+       pop_it (it);
+       it->current.overlay_string_index = -1;
+       it->method = next_element_from_buffer;
+       if (CHARPOS (pos->pos) == ZV)
+       it->overlay_strings_at_end_processed_p = 1;
+     }
+ #endif /* 0 */
+ 
+   if (CHARPOS (pos->string_pos) >= 0)
+     {
+       /* Recorded position is not in an overlay string, but in another
+        string.  This can only be a string from a `display' property.
+        IT should already be filled with that string.  */
+       it->current.string_pos = pos->string_pos;
+       xassert (STRINGP (it->string));
+     }
+ 
+   /* Restore position in display vector translations, control
+      character translations or ellipses.  */
+   if (pos->dpvec_index >= 0)
+     {
+       if (it->dpvec == NULL)
+       get_next_display_element (it);
+       xassert (it->dpvec && it->current.dpvec_index == 0);
+       it->current.dpvec_index = pos->dpvec_index;
+     }
+ 
+   CHECK_IT (it);
+   return !overlay_strings_with_newlines;
+ }
+ 
+ 
+ /* Initialize IT for stepping through current_buffer in window W
+    starting at ROW->start.  */
+ 
+ static void
+ init_to_row_start (it, w, row)
+      struct it *it;
+      struct window *w;
+      struct glyph_row *row;
+ {
+   init_from_display_pos (it, w, &row->start);
+   it->continuation_lines_width = row->continuation_lines_width;
+   CHECK_IT (it);
+ }
+ 
+ 
+ /* Initialize IT for stepping through current_buffer in window W
+    starting in the line following ROW, i.e. starting at ROW->end.
+    Value is zero if there are overlay strings with newlines at ROW's
+    end position.  */
+ 
+ static int
+ init_to_row_end (it, w, row)
+      struct it *it;
+      struct window *w;
+      struct glyph_row *row;
+ {
+   int success = 0;
+ 
+   if (init_from_display_pos (it, w, &row->end))
+     {
+       if (row->continued_p)
+       it->continuation_lines_width
+         = row->continuation_lines_width + row->pixel_width;
+       CHECK_IT (it);
+       success = 1;
+     }
+ 
+   return success;
+ }
+ 
+ 
+ 
+ 
+ /***********************************************************************
+                          Text properties
+  ***********************************************************************/
+ 
+ /* Called when IT reaches IT->stop_charpos.  Handle text property and
+    overlay changes.  Set IT->stop_charpos to the next position where
+    to stop.  */
+ 
+ static void
+ handle_stop (it)
+      struct it *it;
+ {
+   enum prop_handled handled;
+   int handle_overlay_change_p = 1;
+   struct props *p;
+ 
+   it->dpvec = NULL;
+   it->current.dpvec_index = -1;
+ 
+   do
+     {
+       handled = HANDLED_NORMALLY;
+ 
+       /* Call text property handlers.  */
+       for (p = it_props; p->handler; ++p)
+       {
+         handled = p->handler (it);
+ 
+         if (handled == HANDLED_RECOMPUTE_PROPS)
+           break;
+         else if (handled == HANDLED_RETURN)
+           return;
+         else if (handled == HANDLED_OVERLAY_STRING_CONSUMED)
+           handle_overlay_change_p = 0;
+       }
+ 
+       if (handled != HANDLED_RECOMPUTE_PROPS)
+       {
+         /* Don't check for overlay strings below when set to deliver
+            characters from a display vector.  */
+         if (it->method == next_element_from_display_vector)
+           handle_overlay_change_p = 0;
+ 
+         /* Handle overlay changes.  */
+         if (handle_overlay_change_p)
+           handled = handle_overlay_change (it);
+ 
+         /* Determine where to stop next.  */
+         if (handled == HANDLED_NORMALLY)
+           compute_stop_pos (it);
+       }
+     }
+   while (handled == HANDLED_RECOMPUTE_PROPS);
+ }
+ 
+ 
+ /* Compute IT->stop_charpos from text property and overlay change
+    information for IT's current position.  */
+ 
+ static void
+ compute_stop_pos (it)
+      struct it *it;
+ {
+   register INTERVAL iv, next_iv;
+   Lisp_Object object, limit, position;
+ 
+   /* If nowhere else, stop at the end.  */
+   it->stop_charpos = it->end_charpos;
+ 
+   if (STRINGP (it->string))
+     {
+       /* Strings are usually short, so don't limit the search for
+        properties.  */
+       object = it->string;
+       limit = Qnil;
+       position = make_number (IT_STRING_CHARPOS (*it));
+     }
+   else
+     {
+       int charpos;
+ 
+       /* If next overlay change is in front of the current stop pos
+        (which is IT->end_charpos), stop there.  Note: value of
+        next_overlay_change is point-max if no overlay change
+        follows.  */
+       charpos = next_overlay_change (IT_CHARPOS (*it));
+       if (charpos < it->stop_charpos)
+       it->stop_charpos = charpos;
+ 
+       /* If showing the region, we have to stop at the region
+        start or end because the face might change there.  */
+       if (it->region_beg_charpos > 0)
+       {
+         if (IT_CHARPOS (*it) < it->region_beg_charpos)
+           it->stop_charpos = min (it->stop_charpos, it->region_beg_charpos);
+         else if (IT_CHARPOS (*it) < it->region_end_charpos)
+           it->stop_charpos = min (it->stop_charpos, it->region_end_charpos);
+       }
+ 
+       /* Set up variables for computing the stop position from text
+          property changes.  */
+       XSETBUFFER (object, current_buffer);
+       limit = make_number (IT_CHARPOS (*it) + TEXT_PROP_DISTANCE_LIMIT);
+       position = make_number (IT_CHARPOS (*it));
+ 
+     }
+ 
+   /* Get the interval containing IT's position.  Value is a null
+      interval if there isn't such an interval.  */
+   iv = validate_interval_range (object, &position, &position, 0);
+   if (!NULL_INTERVAL_P (iv))
+     {
+       Lisp_Object values_here[LAST_PROP_IDX];
+       struct props *p;
+ 
+       /* Get properties here.  */
+       for (p = it_props; p->handler; ++p)
+       values_here[p->idx] = textget (iv->plist, *p->name);
+ 
+       /* Look for an interval following iv that has different
+        properties.  */
+       for (next_iv = next_interval (iv);
+          (!NULL_INTERVAL_P (next_iv)
+           && (NILP (limit)
+               || XFASTINT (limit) > next_iv->position));
+          next_iv = next_interval (next_iv))
+       {
+         for (p = it_props; p->handler; ++p)
+           {
+             Lisp_Object new_value;
+ 
+             new_value = textget (next_iv->plist, *p->name);
+             if (!EQ (values_here[p->idx], new_value))
+               break;
+           }
+ 
+         if (p->handler)
+           break;
+       }
+ 
+       if (!NULL_INTERVAL_P (next_iv))
+       {
+         if (INTEGERP (limit)
+             && next_iv->position >= XFASTINT (limit))
+           /* No text property change up to limit.  */
+           it->stop_charpos = min (XFASTINT (limit), it->stop_charpos);
+         else
+           /* Text properties change in next_iv.  */
+           it->stop_charpos = min (it->stop_charpos, next_iv->position);
+       }
+     }
+ 
+   xassert (STRINGP (it->string)
+          || (it->stop_charpos >= BEGV
+              && it->stop_charpos >= IT_CHARPOS (*it)));
+ }
+ 
+ 
+ /* Return the position of the next overlay change after POS in
+    current_buffer.  Value is point-max if no overlay change
+    follows.  This is like `next-overlay-change' but doesn't use
+    xmalloc.  */
+ 
+ static int
+ next_overlay_change (pos)
+      int pos;
+ {
+   int noverlays;
+   int endpos;
+   Lisp_Object *overlays;
+   int len;
+   int i;
+ 
+   /* Get all overlays at the given position.  */
+   len = 10;
+   overlays = (Lisp_Object *) alloca (len * sizeof *overlays);
+   noverlays = overlays_at (pos, 0, &overlays, &len, &endpos, NULL, 1);
+   if (noverlays > len)
+     {
+       len = noverlays;
+       overlays = (Lisp_Object *) alloca (len * sizeof *overlays);
+       noverlays = overlays_at (pos, 0, &overlays, &len, &endpos, NULL, 1);
+     }
+ 
+   /* If any of these overlays ends before endpos,
+      use its ending point instead.  */
+   for (i = 0; i < noverlays; ++i)
+     {
+       Lisp_Object oend;
+       int oendpos;
+ 
+       oend = OVERLAY_END (overlays[i]);
+       oendpos = OVERLAY_POSITION (oend);
+       endpos = min (endpos, oendpos);
+     }
+ 
+   return endpos;
+ }
+ 
+ 
+ 
+ /***********************************************************************
+                           Fontification
+  ***********************************************************************/
+ 
+ /* Handle changes in the `fontified' property of the current buffer by
+    calling hook functions from Qfontification_functions to fontify
+    regions of text.  */
+ 
+ static enum prop_handled
+ handle_fontified_prop (it)
+      struct it *it;
+ {
+   Lisp_Object prop, pos;
+   enum prop_handled handled = HANDLED_NORMALLY;
+ 
+   /* 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
+      Qfontification_functions.  */
+   if (!STRINGP (it->string)
+       && it->s == NULL
+       && !NILP (Vfontification_functions)
+       && !NILP (Vrun_hooks)
+       && (pos = make_number (IT_CHARPOS (*it)),
+         prop = Fget_char_property (pos, Qfontified, Qnil),
+         NILP (prop)))
+     {
+       int count = SPECPDL_INDEX ();
+       Lisp_Object val;
+ 
+       val = Vfontification_functions;
+       specbind (Qfontification_functions, Qnil);
+ 
+       if (!CONSP (val) || EQ (XCAR (val), Qlambda))
+       safe_call1 (val, pos);
+       else
+       {
+         Lisp_Object globals, fn;
+         struct gcpro gcpro1, gcpro2;
+ 
+         globals = Qnil;
+         GCPRO2 (val, globals);
+ 
+         for (; CONSP (val); val = XCDR (val))
+           {
+             fn = XCAR (val);
+ 
+             if (EQ (fn, Qt))
+               {
+                 /* A value of t indicates this hook has a local
+                    binding; it means to run the global binding too.
+                    In a global value, t should not occur.  If it
+                    does, we must ignore it to avoid an endless
+                    loop.  */
+                 for (globals = Fdefault_value (Qfontification_functions);
+                      CONSP (globals);
+                      globals = XCDR (globals))
+                   {
+                     fn = XCAR (globals);
+                     if (!EQ (fn, Qt))
+                       safe_call1 (fn, pos);
+                   }
+               }
+             else
+               safe_call1 (fn, pos);
+           }
+ 
+         UNGCPRO;
+       }
+ 
+       unbind_to (count, Qnil);
+ 
+       /* Return HANDLED_RECOMPUTE_PROPS only if function fontified
+        something.  This avoids an endless loop if they failed to
+        fontify the text for which reason ever.  */
+       if (!NILP (Fget_char_property (pos, Qfontified, Qnil)))
+       handled = HANDLED_RECOMPUTE_PROPS;
+     }
+ 
+   return handled;
+ }
+ 
+ 
+ 
+ /***********************************************************************
+                               Faces
+  ***********************************************************************/
+ 
+ /* Set up iterator IT from face properties at its current position.
+    Called from handle_stop.  */
+ 
+ static enum prop_handled
+ handle_face_prop (it)
+      struct it *it;
+ {
+   int new_face_id, next_stop;
+ 
+   if (!STRINGP (it->string))
+     {
+       new_face_id
+       = face_at_buffer_position (it->w,
+                                  IT_CHARPOS (*it),
+                                  it->region_beg_charpos,
+                                  it->region_end_charpos,
+                                  &next_stop,
+                                  (IT_CHARPOS (*it)
+                                   + TEXT_PROP_DISTANCE_LIMIT),
+                                  0);
+ 
+       /* Is this a start of a run of characters with box face?
+        Caveat: this can be called for a freshly initialized
+        iterator; face_id is -1 in this case.  We know that the new
+        face will not change until limit, i.e. if the new face has a
+        box, all characters up to limit will have one.  But, as
+        usual, we don't know whether limit is really the end.  */
+       if (new_face_id != it->face_id)
+       {
+         struct face *new_face = FACE_FROM_ID (it->f, new_face_id);
+ 
+         /* If new face has a box but old face has not, this is
+            the start of a run of characters with box, i.e. it has
+            a shadow on the left side.  The value of face_id of the
+            iterator will be -1 if this is the initial call that gets
+            the face.  In this case, we have to look in front of IT's
+            position and see whether there is a face != new_face_id.  */
+         it->start_of_box_run_p
+           = (new_face->box != FACE_NO_BOX
+              && (it->face_id >= 0
+                  || IT_CHARPOS (*it) == BEG
+                  || new_face_id != face_before_it_pos (it)));
+         it->face_box_p = new_face->box != FACE_NO_BOX;
+       }
+     }
+   else
+     {
+       int base_face_id, bufpos;
+ 
+       if (it->current.overlay_string_index >= 0)
+       bufpos = IT_CHARPOS (*it);
+       else
+       bufpos = 0;
+ 
+       /* For strings from a buffer, i.e. overlay strings or strings
+        from a `display' property, use the face at IT's current
+        buffer position as the base face to merge with, so that
+        overlay strings appear in the same face as surrounding
+        text, unless they specify their own faces.  */
+       base_face_id = underlying_face_id (it);
+ 
+       new_face_id = face_at_string_position (it->w,
+                                            it->string,
+                                            IT_STRING_CHARPOS (*it),
+                                            bufpos,
+                                            it->region_beg_charpos,
+                                            it->region_end_charpos,
+                                            &next_stop,
+                                            base_face_id, 0);
+ 
+ #if 0 /* This shouldn't be neccessary.  Let's check it.  */
+       /* If IT is used to display a mode line we would really like to
+        use the mode line face instead of the frame's default face.  */
+       if (it->glyph_row == MATRIX_MODE_LINE_ROW (it->w->desired_matrix)
+         && new_face_id == DEFAULT_FACE_ID)
+       new_face_id = CURRENT_MODE_LINE_FACE_ID (it->w);
+ #endif
+ 
+       /* Is this a start of a run of characters with box?  Caveat:
+        this can be called for a freshly allocated iterator; face_id
+        is -1 is this case.  We know that the new face will not
+        change until the next check pos, i.e. if the new face has a
+        box, all characters up to that position will have a
+        box.  But, as usual, we don't know whether that position
+        is really the end.  */
+       if (new_face_id != it->face_id)
+       {
+         struct face *new_face = FACE_FROM_ID (it->f, new_face_id);
+         struct face *old_face = FACE_FROM_ID (it->f, it->face_id);
+ 
+         /* If new face has a box but old face hasn't, this is the
+            start of a run of characters with box, i.e. it has a
+            shadow on the left side.  */
+         it->start_of_box_run_p
+           = new_face->box && (old_face == NULL || !old_face->box);
+         it->face_box_p = new_face->box != FACE_NO_BOX;
+       }
+     }
+ 
+   it->face_id = new_face_id;
+   return HANDLED_NORMALLY;
+ }
+ 
+ 
+ /* Return the ID of the face ``underlying'' IT's current position,
+    which is in a string.  If the iterator is associated with a
+    buffer, return the face at IT's current buffer position.
+    Otherwise, use the iterator's base_face_id.  */
+ 
+ static int
+ underlying_face_id (it)
+      struct it *it;
+ {
+   int face_id = it->base_face_id, i;
+ 
+   xassert (STRINGP (it->string));
+ 
+   for (i = it->sp - 1; i >= 0; --i)
+     if (NILP (it->stack[i].string))
+       face_id = it->stack[i].face_id;
+ 
+   return face_id;
+ }
+ 
+ 
+ /* Compute the face one character before or after the current position
+    of IT.  BEFORE_P non-zero means get the face in front of IT's
+    position.  Value is the id of the face.  */
+ 
+ static int
+ face_before_or_after_it_pos (it, before_p)
+      struct it *it;
+      int before_p;
+ {
+   int face_id, limit;
+   int next_check_charpos;
+   struct text_pos pos;
+ 
+   xassert (it->s == NULL);
+ 
+   if (STRINGP (it->string))
+     {
+       int bufpos, base_face_id;
+ 
+       /* No face change past the end of the string (for the case
+        we are padding with spaces).  No face change before the
+        string start.  */
+       if (IT_STRING_CHARPOS (*it) >= SCHARS (it->string)
+         || (IT_STRING_CHARPOS (*it) == 0 && before_p))
+       return it->face_id;
+ 
+       /* Set pos to the position before or after IT's current position.  */
+       if (before_p)
+       pos = string_pos (IT_STRING_CHARPOS (*it) - 1, it->string);
+       else
+       /* For composition, we must check the character after the
+            composition.  */
+       pos = (it->what == IT_COMPOSITION
+              ? string_pos (IT_STRING_CHARPOS (*it) + it->cmp_len, it->string)
+              : string_pos (IT_STRING_CHARPOS (*it) + 1, it->string));
+ 
+       if (it->current.overlay_string_index >= 0)
+       bufpos = IT_CHARPOS (*it);
+       else
+       bufpos = 0;
+ 
+       base_face_id = underlying_face_id (it);
+ 
+       /* Get the face for ASCII, or unibyte.  */
+       face_id = face_at_string_position (it->w,
+                                        it->string,
+                                        CHARPOS (pos),
+                                        bufpos,
+                                        it->region_beg_charpos,
+                                        it->region_end_charpos,
+                                        &next_check_charpos,
+                                        base_face_id, 0);
+ 
+       /* Correct the face for charsets different from ASCII.  Do it
+        for the multibyte case only.  The face returned above is
+        suitable for unibyte text if IT->string is unibyte.  */
+       if (STRING_MULTIBYTE (it->string))
+       {
+         const unsigned char *p = SDATA (it->string) + BYTEPOS (pos);
+         int rest = SBYTES (it->string) - BYTEPOS (pos);
+         int c, len;
+         struct face *face = FACE_FROM_ID (it->f, face_id);
+ 
+         c = string_char_and_length (p, rest, &len);
+         face_id = FACE_FOR_CHAR (it->f, face, c);
+       }
+     }
+   else
+     {
+       if ((IT_CHARPOS (*it) >= ZV && !before_p)
+         || (IT_CHARPOS (*it) <= BEGV && before_p))
+       return it->face_id;
+ 
+       limit = IT_CHARPOS (*it) + TEXT_PROP_DISTANCE_LIMIT;
+       pos = it->current.pos;
+ 
+       if (before_p)
+       DEC_TEXT_POS (pos, it->multibyte_p);
+       else
+       {
+         if (it->what == IT_COMPOSITION)
+           /* For composition, we must check the position after the
+              composition.  */
+           pos.charpos += it->cmp_len, pos.bytepos += it->len;
+         else
+           INC_TEXT_POS (pos, it->multibyte_p);
+       }
+ 
+       /* Determine face for CHARSET_ASCII, or unibyte.  */
+       face_id = face_at_buffer_position (it->w,
+                                        CHARPOS (pos),
+                                        it->region_beg_charpos,
+                                        it->region_end_charpos,
+                                        &next_check_charpos,
+                                        limit, 0);
+ 
+       /* Correct the face for charsets different from ASCII.  Do it
+        for the multibyte case only.  The face returned above is
+        suitable for unibyte text if current_buffer is unibyte.  */
+       if (it->multibyte_p)
+       {
+         int c = FETCH_MULTIBYTE_CHAR (BYTEPOS (pos));
+         struct face *face = FACE_FROM_ID (it->f, face_id);
+         face_id = FACE_FOR_CHAR (it->f, face, c);
+       }
+     }
+ 
+   return face_id;
+ }
+ 
+ 
+ 
+ /***********************************************************************
+                           Invisible text
+  ***********************************************************************/
+ 
+ /* Set up iterator IT from invisible properties at its current
+    position.  Called from handle_stop.  */
+ 
+ static enum prop_handled
+ handle_invisible_prop (it)
+      struct it *it;
+ {
+   enum prop_handled handled = HANDLED_NORMALLY;
+ 
+   if (STRINGP (it->string))
+     {
+       extern Lisp_Object Qinvisible;
+       Lisp_Object prop, end_charpos, limit, charpos;
+ 
+       /* Get the value of the invisible text property at the
+        current position.  Value will be nil if there is no such
+        property.  */
+       charpos = make_number (IT_STRING_CHARPOS (*it));
+       prop = Fget_text_property (charpos, Qinvisible, it->string);
+ 
+       if (!NILP (prop)
+         && IT_STRING_CHARPOS (*it) < it->end_charpos)
+       {
+         handled = HANDLED_RECOMPUTE_PROPS;
+ 
+         /* Get the position at which the next change of the
+            invisible text property can be found in IT->string.
+            Value will be nil if the property value is the same for
+            all the rest of IT->string.  */
+         XSETINT (limit, SCHARS (it->string));
+         end_charpos = Fnext_single_property_change (charpos, Qinvisible,
+                                                     it->string, limit);
+ 
+         /* Text at current position is invisible.  The next
+            change in the property is at position end_charpos.
+            Move IT's current position to that position.  */
+         if (INTEGERP (end_charpos)
+             && XFASTINT (end_charpos) < XFASTINT (limit))
+           {
+             struct text_pos old;
+             old = it->current.string_pos;
+             IT_STRING_CHARPOS (*it) = XFASTINT (end_charpos);
+             compute_string_pos (&it->current.string_pos, old, it->string);
+           }
+         else
+           {
+             /* The rest of the string is invisible.  If this is an
+                overlay string, proceed with the next overlay string
+                or whatever comes and return a character from there.  */
+             if (it->current.overlay_string_index >= 0)
+               {
+                 next_overlay_string (it);
+                 /* Don't check for overlay strings when we just
+                    finished processing them.  */
+                 handled = HANDLED_OVERLAY_STRING_CONSUMED;
+               }
+             else
+               {
+                 IT_STRING_CHARPOS (*it) = SCHARS (it->string);
+                 IT_STRING_BYTEPOS (*it) = SBYTES (it->string);
+               }
+           }
+       }
+     }
+   else
+     {
+       int invis_p, newpos, next_stop, start_charpos;
+       Lisp_Object pos, prop, overlay;
+ 
+       /* First of all, is there invisible text at this position?  */
+       start_charpos = IT_CHARPOS (*it);
+       pos = make_number (IT_CHARPOS (*it));
+       prop = get_char_property_and_overlay (pos, Qinvisible, it->window,
+                                           &overlay);
+       invis_p = TEXT_PROP_MEANS_INVISIBLE (prop);
+ 
+       /* If we are on invisible text, skip over it.  */
+       if (invis_p && IT_CHARPOS (*it) < it->end_charpos)
+       {
+         /* Record whether we have to display an ellipsis for the
+            invisible text.  */
+         int display_ellipsis_p = invis_p == 2;
+ 
+         handled = HANDLED_RECOMPUTE_PROPS;
+ 
+         /* Loop skipping over invisible text.  The loop is left at
+            ZV or with IT on the first char being visible again.  */
+         do
+           {
+             /* Try to skip some invisible text.  Return value is the
+                position reached which can be equal to IT's position
+                if there is nothing invisible here.  This skips both
+                over invisible text properties and overlays with
+                invisible property.  */
+             newpos = skip_invisible (IT_CHARPOS (*it),
+                                      &next_stop, ZV, it->window);
+ 
+             /* If we skipped nothing at all we weren't at invisible
+                text in the first place.  If everything to the end of
+                the buffer was skipped, end the loop.  */
+             if (newpos == IT_CHARPOS (*it) || newpos >= ZV)
+               invis_p = 0;
+             else
+               {
+                 /* We skipped some characters but not necessarily
+                    all there are.  Check if we ended up on visible
+                    text.  Fget_char_property returns the property of
+                    the char before the given position, i.e. if we
+                    get invis_p = 0, this means that the char at
+                    newpos is visible.  */
+                 pos = make_number (newpos);
+                 prop = Fget_char_property (pos, Qinvisible, it->window);
+                 invis_p = TEXT_PROP_MEANS_INVISIBLE (prop);
+               }
+ 
+             /* If we ended up on invisible text, proceed to
+                skip starting with next_stop.  */
+             if (invis_p)
+               IT_CHARPOS (*it) = next_stop;
+           }
+         while (invis_p);
+ 
+         /* The position newpos is now either ZV or on visible text.  */
+         IT_CHARPOS (*it) = newpos;
+         IT_BYTEPOS (*it) = CHAR_TO_BYTE (newpos);
+ 
+         /* If there are before-strings at the start of invisible
+            text, and the text is invisible because of a text
+            property, arrange to show before-strings because 20.x did
+            it that way.  (If the text is invisible because of an
+            overlay property instead of a text property, this is
+            already handled in the overlay code.)  */
+         if (NILP (overlay)
+             && get_overlay_strings (it, start_charpos))
+           {
+             handled = HANDLED_RECOMPUTE_PROPS;
+             it->stack[it->sp - 1].display_ellipsis_p = display_ellipsis_p;
+           }
+         else if (display_ellipsis_p)
+           setup_for_ellipsis (it);
+       }
+     }
+ 
+   return handled;
+ }
+ 
+ 
+ /* Make iterator IT return `...' next.  */
+ 
+ static void
+ setup_for_ellipsis (it)
+      struct it *it;
+ {
+   if (it->dp
+       && VECTORP (DISP_INVIS_VECTOR (it->dp)))
+     {
+       struct Lisp_Vector *v = XVECTOR (DISP_INVIS_VECTOR (it->dp));
+       it->dpvec = v->contents;
+       it->dpend = v->contents + v->size;
+     }
+   else
+     {
+       /* Default `...'.  */
+       it->dpvec = default_invis_vector;
+       it->dpend = default_invis_vector + 3;
+     }
+ 
+   /* The ellipsis display does not replace the display of the
+      character at the new position.  Indicate this by setting
+      IT->dpvec_char_len to zero.  */
+   it->dpvec_char_len = 0;
+ 
+   it->current.dpvec_index = 0;
+   it->method = next_element_from_display_vector;
+ }
+ 
+ 
+ 
+ /***********************************************************************
+                           'display' property
+  ***********************************************************************/
+ 
+ /* Set up iterator IT from `display' property at its current position.
+    Called from handle_stop.  */
+ 
+ static enum prop_handled
+ handle_display_prop (it)
+      struct it *it;
+ {
+   Lisp_Object prop, object;
+   struct text_pos *position;
+   int display_replaced_p = 0;
+ 
+   if (STRINGP (it->string))
+     {
+       object = it->string;
+       position = &it->current.string_pos;
+     }
+   else
+     {
+       object = it->w->buffer;
+       position = &it->current.pos;
+     }
+ 
+   /* Reset those iterator values set from display property values.  */
+   it->font_height = Qnil;
+   it->space_width = Qnil;
+   it->voffset = 0;
+ 
+   /* We don't support recursive `display' properties, i.e. string
+      values that have a string `display' property, that have a string
+      `display' property etc.  */
+   if (!it->string_from_display_prop_p)
+     it->area = TEXT_AREA;
+ 
+   prop = Fget_char_property (make_number (position->charpos),
+                            Qdisplay, object);
+   if (NILP (prop))
+     return HANDLED_NORMALLY;
+ 
+   if (CONSP (prop)
+       /* Simple properties.  */
+       && !EQ (XCAR (prop), Qimage)
+       && !EQ (XCAR (prop), Qspace)
+       && !EQ (XCAR (prop), Qwhen)
+       && !EQ (XCAR (prop), Qspace_width)
+       && !EQ (XCAR (prop), Qheight)
+       && !EQ (XCAR (prop), Qraise)
+       /* Marginal area specifications.  */
+       && !(CONSP (XCAR (prop)) && EQ (XCAR (XCAR (prop)), Qmargin))
+       && !NILP (XCAR (prop)))
+     {
+       for (; CONSP (prop); prop = XCDR (prop))
+       {
+         if (handle_single_display_prop (it, XCAR (prop), object,
+                                         position, display_replaced_p))
+           display_replaced_p = 1;
+       }
+     }
+   else if (VECTORP (prop))
+     {
+       int i;
+       for (i = 0; i < ASIZE (prop); ++i)
+       if (handle_single_display_prop (it, AREF (prop, i), object,
+                                       position, display_replaced_p))
+         display_replaced_p = 1;
+     }
+   else
+     {
+       if (handle_single_display_prop (it, prop, object, position, 0))
+       display_replaced_p = 1;
+     }
+ 
+   return display_replaced_p ? HANDLED_RETURN : HANDLED_NORMALLY;
+ }
+ 
+ 
+ /* Value is the position of the end of the `display' property starting
+    at START_POS in OBJECT.  */
+ 
+ static struct text_pos
+ display_prop_end (it, object, start_pos)
+      struct it *it;
+      Lisp_Object object;
+      struct text_pos start_pos;
+ {
+   Lisp_Object end;
+   struct text_pos end_pos;
+ 
+   end = Fnext_single_char_property_change (make_number (CHARPOS (start_pos)),
+                                          Qdisplay, object, Qnil);
+   CHARPOS (end_pos) = XFASTINT (end);
+   if (STRINGP (object))
+     compute_string_pos (&end_pos, start_pos, it->string);
+   else
+     BYTEPOS (end_pos) = CHAR_TO_BYTE (XFASTINT (end));
+ 
+   return end_pos;
+ }
+ 
+ 
+ /* Set up IT from a single `display' sub-property value PROP.  OBJECT
+    is the object in which the `display' property was found.  *POSITION
+    is the position at which it was found.  DISPLAY_REPLACED_P non-zero
+    means that we previously saw a display sub-property which already
+    replaced text display with something else, for example an image;
+    ignore such properties after the first one has been processed.
+ 
+    If PROP is a `space' or `image' sub-property, set *POSITION to the
+    end position of the `display' property.
+ 
+    Value is non-zero if something was found which replaces the display
+    of buffer or string text.  */
+ 
+ static int
+ handle_single_display_prop (it, prop, object, position,
+                           display_replaced_before_p)
+      struct it *it;
+      Lisp_Object prop;
+      Lisp_Object object;
+      struct text_pos *position;
+      int display_replaced_before_p;
+ {
+   Lisp_Object value;
+   int replaces_text_display_p = 0;
+   Lisp_Object form;
+ 
+   /* If PROP is a list of the form `(when FORM . VALUE)', FORM is
+      evaluated.  If the result is nil, VALUE is ignored.  */
+   form = Qt;
+   if (CONSP (prop) && EQ (XCAR (prop), Qwhen))
+     {
+       prop = XCDR (prop);
+       if (!CONSP (prop))
+       return 0;
+       form = XCAR (prop);
+       prop = XCDR (prop);
+     }
+ 
+   if (!NILP (form) && !EQ (form, Qt))
+     {
+       int count = SPECPDL_INDEX ();
+       struct gcpro gcpro1;
+ 
+       /* Bind `object' to the object having the `display' property, a
+        buffer or string.  Bind `position' to the position in the
+        object where the property was found, and `buffer-position'
+        to the current position in the buffer.  */
+       specbind (Qobject, object);
+       specbind (Qposition, make_number (CHARPOS (*position)));
+       specbind (Qbuffer_position,
+               make_number (STRINGP (object)
+                            ? IT_CHARPOS (*it) : CHARPOS (*position)));
+       GCPRO1 (form);
+       form = safe_eval (form);
+       UNGCPRO;
+       unbind_to (count, Qnil);
+     }
+ 
+   if (NILP (form))
+     return 0;
+ 
+   if (CONSP (prop)
+       && EQ (XCAR (prop), Qheight)
+       && CONSP (XCDR (prop)))
+     {
+       if (FRAME_TERMCAP_P (it->f) || FRAME_MSDOS_P (it->f))
+       return 0;
+ 
+       /* `(height HEIGHT)'.  */
+       it->font_height = XCAR (XCDR (prop));
+       if (!NILP (it->font_height))
+       {
+         struct face *face = FACE_FROM_ID (it->f, it->face_id);
+         int new_height = -1;
+ 
+         if (CONSP (it->font_height)
+             && (EQ (XCAR (it->font_height), Qplus)
+                 || EQ (XCAR (it->font_height), Qminus))
+             && CONSP (XCDR (it->font_height))
+             && INTEGERP (XCAR (XCDR (it->font_height))))
+           {
+             /* `(+ N)' or `(- N)' where N is an integer.  */
+             int steps = XINT (XCAR (XCDR (it->font_height)));
+             if (EQ (XCAR (it->font_height), Qplus))
+               steps = - steps;
+             it->face_id = smaller_face (it->f, it->face_id, steps);
+           }
+         else if (FUNCTIONP (it->font_height))
+           {
+             /* Call function with current height as argument.
+                Value is the new height.  */
+             Lisp_Object height;
+             height = safe_call1 (it->font_height,
+                                  face->lface[LFACE_HEIGHT_INDEX]);
+             if (NUMBERP (height))
+               new_height = XFLOATINT (height);
+           }
+         else if (NUMBERP (it->font_height))
+           {
+             /* Value is a multiple of the canonical char height.  */
+             struct face *face;
+ 
+             face = FACE_FROM_ID (it->f, DEFAULT_FACE_ID);
+             new_height = (XFLOATINT (it->font_height)
+                           * XINT (face->lface[LFACE_HEIGHT_INDEX]));
+           }
+         else
+           {
+             /* Evaluate IT->font_height with `height' bound to the
+                current specified height to get the new height.  */
+             Lisp_Object value;
+             int count = SPECPDL_INDEX ();
+ 
+             specbind (Qheight, face->lface[LFACE_HEIGHT_INDEX]);
+             value = safe_eval (it->font_height);
+             unbind_to (count, Qnil);
+ 
+             if (NUMBERP (value))
+               new_height = XFLOATINT (value);
+           }
+ 
+         if (new_height > 0)
+           it->face_id = face_with_height (it->f, it->face_id, new_height);
+       }
+     }
+   else if (CONSP (prop)
+          && EQ (XCAR (prop), Qspace_width)
+          && CONSP (XCDR (prop)))
+     {
+       /* `(space_width WIDTH)'.  */
+       if (FRAME_TERMCAP_P (it->f) || FRAME_MSDOS_P (it->f))
+       return 0;
+ 
+       value = XCAR (XCDR (prop));
+       if (NUMBERP (value) && XFLOATINT (value) > 0)
+       it->space_width = value;
+     }
+   else if (CONSP (prop)
+          && EQ (XCAR (prop), Qraise)
+          && CONSP (XCDR (prop)))
+     {
+       /* `(raise FACTOR)'.  */
+       if (FRAME_TERMCAP_P (it->f) || FRAME_MSDOS_P (it->f))
+       return 0;
+ 
+ #ifdef HAVE_WINDOW_SYSTEM
+       value = XCAR (XCDR (prop));
+       if (NUMBERP (value))
+       {
+         struct face *face = FACE_FROM_ID (it->f, it->face_id);
+         it->voffset = - (XFLOATINT (value)
+                          * (FONT_HEIGHT (face->font)));
+       }
+ #endif /* HAVE_WINDOW_SYSTEM */
+     }
+   else if (!it->string_from_display_prop_p)
+     {
+       /* `((margin left-margin) VALUE)' or `((margin right-margin)
+        VALUE) or `((margin nil) VALUE)' or VALUE.  */
+       Lisp_Object location, value;
+       struct text_pos start_pos;
+       int valid_p;
+ 
+       /* Characters having this form of property are not displayed, so
+          we have to find the end of the property.  */
+       start_pos = *position;
+       *position = display_prop_end (it, object, start_pos);
+       value = Qnil;
+ 
+       /* Let's stop at the new position and assume that all
+        text properties change there.  */
+       it->stop_charpos = position->charpos;
+ 
+       location = Qunbound;
+       if (CONSP (prop) && CONSP (XCAR (prop)))
+       {
+         Lisp_Object tem;
+ 
+         value = XCDR (prop);
+         if (CONSP (value))
+           value = XCAR (value);
+ 
+         tem = XCAR (prop);
+         if (EQ (XCAR (tem), Qmargin)
+             && (tem = XCDR (tem),
+                 tem = CONSP (tem) ? XCAR (tem) : Qnil,
+                 (NILP (tem)
+                  || EQ (tem, Qleft_margin)
+                  || EQ (tem, Qright_margin))))
+           location = tem;
+       }
+ 
+       if (EQ (location, Qunbound))
+       {
+         location = Qnil;
+         value = prop;
+       }
+ 
+ #ifdef HAVE_WINDOW_SYSTEM
+       if (FRAME_TERMCAP_P (it->f))
+       valid_p = STRINGP (value);
+       else
+       valid_p = (STRINGP (value)
+                  || (CONSP (value) && EQ (XCAR (value), Qspace))
+                  || valid_image_p (value));
+ #else /* not HAVE_WINDOW_SYSTEM */
+       valid_p = STRINGP (value);
+ #endif /* not HAVE_WINDOW_SYSTEM */
+ 
+       if ((EQ (location, Qleft_margin)
+          || EQ (location, Qright_margin)
+          || NILP (location))
+         && valid_p
+         && !display_replaced_before_p)
+       {
+         replaces_text_display_p = 1;
+ 
+         /* Save current settings of IT so that we can restore them
+            when we are finished with the glyph property value.  */
+         push_it (it);
+ 
+         if (NILP (location))
+           it->area = TEXT_AREA;
+         else if (EQ (location, Qleft_margin))
+           it->area = LEFT_MARGIN_AREA;
+         else
+           it->area = RIGHT_MARGIN_AREA;
+ 
+         if (STRINGP (value))
+           {
+             it->string = value;
+             it->multibyte_p = STRING_MULTIBYTE (it->string);
+             it->current.overlay_string_index = -1;
+             IT_STRING_CHARPOS (*it) = IT_STRING_BYTEPOS (*it) = 0;
+             it->end_charpos = it->string_nchars = SCHARS (it->string);
+             it->method = next_element_from_string;
+             it->stop_charpos = 0;
+             it->string_from_display_prop_p = 1;
+             /* Say that we haven't consumed the characters with
+                `display' property yet.  The call to pop_it in
+                set_iterator_to_next will clean this up.  */
+             *position = start_pos;
+           }
+         else if (CONSP (value) && EQ (XCAR (value), Qspace))
+           {
+             it->method = next_element_from_stretch;
+             it->object = value;
+             it->current.pos = it->position = start_pos;
+           }
+ #ifdef HAVE_WINDOW_SYSTEM
+         else
+           {
+             it->what = IT_IMAGE;
+             it->image_id = lookup_image (it->f, value);
+             it->position = start_pos;
+             it->object = NILP (object) ? it->w->buffer : object;
+             it->method = next_element_from_image;
+ 
+             /* Say that we haven't consumed the characters with
+                `display' property yet.  The call to pop_it in
+                set_iterator_to_next will clean this up.  */
+             *position = start_pos;
+           }
+ #endif /* HAVE_WINDOW_SYSTEM */
+       }
+       else
+       /* Invalid property or property not supported.  Restore
+          the position to what it was before.  */
+       *position = start_pos;
+     }
+ 
+   return replaces_text_display_p;
+ }
+ 
+ 
+ /* Check if PROP is a display sub-property value whose text should be
+    treated as intangible.  */
+ 
+ static int
+ single_display_prop_intangible_p (prop)
+      Lisp_Object prop;
+ {
+   /* Skip over `when FORM'.  */
+   if (CONSP (prop) && EQ (XCAR (prop), Qwhen))
+     {
+       prop = XCDR (prop);
+       if (!CONSP (prop))
+       return 0;
+       prop = XCDR (prop);
+     }
+ 
+   if (STRINGP (prop))
+     return 1;
+ 
+   if (!CONSP (prop))
+     return 0;
+ 
+   /* Skip over `margin LOCATION'.  If LOCATION is in the margins,
+      we don't need to treat text as intangible.  */
+   if (EQ (XCAR (prop), Qmargin))
+     {
+       prop = XCDR (prop);
+       if (!CONSP (prop))
+       return 0;
+ 
+       prop = XCDR (prop);
+       if (!CONSP (prop)
+         || EQ (XCAR (prop), Qleft_margin)
+         || EQ (XCAR (prop), Qright_margin))
+       return 0;
+     }
+ 
+   return (CONSP (prop)
+         && (EQ (XCAR (prop), Qimage)
+             || EQ (XCAR (prop), Qspace)));
+ }
+ 
+ 
+ /* Check if PROP is a display property value whose text should be
+    treated as intangible.  */
+ 
+ int
+ display_prop_intangible_p (prop)
+      Lisp_Object prop;
+ {
+   if (CONSP (prop)
+       && CONSP (XCAR (prop))
+       && !EQ (Qmargin, XCAR (XCAR (prop))))
+     {
+       /* A list of sub-properties.  */
+       while (CONSP (prop))
+       {
+         if (single_display_prop_intangible_p (XCAR (prop)))
+           return 1;
+         prop = XCDR (prop);
+       }
+     }
+   else if (VECTORP (prop))
+     {
+       /* A vector of sub-properties.  */
+       int i;
+       for (i = 0; i < ASIZE (prop); ++i)
+       if (single_display_prop_intangible_p (AREF (prop, i)))
+         return 1;
+     }
+   else
+     return single_display_prop_intangible_p (prop);
+ 
+   return 0;
+ }
+ 
+ 
+ /* Return 1 if PROP is a display sub-property value containing STRING.  */
+ 
+ static int
+ single_display_prop_string_p (prop, string)
+      Lisp_Object prop, string;
+ {
+   if (EQ (string, prop))
+     return 1;
+ 
+   /* Skip over `when FORM'.  */
+   if (CONSP (prop) && EQ (XCAR (prop), Qwhen))
+     {
+       prop = XCDR (prop);
+       if (!CONSP (prop))
+       return 0;
+       prop = XCDR (prop);
+     }
+ 
+   if (CONSP (prop))
+     /* Skip over `margin LOCATION'.  */
+     if (EQ (XCAR (prop), Qmargin))
+       {
+       prop = XCDR (prop);
+       if (!CONSP (prop))
+         return 0;
+ 
+       prop = XCDR (prop);
+       if (!CONSP (prop))
+         return 0;
+       }
+ 
+   return CONSP (prop) && EQ (XCAR (prop), string);
+ }
+ 
+ 
+ /* Return 1 if STRING appears in the `display' property PROP.  */
+ 
+ static int
+ display_prop_string_p (prop, string)
+      Lisp_Object prop, string;
+ {
+   if (CONSP (prop)
+       && CONSP (XCAR (prop))
+       && !EQ (Qmargin, XCAR (XCAR (prop))))
+     {
+       /* A list of sub-properties.  */
+       while (CONSP (prop))
+       {
+         if (single_display_prop_string_p (XCAR (prop), string))
+           return 1;
+         prop = XCDR (prop);
+       }
+     }
+   else if (VECTORP (prop))
+     {
+       /* A vector of sub-properties.  */
+       int i;
+       for (i = 0; i < ASIZE (prop); ++i)
+       if (single_display_prop_string_p (AREF (prop, i), string))
+         return 1;
+     }
+   else
+     return single_display_prop_string_p (prop, string);
+ 
+   return 0;
+ }
+ 
+ 
+ /* Determine from which buffer position in W's buffer STRING comes
+    from.  AROUND_CHARPOS is an approximate position where it could
+    be from.  Value is the buffer position or 0 if it couldn't be
+    determined.
+ 
+    W's buffer must be current.
+ 
+    This function is necessary because we don't record buffer positions
+    in glyphs generated from strings (to keep struct glyph small).
+    This function may only use code that doesn't eval because it is
+    called asynchronously from note_mouse_highlight.  */
+ 
+ int
+ string_buffer_position (w, string, around_charpos)
+      struct window *w;
+      Lisp_Object string;
+      int around_charpos;
+ {
+   Lisp_Object limit, prop, pos;
+   const int MAX_DISTANCE = 1000;
+   int found = 0;
+ 
+   pos = make_number (around_charpos);
+   limit = make_number (min (XINT (pos) + MAX_DISTANCE, ZV));
+   while (!found && !EQ (pos, limit))
+     {
+       prop = Fget_char_property (pos, Qdisplay, Qnil);
+       if (!NILP (prop) && display_prop_string_p (prop, string))
+       found = 1;
+       else
+       pos = Fnext_single_char_property_change (pos, Qdisplay, Qnil, limit);
+     }
+ 
+   if (!found)
+     {
+       pos = make_number (around_charpos);
+       limit = make_number (max (XINT (pos) - MAX_DISTANCE, BEGV));
+       while (!found && !EQ (pos, limit))
+       {
+         prop = Fget_char_property (pos, Qdisplay, Qnil);
+         if (!NILP (prop) && display_prop_string_p (prop, string))
+           found = 1;
+         else
+           pos = Fprevious_single_char_property_change (pos, Qdisplay, Qnil,
+                                                        limit);
+       }
+     }
+ 
+   return found ? XINT (pos) : 0;
+ }
+ 
+ 
+ 
+ /***********************************************************************
+                       `composition' property
+  ***********************************************************************/
+ 
+ static enum prop_handled
+ handle_auto_composed_prop (it)
+      struct it *it;
+ {
+   enum prop_handled handled = HANDLED_NORMALLY;
+ 
+   if (! NILP (Vauto_composition_function))
+     {
+       Lisp_Object val;
+       int pos;
+ 
+       if (STRINGP (it->string))
+       pos = IT_STRING_CHARPOS (*it);
+       else
+       pos = IT_CHARPOS (*it);
+ 
+       val =Fget_char_property (make_number (pos), Qauto_composed, it->string);
+       if (NILP (val))
+       {
+         int count = SPECPDL_INDEX ();
+         Lisp_Object args[3];
+ 
+         args[0] = Vauto_composition_function;
+         specbind (Qauto_composition_function, Qnil);
+         args[1] = make_number (pos);
+         args[2] = it->string;
+         safe_call (3, args);
+         unbind_to (count, Qnil);
+ 
+         val = Fget_char_property (args[1], Qauto_composed, it->string);
+         if (! NILP (val))
+           handled = HANDLED_RECOMPUTE_PROPS;
+       }
+     }
+ 
+   return handled;
+ }
+ 
+ /* Set up iterator IT from `composition' property at its current
+    position.  Called from handle_stop.  */
+ 
+ static enum prop_handled
+ handle_composition_prop (it)
+      struct it *it;
+ {
+   Lisp_Object prop, string;
+   int pos, pos_byte, end;
+   enum prop_handled handled = HANDLED_NORMALLY;
+ 
+   if (STRINGP (it->string))
+     {
+       pos = IT_STRING_CHARPOS (*it);
+       pos_byte = IT_STRING_BYTEPOS (*it);
+       string = it->string;
+     }
+   else
+     {
+       pos = IT_CHARPOS (*it);
+       pos_byte = IT_BYTEPOS (*it);
+       string = Qnil;
+     }
+ 
+   /* If there's a valid composition and point is not inside of the
+      composition (in the case that the composition is from the current
+      buffer), draw a glyph composed from the composition components.  */
+   if (find_composition (pos, -1, &pos, &end, &prop, string)
+       && COMPOSITION_VALID_P (pos, end, prop)
+       && (STRINGP (it->string) || (PT <= pos || PT >= end)))
+     {
+       int id = get_composition_id (pos, pos_byte, end - pos, prop, string);
+ 
+       if (id >= 0)
+       {
+         it->method = next_element_from_composition;
+         it->cmp_id = id;
+         it->cmp_len = COMPOSITION_LENGTH (prop);
+         /* For a terminal, draw only the first character of the
+              components.  */
+         it->c = COMPOSITION_GLYPH (composition_table[id], 0);
+         it->len = (STRINGP (it->string)
+                    ? string_char_to_byte (it->string, end)
+                    : CHAR_TO_BYTE (end)) - pos_byte;
+         it->stop_charpos = end;
+         handled = HANDLED_RETURN;
+       }
+     }
+ 
+   return handled;
+ }
+ 
+ 
+ 
+ /***********************************************************************
+                          Overlay strings
+  ***********************************************************************/
+ 
+ /* The following structure is used to record overlay strings for
+    later sorting in load_overlay_strings.  */
+ 
+ struct overlay_entry
+ {
+   Lisp_Object overlay;
+   Lisp_Object string;
+   int priority;
+   int after_string_p;
+ };
+ 
+ 
+ /* Set up iterator IT from overlay strings at its current position.
+    Called from handle_stop.  */
+ 
+ static enum prop_handled
+ handle_overlay_change (it)
+      struct it *it;
+ {
+   if (!STRINGP (it->string) && get_overlay_strings (it, 0))
+     return HANDLED_RECOMPUTE_PROPS;
+   else
+     return HANDLED_NORMALLY;
+ }
+ 
+ 
+ /* Set up the next overlay string for delivery by IT, if there is an
+    overlay string to deliver.  Called by set_iterator_to_next when the
+    end of the current overlay string is reached.  If there are more
+    overlay strings to display, IT->string and
+    IT->current.overlay_string_index are set appropriately here.
+    Otherwise IT->string is set to nil.  */
+ 
+ static void
+ next_overlay_string (it)
+      struct it *it;
+ {
+   ++it->current.overlay_string_index;
+   if (it->current.overlay_string_index == it->n_overlay_strings)
+     {
+       /* No more overlay strings.  Restore IT's settings to what
+        they were before overlay strings were processed, and
+        continue to deliver from current_buffer.  */
+       int display_ellipsis_p = it->stack[it->sp - 1].display_ellipsis_p;
+ 
+       pop_it (it);
+       xassert (it->stop_charpos >= BEGV
+              && it->stop_charpos <= it->end_charpos);
+       it->string = Qnil;
+       it->current.overlay_string_index = -1;
+       SET_TEXT_POS (it->current.string_pos, -1, -1);
+       it->n_overlay_strings = 0;
+       it->method = next_element_from_buffer;
+ 
+       /* If we're at the end of the buffer, record that we have
+        processed the overlay strings there already, so that
+        next_element_from_buffer doesn't try it again.  */
+       if (IT_CHARPOS (*it) >= it->end_charpos)
+       it->overlay_strings_at_end_processed_p = 1;
+ 
+       /* If we have to display `...' for invisible text, set
+        the iterator up for that.  */
+       if (display_ellipsis_p)
+       setup_for_ellipsis (it);
+     }
+   else
+     {
+       /* There are more overlay strings to process.  If
+        IT->current.overlay_string_index has advanced to a position
+        where we must load IT->overlay_strings with more strings, do
+        it.  */
+       int i = it->current.overlay_string_index % OVERLAY_STRING_CHUNK_SIZE;
+ 
+       if (it->current.overlay_string_index && i == 0)
+       load_overlay_strings (it, 0);
+ 
+       /* Initialize IT to deliver display elements from the overlay
+          string.  */
+       it->string = it->overlay_strings[i];
+       it->multibyte_p = STRING_MULTIBYTE (it->string);
+       SET_TEXT_POS (it->current.string_pos, 0, 0);
+       it->method = next_element_from_string;
+       it->stop_charpos = 0;
+     }
+ 
+   CHECK_IT (it);
+ }
+ 
+ 
+ /* Compare two overlay_entry structures E1 and E2.  Used as a
+    comparison function for qsort in load_overlay_strings.  Overlay
+    strings for the same position are sorted so that
+ 
+    1. All after-strings come in front of before-strings, except
+    when they come from the same overlay.
+ 
+    2. Within after-strings, strings are sorted so that overlay strings
+    from overlays with higher priorities come first.
+ 
+    2. Within before-strings, strings are sorted so that overlay
+    strings from overlays with higher priorities come last.
+ 
+    Value is analogous to strcmp.  */
+ 
+ 
+ static int
+ compare_overlay_entries (e1, e2)
+      void *e1, *e2;
+ {
+   struct overlay_entry *entry1 = (struct overlay_entry *) e1;
+   struct overlay_entry *entry2 = (struct overlay_entry *) e2;
+   int result;
+ 
+   if (entry1->after_string_p != entry2->after_string_p)
+     {
+       /* Let after-strings appear in front of before-strings if
+        they come from different overlays.  */
+       if (EQ (entry1->overlay, entry2->overlay))
+       result = entry1->after_string_p ? 1 : -1;
+       else
+       result = entry1->after_string_p ? -1 : 1;
+     }
+   else if (entry1->after_string_p)
+     /* After-strings sorted in order of decreasing priority.  */
+     result = entry2->priority - entry1->priority;
+   else
+     /* Before-strings sorted in order of increasing priority.  */
+     result = entry1->priority - entry2->priority;
+ 
+   return result;
+ }
+ 
+ 
+ /* Load the vector IT->overlay_strings with overlay strings from IT's
+    current buffer position, or from CHARPOS if that is > 0.  Set
+    IT->n_overlays to the total number of overlay strings found.
+ 
+    Overlay strings are processed OVERLAY_STRING_CHUNK_SIZE strings at
+    a time.  On entry into load_overlay_strings,
+    IT->current.overlay_string_index gives the number of overlay
+    strings that have already been loaded by previous calls to this
+    function.
+ 
+    IT->add_overlay_start contains an additional overlay start
+    position to consider for taking overlay strings from, if non-zero.
+    This position comes into play when the overlay has an `invisible'
+    property, and both before and after-strings.  When we've skipped to
+    the end of the overlay, because of its `invisible' property, we
+    nevertheless want its before-string to appear.
+    IT->add_overlay_start will contain the overlay start position
+    in this case.
+ 
+    Overlay strings are sorted so that after-string strings come in
+    front of before-string strings.  Within before and after-strings,
+    strings are sorted by overlay priority.  See also function
+    compare_overlay_entries.  */
+ 
+ static void
+ load_overlay_strings (it, charpos)
+      struct it *it;
+      int charpos;
+ {
+   extern Lisp_Object Qafter_string, Qbefore_string, Qwindow, Qpriority;
+   Lisp_Object overlay, window, str, invisible;
+   struct Lisp_Overlay *ov;
+   int start, end;
+   int size = 20;
+   int n = 0, i, j, invis_p;
+   struct overlay_entry *entries
+     = (struct overlay_entry *) alloca (size * sizeof *entries);
+ 
+   if (charpos <= 0)
+     charpos = IT_CHARPOS (*it);
+ 
+   /* Append the overlay string STRING of overlay OVERLAY to vector
+      `entries' which has size `size' and currently contains `n'
+      elements.  AFTER_P non-zero means STRING is an after-string of
+      OVERLAY.  */
+ #define RECORD_OVERLAY_STRING(OVERLAY, STRING, AFTER_P)                       
\
+   do                                                                  \
+     {                                                                 \
+       Lisp_Object priority;                                           \
+                                                                       \
+       if (n == size)                                                  \
+       {                                                               \
+         int new_size = 2 * size;                                      \
+         struct overlay_entry *old = entries;                          \
+         entries =                                                     \
+             (struct overlay_entry *) alloca (new_size                 \
+                                            * sizeof *entries);        \
+         bcopy (old, entries, size * sizeof *entries);                 \
+         size = new_size;                                              \
+       }                                                               \
+                                                                       \
+       entries[n].string = (STRING);                                   \
+       entries[n].overlay = (OVERLAY);                                 \
+       priority = Foverlay_get ((OVERLAY), Qpriority);                 \
+       entries[n].priority = INTEGERP (priority) ? XINT (priority) : 0;  \
+       entries[n].after_string_p = (AFTER_P);                          \
+       ++n;                                                            \
+     }                                                                 \
+   while (0)
+ 
+   /* Process overlay before the overlay center.  */
+   for (ov = current_buffer->overlays_before; ov; ov = ov->next)
+     {
+       XSETMISC (overlay, ov);
+       xassert (OVERLAYP (overlay));
+       start = OVERLAY_POSITION (OVERLAY_START (overlay));
+       end = OVERLAY_POSITION (OVERLAY_END (overlay));
+ 
+       if (end < charpos)
+       break;
+ 
+       /* Skip this overlay if it doesn't start or end at IT's current
+        position.  */
+       if (end != charpos && start != charpos)
+       continue;
+ 
+       /* Skip this overlay if it doesn't apply to IT->w.  */
+       window = Foverlay_get (overlay, Qwindow);
+       if (WINDOWP (window) && XWINDOW (window) != it->w)
+       continue;
+ 
+       /* If the text ``under'' the overlay is invisible, both before-
+        and after-strings from this overlay are visible; start and
+        end position are indistinguishable.  */
+       invisible = Foverlay_get (overlay, Qinvisible);
+       invis_p = TEXT_PROP_MEANS_INVISIBLE (invisible);
+ 
+       /* If overlay has a non-empty before-string, record it.  */
+       if ((start == charpos || (end == charpos && invis_p))
+         && (str = Foverlay_get (overlay, Qbefore_string), STRINGP (str))
+         && SCHARS (str))
+       RECORD_OVERLAY_STRING (overlay, str, 0);
+ 
+       /* If overlay has a non-empty after-string, record it.  */
+       if ((end == charpos || (start == charpos && invis_p))
+         && (str = Foverlay_get (overlay, Qafter_string), STRINGP (str))
+         && SCHARS (str))
+       RECORD_OVERLAY_STRING (overlay, str, 1);
+     }
+ 
+   /* Process overlays after the overlay center.  */
+   for (ov = current_buffer->overlays_after; ov; ov = ov->next)
+     {
+       XSETMISC (overlay, ov);
+       xassert (OVERLAYP (overlay));
+       start = OVERLAY_POSITION (OVERLAY_START (overlay));
+       end = OVERLAY_POSITION (OVERLAY_END (overlay));
+ 
+       if (start > charpos)
+       break;
+ 
+       /* Skip this overlay if it doesn't start or end at IT's current
+        position.  */
+       if (end != charpos && start != charpos)
+       continue;
+ 
+       /* Skip this overlay if it doesn't apply to IT->w.  */
+       window = Foverlay_get (overlay, Qwindow);
+       if (WINDOWP (window) && XWINDOW (window) != it->w)
+       continue;
+ 
+       /* If the text ``under'' the overlay is invisible, it has a zero
+        dimension, and both before- and after-strings apply.  */
+       invisible = Foverlay_get (overlay, Qinvisible);
+       invis_p = TEXT_PROP_MEANS_INVISIBLE (invisible);
+ 
+       /* If overlay has a non-empty before-string, record it.  */
+       if ((start == charpos || (end == charpos && invis_p))
+         && (str = Foverlay_get (overlay, Qbefore_string), STRINGP (str))
+         && SCHARS (str))
+       RECORD_OVERLAY_STRING (overlay, str, 0);
+ 
+       /* If overlay has a non-empty after-string, record it.  */
+       if ((end == charpos || (start == charpos && invis_p))
+         && (str = Foverlay_get (overlay, Qafter_string), STRINGP (str))
+         && SCHARS (str))
+       RECORD_OVERLAY_STRING (overlay, str, 1);
+     }
+ 
+ #undef RECORD_OVERLAY_STRING
+ 
+   /* Sort entries.  */
+   if (n > 1)
+     qsort (entries, n, sizeof *entries, compare_overlay_entries);
+ 
+   /* Record the total number of strings to process.  */
+   it->n_overlay_strings = n;
+ 
+   /* IT->current.overlay_string_index is the number of overlay strings
+      that have already been consumed by IT.  Copy some of the
+      remaining overlay strings to IT->overlay_strings.  */
+   i = 0;
+   j = it->current.overlay_string_index;
+   while (i < OVERLAY_STRING_CHUNK_SIZE && j < n)
+     it->overlay_strings[i++] = entries[j++].string;
+ 
+   CHECK_IT (it);
+ }
+ 
+ 
+ /* Get the first chunk of overlay strings at IT's current buffer
+    position, or at CHARPOS if that is > 0.  Value is non-zero if at
+    least one overlay string was found.  */
+ 
+ static int
+ get_overlay_strings (it, charpos)
+      struct it *it;
+      int charpos;
+ {
+   /* Get the first OVERLAY_STRING_CHUNK_SIZE overlay strings to
+      process.  This fills IT->overlay_strings with strings, and sets
+      IT->n_overlay_strings to the total number of strings to process.
+      IT->pos.overlay_string_index has to be set temporarily to zero
+      because load_overlay_strings needs this; it must be set to -1
+      when no overlay strings are found because a zero value would
+      indicate a position in the first overlay string.  */
+   it->current.overlay_string_index = 0;
+   load_overlay_strings (it, charpos);
+ 
+   /* If we found overlay strings, set up IT to deliver display
+      elements from the first one.  Otherwise set up IT to deliver
+      from current_buffer.  */
+   if (it->n_overlay_strings)
+     {
+       /* Make sure we know settings in current_buffer, so that we can
+        restore meaningful values when we're done with the overlay
+        strings.  */
+       compute_stop_pos (it);
+       xassert (it->face_id >= 0);
+ 
+       /* Save IT's settings.  They are restored after all overlay
+        strings have been processed.  */
+       xassert (it->sp == 0);
+       push_it (it);
+ 
+       /* Set up IT to deliver display elements from the first overlay
+        string.  */
+       IT_STRING_CHARPOS (*it) = IT_STRING_BYTEPOS (*it) = 0;
+       it->string = it->overlay_strings[0];
+       it->stop_charpos = 0;
+       xassert (STRINGP (it->string));
+       it->end_charpos = SCHARS (it->string);
+       it->multibyte_p = STRING_MULTIBYTE (it->string);
+       it->method = next_element_from_string;
+     }
+   else
+     {
+       it->string = Qnil;
+       it->current.overlay_string_index = -1;
+       it->method = next_element_from_buffer;
+     }
+ 
+   CHECK_IT (it);
+ 
+   /* Value is non-zero if we found at least one overlay string.  */
+   return STRINGP (it->string);
+ }
+ 
+ 
+ 
+ /***********************************************************************
+                     Saving and restoring state
+  ***********************************************************************/
+ 
+ /* Save current settings of IT on IT->stack.  Called, for example,
+    before setting up IT for an overlay string, to be able to restore
+    IT's settings to what they were after the overlay string has been
+    processed.  */
+ 
+ static void
+ push_it (it)
+      struct it *it;
+ {
+   struct iterator_stack_entry *p;
+ 
+   xassert (it->sp < 2);
+   p = it->stack + it->sp;
+ 
+   p->stop_charpos = it->stop_charpos;
+   xassert (it->face_id >= 0);
+   p->face_id = it->face_id;
+   p->string = it->string;
+   p->pos = it->current;
+   p->end_charpos = it->end_charpos;
+   p->string_nchars = it->string_nchars;
+   p->area = it->area;
+   p->multibyte_p = it->multibyte_p;
+   p->space_width = it->space_width;
+   p->font_height = it->font_height;
+   p->voffset = it->voffset;
+   p->string_from_display_prop_p = it->string_from_display_prop_p;
+   p->display_ellipsis_p = 0;
+   ++it->sp;
+ }
+ 
+ 
+ /* Restore IT's settings from IT->stack.  Called, for example, when no
+    more overlay strings must be processed, and we return to delivering
+    display elements from a buffer, or when the end of a string from a
+    `display' property is reached and we return to delivering display
+    elements from an overlay string, or from a buffer.  */
+ 
+ static void
+ pop_it (it)
+      struct it *it;
+ {
+   struct iterator_stack_entry *p;
+ 
+   xassert (it->sp > 0);
+   --it->sp;
+   p = it->stack + it->sp;
+   it->stop_charpos = p->stop_charpos;
+   it->face_id = p->face_id;
+   it->string = p->string;
+   it->current = p->pos;
+   it->end_charpos = p->end_charpos;
+   it->string_nchars = p->string_nchars;
+   it->area = p->area;
+   it->multibyte_p = p->multibyte_p;
+   it->space_width = p->space_width;
+   it->font_height = p->font_height;
+   it->voffset = p->voffset;
+   it->string_from_display_prop_p = p->string_from_display_prop_p;
+ }
+ 
+ 
+ 
+ /***********************************************************************
+                         Moving over lines
+  ***********************************************************************/
+ 
+ /* Set IT's current position to the previous line start.  */
+ 
+ static void
+ back_to_previous_line_start (it)
+      struct it *it;
+ {
+   IT_CHARPOS (*it) = find_next_newline_no_quit (IT_CHARPOS (*it) - 1, -1);
+   IT_BYTEPOS (*it) = CHAR_TO_BYTE (IT_CHARPOS (*it));
+ }
+ 
+ 
+ /* Move IT to the next line start.
+ 
+    Value is non-zero if a newline was found.  Set *SKIPPED_P to 1 if
+    we skipped over part of the text (as opposed to moving the iterator
+    continuously over the text).  Otherwise, don't change the value
+    of *SKIPPED_P.
+ 
+    Newlines may come from buffer text, overlay strings, or strings
+    displayed via the `display' property.  That's the reason we can't
+    simply use find_next_newline_no_quit.
+ 
+    Note that this function may not skip over invisible text that is so
+    because of text properties and immediately follows a newline.  If
+    it would, function reseat_at_next_visible_line_start, when called
+    from set_iterator_to_next, would effectively make invisible
+    characters following a newline part of the wrong glyph row, which
+    leads to wrong cursor motion.  */
+ 
+ static int
+ forward_to_next_line_start (it, skipped_p)
+      struct it *it;
+      int *skipped_p;
+ {
+   int old_selective, newline_found_p, n;
+   const int MAX_NEWLINE_DISTANCE = 500;
+ 
+   /* If already on a newline, just consume it to avoid unintended
+      skipping over invisible text below.  */
+   if (it->what == IT_CHARACTER
+       && it->c == '\n'
+       && CHARPOS (it->position) == IT_CHARPOS (*it))
+     {
+       set_iterator_to_next (it, 0);
+       it->c = 0;
+       return 1;
+     }
+ 
+   /* Don't handle selective display in the following.  It's (a)
+      unnecessary because it's done by the caller, and (b) leads to an
+      infinite recursion because next_element_from_ellipsis indirectly
+      calls this function.  */
+   old_selective = it->selective;
+   it->selective = 0;
+ 
+   /* Scan for a newline within MAX_NEWLINE_DISTANCE display elements
+      from buffer text.  */
+   for (n = newline_found_p = 0;
+        !newline_found_p && n < MAX_NEWLINE_DISTANCE;
+        n += STRINGP (it->string) ? 0 : 1)
+     {
+       if (!get_next_display_element (it))
+       return 0;
+       newline_found_p = it->what == IT_CHARACTER && it->c == '\n';
+       set_iterator_to_next (it, 0);
+     }
+ 
+   /* If we didn't find a newline near enough, see if we can use a
+      short-cut.  */
+   if (!newline_found_p)
+     {
+       int start = IT_CHARPOS (*it);
+       int limit = find_next_newline_no_quit (start, 1);
+       Lisp_Object pos;
+ 
+       xassert (!STRINGP (it->string));
+ 
+       /* If there isn't any `display' property in sight, and no
+        overlays, we can just use the position of the newline in
+        buffer text.  */
+       if (it->stop_charpos >= limit
+         || ((pos = Fnext_single_property_change (make_number (start),
+                                                  Qdisplay,
+                                                  Qnil, make_number (limit)),
+              NILP (pos))
+             && next_overlay_change (start) == ZV))
+       {
+         IT_CHARPOS (*it) = limit;
+         IT_BYTEPOS (*it) = CHAR_TO_BYTE (limit);
+         *skipped_p = newline_found_p = 1;
+       }
+       else
+       {
+         while (get_next_display_element (it)
+                && !newline_found_p)
+           {
+             newline_found_p = ITERATOR_AT_END_OF_LINE_P (it);
+             set_iterator_to_next (it, 0);
+           }
+       }
+     }
+ 
+   it->selective = old_selective;
+   return newline_found_p;
+ }
+ 
+ 
+ /* Set IT's current position to the previous visible line start.  Skip
+    invisible text that is so either due to text properties or due to
+    selective display.  Caution: this does not change IT->current_x and
+    IT->hpos.  */
+ 
+ static void
+ back_to_previous_visible_line_start (it)
+      struct it *it;
+ {
+   int visible_p = 0;
+ 
+   /* Go back one newline if not on BEGV already.  */
+   if (IT_CHARPOS (*it) > BEGV)
+     back_to_previous_line_start (it);
+ 
+   /* Move over lines that are invisible because of selective display
+      or text properties.  */
+   while (IT_CHARPOS (*it) > BEGV
+        && !visible_p)
+     {
+       visible_p = 1;
+ 
+       /* If selective > 0, then lines indented more than that values
+        are invisible.  */
+       if (it->selective > 0
+         && indented_beyond_p (IT_CHARPOS (*it), IT_BYTEPOS (*it),
+                               (double) it->selective)) /* iftc */
+       visible_p = 0;
+       else
+       {
+         Lisp_Object prop;
+ 
+         prop = Fget_char_property (make_number (IT_CHARPOS (*it)),
+                                    Qinvisible, it->window);
+         if (TEXT_PROP_MEANS_INVISIBLE (prop))
+           visible_p = 0;
+       }
+ 
+       /* Back one more newline if the current one is invisible.  */
+       if (!visible_p)
+       back_to_previous_line_start (it);
+     }
+ 
+   xassert (IT_CHARPOS (*it) >= BEGV);
+   xassert (IT_CHARPOS (*it) == BEGV
+          || FETCH_BYTE (IT_BYTEPOS (*it) - 1) == '\n');
+   CHECK_IT (it);
+ }
+ 
+ 
+ /* Reseat iterator IT at the previous visible line start.  Skip
+    invisible text that is so either due to text properties or due to
+    selective display.  At the end, update IT's overlay information,
+    face information etc.  */
+ 
+ static void
+ reseat_at_previous_visible_line_start (it)
+      struct it *it;
+ {
+   back_to_previous_visible_line_start (it);
+   reseat (it, it->current.pos, 1);
+   CHECK_IT (it);
+ }
+ 
+ 
+ /* Reseat iterator IT on the next visible line start in the current
+    buffer.  ON_NEWLINE_P non-zero means position IT on the newline
+    preceding the line start.  Skip over invisible text that is so
+    because of selective display.  Compute faces, overlays etc at the
+    new position.  Note that this function does not skip over text that
+    is invisible because of text properties.  */
+ 
+ static void
+ reseat_at_next_visible_line_start (it, on_newline_p)
+      struct it *it;
+      int on_newline_p;
+ {
+   int newline_found_p, skipped_p = 0;
+ 
+   newline_found_p = forward_to_next_line_start (it, &skipped_p);
+ 
+   /* Skip over lines that are invisible because they are indented
+      more than the value of IT->selective.  */
+   if (it->selective > 0)
+     while (IT_CHARPOS (*it) < ZV
+          && indented_beyond_p (IT_CHARPOS (*it), IT_BYTEPOS (*it),
+                                (double) it->selective)) /* iftc */
+       {
+       xassert (FETCH_BYTE (IT_BYTEPOS (*it) - 1) == '\n');
+       newline_found_p = forward_to_next_line_start (it, &skipped_p);
+       }
+ 
+   /* Position on the newline if that's what's requested.  */
+   if (on_newline_p && newline_found_p)
+     {
+       if (STRINGP (it->string))
+       {
+         if (IT_STRING_CHARPOS (*it) > 0)
+           {
+             --IT_STRING_CHARPOS (*it);
+             --IT_STRING_BYTEPOS (*it);
+           }
+       }
+       else if (IT_CHARPOS (*it) > BEGV)
+       {
+         --IT_CHARPOS (*it);
+         --IT_BYTEPOS (*it);
+         reseat (it, it->current.pos, 0);
+       }
+     }
+   else if (skipped_p)
+     reseat (it, it->current.pos, 0);
+ 
+   CHECK_IT (it);
+ }
+ 
+ 
+ 
+ /***********************************************************************
+                  Changing an iterator's position
+ ***********************************************************************/
+ 
+ /* Change IT's current position to POS in current_buffer.  If FORCE_P
+    is non-zero, always check for text properties at the new position.
+    Otherwise, text properties are only looked up if POS >=
+    IT->check_charpos of a property.  */
+ 
+ static void
+ reseat (it, pos, force_p)
+      struct it *it;
+      struct text_pos pos;
+      int force_p;
+ {
+   int original_pos = IT_CHARPOS (*it);
+ 
+   reseat_1 (it, pos, 0);
+ 
+   /* Determine where to check text properties.  Avoid doing it
+      where possible because text property lookup is very expensive.  */
+   if (force_p
+       || CHARPOS (pos) > it->stop_charpos
+       || CHARPOS (pos) < original_pos)
+     handle_stop (it);
+ 
+   CHECK_IT (it);
+ }
+ 
+ 
+ /* Change IT's buffer position to POS.  SET_STOP_P non-zero means set
+    IT->stop_pos to POS, also.  */
+ 
+ static void
+ reseat_1 (it, pos, set_stop_p)
+      struct it *it;
+      struct text_pos pos;
+      int set_stop_p;
+ {
+   /* Don't call this function when scanning a C string.  */
+   xassert (it->s == NULL);
+ 
+   /* POS must be a reasonable value.  */
+   xassert (CHARPOS (pos) >= BEGV && CHARPOS (pos) <= ZV);
+ 
+   it->current.pos = it->position = pos;
+   XSETBUFFER (it->object, current_buffer);
+   it->end_charpos = ZV;
+   it->dpvec = NULL;
+   it->current.dpvec_index = -1;
+   it->current.overlay_string_index = -1;
+   IT_STRING_CHARPOS (*it) = -1;
+   IT_STRING_BYTEPOS (*it) = -1;
+   it->string = Qnil;
+   it->method = next_element_from_buffer;
+   /* RMS: I added this to fix a bug in move_it_vertically_backward
+      where it->area continued to relate to the starting point
+      for the backward motion.  Bug report from
+      Nick Roberts <address@hidden> on 19 May 2003.
+      However, I am not sure whether reseat still does the right thing
+      in general after this change.  */
+   it->area = TEXT_AREA;
+   it->multibyte_p = !NILP (current_buffer->enable_multibyte_characters);
+   it->sp = 0;
+   it->face_before_selective_p = 0;
+ 
+   if (set_stop_p)
+     it->stop_charpos = CHARPOS (pos);
+ }
+ 
+ 
+ /* Set up IT for displaying a string, starting at CHARPOS in window W.
+    If S is non-null, it is a C string to iterate over.  Otherwise,
+    STRING gives a Lisp string to iterate over.
+ 
+    If PRECISION > 0, don't return more then PRECISION number of
+    characters from the string.
+ 
+    If FIELD_WIDTH > 0, return padding spaces until FIELD_WIDTH
+    characters have been returned.  FIELD_WIDTH < 0 means an infinite
+    field width.
+ 
+    MULTIBYTE = 0 means disable processing of multibyte characters,
+    MULTIBYTE > 0 means enable it,
+    MULTIBYTE < 0 means use IT->multibyte_p.
+ 
+    IT must be initialized via a prior call to init_iterator before
+    calling this function.  */
+ 
+ static void
+ reseat_to_string (it, s, string, charpos, precision, field_width, multibyte)
+      struct it *it;
+      unsigned char *s;
+      Lisp_Object string;
+      int charpos;
+      int precision, field_width, multibyte;
+ {
+   /* No region in strings.  */
+   it->region_beg_charpos = it->region_end_charpos = -1;
+ 
+   /* No text property checks performed by default, but see below.  */
+   it->stop_charpos = -1;
+ 
+   /* Set iterator position and end position.  */
+   bzero (&it->current, sizeof it->current);
+   it->current.overlay_string_index = -1;
+   it->current.dpvec_index = -1;
+   xassert (charpos >= 0);
+ 
+   /* If STRING is specified, use its multibyteness, otherwise use the
+      setting of MULTIBYTE, if specified.  */
+   if (multibyte >= 0)
+     it->multibyte_p = multibyte > 0;
+ 
+   if (s == NULL)
+     {
+       xassert (STRINGP (string));
+       it->string = string;
+       it->s = NULL;
+       it->end_charpos = it->string_nchars = SCHARS (string);
+       it->method = next_element_from_string;
+       it->current.string_pos = string_pos (charpos, string);
+     }
+   else
+     {
+       it->s = s;
+       it->string = Qnil;
+ 
+       /* Note that we use IT->current.pos, not it->current.string_pos,
+        for displaying C strings.  */
+       IT_STRING_CHARPOS (*it) = IT_STRING_BYTEPOS (*it) = -1;
+       if (it->multibyte_p)
+       {
+         it->current.pos = c_string_pos (charpos, s, 1);
+         it->end_charpos = it->string_nchars = number_of_chars (s, 1);
+       }
+       else
+       {
+         IT_CHARPOS (*it) = IT_BYTEPOS (*it) = charpos;
+         it->end_charpos = it->string_nchars = strlen (s);
+       }
+ 
+       it->method = next_element_from_c_string;
+     }
+ 
+   /* PRECISION > 0 means don't return more than PRECISION characters
+      from the string.  */
+   if (precision > 0 && it->end_charpos - charpos > precision)
+     it->end_charpos = it->string_nchars = charpos + precision;
+ 
+   /* FIELD_WIDTH > 0 means pad with spaces until FIELD_WIDTH
+      characters have been returned.  FIELD_WIDTH == 0 means don't pad,
+      FIELD_WIDTH < 0 means infinite field width.  This is useful for
+      padding with `-' at the end of a mode line.  */
+   if (field_width < 0)
+     field_width = INFINITY;
+   if (field_width > it->end_charpos - charpos)
+     it->end_charpos = charpos + field_width;
+ 
+   /* Use the standard display table for displaying strings.  */
+   if (DISP_TABLE_P (Vstandard_display_table))
+     it->dp = XCHAR_TABLE (Vstandard_display_table);
+ 
+   it->stop_charpos = charpos;
+   CHECK_IT (it);
+ }
+ 
+ 
+ 
+ /***********************************************************************
+                             Iteration
+  ***********************************************************************/
+ 
+ /* Load IT's display element fields with information about the next
+    display element from the current position of IT.  Value is zero if
+    end of buffer (or C string) is reached.  */
+ 
+ int
+ get_next_display_element (it)
+      struct it *it;
+ {
+   /* Non-zero means that we found a display element.  Zero means that
+      we hit the end of what we iterate over.  Performance note: the
+      function pointer `method' used here turns out to be faster than
+      using a sequence of if-statements.  */
+   int success_p = (*it->method) (it);
+ 
+   if (it->what == IT_CHARACTER)
+     {
+       /* Map via display table or translate control characters.
+        IT->c, IT->len etc. have been set to the next character by
+        the function call above.  If we have a display table, and it
+        contains an entry for IT->c, translate it.  Don't do this if
+        IT->c itself comes from a display table, otherwise we could
+        end up in an infinite recursion.  (An alternative could be to
+        count the recursion depth of this function and signal an
+        error when a certain maximum depth is reached.)  Is it worth
+        it?  */
+       if (success_p && it->dpvec == NULL)
+       {
+         Lisp_Object dv;
+ 
+         if (it->dp
+             && (dv = DISP_CHAR_VECTOR (it->dp, it->c),
+                 VECTORP (dv)))
+           {
+             struct Lisp_Vector *v = XVECTOR (dv);
+ 
+             /* Return the first character from the display table
+                entry, if not empty.  If empty, don't display the
+                current character.  */
+             if (v->size)
+               {
+                 it->dpvec_char_len = it->len;
+                 it->dpvec = v->contents;
+                 it->dpend = v->contents + v->size;
+                 it->current.dpvec_index = 0;
+                 it->method = next_element_from_display_vector;
+                 success_p = get_next_display_element (it);
+               }
+             else
+               {
+                 set_iterator_to_next (it, 0);
+                 success_p = get_next_display_element (it);
+               }
+           }
+ 
+         /* Translate control characters into `\003' or `^C' form.
+            Control characters coming from a display table entry are
+            currently not translated because we use IT->dpvec to hold
+            the translation.  This could easily be changed but I
+            don't believe that it is worth doing.
+ 
+            If it->multibyte_p is nonzero, eight-bit characters and
+            non-printable multibyte characters are also translated to
+            octal form.
+ 
+            If it->multibyte_p is zero, eight-bit characters that
+            don't have corresponding multibyte char code are also
+            translated to octal form.  */
+         else if ((it->c < ' '
+                   && (it->area != TEXT_AREA
+                       || (it->c != '\n' && it->c != '\t')))
+                  || (it->c != '\n' && it->c != '\t'
+                      && (it->multibyte_p ? !CHAR_PRINTABLE_P (it->c)
+                          : it->c == 127)))
+           {
+             /* IT->c is a control character which must be displayed
+                either as '\003' or as `^C' where the '\\' and '^'
+                can be defined in the display table.  Fill
+                IT->ctl_chars with glyphs for what we have to
+                display.  Then, set IT->dpvec to these glyphs.  */
+             GLYPH g;
+ 
+             if (it->c < 128 && it->ctl_arrow_p)
+               {
+                 /* Set IT->ctl_chars[0] to the glyph for `^'.  */
+                 if (it->dp
+                     && INTEGERP (DISP_CTRL_GLYPH (it->dp))
+                     && GLYPH_CHAR_VALID_P (XINT (DISP_CTRL_GLYPH (it->dp))))
+                   g = XINT (DISP_CTRL_GLYPH (it->dp));
+                 else
+                   g = FAST_MAKE_GLYPH ('^', 0);
+                 XSETINT (it->ctl_chars[0], g);
+ 
+                 g = FAST_MAKE_GLYPH (it->c ^ 0100, 0);
+                 XSETINT (it->ctl_chars[1], g);
+ 
+                 /* Set up IT->dpvec and return first character from it.  */
+                 it->dpvec_char_len = it->len;
+                 it->dpvec = it->ctl_chars;
+                 it->dpend = it->dpvec + 2;
+                 it->current.dpvec_index = 0;
+                 it->method = next_element_from_display_vector;
+                 get_next_display_element (it);
+               }
+             else
+               {
+                 unsigned char str[MAX_MULTIBYTE_LENGTH];
+                 int len;
+                 int i;
+                 GLYPH escape_glyph;
+ 
+                 /* Set IT->ctl_chars[0] to the glyph for `\\'.  */
+                 if (it->dp
+                     && INTEGERP (DISP_ESCAPE_GLYPH (it->dp))
+                     && GLYPH_CHAR_VALID_P (XFASTINT (DISP_ESCAPE_GLYPH 
(it->dp))))
+                   escape_glyph = XFASTINT (DISP_ESCAPE_GLYPH (it->dp));
+                 else
+                   escape_glyph = FAST_MAKE_GLYPH ('\\', 0);
+ 
+                 if (CHAR_BYTE8_P (it->c))
+                   {
+                     str[0] = CHAR_TO_BYTE8 (it->c);
+                     len = 1;
+                   }
+                 else if (it->c < 256)
+                   {
+                     str[0] = it->c;
+                     len = 1;
+                   }
+                 else
+                   {
+                     /* It's an invalid character, which
+                        shouldn't happen actually, but due to
+                        bugs it may happen.  Let's print the char
+                        as is, there's not much meaningful we can
+                        do with it.  */
+                     str[0] = it->c;
+                     str[1] = it->c >> 8;
+                     str[2] = it->c >> 16;
+                     str[3] = it->c >> 24;
+                     len = 4;
+                   }
+ 
+                 for (i = 0; i < len; i++)
+                   {
+                     XSETINT (it->ctl_chars[i * 4], escape_glyph);
+                     /* Insert three more glyphs into IT->ctl_chars for
+                        the octal display of the character.  */
+                     g = FAST_MAKE_GLYPH (((str[i] >> 6) & 7) + '0', 0);
+                     XSETINT (it->ctl_chars[i * 4 + 1], g);
+                     g = FAST_MAKE_GLYPH (((str[i] >> 3) & 7) + '0', 0);
+                     XSETINT (it->ctl_chars[i * 4 + 2], g);
+                     g = FAST_MAKE_GLYPH ((str[i] & 7) + '0', 0);
+                     XSETINT (it->ctl_chars[i * 4 + 3], g);
+                   }
+ 
+                 /* Set up IT->dpvec and return the first character
+                      from it.  */
+                 it->dpvec_char_len = it->len;
+                 it->dpvec = it->ctl_chars;
+                 it->dpend = it->dpvec + len * 4;
+                 it->current.dpvec_index = 0;
+                 it->method = next_element_from_display_vector;
+                 get_next_display_element (it);
+               }
+           }
+       }
+ 
+       /* Adjust face id for a multibyte character.  There are no
+          multibyte character in unibyte text.  */
+       if (it->multibyte_p
+         && success_p
+         && FRAME_WINDOW_P (it->f))
+       {
+         struct face *face = FACE_FROM_ID (it->f, it->face_id);
+         it->face_id = FACE_FOR_CHAR (it->f, face, it->c);
+       }
+     }
+ 
+   /* Is this character the last one of a run of characters with
+      box?  If yes, set IT->end_of_box_run_p to 1.  */
+   if (it->face_box_p
+       && it->s == NULL)
+     {
+       int face_id;
+       struct face *face;
+ 
+       it->end_of_box_run_p
+       = ((face_id = face_after_it_pos (it),
+           face_id != it->face_id)
+          && (face = FACE_FROM_ID (it->f, face_id),
+              face->box == FACE_NO_BOX));
+     }
+ 
+   /* Value is 0 if end of buffer or string reached.  */
+   return success_p;
+ }
+ 
+ 
+ /* Move IT to the next display element.
+ 
+    RESEAT_P non-zero means if called on a newline in buffer text,
+    skip to the next visible line start.
+ 
+    Functions get_next_display_element and set_iterator_to_next are
+    separate because I find this arrangement easier to handle than a
+    get_next_display_element function that also increments IT's
+    position.  The way it is we can first look at an iterator's current
+    display element, decide whether it fits on a line, and if it does,
+    increment the iterator position.  The other way around we probably
+    would either need a flag indicating whether the iterator has to be
+    incremented the next time, or we would have to implement a
+    decrement position function which would not be easy to write.  */
+ 
+ void
+ set_iterator_to_next (it, reseat_p)
+      struct it *it;
+      int reseat_p;
+ {
+   /* Reset flags indicating start and end of a sequence of characters
+      with box.  Reset them at the start of this function because
+      moving the iterator to a new position might set them.  */
+   it->start_of_box_run_p = it->end_of_box_run_p = 0;
+ 
+   if (it->method == next_element_from_buffer)
+     {
+       /* The current display element of IT is a character from
+        current_buffer.  Advance in the buffer, and maybe skip over
+        invisible lines that are so because of selective display.  */
+       if (ITERATOR_AT_END_OF_LINE_P (it) && reseat_p)
+       reseat_at_next_visible_line_start (it, 0);
+       else
+       {
+         xassert (it->len != 0);
+         IT_BYTEPOS (*it) += it->len;
+         IT_CHARPOS (*it) += 1;
+         xassert (IT_BYTEPOS (*it) == CHAR_TO_BYTE (IT_CHARPOS (*it)));
+       }
+     }
+   else if (it->method == next_element_from_composition)
+     {
+       xassert (it->cmp_id >= 0 && it ->cmp_id < n_compositions);
+       if (STRINGP (it->string))
+       {
+         IT_STRING_BYTEPOS (*it) += it->len;
+         IT_STRING_CHARPOS (*it) += it->cmp_len;
+         it->method = next_element_from_string;
+         goto consider_string_end;
+       }
+       else
+       {
+         IT_BYTEPOS (*it) += it->len;
+         IT_CHARPOS (*it) += it->cmp_len;
+         it->method = next_element_from_buffer;
+       }
+     }
+   else if (it->method == next_element_from_c_string)
+     {
+       /* Current display element of IT is from a C string.  */
+       IT_BYTEPOS (*it) += it->len;
+       IT_CHARPOS (*it) += 1;
+     }
+   else if (it->method == next_element_from_display_vector)
+     {
+       /* Current display element of IT is from a display table entry.
+        Advance in the display table definition.  Reset it to null if
+        end reached, and continue with characters from buffers/
+        strings.  */
+       ++it->current.dpvec_index;
+ 
+       /* Restore face of the iterator to what they were before the
+          display vector entry (these entries may contain faces).  */
+       it->face_id = it->saved_face_id;
+ 
+       if (it->dpvec + it->current.dpvec_index == it->dpend)
+       {
+         if (it->s)
+           it->method = next_element_from_c_string;
+         else if (STRINGP (it->string))
+           it->method = next_element_from_string;
+         else
+           it->method = next_element_from_buffer;
+ 
+         it->dpvec = NULL;
+         it->current.dpvec_index = -1;
+ 
+         /* Skip over characters which were displayed via IT->dpvec.  */
+         if (it->dpvec_char_len < 0)
+           reseat_at_next_visible_line_start (it, 1);
+         else if (it->dpvec_char_len > 0)
+           {
+             it->len = it->dpvec_char_len;
+             set_iterator_to_next (it, reseat_p);
+           }
+       }
+     }
+   else if (it->method == next_element_from_string)
+     {
+       /* Current display element is a character from a Lisp string.  */
+       xassert (it->s == NULL && STRINGP (it->string));
+       IT_STRING_BYTEPOS (*it) += it->len;
+       IT_STRING_CHARPOS (*it) += 1;
+ 
+     consider_string_end:
+ 
+       if (it->current.overlay_string_index >= 0)
+       {
+         /* IT->string is an overlay string.  Advance to the
+            next, if there is one.  */
+         if (IT_STRING_CHARPOS (*it) >= SCHARS (it->string))
+           next_overlay_string (it);
+       }
+       else
+       {
+         /* IT->string is not an overlay string.  If we reached
+            its end, and there is something on IT->stack, proceed
+            with what is on the stack.  This can be either another
+            string, this time an overlay string, or a buffer.  */
+         if (IT_STRING_CHARPOS (*it) == SCHARS (it->string)
+             && it->sp > 0)
+           {
+             pop_it (it);
+             if (!STRINGP (it->string))
+               it->method = next_element_from_buffer;
+             else
+               goto consider_string_end;
+           }
+       }
+     }
+   else if (it->method == next_element_from_image
+          || it->method == next_element_from_stretch)
+     {
+       /* The position etc with which we have to proceed are on
+        the stack.  The position may be at the end of a string,
+          if the `display' property takes up the whole string.  */
+       pop_it (it);
+       it->image_id = 0;
+       if (STRINGP (it->string))
+       {
+         it->method = next_element_from_string;
+         goto consider_string_end;
+       }
+       else
+       it->method = next_element_from_buffer;
+     }
+   else
+     /* There are no other methods defined, so this should be a bug.  */
+     abort ();
+ 
+   xassert (it->method != next_element_from_string
+          || (STRINGP (it->string)
+              && IT_STRING_CHARPOS (*it) >= 0));
+ }
+ 
+ 
+ /* Load IT's display element fields with information about the next
+    display element which comes from a display table entry or from the
+    result of translating a control character to one of the forms `^C'
+    or `\003'.  IT->dpvec holds the glyphs to return as characters.  */
+ 
+ static int
+ next_element_from_display_vector (it)
+      struct it *it;
+ {
+   /* Precondition.  */
+   xassert (it->dpvec && it->current.dpvec_index >= 0);
+ 
+   /* 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;
+ 
+   if (INTEGERP (*it->dpvec)
+       && GLYPH_CHAR_VALID_P (XFASTINT (*it->dpvec)))
+     {
+       int lface_id;
+       GLYPH g;
+ 
+       g = XFASTINT (it->dpvec[it->current.dpvec_index]);
+       it->c = FAST_GLYPH_CHAR (g);
+       it->len = CHAR_BYTES (it->c);
+ 
+       /* The entry may contain a face id to use.  Such a face id is
+        the id of a Lisp face, not a realized face.  A face id of
+        zero means no face is specified.  */
+       lface_id = FAST_GLYPH_FACE (g);
+       if (lface_id)
+       {
+         /* The function returns -1 if lface_id is invalid.  */
+         int face_id = ascii_face_of_lisp_face (it->f, lface_id);
+         if (face_id >= 0)
+           it->face_id = face_id;
+       }
+     }
+   else
+     /* Display table entry is invalid.  Return a space.  */
+     it->c = ' ', it->len = 1;
+ 
+   /* Don't change position and object of the iterator here.  They are
+      still the values of the character that had this display table
+      entry or was translated, and that's what we want.  */
+   it->what = IT_CHARACTER;
+   return 1;
+ }
+ 
+ 
+ /* Load IT with the next display element from Lisp string IT->string.
+    IT->current.string_pos is the current position within the string.
+    If IT->current.overlay_string_index >= 0, the Lisp string is an
+    overlay string.  */
+ 
+ static int
+ next_element_from_string (it)
+      struct it *it;
+ {
+   struct text_pos position;
+ 
+   xassert (STRINGP (it->string));
+   xassert (IT_STRING_CHARPOS (*it) >= 0);
+   position = it->current.string_pos;
+ 
+   /* Time to check for invisible text?  */
+   if (IT_STRING_CHARPOS (*it) < it->end_charpos
+       && IT_STRING_CHARPOS (*it) == it->stop_charpos)
+     {
+       handle_stop (it);
+ 
+       /* Since a handler may have changed IT->method, we must
+        recurse here.  */
+       return get_next_display_element (it);
+     }
+ 
+   if (it->current.overlay_string_index >= 0)
+     {
+       /* Get the next character from an overlay string.  In overlay
+        strings, There is no field width or padding with spaces to
+        do.  */
+       if (IT_STRING_CHARPOS (*it) >= SCHARS (it->string))
+       {
+         it->what = IT_EOB;
+         return 0;
+       }
+       else if (STRING_MULTIBYTE (it->string))
+       {
+         int remaining = SBYTES (it->string) - IT_STRING_BYTEPOS (*it);
+         const unsigned char *s = (SDATA (it->string)
+                                   + IT_STRING_BYTEPOS (*it));
+         it->c = string_char_and_length (s, remaining, &it->len);
+       }
+       else
+       {
+         it->c = SREF (it->string, IT_STRING_BYTEPOS (*it));
+         it->len = 1;
+       }
+     }
+   else
+     {
+       /* Get the next character from a Lisp string that is not an
+        overlay string.  Such strings come from the mode line, for
+        example.  We may have to pad with spaces, or truncate the
+        string.  See also next_element_from_c_string.  */
+       if (IT_STRING_CHARPOS (*it) >= it->end_charpos)
+       {
+         it->what = IT_EOB;
+         return 0;
+       }
+       else if (IT_STRING_CHARPOS (*it) >= it->string_nchars)
+       {
+         /* Pad with spaces.  */
+         it->c = ' ', it->len = 1;
+         CHARPOS (position) = BYTEPOS (position) = -1;
+       }
+       else if (STRING_MULTIBYTE (it->string))
+       {
+         int maxlen = SBYTES (it->string) - IT_STRING_BYTEPOS (*it);
+         const unsigned char *s = (SDATA (it->string)
+                                   + IT_STRING_BYTEPOS (*it));
+         it->c = string_char_and_length (s, maxlen, &it->len);
+       }
+       else
+       {
+         it->c = SREF (it->string, IT_STRING_BYTEPOS (*it));
+         it->len = 1;
+       }
+     }
+ 
+   /* Record what we have and where it came from.  Note that we store a
+      buffer position in IT->position although it could arguably be a
+      string position.  */
+   it->what = IT_CHARACTER;
+   it->object = it->string;
+   it->position = position;
+   return 1;
+ }
+ 
+ 
+ /* Load IT with next display element from C string IT->s.
+    IT->string_nchars is the maximum number of characters to return
+    from the string.  IT->end_charpos may be greater than
+    IT->string_nchars when this function is called, in which case we
+    may have to return padding spaces.  Value is zero if end of string
+    reached, including padding spaces.  */
+ 
+ static int
+ next_element_from_c_string (it)
+      struct it *it;
+ {
+   int success_p = 1;
+ 
+   xassert (it->s);
+   it->what = IT_CHARACTER;
+   BYTEPOS (it->position) = CHARPOS (it->position) = 0;
+   it->object = Qnil;
+ 
+   /* IT's position can be greater IT->string_nchars in case a field
+      width or precision has been specified when the iterator was
+      initialized.  */
+   if (IT_CHARPOS (*it) >= it->end_charpos)
+     {
+       /* End of the game.  */
+       it->what = IT_EOB;
+       success_p = 0;
+     }
+   else if (IT_CHARPOS (*it) >= it->string_nchars)
+     {
+       /* Pad with spaces.  */
+       it->c = ' ', it->len = 1;
+       BYTEPOS (it->position) = CHARPOS (it->position) = -1;
+     }
+   else if (it->multibyte_p)
+     {
+       /* Implementation note: The calls to strlen apparently aren't a
+        performance problem because there is no noticeable performance
+        difference between Emacs running in unibyte or multibyte mode.  */
+       int maxlen = strlen (it->s) - IT_BYTEPOS (*it);
+       it->c = string_char_and_length (it->s + IT_BYTEPOS (*it),
+                                     maxlen, &it->len);
+     }
+   else
+     it->c = it->s[IT_BYTEPOS (*it)], it->len = 1;
+ 
+   return success_p;
+ }
+ 
+ 
+ /* Set up IT to return characters from an ellipsis, if appropriate.
+    The definition of the ellipsis glyphs may come from a display table
+    entry.  This function Fills IT with the first glyph from the
+    ellipsis if an ellipsis is to be displayed.  */
+ 
+ static int
+ next_element_from_ellipsis (it)
+      struct it *it;
+ {
+   if (it->selective_display_ellipsis_p)
+     {
+       if (it->dp && VECTORP (DISP_INVIS_VECTOR (it->dp)))
+       {
+         /* Use the display table definition for `...'.  Invalid glyphs
+            will be handled by the method returning elements from dpvec.  */
+         struct Lisp_Vector *v = XVECTOR (DISP_INVIS_VECTOR (it->dp));
+         it->dpvec_char_len = it->len;
+         it->dpvec = v->contents;
+         it->dpend = v->contents + v->size;
+         it->current.dpvec_index = 0;
+         it->method = next_element_from_display_vector;
+       }
+       else
+       {
+         /* Use default `...' which is stored in default_invis_vector.  */
+         it->dpvec_char_len = it->len;
+         it->dpvec = default_invis_vector;
+         it->dpend = default_invis_vector + 3;
+         it->current.dpvec_index = 0;
+         it->method = next_element_from_display_vector;
+       }
+     }
+   else
+     {
+       /* The face at the current position may be different from the
+        face we find after the invisible text.  Remember what it
+        was in IT->saved_face_id, and signal that it's there by
+        setting face_before_selective_p.  */
+       it->saved_face_id = it->face_id;
+       it->method = next_element_from_buffer;
+       reseat_at_next_visible_line_start (it, 1);
+       it->face_before_selective_p = 1;
+     }
+ 
+   return get_next_display_element (it);
+ }
+ 
+ 
+ /* Deliver an image display element.  The iterator IT is already
+    filled with image information (done in handle_display_prop).  Value
+    is always 1.  */
+ 
+ 
+ static int
+ next_element_from_image (it)
+      struct it *it;
+ {
+   it->what = IT_IMAGE;
+   return 1;
+ }
+ 
+ 
+ /* Fill iterator IT with next display element from a stretch glyph
+    property.  IT->object is the value of the text property.  Value is
+    always 1.  */
+ 
+ static int
+ next_element_from_stretch (it)
+      struct it *it;
+ {
+   it->what = IT_STRETCH;
+   return 1;
+ }
+ 
+ 
+ /* Load IT with the next display element from current_buffer.  Value
+    is zero if end of buffer reached.  IT->stop_charpos is the next
+    position at which to stop and check for text properties or buffer
+    end.  */
+ 
+ static int
+ next_element_from_buffer (it)
+      struct it *it;
+ {
+   int success_p = 1;
+ 
+   /* Check this assumption, otherwise, we would never enter the
+      if-statement, below.  */
+   xassert (IT_CHARPOS (*it) >= BEGV
+          && IT_CHARPOS (*it) <= it->stop_charpos);
+ 
+   if (IT_CHARPOS (*it) >= it->stop_charpos)
+     {
+       if (IT_CHARPOS (*it) >= it->end_charpos)
+       {
+         int overlay_strings_follow_p;
+ 
+         /* End of the game, except when overlay strings follow that
+            haven't been returned yet.  */
+         if (it->overlay_strings_at_end_processed_p)
+           overlay_strings_follow_p = 0;
+         else
+           {
+             it->overlay_strings_at_end_processed_p = 1;
+             overlay_strings_follow_p = get_overlay_strings (it, 0);
+           }
+ 
+         if (overlay_strings_follow_p)
+           success_p = get_next_display_element (it);
+         else
+           {
+             it->what = IT_EOB;
+             it->position = it->current.pos;
+             success_p = 0;
+           }
+       }
+       else
+       {
+         handle_stop (it);
+         return get_next_display_element (it);
+       }
+     }
+   else
+     {
+       /* No face changes, overlays etc. in sight, so just return a
+        character from current_buffer.  */
+       unsigned char *p;
+ 
+       /* Maybe run the redisplay end trigger hook.  Performance note:
+        This doesn't seem to cost measurable time.  */
+       if (it->redisplay_end_trigger_charpos
+         && it->glyph_row
+         && IT_CHARPOS (*it) >= it->redisplay_end_trigger_charpos)
+       run_redisplay_end_trigger_hook (it);
+ 
+       /* Get the next character, maybe multibyte.  */
+       p = BYTE_POS_ADDR (IT_BYTEPOS (*it));
+       if (it->multibyte_p && !ASCII_BYTE_P (*p))
+       {
+         int maxlen = ((IT_BYTEPOS (*it) >= GPT_BYTE ? ZV_BYTE : GPT_BYTE)
+                       - IT_BYTEPOS (*it));
+         it->c = string_char_and_length (p, maxlen, &it->len);
+       }
+       else
+       it->c = *p, it->len = 1;
+ 
+       /* Record what we have and where it came from.  */
+       it->what = IT_CHARACTER;;
+       it->object = it->w->buffer;
+       it->position = it->current.pos;
+ 
+       /* Normally we return the character found above, except when we
+        really want to return an ellipsis for selective display.  */
+       if (it->selective)
+       {
+         if (it->c == '\n')
+           {
+             /* A value of selective > 0 means hide lines indented more
+                than that number of columns.  */
+             if (it->selective > 0
+                 && IT_CHARPOS (*it) + 1 < ZV
+                 && indented_beyond_p (IT_CHARPOS (*it) + 1,
+                                       IT_BYTEPOS (*it) + 1,
+                                       (double) it->selective)) /* iftc */
+               {
+                 success_p = next_element_from_ellipsis (it);
+                 it->dpvec_char_len = -1;
+               }
+           }
+         else if (it->c == '\r' && it->selective == -1)
+           {
+             /* A value of selective == -1 means that everything from the
+                CR to the end of the line is invisible, with maybe an
+                ellipsis displayed for it.  */
+             success_p = next_element_from_ellipsis (it);
+             it->dpvec_char_len = -1;
+           }
+       }
+     }
+ 
+   /* Value is zero if end of buffer reached.  */
+   xassert (!success_p || it->what != IT_CHARACTER || it->len > 0);
+   return success_p;
+ }
+ 
+ 
+ /* Run the redisplay end trigger hook for IT.  */
+ 
+ static void
+ run_redisplay_end_trigger_hook (it)
+      struct it *it;
+ {
+   Lisp_Object args[3];
+ 
+   /* IT->glyph_row should be non-null, i.e. we should be actually
+      displaying something, or otherwise we should not run the hook.  */
+   xassert (it->glyph_row);
+ 
+   /* Set up hook arguments.  */
+   args[0] = Qredisplay_end_trigger_functions;
+   args[1] = it->window;
+   XSETINT (args[2], it->redisplay_end_trigger_charpos);
+   it->redisplay_end_trigger_charpos = 0;
+ 
+   /* Since we are *trying* to run these functions, don't try to run
+      them again, even if they get an error.  */
+   it->w->redisplay_end_trigger = Qnil;
+   Frun_hook_with_args (3, args);
+ 
+   /* Notice if it changed the face of the character we are on.  */
+   handle_face_prop (it);
+ }
+ 
+ 
+ /* Deliver a composition display element.  The iterator IT is already
+    filled with composition information (done in
+    handle_composition_prop).  Value is always 1.  */
+ 
+ static int
+ next_element_from_composition (it)
+      struct it *it;
+ {
+   it->what = IT_COMPOSITION;
+   it->position = (STRINGP (it->string)
+                 ? it->current.string_pos
+                 : it->current.pos);
+   return 1;
+ }
+ 
+ 
+ 
+ /***********************************************************************
+            Moving an iterator without producing glyphs
+  ***********************************************************************/
+ 
+ /* Move iterator IT to a specified buffer or X position within one
+    line on the display without producing glyphs.
+ 
+    OP should be a bit mask including some or all of these bits:
+     MOVE_TO_X: Stop on reaching x-position TO_X.
+     MOVE_TO_POS: Stop on reaching buffer or string position TO_CHARPOS.
+    Regardless of OP's value, stop in reaching the end of the display line.
+ 
+    TO_X is normally a value 0 <= TO_X <= IT->last_visible_x.
+    This means, in particular, that TO_X includes window's horizontal
+    scroll amount.
+ 
+    The return value has several possible values that
+    say what condition caused the scan to stop:
+ 
+    MOVE_POS_MATCH_OR_ZV
+      - when TO_POS or ZV was reached.
+ 
+    MOVE_X_REACHED
+      -when TO_X was reached before TO_POS or ZV were reached.
+ 
+    MOVE_LINE_CONTINUED
+      - when we reached the end of the display area and the line must
+      be continued.
+ 
+    MOVE_LINE_TRUNCATED
+      - when we reached the end of the display area and the line is
+      truncated.
+ 
+    MOVE_NEWLINE_OR_CR
+      - when we stopped at a line end, i.e. a newline or a CR and selective
+      display is on.  */
+ 
+ static enum move_it_result
+ move_it_in_display_line_to (it, to_charpos, to_x, op)
+      struct it *it;
+      int to_charpos, to_x, op;
+ {
+   enum move_it_result result = MOVE_UNDEFINED;
+   struct glyph_row *saved_glyph_row;
+ 
+   /* Don't produce glyphs in produce_glyphs.  */
+   saved_glyph_row = it->glyph_row;
+   it->glyph_row = NULL;
+ 
+   while (1)
+     {
+       int x, i, ascent = 0, descent = 0;
+ 
+       /* Stop when ZV or TO_CHARPOS reached.  */
+       if (!get_next_display_element (it)
+         || ((op & MOVE_TO_POS) != 0
+             && BUFFERP (it->object)
+             && IT_CHARPOS (*it) >= to_charpos))
+       {
+         result = MOVE_POS_MATCH_OR_ZV;
+         break;
+       }
+ 
+       /* The call to produce_glyphs will get the metrics of the
+        display element IT is loaded with.  We record in x the
+        x-position before this display element in case it does not
+        fit on the line.  */
+       x = it->current_x;
+ 
+       /* Remember the line height so far in case the next element doesn't
+        fit on the line.  */
+       if (!it->truncate_lines_p)
+       {
+         ascent = it->max_ascent;
+         descent = it->max_descent;
+       }
+ 
+       PRODUCE_GLYPHS (it);
+ 
+       if (it->area != TEXT_AREA)
+       {
+         set_iterator_to_next (it, 1);
+         continue;
+       }
+ 
+       /* The number of glyphs we get back in IT->nglyphs will normally
+        be 1 except when IT->c is (i) a TAB, or (ii) a multi-glyph
+        character on a terminal frame, or (iii) a line end.  For the
+        second case, IT->nglyphs - 1 padding glyphs will be present
+        (on X frames, there is only one glyph produced for a
+        composite character.
+ 
+        The behavior implemented below means, for continuation lines,
+        that as many spaces of a TAB as fit on the current line are
+        displayed there.  For terminal frames, as many glyphs of a
+        multi-glyph character are displayed in the current line, too.
+        This is what the old redisplay code did, and we keep it that
+        way.  Under X, the whole shape of a complex character must
+        fit on the line or it will be completely displayed in the
+        next line.
+ 
+        Note that both for tabs and padding glyphs, all glyphs have
+        the same width.   */
+       if (it->nglyphs)
+       {
+         /* More than one glyph or glyph doesn't fit on line.  All
+            glyphs have the same width.  */
+         int single_glyph_width = it->pixel_width / it->nglyphs;
+         int new_x;
+ 
+         for (i = 0; i < it->nglyphs; ++i, x = new_x)
+           {
+             new_x = x + single_glyph_width;
+ 
+             /* We want to leave anything reaching TO_X to the caller.  */
+             if ((op & MOVE_TO_X) && new_x > to_x)
+               {
+                 it->current_x = x;
+                 result = MOVE_X_REACHED;
+                 break;
+               }
+             else if (/* Lines are continued.  */
+                      !it->truncate_lines_p
+                      && (/* And glyph doesn't fit on the line.  */
+                          new_x > it->last_visible_x
+                          /* Or it fits exactly and we're on a window
+                             system frame.  */
+                          || (new_x == it->last_visible_x
+                              && FRAME_WINDOW_P (it->f))))
+               {
+                 if (/* IT->hpos == 0 means the very first glyph
+                        doesn't fit on the line, e.g. a wide image.  */
+                     it->hpos == 0
+                     || (new_x == it->last_visible_x
+                         && FRAME_WINDOW_P (it->f)))
+                   {
+                     ++it->hpos;
+                     it->current_x = new_x;
+                     if (i == it->nglyphs - 1)
+                       set_iterator_to_next (it, 1);
+                   }
+                 else
+                   {
+                     it->current_x = x;
+                     it->max_ascent = ascent;
+                     it->max_descent = descent;
+                   }
+ 
+                 TRACE_MOVE ((stderr, "move_it_in: continued at %d\n",
+                              IT_CHARPOS (*it)));
+                 result = MOVE_LINE_CONTINUED;
+                 break;
+               }
+             else if (new_x > it->first_visible_x)
+               {
+                 /* Glyph is visible.  Increment number of glyphs that
+                    would be displayed.  */
+                 ++it->hpos;
+               }
+             else
+               {
+                 /* Glyph is completely off the left margin of the display
+                    area.  Nothing to do.  */
+               }
+           }
+ 
+         if (result != MOVE_UNDEFINED)
+           break;
+       }
+       else if ((op & MOVE_TO_X) && it->current_x >= to_x)
+       {
+         /* Stop when TO_X specified and reached.  This check is
+            necessary here because of lines consisting of a line end,
+            only.  The line end will not produce any glyphs and we
+            would never get MOVE_X_REACHED.  */
+         xassert (it->nglyphs == 0);
+         result = MOVE_X_REACHED;
+         break;
+       }
+ 
+       /* Is this a line end?  If yes, we're done.  */
+       if (ITERATOR_AT_END_OF_LINE_P (it))
+       {
+         result = MOVE_NEWLINE_OR_CR;
+         break;
+       }
+ 
+       /* The current display element has been consumed.  Advance
+        to the next.  */
+       set_iterator_to_next (it, 1);
+ 
+       /* Stop if lines are truncated and IT's current x-position is
+        past the right edge of the window now.  */
+       if (it->truncate_lines_p
+         && it->current_x >= it->last_visible_x)
+       {
+         result = MOVE_LINE_TRUNCATED;
+         break;
+       }
+     }
+ 
+   /* Restore the iterator settings altered at the beginning of this
+      function.  */
+   it->glyph_row = saved_glyph_row;
+   return result;
+ }
+ 
+ 
+ /* Move IT forward until it satisfies one or more of the criteria in
+    TO_CHARPOS, TO_X, TO_Y, and TO_VPOS.
+ 
+    OP is a bit-mask that specifies where to stop, and in particular,
+    which of those four position arguments makes a difference.  See the
+    description of enum move_operation_enum.
+ 
+    If TO_CHARPOS is in invisible text, e.g. a truncated part of a
+    screen line, this function will set IT to the next position >
+    TO_CHARPOS.  */
+ 
+ void
+ move_it_to (it, to_charpos, to_x, to_y, to_vpos, op)
+      struct it *it;
+      int to_charpos, to_x, to_y, to_vpos;
+      int op;
+ {
+   enum move_it_result skip, skip2 = MOVE_X_REACHED;
+   int line_height;
+   int reached = 0;
+ 
+   for (;;)
+     {
+       if (op & MOVE_TO_VPOS)
+       {
+         /* If no TO_CHARPOS and no TO_X specified, stop at the
+            start of the line TO_VPOS.  */
+         if ((op & (MOVE_TO_X | MOVE_TO_POS)) == 0)
+           {
+             if (it->vpos == to_vpos)
+               {
+                 reached = 1;
+                 break;
+               }
+             else
+               skip = move_it_in_display_line_to (it, -1, -1, 0);
+           }
+         else
+           {
+             /* TO_VPOS >= 0 means stop at TO_X in the line at
+                TO_VPOS, or at TO_POS, whichever comes first.  */
+             if (it->vpos == to_vpos)
+               {
+                 reached = 2;
+                 break;
+               }
+ 
+             skip = move_it_in_display_line_to (it, to_charpos, to_x, op);
+ 
+             if (skip == MOVE_POS_MATCH_OR_ZV || it->vpos == to_vpos)
+               {
+                 reached = 3;
+                 break;
+               }
+             else if (skip == MOVE_X_REACHED && it->vpos != to_vpos)
+               {
+                 /* We have reached TO_X but not in the line we want.  */
+                 skip = move_it_in_display_line_to (it, to_charpos,
+                                                    -1, MOVE_TO_POS);
+                 if (skip == MOVE_POS_MATCH_OR_ZV)
+                   {
+                     reached = 4;
+                     break;
+                   }
+               }
+           }
+       }
+       else if (op & MOVE_TO_Y)
+       {
+         struct it it_backup;
+ 
+         /* TO_Y specified means stop at TO_X in the line containing
+            TO_Y---or at TO_CHARPOS if this is reached first.  The
+            problem is that we can't really tell whether the line
+            contains TO_Y before we have completely scanned it, and
+            this may skip past TO_X.  What we do is to first scan to
+            TO_X.
+ 
+            If TO_X is not specified, use a TO_X of zero.  The reason
+            is to make the outcome of this function more predictable.
+            If we didn't use TO_X == 0, we would stop at the end of
+            the line which is probably not what a caller would expect
+            to happen.  */
+         skip = move_it_in_display_line_to (it, to_charpos,
+                                            ((op & MOVE_TO_X)
+                                             ? to_x : 0),
+                                            (MOVE_TO_X
+                                             | (op & MOVE_TO_POS)));
+ 
+         /* If TO_CHARPOS is reached or ZV, we don't have to do more.  */
+         if (skip == MOVE_POS_MATCH_OR_ZV)
+           {
+             reached = 5;
+             break;
+           }
+ 
+         /* If TO_X was reached, we would like to know whether TO_Y
+            is in the line.  This can only be said if we know the
+            total line height which requires us to scan the rest of
+            the line.  */
+         if (skip == MOVE_X_REACHED)
+           {
+             it_backup = *it;
+             TRACE_MOVE ((stderr, "move_it: from %d\n", IT_CHARPOS (*it)));
+             skip2 = move_it_in_display_line_to (it, to_charpos, -1,
+                                                 op & MOVE_TO_POS);
+             TRACE_MOVE ((stderr, "move_it: to %d\n", IT_CHARPOS (*it)));
+           }
+ 
+         /* Now, decide whether TO_Y is in this line.  */
+         line_height = it->max_ascent + it->max_descent;
+         TRACE_MOVE ((stderr, "move_it: line_height = %d\n", line_height));
+ 
+         if (to_y >= it->current_y
+             && to_y < it->current_y + line_height)
+           {
+             if (skip == MOVE_X_REACHED)
+               /* If TO_Y is in this line and TO_X was reached above,
+                  we scanned too far.  We have to restore IT's settings
+                  to the ones before skipping.  */
+               *it = it_backup;
+             reached = 6;
+           }
+         else if (skip == MOVE_X_REACHED)
+           {
+             skip = skip2;
+             if (skip == MOVE_POS_MATCH_OR_ZV)
+               reached = 7;
+           }
+ 
+         if (reached)
+           break;
+       }
+       else
+       skip = move_it_in_display_line_to (it, to_charpos, -1, MOVE_TO_POS);
+ 
+       switch (skip)
+       {
+       case MOVE_POS_MATCH_OR_ZV:
+         reached = 8;
+         goto out;
+ 
+       case MOVE_NEWLINE_OR_CR:
+         set_iterator_to_next (it, 1);
+         it->continuation_lines_width = 0;
+         break;
+ 
+       case MOVE_LINE_TRUNCATED:
+         it->continuation_lines_width = 0;
+         reseat_at_next_visible_line_start (it, 0);
+         if ((op & MOVE_TO_POS) != 0
+             && IT_CHARPOS (*it) > to_charpos)
+           {
+             reached = 9;
+             goto out;
+           }
+         break;
+ 
+       case MOVE_LINE_CONTINUED:
+         it->continuation_lines_width += it->current_x;
+         break;
+ 
+       default:
+         abort ();
+       }
+ 
+       /* Reset/increment for the next run.  */
+       recenter_overlay_lists (current_buffer, IT_CHARPOS (*it));
+       it->current_x = it->hpos = 0;
+       it->current_y += it->max_ascent + it->max_descent;
+       ++it->vpos;
+       last_height = it->max_ascent + it->max_descent;
+       last_max_ascent = it->max_ascent;
+       it->max_ascent = it->max_descent = 0;
+     }
+ 
+  out:
+ 
+   TRACE_MOVE ((stderr, "move_it_to: reached %d\n", reached));
+ }
+ 
+ 
+ /* Move iterator IT backward by a specified y-distance DY, DY >= 0.
+ 
+    If DY > 0, move IT backward at least that many pixels.  DY = 0
+    means move IT backward to the preceding line start or BEGV.  This
+    function may move over more than DY pixels if IT->current_y - DY
+    ends up in the middle of a line; in this case IT->current_y will be
+    set to the top of the line moved to.  */
+ 
+ void
+ move_it_vertically_backward (it, dy)
+      struct it *it;
+      int dy;
+ {
+   int nlines, h;
+   struct it it2, it3;
+   int start_pos = IT_CHARPOS (*it);
+ 
+   xassert (dy >= 0);
+ 
+   /* Estimate how many newlines we must move back.  */
+   nlines = max (1, dy / FRAME_LINE_HEIGHT (it->f));
+ 
+   /* Set the iterator's position that many lines back.  */
+   while (nlines-- && IT_CHARPOS (*it) > BEGV)
+     back_to_previous_visible_line_start (it);
+ 
+   /* Reseat the iterator here.  When moving backward, we don't want
+      reseat to skip forward over invisible text, set up the iterator
+      to deliver from overlay strings at the new position etc.  So,
+      use reseat_1 here.  */
+   reseat_1 (it, it->current.pos, 1);
+ 
+   /* We are now surely at a line start.  */
+   it->current_x = it->hpos = 0;
+   it->continuation_lines_width = 0;
+ 
+   /* Move forward and see what y-distance we moved.  First move to the
+      start of the next line so that we get its height.  We need this
+      height to be able to tell whether we reached the specified
+      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);
+   xassert (IT_CHARPOS (*it) >= BEGV);
+   it3 = it2;
+ 
+   move_it_to (&it2, start_pos, -1, -1, -1, MOVE_TO_POS);
+   xassert (IT_CHARPOS (*it) >= BEGV);
+   /* H is the actual vertical distance from the position in *IT
+      and the starting position.  */
+   h = it2.current_y - it->current_y;
+   /* NLINES is the distance in number of lines.  */
+   nlines = it2.vpos - it->vpos;
+ 
+   /* Correct IT's y and vpos position
+      so that they are relative to the starting point.  */
+   it->vpos -= nlines;
+   it->current_y -= h;
+ 
+   if (dy == 0)
+     {
+       /* DY == 0 means move to the start of the screen line.  The
+        value of nlines is > 0 if continuation lines were involved.  */
+       if (nlines > 0)
+       move_it_by_lines (it, nlines, 1);
+       xassert (IT_CHARPOS (*it) <= start_pos);
+     }
+   else
+     {
+       /* The y-position we try to reach, relative to *IT.
+        Note that H has been subtracted in front of the if-statement.  */
+       int target_y = it->current_y + h - dy;
+       int y0 = it3.current_y;
+       int y1 = line_bottom_y (&it3);
+       int line_height = y1 - y0;
+ 
+       /* If we did not reach target_y, try to move further backward if
+        we can.  If we moved too far backward, try to move forward.  */
+       if (target_y < it->current_y
+         /* This is heuristic.  In a window that's 3 lines high, with
+            a line height of 13 pixels each, recentering with point
+            on the bottom line will try to move -39/2 = 19 pixels
+            backward.  Try to avoid moving into the first line.  */
+         && it->current_y - target_y > line_height / 3 * 2
+         && IT_CHARPOS (*it) > BEGV)
+       {
+         TRACE_MOVE ((stderr, "  not far enough -> move_vert %d\n",
+                      target_y - it->current_y));
+         move_it_vertically (it, target_y - it->current_y);
+         xassert (IT_CHARPOS (*it) >= BEGV);
+       }
+       else if (target_y >= it->current_y + line_height
+              && IT_CHARPOS (*it) < ZV)
+       {
+         /* Should move forward by at least one line, maybe more.
+ 
+            Note: Calling move_it_by_lines can be expensive on
+            terminal frames, where compute_motion is used (via
+            vmotion) to do the job, when there are very long lines
+            and truncate-lines is nil.  That's the reason for
+            treating terminal frames specially here.  */
+ 
+         if (!FRAME_WINDOW_P (it->f))
+           move_it_vertically (it, target_y - (it->current_y + line_height));
+         else
+           {
+             do
+               {
+                 move_it_by_lines (it, 1, 1);
+               }
+             while (target_y >= line_bottom_y (it) && IT_CHARPOS (*it) < ZV);
+           }
+ 
+         xassert (IT_CHARPOS (*it) >= BEGV);
+       }
+     }
+ }
+ 
+ 
+ /* Move IT by a specified amount of pixel lines DY.  DY negative means
+    move backwards.  DY = 0 means move to start of screen line.  At the
+    end, IT will be on the start of a screen line.  */
+ 
+ void
+ move_it_vertically (it, dy)
+     struct it *it;
+     int dy;
+ {
+   if (dy <= 0)
+     move_it_vertically_backward (it, -dy);
+   else if (dy > 0)
+     {
+       TRACE_MOVE ((stderr, "move_it_v: from %d, %d\n", IT_CHARPOS (*it), dy));
+       move_it_to (it, ZV, -1, it->current_y + dy, -1,
+                 MOVE_TO_POS | MOVE_TO_Y);
+       TRACE_MOVE ((stderr, "move_it_v: to %d\n", IT_CHARPOS (*it)));
+ 
+       /* 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
+         && FETCH_BYTE (IT_BYTEPOS (*it) - 1) != '\n')
+       move_it_by_lines (it, 0, 0);
+     }
+ }
+ 
+ 
+ /* Move iterator IT past the end of the text line it is in.  */
+ 
+ void
+ move_it_past_eol (it)
+      struct it *it;
+ {
+   enum move_it_result rc;
+ 
+   rc = move_it_in_display_line_to (it, Z, 0, MOVE_TO_POS);
+   if (rc == MOVE_NEWLINE_OR_CR)
+     set_iterator_to_next (it, 0);
+ }
+ 
+ 
+ #if 0 /* Currently not used.  */
+ 
+ /* Return non-zero if some text between buffer positions START_CHARPOS
+    and END_CHARPOS is invisible.  IT->window is the window for text
+    property lookup.  */
+ 
+ static int
+ invisible_text_between_p (it, start_charpos, end_charpos)
+      struct it *it;
+      int start_charpos, end_charpos;
+ {
+   Lisp_Object prop, limit;
+   int invisible_found_p;
+ 
+   xassert (it != NULL && start_charpos <= end_charpos);
+ 
+   /* Is text at START invisible?  */
+   prop = Fget_char_property (make_number (start_charpos), Qinvisible,
+                            it->window);
+   if (TEXT_PROP_MEANS_INVISIBLE (prop))
+     invisible_found_p = 1;
+   else
+     {
+       limit = Fnext_single_char_property_change (make_number (start_charpos),
+                                                Qinvisible, Qnil,
+                                                make_number (end_charpos));
+       invisible_found_p = XFASTINT (limit) < end_charpos;
+     }
+ 
+   return invisible_found_p;
+ }
+ 
+ #endif /* 0 */
+ 
+ 
+ /* Move IT by a specified number DVPOS of screen lines down.  DVPOS
+    negative means move up.  DVPOS == 0 means move to the start of the
+    screen line.  NEED_Y_P non-zero means calculate IT->current_y.  If
+    NEED_Y_P is zero, IT->current_y will be left unchanged.
+ 
+    Further optimization ideas: If we would know that IT->f doesn't use
+    a face with proportional font, we could be faster for
+    truncate-lines nil.  */
+ 
+ void
+ move_it_by_lines (it, dvpos, need_y_p)
+      struct it *it;
+      int dvpos, need_y_p;
+ {
+   struct position pos;
+ 
+   if (!FRAME_WINDOW_P (it->f))
+     {
+       struct text_pos textpos;
+ 
+       /* We can use vmotion on frames without proportional fonts.  */
+       pos = *vmotion (IT_CHARPOS (*it), dvpos, it->w);
+       SET_TEXT_POS (textpos, pos.bufpos, pos.bytepos);
+       reseat (it, textpos, 1);
+       it->vpos += pos.vpos;
+       it->current_y += pos.vpos;
+     }
+   else if (dvpos == 0)
+     {
+       /* DVPOS == 0 means move to the start of the screen line.  */
+       move_it_vertically_backward (it, 0);
+       xassert (it->current_x == 0 && it->hpos == 0);
+     }
+   else if (dvpos > 0)
+     move_it_to (it, -1, -1, -1, it->vpos + dvpos, MOVE_TO_VPOS);
+   else
+     {
+       struct it it2;
+       int start_charpos, i;
+ 
+       /* Start at the beginning of the screen line containing IT's
+        position.  */
+       move_it_vertically_backward (it, 0);
+ 
+       /* Go back -DVPOS visible lines and reseat the iterator there.  */
+       start_charpos = IT_CHARPOS (*it);
+       for (i = -dvpos; i && IT_CHARPOS (*it) > BEGV; --i)
+       back_to_previous_visible_line_start (it);
+       reseat (it, it->current.pos, 1);
+       it->current_x = it->hpos = 0;
+ 
+       /* Above call may have moved too far if continuation lines
+        are involved.  Scan forward and see if it did.  */
+       it2 = *it;
+       it2.vpos = it2.current_y = 0;
+       move_it_to (&it2, start_charpos, -1, -1, -1, MOVE_TO_POS);
+       it->vpos -= it2.vpos;
+       it->current_y -= it2.current_y;
+       it->current_x = it->hpos = 0;
+ 
+       /* If we moved too far, move IT some lines forward.  */
+       if (it2.vpos > -dvpos)
+       {
+         int delta = it2.vpos + dvpos;
+         move_it_to (it, -1, -1, -1, it->vpos + delta, MOVE_TO_VPOS);
+       }
+     }
+ }
+ 
+ /* Return 1 if IT points into the middle of a display vector.  */
+ 
+ int
+ in_display_vector_p (it)
+      struct it *it;
+ {
+   return (it->method == next_element_from_display_vector
+         && it->current.dpvec_index > 0
+         && it->dpvec + it->current.dpvec_index != it->dpend);
+ }
+ 
+ 
+ /***********************************************************************
+                              Messages
+  ***********************************************************************/
+ 
+ 
+ /* Add a message with format string FORMAT and arguments ARG1 and ARG2
+    to *Messages*.  */
+ 
+ void
+ add_to_log (format, arg1, arg2)
+      char *format;
+      Lisp_Object arg1, arg2;
+ {
+   Lisp_Object args[3];
+   Lisp_Object msg, fmt;
+   char *buffer;
+   int len;
+   struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
+ 
+   /* Do nothing if called asynchronously.  Inserting text into
+      a buffer may call after-change-functions and alike and
+      that would means running Lisp asynchronously.  */
+   if (handling_signal)
+     return;
+ 
+   fmt = msg = Qnil;
+   GCPRO4 (fmt, msg, arg1, arg2);
+ 
+   args[0] = fmt = build_string (format);
+   args[1] = arg1;
+   args[2] = arg2;
+   msg = Fformat (3, args);
+ 
+   len = SBYTES (msg) + 1;
+   buffer = (char *) alloca (len);
+   bcopy (SDATA (msg), buffer, len);
+ 
+   message_dolog (buffer, len - 1, 1, 0);
+   UNGCPRO;
+ }
+ 
+ 
+ /* Output a newline in the *Messages* buffer if "needs" one.  */
+ 
+ void
+ message_log_maybe_newline ()
+ {
+   if (message_log_need_newline)
+     message_dolog ("", 0, 1, 0);
+ }
+ 
+ 
+ /* Add a string M of length NBYTES to the message log, optionally
+    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.  */
+ 
+ void
+ message_dolog (m, nbytes, nlflag, multibyte)
+      const char *m;
+      int nbytes, nlflag, multibyte;
+ {
+   if (!NILP (Vmemory_full))
+     return;
+ 
+   if (!NILP (Vmessage_log_max))
+     {
+       struct buffer *oldbuf;
+       Lisp_Object oldpoint, oldbegv, oldzv;
+       int old_windows_or_buffers_changed = windows_or_buffers_changed;
+       int point_at_end = 0;
+       int zv_at_end = 0;
+       Lisp_Object old_deactivate_mark, tem;
+       struct gcpro gcpro1;
+ 
+       old_deactivate_mark = Vdeactivate_mark;
+       oldbuf = current_buffer;
+       Fset_buffer (Fget_buffer_create (Vmessages_buffer_name));
+       current_buffer->undo_list = Qt;
+ 
+       oldpoint = message_dolog_marker1;
+       set_marker_restricted (oldpoint, make_number (PT), Qnil);
+       oldbegv = message_dolog_marker2;
+       set_marker_restricted (oldbegv, make_number (BEGV), Qnil);
+       oldzv = message_dolog_marker3;
+       set_marker_restricted (oldzv, make_number (ZV), Qnil);
+       GCPRO1 (old_deactivate_mark);
+ 
+       if (PT == Z)
+       point_at_end = 1;
+       if (ZV == Z)
+       zv_at_end = 1;
+ 
+       BEGV = BEG;
+       BEGV_BYTE = BEG_BYTE;
+       ZV = Z;
+       ZV_BYTE = Z_BYTE;
+       TEMP_SET_PT_BOTH (Z, Z_BYTE);
+ 
+       /* Insert the string--maybe converting multibyte to single byte
+        or vice versa, so that all the text fits the buffer.  */
+       if (multibyte
+         && NILP (current_buffer->enable_multibyte_characters))
+       {
+         int i, c, char_bytes;
+         unsigned char work[1];
+ 
+         /* Convert a multibyte string to single-byte
+            for the *Message* buffer.  */
+         for (i = 0; i < nbytes; i += char_bytes)
+           {
+             c = string_char_and_length (m + i, nbytes - i, &char_bytes);
+             work[0] = (ASCII_CHAR_P (c)
+                        ? c
+                        : multibyte_char_to_unibyte (c, Qnil));
+             insert_1_both (work, 1, 1, 1, 0, 0);
+           }
+       }
+       else if (! multibyte
+              && ! NILP (current_buffer->enable_multibyte_characters))
+       {
+         int i, c, char_bytes;
+         unsigned char *msg = (unsigned char *) m;
+         unsigned char str[MAX_MULTIBYTE_LENGTH];
+         /* Convert a single-byte string to multibyte
+            for the *Message* buffer.  */
+         for (i = 0; i < nbytes; i++)
+           {
+             c = unibyte_char_to_multibyte (msg[i]);
+             char_bytes = CHAR_STRING (c, str);
+             insert_1_both (str, 1, char_bytes, 1, 0, 0);
+           }
+       }
+       else if (nbytes)
+       insert_1 (m, nbytes, 1, 0, 0);
+ 
+       if (nlflag)
+       {
+         int this_bol, this_bol_byte, prev_bol, prev_bol_byte, dup;
+         insert_1 ("\n", 1, 1, 0, 0);
+ 
+         scan_newline (Z, Z_BYTE, BEG, BEG_BYTE, -2, 0);
+         this_bol = PT;
+         this_bol_byte = PT_BYTE;
+ 
+         /* See if this line duplicates the previous one.
+            If so, combine duplicates.  */
+         if (this_bol > BEG)
+           {
+             scan_newline (PT, PT_BYTE, BEG, BEG_BYTE, -2, 0);
+             prev_bol = PT;
+             prev_bol_byte = PT_BYTE;
+ 
+             dup = message_log_check_duplicate (prev_bol, prev_bol_byte,
+                                                this_bol, this_bol_byte);
+             if (dup)
+               {
+                 del_range_both (prev_bol, prev_bol_byte,
+                                 this_bol, this_bol_byte, 0);
+                 if (dup > 1)
+                   {
+                     char dupstr[40];
+                     int duplen;
+ 
+                     /* If you change this format, don't forget to also
+                        change message_log_check_duplicate.  */
+                     sprintf (dupstr, " [%d times]", dup);
+                     duplen = strlen (dupstr);
+                     TEMP_SET_PT_BOTH (Z - 1, Z_BYTE - 1);
+                     insert_1 (dupstr, duplen, 1, 0, 1);
+                   }
+               }
+           }
+ 
+         /* If we have more than the desired maximum number of lines
+            in the *Messages* buffer now, delete the oldest ones.
+            This is safe because we don't have undo in this buffer.  */
+ 
+         if (NATNUMP (Vmessage_log_max))
+           {
+             scan_newline (Z, Z_BYTE, BEG, BEG_BYTE,
+                           -XFASTINT (Vmessage_log_max) - 1, 0);
+             del_range_both (BEG, BEG_BYTE, PT, PT_BYTE, 0);
+           }
+       }
+       BEGV = XMARKER (oldbegv)->charpos;
+       BEGV_BYTE = marker_byte_position (oldbegv);
+ 
+       if (zv_at_end)
+       {
+         ZV = Z;
+         ZV_BYTE = Z_BYTE;
+       }
+       else
+       {
+         ZV = XMARKER (oldzv)->charpos;
+         ZV_BYTE = marker_byte_position (oldzv);
+       }
+ 
+       if (point_at_end)
+       TEMP_SET_PT_BOTH (Z, Z_BYTE);
+       else
+       /* We can't do Fgoto_char (oldpoint) because it will run some
+            Lisp code.  */
+       TEMP_SET_PT_BOTH (XMARKER (oldpoint)->charpos,
+                         XMARKER (oldpoint)->bytepos);
+ 
+       UNGCPRO;
+       unchain_marker (XMARKER (oldpoint));
+       unchain_marker (XMARKER (oldbegv));
+       unchain_marker (XMARKER (oldzv));
+ 
+       tem = Fget_buffer_window (Fcurrent_buffer (), Qt);
+       set_buffer_internal (oldbuf);
+       if (NILP (tem))
+       windows_or_buffers_changed = old_windows_or_buffers_changed;
+       message_log_need_newline = !nlflag;
+       Vdeactivate_mark = old_deactivate_mark;
+     }
+ }
+ 
+ 
+ /* We are at the end of the buffer after just having inserted a newline.
+    (Note: We depend on the fact we won't be crossing the gap.)
+    Check to see if the most recent message looks a lot like the previous one.
+    Return 0 if different, 1 if the new one should just replace it, or a
+    value N > 1 if we should also append " [N times]".  */
+ 
+ static int
+ message_log_check_duplicate (prev_bol, prev_bol_byte, this_bol, this_bol_byte)
+      int prev_bol, this_bol;
+      int prev_bol_byte, this_bol_byte;
+ {
+   int i;
+   int len = Z_BYTE - 1 - this_bol_byte;
+   int seen_dots = 0;
+   unsigned char *p1 = BUF_BYTE_ADDRESS (current_buffer, prev_bol_byte);
+   unsigned char *p2 = BUF_BYTE_ADDRESS (current_buffer, this_bol_byte);
+ 
+   for (i = 0; i < len; i++)
+     {
+       if (i >= 3 && p1[i-3] == '.' && p1[i-2] == '.' && p1[i-1] == '.')
+       seen_dots = 1;
+       if (p1[i] != p2[i])
+       return seen_dots;
+     }
+   p1 += len;
+   if (*p1 == '\n')
+     return 2;
+   if (*p1++ == ' ' && *p1++ == '[')
+     {
+       int n = 0;
+       while (*p1 >= '0' && *p1 <= '9')
+       n = n * 10 + *p1++ - '0';
+       if (strncmp (p1, " times]\n", 8) == 0)
+       return n+1;
+     }
+   return 0;
+ }
+ 
+ 
+ /* Display an echo area message M with a specified length of NBYTES
+    bytes.  The string may include null characters.  If M is 0, clear
+    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.  */
+ 
+ void
+ message2 (m, nbytes, multibyte)
+      const char *m;
+      int nbytes;
+      int multibyte;
+ {
+   /* First flush out any partial line written with print.  */
+   message_log_maybe_newline ();
+   if (m)
+     message_dolog (m, nbytes, 1, multibyte);
+   message2_nolog (m, nbytes, multibyte);
+ }
+ 
+ 
+ /* The non-logging counterpart of message2.  */
+ 
+ void
+ message2_nolog (m, nbytes, multibyte)
+      const char *m;
+      int nbytes, multibyte;
+ {
+   struct frame *sf = SELECTED_FRAME ();
+   message_enable_multibyte = multibyte;
+ 
+   if (noninteractive)
+     {
+       if (noninteractive_need_newline)
+       putc ('\n', stderr);
+       noninteractive_need_newline = 0;
+       if (m)
+       fwrite (m, nbytes, 1, stderr);
+       if (cursor_in_echo_area == 0)
+       fprintf (stderr, "\n");
+       fflush (stderr);
+     }
+   /* A null message buffer means that the frame hasn't really been
+      initialized yet.  Error messages get reported properly by
+      cmd_error, so this must be just an informative message; toss it.  */
+   else if (INTERACTIVE
+          && sf->glyphs_initialized_p
+          && FRAME_MESSAGE_BUF (sf))
+     {
+       Lisp_Object mini_window;
+       struct frame *f;
+ 
+       /* Get the frame containing the mini-buffer
+        that the selected frame is using.  */
+       mini_window = FRAME_MINIBUF_WINDOW (sf);
+       f = XFRAME (WINDOW_FRAME (XWINDOW (mini_window)));
+ 
+       FRAME_SAMPLE_VISIBILITY (f);
+       if (FRAME_VISIBLE_P (sf)
+         && ! FRAME_VISIBLE_P (f))
+       Fmake_frame_visible (WINDOW_FRAME (XWINDOW (mini_window)));
+ 
+       if (m)
+       {
+         set_message (m, Qnil, nbytes, multibyte);
+         if (minibuffer_auto_raise)
+           Fraise_frame  (WINDOW_FRAME (XWINDOW (mini_window)));
+       }
+       else
+       clear_message (1, 1);
+ 
+       do_pending_window_change (0);
+       echo_area_display (1);
+       do_pending_window_change (0);
+       if (frame_up_to_date_hook != 0 && ! gc_in_progress)
+       (*frame_up_to_date_hook) (f);
+     }
+ }
+ 
+ 
+ /* 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.  */
+ 
+ void
+ message3 (m, nbytes, multibyte)
+      Lisp_Object m;
+      int nbytes;
+      int multibyte;
+ {
+   struct gcpro gcpro1;
+ 
+   GCPRO1 (m);
+ 
+   /* First flush out any partial line written with print.  */
+   message_log_maybe_newline ();
+   if (STRINGP (m))
+     message_dolog (SDATA (m), nbytes, 1, multibyte);
+   message3_nolog (m, nbytes, multibyte);
+ 
+   UNGCPRO;
+ }
+ 
+ 
+ /* The non-logging version of message3.  */
+ 
+ void
+ message3_nolog (m, nbytes, multibyte)
+      Lisp_Object m;
+      int nbytes, multibyte;
+ {
+   struct frame *sf = SELECTED_FRAME ();
+   message_enable_multibyte = multibyte;
+ 
+   if (noninteractive)
+     {
+       if (noninteractive_need_newline)
+       putc ('\n', stderr);
+       noninteractive_need_newline = 0;
+       if (STRINGP (m))
+       fwrite (SDATA (m), nbytes, 1, stderr);
+       if (cursor_in_echo_area == 0)
+       fprintf (stderr, "\n");
+       fflush (stderr);
+     }
+   /* A null message buffer means that the frame hasn't really been
+      initialized yet.  Error messages get reported properly by
+      cmd_error, so this must be just an informative message; toss it.  */
+   else if (INTERACTIVE
+          && sf->glyphs_initialized_p
+          && FRAME_MESSAGE_BUF (sf))
+     {
+       Lisp_Object mini_window;
+       Lisp_Object frame;
+       struct frame *f;
+ 
+       /* Get the frame containing the mini-buffer
+        that the selected frame is using.  */
+       mini_window = FRAME_MINIBUF_WINDOW (sf);
+       frame = XWINDOW (mini_window)->frame;
+       f = XFRAME (frame);
+ 
+       FRAME_SAMPLE_VISIBILITY (f);
+       if (FRAME_VISIBLE_P (sf)
+         && !FRAME_VISIBLE_P (f))
+       Fmake_frame_visible (frame);
+ 
+       if (STRINGP (m) && SCHARS (m) > 0)
+       {
+         set_message (NULL, m, nbytes, multibyte);
+         if (minibuffer_auto_raise)
+           Fraise_frame (frame);
+       }
+       else
+       clear_message (1, 1);
+ 
+       do_pending_window_change (0);
+       echo_area_display (1);
+       do_pending_window_change (0);
+       if (frame_up_to_date_hook != 0 && ! gc_in_progress)
+       (*frame_up_to_date_hook) (f);
+     }
+ }
+ 
+ 
+ /* Display a null-terminated echo area message M.  If M is 0, clear
+    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.  Do not pass
+    text that is stored in a Lisp string.  Do not pass text in a buffer
+    that was alloca'd.  */
+ 
+ void
+ message1 (m)
+      char *m;
+ {
+   message2 (m, (m ? strlen (m) : 0), 0);
+ }
+ 
+ 
+ /* The non-logging counterpart of message1.  */
+ 
+ void
+ message1_nolog (m)
+      char *m;
+ {
+   message2_nolog (m, (m ? strlen (m) : 0), 0);
+ }
+ 
+ /* Display a message M which contains a single %s
+    which gets replaced with STRING.  */
+ 
+ void
+ message_with_string (m, string, log)
+      char *m;
+      Lisp_Object string;
+      int log;
+ {
+   CHECK_STRING (string);
+ 
+   if (noninteractive)
+     {
+       if (m)
+       {
+         if (noninteractive_need_newline)
+           putc ('\n', stderr);
+         noninteractive_need_newline = 0;
+         fprintf (stderr, m, SDATA (string));
+         if (cursor_in_echo_area == 0)
+           fprintf (stderr, "\n");
+         fflush (stderr);
+       }
+     }
+   else if (INTERACTIVE)
+     {
+       /* The frame whose minibuffer we're going to display the message on.
+        It may be larger than the selected frame, so we need
+        to use its buffer, not the selected frame's buffer.  */
+       Lisp_Object mini_window;
+       struct frame *f, *sf = SELECTED_FRAME ();
+ 
+       /* Get the frame containing the minibuffer
+        that the selected frame is using.  */
+       mini_window = FRAME_MINIBUF_WINDOW (sf);
+       f = XFRAME (WINDOW_FRAME (XWINDOW (mini_window)));
+ 
+       /* A null message buffer means that the frame hasn't really been
+        initialized yet.  Error messages get reported properly by
+        cmd_error, so this must be just an informative message; toss it.  */
+       if (FRAME_MESSAGE_BUF (f))
+       {
+         Lisp_Object args[2], message;
+         struct gcpro gcpro1, gcpro2;
+ 
+         args[0] = build_string (m);
+         args[1] = message = string;
+         GCPRO2 (args[0], message);
+         gcpro1.nvars = 2;
+ 
+         message = Fformat (2, args);
+ 
+         if (log)
+           message3 (message, SBYTES (message), STRING_MULTIBYTE (message));
+         else
+           message3_nolog (message, SBYTES (message), STRING_MULTIBYTE 
(message));
+ 
+         UNGCPRO;
+ 
+         /* Print should start at the beginning of the message
+            buffer next time.  */
+         message_buf_print = 0;
+       }
+     }
+ }
+ 
+ 
+ /* Dump an informative message to the minibuf.  If M is 0, clear out
+    any existing message, and let the mini-buffer text show through.  */
+ 
+ /* VARARGS 1 */
+ void
+ message (m, a1, a2, a3)
+      char *m;
+      EMACS_INT a1, a2, a3;
+ {
+   if (noninteractive)
+     {
+       if (m)
+       {
+         if (noninteractive_need_newline)
+           putc ('\n', stderr);
+         noninteractive_need_newline = 0;
+         fprintf (stderr, m, a1, a2, a3);
+         if (cursor_in_echo_area == 0)
+           fprintf (stderr, "\n");
+         fflush (stderr);
+       }
+     }
+   else if (INTERACTIVE)
+     {
+       /* The frame whose mini-buffer we're going to display the message
+        on.  It may be larger than the selected frame, so we need to
+        use its buffer, not the selected frame's buffer.  */
+       Lisp_Object mini_window;
+       struct frame *f, *sf = SELECTED_FRAME ();
+ 
+       /* Get the frame containing the mini-buffer
+        that the selected frame is using.  */
+       mini_window = FRAME_MINIBUF_WINDOW (sf);
+       f = XFRAME (WINDOW_FRAME (XWINDOW (mini_window)));
+ 
+       /* A null message buffer means that the frame hasn't really been
+        initialized yet.  Error messages get reported properly by
+        cmd_error, so this must be just an informative message; toss
+        it.  */
+       if (FRAME_MESSAGE_BUF (f))
+       {
+         if (m)
+           {
+             int len;
+ #ifdef NO_ARG_ARRAY
+             char *a[3];
+             a[0] = (char *) a1;
+             a[1] = (char *) a2;
+             a[2] = (char *) a3;
+ 
+             len = doprnt (FRAME_MESSAGE_BUF (f),
+                           FRAME_MESSAGE_BUF_SIZE (f), m, (char *)0, 3, a);
+ #else
+             len = doprnt (FRAME_MESSAGE_BUF (f),
+                           FRAME_MESSAGE_BUF_SIZE (f), m, (char *)0, 3,
+                           (char **) &a1);
+ #endif /* NO_ARG_ARRAY */
+ 
+             message2 (FRAME_MESSAGE_BUF (f), len, 0);
+           }
+         else
+           message1 (0);
+ 
+         /* Print should start at the beginning of the message
+            buffer next time.  */
+         message_buf_print = 0;
+       }
+     }
+ }
+ 
+ 
+ /* The non-logging version of message.  */
+ 
+ void
+ message_nolog (m, a1, a2, a3)
+      char *m;
+      EMACS_INT a1, a2, a3;
+ {
+   Lisp_Object old_log_max;
+   old_log_max = Vmessage_log_max;
+   Vmessage_log_max = Qnil;
+   message (m, a1, a2, a3);
+   Vmessage_log_max = old_log_max;
+ }
+ 
+ 
+ /* Display the current message in the current mini-buffer.  This is
+    only called from error handlers in process.c, and is not time
+    critical.  */
+ 
+ void
+ update_echo_area ()
+ {
+   if (!NILP (echo_area_buffer[0]))
+     {
+       Lisp_Object string;
+       string = Fcurrent_message ();
+       message3 (string, SBYTES (string),
+               !NILP (current_buffer->enable_multibyte_characters));
+     }
+ }
+ 
+ 
+ /* Make sure echo area buffers in `echo_buffers' are live.
+    If they aren't, make new ones.  */
+ 
+ static void
+ ensure_echo_area_buffers ()
+ {
+   int i;
+ 
+   for (i = 0; i < 2; ++i)
+     if (!BUFFERP (echo_buffer[i])
+       || NILP (XBUFFER (echo_buffer[i])->name))
+       {
+       char name[30];
+       Lisp_Object old_buffer;
+       int j;
+ 
+       old_buffer = echo_buffer[i];
+       sprintf (name, " *Echo Area %d*", i);
+       echo_buffer[i] = Fget_buffer_create (build_string (name));
+       XBUFFER (echo_buffer[i])->truncate_lines = Qnil;
+ 
+       for (j = 0; j < 2; ++j)
+         if (EQ (old_buffer, echo_area_buffer[j]))
+           echo_area_buffer[j] = echo_buffer[i];
+       }
+ }
+ 
+ 
+ /* Call FN with args A1..A4 with either the current or last displayed
+    echo_area_buffer as current buffer.
+ 
+    WHICH zero means use the current message buffer
+    echo_area_buffer[0].  If that is nil, choose a suitable buffer
+    from echo_buffer[] and clear it.
+ 
+    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
+ with_echo_area_buffer (w, which, fn, a1, a2, a3, a4)
+      struct window *w;
+      int which;
+      int (*fn) P_ ((EMACS_INT, Lisp_Object, EMACS_INT, EMACS_INT));
+      EMACS_INT a1;
+      Lisp_Object a2;
+      EMACS_INT a3, a4;
+ {
+   Lisp_Object buffer;
+   int this_one, the_other, clear_buffer_p, rc;
+   int count = SPECPDL_INDEX ();
+ 
+   /* If buffers aren't live, make new ones.  */
+   ensure_echo_area_buffers ();
+ 
+   clear_buffer_p = 0;
+ 
+   if (which == 0)
+     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.  */
+   if (NILP (echo_area_buffer[this_one]))
+     {
+       echo_area_buffer[this_one]
+       = (EQ (echo_area_buffer[the_other], echo_buffer[this_one])
+          ? echo_buffer[the_other]
+          : echo_buffer[this_one]);
+       clear_buffer_p = 1;
+     }
+ 
+   buffer = echo_area_buffer[this_one];
+ 
+   /* Don't get confused by reusing the buffer used for echoing
+      for a different purpose.  */
+   if (echo_kboard == NULL && EQ (buffer, echo_message_buffer))
+     cancel_echoing ();
+ 
+   record_unwind_protect (unwind_with_echo_area_buffer,
+                        with_echo_area_buffer_unwind_data (w));
+ 
+   /* Make the echo area buffer current.  Note that for display
+      purposes, it is not necessary that the displayed window's buffer
+      == current_buffer, except for text property lookup.  So, let's
+      only set that buffer temporarily here without doing a full
+      Fset_window_buffer.  We must also change w->pointm, though,
+      because otherwise an assertions in unshow_buffer fails, and Emacs
+      aborts.  */
+   set_buffer_internal_1 (XBUFFER (buffer));
+   if (w)
+     {
+       w->buffer = buffer;
+       set_marker_both (w->pointm, buffer, BEG, BEG_BYTE);
+     }
+ 
+   current_buffer->undo_list = Qt;
+   current_buffer->read_only = Qnil;
+   specbind (Qinhibit_read_only, Qt);
+   specbind (Qinhibit_modification_hooks, Qt);
+ 
+   if (clear_buffer_p && Z > BEG)
+     del_range (BEG, Z);
+ 
+   xassert (BEGV >= BEG);
+   xassert (ZV <= Z && ZV >= BEGV);
+ 
+   rc = fn (a1, a2, a3, a4);
+ 
+   xassert (BEGV >= BEG);
+   xassert (ZV <= Z && ZV >= BEGV);
+ 
+   unbind_to (count, Qnil);
+   return rc;
+ }
+ 
+ 
+ /* Save state that should be preserved around the call to the function
+    FN called in with_echo_area_buffer.  */
+ 
+ static Lisp_Object
+ with_echo_area_buffer_unwind_data (w)
+      struct window *w;
+ {
+   int i = 0;
+   Lisp_Object vector;
+ 
+   /* Reduce consing by keeping one vector in
+      Vwith_echo_area_save_vector.  */
+   vector = Vwith_echo_area_save_vector;
+   Vwith_echo_area_save_vector = Qnil;
+ 
+   if (NILP (vector))
+     vector = Fmake_vector (make_number (7), Qnil);
+ 
+   XSETBUFFER (AREF (vector, i), current_buffer); ++i;
+   AREF (vector, i) = Vdeactivate_mark, ++i;
+   AREF (vector, i) = make_number (windows_or_buffers_changed), ++i;
+ 
+   if (w)
+     {
+       XSETWINDOW (AREF (vector, i), w); ++i;
+       AREF (vector, i) = w->buffer; ++i;
+       AREF (vector, i) = make_number (XMARKER (w->pointm)->charpos); ++i;
+       AREF (vector, i) = make_number (XMARKER (w->pointm)->bytepos); ++i;
+     }
+   else
+     {
+       int end = i + 4;
+       for (; i < end; ++i)
+       AREF (vector, i) = Qnil;
+     }
+ 
+   xassert (i == ASIZE (vector));
+   return vector;
+ }
+ 
+ 
+ /* Restore global state from VECTOR which was created by
+    with_echo_area_buffer_unwind_data.  */
+ 
+ static Lisp_Object
+ unwind_with_echo_area_buffer (vector)
+      Lisp_Object vector;
+ {
+   set_buffer_internal_1 (XBUFFER (AREF (vector, 0)));
+   Vdeactivate_mark = AREF (vector, 1);
+   windows_or_buffers_changed = XFASTINT (AREF (vector, 2));
+ 
+   if (WINDOWP (AREF (vector, 3)))
+     {
+       struct window *w;
+       Lisp_Object buffer, charpos, bytepos;
+ 
+       w = XWINDOW (AREF (vector, 3));
+       buffer = AREF (vector, 4);
+       charpos = AREF (vector, 5);
+       bytepos = AREF (vector, 6);
+ 
+       w->buffer = buffer;
+       set_marker_both (w->pointm, buffer,
+                      XFASTINT (charpos), XFASTINT (bytepos));
+     }
+ 
+   Vwith_echo_area_save_vector = vector;
+   return Qnil;
+ }
+ 
+ 
+ /* Set up the echo area for use by print functions.  MULTIBYTE_P
+    non-zero means we will print multibyte.  */
+ 
+ void
+ setup_echo_area_for_printing (multibyte_p)
+      int multibyte_p;
+ {
+   /* If we can't find an echo area any more, exit.  */
+   if (! FRAME_LIVE_P (XFRAME (selected_frame)))
+     Fkill_emacs (Qnil);
+ 
+   ensure_echo_area_buffers ();
+ 
+   if (!message_buf_print)
+     {
+       /* A message has been output since the last time we printed.
+        Choose a fresh echo area buffer.  */
+       if (EQ (echo_area_buffer[1], echo_buffer[0]))
+       echo_area_buffer[0] = echo_buffer[1];
+       else
+       echo_area_buffer[0] = echo_buffer[0];
+ 
+       /* Switch to that buffer and clear it.  */
+       set_buffer_internal (XBUFFER (echo_area_buffer[0]));
+       current_buffer->truncate_lines = Qnil;
+ 
+       if (Z > BEG)
+       {
+         int count = SPECPDL_INDEX ();
+         specbind (Qinhibit_read_only, Qt);
+         /* Note that undo recording is always disabled.  */
+         del_range (BEG, Z);
+         unbind_to (count, Qnil);
+       }
+       TEMP_SET_PT_BOTH (BEG, BEG_BYTE);
+ 
+       /* Set up the buffer for the multibyteness we need.  */
+       if (multibyte_p
+         != !NILP (current_buffer->enable_multibyte_characters))
+       Fset_buffer_multibyte (multibyte_p ? Qt : Qnil);
+ 
+       /* Raise the frame containing the echo area.  */
+       if (minibuffer_auto_raise)
+       {
+         struct frame *sf = SELECTED_FRAME ();
+         Lisp_Object mini_window;
+         mini_window = FRAME_MINIBUF_WINDOW (sf);
+         Fraise_frame  (WINDOW_FRAME (XWINDOW (mini_window)));
+       }
+ 
+       message_log_maybe_newline ();
+       message_buf_print = 1;
+     }
+   else
+     {
+       if (NILP (echo_area_buffer[0]))
+       {
+         if (EQ (echo_area_buffer[1], echo_buffer[0]))
+           echo_area_buffer[0] = echo_buffer[1];
+         else
+           echo_area_buffer[0] = echo_buffer[0];
+       }
+ 
+       if (current_buffer != XBUFFER (echo_area_buffer[0]))
+       {
+         /* Someone switched buffers between print requests.  */
+         set_buffer_internal (XBUFFER (echo_area_buffer[0]));
+         current_buffer->truncate_lines = Qnil;
+       }
+     }
+ }
+ 
+ 
+ /* Display an echo area message in window W.  Value is non-zero if W's
+    height is changed.  If display_last_displayed_message_p is
+    non-zero, display the message that was last displayed, otherwise
+    display the current message.  */
+ 
+ static int
+ display_echo_area (w)
+      struct window *w;
+ {
+   int i, no_message_p, window_height_changed_p, count;
+ 
+   /* Temporarily disable garbage collections while displaying the echo
+      area.  This is done because a GC can print a message itself.
+      That message would modify the echo area buffer's contents while a
+      redisplay of the buffer is going on, and seriously confuse
+      redisplay.  */
+   count = inhibit_garbage_collection ();
+ 
+   /* If there is no message, we must call display_echo_area_1
+      nevertheless because it resizes the window.  But we will have to
+      reset the echo_area_buffer in question to nil at the end because
+      with_echo_area_buffer will sets it to an empty buffer.  */
+   i = display_last_displayed_message_p ? 1 : 0;
+   no_message_p = NILP (echo_area_buffer[i]);
+ 
+   window_height_changed_p
+     = with_echo_area_buffer (w, display_last_displayed_message_p,
+                            display_echo_area_1,
+                            (EMACS_INT) w, Qnil, 0, 0);
+ 
+   if (no_message_p)
+     echo_area_buffer[i] = Qnil;
+ 
+   unbind_to (count, Qnil);
+   return window_height_changed_p;
+ }
+ 
+ 
+ /* Helper for display_echo_area.  Display the current buffer which
+    contains the current echo area message in window W, a mini-window,
+    a pointer to which is passed in A1.  A2..A4 are currently not used.
+    Change the height of W so that all of the message is displayed.
+    Value is non-zero if height of W was changed.  */
+ 
+ static int
+ display_echo_area_1 (a1, a2, a3, a4)
+      EMACS_INT a1;
+      Lisp_Object a2;
+      EMACS_INT a3, a4;
+ {
+   struct window *w = (struct window *) a1;
+   Lisp_Object window;
+   struct text_pos start;
+   int window_height_changed_p = 0;
+ 
+   /* Do this before displaying, so that we have a large enough glyph
+      matrix for the display.  */
+   window_height_changed_p = resize_mini_window (w, 0);
+ 
+   /* Display.  */
+   clear_glyph_matrix (w->desired_matrix);
+   XSETWINDOW (window, w);
+   SET_TEXT_POS (start, BEG, BEG_BYTE);
+   try_window (window, start);
+ 
+   return window_height_changed_p;
+ }
+ 
+ 
+ /* Resize the echo area window to exactly the size needed for the
+    currently displayed message, if there is one.  If a mini-buffer
+    is active, don't shrink it.  */
+ 
+ void
+ resize_echo_area_exactly ()
+ {
+   if (BUFFERP (echo_area_buffer[0])
+       && WINDOWP (echo_area_window))
+     {
+       struct window *w = XWINDOW (echo_area_window);
+       int resized_p;
+       Lisp_Object resize_exactly;
+ 
+       if (minibuf_level == 0)
+       resize_exactly = Qt;
+       else
+       resize_exactly = Qnil;
+ 
+       resized_p = with_echo_area_buffer (w, 0, resize_mini_window_1,
+                                        (EMACS_INT) w, resize_exactly, 0, 0);
+       if (resized_p)
+       {
+         ++windows_or_buffers_changed;
+         ++update_mode_lines;
+         redisplay_internal (0);
+       }
+     }
+ }
+ 
+ 
+ /* Callback function for with_echo_area_buffer, when used from
+    resize_echo_area_exactly.  A1 contains a pointer to the window to
+    resize, EXACTLY non-nil means resize the mini-window exactly to the
+    size of the text displayed.  A3 and A4 are not used.  Value is what
+    resize_mini_window returns.  */
+ 
+ static int
+ resize_mini_window_1 (a1, exactly, a3, a4)
+      EMACS_INT a1;
+      Lisp_Object exactly;
+      EMACS_INT a3, a4;
+ {
+   return resize_mini_window ((struct window *) a1, !NILP (exactly));
+ }
+ 
+ 
+ /* 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.  */
+ 
+ int
+ resize_mini_window (w, exact_p)
+      struct window *w;
+      int exact_p;
+ {
+   struct frame *f = XFRAME (w->frame);
+   int window_height_changed_p = 0;
+ 
+   xassert (MINI_WINDOW_P (w));
+ 
+   /* 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,
+      for instance, when which-func prints a long message while
+      we are running fontification-functions.  We're running these
+      functions with safe_call which binds inhibit-redisplay to t.  */
+   if (!NILP (Vinhibit_redisplay))
+     return 0;
+ 
+   /* Nil means don't try to resize.  */
+   if (NILP (Vresize_mini_windows)
+       || (FRAME_X_P (f) && FRAME_X_OUTPUT (f) == NULL))
+     return 0;
+ 
+   if (!FRAME_MINIBUF_ONLY_P (f))
+     {
+       struct it it;
+       struct window *root = XWINDOW (FRAME_ROOT_WINDOW (f));
+       int total_height = WINDOW_TOTAL_LINES (root) + WINDOW_TOTAL_LINES (w);
+       int height, max_height;
+       int unit = FRAME_LINE_HEIGHT (f);
+       struct text_pos start;
+       struct buffer *old_current_buffer = NULL;
+ 
+       if (current_buffer != XBUFFER (w->buffer))
+       {
+         old_current_buffer = current_buffer;
+         set_buffer_internal (XBUFFER (w->buffer));
+       }
+ 
+       init_iterator (&it, w, BEGV, BEGV_BYTE, NULL, DEFAULT_FACE_ID);
+ 
+       /* Compute the max. number of lines specified by the user.  */
+       if (FLOATP (Vmax_mini_window_height))
+       max_height = XFLOATINT (Vmax_mini_window_height) * FRAME_LINES (f);
+       else if (INTEGERP (Vmax_mini_window_height))
+       max_height = XINT (Vmax_mini_window_height);
+       else
+       max_height = total_height / 4;
+ 
+       /* Correct that max. height if it's bogus.  */
+       max_height = max (1, max_height);
+       max_height = min (total_height, max_height);
+ 
+       /* Find out the height of the text in the window.  */
+       if (it.truncate_lines_p)
+       height = 1;
+       else
+       {
+         last_height = 0;
+         move_it_to (&it, ZV, -1, -1, -1, MOVE_TO_POS);
+         if (it.max_ascent == 0 && it.max_descent == 0)
+           height = it.current_y + last_height;
+         else
+           height = it.current_y + it.max_ascent + it.max_descent;
+         height -= it.extra_line_spacing;
+         height = (height + unit - 1) / unit;
+       }
+ 
+       /* Compute a suitable window start.  */
+       if (height > max_height)
+       {
+         height = max_height;
+         init_iterator (&it, w, PT, PT_BYTE, NULL, DEFAULT_FACE_ID);
+         move_it_vertically_backward (&it, (height - 1) * unit);
+         start = it.current.pos;
+       }
+       else
+       SET_TEXT_POS (start, BEGV, BEGV_BYTE);
+       SET_MARKER_FROM_TEXT_POS (w->start, start);
+ 
+       if (EQ (Vresize_mini_windows, Qgrow_only))
+       {
+         /* Let it grow only, until we display an empty message, in which
+            case the window shrinks again.  */
+         if (height > WINDOW_TOTAL_LINES (w))
+           {
+             int old_height = WINDOW_TOTAL_LINES (w);
+             freeze_window_starts (f, 1);
+             grow_mini_window (w, height - WINDOW_TOTAL_LINES (w));
+             window_height_changed_p = WINDOW_TOTAL_LINES (w) != old_height;
+           }
+         else if (height < WINDOW_TOTAL_LINES (w)
+                  && (exact_p || BEGV == ZV))
+           {
+             int old_height = WINDOW_TOTAL_LINES (w);
+             freeze_window_starts (f, 0);
+             shrink_mini_window (w);
+             window_height_changed_p = WINDOW_TOTAL_LINES (w) != old_height;
+           }
+       }
+       else
+       {
+         /* Always resize to exact size needed.  */
+         if (height > WINDOW_TOTAL_LINES (w))
+           {
+             int old_height = WINDOW_TOTAL_LINES (w);
+             freeze_window_starts (f, 1);
+             grow_mini_window (w, height - WINDOW_TOTAL_LINES (w));
+             window_height_changed_p = WINDOW_TOTAL_LINES (w) != old_height;
+           }
+         else if (height < WINDOW_TOTAL_LINES (w))
+           {
+             int old_height = WINDOW_TOTAL_LINES (w);
+             freeze_window_starts (f, 0);
+             shrink_mini_window (w);
+ 
+             if (height)
+               {
+                 freeze_window_starts (f, 1);
+                 grow_mini_window (w, height - WINDOW_TOTAL_LINES (w));
+               }
+ 
+             window_height_changed_p = WINDOW_TOTAL_LINES (w) != old_height;
+           }
+       }
+ 
+       if (old_current_buffer)
+       set_buffer_internal (old_current_buffer);
+     }
+ 
+   return window_height_changed_p;
+ }
+ 
+ 
+ /* Value is the current message, a string, or nil if there is no
+    current message.  */
+ 
+ Lisp_Object
+ current_message ()
+ {
+   Lisp_Object msg;
+ 
+   if (NILP (echo_area_buffer[0]))
+     msg = Qnil;
+   else
+     {
+       with_echo_area_buffer (0, 0, current_message_1,
+                            (EMACS_INT) &msg, Qnil, 0, 0);
+       if (NILP (msg))
+       echo_area_buffer[0] = Qnil;
+     }
+ 
+   return msg;
+ }
+ 
+ 
+ static int
+ current_message_1 (a1, a2, a3, a4)
+      EMACS_INT a1;
+      Lisp_Object a2;
+      EMACS_INT a3, a4;
+ {
+   Lisp_Object *msg = (Lisp_Object *) a1;
+ 
+   if (Z > BEG)
+     *msg = make_buffer_string (BEG, Z, 1);
+   else
+     *msg = Qnil;
+   return 0;
+ }
+ 
+ 
+ /* Push the current message on Vmessage_stack for later restauration
+    by restore_message.  Value is non-zero if the current message isn't
+    empty.  This is a relatively infrequent operation, so it's not
+    worth optimizing.  */
+ 
+ int
+ push_message ()
+ {
+   Lisp_Object msg;
+   msg = current_message ();
+   Vmessage_stack = Fcons (msg, Vmessage_stack);
+   return STRINGP (msg);
+ }
+ 
+ 
+ /* Restore message display from the top of Vmessage_stack.  */
+ 
+ void
+ restore_message ()
+ {
+   Lisp_Object msg;
+ 
+   xassert (CONSP (Vmessage_stack));
+   msg = XCAR (Vmessage_stack);
+   if (STRINGP (msg))
+     message3_nolog (msg, SBYTES (msg), STRING_MULTIBYTE (msg));
+   else
+     message3_nolog (msg, 0, 0);
+ }
+ 
+ 
+ /* Handler for record_unwind_protect calling pop_message.  */
+ 
+ Lisp_Object
+ pop_message_unwind (dummy)
+      Lisp_Object dummy;
+ {
+   pop_message ();
+   return Qnil;
+ }
+ 
+ /* Pop the top-most entry off Vmessage_stack.  */
+ 
+ void
+ pop_message ()
+ {
+   xassert (CONSP (Vmessage_stack));
+   Vmessage_stack = XCDR (Vmessage_stack);
+ }
+ 
+ 
+ /* Check that Vmessage_stack is nil.  Called from emacs.c when Emacs
+    exits.  If the stack is not empty, we have a missing pop_message
+    somewhere.  */
+ 
+ void
+ check_message_stack ()
+ {
+   if (!NILP (Vmessage_stack))
+     abort ();
+ }
+ 
+ 
+ /* Truncate to NCHARS what will be displayed in the echo area the next
+    time we display it---but don't redisplay it now.  */
+ 
+ void
+ truncate_echo_area (nchars)
+      int nchars;
+ {
+   if (nchars == 0)
+     echo_area_buffer[0] = Qnil;
+   /* A null message buffer means that the frame hasn't really been
+      initialized yet.  Error messages get reported properly by
+      cmd_error, so this must be just an informative message; toss it.  */
+   else if (!noninteractive
+          && INTERACTIVE
+          && !NILP (echo_area_buffer[0]))
+     {
+       struct frame *sf = SELECTED_FRAME ();
+       if (FRAME_MESSAGE_BUF (sf))
+       with_echo_area_buffer (0, 0, truncate_message_1, nchars, Qnil, 0, 0);
+     }
+ }
+ 
+ 
+ /* Helper function for truncate_echo_area.  Truncate the current
+    message to at most NCHARS characters.  */
+ 
+ static int
+ truncate_message_1 (nchars, a2, a3, a4)
+      EMACS_INT nchars;
+      Lisp_Object a2;
+      EMACS_INT a3, a4;
+ {
+   if (BEG + nchars < Z)
+     del_range (BEG + nchars, Z);
+   if (Z == BEG)
+     echo_area_buffer[0] = Qnil;
+   return 0;
+ }
+ 
+ 
+ /* Set the current message to a substring of S or STRING.
+ 
+    If STRING is a Lisp string, set the message to the first NBYTES
+    bytes from STRING.  NBYTES zero means use the whole string.  If
+    STRING is multibyte, the message will be displayed multibyte.
+ 
+    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.  */
+ 
+ void
+ set_message (s, string, nbytes, multibyte_p)
+      const char *s;
+      Lisp_Object string;
+      int nbytes, multibyte_p;
+ {
+   message_enable_multibyte
+     = ((s && multibyte_p)
+        || (STRINGP (string) && STRING_MULTIBYTE (string)));
+ 
+   with_echo_area_buffer (0, -1, set_message_1,
+                        (EMACS_INT) s, string, nbytes, multibyte_p);
+   message_buf_print = 0;
+   help_echo_showing_p = 0;
+ }
+ 
+ 
+ /* Helper function for set_message.  Arguments have the same meaning
+    as there, with A1 corresponding to S and A2 corresponding to STRING
+    This function is called with the echo area buffer being
+    current.  */
+ 
+ static int
+ set_message_1 (a1, a2, nbytes, multibyte_p)
+      EMACS_INT a1;
+      Lisp_Object a2;
+      EMACS_INT 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))
+     Fset_buffer_multibyte (message_enable_multibyte ? Qt : Qnil);
+ 
+   current_buffer->truncate_lines = message_truncate_lines ? Qt : Qnil;
+ 
+   /* Insert new message at BEG.  */
+   TEMP_SET_PT_BOTH (BEG, BEG_BYTE);
+ 
+   if (STRINGP (string))
+     {
+       int nchars;
+ 
+       if (nbytes == 0)
+       nbytes = SBYTES (string);
+       nchars = string_byte_to_char (string, nbytes);
+ 
+       /* This function takes care of single/multibyte conversion.  We
+          just have to ensure that the echo area buffer has the right
+          setting of enable_multibyte_characters.  */
+       insert_from_string (string, 0, 0, nchars, nbytes, 1);
+     }
+   else if (s)
+     {
+       if (nbytes == 0)
+       nbytes = strlen (s);
+ 
+       if (multibyte_p && NILP (current_buffer->enable_multibyte_characters))
+       {
+         /* Convert from multi-byte to single-byte.  */
+         int i, c, n;
+         unsigned char work[1];
+ 
+         /* Convert a multibyte string to single-byte.  */
+         for (i = 0; i < nbytes; i += n)
+           {
+             c = string_char_and_length (s + i, nbytes - i, &n);
+             work[0] = (ASCII_CHAR_P (c)
+                        ? c
+                        : multibyte_char_to_unibyte (c, Qnil));
+             insert_1_both (work, 1, 1, 1, 0, 0);
+           }
+       }
+       else if (!multibyte_p
+              && !NILP (current_buffer->enable_multibyte_characters))
+       {
+         /* Convert from single-byte to multi-byte.  */
+         int i, c, n;
+         const unsigned char *msg = (const unsigned char *) s;
+         unsigned char str[MAX_MULTIBYTE_LENGTH];
+ 
+         /* Convert a single-byte string to multibyte.  */
+         for (i = 0; i < nbytes; i++)
+           {
+             c = unibyte_char_to_multibyte (msg[i]);
+             n = CHAR_STRING (c, str);
+             insert_1_both (str, 1, n, 1, 0, 0);
+           }
+       }
+       else
+       insert_1 (s, nbytes, 1, 0, 0);
+     }
+ 
+   return 0;
+ }
+ 
+ 
+ /* Clear messages.  CURRENT_P non-zero means clear the current
+    message.  LAST_DISPLAYED_P non-zero means clear the message
+    last displayed.  */
+ 
+ void
+ clear_message (current_p, last_displayed_p)
+      int current_p, last_displayed_p;
+ {
+   if (current_p)
+     {
+       echo_area_buffer[0] = Qnil;
+       message_cleared_p = 1;
+     }
+ 
+   if (last_displayed_p)
+     echo_area_buffer[1] = Qnil;
+ 
+   message_buf_print = 0;
+ }
+ 
+ /* Clear garbaged frames.
+ 
+    This function is used where the old redisplay called
+    redraw_garbaged_frames which in turn called redraw_frame which in
+    turn called clear_frame.  The call to clear_frame was a source of
+    flickering.  I believe a clear_frame is not necessary.  It should
+    suffice in the new redisplay to invalidate all current matrices,
+    and ensure a complete redisplay of all windows.  */
+ 
+ static void
+ clear_garbaged_frames ()
+ {
+   if (frame_garbaged)
+     {
+       Lisp_Object tail, frame;
+       int changed_count = 0;
+ 
+       FOR_EACH_FRAME (tail, frame)
+       {
+         struct frame *f = XFRAME (frame);
+ 
+         if (FRAME_VISIBLE_P (f) && FRAME_GARBAGED_P (f))
+           {
+             if (f->resized_p)
+               Fredraw_frame (frame);
+             clear_current_matrices (f);
+             changed_count++;
+             f->garbaged = 0;
+             f->resized_p = 0;
+           }
+       }
+ 
+       frame_garbaged = 0;
+       if (changed_count)
+       ++windows_or_buffers_changed;
+     }
+ }
+ 
+ 
+ /* Redisplay the echo area of the selected frame.  If UPDATE_FRAME_P
+    is non-zero update selected_frame.  Value is non-zero if the
+    mini-windows height has been changed.  */
+ 
+ static int
+ echo_area_display (update_frame_p)
+      int update_frame_p;
+ {
+   Lisp_Object mini_window;
+   struct window *w;
+   struct frame *f;
+   int window_height_changed_p = 0;
+   struct frame *sf = SELECTED_FRAME ();
+ 
+   mini_window = FRAME_MINIBUF_WINDOW (sf);
+   w = XWINDOW (mini_window);
+   f = XFRAME (WINDOW_FRAME (w));
+ 
+   /* Don't display if frame is invisible or not yet initialized.  */
+   if (!FRAME_VISIBLE_P (f) || !f->glyphs_initialized_p)
+     return 0;
+ 
+ /* The terminal frame is used as the first Emacs frame on the Mac OS.  */
+ #ifndef MAC_OS8
+ #ifdef HAVE_WINDOW_SYSTEM
+   /* When Emacs starts, selected_frame may be a visible terminal
+      frame, even if we run under a window system.  If we let this
+      through, a message would be displayed on the terminal.  */
+   if (EQ (selected_frame, Vterminal_frame)
+       && !NILP (Vwindow_system))
+     return 0;
+ #endif /* HAVE_WINDOW_SYSTEM */
+ #endif
+ 
+   /* Redraw garbaged frames.  */
+   if (frame_garbaged)
+     clear_garbaged_frames ();
+ 
+   if (!NILP (echo_area_buffer[0]) || minibuf_level == 0)
+     {
+       echo_area_window = mini_window;
+       window_height_changed_p = display_echo_area (w);
+       w->must_be_updated_p = 1;
+ 
+       /* Update the display, unless called from redisplay_internal.
+        Also don't update the screen during redisplay itself.  The
+        update will happen at the end of redisplay, and an update
+        here could cause confusion.  */
+       if (update_frame_p && !redisplaying_p)
+       {
+         int n = 0;
+ 
+         /* If the display update has been interrupted by pending
+            input, update mode lines in the frame.  Due to the
+            pending input, it might have been that redisplay hasn't
+            been called, so that mode lines above the echo area are
+            garbaged.  This looks odd, so we prevent it here.  */
+         if (!display_completed)
+           n = redisplay_mode_lines (FRAME_ROOT_WINDOW (f), 0);
+ 
+         if (window_height_changed_p
+             /* Don't do this if Emacs is shutting down.  Redisplay
+                needs to run hooks.  */
+             && !NILP (Vrun_hooks))
+           {
+             /* Must update other windows.  Likewise as in other
+                cases, don't let this update be interrupted by
+                pending input.  */
+             int count = SPECPDL_INDEX ();
+             specbind (Qredisplay_dont_pause, Qt);
+             windows_or_buffers_changed = 1;
+             redisplay_internal (0);
+             unbind_to (count, Qnil);
+           }
+         else if (FRAME_WINDOW_P (f) && n == 0)
+           {
+             /* Window configuration is the same as before.
+                Can do with a display update of the echo area,
+                unless we displayed some mode lines.  */
+             update_single_window (w, 1);
+             rif->flush_display (f);
+           }
+         else
+           update_frame (f, 1, 1);
+ 
+         /* If cursor is in the echo area, make sure that the next
+            redisplay displays the minibuffer, so that the cursor will
+            be replaced with what the minibuffer wants.  */
+         if (cursor_in_echo_area)
+           ++windows_or_buffers_changed;
+       }
+     }
+   else if (!EQ (mini_window, selected_window))
+     windows_or_buffers_changed++;
+ 
+   /* Last displayed message is now the current message.  */
+   echo_area_buffer[1] = echo_area_buffer[0];
+ 
+   /* Prevent redisplay optimization in redisplay_internal by resetting
+      this_line_start_pos.  This is done because the mini-buffer now
+      displays the message instead of its buffer text.  */
+   if (EQ (mini_window, selected_window))
+     CHARPOS (this_line_start_pos) = 0;
+ 
+   return window_height_changed_p;
+ }
+ 
+ 
+ 
+ /***********************************************************************
+                            Frame Titles
+  ***********************************************************************/
+ 
+ 
+ /* The frame title buffering code is also used by Fformat_mode_line.
+    So it is not conditioned by HAVE_WINDOW_SYSTEM.  */
+ 
+ /* 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 *frame_title_buf;
+ 
+ /* The buffer's end, and a current output position in it.  */
+ 
+ static char *frame_title_buf_end;
+ static char *frame_title_ptr;
+ 
+ 
+ /* Store a single character C for the frame title in frame_title_buf.
+    Re-allocate frame_title_buf if necessary.  */
+ 
+ static void
+ #ifdef PROTOTYPES
+ store_frame_title_char (char c)
+ #else
+ store_frame_title_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)
+     {
+       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;
+     }
+ 
+   *frame_title_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
+    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
+    pad.  Called from display_mode_element when it is used to build a
+    frame title.  */
+ 
+ static int
+ store_frame_title (str, field_width, precision)
+      const unsigned char *str;
+      int field_width, precision;
+ {
+   int n = 0;
+   int dummy, nbytes;
+ 
+   /* Copy at most PRECISION chars from STR.  */
+   nbytes = strlen (str);
+   n+= c_string_width (str, nbytes, precision, &dummy, &nbytes);
+   while (nbytes--)
+     store_frame_title_char (*str++);
+ 
+   /* Fill up with spaces until FIELD_WIDTH reached.  */
+   while (field_width > 0
+        && n < field_width)
+     {
+       store_frame_title_char (' ');
+       ++n;
+     }
+ 
+   return n;
+ }
+ 
+ #ifdef HAVE_WINDOW_SYSTEM
+ 
+ /* Set the title of FRAME, if it has changed.  The title format is
+    Vicon_title_format if FRAME is iconified, otherwise it is
+    frame_title_format.  */
+ 
+ static void
+ x_consider_frame_title (frame)
+      Lisp_Object frame;
+ {
+   struct frame *f = XFRAME (frame);
+ 
+   if (FRAME_WINDOW_P (f)
+       || FRAME_MINIBUF_ONLY_P (f)
+       || f->explicit_name)
+     {
+       /* Do we have more than one visible frame on this X display?  */
+       Lisp_Object tail;
+       Lisp_Object fmt;
+       struct buffer *obuf;
+       int len;
+       struct it it;
+ 
+       for (tail = Vframe_list; CONSP (tail); tail = XCDR (tail))
+       {
+         Lisp_Object other_frame = XCAR (tail);
+         struct frame *tf = XFRAME (other_frame);
+ 
+         if (tf != f
+             && FRAME_KBOARD (tf) == FRAME_KBOARD (f)
+             && !FRAME_MINIBUF_ONLY_P (tf)
+             && !EQ (other_frame, tip_frame)
+             && (FRAME_VISIBLE_P (tf) || FRAME_ICONIFIED_P (tf)))
+           break;
+       }
+ 
+       /* Set global variable indicating that multiple frames exist.  */
+       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;
+       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;
+       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);
+ 
+       /* 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
+        already wasted too much time by walking through the list with
+        display_mode_element, then we might need to optimize at a
+        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);
+     }
+ }
+ 
+ #endif /* not HAVE_WINDOW_SYSTEM */
+ 
+ 
+ 
+ 
+ /***********************************************************************
+                             Menu Bars
+  ***********************************************************************/
+ 
+ 
+ /* Prepare for redisplay by updating menu-bar item lists when
+    appropriate.  This can call eval.  */
+ 
+ void
+ prepare_menu_bars ()
+ {
+   int all_windows;
+   struct gcpro gcpro1, gcpro2;
+   struct frame *f;
+   Lisp_Object tooltip_frame;
+ 
+ #ifdef HAVE_WINDOW_SYSTEM
+   tooltip_frame = tip_frame;
+ #else
+   tooltip_frame = Qnil;
+ #endif
+ 
+   /* Update all frame titles based on their buffer names, etc.  We do
+      this before the menu bars so that the buffer-menu will show the
+      up-to-date frame titles.  */
+ #ifdef HAVE_WINDOW_SYSTEM
+   if (windows_or_buffers_changed || update_mode_lines)
+     {
+       Lisp_Object tail, frame;
+ 
+       FOR_EACH_FRAME (tail, frame)
+       {
+         f = XFRAME (frame);
+         if (!EQ (frame, tooltip_frame)
+             && (FRAME_VISIBLE_P (f) || FRAME_ICONIFIED_P (f)))
+           x_consider_frame_title (frame);
+       }
+     }
+ #endif /* HAVE_WINDOW_SYSTEM */
+ 
+   /* Update the menu bar item lists, if appropriate.  This has to be
+      done before any actual redisplay or generation of display lines.  */
+   all_windows = (update_mode_lines
+                || buffer_shared > 1
+                || windows_or_buffers_changed);
+   if (all_windows)
+     {
+       Lisp_Object tail, frame;
+       int count = SPECPDL_INDEX ();
+ 
+       record_unwind_protect (Fset_match_data, Fmatch_data (Qnil, Qnil));
+ 
+       FOR_EACH_FRAME (tail, frame)
+       {
+         f = XFRAME (frame);
+ 
+         /* Ignore tooltip frame.  */
+         if (EQ (frame, tooltip_frame))
+           continue;
+ 
+         /* If a window on this frame changed size, report that to
+            the user and clear the size-change flag.  */
+         if (FRAME_WINDOW_SIZES_CHANGED (f))
+           {
+             Lisp_Object functions;
+ 
+             /* Clear flag first in case we get an error below.  */
+             FRAME_WINDOW_SIZES_CHANGED (f) = 0;
+             functions = Vwindow_size_change_functions;
+             GCPRO2 (tail, functions);
+ 
+             while (CONSP (functions))
+               {
+                 call1 (XCAR (functions), frame);
+                 functions = XCDR (functions);
+               }
+             UNGCPRO;
+           }
+ 
+         GCPRO1 (tail);
+         update_menu_bar (f, 0);
+ #ifdef HAVE_WINDOW_SYSTEM
+         update_tool_bar (f, 0);
+ #endif
+         UNGCPRO;
+       }
+ 
+       unbind_to (count, Qnil);
+     }
+   else
+     {
+       struct frame *sf = SELECTED_FRAME ();
+       update_menu_bar (sf, 1);
+ #ifdef HAVE_WINDOW_SYSTEM
+       update_tool_bar (sf, 1);
+ #endif
+     }
+ 
+   /* Motif needs this.  See comment in xmenu.c.  Turn it off when
+      pending_menu_activation is not defined.  */
+ #ifdef USE_X_TOOLKIT
+   pending_menu_activation = 0;
+ #endif
+ }
+ 
+ 
+ /* Update the menu bar item list for frame F.  This has to be done
+    before we start to fill in any display lines, because it can call
+    eval.
+ 
+    If SAVE_MATCH_DATA is non-zero, we must save and restore it here.  */
+ 
+ static void
+ update_menu_bar (f, save_match_data)
+      struct frame *f;
+      int save_match_data;
+ {
+   Lisp_Object window;
+   register struct window *w;
+ 
+   /* If called recursively during a menu update, do nothing.  This can
+      happen when, for instance, an activate-menubar-hook causes a
+      redisplay.  */
+   if (inhibit_menubar_update)
+     return;
+ 
+   window = FRAME_SELECTED_WINDOW (f);
+   w = XWINDOW (window);
+ 
+ #if 0 /* The if statement below this if statement used to include the
+          condition !NILP (w->update_mode_line), rather than using
+          update_mode_lines directly, and this if statement may have
+          been added to make that condition work.  Now the if
+          statement below matches its comment, this isn't needed.  */
+   if (update_mode_lines)
+     w->update_mode_line = Qt;
+ #endif
+ 
+   if (FRAME_WINDOW_P (f)
+       ?
+ #if defined (USE_X_TOOLKIT) || defined (HAVE_NTGUI) || defined (MAC_OS) \
+     || defined (USE_GTK)
+       FRAME_EXTERNAL_MENU_BAR (f)
+ #else
+       FRAME_MENU_BAR_LINES (f) > 0
+ #endif
+       : FRAME_MENU_BAR_LINES (f) > 0)
+     {
+       /* If the user has switched buffers or windows, we need to
+        recompute to reflect the new bindings.  But we'll
+        recompute when update_mode_lines is set too; that means
+        that people can use force-mode-line-update to request
+        that the menu bar be recomputed.  The adverse effect on
+        the rest of the redisplay algorithm is about the same as
+        windows_or_buffers_changed anyway.  */
+       if (windows_or_buffers_changed
+         /* This used to test w->update_mode_line, but we believe
+            there is no need to recompute the menu in that case.  */
+         || update_mode_lines
+         || ((BUF_SAVE_MODIFF (XBUFFER (w->buffer))
+              < BUF_MODIFF (XBUFFER (w->buffer)))
+             != !NILP (w->last_had_star))
+         || ((!NILP (Vtransient_mark_mode)
+              && !NILP (XBUFFER (w->buffer)->mark_active))
+             != !NILP (w->region_showing)))
+       {
+         struct buffer *prev = current_buffer;
+         int count = SPECPDL_INDEX ();
+ 
+         specbind (Qinhibit_menubar_update, Qt);
+ 
+         set_buffer_internal_1 (XBUFFER (w->buffer));
+         if (save_match_data)
+           record_unwind_protect (Fset_match_data, Fmatch_data (Qnil, Qnil));
+         if (NILP (Voverriding_local_map_menu_flag))
+           {
+             specbind (Qoverriding_terminal_local_map, Qnil);
+             specbind (Qoverriding_local_map, Qnil);
+           }
+ 
+         /* Run the Lucid hook.  */
+         safe_run_hooks (Qactivate_menubar_hook);
+ 
+         /* If it has changed current-menubar from previous value,
+            really recompute the menu-bar from the value.  */
+         if (! NILP (Vlucid_menu_bar_dirty_flag))
+           call0 (Qrecompute_lucid_menubar);
+ 
+         safe_run_hooks (Qmenu_bar_update_hook);
+         FRAME_MENU_BAR_ITEMS (f) = menu_bar_items (FRAME_MENU_BAR_ITEMS (f));
+ 
+         /* 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 ()
+ #endif
+            )
+           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.  */
+           w->update_mode_line = Qt;
+ #else /* ! (USE_X_TOOLKIT || HAVE_NTGUI || MAC_OS || USE_GTK) */
+         /* In the non-toolkit version, the menu bar is an ordinary screen
+            line, and this makes it get updated.  */
+         w->update_mode_line = Qt;
+ #endif /* ! (USE_X_TOOLKIT || HAVE_NTGUI || MAC_OS || USE_GTK) */
+ 
+         unbind_to (count, Qnil);
+         set_buffer_internal_1 (prev);
+       }
+     }
+ }
+ 
+ 
+ 
+ /***********************************************************************
+                           Output Cursor
+  ***********************************************************************/
+ 
+ #ifdef HAVE_WINDOW_SYSTEM
+ 
+ /* EXPORT:
+    Nominal cursor position -- where to draw output.
+    HPOS and VPOS are window relative glyph matrix coordinates.
+    X and Y are window relative pixel coordinates.  */
+ 
+ struct cursor_pos output_cursor;
+ 
+ 
+ /* EXPORT:
+    Set the global variable output_cursor to CURSOR.  All cursor
+    positions are relative to updated_window.  */
+ 
+ void
+ set_output_cursor (cursor)
+     struct cursor_pos *cursor;
+ {
+   output_cursor.hpos = cursor->hpos;
+   output_cursor.vpos = cursor->vpos;
+   output_cursor.x = cursor->x;
+   output_cursor.y = cursor->y;
+ }
+ 
+ 
+ /* EXPORT for RIF:
+    Set a nominal cursor position.
+ 
+    HPOS and VPOS are column/row positions in a window glyph matrix.  X
+    and Y are window text area relative pixel positions.
+ 
+    If this is done during an update, updated_window will contain the
+    window that is being updated and the position is the future output
+    cursor position for that window.  If updated_window is null, use
+    selected_window and display the cursor at the given position.  */
+ 
+ void
+ x_cursor_to (vpos, hpos, y, x)
+      int vpos, hpos, y, x;
+ {
+   struct window *w;
+ 
+   /* If updated_window is not set, work on selected_window.  */
+   if (updated_window)
+     w = updated_window;
+   else
+     w = XWINDOW (selected_window);
+ 
+   /* Set the output cursor.  */
+   output_cursor.hpos = hpos;
+   output_cursor.vpos = vpos;
+   output_cursor.x = x;
+   output_cursor.y = y;
+ 
+   /* If not called as part of an update, really display the cursor.
+      This will also set the cursor position of W.  */
+   if (updated_window == NULL)
+     {
+       BLOCK_INPUT;
+       display_and_set_cursor (w, 1, hpos, vpos, x, y);
+       if (rif->flush_display_optional)
+       rif->flush_display_optional (SELECTED_FRAME ());
+       UNBLOCK_INPUT;
+     }
+ }
+ 
+ #endif /* HAVE_WINDOW_SYSTEM */
+ 
+ 
+ /***********************************************************************
+                              Tool-bars
+  ***********************************************************************/
+ 
+ #ifdef HAVE_WINDOW_SYSTEM
+ 
+ /* Where the mouse was last time we reported a mouse event.  */
+ 
+ FRAME_PTR last_mouse_frame;
+ 
+ /* Tool-bar item index of the item on which a mouse button was pressed
+    or -1.  */
+ 
+ int last_tool_bar_item;
+ 
+ 
+ /* Update the tool-bar item list for frame F.  This has to be done
+    before we start to fill in any display lines.  Called from
+    prepare_menu_bars.  If SAVE_MATCH_DATA is non-zero, we must save
+    and restore it here.  */
+ 
+ static void
+ update_tool_bar (f, save_match_data)
+      struct frame *f;
+      int save_match_data;
+ {
+ #ifdef USE_GTK
+   int do_update = FRAME_EXTERNAL_TOOL_BAR(f);
+ #else
+   int do_update = WINDOWP (f->tool_bar_window)
+     && WINDOW_TOTAL_LINES (XWINDOW (f->tool_bar_window)) > 0;
+ #endif
+ 
+   if (do_update)
+     {
+       Lisp_Object window;
+       struct window *w;
+ 
+       window = FRAME_SELECTED_WINDOW (f);
+       w = XWINDOW (window);
+ 
+       /* If the user has switched buffers or windows, we need to
+        recompute to reflect the new bindings.  But we'll
+        recompute when update_mode_lines is set too; that means
+        that people can use force-mode-line-update to request
+        that the menu bar be recomputed.  The adverse effect on
+        the rest of the redisplay algorithm is about the same as
+        windows_or_buffers_changed anyway.  */
+       if (windows_or_buffers_changed
+         || !NILP (w->update_mode_line)
+         || update_mode_lines
+         || ((BUF_SAVE_MODIFF (XBUFFER (w->buffer))
+              < BUF_MODIFF (XBUFFER (w->buffer)))
+             != !NILP (w->last_had_star))
+         || ((!NILP (Vtransient_mark_mode)
+              && !NILP (XBUFFER (w->buffer)->mark_active))
+             != !NILP (w->region_showing)))
+       {
+         struct buffer *prev = current_buffer;
+         int count = SPECPDL_INDEX ();
+         Lisp_Object old_tool_bar;
+         struct gcpro gcpro1;
+ 
+         /* Set current_buffer to the buffer of the selected
+            window of the frame, so that we get the right local
+            keymaps.  */
+         set_buffer_internal_1 (XBUFFER (w->buffer));
+ 
+         /* Save match data, if we must.  */
+         if (save_match_data)
+           record_unwind_protect (Fset_match_data, Fmatch_data (Qnil, Qnil));
+ 
+         /* Make sure that we don't accidentally use bogus keymaps.  */
+         if (NILP (Voverriding_local_map_menu_flag))
+           {
+             specbind (Qoverriding_terminal_local_map, Qnil);
+             specbind (Qoverriding_local_map, Qnil);
+           }
+ 
+         old_tool_bar = f->tool_bar_items;
+         GCPRO1 (old_tool_bar);
+ 
+         /* Build desired tool-bar items from keymaps.  */
+           BLOCK_INPUT;
+         f->tool_bar_items
+           = tool_bar_items (f->tool_bar_items, &f->n_tool_bar_items);
+           UNBLOCK_INPUT;
+ 
+         /* Redisplay the tool-bar if we changed it.  */
+         if (! NILP (Fequal (old_tool_bar, f->tool_bar_items)))
+           w->update_mode_line = Qt;
+         
+         UNGCPRO;
+ 
+         unbind_to (count, Qnil);
+         set_buffer_internal_1 (prev);
+       }
+     }
+ }
+ 
+ 
+ /* Set F->desired_tool_bar_string to a Lisp string representing frame
+    F's desired tool-bar contents.  F->tool_bar_items must have
+    been set up previously by calling prepare_menu_bars.  */
+ 
+ static void
+ build_desired_tool_bar_string (f)
+      struct frame *f;
+ {
+   int i, size, size_needed;
+   struct gcpro gcpro1, gcpro2, gcpro3;
+   Lisp_Object image, plist, props;
+ 
+   image = plist = props = Qnil;
+   GCPRO3 (image, plist, props);
+ 
+   /* Prepare F->desired_tool_bar_string.  If we can reuse it, do so.
+      Otherwise, make a new string.  */
+ 
+   /* The size of the string we might be able to reuse.  */
+   size = (STRINGP (f->desired_tool_bar_string)
+         ? SCHARS (f->desired_tool_bar_string)
+         : 0);
+ 
+   /* We need one space in the string for each image.  */
+   size_needed = f->n_tool_bar_items;
+ 
+   /* Reuse f->desired_tool_bar_string, if possible.  */
+   if (size < size_needed || NILP (f->desired_tool_bar_string))
+     f->desired_tool_bar_string = Fmake_string (make_number (size_needed),
+                                              make_number (' '));
+   else
+     {
+       props = list4 (Qdisplay, Qnil, Qmenu_item, Qnil);
+       Fremove_text_properties (make_number (0), make_number (size),
+                              props, f->desired_tool_bar_string);
+     }
+ 
+   /* Put a `display' property on the string for the images to display,
+      put a `menu_item' property on tool-bar items with a value that
+      is the index of the item in F's tool-bar item vector.  */
+   for (i = 0; i < f->n_tool_bar_items; ++i)
+     {
+ #define PROP(IDX) AREF (f->tool_bar_items, i * TOOL_BAR_ITEM_NSLOTS + (IDX))
+ 
+       int enabled_p = !NILP (PROP (TOOL_BAR_ITEM_ENABLED_P));
+       int selected_p = !NILP (PROP (TOOL_BAR_ITEM_SELECTED_P));
+       int hmargin, vmargin, relief, idx, end;
+       extern Lisp_Object QCrelief, QCmargin, QCconversion, Qimage;
+ 
+       /* If image is a vector, choose the image according to the
+        button state.  */
+       image = PROP (TOOL_BAR_ITEM_IMAGES);
+       if (VECTORP (image))
+       {
+         if (enabled_p)
+           idx = (selected_p
+                  ? TOOL_BAR_IMAGE_ENABLED_SELECTED
+                  : TOOL_BAR_IMAGE_ENABLED_DESELECTED);
+         else
+           idx = (selected_p
+                  ? TOOL_BAR_IMAGE_DISABLED_SELECTED
+                  : TOOL_BAR_IMAGE_DISABLED_DESELECTED);
+ 
+         xassert (ASIZE (image) >= idx);
+         image = AREF (image, idx);
+       }
+       else
+       idx = -1;
+ 
+       /* Ignore invalid image specifications.  */
+       if (!valid_image_p (image))
+       continue;
+ 
+       /* Display the tool-bar button pressed, or depressed.  */
+       plist = Fcopy_sequence (XCDR (image));
+ 
+       /* Compute margin and relief to draw.  */
+       relief = (tool_bar_button_relief >= 0
+               ? tool_bar_button_relief
+               : DEFAULT_TOOL_BAR_BUTTON_RELIEF);
+       hmargin = vmargin = relief;
+ 
+       if (INTEGERP (Vtool_bar_button_margin)
+         && XINT (Vtool_bar_button_margin) > 0)
+       {
+         hmargin += XFASTINT (Vtool_bar_button_margin);
+         vmargin += XFASTINT (Vtool_bar_button_margin);
+       }
+       else if (CONSP (Vtool_bar_button_margin))
+       {
+         if (INTEGERP (XCAR (Vtool_bar_button_margin))
+             && XINT (XCAR (Vtool_bar_button_margin)) > 0)
+           hmargin += XFASTINT (XCAR (Vtool_bar_button_margin));
+ 
+         if (INTEGERP (XCDR (Vtool_bar_button_margin))
+             && XINT (XCDR (Vtool_bar_button_margin)) > 0)
+           vmargin += XFASTINT (XCDR (Vtool_bar_button_margin));
+       }
+ 
+       if (auto_raise_tool_bar_buttons_p)
+       {
+         /* Add a `:relief' property to the image spec if the item is
+            selected.  */
+         if (selected_p)
+           {
+             plist = Fplist_put (plist, QCrelief, make_number (-relief));
+             hmargin -= relief;
+             vmargin -= relief;
+           }
+       }
+       else
+       {
+         /* If image is selected, display it pressed, i.e. with a
+            negative relief.  If it's not selected, display it with a
+            raised relief.  */
+         plist = Fplist_put (plist, QCrelief,
+                             (selected_p
+                              ? make_number (-relief)
+                              : make_number (relief)));
+         hmargin -= relief;
+         vmargin -= relief;
+       }
+ 
+       /* Put a margin around the image.  */
+       if (hmargin || vmargin)
+       {
+         if (hmargin == vmargin)
+           plist = Fplist_put (plist, QCmargin, make_number (hmargin));
+         else
+           plist = Fplist_put (plist, QCmargin,
+                               Fcons (make_number (hmargin),
+                                      make_number (vmargin)));
+       }
+ 
+       /* If button is not enabled, and we don't have special images
+        for the disabled state, make the image appear disabled by
+        applying an appropriate algorithm to it.  */
+       if (!enabled_p && idx < 0)
+       plist = Fplist_put (plist, QCconversion, Qdisabled);
+ 
+       /* Put a `display' text property on the string for the image to
+        display.  Put a `menu-item' property on the string that gives
+        the start of this item's properties in the tool-bar items
+        vector.  */
+       image = Fcons (Qimage, plist);
+       props = list4 (Qdisplay, image,
+                    Qmenu_item, make_number (i * TOOL_BAR_ITEM_NSLOTS));
+ 
+       /* Let the last image hide all remaining spaces in the tool bar
+          string.  The string can be longer than needed when we reuse a
+          previous string.  */
+       if (i + 1 == f->n_tool_bar_items)
+       end = SCHARS (f->desired_tool_bar_string);
+       else
+       end = i + 1;
+       Fadd_text_properties (make_number (i), make_number (end),
+                           props, f->desired_tool_bar_string);
+ #undef PROP
+     }
+ 
+   UNGCPRO;
+ }
+ 
+ 
+ /* Display one line of the tool-bar of frame IT->f.  */
+ 
+ static void
+ display_tool_bar_line (it)
+      struct it *it;
+ {
+   struct glyph_row *row = it->glyph_row;
+   int max_x = it->last_visible_x;
+   struct glyph *last;
+ 
+   prepare_desired_row (row);
+   row->y = it->current_y;
+ 
+   /* Note that this isn't made use of if the face hasn't a box,
+      so there's no need to check the face here.  */
+   it->start_of_box_run_p = 1;
+ 
+   while (it->current_x < max_x)
+     {
+       int x_before, x, n_glyphs_before, i, nglyphs;
+ 
+       /* Get the next display element.  */
+       if (!get_next_display_element (it))
+       break;
+ 
+       /* Produce glyphs.  */
+       x_before = it->current_x;
+       n_glyphs_before = it->glyph_row->used[TEXT_AREA];
+       PRODUCE_GLYPHS (it);
+ 
+       nglyphs = it->glyph_row->used[TEXT_AREA] - n_glyphs_before;
+       i = 0;
+       x = x_before;
+       while (i < nglyphs)
+       {
+         struct glyph *glyph = row->glyphs[TEXT_AREA] + n_glyphs_before + i;
+ 
+         if (x + glyph->pixel_width > max_x)
+           {
+             /* Glyph doesn't fit on line.  */
+             it->glyph_row->used[TEXT_AREA] = n_glyphs_before + i;
+             it->current_x = x;
+             goto out;
+           }
+ 
+         ++it->hpos;
+         x += glyph->pixel_width;
+         ++i;
+       }
+ 
+       /* Stop at line ends.  */
+       if (ITERATOR_AT_END_OF_LINE_P (it))
+       break;
+ 
+       set_iterator_to_next (it, 1);
+     }
+ 
+  out:;
+ 
+   row->displays_text_p = row->used[TEXT_AREA] != 0;
+   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;
+   compute_line_metrics (it);
+ 
+   /* If line is empty, make it occupy the rest of the tool-bar.  */
+   if (!row->displays_text_p)
+     {
+       row->height = row->phys_height = it->last_visible_y - row->y;
+       row->ascent = row->phys_ascent = 0;
+     }
+ 
+   row->full_width_p = 1;
+   row->continued_p = 0;
+   row->truncated_on_left_p = 0;
+   row->truncated_on_right_p = 0;
+ 
+   it->current_x = it->hpos = 0;
+   it->current_y += row->height;
+   ++it->vpos;
+   ++it->glyph_row;
+ }
+ 
+ 
+ /* Value is the number of screen lines needed to make all tool-bar
+    items of frame F visible.  */
+ 
+ static int
+ tool_bar_lines_needed (f)
+      struct frame *f;
+ {
+   struct window *w = XWINDOW (f->tool_bar_window);
+   struct it it;
+ 
+   /* Initialize an iterator for iteration over
+      F->desired_tool_bar_string in the tool-bar window of frame F.  */
+   init_iterator (&it, w, -1, -1, w->desired_matrix->rows, TOOL_BAR_FACE_ID);
+   it.first_visible_x = 0;
+   it.last_visible_x = FRAME_TOTAL_COLS (f) * FRAME_COLUMN_WIDTH (f);
+   reseat_to_string (&it, NULL, f->desired_tool_bar_string, 0, 0, 0, -1);
+ 
+   while (!ITERATOR_AT_END_P (&it))
+     {
+       it.glyph_row = w->desired_matrix->rows;
+       clear_glyph_row (it.glyph_row);
+       display_tool_bar_line (&it);
+     }
+ 
+   return (it.current_y + FRAME_LINE_HEIGHT (f) - 1) / FRAME_LINE_HEIGHT (f);
+ }
+ 
+ 
+ DEFUN ("tool-bar-lines-needed", Ftool_bar_lines_needed, 
Stool_bar_lines_needed,
+        0, 1, 0,
+        doc: /* Return the number of lines occupied by the tool bar of FRAME.  
*/)
+      (frame)
+      Lisp_Object frame;
+ {
+   struct frame *f;
+   struct window *w;
+   int nlines = 0;
+ 
+   if (NILP (frame))
+     frame = selected_frame;
+   else
+     CHECK_FRAME (frame);
+   f = XFRAME (frame);
+ 
+   if (WINDOWP (f->tool_bar_window)
+       || (w = XWINDOW (f->tool_bar_window),
+         WINDOW_TOTAL_LINES (w) > 0))
+     {
+       update_tool_bar (f, 1);
+       if (f->n_tool_bar_items)
+       {
+         build_desired_tool_bar_string (f);
+         nlines = tool_bar_lines_needed (f);
+       }
+     }
+ 
+   return make_number (nlines);
+ }
+ 
+ 
+ /* Display the tool-bar of frame F.  Value is non-zero if tool-bar's
+    height should be changed.  */
+ 
+ static int
+ redisplay_tool_bar (f)
+      struct frame *f;
+ {
+   struct window *w;
+   struct it it;
+   struct glyph_row *row;
+   int change_height_p = 0;
+ 
+ #ifdef USE_GTK
+   if (FRAME_EXTERNAL_TOOL_BAR(f))
+     update_frame_tool_bar (f);
+   return 0;
+ #endif
+ 
+   /* If frame hasn't a tool-bar window or if it is zero-height, don't
+      do anything.  This means you must start with tool-bar-lines
+      non-zero to get the auto-sizing effect.  Or in other words, you
+      can turn off tool-bars by specifying tool-bar-lines zero.  */
+   if (!WINDOWP (f->tool_bar_window)
+       || (w = XWINDOW (f->tool_bar_window),
+           WINDOW_TOTAL_LINES (w) == 0))
+     return 0;
+ 
+   /* Set up an iterator for the tool-bar window.  */
+   init_iterator (&it, w, -1, -1, w->desired_matrix->rows, TOOL_BAR_FACE_ID);
+   it.first_visible_x = 0;
+   it.last_visible_x = FRAME_TOTAL_COLS (f) * FRAME_COLUMN_WIDTH (f);
+   row = it.glyph_row;
+ 
+   /* Build a string that represents the contents of the tool-bar.  */
+   build_desired_tool_bar_string (f);
+   reseat_to_string (&it, NULL, f->desired_tool_bar_string, 0, 0, 0, -1);
+ 
+   /* 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);
+ 
+   /* It doesn't make much sense to try scrolling in the tool-bar
+      window, so don't do it.  */
+   w->desired_matrix->no_scrolling_p = 1;
+   w->must_be_updated_p = 1;
+ 
+   if (auto_resize_tool_bars_p)
+     {
+       int nlines;
+ 
+       /* If we couldn't display everything, change the tool-bar's
+        height.  */
+       if (IT_STRING_CHARPOS (it) < it.end_charpos)
+       change_height_p = 1;
+ 
+       /* If there are blank lines at the end, except for a partially
+        visible blank line at the end that is smaller than
+        FRAME_LINE_HEIGHT, change the tool-bar's height.  */
+       row = it.glyph_row - 1;
+       if (!row->displays_text_p
+         && row->height >= FRAME_LINE_HEIGHT (f))
+       change_height_p = 1;
+ 
+       /* If row displays tool-bar items, but is partially visible,
+        change the tool-bar's height.  */
+       if (row->displays_text_p
+         && MATRIX_ROW_BOTTOM_Y (row) > it.last_visible_y)
+       change_height_p = 1;
+ 
+       /* Resize windows as needed by changing the `tool-bar-lines'
+        frame parameter.  */
+       if (change_height_p
+         && (nlines = tool_bar_lines_needed (f),
+             nlines != WINDOW_TOTAL_LINES (w)))
+       {
+         extern Lisp_Object Qtool_bar_lines;
+         Lisp_Object frame;
+         int old_height = WINDOW_TOTAL_LINES (w);
+ 
+         XSETFRAME (frame, f);
+         clear_glyph_matrix (w->desired_matrix);
+         Fmodify_frame_parameters (frame,
+                                   Fcons (Fcons (Qtool_bar_lines,
+                                                 make_number (nlines)),
+                                          Qnil));
+         if (WINDOW_TOTAL_LINES (w) != old_height)
+           fonts_changed_p = 1;
+       }
+     }
+ 
+   return change_height_p;
+ }
+ 
+ 
+ /* Get information about the tool-bar item which is displayed in GLYPH
+    on frame F.  Return in *PROP_IDX the index where tool-bar item
+    properties start in F->tool_bar_items.  Value is zero if
+    GLYPH doesn't display a tool-bar item.  */
+ 
+ static int
+ tool_bar_item_info (f, glyph, prop_idx)
+      struct frame *f;
+      struct glyph *glyph;
+      int *prop_idx;
+ {
+   Lisp_Object prop;
+   int success_p;
+   int charpos;
+ 
+   /* This function can be called asynchronously, which means we must
+      exclude any possibility that Fget_text_property signals an
+      error.  */
+   charpos = min (SCHARS (f->current_tool_bar_string), glyph->charpos);
+   charpos = max (0, charpos);
+ 
+   /* Get the text property `menu-item' at pos. The value of that
+      property is the start index of this item's properties in
+      F->tool_bar_items.  */
+   prop = Fget_text_property (make_number (charpos),
+                            Qmenu_item, f->current_tool_bar_string);
+   if (INTEGERP (prop))
+     {
+       *prop_idx = XINT (prop);
+       success_p = 1;
+     }
+   else
+     success_p = 0;
+ 
+   return success_p;
+ }
+ 
+ 
+ /* Get information about the tool-bar item at position X/Y on frame F.
+    Return in *GLYPH a pointer to the glyph of the tool-bar item in
+    the current matrix of the tool-bar window of F, or NULL if not
+    on a tool-bar item.  Return in *PROP_IDX the index of the tool-bar
+    item in F->tool_bar_items.  Value is
+ 
+    -1 if X/Y is not on a tool-bar item
+    0  if X/Y is on the same item that was highlighted before.
+    1  otherwise.  */
+ 
+ static int
+ get_tool_bar_item (f, x, y, glyph, hpos, vpos, prop_idx)
+      struct frame *f;
+      int x, y;
+      struct glyph **glyph;
+      int *hpos, *vpos, *prop_idx;
+ {
+   Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
+   struct window *w = XWINDOW (f->tool_bar_window);
+   int area;
+ 
+   /* Find the glyph under X/Y.  */
+   *glyph = x_y_to_hpos_vpos (w, x, y, hpos, vpos, &area, 0);
+   if (*glyph == NULL)
+     return -1;
+ 
+   /* Get the start of this tool-bar item's properties in
+      f->tool_bar_items.  */
+   if (!tool_bar_item_info (f, *glyph, prop_idx))
+     return -1;
+ 
+   /* Is mouse on the highlighted item?  */
+   if (EQ (f->tool_bar_window, dpyinfo->mouse_face_window)
+       && *vpos >= dpyinfo->mouse_face_beg_row
+       && *vpos <= dpyinfo->mouse_face_end_row
+       && (*vpos > dpyinfo->mouse_face_beg_row
+         || *hpos >= dpyinfo->mouse_face_beg_col)
+       && (*vpos < dpyinfo->mouse_face_end_row
+         || *hpos < dpyinfo->mouse_face_end_col
+         || dpyinfo->mouse_face_past_end))
+     return 0;
+ 
+   return 1;
+ }
+ 
+ 
+ /* EXPORT:
+    Handle mouse button event on the tool-bar of frame F, at
+    frame-relative coordinates X/Y.  DOWN_P is 1 for a button press,
+    0 for button release.  MODIFIERS is event modifiers for button
+    release.  */
+ 
+ void
+ handle_tool_bar_click (f, x, y, down_p, modifiers)
+      struct frame *f;
+      int x, y, down_p;
+      unsigned int modifiers;
+ {
+   Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
+   struct window *w = XWINDOW (f->tool_bar_window);
+   int hpos, vpos, prop_idx;
+   struct glyph *glyph;
+   Lisp_Object enabled_p;
+ 
+   /* If not on the highlighted tool-bar item, return.  */
+   frame_to_window_pixel_xy (w, &x, &y);
+   if (get_tool_bar_item (f, x, y, &glyph, &hpos, &vpos, &prop_idx) != 0)
+     return;
+ 
+   /* If item is disabled, do nothing.  */
+   enabled_p = AREF (f->tool_bar_items, prop_idx + TOOL_BAR_ITEM_ENABLED_P);
+   if (NILP (enabled_p))
+     return;
+ 
+   if (down_p)
+     {
+       /* Show item in pressed state.  */
+       show_mouse_face (dpyinfo, DRAW_IMAGE_SUNKEN);
+       dpyinfo->mouse_face_image_state = DRAW_IMAGE_SUNKEN;
+       last_tool_bar_item = prop_idx;
+     }
+   else
+     {
+       Lisp_Object key, frame;
+       struct input_event event;
+       EVENT_INIT (event);
+ 
+       /* Show item in released state.  */
+       show_mouse_face (dpyinfo, DRAW_IMAGE_RAISED);
+       dpyinfo->mouse_face_image_state = DRAW_IMAGE_RAISED;
+ 
+       key = AREF (f->tool_bar_items, prop_idx + TOOL_BAR_ITEM_KEY);
+ 
+       XSETFRAME (frame, f);
+       event.kind = TOOL_BAR_EVENT;
+       event.frame_or_window = frame;
+       event.arg = frame;
+       kbd_buffer_store_event (&event);
+ 
+       event.kind = TOOL_BAR_EVENT;
+       event.frame_or_window = frame;
+       event.arg = key;
+       event.modifiers = modifiers;
+       kbd_buffer_store_event (&event);
+       last_tool_bar_item = -1;
+     }
+ }
+ 
+ 
+ /* Possibly highlight a tool-bar item on frame F when mouse moves to
+    tool-bar window-relative coordinates X/Y.  Called from
+    note_mouse_highlight.  */
+ 
+ static void
+ note_tool_bar_highlight (f, x, y)
+      struct frame *f;
+      int x, y;
+ {
+   Lisp_Object window = f->tool_bar_window;
+   struct window *w = XWINDOW (window);
+   Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
+   int hpos, vpos;
+   struct glyph *glyph;
+   struct glyph_row *row;
+   int i;
+   Lisp_Object enabled_p;
+   int prop_idx;
+   enum draw_glyphs_face draw = DRAW_IMAGE_RAISED;
+   int mouse_down_p, rc;
+ 
+   /* Function note_mouse_highlight is called with negative x(y
+      values when mouse moves outside of the frame.  */
+   if (x <= 0 || y <= 0)
+     {
+       clear_mouse_face (dpyinfo);
+       return;
+     }
+ 
+   rc = get_tool_bar_item (f, x, y, &glyph, &hpos, &vpos, &prop_idx);
+   if (rc < 0)
+     {
+       /* Not on tool-bar item.  */
+       clear_mouse_face (dpyinfo);
+       return;
+     }
+   else if (rc == 0)
+     /* On same tool-bar item as before.  */
+     goto set_help_echo;
+ 
+   clear_mouse_face (dpyinfo);
+ 
+   /* Mouse is down, but on different tool-bar item?  */
+   mouse_down_p = (dpyinfo->grabbed
+                 && f == last_mouse_frame
+                 && FRAME_LIVE_P (f));
+   if (mouse_down_p
+       && last_tool_bar_item != prop_idx)
+     return;
+ 
+   dpyinfo->mouse_face_image_state = DRAW_NORMAL_TEXT;
+   draw = mouse_down_p ? DRAW_IMAGE_SUNKEN : DRAW_IMAGE_RAISED;
+ 
+   /* If tool-bar item is not enabled, don't highlight it.  */
+   enabled_p = AREF (f->tool_bar_items, prop_idx + TOOL_BAR_ITEM_ENABLED_P);
+   if (!NILP (enabled_p))
+     {
+       /* Compute the x-position of the glyph.  In front and past the
+        image is a space.  We include this in the highlighted area.  */
+       row = MATRIX_ROW (w->current_matrix, vpos);
+       for (i = x = 0; i < hpos; ++i)
+       x += row->glyphs[TEXT_AREA][i].pixel_width;
+ 
+       /* Record this as the current active region.  */
+       dpyinfo->mouse_face_beg_col = hpos;
+       dpyinfo->mouse_face_beg_row = vpos;
+       dpyinfo->mouse_face_beg_x = x;
+       dpyinfo->mouse_face_beg_y = row->y;
+       dpyinfo->mouse_face_past_end = 0;
+ 
+       dpyinfo->mouse_face_end_col = hpos + 1;
+       dpyinfo->mouse_face_end_row = vpos;
+       dpyinfo->mouse_face_end_x = x + glyph->pixel_width;
+       dpyinfo->mouse_face_end_y = row->y;
+       dpyinfo->mouse_face_window = window;
+       dpyinfo->mouse_face_face_id = TOOL_BAR_FACE_ID;
+ 
+       /* Display it as active.  */
+       show_mouse_face (dpyinfo, draw);
+       dpyinfo->mouse_face_image_state = draw;
+     }
+ 
+  set_help_echo:
+ 
+   /* Set help_echo_string to a help string to display for this tool-bar item.
+      XTread_socket does the rest.  */
+   help_echo_object = help_echo_window = Qnil;
+   help_echo_pos = -1;
+   help_echo_string = AREF (f->tool_bar_items, prop_idx + TOOL_BAR_ITEM_HELP);
+   if (NILP (help_echo_string))
+     help_echo_string = AREF (f->tool_bar_items, prop_idx + 
TOOL_BAR_ITEM_CAPTION);
+ }
+ 
+ #endif /* HAVE_WINDOW_SYSTEM */
+ 
+ 
+ 
+ /***********************************************************************
+                              Fringes
+  ***********************************************************************/
+ 
+ #ifdef HAVE_WINDOW_SYSTEM
+ 
+ /* An arrow like this: `<-'.  */
+ static unsigned char left_bits[] = {
+    0x18, 0x0c, 0x06, 0x3f, 0x3f, 0x06, 0x0c, 0x18};
+ 
+ /* Right truncation arrow bitmap `->'.  */
+ static unsigned char right_bits[] = {
+    0x18, 0x30, 0x60, 0xfc, 0xfc, 0x60, 0x30, 0x18};
+ 
+ /* Marker for continued lines.  */
+ static unsigned char continued_bits[] = {
+    0x3c, 0x7c, 0xc0, 0xe4, 0xfc, 0x7c, 0x3c, 0x7c};
+ 
+ /* Marker for continuation lines.  */
+ static unsigned char continuation_bits[] = {
+    0x3c, 0x3e, 0x03, 0x27, 0x3f, 0x3e, 0x3c, 0x3e};
+ 
+ /* Overlay arrow bitmap.  A triangular arrow.  */
+ static unsigned char ov_bits[] = {
+    0x03, 0x0f, 0x1f, 0x3f, 0x3f, 0x1f, 0x0f, 0x03};
+ 
+ /* Bitmap drawn to indicate lines not displaying text if
+    `indicate-empty-lines' is non-nil.  */
+ static unsigned char zv_bits[] = {
+   0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00,
+   0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00,
+   0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00,
+   0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00,
+   0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00,
+   0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00,
+   0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00,
+   0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00};
+ 
+ struct fringe_bitmap fringe_bitmaps[MAX_FRINGE_BITMAPS] =
+ {
+   { 0, 0, 0, NULL /* NO_FRINGE_BITMAP */ },
+   { 8, sizeof (left_bits), 0, left_bits },
+   { 8, sizeof (right_bits), 0, right_bits },
+   { 8, sizeof (continued_bits), 0, continued_bits },
+   { 8, sizeof (continuation_bits), 0, continuation_bits },
+   { 8, sizeof (ov_bits), 0, ov_bits },
+   { 8, sizeof (zv_bits), 3, zv_bits }
+ };
+ 
+ 
+ /* Draw the bitmap WHICH in one of the left or right fringes of
+    window W.  ROW is the glyph row for which to display the bitmap; it
+    determines the vertical position at which the bitmap has to be
+    drawn.  */
+ 
+ static void
+ draw_fringe_bitmap (w, row, which, left_p)
+      struct window *w;
+      struct glyph_row *row;
+      enum fringe_bitmap_type which;
+      int left_p;
+ {
+   struct frame *f = XFRAME (WINDOW_FRAME (w));
+   struct draw_fringe_bitmap_params p;
+ 
+   /* Convert row to frame coordinates.  */
+   p.y = WINDOW_TO_FRAME_PIXEL_Y (w, row->y);
+ 
+   p.which = which;
+   p.wd = fringe_bitmaps[which].width;
+ 
+   p.h = fringe_bitmaps[which].height;
+   p.dh = (fringe_bitmaps[which].period
+         ? (p.y % fringe_bitmaps[which].period)
+         : 0);
+   p.h -= p.dh;
+   /* Clip bitmap if too high.  */
+   if (p.h > row->height)
+     p.h = row->height;
+ 
+   p.face = FACE_FROM_ID (f, FRINGE_FACE_ID);
+   PREPARE_FACE_FOR_DISPLAY (f, p.face);
+ 
+   /* Clear left fringe if no bitmap to draw or if bitmap doesn't fill
+      the fringe.  */
+   p.bx = -1;
+   if (left_p)
+     {
+       int wd = WINDOW_LEFT_FRINGE_WIDTH (w);
+       int x = window_box_left (w, (WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (w)
+                                  ? LEFT_MARGIN_AREA
+                                  : TEXT_AREA));
+       if (p.wd > wd)
+       p.wd = wd;
+       p.x = x - p.wd - (wd - p.wd) / 2;
+ 
+       if (p.wd < wd || row->height > p.h)
+       {
+         /* If W has a vertical border to its left, don't draw over it.  */
+         wd -= ((!WINDOW_LEFTMOST_P (w)
+                 && !WINDOW_HAS_VERTICAL_SCROLL_BAR (w))
+                ? 1 : 0);
+         p.bx = x - wd;
+         p.nx = wd;
+       }
+     }
+   else
+     {
+       int x = window_box_right (w,
+                               (WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (w)
+                                ? RIGHT_MARGIN_AREA
+                                : TEXT_AREA));
+       int wd = WINDOW_RIGHT_FRINGE_WIDTH (w);
+       if (p.wd > wd)
+       p.wd = wd;
+       p.x = x + (wd - p.wd) / 2;
+       /* Clear right fringe if no bitmap to draw of if bitmap doesn't fill
+        the fringe.  */
+       if (p.wd < wd || row->height > p.h)
+       {
+         p.bx = x;
+         p.nx = wd;
+       }
+     }
+ 
+   if (p.bx >= 0)
+     {
+       int header_line_height = WINDOW_HEADER_LINE_HEIGHT (w);
+ 
+       p.by = WINDOW_TO_FRAME_PIXEL_Y (w, max (header_line_height, row->y));
+       p.ny = row->visible_height;
+     }
+ 
+   /* Adjust y to the offset in the row to start drawing the bitmap.  */
+   p.y += (row->height - p.h) / 2;
+ 
+   rif->draw_fringe_bitmap (w, row, &p);
+ }
+ 
+ /* Draw fringe bitmaps for glyph row ROW on window W.  Call this
+    function with input blocked.  */
+ 
+ void
+ draw_row_fringe_bitmaps (w, row)
+      struct window *w;
+      struct glyph_row *row;
+ {
+   enum fringe_bitmap_type bitmap;
+ 
+   xassert (interrupt_input_blocked);
+ 
+   /* If row is completely invisible, because of vscrolling, we
+      don't have to draw anything.  */
+   if (row->visible_height <= 0)
+     return;
+ 
+   if (WINDOW_LEFT_FRINGE_WIDTH (w) != 0)
+     {
+       /* Decide which bitmap to draw in the left fringe.  */
+       if (row->overlay_arrow_p)
+       bitmap = OVERLAY_ARROW_BITMAP;
+       else if (row->truncated_on_left_p)
+       bitmap = LEFT_TRUNCATION_BITMAP;
+       else if (MATRIX_ROW_CONTINUATION_LINE_P (row))
+       bitmap = CONTINUATION_LINE_BITMAP;
+       else if (row->indicate_empty_line_p)
+       bitmap = ZV_LINE_BITMAP;
+       else
+       bitmap = NO_FRINGE_BITMAP;
+ 
+       draw_fringe_bitmap (w, row, bitmap, 1);
+     }
+ 
+   if (WINDOW_RIGHT_FRINGE_WIDTH (w) != 0)
+     {
+       /* Decide which bitmap to draw in the right fringe.  */
+       if (row->truncated_on_right_p)
+       bitmap = RIGHT_TRUNCATION_BITMAP;
+       else if (row->continued_p)
+       bitmap = CONTINUED_LINE_BITMAP;
+       else if (row->indicate_empty_line_p && WINDOW_LEFT_FRINGE_WIDTH (w) == 
0)
+       bitmap = ZV_LINE_BITMAP;
+       else
+       bitmap = NO_FRINGE_BITMAP;
+ 
+       draw_fringe_bitmap (w, row, bitmap, 0);
+     }
+ }
+ 
+ 
+ /* Compute actual fringe widths */
+ 
+ void
+ compute_fringe_widths (f, redraw)
+      struct frame *f;
+      int redraw;
+ {
+   int o_left = FRAME_LEFT_FRINGE_WIDTH (f);
+   int o_right = FRAME_RIGHT_FRINGE_WIDTH (f);
+   int o_cols = FRAME_FRINGE_COLS (f);
+ 
+   Lisp_Object left_fringe = Fassq (Qleft_fringe, f->param_alist);
+   Lisp_Object right_fringe = Fassq (Qright_fringe, f->param_alist);
+   int left_fringe_width, right_fringe_width;
+ 
+   if (!NILP (left_fringe))
+     left_fringe = Fcdr (left_fringe);
+   if (!NILP (right_fringe))
+     right_fringe = Fcdr (right_fringe);
+ 
+   left_fringe_width = ((NILP (left_fringe) || !INTEGERP (left_fringe)) ? 8 :
+                      XINT (left_fringe));
+   right_fringe_width = ((NILP (right_fringe) || !INTEGERP (right_fringe)) ? 8 
:
+                       XINT (right_fringe));
+ 
+   if (left_fringe_width || right_fringe_width)
+     {
+       int left_wid = left_fringe_width >= 0 ? left_fringe_width : 
-left_fringe_width;
+       int right_wid = right_fringe_width >= 0 ? right_fringe_width : 
-right_fringe_width;
+       int conf_wid = left_wid + right_wid;
+       int font_wid = FRAME_COLUMN_WIDTH (f);
+       int cols = (left_wid + right_wid + font_wid-1) / font_wid;
+       int real_wid = cols * font_wid;
+       if (left_wid && right_wid)
+       {
+         if (left_fringe_width < 0)
+           {
+             /* Left fringe width is fixed, adjust right fringe if necessary */
+             FRAME_LEFT_FRINGE_WIDTH (f) = left_wid;
+             FRAME_RIGHT_FRINGE_WIDTH (f) = real_wid - left_wid;
+           }
+         else if (right_fringe_width < 0)
+           {
+             /* Right fringe width is fixed, adjust left fringe if necessary */
+             FRAME_LEFT_FRINGE_WIDTH (f) = real_wid - right_wid;
+             FRAME_RIGHT_FRINGE_WIDTH (f) = right_wid;
+           }
+         else
+           {
+             /* Adjust both fringes with an equal amount.
+                Note that we are doing integer arithmetic here, so don't
+                lose a pixel if the total width is an odd number.  */
+             int fill = real_wid - conf_wid;
+             FRAME_LEFT_FRINGE_WIDTH (f) = left_wid + fill/2;
+             FRAME_RIGHT_FRINGE_WIDTH (f) = right_wid + fill - fill/2;
+           }
+       }
+       else if (left_fringe_width)
+       {
+         FRAME_LEFT_FRINGE_WIDTH (f) = real_wid;
+         FRAME_RIGHT_FRINGE_WIDTH (f) = 0;
+       }
+       else
+       {
+         FRAME_LEFT_FRINGE_WIDTH (f) = 0;
+         FRAME_RIGHT_FRINGE_WIDTH (f) = real_wid;
+       }
+       FRAME_FRINGE_COLS (f) = cols;
+     }
+   else
+     {
+       FRAME_LEFT_FRINGE_WIDTH (f) = 0;
+       FRAME_RIGHT_FRINGE_WIDTH (f) = 0;
+       FRAME_FRINGE_COLS (f) = 0;
+     }
+ 
+   if (redraw && FRAME_VISIBLE_P (f))
+     if (o_left != FRAME_LEFT_FRINGE_WIDTH (f) ||
+       o_right != FRAME_RIGHT_FRINGE_WIDTH (f) ||
+       o_cols != FRAME_FRINGE_COLS (f))
+       redraw_frame (f);
+ }
+ 
+ #endif /* HAVE_WINDOW_SYSTEM */
+ 
+ 
+ 
+ /************************************************************************
+                        Horizontal scrolling
+  ************************************************************************/
+ 
+ static int hscroll_window_tree P_ ((Lisp_Object));
+ static int hscroll_windows P_ ((Lisp_Object));
+ 
+ /* For all leaf windows in the window tree rooted at WINDOW, set their
+    hscroll value so that PT is (i) visible in the window, and (ii) so
+    that it is not within a certain margin at the window's left and
+    right border.  Value is non-zero if any window's hscroll has been
+    changed.  */
+ 
+ static int
+ hscroll_window_tree (window)
+      Lisp_Object window;
+ {
+   int hscrolled_p = 0;
+   int hscroll_relative_p = FLOATP (Vhscroll_step);
+   int hscroll_step_abs = 0;
+   double hscroll_step_rel = 0;
+ 
+   if (hscroll_relative_p)
+     {
+       hscroll_step_rel = XFLOAT_DATA (Vhscroll_step);
+       if (hscroll_step_rel < 0)
+       {
+         hscroll_relative_p = 0;
+         hscroll_step_abs = 0;
+       }
+     }
+   else if (INTEGERP (Vhscroll_step))
+     {
+       hscroll_step_abs = XINT (Vhscroll_step);
+       if (hscroll_step_abs < 0)
+       hscroll_step_abs = 0;
+     }
+   else
+     hscroll_step_abs = 0;
+ 
+   while (WINDOWP (window))
+     {
+       struct window *w = XWINDOW (window);
+ 
+       if (WINDOWP (w->hchild))
+       hscrolled_p |= hscroll_window_tree (w->hchild);
+       else if (WINDOWP (w->vchild))
+       hscrolled_p |= hscroll_window_tree (w->vchild);
+       else if (w->cursor.vpos >= 0)
+       {
+         int h_margin;
+         int text_area_width;
+         struct glyph_row *current_cursor_row
+           = MATRIX_ROW (w->current_matrix, w->cursor.vpos);
+         struct glyph_row *desired_cursor_row
+           = MATRIX_ROW (w->desired_matrix, w->cursor.vpos);
+         struct glyph_row *cursor_row
+           = (desired_cursor_row->enabled_p
+              ? desired_cursor_row
+              : current_cursor_row);
+ 
+         text_area_width = window_box_width (w, TEXT_AREA);
+ 
+         /* Scroll when cursor is inside this scroll margin.  */
+         h_margin = hscroll_margin * WINDOW_FRAME_COLUMN_WIDTH (w);
+ 
+         if ((XFASTINT (w->hscroll)
+              && w->cursor.x <= h_margin)
+             || (cursor_row->enabled_p
+                 && cursor_row->truncated_on_right_p
+                 && (w->cursor.x >= text_area_width - h_margin)))
+           {
+             struct it it;
+             int hscroll;
+             struct buffer *saved_current_buffer;
+             int pt;
+             int wanted_x;
+ 
+             /* Find point in a display of infinite width.  */
+             saved_current_buffer = current_buffer;
+             current_buffer = XBUFFER (w->buffer);
+ 
+             if (w == XWINDOW (selected_window))
+               pt = BUF_PT (current_buffer);
+             else
+               {
+                 pt = marker_position (w->pointm);
+                 pt = max (BEGV, pt);
+                 pt = min (ZV, pt);
+               }
+ 
+             /* Move iterator to pt starting at cursor_row->start in
+                a line with infinite width.  */
+             init_to_row_start (&it, w, cursor_row);
+             it.last_visible_x = INFINITY;
+             move_it_in_display_line_to (&it, pt, -1, MOVE_TO_POS);
+             current_buffer = saved_current_buffer;
+ 
+             /* Position cursor in window.  */
+             if (!hscroll_relative_p && hscroll_step_abs == 0)
+               hscroll = max (0, it.current_x - text_area_width / 2)
+                         / FRAME_COLUMN_WIDTH (it.f);
+             else if (w->cursor.x >= text_area_width - h_margin)
+               {
+                 if (hscroll_relative_p)
+                   wanted_x = text_area_width * (1 - hscroll_step_rel)
+                              - h_margin;
+                 else
+                   wanted_x = text_area_width
+                              - hscroll_step_abs * FRAME_COLUMN_WIDTH (it.f)
+                              - h_margin;
+                 hscroll
+                   = max (0, it.current_x - wanted_x) / FRAME_COLUMN_WIDTH 
(it.f);
+               }
+             else
+               {
+                 if (hscroll_relative_p)
+                   wanted_x = text_area_width * hscroll_step_rel
+                              + h_margin;
+                 else
+                   wanted_x = hscroll_step_abs * FRAME_COLUMN_WIDTH (it.f)
+                              + h_margin;
+                 hscroll
+                   = max (0, it.current_x - wanted_x) / FRAME_COLUMN_WIDTH 
(it.f);
+               }
+             hscroll = max (hscroll, XFASTINT (w->min_hscroll));
+ 
+             /* Don't call Fset_window_hscroll if value hasn't
+                changed because it will prevent redisplay
+                optimizations.  */
+             if (XFASTINT (w->hscroll) != hscroll)
+               {
+                 XBUFFER (w->buffer)->prevent_redisplay_optimizations_p = 1;
+                 w->hscroll = make_number (hscroll);
+                 hscrolled_p = 1;
+               }
+           }
+       }
+ 
+       window = w->next;
+     }
+ 
+   /* Value is non-zero if hscroll of any leaf window has been changed.  */
+   return hscrolled_p;
+ }
+ 
+ 
+ /* Set hscroll so that cursor is visible and not inside horizontal
+    scroll margins for all windows in the tree rooted at WINDOW.  See
+    also hscroll_window_tree above.  Value is non-zero if any window's
+    hscroll has been changed.  If it has, desired matrices on the frame
+    of WINDOW are cleared.  */
+ 
+ static int
+ hscroll_windows (window)
+      Lisp_Object window;
+ {
+   int hscrolled_p;
+ 
+   if (automatic_hscrolling_p)
+     {
+       hscrolled_p = hscroll_window_tree (window);
+       if (hscrolled_p)
+       clear_desired_matrices (XFRAME (WINDOW_FRAME (XWINDOW (window))));
+     }
+   else
+     hscrolled_p = 0;
+   return hscrolled_p;
+ }
+ 
+ 
+ 
+ /************************************************************************
+                               Redisplay
+  ************************************************************************/
+ 
+ /* Variables holding some state of redisplay if GLYPH_DEBUG is defined
+    to a non-zero value.  This is sometimes handy to have in a debugger
+    session.  */
+ 
+ #if GLYPH_DEBUG
+ 
+ /* First and last unchanged row for try_window_id.  */
+ 
+ int debug_first_unchanged_at_end_vpos;
+ int debug_last_unchanged_at_beg_vpos;
+ 
+ /* Delta vpos and y.  */
+ 
+ int debug_dvpos, debug_dy;
+ 
+ /* Delta in characters and bytes for try_window_id.  */
+ 
+ int debug_delta, debug_delta_bytes;
+ 
+ /* Values of window_end_pos and window_end_vpos at the end of
+    try_window_id.  */
+ 
+ EMACS_INT debug_end_pos, debug_end_vpos;
+ 
+ /* Append a string to W->desired_matrix->method.  FMT is a printf
+    format string.  A1...A9 are a supplement for a variable-length
+    argument list.  If trace_redisplay_p is non-zero also printf the
+    resulting string to stderr.  */
+ 
+ static void
+ debug_method_add (w, fmt, a1, a2, a3, a4, a5, a6, a7, a8, a9)
+      struct window *w;
+      char *fmt;
+      int a1, a2, a3, a4, a5, a6, a7, a8, a9;
+ {
+   char buffer[512];
+   char *method = w->desired_matrix->method;
+   int len = strlen (method);
+   int size = sizeof w->desired_matrix->method;
+   int remaining = size - len - 1;
+ 
+   sprintf (buffer, fmt, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+   if (len && remaining)
+     {
+       method[len] = '|';
+       --remaining, ++len;
+     }
+ 
+   strncpy (method + len, buffer, remaining);
+ 
+   if (trace_redisplay_p)
+     fprintf (stderr, "%p (%s): %s\n",
+            w,
+            ((BUFFERP (w->buffer)
+              && STRINGP (XBUFFER (w->buffer)->name))
+             ? (char *) SDATA (XBUFFER (w->buffer)->name)
+             : "no buffer"),
+            buffer);
+ }
+ 
+ #endif /* GLYPH_DEBUG */
+ 
+ 
+ /* Value is non-zero if all changes in window W, which displays
+    current_buffer, are in the text between START and END.  START is a
+    buffer position, END is given as a distance from Z.  Used in
+    redisplay_internal for display optimization.  */
+ 
+ static INLINE int
+ text_outside_line_unchanged_p (w, start, end)
+      struct window *w;
+      int start, end;
+ {
+   int unchanged_p = 1;
+ 
+   /* If text or overlays have changed, see where.  */
+   if (XFASTINT (w->last_modified) < MODIFF
+       || XFASTINT (w->last_overlay_modified) < OVERLAY_MODIFF)
+     {
+       /* Gap in the line?  */
+       if (GPT < start || Z - GPT < end)
+       unchanged_p = 0;
+ 
+       /* Changes start in front of the line, or end after it?  */
+       if (unchanged_p
+         && (BEG_UNCHANGED < start - 1
+             || END_UNCHANGED < end))
+       unchanged_p = 0;
+ 
+       /* If selective display, can't optimize if changes start at the
+        beginning of the line.  */
+       if (unchanged_p
+         && INTEGERP (current_buffer->selective_display)
+         && XINT (current_buffer->selective_display) > 0
+         && (BEG_UNCHANGED < start || GPT <= start))
+       unchanged_p = 0;
+ 
+       /* If there are overlays at the start or end of the line, these
+        may have overlay strings with newlines in them.  A change at
+        START, for instance, may actually concern the display of such
+        overlay strings as well, and they are displayed on different
+        lines.  So, quickly rule out this case.  (For the future, it
+        might be desirable to implement something more telling than
+        just BEG/END_UNCHANGED.)  */
+       if (unchanged_p)
+       {
+         if (BEG + BEG_UNCHANGED == start
+             && overlay_touches_p (start))
+           unchanged_p = 0;
+         if (END_UNCHANGED == end
+             && overlay_touches_p (Z - end))
+           unchanged_p = 0;
+       }
+     }
+ 
+   return unchanged_p;
+ }
+ 
+ 
+ /* Do a frame update, taking possible shortcuts into account.  This is
+    the main external entry point for redisplay.
+ 
+    If the last redisplay displayed an echo area message and that message
+    is no longer requested, we clear the echo area or bring back the
+    mini-buffer if that is in use.  */
+ 
+ void
+ redisplay ()
+ {
+   redisplay_internal (0);
+ }
+ 
+ 
+ /* Return 1 if point moved out of or into a composition.  Otherwise
+    return 0.  PREV_BUF and PREV_PT are the last point buffer and
+    position.  BUF and PT are the current point buffer and position.  */
+ 
+ int
+ check_point_in_composition (prev_buf, prev_pt, buf, pt)
+      struct buffer *prev_buf, *buf;
+      int prev_pt, pt;
+ {
+   int start, end;
+   Lisp_Object prop;
+   Lisp_Object buffer;
+ 
+   XSETBUFFER (buffer, buf);
+   /* Check a composition at the last point if point moved within the
+      same buffer.  */
+   if (prev_buf == buf)
+     {
+       if (prev_pt == pt)
+       /* Point didn't move.  */
+       return 0;
+ 
+       if (prev_pt > BUF_BEGV (buf) && prev_pt < BUF_ZV (buf)
+         && find_composition (prev_pt, -1, &start, &end, &prop, buffer)
+         && COMPOSITION_VALID_P (start, end, prop)
+         && start < prev_pt && end > prev_pt)
+       /* The last point was within the composition.  Return 1 iff
+             point moved out of the composition.  */
+       return (pt <= start || pt >= end);
+     }
+ 
+   /* Check a composition at the current point.  */
+   return (pt > BUF_BEGV (buf) && pt < BUF_ZV (buf)
+         && find_composition (pt, -1, &start, &end, &prop, buffer)
+         && COMPOSITION_VALID_P (start, end, prop)
+         && start < pt && end > pt);
+ }
+ 
+ 
+ /* Reconsider the setting of B->clip_changed which is displayed
+    in window W.  */
+ 
+ static INLINE void
+ reconsider_clip_changes (w, b)
+      struct window *w;
+      struct buffer *b;
+ {
+   if (b->clip_changed
+          && !NILP (w->window_end_valid)
+          && w->current_matrix->buffer == b
+          && w->current_matrix->zv == BUF_ZV (b)
+          && w->current_matrix->begv == BUF_BEGV (b))
+     b->clip_changed = 0;
+ 
+   /* If display wasn't paused, and W is not a tool bar window, see if
+      point has been moved into or out of a composition.  In that case,
+      we set b->clip_changed to 1 to force updating the screen.  If
+      b->clip_changed has already been set to 1, we can skip this
+      check.  */
+   if (!b->clip_changed
+       && BUFFERP (w->buffer) && !NILP (w->window_end_valid))
+     {
+       int pt;
+ 
+       if (w == XWINDOW (selected_window))
+       pt = BUF_PT (current_buffer);
+       else
+       pt = marker_position (w->pointm);
+ 
+       if ((w->current_matrix->buffer != XBUFFER (w->buffer)
+          || pt != XINT (w->last_point))
+         && check_point_in_composition (w->current_matrix->buffer,
+                                        XINT (w->last_point),
+                                        XBUFFER (w->buffer), pt))
+       b->clip_changed = 1;
+     }
+ }
+ 
+ #define STOP_POLLING                                  \
+ do { if (! polling_stopped_here) stop_polling ();     \
+        polling_stopped_here = 1; } while (0)
+ 
+ #define RESUME_POLLING                                        \
+ do { if (polling_stopped_here) start_polling ();      \
+        polling_stopped_here = 0; } while (0)
+ 
+ 
+ /* If PRESERVE_ECHO_AREA is nonzero, it means this redisplay is not in
+    response to any user action; therefore, we should preserve the echo
+    area.  (Actually, our caller does that job.)  Perhaps in the future
+    avoid recentering windows if it is not necessary; currently that
+    causes some problems.  */
+ 
+ static void
+ redisplay_internal (preserve_echo_area)
+      int preserve_echo_area;
+ {
+   struct window *w = XWINDOW (selected_window);
+   struct frame *f = XFRAME (w->frame);
+   int pause;
+   int must_finish = 0;
+   struct text_pos tlbufpos, tlendpos;
+   int number_of_visible_frames;
+   int count;
+   struct frame *sf = SELECTED_FRAME ();
+   int polling_stopped_here = 0;
+ 
+   /* Non-zero means redisplay has to consider all windows on all
+      frames.  Zero means, only selected_window is considered.  */
+   int consider_all_windows_p;
+ 
+   TRACE ((stderr, "redisplay_internal %d\n", redisplaying_p));
+ 
+   /* No redisplay if running in batch mode or frame is not yet fully
+      initialized, or redisplay is explicitly turned off by setting
+      Vinhibit_redisplay.  */
+   if (noninteractive
+       || !NILP (Vinhibit_redisplay)
+       || !f->glyphs_initialized_p)
+     return;
+ 
+   /* The flag redisplay_performed_directly_p is set by
+      direct_output_for_insert when it already did the whole screen
+      update necessary.  */
+   if (redisplay_performed_directly_p)
+     {
+       redisplay_performed_directly_p = 0;
+       if (!hscroll_windows (selected_window))
+       return;
+     }
+ 
+ #if defined (USE_X_TOOLKIT) || defined (USE_GTK)
+   if (popup_activated ())
+     return;
+ #endif
+ 
+   /* I don't think this happens but let's be paranoid.  */
+   if (redisplaying_p)
+     return;
+ 
+   /* Record a function that resets redisplaying_p to its old value
+      when we leave this function.  */
+   count = SPECPDL_INDEX ();
+   record_unwind_protect (unwind_redisplay, make_number (redisplaying_p));
+   ++redisplaying_p;
+   specbind (Qinhibit_free_realized_faces, Qnil);
+ 
+  retry:
+   pause = 0;
+   reconsider_clip_changes (w, current_buffer);
+ 
+   /* If new fonts have been loaded that make a glyph matrix adjustment
+      necessary, do it.  */
+   if (fonts_changed_p)
+     {
+       adjust_glyphs (NULL);
+       ++windows_or_buffers_changed;
+       fonts_changed_p = 0;
+     }
+ 
+   /* If face_change_count is non-zero, init_iterator will free all
+      realized faces, which includes the faces referenced from current
+      matrices.  So, we can't reuse current matrices in this case.  */
+   if (face_change_count)
+     ++windows_or_buffers_changed;
+ 
+   if (! FRAME_WINDOW_P (sf)
+       && previous_terminal_frame != sf)
+     {
+       /* Since frames on an ASCII terminal share the same display
+        area, displaying a different frame means redisplay the whole
+        thing.  */
+       windows_or_buffers_changed++;
+       SET_FRAME_GARBAGED (sf);
+       XSETFRAME (Vterminal_frame, sf);
+     }
+   previous_terminal_frame = sf;
+ 
+   /* Set the visible flags for all frames.  Do this before checking
+      for resized or garbaged frames; they want to know if their frames
+      are visible.  See the comment in frame.h for
+      FRAME_SAMPLE_VISIBILITY.  */
+   {
+     Lisp_Object tail, frame;
+ 
+     number_of_visible_frames = 0;
+ 
+     FOR_EACH_FRAME (tail, frame)
+       {
+       struct frame *f = XFRAME (frame);
+ 
+       FRAME_SAMPLE_VISIBILITY (f);
+       if (FRAME_VISIBLE_P (f))
+         ++number_of_visible_frames;
+       clear_desired_matrices (f);
+       }
+   }
+ 
+   /* Notice any pending interrupt request to change frame size.  */
+   do_pending_window_change (1);
+ 
+   /* Clear frames marked as garbaged.  */
+   if (frame_garbaged)
+     clear_garbaged_frames ();
+ 
+   /* Build menubar and tool-bar items.  */
+   prepare_menu_bars ();
+ 
+   if (windows_or_buffers_changed)
+     update_mode_lines++;
+ 
+   /* Detect case that we need to write or remove a star in the mode line.  */
+   if ((SAVE_MODIFF < MODIFF) != !NILP (w->last_had_star))
+     {
+       w->update_mode_line = Qt;
+       if (buffer_shared > 1)
+       update_mode_lines++;
+     }
+ 
+   /* If %c is in the mode line, update it if needed.  */
+   if (!NILP (w->column_number_displayed)
+       /* This alternative quickly identifies a common case
+        where no change is needed.  */
+       && !(PT == XFASTINT (w->last_point)
+          && XFASTINT (w->last_modified) >= MODIFF
+          && XFASTINT (w->last_overlay_modified) >= OVERLAY_MODIFF)
+       && (XFASTINT (w->column_number_displayed)
+           != (int) current_column ()))  /* iftc */
+     w->update_mode_line = Qt;
+ 
+   FRAME_SCROLL_BOTTOM_VPOS (XFRAME (w->frame)) = -1;
+ 
+   /* The variable buffer_shared is set in redisplay_window and
+      indicates that we redisplay a buffer in different windows.  See
+      there.  */
+   consider_all_windows_p = (update_mode_lines || buffer_shared > 1
+                           || cursor_type_changed);
+ 
+   /* If specs for an arrow have changed, do thorough redisplay
+      to ensure we remove any arrow that should no longer exist.  */
+   if (! EQ (COERCE_MARKER (Voverlay_arrow_position), last_arrow_position)
+       || ! EQ (Voverlay_arrow_string, last_arrow_string))
+     consider_all_windows_p = windows_or_buffers_changed = 1;
+ 
+   /* Normally the message* functions will have already displayed and
+      updated the echo area, but the frame may have been trashed, or
+      the update may have been preempted, so display the echo area
+      again here.  Checking message_cleared_p captures the case that
+      the echo area should be cleared.  */
+   if ((!NILP (echo_area_buffer[0]) && !display_last_displayed_message_p)
+       || (!NILP (echo_area_buffer[1]) && display_last_displayed_message_p)
+       || (message_cleared_p
+         && minibuf_level == 0
+         /* If the mini-window is currently selected, this means the
+            echo-area doesn't show through.  */
+         && !MINI_WINDOW_P (XWINDOW (selected_window))))
+     {
+       int window_height_changed_p = echo_area_display (0);
+       must_finish = 1;
+ 
+       /* If we don't display the current message, don't clear the
+        message_cleared_p flag, because, if we did, we wouldn't clear
+        the echo area in the next redisplay which doesn't preserve
+        the echo area.  */
+       if (!display_last_displayed_message_p)
+       message_cleared_p = 0;
+ 
+       if (fonts_changed_p)
+       goto retry;
+       else if (window_height_changed_p)
+       {
+         consider_all_windows_p = 1;
+         ++update_mode_lines;
+         ++windows_or_buffers_changed;
+ 
+         /* If window configuration was changed, frames may have been
+            marked garbaged.  Clear them or we will experience
+            surprises wrt scrolling.  */
+         if (frame_garbaged)
+           clear_garbaged_frames ();
+       }
+     }
+   else if (EQ (selected_window, minibuf_window)
+          && (current_buffer->clip_changed
+              || XFASTINT (w->last_modified) < MODIFF
+              || XFASTINT (w->last_overlay_modified) < OVERLAY_MODIFF)
+          && resize_mini_window (w, 0))
+     {
+       /* Resized active mini-window to fit the size of what it is
+          showing if its contents might have changed.  */
+       must_finish = 1;
+       consider_all_windows_p = 1;
+       ++windows_or_buffers_changed;
+       ++update_mode_lines;
+ 
+       /* If window configuration was changed, frames may have been
+        marked garbaged.  Clear them or we will experience
+        surprises wrt scrolling.  */
+       if (frame_garbaged)
+       clear_garbaged_frames ();
+     }
+ 
+ 
+   /* If showing the region, and mark has changed, we must redisplay
+      the whole window.  The assignment to this_line_start_pos prevents
+      the optimization directly below this if-statement.  */
+   if (((!NILP (Vtransient_mark_mode)
+       && !NILP (XBUFFER (w->buffer)->mark_active))
+        != !NILP (w->region_showing))
+       || (!NILP (w->region_showing)
+         && !EQ (w->region_showing,
+                 Fmarker_position (XBUFFER (w->buffer)->mark))))
+     CHARPOS (this_line_start_pos) = 0;
+ 
+   /* Optimize the case that only the line containing the cursor in the
+      selected window has changed.  Variables starting with this_ are
+      set in display_line and record information about the line
+      containing the cursor.  */
+   tlbufpos = this_line_start_pos;
+   tlendpos = this_line_end_pos;
+   if (!consider_all_windows_p
+       && CHARPOS (tlbufpos) > 0
+       && NILP (w->update_mode_line)
+       && !current_buffer->clip_changed
+       && !current_buffer->prevent_redisplay_optimizations_p
+       && FRAME_VISIBLE_P (XFRAME (w->frame))
+       && !FRAME_OBSCURED_P (XFRAME (w->frame))
+       /* Make sure recorded data applies to current buffer, etc.  */
+       && this_line_buffer == current_buffer
+       && current_buffer == XBUFFER (w->buffer)
+       && NILP (w->force_start)
+       && NILP (w->optional_new_start)
+       /* Point must be on the line that we have info recorded about.  */
+       && PT >= CHARPOS (tlbufpos)
+       && PT <= Z - CHARPOS (tlendpos)
+       /* All text outside that line, including its final newline,
+        must be unchanged */
+       && text_outside_line_unchanged_p (w, CHARPOS (tlbufpos),
+                                       CHARPOS (tlendpos)))
+     {
+       if (CHARPOS (tlbufpos) > BEGV
+         && FETCH_BYTE (BYTEPOS (tlbufpos) - 1) != '\n'
+         && (CHARPOS (tlbufpos) == ZV
+             || FETCH_BYTE (BYTEPOS (tlbufpos)) == '\n'))
+       /* Former continuation line has disappeared by becoming empty */
+       goto cancel;
+       else if (XFASTINT (w->last_modified) < MODIFF
+              || XFASTINT (w->last_overlay_modified) < OVERLAY_MODIFF
+              || MINI_WINDOW_P (w))
+       {
+         /* We have to handle the case of continuation around a
+            wide-column character (See the comment in indent.c around
+            line 885).
+ 
+            For instance, in the following case:
+ 
+            --------  Insert  --------
+            K_A_N_\\   `a'    K_A_N_a\         `X_' are wide-column chars.
+            J_I_       ==>    J_I_             `^^' are cursors.
+            ^^                ^^
+            --------          --------
+ 
+            As we have to redraw the line above, we should goto cancel.  */
+ 
+         struct it it;
+         int line_height_before = this_line_pixel_height;
+ 
+         /* Note that start_display will handle the case that the
+            line starting at tlbufpos is a continuation lines.  */
+         start_display (&it, w, tlbufpos);
+ 
+         /* Implementation note: It this still necessary?  */
+         if (it.current_x != this_line_start_x)
+           goto cancel;
+ 
+         TRACE ((stderr, "trying display optimization 1\n"));
+         w->cursor.vpos = -1;
+         overlay_arrow_seen = 0;
+         it.vpos = this_line_vpos;
+         it.current_y = this_line_y;
+         it.glyph_row = MATRIX_ROW (w->desired_matrix, this_line_vpos);
+         display_line (&it);
+ 
+         /* If line contains point, is not continued,
+              and ends at same distance from eob as before, we win */
+         if (w->cursor.vpos >= 0
+               /* Line is not continued, otherwise this_line_start_pos
+                  would have been set to 0 in display_line.  */
+             && CHARPOS (this_line_start_pos)
+             /* Line ends as before.  */
+             && CHARPOS (this_line_end_pos) == CHARPOS (tlendpos)
+               /* Line has same height as before.  Otherwise other lines
+                  would have to be shifted up or down.  */
+             && this_line_pixel_height == line_height_before)
+           {
+             /* If this is not the window's last line, we must adjust
+                the charstarts of the lines below.  */
+             if (it.current_y < it.last_visible_y)
+               {
+                 struct glyph_row *row
+                   = MATRIX_ROW (w->current_matrix, this_line_vpos + 1);
+                 int delta, delta_bytes;
+ 
+                 if (Z - CHARPOS (tlendpos) == ZV)
+                   {
+                     /* This line ends at end of (accessible part of)
+                        buffer.  There is no newline to count.  */
+                     delta = (Z
+                              - CHARPOS (tlendpos)
+                              - MATRIX_ROW_START_CHARPOS (row));
+                     delta_bytes = (Z_BYTE
+                                    - BYTEPOS (tlendpos)
+                                    - MATRIX_ROW_START_BYTEPOS (row));
+                   }
+                 else
+                   {
+                     /* This line ends in a newline.  Must take
+                        account of the newline and the rest of the
+                        text that follows.  */
+                     delta = (Z
+                              - CHARPOS (tlendpos)
+                              - MATRIX_ROW_START_CHARPOS (row));
+                     delta_bytes = (Z_BYTE
+                                    - BYTEPOS (tlendpos)
+                                    - MATRIX_ROW_START_BYTEPOS (row));
+                   }
+ 
+                 increment_matrix_positions (w->current_matrix,
+                                             this_line_vpos + 1,
+                                             w->current_matrix->nrows,
+                                             delta, delta_bytes);
+               }
+ 
+             /* If this row displays text now but previously didn't,
+                or vice versa, w->window_end_vpos may have to be
+                adjusted.  */
+             if ((it.glyph_row - 1)->displays_text_p)
+               {
+                 if (XFASTINT (w->window_end_vpos) < this_line_vpos)
+                   XSETINT (w->window_end_vpos, this_line_vpos);
+               }
+             else if (XFASTINT (w->window_end_vpos) == this_line_vpos
+                      && this_line_vpos > 0)
+               XSETINT (w->window_end_vpos, this_line_vpos - 1);
+             w->window_end_valid = Qnil;
+ 
+             /* Update hint: No need to try to scroll in update_window.  */
+             w->desired_matrix->no_scrolling_p = 1;
+ 
+ #if GLYPH_DEBUG
+             *w->desired_matrix->method = 0;
+             debug_method_add (w, "optimization 1");
+ #endif
+             goto update;
+           }
+         else
+           goto cancel;
+       }
+       else if (/* Cursor position hasn't changed.  */
+              PT == XFASTINT (w->last_point)
+              /* Make sure the cursor was last displayed
+                 in this window.  Otherwise we have to reposition it.  */
+              && 0 <= w->cursor.vpos
+              && WINDOW_TOTAL_LINES (w) > w->cursor.vpos)
+       {
+         if (!must_finish)
+           {
+             do_pending_window_change (1);
+ 
+             /* We used to always goto end_of_redisplay here, but this
+                isn't enough if we have a blinking cursor.  */
+             if (w->cursor_off_p == w->last_cursor_off_p)
+               goto end_of_redisplay;
+           }
+         goto update;
+       }
+       /* If highlighting the region, or if the cursor is in the echo area,
+        then we can't just move the cursor.  */
+       else if (! (!NILP (Vtransient_mark_mode)
+                 && !NILP (current_buffer->mark_active))
+              && (EQ (selected_window, current_buffer->last_selected_window)
+                  || highlight_nonselected_windows)
+              && NILP (w->region_showing)
+              && NILP (Vshow_trailing_whitespace)
+              && !cursor_in_echo_area)
+       {
+         struct it it;
+         struct glyph_row *row;
+ 
+         /* Skip from tlbufpos to PT and see where it is.  Note that
+            PT may be in invisible text.  If so, we will end at the
+            next visible position.  */
+         init_iterator (&it, w, CHARPOS (tlbufpos), BYTEPOS (tlbufpos),
+                        NULL, DEFAULT_FACE_ID);
+         it.current_x = this_line_start_x;
+         it.current_y = this_line_y;
+         it.vpos = this_line_vpos;
+ 
+         /* The call to move_it_to stops in front of PT, but
+            moves over before-strings.  */
+         move_it_to (&it, PT, -1, -1, -1, MOVE_TO_POS);
+ 
+         if (it.vpos == this_line_vpos
+             && (row = MATRIX_ROW (w->current_matrix, this_line_vpos),
+                 row->enabled_p))
+           {
+             xassert (this_line_vpos == it.vpos);
+             xassert (this_line_y == it.current_y);
+             set_cursor_from_row (w, row, w->current_matrix, 0, 0, 0, 0);
+ #if GLYPH_DEBUG
+             *w->desired_matrix->method = 0;
+             debug_method_add (w, "optimization 3");
+ #endif
+             goto update;
+           }
+         else
+           goto cancel;
+       }
+ 
+     cancel:
+       /* Text changed drastically or point moved off of line.  */
+       SET_MATRIX_ROW_ENABLED_P (w->desired_matrix, this_line_vpos, 0);
+     }
+ 
+   CHARPOS (this_line_start_pos) = 0;
+   consider_all_windows_p |= buffer_shared > 1;
+   ++clear_face_cache_count;
+ 
+ 
+   /* Build desired matrices, and update the display.  If
+      consider_all_windows_p is non-zero, do it for all windows on all
+      frames.  Otherwise do it for selected_window, only.  */
+ 
+   if (consider_all_windows_p)
+     {
+       Lisp_Object tail, frame;
+       int i, n = 0, size = 50;
+       struct frame **updated
+       = (struct frame **) alloca (size * sizeof *updated);
+ 
+       /* Clear the face cache eventually.  */
+       if (clear_face_cache_count > CLEAR_FACE_CACHE_COUNT)
+       {
+         clear_face_cache (0);
+         clear_face_cache_count = 0;
+       }
+ 
+       /* Recompute # windows showing selected buffer.  This will be
+        incremented each time such a window is displayed.  */
+       buffer_shared = 0;
+ 
+       FOR_EACH_FRAME (tail, frame)
+       {
+         struct frame *f = XFRAME (frame);
+ 
+         if (FRAME_WINDOW_P (f) || f == sf)
+           {
+ #ifdef HAVE_WINDOW_SYSTEM
+             if (clear_face_cache_count % 50 == 0
+                 && FRAME_WINDOW_P (f))
+               clear_image_cache (f, 0);
+ #endif /* HAVE_WINDOW_SYSTEM */
+ 
+             /* Mark all the scroll bars to be removed; we'll redeem
+                the ones we want when we redisplay their windows.  */
+             if (condemn_scroll_bars_hook)
+               condemn_scroll_bars_hook (f);
+ 
+             if (FRAME_VISIBLE_P (f) && !FRAME_OBSCURED_P (f))
+               redisplay_windows (FRAME_ROOT_WINDOW (f));
+ 
+             /* Any scroll bars which redisplay_windows should have
+                nuked should now go away.  */
+             if (judge_scroll_bars_hook)
+               judge_scroll_bars_hook (f);
+ 
+             /* If fonts changed, display again.  */
+             /* ??? rms: I suspect it is a mistake to jump all the way
+                back to retry here.  It should just retry this frame.  */
+             if (fonts_changed_p)
+               goto retry;
+ 
+             if (FRAME_VISIBLE_P (f) && !FRAME_OBSCURED_P (f))
+               {
+                 /* See if we have to hscroll.  */
+                 if (hscroll_windows (f->root_window))
+                   goto retry;
+ 
+                 /* Prevent various kinds of signals during display
+                    update.  stdio is not robust about handling
+                    signals, which can cause an apparent I/O
+                    error.  */
+                 if (interrupt_input)
+                   unrequest_sigio ();
+                 STOP_POLLING;
+ 
+                 /* Update the display.  */
+                 set_window_update_flags (XWINDOW (f->root_window), 1);
+                 pause |= update_frame (f, 0, 0);
+ #if 0  /* Exiting the loop can leave the wrong value for buffer_shared.  */
+                 if (pause)
+                   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;
+               }
+           }
+       }
+ 
+       /* 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)
+       {
+         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);
+       }
+     }
+   else if (FRAME_VISIBLE_P (sf) && !FRAME_OBSCURED_P (sf))
+     {
+       Lisp_Object mini_window;
+       struct frame *mini_frame;
+ 
+       displayed_buffer = XBUFFER (XWINDOW (selected_window)->buffer);
+       /* Use list_of_error, not Qerror, so that
+        we catch only errors and don't run the debugger.  */
+       internal_condition_case_1 (redisplay_window_1, selected_window,
+                                list_of_error,
+                                redisplay_window_error);
+ 
+       /* Compare desired and current matrices, perform output.  */
+ 
+     update:
+       /* If fonts changed, display again.  */
+       if (fonts_changed_p)
+       goto retry;
+ 
+       /* Prevent various kinds of signals during display update.
+        stdio is not robust about handling signals,
+        which can cause an apparent I/O error.  */
+       if (interrupt_input)
+       unrequest_sigio ();
+       STOP_POLLING;
+ 
+       if (FRAME_VISIBLE_P (sf) && !FRAME_OBSCURED_P (sf))
+       {
+         if (hscroll_windows (selected_window))
+           goto retry;
+ 
+         XWINDOW (selected_window)->must_be_updated_p = 1;
+         pause = update_frame (sf, 0, 0);
+       }
+ 
+       /* We may have called echo_area_display at the top of this
+        function.  If the echo area is on another frame, that may
+        have put text on a frame other than the selected one, so the
+        above call to update_frame would not have caught it.  Catch
+        it here.  */
+       mini_window = FRAME_MINIBUF_WINDOW (sf);
+       mini_frame = XFRAME (WINDOW_FRAME (XWINDOW (mini_window)));
+ 
+       if (mini_frame != sf && FRAME_WINDOW_P (mini_frame))
+       {
+         XWINDOW (mini_window)->must_be_updated_p = 1;
+         pause |= update_frame (mini_frame, 0, 0);
+         if (!pause && hscroll_windows (mini_window))
+           goto retry;
+       }
+     }
+ 
+   /* If display was paused because of pending input, make sure we do a
+      thorough update the next time.  */
+   if (pause)
+     {
+       /* Prevent the optimization at the beginning of
+        redisplay_internal that tries a single-line update of the
+        line containing the cursor in the selected window.  */
+       CHARPOS (this_line_start_pos) = 0;
+ 
+       /* Let the overlay arrow be updated the next time.  */
+       if (!NILP (last_arrow_position))
+       {
+         last_arrow_position = Qt;
+         last_arrow_string = Qt;
+       }
+ 
+       /* If we pause after scrolling, some rows in the current
+        matrices of some windows are not valid.  */
+       if (!WINDOW_FULL_WIDTH_P (w)
+         && !FRAME_WINDOW_P (XFRAME (w->frame)))
+       update_mode_lines = 1;
+     }
+   else
+     {
+       if (!consider_all_windows_p)
+       {
+         /* This has already been done above if
+            consider_all_windows_p is set.  */
+         mark_window_display_accurate_1 (w, 1);
+ 
+         last_arrow_position = COERCE_MARKER (Voverlay_arrow_position);
+         last_arrow_string = Voverlay_arrow_string;
+ 
+         if (frame_up_to_date_hook != 0)
+           frame_up_to_date_hook (sf);
+       }
+ 
+       update_mode_lines = 0;
+       windows_or_buffers_changed = 0;
+       cursor_type_changed = 0;
+     }
+ 
+   /* Start SIGIO interrupts coming again.  Having them off during the
+      code above makes it less likely one will discard output, but not
+      impossible, since there might be stuff in the system buffer here.
+      But it is much hairier to try to do anything about that.  */
+   if (interrupt_input)
+     request_sigio ();
+   RESUME_POLLING;
+ 
+   /* If a frame has become visible which was not before, redisplay
+      again, so that we display it.  Expose events for such a frame
+      (which it gets when becoming visible) don't call the parts of
+      redisplay constructing glyphs, so simply exposing a frame won't
+      display anything in this case.  So, we have to display these
+      frames here explicitly.  */
+   if (!pause)
+     {
+       Lisp_Object tail, frame;
+       int new_count = 0;
+ 
+       FOR_EACH_FRAME (tail, frame)
+       {
+         int this_is_visible = 0;
+ 
+         if (XFRAME (frame)->visible)
+           this_is_visible = 1;
+         FRAME_SAMPLE_VISIBILITY (XFRAME (frame));
+         if (XFRAME (frame)->visible)
+           this_is_visible = 1;
+ 
+         if (this_is_visible)
+           new_count++;
+       }
+ 
+       if (new_count != number_of_visible_frames)
+       windows_or_buffers_changed++;
+     }
+ 
+   /* Change frame size now if a change is pending.  */
+   do_pending_window_change (1);
+ 
+   /* If we just did a pending size change, or have additional
+      visible frames, redisplay again.  */
+   if (windows_or_buffers_changed && !pause)
+     goto retry;
+ 
+  end_of_redisplay:
+   unbind_to (count, Qnil);
+   RESUME_POLLING;
+ }
+ 
+ 
+ /* Redisplay, but leave alone any recent echo area message unless
+    another message has been requested in its place.
+ 
+    This is useful in situations where you need to redisplay but no
+    user action has occurred, making it inappropriate for the message
+    area to be cleared.  See tracking_off and
+    wait_reading_process_input for examples of these situations.
+ 
+    FROM_WHERE is an integer saying from where this function was
+    called.  This is useful for debugging.  */
+ 
+ void
+ redisplay_preserve_echo_area (from_where)
+      int from_where;
+ {
+   TRACE ((stderr, "redisplay_preserve_echo_area (%d)\n", from_where));
+ 
+   if (!NILP (echo_area_buffer[1]))
+     {
+       /* We have a previously displayed message, but no current
+        message.  Redisplay the previous message.  */
+       display_last_displayed_message_p = 1;
+       redisplay_internal (1);
+       display_last_displayed_message_p = 0;
+     }
+   else
+     redisplay_internal (1);
+ }
+ 
+ 
+ /* Function registered with record_unwind_protect in
+    redisplay_internal.  Reset redisplaying_p to the value it had
+    before redisplay_internal was called, and clear
+    prevent_freeing_realized_faces_p.  */
+ 
+ static Lisp_Object
+ unwind_redisplay (old_redisplaying_p)
+      Lisp_Object old_redisplaying_p;
+ {
+   redisplaying_p = XFASTINT (old_redisplaying_p);
+   return Qnil;
+ }
+ 
+ 
+ /* Mark the display of window W as accurate or inaccurate.  If
+    ACCURATE_P is non-zero mark display of W as accurate.  If
+    ACCURATE_P is zero, arrange for W to be redisplayed the next time
+    redisplay_internal is called.  */
+ 
+ static void
+ mark_window_display_accurate_1 (w, accurate_p)
+      struct window *w;
+      int accurate_p;
+ {
+   if (BUFFERP (w->buffer))
+     {
+       struct buffer *b = XBUFFER (w->buffer);
+ 
+       w->last_modified
+       = make_number (accurate_p ? BUF_MODIFF (b) : 0);
+       w->last_overlay_modified
+       = make_number (accurate_p ? BUF_OVERLAY_MODIFF (b) : 0);
+       w->last_had_star
+       = BUF_MODIFF (b) > BUF_SAVE_MODIFF (b) ? Qt : Qnil;
+ 
+       if (accurate_p)
+       {
+         b->clip_changed = 0;
+         b->prevent_redisplay_optimizations_p = 0;
+ 
+         BUF_UNCHANGED_MODIFIED (b) = BUF_MODIFF (b);
+         BUF_OVERLAY_UNCHANGED_MODIFIED (b) = BUF_OVERLAY_MODIFF (b);
+         BUF_BEG_UNCHANGED (b) = BUF_GPT (b) - BUF_BEG (b);
+         BUF_END_UNCHANGED (b) = BUF_Z (b) - BUF_GPT (b);
+ 
+         w->current_matrix->buffer = b;
+         w->current_matrix->begv = BUF_BEGV (b);
+         w->current_matrix->zv = BUF_ZV (b);
+ 
+         w->last_cursor = w->cursor;
+         w->last_cursor_off_p = w->cursor_off_p;
+ 
+         if (w == XWINDOW (selected_window))
+           w->last_point = make_number (BUF_PT (b));
+         else
+           w->last_point = make_number (XMARKER (w->pointm)->charpos);
+       }
+     }
+ 
+   if (accurate_p)
+     {
+       w->window_end_valid = w->buffer;
+ #if 0 /* This is incorrect with variable-height lines.  */
+       xassert (XINT (w->window_end_vpos)
+              < (WINDOW_TOTAL_LINES (w)
+                 - (WINDOW_WANTS_MODELINE_P (w) ? 1 : 0)));
+ #endif
+       w->update_mode_line = Qnil;
+     }
+ }
+ 
+ 
+ /* Mark the display of windows in the window tree rooted at WINDOW as
+    accurate or inaccurate.  If ACCURATE_P is non-zero mark display of
+    windows as accurate.  If ACCURATE_P is zero, arrange for windows to
+    be redisplayed the next time redisplay_internal is called.  */
+ 
+ void
+ mark_window_display_accurate (window, accurate_p)
+      Lisp_Object window;
+      int accurate_p;
+ {
+   struct window *w;
+ 
+   for (; !NILP (window); window = w->next)
+     {
+       w = XWINDOW (window);
+       mark_window_display_accurate_1 (w, accurate_p);
+ 
+       if (!NILP (w->vchild))
+       mark_window_display_accurate (w->vchild, accurate_p);
+       if (!NILP (w->hchild))
+       mark_window_display_accurate (w->hchild, accurate_p);
+     }
+ 
+   if (accurate_p)
+     {
+       last_arrow_position = COERCE_MARKER (Voverlay_arrow_position);
+       last_arrow_string = Voverlay_arrow_string;
+     }
+   else
+     {
+       /* Force a thorough redisplay the next time by setting
+        last_arrow_position and last_arrow_string to t, which is
+        unequal to any useful value of Voverlay_arrow_...  */
+       last_arrow_position = Qt;
+       last_arrow_string = Qt;
+     }
+ }
+ 
+ 
+ /* Return value in display table DP (Lisp_Char_Table *) for character
+    C.  Since a display table doesn't have any parent, we don't have to
+    follow parent.  Do not call this function directly but use the
+    macro DISP_CHAR_VECTOR.  */
+ 
+ Lisp_Object
+ disp_char_vector (dp, c)
+      struct Lisp_Char_Table *dp;
+      int c;
+ {
+   Lisp_Object val;
+ 
+   if (ASCII_CHAR_P (c))
+     {
+       val = dp->ascii;
+       if (SUB_CHAR_TABLE_P (val))
+       val = XSUB_CHAR_TABLE (val)->contents[c];
+     }
+   else
+     {
+       Lisp_Object table;
+ 
+       XSETCHAR_TABLE (table, dp);
+       val = char_table_ref (table, c);
+     }
+   if (NILP (val))
+     val = dp->defalt;
+   return val;
+ }
+ 
+ 
+ 
+ /***********************************************************************
+                          Window Redisplay
+  ***********************************************************************/
+ 
+ /* Redisplay all leaf windows in the window tree rooted at WINDOW.  */
+ 
+ static void
+ redisplay_windows (window)
+      Lisp_Object window;
+ {
+   while (!NILP (window))
+     {
+       struct window *w = XWINDOW (window);
+ 
+       if (!NILP (w->hchild))
+       redisplay_windows (w->hchild);
+       else if (!NILP (w->vchild))
+       redisplay_windows (w->vchild);
+       else
+       {
+         displayed_buffer = XBUFFER (w->buffer);
+         /* Use list_of_error, not Qerror, so that
+            we catch only errors and don't run the debugger.  */
+         internal_condition_case_1 (redisplay_window_0, window,
+                                    list_of_error,
+                                    redisplay_window_error);
+       }
+ 
+       window = w->next;
+     }
+ }
+ 
+ static Lisp_Object
+ redisplay_window_error ()
+ {
+   displayed_buffer->display_error_modiff = BUF_MODIFF (displayed_buffer);
+   return Qnil;
+ }
+ 
+ static Lisp_Object
+ redisplay_window_0 (window)
+      Lisp_Object window;
+ {
+   if (displayed_buffer->display_error_modiff < BUF_MODIFF (displayed_buffer))
+     redisplay_window (window, 0);
+   return Qnil;
+ }
+ 
+ static Lisp_Object
+ redisplay_window_1 (window)
+      Lisp_Object window;
+ {
+   if (displayed_buffer->display_error_modiff < BUF_MODIFF (displayed_buffer))
+     redisplay_window (window, 1);
+   return Qnil;
+ }
+ 
+ 
+ /* Increment GLYPH until it reaches END or CONDITION fails while
+    adding (GLYPH)->pixel_width to X. */
+ 
+ #define SKIP_GLYPHS(glyph, end, x, condition) \
+   do                                          \
+     {                                         \
+       (x) += (glyph)->pixel_width;            \
+       ++(glyph);                              \
+     }                                         \
+   while ((glyph) < (end) && (condition))
+ 
+ 
+ /* Set cursor position of W.  PT is assumed to be displayed in ROW.
+    DELTA is the number of bytes by which positions recorded in ROW
+    differ from current buffer positions.  */
+ 
+ void
+ set_cursor_from_row (w, row, matrix, delta, delta_bytes, dy, dvpos)
+      struct window *w;
+      struct glyph_row *row;
+      struct glyph_matrix *matrix;
+      int delta, delta_bytes, dy, dvpos;
+ {
+   struct glyph *glyph = row->glyphs[TEXT_AREA];
+   struct glyph *end = glyph + row->used[TEXT_AREA];
+   /* The first glyph that starts a sequence of glyphs from string.  */
+   struct glyph *string_start;
+   /* The X coordinate of string_start.  */
+   int string_start_x;
+   /* The last known character position.  */
+   int last_pos = MATRIX_ROW_START_CHARPOS (row) + delta;
+   /* The last known character position before string_start.  */
+   int string_before_pos;
+   int x = row->x;
+   int pt_old = PT - delta;
+ 
+   /* Skip over glyphs not having an object at the start of the row.
+      These are special glyphs like truncation marks on terminal
+      frames.  */
+   if (row->displays_text_p)
+     while (glyph < end
+          && INTEGERP (glyph->object)
+          && glyph->charpos < 0)
+       {
+       x += glyph->pixel_width;
+       ++glyph;
+       }
+ 
+   string_start = NULL;
+   while (glyph < end
+        && !INTEGERP (glyph->object)
+        && (!BUFFERP (glyph->object)
+            || (last_pos = glyph->charpos) < pt_old))
+     {
+       if (! STRINGP (glyph->object))
+       {
+         string_start = NULL;
+         x += glyph->pixel_width;
+         ++glyph;
+       }
+       else
+       {
+         string_before_pos = last_pos;
+         string_start = glyph;
+         string_start_x = x;
+         /* Skip all glyphs from string.  */
+         SKIP_GLYPHS (glyph, end, x, STRINGP (glyph->object));
+       }
+     }
+ 
+   if (string_start
+       && (glyph == end || !BUFFERP (glyph->object) || last_pos > pt_old))
+     {
+       /* We may have skipped over point because the previous glyphs
+        are from string.  As there's no easy way to know the
+        character position of the current glyph, find the correct
+        glyph on point by scanning from string_start again.  */
+       Lisp_Object limit;
+       Lisp_Object string;
+       int pos;
+ 
+       limit = make_number (pt_old + 1);
+       end = glyph;
+       glyph = string_start;
+       x = string_start_x;
+       string = glyph->object;
+       pos = string_buffer_position (w, string, string_before_pos);
+       /* If STRING is from overlay, LAST_POS == 0.  We skip such glyphs
+        because we always put cursor after overlay strings.  */
+       while (pos == 0 && glyph < end)
+       {
+         string = glyph->object;
+         SKIP_GLYPHS (glyph, end, x, EQ (glyph->object, string));
+         if (glyph < end)
+           pos = string_buffer_position (w, glyph->object, string_before_pos);
+       }
+ 
+       while (glyph < end)
+       {
+         pos = XINT (Fnext_single_char_property_change
+                     (make_number (pos), Qdisplay, Qnil, limit));
+         if (pos > pt_old)
+           break;
+         /* Skip glyphs from the same string.  */
+         string = glyph->object;
+         SKIP_GLYPHS (glyph, end, x, EQ (glyph->object, string));
+         /* Skip glyphs from an overlay.  */
+         while (glyph < end
+                && ! string_buffer_position (w, glyph->object, pos))
+           {
+             string = glyph->object;
+             SKIP_GLYPHS (glyph, end, x, EQ (glyph->object, string));
+           }
+       }
+     }
+ 
+   w->cursor.hpos = glyph - row->glyphs[TEXT_AREA];
+   w->cursor.x = x;
+   w->cursor.vpos = MATRIX_ROW_VPOS (row, matrix) + dvpos;
+   w->cursor.y = row->y + dy;
+ 
+   if (w == XWINDOW (selected_window))
+     {
+       if (!row->continued_p
+         && !MATRIX_ROW_CONTINUATION_LINE_P (row)
+         && row->x == 0)
+       {
+         this_line_buffer = XBUFFER (w->buffer);
+ 
+         CHARPOS (this_line_start_pos)
+           = MATRIX_ROW_START_CHARPOS (row) + delta;
+         BYTEPOS (this_line_start_pos)
+           = MATRIX_ROW_START_BYTEPOS (row) + delta_bytes;
+ 
+         CHARPOS (this_line_end_pos)
+           = Z - (MATRIX_ROW_END_CHARPOS (row) + delta);
+         BYTEPOS (this_line_end_pos)
+           = Z_BYTE - (MATRIX_ROW_END_BYTEPOS (row) + delta_bytes);
+ 
+         this_line_y = w->cursor.y;
+         this_line_pixel_height = row->height;
+         this_line_vpos = w->cursor.vpos;
+         this_line_start_x = row->x;
+       }
+       else
+       CHARPOS (this_line_start_pos) = 0;
+     }
+ }
+ 
+ 
+ /* Run window scroll functions, if any, for WINDOW with new window
+    start STARTP.  Sets the window start of WINDOW to that position.
+ 
+    We assume that the window's buffer is really current.  */
+ 
+ static INLINE struct text_pos
+ run_window_scroll_functions (window, startp)
+      Lisp_Object window;
+      struct text_pos startp;
+ {
+   struct window *w = XWINDOW (window);
+   SET_MARKER_FROM_TEXT_POS (w->start, startp);
+ 
+   if (current_buffer != XBUFFER (w->buffer))
+     abort ();
+ 
+   if (!NILP (Vwindow_scroll_functions))
+     {
+       run_hook_with_args_2 (Qwindow_scroll_functions, window,
+                           make_number (CHARPOS (startp)));
+       SET_TEXT_POS_FROM_MARKER (startp, w->start);
+       /* In case the hook functions switch buffers.  */
+       if (current_buffer != XBUFFER (w->buffer))
+       set_buffer_internal_1 (XBUFFER (w->buffer));
+     }
+ 
+   return startp;
+ }
+ 
+ 
+ /* Make sure the line containing the cursor is fully visible.
+    A value of 1 means there is nothing to be done.
+    (Either the line is fully visible, or it cannot be made so,
+    or we cannot tell.)
+    A value of 0 means the caller should do scrolling
+    as if point had gone off the screen.  */
+ 
+ static int
+ make_cursor_line_fully_visible (w)
+      struct window *w;
+ {
+   struct glyph_matrix *matrix;
+   struct glyph_row *row;
+   int window_height;
+ 
+   /* It's not always possible to find the cursor, e.g, when a window
+      is full of overlay strings.  Don't do anything in that case.  */
+   if (w->cursor.vpos < 0)
+     return 1;
+ 
+   matrix = w->desired_matrix;
+   row = MATRIX_ROW (matrix, w->cursor.vpos);
+ 
+   /* If the cursor row is not partially visible, there's nothing to do.  */
+   if (!MATRIX_ROW_PARTIALLY_VISIBLE_P (row))
+     return 1;
+ 
+   /* If the row the cursor is in is taller than the window's height,
+      it's not clear what to do, so do nothing.  */
+   window_height = window_box_height (w);
+   if (row->height >= window_height)
+     return 1;
+ 
+   return 0;
+ 
+ #if 0
+   /* This code used to try to scroll the window just enough to make
+      the line visible.  It returned 0 to say that the caller should
+      allocate larger glyph matrices.  */
+ 
+   if (MATRIX_ROW_PARTIALLY_VISIBLE_AT_TOP_P (w, row))
+     {
+       int dy = row->height - row->visible_height;
+       w->vscroll = 0;
+       w->cursor.y += dy;
+       shift_glyph_matrix (w, matrix, 0, matrix->nrows, dy);
+     }
+   else /* MATRIX_ROW_PARTIALLY_VISIBLE_AT_BOTTOM_P (w, row)) */
+     {
+       int dy = - (row->height - row->visible_height);
+       w->vscroll = dy;
+       w->cursor.y += dy;
+       shift_glyph_matrix (w, matrix, 0, matrix->nrows, dy);
+     }
+ 
+   /* When we change the cursor y-position of the selected window,
+      change this_line_y as well so that the display optimization for
+      the cursor line of the selected window in redisplay_internal uses
+      the correct y-position.  */
+   if (w == XWINDOW (selected_window))
+     this_line_y = w->cursor.y;
+ 
+   /* If vscrolling requires a larger glyph matrix, arrange for a fresh
+      redisplay with larger matrices.  */
+   if (matrix->nrows < required_matrix_height (w))
+     {
+       fonts_changed_p = 1;
+       return 0;
+     }
+ 
+   return 1;
+ #endif /* 0 */
+ }
+ 
+ 
+ /* Try scrolling PT into view in window WINDOW.  JUST_THIS_ONE_P
+    non-zero means only WINDOW is redisplayed in redisplay_internal.
+    TEMP_SCROLL_STEP has the same meaning as scroll_step, and is used
+    in redisplay_window to bring a partially visible line into view in
+    the case that only the cursor has moved.
+ 
+    LAST_LINE_MISFIT should be nonzero if we're scrolling because the
+    last screen line's vertical height extends past the end of the screen.
+ 
+    Value is
+ 
+    1  if scrolling succeeded
+ 
+    0  if scrolling didn't find point.
+ 
+    -1 if new fonts have been loaded so that we must interrupt
+    redisplay, adjust glyph matrices, and try again.  */
+ 
+ enum
+ {
+   SCROLLING_SUCCESS,
+   SCROLLING_FAILED,
+   SCROLLING_NEED_LARGER_MATRICES
+ };
+ 
+ static int
+ try_scrolling (window, just_this_one_p, scroll_conservatively,
+              scroll_step, temp_scroll_step, last_line_misfit)
+      Lisp_Object window;
+      int just_this_one_p;
+      EMACS_INT scroll_conservatively, scroll_step;
+      int temp_scroll_step;
+      int last_line_misfit;
+ {
+   struct window *w = XWINDOW (window);
+   struct frame *f = XFRAME (w->frame);
+   struct text_pos scroll_margin_pos;
+   struct text_pos pos;
+   struct text_pos startp;
+   struct it it;
+   Lisp_Object window_end;
+   int this_scroll_margin;
+   int dy = 0;
+   int scroll_max;
+   int rc;
+   int amount_to_scroll = 0;
+   Lisp_Object aggressive;
+   int height;
+   int end_scroll_margin;
+ 
+ #if GLYPH_DEBUG
+   debug_method_add (w, "try_scrolling");
+ #endif
+ 
+   SET_TEXT_POS_FROM_MARKER (startp, w->start);
+ 
+   /* Compute scroll margin height in pixels.  We scroll when point is
+      within this distance from the top or bottom of the window.  */
+   if (scroll_margin > 0)
+     {
+       this_scroll_margin = min (scroll_margin, WINDOW_TOTAL_LINES (w) / 4);
+       this_scroll_margin *= FRAME_LINE_HEIGHT (f);
+     }
+   else
+     this_scroll_margin = 0;
+ 
+   /* Compute how much we should try to scroll maximally to bring point
+      into view.  */
+   if (scroll_step || scroll_conservatively || temp_scroll_step)
+     scroll_max = max (scroll_step,
+                     max (scroll_conservatively, temp_scroll_step));
+   else if (NUMBERP (current_buffer->scroll_down_aggressively)
+          || NUMBERP (current_buffer->scroll_up_aggressively))
+     /* We're trying to scroll because of aggressive scrolling
+        but no scroll_step is set.  Choose an arbitrary one.  Maybe
+        there should be a variable for this.  */
+     scroll_max = 10;
+   else
+     scroll_max = 0;
+   scroll_max *= FRAME_LINE_HEIGHT (f);
+ 
+   /* Decide whether we have to scroll down.  Start at the window end
+      and move this_scroll_margin up to find the position of the scroll
+      margin.  */
+   window_end = Fwindow_end (window, Qt);
+ 
+  too_near_end:
+ 
+   CHARPOS (scroll_margin_pos) = XINT (window_end);
+   BYTEPOS (scroll_margin_pos) = CHAR_TO_BYTE (CHARPOS (scroll_margin_pos));
+ 
+   end_scroll_margin = this_scroll_margin + !!last_line_misfit;
+   if (end_scroll_margin)
+     {
+       start_display (&it, w, scroll_margin_pos);
+       move_it_vertically (&it, - end_scroll_margin);
+       scroll_margin_pos = it.current.pos;
+     }
+ 
+   if (PT >= CHARPOS (scroll_margin_pos))
+     {
+       int y0;
+ 
+       /* Point is in the scroll margin at the bottom of the window, or
+        below.  Compute a new window start that makes point visible.  */
+ 
+       /* Compute the distance from the scroll margin to PT.
+        Give up if the distance is greater than scroll_max.  */
+       start_display (&it, w, scroll_margin_pos);
+       y0 = it.current_y;
+       move_it_to (&it, PT, 0, it.last_visible_y, -1,
+                 MOVE_TO_POS | MOVE_TO_X | MOVE_TO_Y);
+ 
+       /* To make point visible, we have to move the window start
+        down so that the line the cursor is in is visible, which
+        means we have to add in the height of the cursor line.  */
+       dy = line_bottom_y (&it) - y0;
+ 
+       if (dy > scroll_max)
+       return SCROLLING_FAILED;
+ 
+       /* Move the window start down.  If scrolling conservatively,
+        move it just enough down to make point visible.  If
+        scroll_step is set, move it down by scroll_step.  */
+       start_display (&it, w, startp);
+ 
+       if (scroll_conservatively)
+       /* Set AMOUNT_TO_SCROLL to at least one line,
+          and at most scroll_conservatively lines.  */
+       amount_to_scroll
+         = min (max (dy, FRAME_LINE_HEIGHT (f)),
+                FRAME_LINE_HEIGHT (f) * scroll_conservatively);
+       else if (scroll_step || temp_scroll_step)
+       amount_to_scroll = scroll_max;
+       else
+       {
+         aggressive = current_buffer->scroll_up_aggressively;
+         height = WINDOW_BOX_TEXT_HEIGHT (w);
+         if (NUMBERP (aggressive))
+           amount_to_scroll = XFLOATINT (aggressive) * height;
+       }
+ 
+       if (amount_to_scroll <= 0)
+       return SCROLLING_FAILED;
+ 
+       /* If moving by amount_to_scroll leaves STARTP unchanged,
+        move it down one screen line.  */
+ 
+       move_it_vertically (&it, amount_to_scroll);
+       if (CHARPOS (it.current.pos) == CHARPOS (startp))
+       move_it_by_lines (&it, 1, 1);
+       startp = it.current.pos;
+     }
+   else
+     {
+       /* See if point is inside the scroll margin at the top of the
+          window.  */
+       scroll_margin_pos = startp;
+       if (this_scroll_margin)
+       {
+         start_display (&it, w, startp);
+         move_it_vertically (&it, this_scroll_margin);
+         scroll_margin_pos = it.current.pos;
+       }
+ 
+       if (PT < CHARPOS (scroll_margin_pos))
+       {
+         /* Point is in the scroll margin at the top of the window or
+            above what is displayed in the window.  */
+         int y0;
+ 
+         /* Compute the vertical distance from PT to the scroll
+            margin position.  Give up if distance is greater than
+            scroll_max.  */
+         SET_TEXT_POS (pos, PT, PT_BYTE);
+         start_display (&it, w, pos);
+         y0 = it.current_y;
+         move_it_to (&it, CHARPOS (scroll_margin_pos), 0,
+                     it.last_visible_y, -1,
+                     MOVE_TO_POS | MOVE_TO_X | MOVE_TO_Y);
+         dy = it.current_y - y0;
+         if (dy > scroll_max)
+           return SCROLLING_FAILED;
+ 
+         /* Compute new window start.  */
+         start_display (&it, w, startp);
+ 
+         if (scroll_conservatively)
+           amount_to_scroll =
+             max (dy, FRAME_LINE_HEIGHT (f) * max (scroll_step, 
temp_scroll_step));
+         else if (scroll_step || temp_scroll_step)
+           amount_to_scroll = scroll_max;
+         else
+           {
+             aggressive = current_buffer->scroll_down_aggressively;
+             height = WINDOW_BOX_TEXT_HEIGHT (w);
+             if (NUMBERP (aggressive))
+               amount_to_scroll = XFLOATINT (aggressive) * height;
+           }
+ 
+         if (amount_to_scroll <= 0)
+           return SCROLLING_FAILED;
+ 
+         move_it_vertically (&it, - amount_to_scroll);
+         startp = it.current.pos;
+       }
+     }
+ 
+   /* Run window scroll functions.  */
+   startp = run_window_scroll_functions (window, startp);
+ 
+   /* Display the window.  Give up if new fonts are loaded, or if point
+      doesn't appear.  */
+   if (!try_window (window, startp))
+     rc = SCROLLING_NEED_LARGER_MATRICES;
+   else if (w->cursor.vpos < 0)
+     {
+       clear_glyph_matrix (w->desired_matrix);
+       rc = SCROLLING_FAILED;
+     }
+   else
+     {
+       /* Maybe forget recorded base line for line number display.  */
+       if (!just_this_one_p
+         || current_buffer->clip_changed
+         || BEG_UNCHANGED < CHARPOS (startp))
+       w->base_line_number = Qnil;
+ 
+       /* If cursor ends up on a partially visible line,
+        treat that as being off the bottom of the screen.  */
+       if (! make_cursor_line_fully_visible (w))
+       {
+         clear_glyph_matrix (w->desired_matrix);
+         last_line_misfit = 1;
+         goto too_near_end;
+       }
+       rc = SCROLLING_SUCCESS;
+     }
+ 
+   return rc;
+ }
+ 
+ 
+ /* Compute a suitable window start for window W if display of W starts
+    on a continuation line.  Value is non-zero if a new window start
+    was computed.
+ 
+    The new window start will be computed, based on W's width, starting
+    from the start of the continued line.  It is the start of the
+    screen line with the minimum distance from the old start W->start.  */
+ 
+ static int
+ compute_window_start_on_continuation_line (w)
+      struct window *w;
+ {
+   struct text_pos pos, start_pos;
+   int window_start_changed_p = 0;
+ 
+   SET_TEXT_POS_FROM_MARKER (start_pos, w->start);
+ 
+   /* If window start is on a continuation line...  Window start may be
+      < BEGV in case there's invisible text at the start of the
+      buffer (M-x rmail, for example).  */
+   if (CHARPOS (start_pos) > BEGV
+       && FETCH_BYTE (BYTEPOS (start_pos) - 1) != '\n')
+     {
+       struct it it;
+       struct glyph_row *row;
+ 
+       /* Handle the case that the window start is out of range.  */
+       if (CHARPOS (start_pos) < BEGV)
+       SET_TEXT_POS (start_pos, BEGV, BEGV_BYTE);
+       else if (CHARPOS (start_pos) > ZV)
+       SET_TEXT_POS (start_pos, ZV, ZV_BYTE);
+ 
+       /* Find the start of the continued line.  This should be fast
+        because scan_buffer is fast (newline cache).  */
+       row = w->desired_matrix->rows + (WINDOW_WANTS_HEADER_LINE_P (w) ? 1 : 
0);
+       init_iterator (&it, w, CHARPOS (start_pos), BYTEPOS (start_pos),
+                    row, DEFAULT_FACE_ID);
+       reseat_at_previous_visible_line_start (&it);
+ 
+       /* If the line start is "too far" away from the window start,
+          say it takes too much time to compute a new window start.  */
+       if (CHARPOS (start_pos) - IT_CHARPOS (it)
+         < WINDOW_TOTAL_LINES (w) * WINDOW_TOTAL_COLS (w))
+       {
+         int min_distance, distance;
+ 
+         /* Move forward by display lines to find the new window
+            start.  If window width was enlarged, the new start can
+            be expected to be > the old start.  If window width was
+            decreased, the new window start will be < the old start.
+            So, we're looking for the display line start with the
+            minimum distance from the old window start.  */
+         pos = it.current.pos;
+         min_distance = INFINITY;
+         while ((distance = abs (CHARPOS (start_pos) - IT_CHARPOS (it))),
+                distance < min_distance)
+           {
+             min_distance = distance;
+             pos = it.current.pos;
+             move_it_by_lines (&it, 1, 0);
+           }
+ 
+         /* Set the window start there.  */
+         SET_MARKER_FROM_TEXT_POS (w->start, pos);
+         window_start_changed_p = 1;
+       }
+     }
+ 
+   return window_start_changed_p;
+ }
+ 
+ 
+ /* Try cursor movement in case text has not changed in window WINDOW,
+    with window start STARTP.  Value is
+ 
+    CURSOR_MOVEMENT_SUCCESS if successful
+ 
+    CURSOR_MOVEMENT_CANNOT_BE_USED if this method cannot be used
+ 
+    CURSOR_MOVEMENT_MUST_SCROLL if we know we have to scroll the
+    display.  *SCROLL_STEP is set to 1, under certain circumstances, if
+    we want to scroll as if scroll-step were set to 1.  See the code.
+ 
+    CURSOR_MOVEMENT_NEED_LARGER_MATRICES if we need larger matrices, in
+    which case we have to abort this redisplay, and adjust matrices
+    first.  */
+ 
+ enum
+ {
+   CURSOR_MOVEMENT_SUCCESS,
+   CURSOR_MOVEMENT_CANNOT_BE_USED,
+   CURSOR_MOVEMENT_MUST_SCROLL,
+   CURSOR_MOVEMENT_NEED_LARGER_MATRICES
+ };
+ 
+ static int
+ try_cursor_movement (window, startp, scroll_step)
+      Lisp_Object window;
+      struct text_pos startp;
+      int *scroll_step;
+ {
+   struct window *w = XWINDOW (window);
+   struct frame *f = XFRAME (w->frame);
+   int rc = CURSOR_MOVEMENT_CANNOT_BE_USED;
+ 
+ #if GLYPH_DEBUG
+   if (inhibit_try_cursor_movement)
+     return rc;
+ #endif
+ 
+   /* Handle case where text has not changed, only point, and it has
+      not moved off the frame.  */
+   if (/* Point may be in this window.  */
+       PT >= CHARPOS (startp)
+       /* Selective display hasn't changed.  */
+       && !current_buffer->clip_changed
+       /* Function force-mode-line-update is used to force a thorough
+        redisplay.  It sets either windows_or_buffers_changed or
+        update_mode_lines.  So don't take a shortcut here for these
+        cases.  */
+       && !update_mode_lines
+       && !windows_or_buffers_changed
+       && !cursor_type_changed
+       /* Can't use this case if highlighting a region.  When a
+          region exists, cursor movement has to do more than just
+          set the cursor.  */
+       && !(!NILP (Vtransient_mark_mode)
+          && !NILP (current_buffer->mark_active))
+       && NILP (w->region_showing)
+       && NILP (Vshow_trailing_whitespace)
+       /* Right after splitting windows, last_point may be nil.  */
+       && INTEGERP (w->last_point)
+       /* This code is not used for mini-buffer for the sake of the case
+        of redisplaying to replace an echo area message; since in
+        that case the mini-buffer contents per se are usually
+        unchanged.  This code is of no real use in the mini-buffer
+        since the handling of this_line_start_pos, etc., in redisplay
+        handles the same cases.  */
+       && !EQ (window, minibuf_window)
+       /* When splitting windows or for new windows, it happens that
+        redisplay is called with a nil window_end_vpos or one being
+        larger than the window.  This should really be fixed in
+        window.c.  I don't have this on my list, now, so we do
+        approximately the same as the old redisplay code.  --gerd.  */
+       && INTEGERP (w->window_end_vpos)
+       && XFASTINT (w->window_end_vpos) < w->current_matrix->nrows
+       && (FRAME_WINDOW_P (f)
+         || !MARKERP (Voverlay_arrow_position)
+         || current_buffer != XMARKER (Voverlay_arrow_position)->buffer))
+     {
+       int this_scroll_margin;
+       struct glyph_row *row = NULL;
+ 
+ #if GLYPH_DEBUG
+       debug_method_add (w, "cursor movement");
+ #endif
+ 
+       /* Scroll if point within this distance from the top or bottom
+        of the window.  This is a pixel value.  */
+       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 (f);
+ 
+       /* Start with the row the cursor was displayed during the last
+        not paused redisplay.  Give up if that row is not valid.  */
+       if (w->last_cursor.vpos < 0
+         || w->last_cursor.vpos >= w->current_matrix->nrows)
+       rc = CURSOR_MOVEMENT_MUST_SCROLL;
+       else
+       {
+         row = MATRIX_ROW (w->current_matrix, w->last_cursor.vpos);
+         if (row->mode_line_p)
+           ++row;
+         if (!row->enabled_p)
+           rc = CURSOR_MOVEMENT_MUST_SCROLL;
+       }
+ 
+       if (rc == CURSOR_MOVEMENT_CANNOT_BE_USED)
+       {
+         int scroll_p = 0;
+         int last_y = window_text_bottom_y (w) - this_scroll_margin;
+ 
+         if (PT > XFASTINT (w->last_point))
+           {
+             /* Point has moved forward.  */
+             while (MATRIX_ROW_END_CHARPOS (row) < PT
+                    && MATRIX_ROW_BOTTOM_Y (row) < last_y)
+               {
+                 xassert (row->enabled_p);
+                 ++row;
+               }
+ 
+             /* The end position of a row equals the start position
+                of the next row.  If PT is there, we would rather
+                display it in the next line.  */
+             while (MATRIX_ROW_BOTTOM_Y (row) < last_y
+                    && MATRIX_ROW_END_CHARPOS (row) == PT
+                    && !cursor_row_p (w, row))
+               ++row;
+ 
+             /* If within the scroll margin, scroll.  Note that
+                MATRIX_ROW_BOTTOM_Y gives the pixel position at which
+                the next line would be drawn, and that
+                this_scroll_margin can be zero.  */
+             if (MATRIX_ROW_BOTTOM_Y (row) > last_y
+                 || PT > MATRIX_ROW_END_CHARPOS (row)
+                 /* Line is completely visible last line in window
+                    and PT is to be set in the next line.  */
+                 || (MATRIX_ROW_BOTTOM_Y (row) == last_y
+                     && PT == MATRIX_ROW_END_CHARPOS (row)
+                     && !row->ends_at_zv_p
+                     && !MATRIX_ROW_ENDS_IN_MIDDLE_OF_CHAR_P (row)))
+               scroll_p = 1;
+           }
+         else if (PT < XFASTINT (w->last_point))
+           {
+             /* Cursor has to be moved backward.  Note that PT >=
+                CHARPOS (startp) because of the outer
+                if-statement.  */
+             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)))
+                    && (row->y > this_scroll_margin
+                        || CHARPOS (startp) == BEGV))
+               {
+                 xassert (row->enabled_p);
+                 --row;
+               }
+ 
+             /* Consider the following case: Window starts at BEGV,
+                there is invisible, intangible text at BEGV, so that
+                display starts at some point START > BEGV.  It can
+                happen that we are called with PT somewhere between
+                BEGV and START.  Try to handle that case.  */
+             if (row < w->current_matrix->rows
+                 || row->mode_line_p)
+               {
+                 row = w->current_matrix->rows;
+                 if (row->mode_line_p)
+                   ++row;
+               }
+ 
+             /* Due to newlines in overlay strings, we may have to
+                skip forward over overlay strings.  */
+             while (MATRIX_ROW_BOTTOM_Y (row) < last_y
+                    && MATRIX_ROW_END_CHARPOS (row) == PT
+                    && !cursor_row_p (w, row))
+               ++row;
+ 
+             /* If within the scroll margin, scroll.  */
+             if (row->y < this_scroll_margin
+                 && CHARPOS (startp) != BEGV)
+               scroll_p = 1;
+           }
+ 
+         if (PT < MATRIX_ROW_START_CHARPOS (row)
+             || PT > MATRIX_ROW_END_CHARPOS (row))
+           {
+             /* if PT is not in the glyph row, give up.  */
+             rc = CURSOR_MOVEMENT_MUST_SCROLL;
+           }
+         else if (MATRIX_ROW_PARTIALLY_VISIBLE_P (row))
+           {
+             if (PT == MATRIX_ROW_END_CHARPOS (row)
+                 && !row->ends_at_zv_p
+                 && !MATRIX_ROW_ENDS_IN_MIDDLE_OF_CHAR_P (row))
+               rc = CURSOR_MOVEMENT_MUST_SCROLL;
+             else if (row->height > window_box_height (w))
+               {
+                 /* If we end up in a partially visible line, let's
+                    make it fully visible, except when it's taller
+                    than the window, in which case we can't do much
+                    about it.  */
+                 *scroll_step = 1;
+                 rc = CURSOR_MOVEMENT_MUST_SCROLL;
+               }
+             else
+               {
+                 set_cursor_from_row (w, row, w->current_matrix, 0, 0, 0, 0);
+                 if (!make_cursor_line_fully_visible (w))
+                   rc = CURSOR_MOVEMENT_MUST_SCROLL;
+                 else
+                   rc = CURSOR_MOVEMENT_SUCCESS;
+               }
+           }
+         else if (scroll_p)
+           rc = CURSOR_MOVEMENT_MUST_SCROLL;
+         else
+           {
+             set_cursor_from_row (w, row, w->current_matrix, 0, 0, 0, 0);
+             rc = CURSOR_MOVEMENT_SUCCESS;
+           }
+       }
+     }
+ 
+   return rc;
+ }
+ 
+ void
+ set_vertical_scroll_bar (w)
+      struct window *w;
+ {
+   int start, end, whole;
+ 
+   /* Calculate the start and end positions for the current window.
+      At some point, it would be nice to choose between scrollbars
+      which reflect the whole buffer size, with special markers
+      indicating narrowing, and scrollbars which reflect only the
+      visible region.
+      
+      Note that mini-buffers sometimes aren't displaying any text.  */
+   if (!MINI_WINDOW_P (w)
+       || (w == XWINDOW (minibuf_window)
+         && NILP (echo_area_buffer[0])))
+     {
+       struct buffer *buf = XBUFFER (w->buffer);
+       whole = BUF_ZV (buf) - BUF_BEGV (buf);
+       start = marker_position (w->start) - BUF_BEGV (buf);
+       /* I don't think this is guaranteed to be right.  For the
+        moment, we'll pretend it is.  */
+       end = BUF_Z (buf) - XFASTINT (w->window_end_pos) - BUF_BEGV (buf);
+       
+       if (end < start)
+       end = start;
+       if (whole < (end - start))
+       whole = end - start;
+     }
+   else
+     start = end = whole = 0;
+ 
+   /* Indicate what this scroll bar ought to be displaying now.  */
+   set_vertical_scroll_bar_hook (w, end - start, whole, start);
+ }
+ 
+ /* Redisplay leaf window WINDOW.  JUST_THIS_ONE_P non-zero means only
+    selected_window is redisplayed.
+ 
+    We can return without actually redisplaying the window if
+    fonts_changed_p is nonzero.  In that case, redisplay_internal will
+    retry.  */
+ 
+ static void
+ redisplay_window (window, just_this_one_p)
+      Lisp_Object window;
+      int just_this_one_p;
+ {
+   struct window *w = XWINDOW (window);
+   struct frame *f = XFRAME (w->frame);
+   struct buffer *buffer = XBUFFER (w->buffer);
+   struct buffer *old = current_buffer;
+   struct text_pos lpoint, opoint, startp;
+   int update_mode_line;
+   int tem;
+   struct it it;
+   /* Record it now because it's overwritten.  */
+   int current_matrix_up_to_date_p = 0;
+   /* This is less strict than current_matrix_up_to_date_p.
+      It indictes that the buffer contents and narrowing are unchanged.  */
+   int buffer_unchanged_p = 0;
+   int temp_scroll_step = 0;
+   int count = SPECPDL_INDEX ();
+   int rc;
+   int centering_position;
+   int last_line_misfit = 0;
+ 
+   SET_TEXT_POS (lpoint, PT, PT_BYTE);
+   opoint = lpoint;
+ 
+   /* W must be a leaf window here.  */
+   xassert (!NILP (w->buffer));
+ #if GLYPH_DEBUG
+   *w->desired_matrix->method = 0;
+ #endif
+ 
+   specbind (Qinhibit_point_motion_hooks, Qt);
+ 
+   reconsider_clip_changes (w, buffer);
+ 
+   /* Has the mode line to be updated?  */
+   update_mode_line = (!NILP (w->update_mode_line)
+                     || update_mode_lines
+                     || buffer->clip_changed
+                     || buffer->prevent_redisplay_optimizations_p);
+ 
+   if (MINI_WINDOW_P (w))
+     {
+       if (w == XWINDOW (echo_area_window)
+         && !NILP (echo_area_buffer[0]))
+       {
+         if (update_mode_line)
+           /* We may have to update a tty frame's menu bar or a
+              tool-bar.  Example `M-x C-h C-h C-g'.  */
+           goto finish_menu_bars;
+         else
+           /* We've already displayed the echo area glyphs in this window.  */
+           goto finish_scroll_bars;
+       }
+       else if ((w != XWINDOW (minibuf_window)
+               || minibuf_level == 0)
+              /* When buffer is nonempty, redisplay window normally. */
+              && BUF_Z (XBUFFER (w->buffer)) == BUF_BEG (XBUFFER (w->buffer))
+              /* Quail displays non-mini buffers in minibuffer window.
+                 In that case, redisplay the window normally.  */
+              && !NILP (Fmemq (w->buffer, Vminibuffer_list)))
+       {
+         /* W is a mini-buffer window, but it's not active, so clear
+            it.  */
+         int yb = window_text_bottom_y (w);
+         struct glyph_row *row;
+         int y;
+ 
+         for (y = 0, row = w->desired_matrix->rows;
+              y < yb;
+              y += row->height, ++row)
+           blank_row (w, row, y);
+         goto finish_scroll_bars;
+       }
+ 
+       clear_glyph_matrix (w->desired_matrix);
+     }
+ 
+   /* Otherwise set up data on this window; select its buffer and point
+      value.  */
+   /* Really select the buffer, for the sake of buffer-local
+      variables.  */
+   set_buffer_internal_1 (XBUFFER (w->buffer));
+   SET_TEXT_POS (opoint, PT, PT_BYTE);
+ 
+   current_matrix_up_to_date_p
+     = (!NILP (w->window_end_valid)
+        && !current_buffer->clip_changed
+        && !current_buffer->prevent_redisplay_optimizations_p
+        && XFASTINT (w->last_modified) >= MODIFF
+        && XFASTINT (w->last_overlay_modified) >= OVERLAY_MODIFF);
+ 
+   buffer_unchanged_p
+     = (!NILP (w->window_end_valid)
+        && !current_buffer->clip_changed
+        && XFASTINT (w->last_modified) >= MODIFF
+        && XFASTINT (w->last_overlay_modified) >= OVERLAY_MODIFF);
+ 
+   /* When windows_or_buffers_changed is non-zero, we can't rely on
+      the window end being valid, so set it to nil there.  */
+   if (windows_or_buffers_changed)
+     {
+       /* If window starts on a continuation line, maybe adjust the
+        window start in case the window's width changed.  */
+       if (XMARKER (w->start)->buffer == current_buffer)
+       compute_window_start_on_continuation_line (w);
+ 
+       w->window_end_valid = Qnil;
+     }
+ 
+   /* Some sanity checks.  */
+   CHECK_WINDOW_END (w);
+   if (Z == Z_BYTE && CHARPOS (opoint) != BYTEPOS (opoint))
+     abort ();
+   if (BYTEPOS (opoint) < CHARPOS (opoint))
+     abort ();
+ 
+   /* If %c is in mode line, update it if needed.  */
+   if (!NILP (w->column_number_displayed)
+       /* This alternative quickly identifies a common case
+        where no change is needed.  */
+       && !(PT == XFASTINT (w->last_point)
+          && XFASTINT (w->last_modified) >= MODIFF
+          && XFASTINT (w->last_overlay_modified) >= OVERLAY_MODIFF)
+       && (XFASTINT (w->column_number_displayed)
+           != (int) current_column ()))  /* iftc */
+     update_mode_line = 1;
+ 
+   /* Count number of windows showing the selected buffer.  An indirect
+      buffer counts as its base buffer.  */
+   if (!just_this_one_p)
+     {
+       struct buffer *current_base, *window_base;
+       current_base = current_buffer;
+       window_base = XBUFFER (XWINDOW (selected_window)->buffer);
+       if (current_base->base_buffer)
+       current_base = current_base->base_buffer;
+       if (window_base->base_buffer)
+       window_base = window_base->base_buffer;
+       if (current_base == window_base)
+       buffer_shared++;
+     }
+ 
+   /* Point refers normally to the selected window.  For any other
+      window, set up appropriate value.  */
+   if (!EQ (window, selected_window))
+     {
+       int new_pt = XMARKER (w->pointm)->charpos;
+       int new_pt_byte = marker_byte_position (w->pointm);
+       if (new_pt < BEGV)
+       {
+         new_pt = BEGV;
+         new_pt_byte = BEGV_BYTE;
+         set_marker_both (w->pointm, Qnil, BEGV, BEGV_BYTE);
+       }
+       else if (new_pt > (ZV - 1))
+       {
+         new_pt = ZV;
+         new_pt_byte = ZV_BYTE;
+         set_marker_both (w->pointm, Qnil, ZV, ZV_BYTE);
+       }
+ 
+       /* We don't use SET_PT so that the point-motion hooks don't run.  */
+       TEMP_SET_PT_BOTH (new_pt, new_pt_byte);
+     }
+ 
+   /* If any of the character widths specified in the display table
+      have changed, invalidate the width run cache.  It's true that
+      this may be a bit late to catch such changes, but the rest of
+      redisplay goes (non-fatally) haywire when the display table is
+      changed, so why should we worry about doing any better?  */
+   if (current_buffer->width_run_cache)
+     {
+       struct Lisp_Char_Table *disptab = buffer_display_table ();
+ 
+       if (! disptab_matches_widthtab (disptab,
+                                       XVECTOR (current_buffer->width_table)))
+         {
+           invalidate_region_cache (current_buffer,
+                                    current_buffer->width_run_cache,
+                                    BEG, Z);
+           recompute_width_table (current_buffer, disptab);
+         }
+     }
+ 
+   /* If window-start is screwed up, choose a new one.  */
+   if (XMARKER (w->start)->buffer != current_buffer)
+     goto recenter;
+ 
+   SET_TEXT_POS_FROM_MARKER (startp, w->start);
+ 
+   /* If someone specified a new starting point but did not insist,
+      check whether it can be used.  */
+   if (!NILP (w->optional_new_start)
+       && CHARPOS (startp) >= BEGV
+       && CHARPOS (startp) <= ZV)
+     {
+       w->optional_new_start = Qnil;
+       start_display (&it, w, startp);
+       move_it_to (&it, PT, 0, it.last_visible_y, -1,
+                 MOVE_TO_POS | MOVE_TO_X | MOVE_TO_Y);
+       if (IT_CHARPOS (it) == PT)
+       w->force_start = Qt;
+     }
+ 
+   /* Handle case where place to start displaying has been specified,
+      unless the specified location is outside the accessible range.  */
+   if (!NILP (w->force_start)
+       || w->frozen_window_start_p)
+     {
+       /* We set this later on if we have to adjust point.  */
+       int new_vpos = -1;
+ 
+       w->force_start = Qnil;
+       w->vscroll = 0;
+       w->window_end_valid = Qnil;
+ 
+       /* Forget any recorded base line for line number display.  */
+       if (!buffer_unchanged_p)
+       w->base_line_number = Qnil;
+ 
+       /* Redisplay the mode line.  Select the buffer properly for that.
+        Also, run the hook window-scroll-functions
+        because we have scrolled.  */
+       /* Note, we do this after clearing force_start because
+        if there's an error, it is better to forget about force_start
+        than to get into an infinite loop calling the hook functions
+        and having them get more errors.  */
+       if (!update_mode_line
+         || ! NILP (Vwindow_scroll_functions))
+       {
+         update_mode_line = 1;
+         w->update_mode_line = Qt;
+         startp = run_window_scroll_functions (window, startp);
+       }
+ 
+       w->last_modified = make_number (0);
+       w->last_overlay_modified = make_number (0);
+       if (CHARPOS (startp) < BEGV)
+       SET_TEXT_POS (startp, BEGV, BEGV_BYTE);
+       else if (CHARPOS (startp) > ZV)
+       SET_TEXT_POS (startp, ZV, ZV_BYTE);
+ 
+       /* Redisplay, then check if cursor has been set during the
+        redisplay.  Give up if new fonts were loaded.  */
+       if (!try_window (window, startp))
+       {
+         w->force_start = Qt;
+         clear_glyph_matrix (w->desired_matrix);
+         goto need_larger_matrices;
+       }
+ 
+       if (w->cursor.vpos < 0 && !w->frozen_window_start_p)
+       {
+         /* If point does not appear, try to move point so it does
+            appear. The desired matrix has been built above, so we
+            can use it here.  */
+         new_vpos = window_box_height (w) / 2;
+       }
+ 
+       if (!make_cursor_line_fully_visible (w))
+       {
+         /* Point does appear, but on a line partly visible at end of window.
+            Move it back to a fully-visible line.  */
+         new_vpos = window_box_height (w);
+       }
+ 
+       /* If we need to move point for either of the above reasons,
+        now actually do it.  */
+       if (new_vpos >= 0)
+       {
+         struct glyph_row *row;
+ 
+         row = MATRIX_FIRST_TEXT_ROW (w->desired_matrix);
+         while (MATRIX_ROW_BOTTOM_Y (row) < new_vpos)
+           ++row;
+ 
+         TEMP_SET_PT_BOTH (MATRIX_ROW_START_CHARPOS (row),
+                           MATRIX_ROW_START_BYTEPOS (row));
+ 
+         if (w != XWINDOW (selected_window))
+           set_marker_both (w->pointm, Qnil, PT, PT_BYTE);
+         else if (current_buffer == old)
+           SET_TEXT_POS (lpoint, PT, PT_BYTE);
+ 
+         set_cursor_from_row (w, row, w->desired_matrix, 0, 0, 0, 0);
+ 
+         /* If we are highlighting the region, then we just changed
+            the region, so redisplay to show it.  */
+         if (!NILP (Vtransient_mark_mode)
+             && !NILP (current_buffer->mark_active))
+           {
+             clear_glyph_matrix (w->desired_matrix);
+             if (!try_window (window, startp))
+               goto need_larger_matrices;
+           }
+       }
+ 
+ #if GLYPH_DEBUG
+       debug_method_add (w, "forced window start");
+ #endif
+       goto done;
+     }
+ 
+   /* Handle case where text has not changed, only point, and it has
+      not moved off the frame, and we are not retrying after hscroll.
+      (current_matrix_up_to_date_p is nonzero when retrying.)  */
+   if (current_matrix_up_to_date_p
+       && (rc = try_cursor_movement (window, startp, &temp_scroll_step),
+         rc != CURSOR_MOVEMENT_CANNOT_BE_USED))
+     {
+       switch (rc)
+       {
+       case CURSOR_MOVEMENT_SUCCESS:
+         goto done;
+ 
+ #if 0  /* try_cursor_movement never returns this value.  */
+       case CURSOR_MOVEMENT_NEED_LARGER_MATRICES:
+         goto need_larger_matrices;
+ #endif
+ 
+       case CURSOR_MOVEMENT_MUST_SCROLL:
+         goto try_to_scroll;
+ 
+       default:
+         abort ();
+       }
+     }
+   /* If current starting point was originally the beginning of a line
+      but no longer is, find a new starting point.  */
+   else if (!NILP (w->start_at_line_beg)
+          && !(CHARPOS (startp) <= BEGV
+               || FETCH_BYTE (BYTEPOS (startp) - 1) == '\n'))
+     {
+ #if GLYPH_DEBUG
+       debug_method_add (w, "recenter 1");
+ #endif
+       goto recenter;
+     }
+ 
+   /* Try scrolling with try_window_id.  Value is > 0 if update has
+      been done, it is -1 if we know that the same window start will
+      not work.  It is 0 if unsuccessful for some other reason.  */
+   else if ((tem = try_window_id (w)) != 0)
+     {
+ #if GLYPH_DEBUG
+       debug_method_add (w, "try_window_id %d", tem);
+ #endif
+ 
+       if (fonts_changed_p)
+       goto need_larger_matrices;
+       if (tem > 0)
+       goto done;
+ 
+       /* Otherwise try_window_id has returned -1 which means that we
+        don't want the alternative below this comment to execute.  */
+     }
+   else if (CHARPOS (startp) >= BEGV
+          && CHARPOS (startp) <= ZV
+          && PT >= CHARPOS (startp)
+          && (CHARPOS (startp) < ZV
+              /* Avoid starting at end of buffer.  */
+              || CHARPOS (startp) == BEGV
+              || (XFASTINT (w->last_modified) >= MODIFF
+                  && XFASTINT (w->last_overlay_modified) >= OVERLAY_MODIFF)))
+     {
+ #if GLYPH_DEBUG
+       debug_method_add (w, "same window start");
+ #endif
+ 
+       /* Try to redisplay starting at same place as before.
+          If point has not moved off frame, accept the results.  */
+       if (!current_matrix_up_to_date_p
+         /* Don't use try_window_reusing_current_matrix in this case
+            because a window scroll function can have changed the
+            buffer.  */
+         || !NILP (Vwindow_scroll_functions)
+         || MINI_WINDOW_P (w)
+         || !try_window_reusing_current_matrix (w))
+       {
+         IF_DEBUG (debug_method_add (w, "1"));
+         try_window (window, startp);
+       }
+ 
+       if (fonts_changed_p)
+       goto need_larger_matrices;
+ 
+       if (w->cursor.vpos >= 0)
+       {
+         if (!just_this_one_p
+             || current_buffer->clip_changed
+             || BEG_UNCHANGED < CHARPOS (startp))
+           /* Forget any recorded base line for line number display.  */
+           w->base_line_number = Qnil;
+ 
+         if (!make_cursor_line_fully_visible (w))
+           {
+             clear_glyph_matrix (w->desired_matrix);
+             last_line_misfit = 1;
+           }
+           /* Drop through and scroll.  */
+         else
+           goto done;
+       }
+       else
+       clear_glyph_matrix (w->desired_matrix);
+     }
+ 
+  try_to_scroll:
+ 
+   w->last_modified = make_number (0);
+   w->last_overlay_modified = make_number (0);
+ 
+   /* Redisplay the mode line.  Select the buffer properly for that.  */
+   if (!update_mode_line)
+     {
+       update_mode_line = 1;
+       w->update_mode_line = Qt;
+     }
+ 
+   /* Try to scroll by specified few lines.  */
+   if ((scroll_conservatively
+        || scroll_step
+        || temp_scroll_step
+        || NUMBERP (current_buffer->scroll_up_aggressively)
+        || NUMBERP (current_buffer->scroll_down_aggressively))
+       && !current_buffer->clip_changed
+       && CHARPOS (startp) >= BEGV
+       && CHARPOS (startp) <= ZV)
+     {
+       /* The function returns -1 if new fonts were loaded, 1 if
+        successful, 0 if not successful.  */
+       int rc = try_scrolling (window, just_this_one_p,
+                             scroll_conservatively,
+                             scroll_step,
+                             temp_scroll_step, last_line_misfit);
+       switch (rc)
+       {
+       case SCROLLING_SUCCESS:
+         goto done;
+ 
+       case SCROLLING_NEED_LARGER_MATRICES:
+         goto need_larger_matrices;
+ 
+       case SCROLLING_FAILED:
+         break;
+ 
+       default:
+         abort ();
+       }
+     }
+ 
+   /* Finally, just choose place to start which centers point */
+ 
+  recenter:
+   centering_position = window_box_height (w) / 2;
+ 
+  point_at_top:
+   /* Jump here with centering_position already set to 0.  */
+ 
+ #if GLYPH_DEBUG
+   debug_method_add (w, "recenter");
+ #endif
+ 
+   /* w->vscroll = 0; */
+ 
+   /* Forget any previously recorded base line for line number display.  */
+   if (!buffer_unchanged_p)
+     w->base_line_number = Qnil;
+ 
+   /* Move backward half the height of the window.  */
+   init_iterator (&it, w, PT, PT_BYTE, NULL, DEFAULT_FACE_ID);
+   it.current_y = it.last_visible_y;
+   move_it_vertically_backward (&it, centering_position);
+   xassert (IT_CHARPOS (it) >= BEGV);
+ 
+   /* The function move_it_vertically_backward may move over more
+      than the specified y-distance.  If it->w is small, e.g. a
+      mini-buffer window, we may end up in front of the window's
+      display area.  Start displaying at the start of the line
+      containing PT in this case.  */
+   if (it.current_y <= 0)
+     {
+       init_iterator (&it, w, PT, PT_BYTE, NULL, DEFAULT_FACE_ID);
+       move_it_vertically (&it, 0);
+       xassert (IT_CHARPOS (it) <= PT);
+       it.current_y = 0;
+     }
+ 
+   it.current_x = it.hpos = 0;
+ 
+   /* Set startp here explicitly in case that helps avoid an infinite loop
+      in case the window-scroll-functions functions get errors.  */
+   set_marker_both (w->start, Qnil, IT_CHARPOS (it), IT_BYTEPOS (it));
+ 
+   /* Run scroll hooks.  */
+   startp = run_window_scroll_functions (window, it.current.pos);
+ 
+   /* Redisplay the window.  */
+   if (!current_matrix_up_to_date_p
+       || windows_or_buffers_changed
+       || cursor_type_changed
+       /* Don't use try_window_reusing_current_matrix in this case
+        because it can have changed the buffer.  */
+       || !NILP (Vwindow_scroll_functions)
+       || !just_this_one_p
+       || MINI_WINDOW_P (w)
+       || !try_window_reusing_current_matrix (w))
+     try_window (window, startp);
+ 
+   /* 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
+      matrices.  */
+   if (fonts_changed_p)
+     goto need_larger_matrices;
+ 
+   /* If cursor did not appear assume that the middle of the window is
+      in the first line of the window.  Do it again with the next line.
+      (Imagine a window of height 100, displaying two lines of height
+      60.  Moving back 50 from it->last_visible_y will end in the first
+      line.)  */
+   if (w->cursor.vpos < 0)
+     {
+       if (!NILP (w->window_end_valid)
+         && PT >= Z - XFASTINT (w->window_end_pos))
+       {
+         clear_glyph_matrix (w->desired_matrix);
+         move_it_by_lines (&it, 1, 0);
+         try_window (window, it.current.pos);
+       }
+       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);
+       }
+       else
+       {
+         /* Not much we can do about it.  */
+       }
+     }
+ 
+   /* Consider the following case: Window starts at BEGV, there is
+      invisible, intangible text at BEGV, so that display starts at
+      some point START > BEGV.  It can happen that we are called with
+      PT somewhere between BEGV and START.  Try to handle that case.  */
+   if (w->cursor.vpos < 0)
+     {
+       struct glyph_row *row = w->current_matrix->rows;
+       if (row->mode_line_p)
+       ++row;
+       set_cursor_from_row (w, row, w->current_matrix, 0, 0, 0, 0);
+     }
+ 
+   if (!make_cursor_line_fully_visible (w))
+     {
+       /* If vscroll is enabled, disable it and try again.  */
+       if (w->vscroll)
+       {
+         w->vscroll = 0;
+         clear_glyph_matrix (w->desired_matrix);
+         goto recenter;
+       }
+ 
+       /* If centering point failed to make the whole line visible,
+        put point at the top instead.  That has to make the whole line
+        visible, if it can be done.  */
+       centering_position = 0;
+       goto point_at_top;
+     }
+ 
+  done:
+ 
+   SET_TEXT_POS_FROM_MARKER (startp, w->start);
+   w->start_at_line_beg = ((CHARPOS (startp) == BEGV
+                          || FETCH_BYTE (BYTEPOS (startp) - 1) == '\n')
+                         ? Qt : Qnil);
+ 
+   /* Display the mode line, if we must.  */
+   if ((update_mode_line
+        /* If window not full width, must redo its mode line
+         if (a) the window to its side is being redone and
+         (b) we do a frame-based redisplay.  This is a consequence
+         of how inverted lines are drawn in frame-based redisplay.  */
+        || (!just_this_one_p
+          && !FRAME_WINDOW_P (f)
+          && !WINDOW_FULL_WIDTH_P (w))
+        /* Line number to display.  */
+        || INTEGERP (w->base_line_pos)
+        /* Column number is displayed and different from the one displayed.  */
+        || (!NILP (w->column_number_displayed)
+          && (XFASTINT (w->column_number_displayed)
+                != (int) current_column ()))) /* iftc */
+        /* This means that the window has a mode line.  */
+        && (WINDOW_WANTS_MODELINE_P (w)
+          || WINDOW_WANTS_HEADER_LINE_P (w)))
+     {
+       display_mode_lines (w);
+ 
+       /* If mode line height has changed, arrange for a thorough
+        immediate redisplay using the correct mode line height.  */
+       if (WINDOW_WANTS_MODELINE_P (w)
+         && CURRENT_MODE_LINE_HEIGHT (w) != DESIRED_MODE_LINE_HEIGHT (w))
+       {
+         fonts_changed_p = 1;
+         MATRIX_MODE_LINE_ROW (w->current_matrix)->height
+           = DESIRED_MODE_LINE_HEIGHT (w);
+       }
+ 
+       /* If top line height has changed, arrange for a thorough
+        immediate redisplay using the correct mode line height.  */
+       if (WINDOW_WANTS_HEADER_LINE_P (w)
+         && CURRENT_HEADER_LINE_HEIGHT (w) != DESIRED_HEADER_LINE_HEIGHT (w))
+       {
+         fonts_changed_p = 1;
+         MATRIX_HEADER_LINE_ROW (w->current_matrix)->height
+           = DESIRED_HEADER_LINE_HEIGHT (w);
+       }
+ 
+       if (fonts_changed_p)
+       goto need_larger_matrices;
+     }
+ 
+   if (!line_number_displayed
+       && !BUFFERP (w->base_line_pos))
+     {
+       w->base_line_pos = Qnil;
+       w->base_line_number = Qnil;
+     }
+ 
+  finish_menu_bars:
+ 
+   /* When we reach a frame's selected window, redo the frame's menu bar.  */
+   if (update_mode_line
+       && EQ (FRAME_SELECTED_WINDOW (f), window))
+     {
+       int redisplay_menu_p = 0;
+       int redisplay_tool_bar_p = 0;
+ 
+       if (FRAME_WINDOW_P (f))
+       {
+ #if defined (USE_X_TOOLKIT) || defined (HAVE_NTGUI) || defined (MAC_OS) \
+     || defined (USE_GTK)
+         redisplay_menu_p = FRAME_EXTERNAL_MENU_BAR (f);
+ #else
+         redisplay_menu_p = FRAME_MENU_BAR_LINES (f) > 0;
+ #endif
+       }
+       else
+         redisplay_menu_p = FRAME_MENU_BAR_LINES (f) > 0;
+ 
+       if (redisplay_menu_p)
+         display_menu_bar (w);
+ 
+ #ifdef HAVE_WINDOW_SYSTEM
+ #ifdef USE_GTK
+       redisplay_tool_bar_p = FRAME_EXTERNAL_TOOL_BAR (f);
+ #else
+       redisplay_tool_bar_p = WINDOWP (f->tool_bar_window)
+         && (FRAME_TOOL_BAR_LINES (f) > 0
+             || auto_resize_tool_bars_p);
+ 
+ #endif
+ 
+       if (redisplay_tool_bar_p)
+         redisplay_tool_bar (f);
+ #endif
+     }
+ 
+   /* We go to this label, with fonts_changed_p nonzero,
+      if it is necessary to try again using larger glyph matrices.
+      We have to redeem the scroll bar even in this case,
+      because the loop in redisplay_internal expects that.  */
+  need_larger_matrices:
+   ;
+  finish_scroll_bars:
+ 
+   if (WINDOW_HAS_VERTICAL_SCROLL_BAR (w))
+     {
+       /* Set the thumb's position and size.  */
+       set_vertical_scroll_bar (w);
+ 
+       /* Note that we actually used the scroll bar attached to this
+        window, so it shouldn't be deleted at the end of redisplay.  */
+       redeem_scroll_bar_hook (w);
+     }
+ 
+   /* Restore current_buffer and value of point in it.  */
+   TEMP_SET_PT_BOTH (CHARPOS (opoint), BYTEPOS (opoint));
+   set_buffer_internal_1 (old);
+   TEMP_SET_PT_BOTH (CHARPOS (lpoint), BYTEPOS (lpoint));
+ 
+   unbind_to (count, Qnil);
+ }
+ 
+ 
+ /* 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.  */
+ 
+ int
+ try_window (window, pos)
+      Lisp_Object window;
+      struct text_pos pos;
+ {
+   struct window *w = XWINDOW (window);
+   struct it it;
+   struct glyph_row *last_text_row = NULL;
+ 
+   /* Make POS the new window start.  */
+   set_marker_both (w->start, Qnil, CHARPOS (pos), BYTEPOS (pos));
+ 
+   /* Mark cursor position as unknown.  No overlay arrow seen.  */
+   w->cursor.vpos = -1;
+   overlay_arrow_seen = 0;
+ 
+   /* Initialize iterator and info to start at POS.  */
+   start_display (&it, w, pos);
+ 
+   /* Display all lines of W.  */
+   while (it.current_y < it.last_visible_y)
+     {
+       if (display_line (&it))
+       last_text_row = it.glyph_row - 1;
+       if (fonts_changed_p)
+       return 0;
+     }
+ 
+   /* If bottom moved off end of frame, change mode line percentage.  */
+   if (XFASTINT (w->window_end_pos) <= 0
+       && Z != IT_CHARPOS (it))
+     w->update_mode_line = Qt;
+ 
+   /* Set window_end_pos to the offset of the last character displayed
+      on the window from the end of current_buffer.  Set
+      window_end_vpos to its row number.  */
+   if (last_text_row)
+     {
+       xassert (MATRIX_ROW_DISPLAYS_TEXT_P (last_text_row));
+       w->window_end_bytepos
+       = Z_BYTE - MATRIX_ROW_END_BYTEPOS (last_text_row);
+       w->window_end_pos
+       = make_number (Z - MATRIX_ROW_END_CHARPOS (last_text_row));
+       w->window_end_vpos
+       = make_number (MATRIX_ROW_VPOS (last_text_row, w->desired_matrix));
+       xassert (MATRIX_ROW (w->desired_matrix, XFASTINT (w->window_end_vpos))
+              ->displays_text_p);
+     }
+   else
+     {
+       w->window_end_bytepos = Z_BYTE - ZV_BYTE;
+       w->window_end_pos = make_number (Z - ZV);
+       w->window_end_vpos = make_number (0);
+     }
+ 
+   /* But that is not valid info until redisplay finishes.  */
+   w->window_end_valid = Qnil;
+   return 1;
+ }
+ 
+ 
+ 
+ /************************************************************************
+     Window redisplay reusing current matrix when buffer has not changed
+  ************************************************************************/
+ 
+ /* Try redisplay of window W showing an unchanged buffer with a
+    different window start than the last time it was displayed by
+    reusing its current matrix.  Value is non-zero if successful.
+    W->start is the new window start.  */
+ 
+ static int
+ try_window_reusing_current_matrix (w)
+      struct window *w;
+ {
+   struct frame *f = XFRAME (w->frame);
+   struct glyph_row *row, *bottom_row;
+   struct it it;
+   struct run run;
+   struct text_pos start, new_start;
+   int nrows_scrolled, i;
+   struct glyph_row *last_text_row;
+   struct glyph_row *last_reused_text_row;
+   struct glyph_row *start_row;
+   int start_vpos, min_y, max_y;
+ 
+ #if GLYPH_DEBUG
+   if (inhibit_try_window_reusing)
+     return 0;
+ #endif
+ 
+   if (/* This function doesn't handle terminal frames.  */
+       !FRAME_WINDOW_P (f)
+       /* Don't try to reuse the display if windows have been split
+        or such.  */
+       || windows_or_buffers_changed
+       || cursor_type_changed)
+     return 0;
+ 
+   /* Can't do this if region may have changed.  */
+   if ((!NILP (Vtransient_mark_mode)
+        && !NILP (current_buffer->mark_active))
+       || !NILP (w->region_showing)
+       || !NILP (Vshow_trailing_whitespace))
+     return 0;
+ 
+   /* If top-line visibility has changed, give up.  */
+   if (WINDOW_WANTS_HEADER_LINE_P (w)
+       != MATRIX_HEADER_LINE_ROW (w->current_matrix)->mode_line_p)
+     return 0;
+ 
+   /* Give up if old or new display is scrolled vertically.  We could
+      make this function handle this, but right now it doesn't.  */
+   start_row = MATRIX_FIRST_TEXT_ROW (w->current_matrix);
+   if (w->vscroll || MATRIX_ROW_PARTIALLY_VISIBLE_P (start_row))
+     return 0;
+ 
+   /* The variable new_start now holds the new window start.  The old
+      start `start' can be determined from the current matrix.  */
+   SET_TEXT_POS_FROM_MARKER (new_start, w->start);
+   start = start_row->start.pos;
+   start_vpos = MATRIX_ROW_VPOS (start_row, w->current_matrix);
+ 
+   /* Clear the desired matrix for the display below.  */
+   clear_glyph_matrix (w->desired_matrix);
+ 
+   if (CHARPOS (new_start) <= CHARPOS (start))
+     {
+       int first_row_y;
+ 
+       /* Don't use this method if the display starts with an ellipsis
+        displayed for invisible text.  It's not easy to handle that case
+        below, and it's certainly not worth the effort since this is
+        not a frequent case.  */
+       if (in_ellipses_for_invisible_text_p (&start_row->start, w))
+       return 0;
+ 
+       IF_DEBUG (debug_method_add (w, "twu1"));
+ 
+       /* Display up to a row that can be reused.  The variable
+        last_text_row is set to the last row displayed that displays
+        text.  Note that it.vpos == 0 if or if not there is a
+          header-line; it's not the same as the MATRIX_ROW_VPOS!  */
+       start_display (&it, w, new_start);
+       first_row_y = it.current_y;
+       w->cursor.vpos = -1;
+       last_text_row = last_reused_text_row = NULL;
+ 
+       while (it.current_y < it.last_visible_y
+            && IT_CHARPOS (it) < CHARPOS (start)
+            && !fonts_changed_p)
+       if (display_line (&it))
+         last_text_row = it.glyph_row - 1;
+ 
+       /* A value of current_y < last_visible_y means that we stopped
+        at the previous window start, which in turn means that we
+        have at least one reusable row.  */
+       if (it.current_y < it.last_visible_y)
+       {
+         /* IT.vpos always starts from 0; it counts text lines.  */
+         nrows_scrolled = it.vpos;
+ 
+         /* Find PT if not already found in the lines displayed.  */
+         if (w->cursor.vpos < 0)
+           {
+             int dy = it.current_y - first_row_y;
+ 
+             row = MATRIX_FIRST_TEXT_ROW (w->current_matrix);
+             row = row_containing_pos (w, PT, row, NULL, dy);
+             if (row)
+               set_cursor_from_row (w, row, w->current_matrix, 0, 0,
+                                    dy, nrows_scrolled);
+             else
+               {
+                 clear_glyph_matrix (w->desired_matrix);
+                 return 0;
+               }
+           }
+ 
+         /* Scroll the display.  Do it before the current matrix is
+            changed.  The problem here is that update has not yet
+            run, i.e. part of the current matrix is not up to date.
+            scroll_run_hook will clear the cursor, and use the
+            current matrix to get the height of the row the cursor is
+            in.  */
+         run.current_y = first_row_y;
+         run.desired_y = it.current_y;
+         run.height = it.last_visible_y - it.current_y;
+ 
+         if (run.height > 0 && run.current_y != run.desired_y)
+           {
+             update_begin (f);
+             rif->update_window_begin_hook (w);
+             rif->clear_window_mouse_face (w);
+             rif->scroll_run_hook (w, &run);
+             rif->update_window_end_hook (w, 0, 0);
+             update_end (f);
+           }
+ 
+         /* Shift current matrix down by nrows_scrolled lines.  */
+         bottom_row = MATRIX_BOTTOM_TEXT_ROW (w->current_matrix, w);
+         rotate_matrix (w->current_matrix,
+                        start_vpos,
+                        MATRIX_ROW_VPOS (bottom_row, w->current_matrix),
+                        nrows_scrolled);
+ 
+         /* Disable lines that must be updated.  */
+         for (i = 0; i < it.vpos; ++i)
+           (start_row + i)->enabled_p = 0;
+ 
+         /* Re-compute Y positions.  */
+         min_y = WINDOW_HEADER_LINE_HEIGHT (w);
+         max_y = it.last_visible_y;
+         for (row = start_row + nrows_scrolled;
+              row < bottom_row;
+              ++row)
+           {
+             row->y = it.current_y;
+             row->visible_height = row->height;
+ 
+             if (row->y < min_y)
+               row->visible_height -= min_y - row->y;
+             if (row->y + row->height > max_y)
+               row->visible_height -= row->y + row->height - max_y;
+ 
+             it.current_y += row->height;
+ 
+             if (MATRIX_ROW_DISPLAYS_TEXT_P (row))
+               last_reused_text_row = row;
+             if (MATRIX_ROW_BOTTOM_Y (row) >= it.last_visible_y)
+               break;
+           }
+ 
+         /* Disable lines in the current matrix which are now
+            below the window.  */
+         for (++row; row < bottom_row; ++row)
+           row->enabled_p = 0;
+       }
+ 
+       /* Update window_end_pos etc.; last_reused_text_row is the last
+        reused row from the current matrix containing text, if any.
+        The value of last_text_row is the last displayed line
+        containing text.  */
+       if (last_reused_text_row)
+       {
+         w->window_end_bytepos
+           = Z_BYTE - MATRIX_ROW_END_BYTEPOS (last_reused_text_row);
+         w->window_end_pos
+           = make_number (Z - MATRIX_ROW_END_CHARPOS (last_reused_text_row));
+         w->window_end_vpos
+           = make_number (MATRIX_ROW_VPOS (last_reused_text_row,
+                                           w->current_matrix));
+       }
+       else if (last_text_row)
+       {
+         w->window_end_bytepos
+           = Z_BYTE - MATRIX_ROW_END_BYTEPOS (last_text_row);
+         w->window_end_pos
+           = make_number (Z - MATRIX_ROW_END_CHARPOS (last_text_row));
+         w->window_end_vpos
+           = make_number (MATRIX_ROW_VPOS (last_text_row, w->desired_matrix));
+       }
+       else
+       {
+         /* This window must be completely empty.  */
+         w->window_end_bytepos = Z_BYTE - ZV_BYTE;
+         w->window_end_pos = make_number (Z - ZV);
+         w->window_end_vpos = make_number (0);
+       }
+       w->window_end_valid = Qnil;
+ 
+       /* Update hint: don't try scrolling again in update_window.  */
+       w->desired_matrix->no_scrolling_p = 1;
+ 
+ #if GLYPH_DEBUG
+       debug_method_add (w, "try_window_reusing_current_matrix 1");
+ #endif
+       return 1;
+     }
+   else if (CHARPOS (new_start) > CHARPOS (start))
+     {
+       struct glyph_row *pt_row, *row;
+       struct glyph_row *first_reusable_row;
+       struct glyph_row *first_row_to_display;
+       int dy;
+       int yb = window_text_bottom_y (w);
+ 
+       /* Find the row starting at new_start, if there is one.  Don't
+        reuse a partially visible line at the end.  */
+       first_reusable_row = start_row;
+       while (first_reusable_row->enabled_p
+            && MATRIX_ROW_BOTTOM_Y (first_reusable_row) < yb
+            && (MATRIX_ROW_START_CHARPOS (first_reusable_row)
+                < CHARPOS (new_start)))
+       ++first_reusable_row;
+ 
+       /* Give up if there is no row to reuse.  */
+       if (MATRIX_ROW_BOTTOM_Y (first_reusable_row) >= yb
+         || !first_reusable_row->enabled_p
+         || (MATRIX_ROW_START_CHARPOS (first_reusable_row)
+             != CHARPOS (new_start)))
+       return 0;
+ 
+       /* We can reuse fully visible rows beginning with
+          first_reusable_row to the end of the window.  Set
+          first_row_to_display to the first row that cannot be reused.
+          Set pt_row to the row containing point, if there is any.  */
+       pt_row = NULL;
+       for (first_row_to_display = first_reusable_row;
+          MATRIX_ROW_BOTTOM_Y (first_row_to_display) < yb;
+          ++first_row_to_display)
+       {
+         if (PT >= MATRIX_ROW_START_CHARPOS (first_row_to_display)
+             && PT < MATRIX_ROW_END_CHARPOS (first_row_to_display))
+           pt_row = first_row_to_display;
+       }
+ 
+       /* Start displaying at the start of first_row_to_display.  */
+       xassert (first_row_to_display->y < yb);
+       init_to_row_start (&it, w, first_row_to_display);
+ 
+       nrows_scrolled = (MATRIX_ROW_VPOS (first_reusable_row, 
w->current_matrix)
+                       - start_vpos);
+       it.vpos = (MATRIX_ROW_VPOS (first_row_to_display, w->current_matrix)
+                - nrows_scrolled);
+       it.current_y = (first_row_to_display->y - first_reusable_row->y
+                     + WINDOW_HEADER_LINE_HEIGHT (w));
+ 
+       /* Display lines beginning with first_row_to_display in the
+          desired matrix.  Set last_text_row to the last row displayed
+          that displays text.  */
+       it.glyph_row = MATRIX_ROW (w->desired_matrix, it.vpos);
+       if (pt_row == NULL)
+       w->cursor.vpos = -1;
+       last_text_row = NULL;
+       while (it.current_y < it.last_visible_y && !fonts_changed_p)
+       if (display_line (&it))
+         last_text_row = it.glyph_row - 1;
+ 
+       /* Give up If point isn't in a row displayed or reused.  */
+       if (w->cursor.vpos < 0)
+       {
+         clear_glyph_matrix (w->desired_matrix);
+         return 0;
+       }
+ 
+       /* If point is in a reused row, adjust y and vpos of the cursor
+        position.  */
+       if (pt_row)
+       {
+         w->cursor.vpos -= MATRIX_ROW_VPOS (first_reusable_row,
+                                            w->current_matrix);
+         w->cursor.y -= first_reusable_row->y;
+       }
+ 
+       /* Scroll the display.  */
+       run.current_y = first_reusable_row->y;
+       run.desired_y = WINDOW_HEADER_LINE_HEIGHT (w);
+       run.height = it.last_visible_y - run.current_y;
+       dy = run.current_y - run.desired_y;
+ 
+       if (run.height)
+       {
+         struct frame *f = XFRAME (WINDOW_FRAME (w));
+         update_begin (f);
+         rif->update_window_begin_hook (w);
+         rif->clear_window_mouse_face (w);
+         rif->scroll_run_hook (w, &run);
+         rif->update_window_end_hook (w, 0, 0);
+         update_end (f);
+       }
+ 
+       /* Adjust Y positions of reused rows.  */
+       bottom_row = MATRIX_BOTTOM_TEXT_ROW (w->current_matrix, w);
+       min_y = WINDOW_HEADER_LINE_HEIGHT (w);
+       max_y = it.last_visible_y;
+       for (row = first_reusable_row; row < first_row_to_display; ++row)
+       {
+         row->y -= dy;
+         row->visible_height = row->height;
+         if (row->y < min_y)
+           row->visible_height -= min_y - row->y;
+         if (row->y + row->height > max_y)
+           row->visible_height -= row->y + row->height - max_y;
+       }
+ 
+       /* Scroll the current matrix.  */
+       xassert (nrows_scrolled > 0);
+       rotate_matrix (w->current_matrix,
+                    start_vpos,
+                    MATRIX_ROW_VPOS (bottom_row, w->current_matrix),
+                    -nrows_scrolled);
+ 
+       /* Disable rows not reused.  */
+       for (row -= nrows_scrolled; row < bottom_row; ++row)
+       row->enabled_p = 0;
+ 
+       /* Adjust window end.  A null value of last_text_row means that
+        the window end is in reused rows which in turn means that
+        only its vpos can have changed.  */
+       if (last_text_row)
+       {
+         w->window_end_bytepos
+           = Z_BYTE - MATRIX_ROW_END_BYTEPOS (last_text_row);
+         w->window_end_pos
+           = make_number (Z - MATRIX_ROW_END_CHARPOS (last_text_row));
+         w->window_end_vpos
+           = make_number (MATRIX_ROW_VPOS (last_text_row, w->desired_matrix));
+       }
+       else
+       {
+         w->window_end_vpos
+           = make_number (XFASTINT (w->window_end_vpos) - nrows_scrolled);
+       }
+ 
+       w->window_end_valid = Qnil;
+       w->desired_matrix->no_scrolling_p = 1;
+ 
+ #if GLYPH_DEBUG
+       debug_method_add (w, "try_window_reusing_current_matrix 2");
+ #endif
+       return 1;
+     }
+ 
+   return 0;
+ }
+ 
+ 
+ 
+ /************************************************************************
+    Window redisplay reusing current matrix when buffer has changed
+  ************************************************************************/
+ 
+ static struct glyph_row *find_last_unchanged_at_beg_row P_ ((struct window 
*));
+ static struct glyph_row *find_first_unchanged_at_end_row P_ ((struct window *,
+                                                            int *, int *));
+ static struct glyph_row *
+ find_last_row_displaying_text P_ ((struct glyph_matrix *, struct it *,
+                                  struct glyph_row *));
+ 
+ 
+ /* Return the last row in MATRIX displaying text.  If row START is
+    non-null, start searching with that row.  IT gives the dimensions
+    of the display.  Value is null if matrix is empty; otherwise it is
+    a pointer to the row found.  */
+ 
+ static struct glyph_row *
+ find_last_row_displaying_text (matrix, it, start)
+      struct glyph_matrix *matrix;
+      struct it *it;
+      struct glyph_row *start;
+ {
+   struct glyph_row *row, *row_found;
+ 
+   /* Set row_found to the last row in IT->w's current matrix
+      displaying text.  The loop looks funny but think of partially
+      visible lines.  */
+   row_found = NULL;
+   row = start ? start : MATRIX_FIRST_TEXT_ROW (matrix);
+   while (MATRIX_ROW_DISPLAYS_TEXT_P (row))
+     {
+       xassert (row->enabled_p);
+       row_found = row;
+       if (MATRIX_ROW_BOTTOM_Y (row) >= it->last_visible_y)
+       break;
+       ++row;
+     }
+ 
+   return row_found;
+ }
+ 
+ 
+ /* Return the last row in the current matrix of W that is not affected
+    by changes at the start of current_buffer that occurred since W's
+    current matrix was built.  Value is null if no such row exists.
+ 
+    BEG_UNCHANGED us the number of characters unchanged at the start of
+    current_buffer.  BEG + BEG_UNCHANGED is the buffer position of the
+    first changed character in current_buffer.  Characters at positions <
+    BEG + BEG_UNCHANGED are at the same buffer positions as they were
+    when the current matrix was built.  */
+ 
+ static struct glyph_row *
+ find_last_unchanged_at_beg_row (w)
+      struct window *w;
+ {
+   int first_changed_pos = BEG + BEG_UNCHANGED;
+   struct glyph_row *row;
+   struct glyph_row *row_found = NULL;
+   int yb = window_text_bottom_y (w);
+ 
+   /* Find the last row displaying unchanged text.  */
+   row = MATRIX_FIRST_TEXT_ROW (w->current_matrix);
+   while (MATRIX_ROW_DISPLAYS_TEXT_P (row)
+        && MATRIX_ROW_START_CHARPOS (row) < first_changed_pos)
+     {
+       if (/* If row ends before first_changed_pos, it is unchanged,
+            except in some case.  */
+         MATRIX_ROW_END_CHARPOS (row) <= first_changed_pos
+         /* When row ends in ZV and we write at ZV it is not
+              unchanged.  */
+         && !row->ends_at_zv_p
+         /* When first_changed_pos is the end of a continued line,
+            row is not unchanged because it may be no longer
+            continued.  */
+         && !(MATRIX_ROW_END_CHARPOS (row) == first_changed_pos
+              && row->continued_p))
+       row_found = row;
+ 
+       /* Stop if last visible row.  */
+      if (MATRIX_ROW_BOTTOM_Y (row) >= yb)
+       break;
+ 
+       ++row;
+     }
+ 
+   return row_found;
+ }
+ 
+ 
+ /* Find the first glyph row in the current matrix of W that is not
+    affected by changes at the end of current_buffer since the
+    time W's current matrix was built.
+ 
+    Return in *DELTA the number of chars by which buffer positions in
+    unchanged text at the end of current_buffer must be adjusted.
+ 
+    Return in *DELTA_BYTES the corresponding number of bytes.
+ 
+    Value is null if no such row exists, i.e. all rows are affected by
+    changes.  */
+ 
+ static struct glyph_row *
+ find_first_unchanged_at_end_row (w, delta, delta_bytes)
+      struct window *w;
+      int *delta, *delta_bytes;
+ {
+   struct glyph_row *row;
+   struct glyph_row *row_found = NULL;
+ 
+   *delta = *delta_bytes = 0;
+ 
+   /* Display must not have been paused, otherwise the current matrix
+      is not up to date.  */
+   if (NILP (w->window_end_valid))
+     abort ();
+ 
+   /* A value of window_end_pos >= END_UNCHANGED means that the window
+      end is in the range of changed text.  If so, there is no
+      unchanged row at the end of W's current matrix.  */
+   if (XFASTINT (w->window_end_pos) >= END_UNCHANGED)
+     return NULL;
+ 
+   /* Set row to the last row in W's current matrix displaying text.  */
+   row = MATRIX_ROW (w->current_matrix, XFASTINT (w->window_end_vpos));
+ 
+   /* If matrix is entirely empty, no unchanged row exists.  */
+   if (MATRIX_ROW_DISPLAYS_TEXT_P (row))
+     {
+       /* The value of row is the last glyph row in the matrix having a
+        meaningful buffer position in it.  The end position of row
+        corresponds to window_end_pos.  This allows us to translate
+        buffer positions in the current matrix to current buffer
+        positions for characters not in changed text.  */
+       int Z_old = MATRIX_ROW_END_CHARPOS (row) + XFASTINT (w->window_end_pos);
+       int Z_BYTE_old = MATRIX_ROW_END_BYTEPOS (row) + w->window_end_bytepos;
+       int last_unchanged_pos, last_unchanged_pos_old;
+       struct glyph_row *first_text_row
+       = MATRIX_FIRST_TEXT_ROW (w->current_matrix);
+ 
+       *delta = Z - Z_old;
+       *delta_bytes = Z_BYTE - Z_BYTE_old;
+ 
+       /* Set last_unchanged_pos to the buffer position of the last
+        character in the buffer that has not been changed.  Z is the
+        index + 1 of the last character in current_buffer, i.e. by
+        subtracting END_UNCHANGED we get the index of the last
+        unchanged character, and we have to add BEG to get its buffer
+        position.  */
+       last_unchanged_pos = Z - END_UNCHANGED + BEG;
+       last_unchanged_pos_old = last_unchanged_pos - *delta;
+ 
+       /* Search backward from ROW for a row displaying a line that
+        starts at a minimum position >= last_unchanged_pos_old.  */
+       for (; row > first_text_row; --row)
+       {
+         if (!row->enabled_p || !MATRIX_ROW_DISPLAYS_TEXT_P (row))
+           abort ();
+ 
+         if (MATRIX_ROW_START_CHARPOS (row) >= last_unchanged_pos_old)
+           row_found = row;
+       }
+     }
+ 
+   if (row_found && !MATRIX_ROW_DISPLAYS_TEXT_P (row_found))
+     abort ();
+ 
+   return row_found;
+ }
+ 
+ 
+ /* Make sure that glyph rows in the current matrix of window W
+    reference the same glyph memory as corresponding rows in the
+    frame's frame matrix.  This function is called after scrolling W's
+    current matrix on a terminal frame in try_window_id and
+    try_window_reusing_current_matrix.  */
+ 
+ static void
+ sync_frame_with_window_matrix_rows (w)
+      struct window *w;
+ {
+   struct frame *f = XFRAME (w->frame);
+   struct glyph_row *window_row, *window_row_end, *frame_row;
+ 
+   /* Preconditions: W must be a leaf window and full-width.  Its frame
+      must have a frame matrix.  */
+   xassert (NILP (w->hchild) && NILP (w->vchild));
+   xassert (WINDOW_FULL_WIDTH_P (w));
+   xassert (!FRAME_WINDOW_P (f));
+ 
+   /* If W is a full-width window, glyph pointers in W's current matrix
+      have, by definition, to be the same as glyph pointers in the
+      corresponding frame matrix.  Note that frame matrices have no
+      marginal areas (see build_frame_matrix).  */
+   window_row = w->current_matrix->rows;
+   window_row_end = window_row + w->current_matrix->nrows;
+   frame_row = f->current_matrix->rows + WINDOW_TOP_EDGE_LINE (w);
+   while (window_row < window_row_end)
+     {
+       struct glyph *start = window_row->glyphs[LEFT_MARGIN_AREA];
+       struct glyph *end = window_row->glyphs[LAST_AREA];
+ 
+       frame_row->glyphs[LEFT_MARGIN_AREA] = start;
+       frame_row->glyphs[TEXT_AREA] = start;
+       frame_row->glyphs[RIGHT_MARGIN_AREA] = end;
+       frame_row->glyphs[LAST_AREA] = end;
+ 
+       /* Disable frame rows whose corresponding window rows have
+        been disabled in try_window_id.  */
+       if (!window_row->enabled_p)
+       frame_row->enabled_p = 0;
+ 
+       ++window_row, ++frame_row;
+     }
+ }
+ 
+ 
+ /* Find the glyph row in window W containing CHARPOS.  Consider all
+    rows between START and END (not inclusive).  END null means search
+    all rows to the end of the display area of W.  Value is the row
+    containing CHARPOS or null.  */
+ 
+ struct glyph_row *
+ row_containing_pos (w, charpos, start, end, dy)
+      struct window *w;
+      int charpos;
+      struct glyph_row *start, *end;
+      int dy;
+ {
+   struct glyph_row *row = start;
+   int last_y;
+ 
+   /* If we happen to start on a header-line, skip that.  */
+   if (row->mode_line_p)
+     ++row;
+ 
+   if ((end && row >= end) || !row->enabled_p)
+     return NULL;
+ 
+   last_y = window_text_bottom_y (w) - dy;
+ 
+   while (1)
+     {
+       /* Give up if we have gone too far.  */
+       if (end && row >= end)
+       return NULL;
+       /* This formerly returned if they were equal.
+        I think that both quantities are of a "last plus one" type;
+        if so, when they are equal, the row is within the screen. -- rms.  */
+       if (MATRIX_ROW_BOTTOM_Y (row) > last_y)
+       return NULL;
+ 
+       /* If it is in this row, return this row.  */
+       if (! (MATRIX_ROW_END_CHARPOS (row) < charpos
+            || (MATRIX_ROW_END_CHARPOS (row) == charpos
+                /* The end position of a row equals the start
+                   position of the next row.  If CHARPOS is there, we
+                   would rather display it in the next line, except
+                   when this line ends in ZV.  */
+                && !row->ends_at_zv_p
+                && !MATRIX_ROW_ENDS_IN_MIDDLE_OF_CHAR_P (row)))
+         && charpos >= MATRIX_ROW_START_CHARPOS (row))
+       return row;
+       ++row;
+     }
+ }
+ 
+ 
+ /* Try to redisplay window W by reusing its existing display.  W's
+    current matrix must be up to date when this function is called,
+    i.e. window_end_valid must not be nil.
+ 
+    Value is
+ 
+    1  if display has been updated
+    0  if otherwise unsuccessful
+    -1 if redisplay with same window start is known not to succeed
+ 
+    The following steps are performed:
+ 
+    1. Find the last row in the current matrix of W that is not
+    affected by changes at the start of current_buffer.  If no such row
+    is found, give up.
+ 
+    2. Find the first row in W's current matrix that is not affected by
+    changes at the end of current_buffer.  Maybe there is no such row.
+ 
+    3. Display lines beginning with the row + 1 found in step 1 to the
+    row found in step 2 or, if step 2 didn't find a row, to the end of
+    the window.
+ 
+    4. If cursor is not known to appear on the window, give up.
+ 
+    5. If display stopped at the row found in step 2, scroll the
+    display and current matrix as needed.
+ 
+    6. Maybe display some lines at the end of W, if we must.  This can
+    happen under various circumstances, like a partially visible line
+    becoming fully visible, or because newly displayed lines are displayed
+    in smaller font sizes.
+ 
+    7. Update W's window end information.  */
+ 
+ static int
+ try_window_id (w)
+      struct window *w;
+ {
+   struct frame *f = XFRAME (w->frame);
+   struct glyph_matrix *current_matrix = w->current_matrix;
+   struct glyph_matrix *desired_matrix = w->desired_matrix;
+   struct glyph_row *last_unchanged_at_beg_row;
+   struct glyph_row *first_unchanged_at_end_row;
+   struct glyph_row *row;
+   struct glyph_row *bottom_row;
+   int bottom_vpos;
+   struct it it;
+   int delta = 0, delta_bytes = 0, stop_pos, dvpos, dy;
+   struct text_pos start_pos;
+   struct run run;
+   int first_unchanged_at_end_vpos = 0;
+   struct glyph_row *last_text_row, *last_text_row_at_end;
+   struct text_pos start;
+   int first_changed_charpos, last_changed_charpos;
+ 
+ #if GLYPH_DEBUG
+   if (inhibit_try_window_id)
+     return 0;
+ #endif
+ 
+   /* This is handy for debugging.  */
+ #if 0
+ #define GIVE_UP(X)                                            \
+   do {                                                                \
+     fprintf (stderr, "try_window_id give up %d\n", (X));      \
+     return 0;                                                 \
+   } while (0)
+ #else
+ #define GIVE_UP(X) return 0
+ #endif
+ 
+   SET_TEXT_POS_FROM_MARKER (start, w->start);
+ 
+   /* Don't use this for mini-windows because these can show
+      messages and mini-buffers, and we don't handle that here.  */
+   if (MINI_WINDOW_P (w))
+     GIVE_UP (1);
+ 
+   /* This flag is used to prevent redisplay optimizations.  */
+   if (windows_or_buffers_changed || cursor_type_changed)
+     GIVE_UP (2);
+ 
+   /* Verify that narrowing has not changed.
+      Also verify that we were not told to prevent redisplay optimizations.
+      It would be nice to further
+      reduce the number of cases where this prevents try_window_id.  */
+   if (current_buffer->clip_changed
+       || current_buffer->prevent_redisplay_optimizations_p)
+     GIVE_UP (3);
+ 
+   /* Window must either use window-based redisplay or be full width.  */
+   if (!FRAME_WINDOW_P (f)
+       && (!line_ins_del_ok
+         || !WINDOW_FULL_WIDTH_P (w)))
+     GIVE_UP (4);
+ 
+   /* Give up if point is not known NOT to appear in W.  */
+   if (PT < CHARPOS (start))
+     GIVE_UP (5);
+ 
+   /* Another way to prevent redisplay optimizations.  */
+   if (XFASTINT (w->last_modified) == 0)
+     GIVE_UP (6);
+ 
+   /* Verify that window is not hscrolled.  */
+   if (XFASTINT (w->hscroll) != 0)
+     GIVE_UP (7);
+ 
+   /* Verify that display wasn't paused.  */
+   if (NILP (w->window_end_valid))
+     GIVE_UP (8);
+ 
+   /* Can't use this if highlighting a region because a cursor movement
+      will do more than just set the cursor.  */
+   if (!NILP (Vtransient_mark_mode)
+       && !NILP (current_buffer->mark_active))
+     GIVE_UP (9);
+ 
+   /* Likewise if highlighting trailing whitespace.  */
+   if (!NILP (Vshow_trailing_whitespace))
+     GIVE_UP (11);
+ 
+   /* Likewise if showing a region.  */
+   if (!NILP (w->region_showing))
+     GIVE_UP (10);
+ 
+   /* Can use this if overlay arrow position and or string have changed.  */
+   if (!EQ (last_arrow_position, COERCE_MARKER (Voverlay_arrow_position))
+       || !EQ (last_arrow_string, Voverlay_arrow_string))
+     GIVE_UP (12);
+ 
+ 
+   /* Make sure beg_unchanged and end_unchanged are up to date.  Do it
+      only if buffer has really changed.  The reason is that the gap is
+      initially at Z for freshly visited files.  The code below would
+      set end_unchanged to 0 in that case.  */
+   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;
+     }
+ 
+   /* The position of the first and last character that has been changed.  */
+   first_changed_charpos = BEG + BEG_UNCHANGED;
+   last_changed_charpos  = Z - END_UNCHANGED;
+ 
+   /* If window starts after a line end, and the last change is in
+      front of that newline, then changes don't affect the display.
+      This case happens with stealth-fontification.  Note that although
+      the display is unchanged, glyph positions in the matrix have to
+      be adjusted, of course.  */
+   row = MATRIX_ROW (w->current_matrix, XFASTINT (w->window_end_vpos));
+   if (MATRIX_ROW_DISPLAYS_TEXT_P (row)
+       && ((last_changed_charpos < CHARPOS (start)
+          && CHARPOS (start) == BEGV)
+         || (last_changed_charpos < CHARPOS (start) - 1
+             && FETCH_BYTE (BYTEPOS (start) - 1) == '\n')))
+     {
+       int Z_old, delta, Z_BYTE_old, delta_bytes;
+       struct glyph_row *r0;
+ 
+       /* Compute how many chars/bytes have been added to or removed
+        from the buffer.  */
+       Z_old = MATRIX_ROW_END_CHARPOS (row) + XFASTINT (w->window_end_pos);
+       Z_BYTE_old = MATRIX_ROW_END_BYTEPOS (row) + w->window_end_bytepos;
+       delta = Z - Z_old;
+       delta_bytes = Z_BYTE - Z_BYTE_old;
+ 
+       /* Give up if PT is not in the window.  Note that it already has
+        been checked at the start of try_window_id that PT is not in
+        front of the window start.  */
+       if (PT >= MATRIX_ROW_END_CHARPOS (row) + delta)
+       GIVE_UP (13);
+ 
+       /* If window start is unchanged, we can reuse the whole matrix
+        as is, after adjusting glyph positions.  No need to compute
+        the window end again, since its offset from Z hasn't changed.  */
+       r0 = MATRIX_FIRST_TEXT_ROW (current_matrix);
+       if (CHARPOS (start) == MATRIX_ROW_START_CHARPOS (r0) + delta
+         && BYTEPOS (start) == MATRIX_ROW_START_BYTEPOS (r0) + delta_bytes
+         /* PT must not be in a partially visible line.  */
+         && !(PT >= MATRIX_ROW_START_CHARPOS (row) + delta
+              && MATRIX_ROW_BOTTOM_Y (row) > window_text_bottom_y (w)))
+       {
+         /* Adjust positions in the glyph matrix.  */
+         if (delta || delta_bytes)
+           {
+             struct glyph_row *r1
+               = MATRIX_BOTTOM_TEXT_ROW (current_matrix, w);
+             increment_matrix_positions (w->current_matrix,
+                                         MATRIX_ROW_VPOS (r0, current_matrix),
+                                         MATRIX_ROW_VPOS (r1, current_matrix),
+                                         delta, delta_bytes);
+           }
+ 
+         /* Set the cursor.  */
+         row = row_containing_pos (w, PT, r0, NULL, 0);
+         if (row)
+           set_cursor_from_row (w, row, current_matrix, 0, 0, 0, 0);
+         else
+           abort ();
+         return 1;
+       }
+     }
+ 
+   /* Handle the case that changes are all below what is displayed in
+      the window, and that PT is in the window.  This shortcut cannot
+      be taken if ZV is visible in the window, and text has been added
+      there that is visible in the window.  */
+   if (first_changed_charpos >= MATRIX_ROW_END_CHARPOS (row)
+       /* ZV is not visible in the window, or there are no
+        changes at ZV, actually.  */
+       && (current_matrix->zv > MATRIX_ROW_END_CHARPOS (row)
+         || first_changed_charpos == last_changed_charpos))
+     {
+       struct glyph_row *r0;
+ 
+       /* Give up if PT is not in the window.  Note that it already has
+        been checked at the start of try_window_id that PT is not in
+        front of the window start.  */
+       if (PT >= MATRIX_ROW_END_CHARPOS (row))
+       GIVE_UP (14);
+ 
+       /* If window start is unchanged, we can reuse the whole matrix
+        as is, without changing glyph positions since no text has
+        been added/removed in front of the window end.  */
+       r0 = MATRIX_FIRST_TEXT_ROW (current_matrix);
+       if (TEXT_POS_EQUAL_P (start, r0->start.pos)
+         /* PT must not be in a partially visible line.  */
+         && !(PT >= MATRIX_ROW_START_CHARPOS (row)
+              && MATRIX_ROW_BOTTOM_Y (row) > window_text_bottom_y (w)))
+       {
+         /* We have to compute the window end anew since text
+            can have been added/removed after it.  */
+         w->window_end_pos
+           = make_number (Z - MATRIX_ROW_END_CHARPOS (row));
+         w->window_end_bytepos
+           = Z_BYTE - MATRIX_ROW_END_BYTEPOS (row);
+ 
+         /* Set the cursor.  */
+         row = row_containing_pos (w, PT, r0, NULL, 0);
+         if (row)
+           set_cursor_from_row (w, row, current_matrix, 0, 0, 0, 0);
+         else
+           abort ();
+         return 2;
+       }
+     }
+ 
+   /* Give up if window start is in the changed area.
+ 
+      The condition used to read
+ 
+      (BEG_UNCHANGED + END_UNCHANGED != Z - BEG && ...)
+ 
+      but why that was tested escapes me at the moment.  */
+   if (CHARPOS (start) >= first_changed_charpos
+       && CHARPOS (start) <= last_changed_charpos)
+     GIVE_UP (15);
+ 
+   /* Check that window start agrees with the start of the first glyph
+      row in its current matrix.  Check this after we know the window
+      start is not in changed text, otherwise positions would not be
+      comparable.  */
+   row = MATRIX_FIRST_TEXT_ROW (current_matrix);
+   if (!TEXT_POS_EQUAL_P (start, row->start.pos))
+     GIVE_UP (16);
+ 
+   /* Give up if the window ends in strings.  Overlay strings
+      at the end are difficult to handle, so don't try.  */
+   row = MATRIX_ROW (current_matrix, XFASTINT (w->window_end_vpos));
+   if (MATRIX_ROW_START_CHARPOS (row) == MATRIX_ROW_END_CHARPOS (row))
+     GIVE_UP (20);
+ 
+   /* Compute the position at which we have to start displaying new
+      lines.  Some of the lines at the top of the window might be
+      reusable because they are not displaying changed text.  Find the
+      last row in W's current matrix not affected by changes at the
+      start of current_buffer.  Value is null if changes start in the
+      first line of window.  */
+   last_unchanged_at_beg_row = find_last_unchanged_at_beg_row (w);
+   if (last_unchanged_at_beg_row)
+     {
+       /* Avoid starting to display in the moddle of a character, a TAB
+        for instance.  This is easier than to set up the iterator
+        exactly, and it's not a frequent case, so the additional
+        effort wouldn't really pay off.  */
+       while ((MATRIX_ROW_ENDS_IN_MIDDLE_OF_CHAR_P (last_unchanged_at_beg_row)
+             || last_unchanged_at_beg_row->ends_in_newline_from_string_p)
+            && last_unchanged_at_beg_row > w->current_matrix->rows)
+       --last_unchanged_at_beg_row;
+ 
+       if (MATRIX_ROW_ENDS_IN_MIDDLE_OF_CHAR_P (last_unchanged_at_beg_row))
+       GIVE_UP (17);
+ 
+       if (init_to_row_end (&it, w, last_unchanged_at_beg_row) == 0)
+       GIVE_UP (18);
+       start_pos = it.current.pos;
+ 
+       /* Start displaying new lines in the desired matrix at the same
+        vpos we would use in the current matrix, i.e. below
+        last_unchanged_at_beg_row.  */
+       it.vpos = 1 + MATRIX_ROW_VPOS (last_unchanged_at_beg_row,
+                                    current_matrix);
+       it.glyph_row = MATRIX_ROW (desired_matrix, it.vpos);
+       it.current_y = MATRIX_ROW_BOTTOM_Y (last_unchanged_at_beg_row);
+ 
+       xassert (it.hpos == 0 && it.current_x == 0);
+     }
+   else
+     {
+       /* There are no reusable lines at the start of the window.
+        Start displaying in the first line.  */
+       start_display (&it, w, start);
+       start_pos = it.current.pos;
+     }
+ 
+   /* Find the first row that is not affected by changes at the end of
+      the buffer.  Value will be null if there is no unchanged row, in
+      which case we must redisplay to the end of the window.  delta
+      will be set to the value by which buffer positions beginning with
+      first_unchanged_at_end_row have to be adjusted due to text
+      changes.  */
+   first_unchanged_at_end_row
+     = find_first_unchanged_at_end_row (w, &delta, &delta_bytes);
+   IF_DEBUG (debug_delta = delta);
+   IF_DEBUG (debug_delta_bytes = delta_bytes);
+ 
+   /* Set stop_pos to the buffer position up to which we will have to
+      display new lines.  If first_unchanged_at_end_row != NULL, this
+      is the buffer position of the start of the line displayed in that
+      row.  For first_unchanged_at_end_row == NULL, use 0 to indicate
+      that we don't stop at a buffer position.  */
+   stop_pos = 0;
+   if (first_unchanged_at_end_row)
+     {
+       xassert (last_unchanged_at_beg_row == NULL
+              || first_unchanged_at_end_row >= last_unchanged_at_beg_row);
+ 
+       /* If this is a continuation line, move forward to the next one
+        that isn't.  Changes in lines above affect this line.
+        Caution: this may move first_unchanged_at_end_row to a row
+        not displaying text.  */
+       while (MATRIX_ROW_CONTINUATION_LINE_P (first_unchanged_at_end_row)
+            && MATRIX_ROW_DISPLAYS_TEXT_P (first_unchanged_at_end_row)
+            && (MATRIX_ROW_BOTTOM_Y (first_unchanged_at_end_row)
+                < it.last_visible_y))
+       ++first_unchanged_at_end_row;
+ 
+       if (!MATRIX_ROW_DISPLAYS_TEXT_P (first_unchanged_at_end_row)
+         || (MATRIX_ROW_BOTTOM_Y (first_unchanged_at_end_row)
+             >= it.last_visible_y))
+       first_unchanged_at_end_row = NULL;
+       else
+       {
+         stop_pos = (MATRIX_ROW_START_CHARPOS (first_unchanged_at_end_row)
+                     + delta);
+         first_unchanged_at_end_vpos
+           = MATRIX_ROW_VPOS (first_unchanged_at_end_row, current_matrix);
+         xassert (stop_pos >= Z - END_UNCHANGED);
+       }
+     }
+   else if (last_unchanged_at_beg_row == NULL)
+     GIVE_UP (19);
+ 
+ 
+ #if GLYPH_DEBUG
+ 
+   /* Either there is no unchanged row at the end, or the one we have
+      now displays text.  This is a necessary condition for the window
+      end pos calculation at the end of this function.  */
+   xassert (first_unchanged_at_end_row == NULL
+          || MATRIX_ROW_DISPLAYS_TEXT_P (first_unchanged_at_end_row));
+ 
+   debug_last_unchanged_at_beg_vpos
+     = (last_unchanged_at_beg_row
+        ? MATRIX_ROW_VPOS (last_unchanged_at_beg_row, current_matrix)
+        : -1);
+   debug_first_unchanged_at_end_vpos = first_unchanged_at_end_vpos;
+ 
+ #endif /* GLYPH_DEBUG != 0 */
+ 
+ 
+   /* Display new lines.  Set last_text_row to the last new line
+      displayed which has text on it, i.e. might end up as being the
+      line where the window_end_vpos is.  */
+   w->cursor.vpos = -1;
+   last_text_row = NULL;
+   overlay_arrow_seen = 0;
+   while (it.current_y < it.last_visible_y
+        && !fonts_changed_p
+        && (first_unchanged_at_end_row == NULL
+            || IT_CHARPOS (it) < stop_pos))
+     {
+       if (display_line (&it))
+       last_text_row = it.glyph_row - 1;
+     }
+ 
+   if (fonts_changed_p)
+     return -1;
+ 
+ 
+   /* Compute differences in buffer positions, y-positions etc.  for
+      lines reused at the bottom of the window.  Compute what we can
+      scroll.  */
+   if (first_unchanged_at_end_row
+       /* No lines reused because we displayed everything up to the
+          bottom of the window.  */
+       && it.current_y < it.last_visible_y)
+     {
+       dvpos = (it.vpos
+              - MATRIX_ROW_VPOS (first_unchanged_at_end_row,
+                                 current_matrix));
+       dy = it.current_y - first_unchanged_at_end_row->y;
+       run.current_y = first_unchanged_at_end_row->y;
+       run.desired_y = run.current_y + dy;
+       run.height = it.last_visible_y - max (run.current_y, run.desired_y);
+     }
+   else
+     {
+       delta = dvpos = dy = run.current_y = run.desired_y = run.height = 0;
+       first_unchanged_at_end_row = NULL;
+     }
+   IF_DEBUG (debug_dvpos = dvpos; debug_dy = dy);
+ 
+ 
+   /* Find the cursor if not already found.  We have to decide whether
+      PT will appear on this window (it sometimes doesn't, but this is
+      not a very frequent case.)  This decision has to be made before
+      the current matrix is altered.  A value of cursor.vpos < 0 means
+      that PT is either in one of the lines beginning at
+      first_unchanged_at_end_row or below the window.  Don't care for
+      lines that might be displayed later at the window end; as
+      mentioned, this is not a frequent case.  */
+   if (w->cursor.vpos < 0)
+     {
+       /* Cursor in unchanged rows at the top?  */
+       if (PT < CHARPOS (start_pos)
+         && last_unchanged_at_beg_row)
+       {
+         row = row_containing_pos (w, PT,
+                                   MATRIX_FIRST_TEXT_ROW (w->current_matrix),
+                                   last_unchanged_at_beg_row + 1, 0);
+         if (row)
+           set_cursor_from_row (w, row, w->current_matrix, 0, 0, 0, 0);
+       }
+ 
+       /* Start from first_unchanged_at_end_row looking for PT.  */
+       else if (first_unchanged_at_end_row)
+       {
+         row = row_containing_pos (w, PT - delta,
+                                   first_unchanged_at_end_row, NULL, 0);
+         if (row)
+           set_cursor_from_row (w, row, w->current_matrix, delta,
+                                delta_bytes, dy, dvpos);
+       }
+ 
+       /* Give up if cursor was not found.  */
+       if (w->cursor.vpos < 0)
+       {
+         clear_glyph_matrix (w->desired_matrix);
+         return -1;
+       }
+     }
+ 
+   /* Don't let the cursor end in the scroll margins.  */
+   {
+     int this_scroll_margin, cursor_height;
+ 
+     this_scroll_margin = max (0, scroll_margin);
+     this_scroll_margin = min (this_scroll_margin, WINDOW_TOTAL_LINES (w) / 4);
+     this_scroll_margin *= FRAME_LINE_HEIGHT (it.f);
+     cursor_height = MATRIX_ROW (w->desired_matrix, w->cursor.vpos)->height;
+ 
+     if ((w->cursor.y < this_scroll_margin
+        && CHARPOS (start) > BEGV)
+       /* Don't take scroll margin into account at the bottom because
+          old redisplay didn't do it either.  */
+       || w->cursor.y + cursor_height > it.last_visible_y)
+       {
+       w->cursor.vpos = -1;
+       clear_glyph_matrix (w->desired_matrix);
+       return -1;
+       }
+   }
+ 
+   /* Scroll the display.  Do it before changing the current matrix so
+      that xterm.c doesn't get confused about where the cursor glyph is
+      found.  */
+   if (dy && run.height)
+     {
+       update_begin (f);
+ 
+       if (FRAME_WINDOW_P (f))
+       {
+         rif->update_window_begin_hook (w);
+         rif->clear_window_mouse_face (w);
+         rif->scroll_run_hook (w, &run);
+         rif->update_window_end_hook (w, 0, 0);
+       }
+       else
+       {
+         /* Terminal frame.  In this case, dvpos gives the number of
+            lines to scroll by; dvpos < 0 means scroll up.  */
+         int first_unchanged_at_end_vpos
+           = MATRIX_ROW_VPOS (first_unchanged_at_end_row, w->current_matrix);
+         int from = WINDOW_TOP_EDGE_LINE (w) + first_unchanged_at_end_vpos;
+         int end = (WINDOW_TOP_EDGE_LINE (w)
+                    + (WINDOW_WANTS_HEADER_LINE_P (w) ? 1 : 0)
+                    + window_internal_height (w));
+ 
+         /* Perform the operation on the screen.  */
+         if (dvpos > 0)
+           {
+             /* Scroll last_unchanged_at_beg_row to the end of the
+                window down dvpos lines.  */
+             set_terminal_window (end);
+ 
+             /* On dumb terminals delete dvpos lines at the end
+                before inserting dvpos empty lines.  */
+             if (!scroll_region_ok)
+               ins_del_lines (end - dvpos, -dvpos);
+ 
+             /* Insert dvpos empty lines in front of
+                  last_unchanged_at_beg_row.  */
+             ins_del_lines (from, dvpos);
+           }
+         else if (dvpos < 0)
+           {
+             /* Scroll up last_unchanged_at_beg_vpos to the end of
+                the window to last_unchanged_at_beg_vpos - |dvpos|.  */
+             set_terminal_window (end);
+ 
+             /* Delete dvpos lines in front of
+                last_unchanged_at_beg_vpos.  ins_del_lines will set
+                the cursor to the given vpos and emit |dvpos| delete
+                line sequences.  */
+             ins_del_lines (from + dvpos, dvpos);
+ 
+             /* On a dumb terminal insert dvpos empty lines at the
+                  end.  */
+             if (!scroll_region_ok)
+               ins_del_lines (end + dvpos, -dvpos);
+           }
+ 
+         set_terminal_window (0);
+       }
+ 
+       update_end (f);
+     }
+ 
+   /* Shift reused rows of the current matrix to the right position.
+      BOTTOM_ROW is the last + 1 row in the current matrix reserved for
+      text.  */
+   bottom_row = MATRIX_BOTTOM_TEXT_ROW (current_matrix, w);
+   bottom_vpos = MATRIX_ROW_VPOS (bottom_row, current_matrix);
+   if (dvpos < 0)
+     {
+       rotate_matrix (current_matrix, first_unchanged_at_end_vpos + dvpos,
+                    bottom_vpos, dvpos);
+       enable_glyph_matrix_rows (current_matrix, bottom_vpos + dvpos,
+                               bottom_vpos, 0);
+     }
+   else if (dvpos > 0)
+     {
+       rotate_matrix (current_matrix, first_unchanged_at_end_vpos,
+                    bottom_vpos, dvpos);
+       enable_glyph_matrix_rows (current_matrix, first_unchanged_at_end_vpos,
+                               first_unchanged_at_end_vpos + dvpos, 0);
+     }
+ 
+   /* For frame-based redisplay, make sure that current frame and window
+      matrix are in sync with respect to glyph memory.  */
+   if (!FRAME_WINDOW_P (f))
+     sync_frame_with_window_matrix_rows (w);
+ 
+   /* Adjust buffer positions in reused rows.  */
+   if (delta)
+     increment_matrix_positions (current_matrix,
+                               first_unchanged_at_end_vpos + dvpos,
+                               bottom_vpos, delta, delta_bytes);
+ 
+   /* Adjust Y positions.  */
+   if (dy)
+     shift_glyph_matrix (w, current_matrix,
+                       first_unchanged_at_end_vpos + dvpos,
+                       bottom_vpos, dy);
+ 
+   if (first_unchanged_at_end_row)
+     first_unchanged_at_end_row += dvpos;
+ 
+   /* If scrolling up, there may be some lines to display at the end of
+      the window.  */
+   last_text_row_at_end = NULL;
+   if (dy < 0)
+     {
+       /* Scrolling up can leave for example a partially visible line
+        at the end of the window to be redisplayed.  */
+       /* Set last_row to the glyph row in the current matrix where the
+        window end line is found.  It has been moved up or down in
+        the matrix by dvpos.  */
+       int last_vpos = XFASTINT (w->window_end_vpos) + dvpos;
+       struct glyph_row *last_row = MATRIX_ROW (current_matrix, last_vpos);
+ 
+       /* If last_row is the window end line, it should display text.  */
+       xassert (last_row->displays_text_p);
+ 
+       /* If window end line was partially visible before, begin
+        displaying at that line.  Otherwise begin displaying with the
+        line following it.  */
+       if (MATRIX_ROW_BOTTOM_Y (last_row) - dy >= it.last_visible_y)
+       {
+         init_to_row_start (&it, w, last_row);
+         it.vpos = last_vpos;
+         it.current_y = last_row->y;
+       }
+       else
+       {
+         init_to_row_end (&it, w, last_row);
+         it.vpos = 1 + last_vpos;
+         it.current_y = MATRIX_ROW_BOTTOM_Y (last_row);
+         ++last_row;
+       }
+ 
+       /* We may start in a continuation line.  If so, we have to
+        get the right continuation_lines_width and current_x.  */
+       it.continuation_lines_width = last_row->continuation_lines_width;
+       it.hpos = it.current_x = 0;
+ 
+       /* Display the rest of the lines at the window end.  */
+       it.glyph_row = MATRIX_ROW (desired_matrix, it.vpos);
+       while (it.current_y < it.last_visible_y
+            && !fonts_changed_p)
+       {
+         /* Is it always sure that the display agrees with lines in
+            the current matrix?  I don't think so, so we mark rows
+            displayed invalid in the current matrix by setting their
+            enabled_p flag to zero.  */
+         MATRIX_ROW (w->current_matrix, it.vpos)->enabled_p = 0;
+         if (display_line (&it))
+           last_text_row_at_end = it.glyph_row - 1;
+       }
+     }
+ 
+   /* Update window_end_pos and window_end_vpos.  */
+   if (first_unchanged_at_end_row
+       && first_unchanged_at_end_row->y < it.last_visible_y
+       && !last_text_row_at_end)
+     {
+       /* Window end line if one of the preserved rows from the current
+        matrix.  Set row to the last row displaying text in current
+        matrix starting at first_unchanged_at_end_row, after
+        scrolling.  */
+       xassert (first_unchanged_at_end_row->displays_text_p);
+       row = find_last_row_displaying_text (w->current_matrix, &it,
+                                          first_unchanged_at_end_row);
+       xassert (row && MATRIX_ROW_DISPLAYS_TEXT_P (row));
+ 
+       w->window_end_pos = make_number (Z - MATRIX_ROW_END_CHARPOS (row));
+       w->window_end_bytepos = Z_BYTE - MATRIX_ROW_END_BYTEPOS (row);
+       w->window_end_vpos
+       = make_number (MATRIX_ROW_VPOS (row, w->current_matrix));
+       xassert (w->window_end_bytepos >= 0);
+       IF_DEBUG (debug_method_add (w, "A"));
+     }
+   else if (last_text_row_at_end)
+     {
+       w->window_end_pos
+       = make_number (Z - MATRIX_ROW_END_CHARPOS (last_text_row_at_end));
+       w->window_end_bytepos
+       = Z_BYTE - MATRIX_ROW_END_BYTEPOS (last_text_row_at_end);
+       w->window_end_vpos
+       = make_number (MATRIX_ROW_VPOS (last_text_row_at_end, desired_matrix));
+       xassert (w->window_end_bytepos >= 0);
+       IF_DEBUG (debug_method_add (w, "B"));
+     }
+   else if (last_text_row)
+     {
+       /* We have displayed either to the end of the window or at the
+        end of the window, i.e. the last row with text is to be found
+        in the desired matrix.  */
+       w->window_end_pos
+       = make_number (Z - MATRIX_ROW_END_CHARPOS (last_text_row));
+       w->window_end_bytepos
+       = Z_BYTE - MATRIX_ROW_END_BYTEPOS (last_text_row);
+       w->window_end_vpos
+       = make_number (MATRIX_ROW_VPOS (last_text_row, desired_matrix));
+       xassert (w->window_end_bytepos >= 0);
+     }
+   else if (first_unchanged_at_end_row == NULL
+          && last_text_row == NULL
+          && last_text_row_at_end == NULL)
+     {
+       /* Displayed to end of window, but no line containing text was
+        displayed.  Lines were deleted at the end of the window.  */
+       int first_vpos = WINDOW_WANTS_HEADER_LINE_P (w) ? 1 : 0;
+       int vpos = XFASTINT (w->window_end_vpos);
+       struct glyph_row *current_row = current_matrix->rows + vpos;
+       struct glyph_row *desired_row = desired_matrix->rows + vpos;
+ 
+       for (row = NULL;
+          row == NULL && vpos >= first_vpos;
+          --vpos, --current_row, --desired_row)
+       {
+         if (desired_row->enabled_p)
+           {
+             if (desired_row->displays_text_p)
+               row = desired_row;
+           }
+         else if (current_row->displays_text_p)
+           row  = current_row;
+       }
+ 
+       xassert (row != NULL);
+       w->window_end_vpos = make_number (vpos + 1);
+       w->window_end_pos = make_number (Z - MATRIX_ROW_END_CHARPOS (row));
+       w->window_end_bytepos = Z_BYTE - MATRIX_ROW_END_BYTEPOS (row);
+       xassert (w->window_end_bytepos >= 0);
+       IF_DEBUG (debug_method_add (w, "C"));
+     }
+   else
+     abort ();
+ 
+ #if 0 /* This leads to problems, for instance when the cursor is
+        at ZV, and the cursor line displays no text.  */
+   /* Disable rows below what's displayed in the window.  This makes
+      debugging easier.  */
+   enable_glyph_matrix_rows (current_matrix,
+                           XFASTINT (w->window_end_vpos) + 1,
+                           bottom_vpos, 0);
+ #endif
+ 
+   IF_DEBUG (debug_end_pos = XFASTINT (w->window_end_pos);
+           debug_end_vpos = XFASTINT (w->window_end_vpos));
+ 
+   /* Record that display has not been completed.  */
+   w->window_end_valid = Qnil;
+   w->desired_matrix->no_scrolling_p = 1;
+   return 3;
+ 
+ #undef GIVE_UP
+ }
+ 
+ 
+ 
+ /***********************************************************************
+                       More debugging support
+  ***********************************************************************/
+ 
+ #if GLYPH_DEBUG
+ 
+ void dump_glyph_row P_ ((struct glyph_row *, int, int));
+ void dump_glyph_matrix P_ ((struct glyph_matrix *, int));
+ void dump_glyph P_ ((struct glyph_row *, struct glyph *, int));
+ 
+ 
+ /* Dump the contents of glyph matrix MATRIX on stderr.
+ 
+    GLYPHS 0 means don't show glyph contents.
+    GLYPHS 1 means show glyphs in short form
+    GLYPHS > 1 means show glyphs in long form.  */
+ 
+ void
+ dump_glyph_matrix (matrix, glyphs)
+      struct glyph_matrix *matrix;
+      int glyphs;
+ {
+   int i;
+   for (i = 0; i < matrix->nrows; ++i)
+     dump_glyph_row (MATRIX_ROW (matrix, i), i, glyphs);
+ }
+ 
+ 
+ /* Dump contents of glyph GLYPH to stderr.  ROW and AREA are
+    the glyph row and area where the glyph comes from.  */
+ 
+ void
+ dump_glyph (row, glyph, area)
+      struct glyph_row *row;
+      struct glyph *glyph;
+      int area;
+ {
+   if (glyph->type == CHAR_GLYPH)
+     {
+       fprintf (stderr,
+              "  %5d %4c %6d %c %3d 0x%05x %c %4d %1.1d%1.1d\n",
+              glyph - row->glyphs[TEXT_AREA],
+              'C',
+              glyph->charpos,
+              (BUFFERP (glyph->object)
+               ? 'B'
+               : (STRINGP (glyph->object)
+                  ? 'S'
+                  : '-')),
+              glyph->pixel_width,
+              glyph->u.ch,
+              (glyph->u.ch < 0x80 && glyph->u.ch >= ' '
+               ? glyph->u.ch
+               : '.'),
+              glyph->face_id,
+              glyph->left_box_line_p,
+              glyph->right_box_line_p);
+     }
+   else if (glyph->type == STRETCH_GLYPH)
+     {
+       fprintf (stderr,
+              "  %5d %4c %6d %c %3d 0x%05x %c %4d %1.1d%1.1d\n",
+              glyph - row->glyphs[TEXT_AREA],
+              'S',
+              glyph->charpos,
+              (BUFFERP (glyph->object)
+               ? 'B'
+               : (STRINGP (glyph->object)
+                  ? 'S'
+                  : '-')),
+              glyph->pixel_width,
+              0,
+              '.',
+              glyph->face_id,
+              glyph->left_box_line_p,
+              glyph->right_box_line_p);
+     }
+   else if (glyph->type == IMAGE_GLYPH)
+     {
+       fprintf (stderr,
+              "  %5d %4c %6d %c %3d 0x%05x %c %4d %1.1d%1.1d\n",
+              glyph - row->glyphs[TEXT_AREA],
+              'I',
+              glyph->charpos,
+              (BUFFERP (glyph->object)
+               ? 'B'
+               : (STRINGP (glyph->object)
+                  ? 'S'
+                  : '-')),
+              glyph->pixel_width,
+              glyph->u.img_id,
+              '.',
+              glyph->face_id,
+              glyph->left_box_line_p,
+              glyph->right_box_line_p);
+     }
+ }
+ 
+ 
+ /* Dump the contents of glyph row at VPOS in MATRIX to stderr.
+    GLYPHS 0 means don't show glyph contents.
+    GLYPHS 1 means show glyphs in short form
+    GLYPHS > 1 means show glyphs in long form.  */
+ 
+ void
+ dump_glyph_row (row, vpos, glyphs)
+      struct glyph_row *row;
+      int vpos, glyphs;
+ {
+   if (glyphs != 1)
+     {
+       fprintf (stderr, "Row Start   End Used oEI><O\\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\
+ %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),
+              MATRIX_ROW_END_CHARPOS (row),
+              row->used[TEXT_AREA],
+              row->contains_overlapping_glyphs_p,
+              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,
+              row->ends_at_zv_p,
+              row->fill_line_p,
+              row->ends_in_middle_of_char_p,
+              row->starts_in_middle_of_char_p,
+              row->mouse_face_p,
+              row->x,
+              row->y,
+              row->pixel_width,
+              row->height,
+              row->visible_height,
+              row->ascent,
+              row->phys_ascent);
+       fprintf (stderr, "%9d %5d\t%5d\n", row->start.overlay_string_index,
+              row->end.overlay_string_index,
+              row->continuation_lines_width);
+       fprintf (stderr, "%9d %5d\n",
+              CHARPOS (row->start.string_pos),
+              CHARPOS (row->end.string_pos));
+       fprintf (stderr, "%9d %5d\n", row->start.dpvec_index,
+              row->end.dpvec_index);
+     }
+ 
+   if (glyphs > 1)
+     {
+       int area;
+ 
+       for (area = LEFT_MARGIN_AREA; area < LAST_AREA; ++area)
+       {
+         struct glyph *glyph = row->glyphs[area];
+         struct glyph *glyph_end = glyph + row->used[area];
+ 
+         /* Glyph for a line end in text.  */
+         if (area == TEXT_AREA && glyph == glyph_end && glyph->charpos > 0)
+           ++glyph_end;
+ 
+         if (glyph < glyph_end)
+           fprintf (stderr, "  Glyph    Type Pos   O W    Code C Face LR\n");
+ 
+         for (; glyph < glyph_end; ++glyph)
+           dump_glyph (row, glyph, area);
+       }
+     }
+   else if (glyphs == 1)
+     {
+       int area;
+ 
+       for (area = LEFT_MARGIN_AREA; area < LAST_AREA; ++area)
+       {
+         char *s = (char *) alloca (row->used[area] + 1);
+         int i;
+ 
+         for (i = 0; i < row->used[area]; ++i)
+           {
+             struct glyph *glyph = row->glyphs[area] + i;
+             if (glyph->type == CHAR_GLYPH
+                 && glyph->u.ch < 0x80
+                 && glyph->u.ch >= ' ')
+               s[i] = glyph->u.ch;
+             else
+               s[i] = '.';
+           }
+ 
+         s[i] = '\0';
+         fprintf (stderr, "%3d: (%d) '%s'\n", vpos, row->enabled_p, s);
+       }
+     }
+ }
+ 
+ 
+ DEFUN ("dump-glyph-matrix", Fdump_glyph_matrix,
+        Sdump_glyph_matrix, 0, 1, "p",
+        doc: /* Dump the current matrix of the selected window to stderr.
+ Shows contents of glyph row structures.  With non-nil
+ parameter GLYPHS, dump glyphs as well.  If GLYPHS is 1 show
+ glyphs in short form, otherwise show glyphs in long form.  */)
+      (glyphs)
+      Lisp_Object glyphs;
+ {
+   struct window *w = XWINDOW (selected_window);
+   struct buffer *buffer = XBUFFER (w->buffer);
+ 
+   fprintf (stderr, "PT = %d, BEGV = %d. ZV = %d\n",
+          BUF_PT (buffer), BUF_BEGV (buffer), BUF_ZV (buffer));
+   fprintf (stderr, "Cursor x = %d, y = %d, hpos = %d, vpos = %d\n",
+          w->cursor.x, w->cursor.y, w->cursor.hpos, w->cursor.vpos);
+   fprintf (stderr, "=============================================\n");
+   dump_glyph_matrix (w->current_matrix,
+                    NILP (glyphs) ? 0 : XINT (glyphs));
+   return Qnil;
+ }
+ 
+ 
+ DEFUN ("dump-frame-glyph-matrix", Fdump_frame_glyph_matrix,
+        Sdump_frame_glyph_matrix, 0, 0, "", doc: /* */)
+      ()
+ {
+   struct frame *f = XFRAME (selected_frame);
+   dump_glyph_matrix (f->current_matrix, 1);
+   return Qnil;
+ }
+ 
+ 
+ DEFUN ("dump-glyph-row", Fdump_glyph_row, Sdump_glyph_row, 1, 2, "",
+        doc: /* Dump glyph row ROW to stderr.
+ GLYPH 0 means don't dump glyphs.
+ GLYPH 1 means dump glyphs in short form.
+ GLYPH > 1 or omitted means dump glyphs in long form.  */)
+      (row, glyphs)
+      Lisp_Object row, glyphs;
+ {
+   struct glyph_matrix *matrix;
+   int vpos;
+ 
+   CHECK_NUMBER (row);
+   matrix = XWINDOW (selected_window)->current_matrix;
+   vpos = XINT (row);
+   if (vpos >= 0 && vpos < matrix->nrows)
+     dump_glyph_row (MATRIX_ROW (matrix, vpos),
+                   vpos,
+                   INTEGERP (glyphs) ? XINT (glyphs) : 2);
+   return Qnil;
+ }
+ 
+ 
+ DEFUN ("dump-tool-bar-row", Fdump_tool_bar_row, Sdump_tool_bar_row, 1, 2, "",
+        doc: /* Dump glyph row ROW of the tool-bar of the current frame to 
stderr.
+ GLYPH 0 means don't dump glyphs.
+ GLYPH 1 means dump glyphs in short form.
+ GLYPH > 1 or omitted means dump glyphs in long form.  */)
+      (row, glyphs)
+      Lisp_Object row, glyphs;
+ {
+   struct frame *sf = SELECTED_FRAME ();
+   struct glyph_matrix *m = XWINDOW (sf->tool_bar_window)->current_matrix;
+   int vpos;
+ 
+   CHECK_NUMBER (row);
+   vpos = XINT (row);
+   if (vpos >= 0 && vpos < m->nrows)
+     dump_glyph_row (MATRIX_ROW (m, vpos), vpos,
+                   INTEGERP (glyphs) ? XINT (glyphs) : 2);
+   return Qnil;
+ }
+ 
+ 
+ DEFUN ("trace-redisplay", Ftrace_redisplay, Strace_redisplay, 0, 1, "P",
+        doc: /* Toggle tracing of redisplay.
+ With ARG, turn tracing on if and only if ARG is positive.  */)
+      (arg)
+      Lisp_Object arg;
+ {
+   if (NILP (arg))
+     trace_redisplay_p = !trace_redisplay_p;
+   else
+     {
+       arg = Fprefix_numeric_value (arg);
+       trace_redisplay_p = XINT (arg) > 0;
+     }
+ 
+   return Qnil;
+ }
+ 
+ 
+ DEFUN ("trace-to-stderr", Ftrace_to_stderr, Strace_to_stderr, 1, MANY, "",
+        doc: /* Like `format', but print result to stderr.
+ usage: (trace-to-stderr STRING &rest OBJECTS)  */)
+      (nargs, args)
+      int nargs;
+      Lisp_Object *args;
+ {
+   Lisp_Object s = Fformat (nargs, args);
+   fprintf (stderr, "%s", SDATA (s));
+   return Qnil;
+ }
+ 
+ #endif /* GLYPH_DEBUG */
+ 
+ 
+ 
+ /***********************************************************************
+                    Building Desired Matrix Rows
+  ***********************************************************************/
+ 
+ /* Return a temporary glyph row holding the glyphs of an overlay
+    arrow.  Only used for non-window-redisplay windows.  */
+ 
+ static struct glyph_row *
+ get_overlay_arrow_glyph_row (w)
+      struct window *w;
+ {
+   struct frame *f = XFRAME (WINDOW_FRAME (w));
+   struct buffer *buffer = XBUFFER (w->buffer);
+   struct buffer *old = current_buffer;
+   const unsigned char *arrow_string = SDATA (Voverlay_arrow_string);
+   int arrow_len = SCHARS (Voverlay_arrow_string);
+   const unsigned char *arrow_end = arrow_string + arrow_len;
+   const unsigned char *p;
+   struct it it;
+   int multibyte_p;
+   int n_glyphs_before;
+ 
+   set_buffer_temp (buffer);
+   init_iterator (&it, w, -1, -1, &scratch_glyph_row, DEFAULT_FACE_ID);
+   it.glyph_row->used[TEXT_AREA] = 0;
+   SET_TEXT_POS (it.position, 0, 0);
+ 
+   multibyte_p = !NILP (buffer->enable_multibyte_characters);
+   p = arrow_string;
+   while (p < arrow_end)
+     {
+       Lisp_Object face, ilisp;
+ 
+       /* Get the next character.  */
+       if (multibyte_p)
+       it.c = string_char_and_length (p, arrow_len, &it.len);
+       else
+       it.c = *p, it.len = 1;
+       p += it.len;
+ 
+       /* Get its face.  */
+       ilisp = make_number (p - arrow_string);
+       face = Fget_text_property (ilisp, Qface, Voverlay_arrow_string);
+       it.face_id = compute_char_face (f, it.c, face);
+ 
+       /* Compute its width, get its glyphs.  */
+       n_glyphs_before = it.glyph_row->used[TEXT_AREA];
+       SET_TEXT_POS (it.position, -1, -1);
+       PRODUCE_GLYPHS (&it);
+ 
+       /* If this character doesn't fit any more in the line, we have
+        to remove some glyphs.  */
+       if (it.current_x > it.last_visible_x)
+       {
+         it.glyph_row->used[TEXT_AREA] = n_glyphs_before;
+         break;
+       }
+     }
+ 
+   set_buffer_temp (old);
+   return it.glyph_row;
+ }
+ 
+ 
+ /* Insert truncation glyphs at the start of IT->glyph_row.  Truncation
+    glyphs are only inserted for terminal frames since we can't really
+    win with truncation glyphs when partially visible glyphs are
+    involved.  Which glyphs to insert is determined by
+    produce_special_glyphs.  */
+ 
+ static void
+ insert_left_trunc_glyphs (it)
+      struct it *it;
+ {
+   struct it truncate_it;
+   struct glyph *from, *end, *to, *toend;
+ 
+   xassert (!FRAME_WINDOW_P (it->f));
+ 
+   /* Get the truncation glyphs.  */
+   truncate_it = *it;
+   truncate_it.current_x = 0;
+   truncate_it.face_id = DEFAULT_FACE_ID;
+   truncate_it.glyph_row = &scratch_glyph_row;
+   truncate_it.glyph_row->used[TEXT_AREA] = 0;
+   CHARPOS (truncate_it.position) = BYTEPOS (truncate_it.position) = -1;
+   truncate_it.object = make_number (0);
+   produce_special_glyphs (&truncate_it, IT_TRUNCATION);
+ 
+   /* Overwrite glyphs from IT with truncation glyphs.  */
+   from = truncate_it.glyph_row->glyphs[TEXT_AREA];
+   end = from + truncate_it.glyph_row->used[TEXT_AREA];
+   to = it->glyph_row->glyphs[TEXT_AREA];
+   toend = to + it->glyph_row->used[TEXT_AREA];
+ 
+   while (from < end)
+     *to++ = *from++;
+ 
+   /* There may be padding glyphs left over.  Overwrite them too.  */
+   while (to < toend && CHAR_GLYPH_PADDING_P (*to))
+     {
+       from = truncate_it.glyph_row->glyphs[TEXT_AREA];
+       while (from < end)
+       *to++ = *from++;
+     }
+ 
+   if (to > toend)
+     it->glyph_row->used[TEXT_AREA] = to - it->glyph_row->glyphs[TEXT_AREA];
+ }
+ 
+ 
+ /* Compute the pixel height and width of IT->glyph_row.
+ 
+    Most of the time, ascent and height of a display line will be equal
+    to the max_ascent and max_height values of the display iterator
+    structure.  This is not the case if
+ 
+    1. We hit ZV without displaying anything.  In this case, max_ascent
+    and max_height will be zero.
+ 
+    2. We have some glyphs that don't contribute to the line height.
+    (The glyph row flag contributes_to_line_height_p is for future
+    pixmap extensions).
+ 
+    The first case is easily covered by using default values because in
+    these cases, the line height does not really matter, except that it
+    must not be zero.  */
+ 
+ static void
+ compute_line_metrics (it)
+      struct it *it;
+ {
+   struct glyph_row *row = it->glyph_row;
+   int area, i;
+ 
+   if (FRAME_WINDOW_P (it->f))
+     {
+       int i, min_y, max_y;
+ 
+       /* The line may consist of one space only, that was added to
+        place the cursor on it.  If so, the row's height hasn't been
+        computed yet.  */
+       if (row->height == 0)
+       {
+         if (it->max_ascent + it->max_descent == 0)
+           it->max_descent = it->max_phys_descent = FRAME_LINE_HEIGHT (it->f);
+         row->ascent = it->max_ascent;
+         row->height = it->max_ascent + it->max_descent;
+         row->phys_ascent = it->max_phys_ascent;
+         row->phys_height = it->max_phys_ascent + it->max_phys_descent;
+       }
+ 
+       /* Compute the width of this line.  */
+       row->pixel_width = row->x;
+       for (i = 0; i < row->used[TEXT_AREA]; ++i)
+       row->pixel_width += row->glyphs[TEXT_AREA][i].pixel_width;
+ 
+       xassert (row->pixel_width >= 0);
+       xassert (row->ascent >= 0 && row->height > 0);
+ 
+       row->overlapping_p = (MATRIX_ROW_OVERLAPS_SUCC_P (row)
+                           || MATRIX_ROW_OVERLAPS_PRED_P (row));
+ 
+       /* If first line's physical ascent is larger than its logical
+          ascent, use the physical ascent, and make the row taller.
+          This makes accented characters fully visible.  */
+       if (row == MATRIX_FIRST_TEXT_ROW (it->w->desired_matrix)
+         && row->phys_ascent > row->ascent)
+       {
+         row->height += row->phys_ascent - row->ascent;
+         row->ascent = row->phys_ascent;
+       }
+ 
+       /* Compute how much of the line is visible.  */
+       row->visible_height = row->height;
+ 
+       min_y = WINDOW_HEADER_LINE_HEIGHT (it->w);
+       max_y = WINDOW_BOX_HEIGHT_NO_MODE_LINE (it->w);
+ 
+       if (row->y < min_y)
+       row->visible_height -= min_y - row->y;
+       if (row->y + row->height > max_y)
+       row->visible_height -= row->y + row->height - max_y;
+     }
+   else
+     {
+       row->pixel_width = row->used[TEXT_AREA];
+       if (row->continued_p)
+       row->pixel_width -= it->continuation_pixel_width;
+       else if (row->truncated_on_right_p)
+       row->pixel_width -= it->truncation_pixel_width;
+       row->ascent = row->phys_ascent = 0;
+       row->height = row->phys_height = row->visible_height = 1;
+     }
+ 
+   /* Compute a hash code for this row.  */
+   row->hash = 0;
+   for (area = LEFT_MARGIN_AREA; area < LAST_AREA; ++area)
+     for (i = 0; i < row->used[area]; ++i)
+       row->hash = ((((row->hash << 4) + (row->hash >> 24)) & 0x0fffffff)
+                  + row->glyphs[area][i].u.val
+                  + row->glyphs[area][i].face_id
+                  + row->glyphs[area][i].padding_p
+                  + (row->glyphs[area][i].type << 2));
+ 
+   it->max_ascent = it->max_descent = 0;
+   it->max_phys_ascent = it->max_phys_descent = 0;
+ }
+ 
+ 
+ /* Append one space to the glyph row of iterator IT if doing a
+    window-based redisplay.  DEFAULT_FACE_P non-zero means let the
+    space have the default face, otherwise let it have the same face as
+    IT->face_id.  Value is non-zero if a space was added.
+ 
+    This function is called to make sure that there is always one glyph
+    at the end of a glyph row that the cursor can be set on under
+    window-systems.  (If there weren't such a glyph we would not know
+    how wide and tall a box cursor should be displayed).
+ 
+    At the same time this space let's a nicely handle clearing to the
+    end of the line if the row ends in italic text.  */
+ 
+ static int
+ append_space (it, default_face_p)
+      struct it *it;
+      int default_face_p;
+ {
+   if (FRAME_WINDOW_P (it->f))
+     {
+       int n = it->glyph_row->used[TEXT_AREA];
+ 
+       if (it->glyph_row->glyphs[TEXT_AREA] + n
+         < it->glyph_row->glyphs[1 + TEXT_AREA])
+       {
+         /* Save some values that must not be changed.
+            Must save IT->c and IT->len because otherwise
+            ITERATOR_AT_END_P wouldn't work anymore after
+            append_space has been called.  */
+         enum display_element_type saved_what = it->what;
+         int saved_c = it->c, saved_len = it->len;
+         int saved_x = it->current_x;
+         int saved_face_id = it->face_id;
+         struct text_pos saved_pos;
+         Lisp_Object saved_object;
+         struct face *face;
+ 
+         saved_object = it->object;
+         saved_pos = it->position;
+ 
+         it->what = IT_CHARACTER;
+         bzero (&it->position, sizeof it->position);
+         it->object = make_number (0);
+         it->c = ' ';
+         it->len = 1;
+ 
+         if (default_face_p)
+           it->face_id = DEFAULT_FACE_ID;
+         else if (it->face_before_selective_p)
+           it->face_id = it->saved_face_id;
+         face = FACE_FROM_ID (it->f, it->face_id);
+         it->face_id = FACE_FOR_CHAR (it->f, face, 0);
+ 
+         PRODUCE_GLYPHS (it);
+ 
+         it->current_x = saved_x;
+         it->object = saved_object;
+         it->position = saved_pos;
+         it->what = saved_what;
+         it->face_id = saved_face_id;
+         it->len = saved_len;
+         it->c = saved_c;
+         return 1;
+       }
+     }
+ 
+   return 0;
+ }
+ 
+ 
+ /* Extend the face of the last glyph in the text area of IT->glyph_row
+    to the end of the display line.  Called from display_line.
+    If the glyph row is empty, add a space glyph to it so that we
+    know the face to draw.  Set the glyph row flag fill_line_p.  */
+ 
+ static void
+ extend_face_to_end_of_line (it)
+      struct it *it;
+ {
+   struct face *face;
+   struct frame *f = it->f;
+ 
+   /* If line is already filled, do nothing.  */
+   if (it->current_x >= it->last_visible_x)
+     return;
+ 
+   /* Face extension extends the background and box of IT->face_id
+      to the end of the line.  If the background equals the background
+      of the frame, we don't have to do anything.  */
+   if (it->face_before_selective_p)
+     face = FACE_FROM_ID (it->f, it->saved_face_id);
+   else
+     face = FACE_FROM_ID (f, it->face_id);
+ 
+   if (FRAME_WINDOW_P (f)
+       && face->box == FACE_NO_BOX
+       && face->background == FRAME_BACKGROUND_PIXEL (f)
+       && !face->stipple)
+     return;
+ 
+   /* Set the glyph row flag indicating that the face of the last glyph
+      in the text area has to be drawn to the end of the text area.  */
+   it->glyph_row->fill_line_p = 1;
+ 
+   /* If current character of IT is not ASCII, make sure we have the
+          ASCII face.  This will be automatically undone the next time
+          get_next_display_element returns a multibyte character.  Note
+          that the character will always be single byte in unibyte text.  */
+   if (!ASCII_CHAR_P (it->c))
+     {
+       it->face_id = FACE_FOR_CHAR (f, face, 0);
+     }
+ 
+   if (FRAME_WINDOW_P (f))
+     {
+       /* If the row is empty, add a space with the current face of IT,
+        so that we know which face to draw.  */
+       if (it->glyph_row->used[TEXT_AREA] == 0)
+       {
+         it->glyph_row->glyphs[TEXT_AREA][0] = space_glyph;
+         it->glyph_row->glyphs[TEXT_AREA][0].face_id = it->face_id;
+         it->glyph_row->used[TEXT_AREA] = 1;
+       }
+     }
+   else
+     {
+       /* Save some values that must not be changed.  */
+       int saved_x = it->current_x;
+       struct text_pos saved_pos;
+       Lisp_Object saved_object;
+       enum display_element_type saved_what = it->what;
+       int saved_face_id = it->face_id;
+ 
+       saved_object = it->object;
+       saved_pos = it->position;
+ 
+       it->what = IT_CHARACTER;
+       bzero (&it->position, sizeof it->position);
+       it->object = make_number (0);
+       it->c = ' ';
+       it->len = 1;
+       it->face_id = face->id;
+ 
+       PRODUCE_GLYPHS (it);
+ 
+       while (it->current_x <= it->last_visible_x)
+       PRODUCE_GLYPHS (it);
+ 
+       /* Don't count these blanks really.  It would let us insert a left
+        truncation glyph below and make us set the cursor on them, maybe.  */
+       it->current_x = saved_x;
+       it->object = saved_object;
+       it->position = saved_pos;
+       it->what = saved_what;
+       it->face_id = saved_face_id;
+     }
+ }
+ 
+ 
+ /* Value is non-zero if text starting at CHARPOS in current_buffer is
+    trailing whitespace.  */
+ 
+ static int
+ trailing_whitespace_p (charpos)
+      int charpos;
+ {
+   int bytepos = CHAR_TO_BYTE (charpos);
+   int c = 0;
+ 
+   while (bytepos < ZV_BYTE
+        && (c = FETCH_CHAR (bytepos),
+            c == ' ' || c == '\t'))
+     ++bytepos;
+ 
+   if (bytepos >= ZV_BYTE || c == '\n' || c == '\r')
+     {
+       if (bytepos != PT_BYTE)
+       return 1;
+     }
+   return 0;
+ }
+ 
+ 
+ /* Highlight trailing whitespace, if any, in ROW.  */
+ 
+ void
+ highlight_trailing_whitespace (f, row)
+      struct frame *f;
+      struct glyph_row *row;
+ {
+   int used = row->used[TEXT_AREA];
+ 
+   if (used)
+     {
+       struct glyph *start = row->glyphs[TEXT_AREA];
+       struct glyph *glyph = start + used - 1;
+ 
+       /* Skip over glyphs inserted to display the cursor at the
+        end of a line, for extending the face of the last glyph
+        to the end of the line on terminals, and for truncation
+        and continuation glyphs.  */
+       while (glyph >= start
+            && glyph->type == CHAR_GLYPH
+            && INTEGERP (glyph->object))
+       --glyph;
+ 
+       /* If last glyph is a space or stretch, and it's trailing
+        whitespace, set the face of all trailing whitespace glyphs in
+        IT->glyph_row to `trailing-whitespace'.  */
+       if (glyph >= start
+         && BUFFERP (glyph->object)
+         && (glyph->type == STRETCH_GLYPH
+             || (glyph->type == CHAR_GLYPH
+                 && glyph->u.ch == ' '))
+         && trailing_whitespace_p (glyph->charpos))
+       {
+         int face_id = lookup_named_face (f, Qtrailing_whitespace);
+ 
+         while (glyph >= start
+                && BUFFERP (glyph->object)
+                && (glyph->type == STRETCH_GLYPH
+                    || (glyph->type == CHAR_GLYPH
+                        && glyph->u.ch == ' ')))
+           (glyph--)->face_id = face_id;
+       }
+     }
+ }
+ 
+ 
+ /* Value is non-zero if glyph row ROW in window W should be
+    used to hold the cursor.  */
+ 
+ static int
+ cursor_row_p (w, row)
+      struct window *w;
+      struct glyph_row *row;
+ {
+   int cursor_row_p = 1;
+ 
+   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).  */
+       if (CHARPOS (row->end.string_pos) >= 0
+         || MATRIX_ROW_ENDS_IN_MIDDLE_OF_CHAR_P (row))
+       cursor_row_p = row->continued_p;
+ 
+       /* If the row ends at ZV, display the cursor at the end of that
+        row instead of at the start of the row below.  */
+       else if (row->ends_at_zv_p)
+       cursor_row_p = 1;
+       else
+       cursor_row_p = 0;
+     }
+ 
+   return cursor_row_p;
+ }
+ 
+ 
+ /* Construct the glyph row IT->glyph_row in the desired matrix of
+    IT->w from text at the current position of IT.  See dispextern.h
+    for an overview of struct it.  Value is non-zero if
+    IT->glyph_row displays text, as opposed to a line displaying ZV
+    only.  */
+ 
+ static int
+ display_line (it)
+      struct it *it;
+ {
+   struct glyph_row *row = it->glyph_row;
+ 
+   /* We always start displaying at hpos zero even if hscrolled.  */
+   xassert (it->hpos == 0 && it->current_x == 0);
+ 
+   /* We must not display in a row that's not a text row.  */
+   xassert (MATRIX_ROW_VPOS (row, it->w->desired_matrix)
+          < it->w->desired_matrix->nrows);
+ 
+   /* Is IT->w showing the region?  */
+   it->w->region_showing = it->region_beg_charpos > 0 ? Qt : Qnil;
+ 
+   /* Clear the result glyph row and enable it.  */
+   prepare_desired_row (row);
+ 
+   row->y = it->current_y;
+   row->start = it->current;
+   row->continuation_lines_width = it->continuation_lines_width;
+   row->displays_text_p = 1;
+   row->starts_in_middle_of_char_p = it->starts_in_middle_of_char_p;
+   it->starts_in_middle_of_char_p = 0;
+ 
+   /* Arrange the overlays nicely for our purposes.  Usually, we call
+      display_line on only one line at a time, in which case this
+      can't really hurt too much, or we call it on lines which appear
+      one after another in the buffer, in which case all calls to
+      recenter_overlay_lists but the first will be pretty cheap.  */
+   recenter_overlay_lists (current_buffer, IT_CHARPOS (*it));
+ 
+   /* Move over display elements that are not visible because we are
+      hscrolled.  This may stop at an x-position < IT->first_visible_x
+      if the first glyph is partially visible or if we hit a line end.  */
+   if (it->current_x < it->first_visible_x)
+     move_it_in_display_line_to (it, ZV, it->first_visible_x,
+                               MOVE_TO_POS | MOVE_TO_X);
+ 
+   /* Get the initial row height.  This is either the height of the
+      text hscrolled, if there is any, or zero.  */
+   row->ascent = it->max_ascent;
+   row->height = it->max_ascent + it->max_descent;
+   row->phys_ascent = it->max_phys_ascent;
+   row->phys_height = it->max_phys_ascent + it->max_phys_descent;
+ 
+   /* Loop generating characters.  The loop is left with IT on the next
+      character to display.  */
+   while (1)
+     {
+       int n_glyphs_before, hpos_before, x_before;
+       int x, i, nglyphs;
+       int ascent = 0, descent = 0, phys_ascent = 0, phys_descent = 0;
+ 
+       /* Retrieve the next thing to display.  Value is zero if end of
+        buffer reached.  */
+       if (!get_next_display_element (it))
+       {
+         /* Maybe add a space at the end of this line that is used to
+            display the cursor there under X.  Set the charpos of the
+            first glyph of blank lines not corresponding to any text
+            to -1.  */
+         if ((append_space (it, 1) && row->used[TEXT_AREA] == 1)
+             || row->used[TEXT_AREA] == 0)
+           {
+             row->glyphs[TEXT_AREA]->charpos = -1;
+             row->displays_text_p = 0;
+ 
+             if (!NILP (XBUFFER (it->w->buffer)->indicate_empty_lines)
+                 && (!MINI_WINDOW_P (it->w)
+                     || (minibuf_level && EQ (it->window, minibuf_window))))
+               row->indicate_empty_line_p = 1;
+           }
+ 
+         it->continuation_lines_width = 0;
+         row->ends_at_zv_p = 1;
+         break;
+       }
+ 
+       /* Now, get the metrics of what we want to display.  This also
+        generates glyphs in `row' (which is IT->glyph_row).  */
+       n_glyphs_before = row->used[TEXT_AREA];
+       x = it->current_x;
+ 
+       /* Remember the line height so far in case the next element doesn't
+        fit on the line.  */
+       if (!it->truncate_lines_p)
+       {
+         ascent = it->max_ascent;
+         descent = it->max_descent;
+         phys_ascent = it->max_phys_ascent;
+         phys_descent = it->max_phys_descent;
+       }
+ 
+       PRODUCE_GLYPHS (it);
+ 
+       /* If this display element was in marginal areas, continue with
+        the next one.  */
+       if (it->area != TEXT_AREA)
+       {
+         row->ascent = max (row->ascent, it->max_ascent);
+         row->height = max (row->height, it->max_ascent + it->max_descent);
+         row->phys_ascent = max (row->phys_ascent, it->max_phys_ascent);
+         row->phys_height = max (row->phys_height,
+                                 it->max_phys_ascent + it->max_phys_descent);
+         set_iterator_to_next (it, 1);
+         continue;
+       }
+ 
+       /* Does the display element fit on the line?  If we truncate
+        lines, we should draw past the right edge of the window.  If
+        we don't truncate, we want to stop so that we can display the
+        continuation glyph before the right margin.  If lines are
+        continued, there are two possible strategies for characters
+        resulting in more than 1 glyph (e.g. tabs): Display as many
+        glyphs as possible in this line and leave the rest for the
+        continuation line, or display the whole element in the next
+        line.  Original redisplay did the former, so we do it also.  */
+       nglyphs = row->used[TEXT_AREA] - n_glyphs_before;
+       hpos_before = it->hpos;
+       x_before = x;
+ 
+       if (/* Not a newline.  */
+         nglyphs > 0
+         /* Glyphs produced fit entirely in the line.  */
+         && it->current_x < it->last_visible_x)
+       {
+         it->hpos += nglyphs;
+         row->ascent = max (row->ascent, it->max_ascent);
+         row->height = max (row->height, it->max_ascent + it->max_descent);
+         row->phys_ascent = max (row->phys_ascent, it->max_phys_ascent);
+         row->phys_height = max (row->phys_height,
+                                 it->max_phys_ascent + it->max_phys_descent);
+         if (it->current_x - it->pixel_width < it->first_visible_x)
+           row->x = x - it->first_visible_x;
+       }
+       else
+       {
+         int new_x;
+         struct glyph *glyph;
+ 
+         for (i = 0; i < nglyphs; ++i, x = new_x)
+           {
+             glyph = row->glyphs[TEXT_AREA] + n_glyphs_before + i;
+             new_x = x + glyph->pixel_width;
+ 
+             if (/* Lines are continued.  */
+                 !it->truncate_lines_p
+                 && (/* Glyph doesn't fit on the line.  */
+                     new_x > it->last_visible_x
+                     /* Or it fits exactly on a window system frame.  */
+                     || (new_x == it->last_visible_x
+                         && FRAME_WINDOW_P (it->f))))
+               {
+                 /* End of a continued line.  */
+ 
+                 if (it->hpos == 0
+                     || (new_x == it->last_visible_x
+                         && FRAME_WINDOW_P (it->f)))
+                   {
+                     /* Current glyph is the only one on the line or
+                        fits exactly on the line.  We must continue
+                        the line because we can't draw the cursor
+                        after the glyph.  */
+                     row->continued_p = 1;
+                     it->current_x = new_x;
+                     it->continuation_lines_width += new_x;
+                     ++it->hpos;
+                     if (i == nglyphs - 1)
+                       set_iterator_to_next (it, 1);
+                   }
+                 else if (CHAR_GLYPH_PADDING_P (*glyph)
+                          && !FRAME_WINDOW_P (it->f))
+                   {
+                     /* A padding glyph that doesn't fit on this line.
+                        This means the whole character doesn't fit
+                        on the line.  */
+                     row->used[TEXT_AREA] = n_glyphs_before;
+ 
+                     /* Fill the rest of the row with continuation
+                        glyphs like in 20.x.  */
+                     while (row->glyphs[TEXT_AREA] + row->used[TEXT_AREA]
+                            < row->glyphs[1 + TEXT_AREA])
+                       produce_special_glyphs (it, IT_CONTINUATION);
+ 
+                     row->continued_p = 1;
+                     it->current_x = x_before;
+                     it->continuation_lines_width += x_before;
+ 
+                     /* Restore the height to what it was before the
+                        element not fitting on the line.  */
+                     it->max_ascent = ascent;
+                     it->max_descent = descent;
+                     it->max_phys_ascent = phys_ascent;
+                     it->max_phys_descent = phys_descent;
+                   }
+                 else if (it->c == '\t' && FRAME_WINDOW_P (it->f))
+                   {
+                     /* A TAB that extends past the right edge of the
+                        window.  This produces a single glyph on
+                        window system frames.  We leave the glyph in
+                        this row and let it fill the row, but don't
+                        consume the TAB.  */
+                     it->continuation_lines_width += it->last_visible_x;
+                     row->ends_in_middle_of_char_p = 1;
+                     row->continued_p = 1;
+                     glyph->pixel_width = it->last_visible_x - x;
+                     it->starts_in_middle_of_char_p = 1;
+                   }
+                 else
+                   {
+                     /* Something other than a TAB that draws past
+                        the right edge of the window.  Restore
+                        positions to values before the element.  */
+                     row->used[TEXT_AREA] = n_glyphs_before + i;
+ 
+                     /* Display continuation glyphs.  */
+                     if (!FRAME_WINDOW_P (it->f))
+                       produce_special_glyphs (it, IT_CONTINUATION);
+                     row->continued_p = 1;
+ 
+                     it->continuation_lines_width += x;
+ 
+                     if (nglyphs > 1 && i > 0)
+                       {
+                         row->ends_in_middle_of_char_p = 1;
+                         it->starts_in_middle_of_char_p = 1;
+                       }
+ 
+                     /* Restore the height to what it was before the
+                        element not fitting on the line.  */
+                     it->max_ascent = ascent;
+                     it->max_descent = descent;
+                     it->max_phys_ascent = phys_ascent;
+                     it->max_phys_descent = phys_descent;
+                   }
+ 
+                 break;
+               }
+             else if (new_x > it->first_visible_x)
+               {
+                 /* Increment number of glyphs actually displayed.  */
+                 ++it->hpos;
+ 
+                 if (x < it->first_visible_x)
+                   /* Glyph is partially visible, i.e. row starts at
+                      negative X position.  */
+                   row->x = x - it->first_visible_x;
+               }
+             else
+               {
+                 /* Glyph is completely off the left margin of the
+                    window.  This should not happen because of the
+                    move_it_in_display_line at the start of this
+                    function, unless the text display area of the
+                    window is empty.  */
+                 xassert (it->first_visible_x <= it->last_visible_x);
+               }
+           }
+ 
+         row->ascent = max (row->ascent, it->max_ascent);
+         row->height = max (row->height, it->max_ascent + it->max_descent);
+         row->phys_ascent = max (row->phys_ascent, it->max_phys_ascent);
+         row->phys_height = max (row->phys_height,
+                                 it->max_phys_ascent + it->max_phys_descent);
+ 
+         /* End of this display line if row is continued.  */
+         if (row->continued_p)
+           break;
+       }
+ 
+       /* Is this a line end?  If yes, we're also done, after making
+        sure that a non-default face is extended up to the right
+        margin of the window.  */
+       if (ITERATOR_AT_END_OF_LINE_P (it))
+       {
+         int used_before = row->used[TEXT_AREA];
+ 
+         row->ends_in_newline_from_string_p = STRINGP (it->object);
+ 
+         /* Add a space at the end of the line that is used to
+            display the cursor there.  */
+         append_space (it, 0);
+ 
+         /* Extend the face to the end of the line.  */
+         extend_face_to_end_of_line (it);
+ 
+         /* Make sure we have the position.  */
+         if (used_before == 0)
+           row->glyphs[TEXT_AREA]->charpos = CHARPOS (it->position);
+ 
+         /* Consume the line end.  This skips over invisible lines.  */
+         set_iterator_to_next (it, 1);
+         it->continuation_lines_width = 0;
+         break;
+       }
+ 
+       /* Proceed with next display element.  Note that this skips
+        over lines invisible because of selective display.  */
+       set_iterator_to_next (it, 1);
+ 
+       /* If we truncate lines, we are done when the last displayed
+        glyphs reach past the right margin of the window.  */
+       if (it->truncate_lines_p
+         && (FRAME_WINDOW_P (it->f)
+             ? (it->current_x >= it->last_visible_x)
+             : (it->current_x > it->last_visible_x)))
+       {
+         /* Maybe add truncation glyphs.  */
+         if (!FRAME_WINDOW_P (it->f))
+           {
+             int i, n;
+ 
+             for (i = row->used[TEXT_AREA] - 1; i > 0; --i)
+               if (!CHAR_GLYPH_PADDING_P (row->glyphs[TEXT_AREA][i]))
+                 break;
+ 
+             for (n = row->used[TEXT_AREA]; i < n; ++i)
+               {
+                 row->used[TEXT_AREA] = i;
+                 produce_special_glyphs (it, IT_TRUNCATION);
+               }
+           }
+ 
+         row->truncated_on_right_p = 1;
+         it->continuation_lines_width = 0;
+         reseat_at_next_visible_line_start (it, 0);
+         row->ends_at_zv_p = FETCH_BYTE (IT_BYTEPOS (*it) - 1) != '\n';
+         it->hpos = hpos_before;
+         it->current_x = x_before;
+         break;
+       }
+     }
+ 
+   /* If line is not empty and hscrolled, maybe insert truncation glyphs
+      at the left window margin.  */
+   if (it->first_visible_x
+       && IT_CHARPOS (*it) != MATRIX_ROW_START_CHARPOS (row))
+     {
+       if (!FRAME_WINDOW_P (it->f))
+       insert_left_trunc_glyphs (it);
+       row->truncated_on_left_p = 1;
+     }
+ 
+   /* If the start of this line is the overlay arrow-position, then
+      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 (MARKERP (Voverlay_arrow_position)
+       && current_buffer == XMARKER (Voverlay_arrow_position)->buffer
+       && (MATRIX_ROW_START_CHARPOS (row)
+         == marker_position (Voverlay_arrow_position))
+       && STRINGP (Voverlay_arrow_string)
+       && ! overlay_arrow_seen)
+     {
+       /* Overlay arrow in window redisplay is a fringe bitmap.  */
+       if (!FRAME_WINDOW_P (it->f))
+       {
+         struct glyph_row *arrow_row = get_overlay_arrow_glyph_row (it->w);
+         struct glyph *glyph = arrow_row->glyphs[TEXT_AREA];
+         struct glyph *arrow_end = glyph + arrow_row->used[TEXT_AREA];
+         struct glyph *p = row->glyphs[TEXT_AREA];
+         struct glyph *p2, *end;
+ 
+         /* Copy the arrow glyphs.  */
+         while (glyph < arrow_end)
+           *p++ = *glyph++;
+ 
+         /* Throw away padding glyphs.  */
+         p2 = p;
+         end = row->glyphs[TEXT_AREA] + row->used[TEXT_AREA];
+         while (p2 < end && CHAR_GLYPH_PADDING_P (*p2))
+           ++p2;
+         if (p2 > p)
+           {
+             while (p2 < end)
+               *p++ = *p2++;
+             row->used[TEXT_AREA] = p2 - row->glyphs[TEXT_AREA];
+           }
+       }
+ 
+       overlay_arrow_seen = 1;
+       row->overlay_arrow_p = 1;
+     }
+ 
+   /* Compute pixel dimensions of this line.  */
+   compute_line_metrics (it);
+ 
+   /* Remember the position at which this line ends.  */
+   row->end = it->current;
+ 
+   /* Maybe set the cursor.  */
+   if (it->w->cursor.vpos < 0
+       && PT >= MATRIX_ROW_START_CHARPOS (row)
+       && PT <= MATRIX_ROW_END_CHARPOS (row)
+       && cursor_row_p (it->w, row))
+     set_cursor_from_row (it->w, row, it->w->desired_matrix, 0, 0, 0, 0);
+ 
+   /* Highlight trailing whitespace.  */
+   if (!NILP (Vshow_trailing_whitespace))
+     highlight_trailing_whitespace (it->f, it->glyph_row);
+ 
+   /* Prepare for the next line.  This line starts horizontally at (X
+      HPOS) = (0 0).  Vertical positions are incremented.  As a
+      convenience for the caller, IT->glyph_row is set to the next
+      row to be used.  */
+   it->current_x = it->hpos = 0;
+   it->current_y += row->height;
+   ++it->vpos;
+   ++it->glyph_row;
+   return row->displays_text_p;
+ }
+ 
+ 
+ 
+ /***********************************************************************
+                              Menu Bar
+  ***********************************************************************/
+ 
+ /* Redisplay the menu bar in the frame for window W.
+ 
+    The menu bar of X frames that don't have X toolkit support is
+    displayed in a special window W->frame->menu_bar_window.
+ 
+    The menu bar of terminal frames is treated specially as far as
+    glyph matrices are concerned.  Menu bar lines are not part of
+    windows, so the update is done directly on the frame matrix rows
+    for the menu bar.  */
+ 
+ static void
+ display_menu_bar (w)
+      struct window *w;
+ {
+   struct frame *f = XFRAME (WINDOW_FRAME (w));
+   struct it it;
+   Lisp_Object items;
+   int i;
+ 
+   /* Don't do all this for graphical frames.  */
+ #ifdef HAVE_NTGUI
+   if (!NILP (Vwindow_system))
+     return;
+ #endif
+ #if defined (USE_X_TOOLKIT) || defined (USE_GTK)
+   if (FRAME_X_P (f))
+     return;
+ #endif
+ #ifdef MAC_OS
+   if (FRAME_MAC_P (f))
+     return;
+ #endif
+ 
+ #ifdef USE_X_TOOLKIT
+   xassert (!FRAME_WINDOW_P (f));
+   init_iterator (&it, w, -1, -1, f->desired_matrix->rows, MENU_FACE_ID);
+   it.first_visible_x = 0;
+   it.last_visible_x = FRAME_TOTAL_COLS (f) * FRAME_COLUMN_WIDTH (f);
+ #else /* not USE_X_TOOLKIT */
+   if (FRAME_WINDOW_P (f))
+     {
+       /* Menu bar lines are displayed in the desired matrix of the
+        dummy window menu_bar_window.  */
+       struct window *menu_w;
+       xassert (WINDOWP (f->menu_bar_window));
+       menu_w = XWINDOW (f->menu_bar_window);
+       init_iterator (&it, menu_w, -1, -1, menu_w->desired_matrix->rows,
+                    MENU_FACE_ID);
+       it.first_visible_x = 0;
+       it.last_visible_x = FRAME_TOTAL_COLS (f) * FRAME_COLUMN_WIDTH (f);
+     }
+   else
+     {
+       /* This is a TTY frame, i.e. character hpos/vpos are used as
+        pixel x/y.  */
+       init_iterator (&it, w, -1, -1, f->desired_matrix->rows,
+                    MENU_FACE_ID);
+       it.first_visible_x = 0;
+       it.last_visible_x = FRAME_COLS (f);
+     }
+ #endif /* not USE_X_TOOLKIT */
+ 
+   if (! mode_line_inverse_video)
+     /* Force the menu-bar to be displayed in the default face.  */
+     it.base_face_id = it.face_id = DEFAULT_FACE_ID;
+ 
+   /* Clear all rows of the menu bar.  */
+   for (i = 0; i < FRAME_MENU_BAR_LINES (f); ++i)
+     {
+       struct glyph_row *row = it.glyph_row + i;
+       clear_glyph_row (row);
+       row->enabled_p = 1;
+       row->full_width_p = 1;
+     }
+ 
+   /* Display all items of the menu bar.  */
+   items = FRAME_MENU_BAR_ITEMS (it.f);
+   for (i = 0; i < XVECTOR (items)->size; i += 4)
+     {
+       Lisp_Object string;
+ 
+       /* Stop at nil string.  */
+       string = AREF (items, i + 1);
+       if (NILP (string))
+       break;
+ 
+       /* Remember where item was displayed.  */
+       AREF (items, i + 3) = make_number (it.hpos);
+ 
+       /* Display the item, pad with one space.  */
+       if (it.current_x < it.last_visible_x)
+       display_string (NULL, string, Qnil, 0, 0, &it,
+                       SCHARS (string) + 1, 0, 0, -1);
+     }
+ 
+   /* Fill out the line with spaces.  */
+   if (it.current_x < it.last_visible_x)
+     display_string ("", Qnil, Qnil, 0, 0, &it, -1, 0, 0, -1);
+ 
+   /* Compute the total height of the lines.  */
+   compute_line_metrics (&it);
+ }
+ 
+ 
+ 
+ /***********************************************************************
+                             Mode Line
+  ***********************************************************************/
+ 
+ /* Redisplay mode lines in the window tree whose root is WINDOW.  If
+    FORCE is non-zero, redisplay mode lines unconditionally.
+    Otherwise, redisplay only mode lines that are garbaged.  Value is
+    the number of windows whose mode lines were redisplayed.  */
+ 
+ static int
+ redisplay_mode_lines (window, force)
+      Lisp_Object window;
+      int force;
+ {
+   int nwindows = 0;
+ 
+   while (!NILP (window))
+     {
+       struct window *w = XWINDOW (window);
+ 
+       if (WINDOWP (w->hchild))
+       nwindows += redisplay_mode_lines (w->hchild, force);
+       else if (WINDOWP (w->vchild))
+       nwindows += redisplay_mode_lines (w->vchild, force);
+       else if (force
+              || FRAME_GARBAGED_P (XFRAME (w->frame))
+              || !MATRIX_MODE_LINE_ROW (w->current_matrix)->enabled_p)
+       {
+         struct text_pos lpoint;
+         struct buffer *old = current_buffer;
+ 
+         /* Set the window's buffer for the mode line display.  */
+         SET_TEXT_POS (lpoint, PT, PT_BYTE);
+         set_buffer_internal_1 (XBUFFER (w->buffer));
+ 
+         /* Point refers normally to the selected window.  For any
+            other window, set up appropriate value.  */
+         if (!EQ (window, selected_window))
+           {
+             struct text_pos pt;
+ 
+             SET_TEXT_POS_FROM_MARKER (pt, w->pointm);
+             if (CHARPOS (pt) < BEGV)
+               TEMP_SET_PT_BOTH (BEGV, BEGV_BYTE);
+             else if (CHARPOS (pt) > (ZV - 1))
+               TEMP_SET_PT_BOTH (ZV, ZV_BYTE);
+             else
+               TEMP_SET_PT_BOTH (CHARPOS (pt), BYTEPOS (pt));
+           }
+ 
+         /* Display mode lines.  */
+         clear_glyph_matrix (w->desired_matrix);
+         if (display_mode_lines (w))
+           {
+             ++nwindows;
+             w->must_be_updated_p = 1;
+           }
+ 
+         /* Restore old settings.  */
+         set_buffer_internal_1 (old);
+         TEMP_SET_PT_BOTH (CHARPOS (lpoint), BYTEPOS (lpoint));
+       }
+ 
+       window = w->next;
+     }
+ 
+   return nwindows;
+ }
+ 
+ 
+ /* Display the mode and/or top line of window W.  Value is the number
+    of mode lines displayed.  */
+ 
+ static int
+ display_mode_lines (w)
+      struct window *w;
+ {
+   Lisp_Object old_selected_window, old_selected_frame;
+   int n = 0;
+ 
+   old_selected_frame = selected_frame;
+   selected_frame = w->frame;
+   old_selected_window = selected_window;
+   XSETWINDOW (selected_window, w);
+ 
+   /* These will be set while the mode line specs are processed.  */
+   line_number_displayed = 0;
+   w->column_number_displayed = Qnil;
+ 
+   if (WINDOW_WANTS_MODELINE_P (w))
+     {
+       struct window *sel_w = XWINDOW (old_selected_window);
+ 
+       /* Select mode line face based on the real selected window.  */
+       display_mode_line (w, CURRENT_MODE_LINE_FACE_ID_3 (sel_w, sel_w, w),
+                        current_buffer->mode_line_format);
+       ++n;
+     }
+ 
+   if (WINDOW_WANTS_HEADER_LINE_P (w))
+     {
+       display_mode_line (w, HEADER_LINE_FACE_ID,
+                        current_buffer->header_line_format);
+       ++n;
+     }
+ 
+   selected_frame = old_selected_frame;
+   selected_window = old_selected_window;
+   return n;
+ }
+ 
+ 
+ /* Display mode or top line of window W.  FACE_ID specifies which line
+    to display; it is either MODE_LINE_FACE_ID or HEADER_LINE_FACE_ID.
+    FORMAT is the mode line format to display.  Value is the pixel
+    height of the mode line displayed.  */
+ 
+ static int
+ display_mode_line (w, face_id, format)
+      struct window *w;
+      enum face_id face_id;
+      Lisp_Object format;
+ {
+   struct it it;
+   struct face *face;
+ 
+   init_iterator (&it, w, -1, -1, NULL, face_id);
+   prepare_desired_row (it.glyph_row);
+ 
+   if (! mode_line_inverse_video)
+     /* Force the mode-line to be displayed in the default face.  */
+     it.base_face_id = it.face_id = DEFAULT_FACE_ID;
+ 
+   /* Temporarily make frame's keyboard the current kboard so that
+      kboard-local variables in the mode_line_format will get the right
+      values.  */
+   push_frame_kboard (it.f);
+   display_mode_element (&it, 0, 0, 0, format, Qnil, 0);
+   pop_frame_kboard ();
+ 
+   /* Fill up with spaces.  */
+   display_string (" ", Qnil, Qnil, 0, 0, &it, 10000, -1, -1, 0);
+ 
+   compute_line_metrics (&it);
+   it.glyph_row->full_width_p = 1;
+   it.glyph_row->mode_line_p = 1;
+   it.glyph_row->continued_p = 0;
+   it.glyph_row->truncated_on_left_p = 0;
+   it.glyph_row->truncated_on_right_p = 0;
+ 
+   /* Make a 3D mode-line have a shadow at its right end.  */
+   face = FACE_FROM_ID (it.f, face_id);
+   extend_face_to_end_of_line (&it);
+   if (face->box != FACE_NO_BOX)
+     {
+       struct glyph *last = (it.glyph_row->glyphs[TEXT_AREA]
+                           + it.glyph_row->used[TEXT_AREA] - 1);
+       last->right_box_line_p = 1;
+     }
+ 
+   return it.glyph_row->height;
+ }
+ 
+ /* Alist that caches the results of :propertize.
+    Each element is (PROPERTIZED-STRING . PROPERTY-LIST).  */
+ Lisp_Object mode_line_proptrans_alist;
+ 
+ /* List of strings making up the mode-line.  */
+ Lisp_Object mode_line_string_list;
+ 
+ /* Base face property when building propertized mode line string.  */
+ static Lisp_Object mode_line_string_face;
+ static Lisp_Object mode_line_string_face_prop;
+ 
+ 
+ /* Contribute ELT to the mode line for window IT->w.  How it
+    translates into text depends on its data type.
+ 
+    IT describes the display environment in which we display, as usual.
+ 
+    DEPTH is the depth in recursion.  It is used to prevent
+    infinite recursion here.
+ 
+    FIELD_WIDTH is the number of characters the display of ELT should
+    occupy in the mode line, and PRECISION is the maximum number of
+    characters to display from ELT's representation.  See
+    display_string for details.
+ 
+    Returns the hpos of the end of the text generated by ELT.
+ 
+    PROPS is a property list to add to any string we encounter.
+ 
+    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'.  */
+ 
+ static int
+ display_mode_element (it, depth, field_width, precision, elt, props, risky)
+      struct it *it;
+      int depth;
+      int field_width, precision;
+      Lisp_Object elt, props;
+      int risky;
+ {
+   int n = 0, field, prec;
+   int literal = 0;
+ 
+  tail_recurse:
+   if (depth > 100)
+     elt = build_string ("*too-deep*");
+ 
+   depth++;
+ 
+   switch (SWITCH_ENUM_CAST (XTYPE (elt)))
+     {
+     case Lisp_String:
+       {
+       /* A string: output it and check for %-constructs within it.  */
+       unsigned char c;
+       const unsigned char *this, *lisp_string;
+ 
+       if (!NILP (props) || risky)
+         {
+           Lisp_Object oprops, aelt;
+           oprops = Ftext_properties_at (make_number (0), elt);
+ 
+           if (NILP (Fequal (props, oprops)) || risky)
+             {
+               /* If the starting string has properties,
+                  merge the specified ones onto the existing ones.  */
+               if (! NILP (oprops) && !risky)
+                 {
+                   Lisp_Object tem;
+ 
+                   oprops = Fcopy_sequence (oprops);
+                   tem = props;
+                   while (CONSP (tem))
+                     {
+                       oprops = Fplist_put (oprops, XCAR (tem),
+                                            XCAR (XCDR (tem)));
+                       tem = XCDR (XCDR (tem));
+                     }
+                   props = oprops;
+                 }
+ 
+               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));
+                   elt = XCAR (aelt);
+                 }
+               else
+                 {
+                   Lisp_Object tem;
+ 
+                   elt = Fcopy_sequence (elt);
+                   Fset_text_properties (make_number (0), Flength (elt),
+                                         props, elt);
+                   /* Add this item to mode_line_proptrans_alist.  */
+                   mode_line_proptrans_alist
+                     = Fcons (Fcons (elt, props),
+                              mode_line_proptrans_alist);
+                   /* Truncate mode_line_proptrans_alist
+                      to at most 50 elements.  */
+                   tem = Fnthcdr (make_number (50),
+                                  mode_line_proptrans_alist);
+                   if (! NILP (tem))
+                     XSETCDR (tem, Qnil);
+                 }
+             }
+         }
+ 
+       this = SDATA (elt);
+       lisp_string = this;
+ 
+       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));
+ 
+           break;
+         }
+ 
+       while ((precision <= 0 || n < precision)
+              && *this
+              && (frame_title_ptr
+                  || !NILP (mode_line_string_list)
+                  || it->current_x < it->last_visible_x))
+         {
+           const unsigned char *last = this;
+ 
+           /* Advance to end of string or next format specifier.  */
+           while ((c = *this++) != '\0' && c != '%')
+             ;
+ 
+           if (this - 1 != last)
+             {
+               /* Output to end of string or up to '%'.  Field width
+                  is length of string.  Don't output more than
+                  PRECISION allows us.  */
+               --this;
+ 
+               prec = chars_in_text (last, this - last);
+               if (precision > 0 && prec > precision - n)
+                 prec = precision - n;
+ 
+               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);
+                   n += store_mode_line_string (NULL,
+                                                Fsubstring (elt, make_number 
(charpos),
+                                                            make_number 
(charpos + prec)),
+                                                0, 0, 0, Qnil);
+                 }
+               else
+                 {
+                   int bytepos = last - lisp_string;
+                   int charpos = string_byte_to_char (elt, bytepos);
+                   n += display_string (NULL, elt, Qnil, 0, charpos,
+                                        it, 0, prec, 0,
+                                        STRING_MULTIBYTE (elt));
+                 }
+             }
+           else /* c == '%' */
+             {
+               const unsigned char *percent_position = this;
+ 
+               /* Get the specified minimum width.  Zero means
+                  don't pad.  */
+               field = 0;
+               while ((c = *this++) >= '0' && c <= '9')
+                 field = field * 10 + c - '0';
+ 
+               /* Don't pad beyond the total padding allowed.  */
+               if (field_width - n > 0 && field > field_width - n)
+                 field = field_width - n;
+ 
+               /* Note that either PRECISION <= 0 or N < PRECISION.  */
+               prec = precision - n;
+ 
+               if (c == 'M')
+                 n += display_mode_element (it, depth, field, prec,
+                                            Vglobal_mode_string, props,
+                                            risky);
+               else if (c != 0)
+                 {
+                   int multibyte;
+                   int bytepos, charpos;
+                   unsigned char *spec;
+ 
+                   bytepos = percent_position - lisp_string;
+                   charpos = (STRING_MULTIBYTE (elt)
+                              ? string_byte_to_char (elt, bytepos)
+                              : bytepos);
+ 
+                   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))
+                     {
+                       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;
+                         }
+                     }
+                 }
+               else /* c == 0 */
+                 break;
+             }
+         }
+       }
+       break;
+ 
+     case Lisp_Symbol:
+       /* A symbol: process the value of the symbol recursively
+        as if it appeared here directly.  Avoid error if symbol void.
+        Special case: if value of symbol is a string, output the string
+        literally.  */
+       {
+       register Lisp_Object tem;
+ 
+       /* If the variable is not marked as risky to set
+          then its contents are risky to use.  */
+       if (NILP (Fget (elt, Qrisky_local_variable)))
+         risky = 1;
+ 
+       tem = Fboundp (elt);
+       if (!NILP (tem))
+         {
+           tem = Fsymbol_value (elt);
+           /* If value is a string, output that string literally:
+              don't check for % within it.  */
+           if (STRINGP (tem))
+             literal = 1;
+ 
+           if (!EQ (tem, elt))
+             {
+               /* Give up right away for nil or t.  */
+               elt = tem;
+               goto tail_recurse;
+             }
+         }
+       }
+       break;
+ 
+     case Lisp_Cons:
+       {
+       register Lisp_Object car, tem;
+ 
+       /* A cons cell: five distinct cases.
+          If first element is :eval or :propertize, do something special.
+          If first element is a string or a cons, process all the elements
+          and effectively concatenate them.
+          If first element is a negative number, truncate displaying cdr to
+          at most that many characters.  If positive, pad (with spaces)
+          to at least that many characters.
+          If first element is a symbol, process the cadr or caddr recursively
+          according to whether the symbol's value is non-nil or nil.  */
+       car = XCAR (elt);
+       if (EQ (car, QCeval))
+         {
+           /* An element of the form (:eval FORM) means evaluate FORM
+              and use the result as mode line elements.  */
+ 
+           if (risky)
+             break;
+ 
+           if (CONSP (XCDR (elt)))
+             {
+               Lisp_Object spec;
+               spec = safe_eval (XCAR (XCDR (elt)));
+               n += display_mode_element (it, depth, field_width - n,
+                                          precision - n, spec, props,
+                                          risky);
+             }
+         }
+       else if (EQ (car, QCpropertize))
+         {
+           /* An element of the form (:propertize ELT PROPS...)
+              means display ELT but applying properties PROPS.  */
+ 
+           if (risky)
+             break;
+ 
+           if (CONSP (XCDR (elt)))
+             n += display_mode_element (it, depth, field_width - n,
+                                        precision - n, XCAR (XCDR (elt)),
+                                        XCDR (XCDR (elt)), risky);
+         }
+       else if (SYMBOLP (car))
+         {
+           tem = Fboundp (car);
+           elt = XCDR (elt);
+           if (!CONSP (elt))
+             goto invalid;
+           /* elt is now the cdr, and we know it is a cons cell.
+              Use its car if CAR has a non-nil value.  */
+           if (!NILP (tem))
+             {
+               tem = Fsymbol_value (car);
+               if (!NILP (tem))
+                 {
+                   elt = XCAR (elt);
+                   goto tail_recurse;
+                 }
+             }
+           /* Symbol's value is nil (or symbol is unbound)
+              Get the cddr of the original list
+              and if possible find the caddr and use that.  */
+           elt = XCDR (elt);
+           if (NILP (elt))
+             break;
+           else if (!CONSP (elt))
+             goto invalid;
+           elt = XCAR (elt);
+           goto tail_recurse;
+         }
+       else if (INTEGERP (car))
+         {
+           register int lim = XINT (car);
+           elt = XCDR (elt);
+           if (lim < 0)
+             {
+               /* Negative int means reduce maximum width.  */
+               if (precision <= 0)
+                 precision = -lim;
+               else
+                 precision = min (precision, -lim);
+             }
+           else if (lim > 0)
+             {
+               /* Padding specified.  Don't let it be more than
+                  current maximum.  */
+               if (precision > 0)
+                 lim = min (precision, lim);
+ 
+               /* If that's more padding than already wanted, queue it.
+                  But don't reduce padding already specified even if
+                  that is beyond the current truncation point.  */
+               field_width = max (lim, field_width);
+             }
+           goto tail_recurse;
+         }
+       else if (STRINGP (car) || CONSP (car))
+         {
+           register int limit = 50;
+           /* Limit is to protect against circular lists.  */
+           while (CONSP (elt)
+                  && --limit > 0
+                  && (precision <= 0 || n < precision))
+             {
+               n += display_mode_element (it, depth, field_width - n,
+                                          precision - n, XCAR (elt),
+                                          props, risky);
+               elt = XCDR (elt);
+             }
+         }
+       }
+       break;
+ 
+     default:
+     invalid:
+       elt = build_string ("*invalid*");
+       goto tail_recurse;
+     }
+ 
+   /* 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);
+     }
+ 
+   return n;
+ }
+ 
+ /* Store a mode-line string element in mode_line_string_list.
+ 
+    If STRING is non-null, display that C string.  Otherwise, the Lisp
+    string LISP_STRING is displayed.
+ 
+    FIELD_WIDTH is the minimum number of output glyphs to produce.
+    If STRING has fewer characters than FIELD_WIDTH, pad to the right
+    with spaces.  FIELD_WIDTH <= 0 means don't pad.
+ 
+    PRECISION is the maximum number of characters to output from
+    STRING.  PRECISION <= 0  means don't truncate the string.
+ 
+    If COPY_STRING is non-zero, make a copy of LISP_STRING before adding
+    properties to the string.
+ 
+    PROPS are the properties to add to the string.
+    The mode_line_string_face face property is always added to the string.
+  */
+ 
+ static int store_mode_line_string (string, lisp_string, copy_string, 
field_width, precision, props)
+      char *string;
+      Lisp_Object lisp_string;
+      int copy_string;
+      int field_width;
+      int precision;
+      Lisp_Object props;
+ {
+   int len;
+   int n = 0;
+ 
+   if (string != NULL)
+     {
+       len = strlen (string);
+       if (precision > 0 && len > precision)
+       len = precision;
+       lisp_string = make_string (string, len);
+       if (NILP (props))
+       props = mode_line_string_face_prop;
+       else if (!NILP (mode_line_string_face))
+       {
+         Lisp_Object face = Fplist_get (props, Qface);
+         props = Fcopy_sequence (props);
+         if (NILP (face))
+           face = mode_line_string_face;
+         else
+           face = Fcons (face, Fcons (mode_line_string_face, Qnil));
+         props = Fplist_put (props, Qface, face);
+       }
+       Fadd_text_properties (make_number (0), make_number (len),
+                           props, lisp_string);
+     }
+   else
+     {
+       len = XFASTINT (Flength (lisp_string));
+       if (precision > 0 && len > precision)
+       {
+         len = precision;
+         lisp_string = Fsubstring (lisp_string, make_number (0), make_number 
(len));
+         precision = -1;
+       }
+       if (!NILP (mode_line_string_face))
+       {
+         Lisp_Object face;
+         if (NILP (props))
+           props = Ftext_properties_at (make_number (0), lisp_string);
+         face = Fplist_get (props, Qface);
+         if (NILP (face))
+           face = mode_line_string_face;
+         else
+           face = Fcons (face, Fcons (mode_line_string_face, Qnil));
+         props = Fcons (Qface, Fcons (face, Qnil));
+         if (copy_string)
+           lisp_string = Fcopy_sequence (lisp_string);
+       }
+       if (!NILP (props))
+       Fadd_text_properties (make_number (0), make_number (len),
+                             props, lisp_string);
+     }
+ 
+   if (len > 0)
+     {
+       mode_line_string_list = Fcons (lisp_string, mode_line_string_list);
+       n += len;
+     }
+ 
+   if (field_width > len)
+     {
+       field_width -= len;
+       lisp_string = Fmake_string (make_number (field_width), make_number (' 
'));
+       if (!NILP (props))
+       Fadd_text_properties (make_number (0), make_number (field_width),
+                             props, lisp_string);
+       mode_line_string_list = Fcons (lisp_string, mode_line_string_list);
+       n += field_width;
+     }
+ 
+   return n;
+ }
+ 
+ 
+ DEFUN ("format-mode-line", Fformat_mode_line, Sformat_mode_line,
+        0, 3, 0,
+        doc: /* Return the mode-line of selected window as a string.
+ First optional arg FORMAT specifies a different format string (see
+ `mode-line-format' for details) to use.  If FORMAT is t, return
+ the buffer's header-line.  Second optional arg WINDOW specifies a
+ different window to use as the context for the formatting.
+ If third optional arg NO-PROPS is non-nil, string is not propertized.  */)
+      (format, window, no_props)
+      Lisp_Object format, window, no_props;
+ {
+   struct it it;
+   int len;
+   struct window *w;
+   struct buffer *old_buffer = NULL;
+   enum face_id face_id = DEFAULT_FACE_ID;
+ 
+   if (NILP (window))
+     window = selected_window;
+   CHECK_WINDOW (window);
+   w = XWINDOW (window);
+   CHECK_BUFFER (w->buffer);
+ 
+   if (XBUFFER (w->buffer) != current_buffer)
+     {
+       old_buffer = current_buffer;
+       set_buffer_internal_1 (XBUFFER (w->buffer));
+     }
+ 
+   if (NILP (format) || EQ (format, Qt))
+     {
+       face_id = NILP (format)
+       ? CURRENT_MODE_LINE_FACE_ID (w) :
+       HEADER_LINE_FACE_ID;
+       format = NILP (format)
+       ? current_buffer->mode_line_format
+       : current_buffer->header_line_format;
+     }
+ 
+   init_iterator (&it, w, -1, -1, NULL, face_id);
+ 
+   if (NILP (no_props))
+     {
+       mode_line_string_face =
+       (face_id == MODE_LINE_FACE_ID ? Qmode_line :
+        face_id == MODE_LINE_INACTIVE_FACE_ID ? Qmode_line_inactive :
+        face_id == HEADER_LINE_FACE_ID ? Qheader_line : Qnil);
+ 
+       mode_line_string_face_prop =
+       NILP (mode_line_string_face) ? Qnil :
+       Fcons (Qface, Fcons (mode_line_string_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;
+     }
+   else
+     {
+       mode_line_string_face_prop = Qnil;
+       mode_line_string_list = Qnil;
+       frame_title_ptr = frame_title_buf;
+     }
+ 
+   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 (NILP (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 = frame_title_ptr - frame_title_buf;
+   if (len > 0 && frame_title_ptr[-1] == '-')
+     {
+       /* 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;
+     }
+ 
+   frame_title_ptr = NULL;
+   return make_string (frame_title_buf, len);
+ }
+ 
+ /* Write a null-terminated, right justified decimal representation of
+    the positive integer D to BUF using a minimal field width WIDTH.  */
+ 
+ static void
+ pint2str (buf, width, d)
+      register char *buf;
+      register int width;
+      register int d;
+ {
+   register char *p = buf;
+ 
+   if (d <= 0)
+     *p++ = '0';
+   else
+     {
+       while (d > 0)
+       {
+         *p++ = d % 10 + '0';
+         d /= 10;
+       }
+     }
+ 
+   for (width -= (int) (p - buf); width > 0; --width)
+     *p++ = ' ';
+   *p-- = '\0';
+   while (p > buf)
+     {
+       d = *buf;
+       *buf++ = *p;
+       *p-- = d;
+     }
+ }
+ 
+ /* Set a mnemonic character for coding_system (Lisp symbol) in BUF.
+    If EOL_FLAG is 1, set also a mnemonic character for end-of-line
+    type of CODING_SYSTEM.  Return updated pointer into BUF.  */
+ 
+ static unsigned char invalid_eol_type[] = "(*invalid*)";
+ 
+ static char *
+ decode_mode_spec_coding (coding_system, buf, eol_flag)
+      Lisp_Object coding_system;
+      register char *buf;
+      int eol_flag;
+ {
+   Lisp_Object val;
+   int multibyte = !NILP (current_buffer->enable_multibyte_characters);
+   const unsigned char *eol_str;
+   int eol_str_len;
+   /* The EOL conversion we are using.  */
+   Lisp_Object eoltype;
+ 
+   val = CODING_SYSTEM_SPEC (coding_system);
+   eoltype = Qnil;
+ 
+   if (!VECTORP (val))         /* Not yet decided.  */
+     {
+       if (multibyte)
+       *buf++ = '-';
+       if (eol_flag)
+       eoltype = eol_mnemonic_undecided;
+       /* Don't mention EOL conversion if it isn't decided.  */
+     }
+   else
+     {
+       Lisp_Object attrs;
+       Lisp_Object eolvalue;
+ 
+       attrs = AREF (val, 0);
+       eolvalue = AREF (val, 2);
+ 
+       if (multibyte)
+       *buf++ = XFASTINT (CODING_ATTR_MNEMONIC (attrs));
+ 
+       if (eol_flag)
+       {
+         /* The EOL conversion that is normal on this system.  */
+ 
+         if (NILP (eolvalue))  /* Not yet decided.  */
+           eoltype = eol_mnemonic_undecided;
+         else if (VECTORP (eolvalue)) /* Not yet decided.  */
+           eoltype = eol_mnemonic_undecided;
+         else                  /* eolvalue is Qunix, Qdos, or Qmac.  */
+           eoltype = (EQ (eolvalue, Qunix)
+                      ? eol_mnemonic_unix
+                      : (EQ (eolvalue, Qdos) == 1
+                         ? eol_mnemonic_dos : eol_mnemonic_mac));
+       }
+     }
+ 
+   if (eol_flag)
+     {
+       /* Mention the EOL conversion if it is not the usual one.  */
+       if (STRINGP (eoltype))
+       {
+         eol_str = SDATA (eoltype);
+         eol_str_len = SBYTES (eoltype);
+       }
+       else if (CHARACTERP (eoltype))
+       {
+         unsigned char *tmp = (unsigned char *) alloca (MAX_MULTIBYTE_LENGTH);
+         eol_str_len = CHAR_STRING (XINT (eoltype), tmp);
+         eol_str = tmp;
+       }
+       else
+       {
+         eol_str = invalid_eol_type;
+         eol_str_len = sizeof (invalid_eol_type) - 1;
+       }
+       bcopy (eol_str, buf, eol_str_len);
+       buf += eol_str_len;
+     }
+ 
+   return buf;
+ }
+ 
+ /* Return a string for the output of a mode line %-spec for window W,
+    generated by character C.  PRECISION >= 0 means don't return a
+    string longer than that value.  FIELD_WIDTH > 0 means pad the
+    string returned with spaces to that value.  Return 1 in *MULTIBYTE
+    if the result is multibyte text.  */
+ 
+ static char lots_of_dashes[] = 
"--------------------------------------------------------------------------------------------------------------------------------------------";
+ 
+ static char *
+ decode_mode_spec (w, c, field_width, precision, multibyte)
+      struct window *w;
+      register int c;
+      int field_width, precision;
+      int *multibyte;
+ {
+   Lisp_Object obj;
+   struct frame *f = XFRAME (WINDOW_FRAME (w));
+   char *decode_mode_spec_buf = f->decode_mode_spec_buffer;
+   struct buffer *b = XBUFFER (w->buffer);
+ 
+   obj = Qnil;
+   *multibyte = 0;
+ 
+   switch (c)
+     {
+     case '*':
+       if (!NILP (b->read_only))
+       return "%";
+       if (BUF_MODIFF (b) > BUF_SAVE_MODIFF (b))
+       return "*";
+       return "-";
+ 
+     case '+':
+       /* This differs from %* only for a modified read-only buffer.  */
+       if (BUF_MODIFF (b) > BUF_SAVE_MODIFF (b))
+       return "*";
+       if (!NILP (b->read_only))
+       return "%";
+       return "-";
+ 
+     case '&':
+       /* This differs from %* in ignoring read-only-ness.  */
+       if (BUF_MODIFF (b) > BUF_SAVE_MODIFF (b))
+       return "*";
+       return "-";
+ 
+     case '%':
+       return "%";
+ 
+     case '[':
+       {
+       int i;
+       char *p;
+ 
+       if (command_loop_level > 5)
+         return "[[[... ";
+       p = decode_mode_spec_buf;
+       for (i = 0; i < command_loop_level; i++)
+         *p++ = '[';
+       *p = 0;
+       return decode_mode_spec_buf;
+       }
+ 
+     case ']':
+       {
+       int i;
+       char *p;
+ 
+       if (command_loop_level > 5)
+         return " ...]]]";
+       p = decode_mode_spec_buf;
+       for (i = 0; i < command_loop_level; i++)
+         *p++ = ']';
+       *p = 0;
+       return decode_mode_spec_buf;
+       }
+ 
+     case '-':
+       {
+       register int i;
+ 
+       /* Let lots_of_dashes be a string of infinite length.  */
+       if (!NILP (mode_line_string_list))
+         return "--";
+       if (field_width <= 0
+           || field_width > sizeof (lots_of_dashes))
+         {
+           for (i = 0; i < FRAME_MESSAGE_BUF_SIZE (f) - 1; ++i)
+             decode_mode_spec_buf[i] = '-';
+           decode_mode_spec_buf[i] = '\0';
+           return decode_mode_spec_buf;
+         }
+       else
+         return lots_of_dashes;
+       }
+ 
+     case 'b':
+       obj = b->name;
+       break;
+ 
+     case 'c':
+       {
+       int col = (int) current_column (); /* iftc */
+       w->column_number_displayed = make_number (col);
+       pint2str (decode_mode_spec_buf, field_width, col);
+       return decode_mode_spec_buf;
+       }
+ 
+     case 'F':
+       /* %F displays the frame name.  */
+       if (!NILP (f->title))
+       return (char *) SDATA (f->title);
+       if (f->explicit_name || ! FRAME_WINDOW_P (f))
+       return (char *) SDATA (f->name);
+       return "Emacs";
+ 
+     case 'f':
+       obj = b->filename;
+       break;
+ 
+     case 'l':
+       {
+       int startpos = XMARKER (w->start)->charpos;
+       int startpos_byte = marker_byte_position (w->start);
+       int line, linepos, linepos_byte, topline;
+       int nlines, junk;
+       int height = WINDOW_TOTAL_LINES (w);
+ 
+       /* If we decided that this buffer isn't suitable for line numbers,
+          don't forget that too fast.  */
+       if (EQ (w->base_line_pos, w->buffer))
+         goto no_value;
+       /* But do forget it, if the window shows a different buffer now.  */
+       else if (BUFFERP (w->base_line_pos))
+         w->base_line_pos = Qnil;
+ 
+       /* If the buffer is very big, don't waste time.  */
+       if (INTEGERP (Vline_number_display_limit)
+           && BUF_ZV (b) - BUF_BEGV (b) > XINT (Vline_number_display_limit))
+         {
+           w->base_line_pos = Qnil;
+           w->base_line_number = Qnil;
+           goto no_value;
+         }
+ 
+       if (!NILP (w->base_line_number)
+           && !NILP (w->base_line_pos)
+           && XFASTINT (w->base_line_pos) <= startpos)
+         {
+           line = XFASTINT (w->base_line_number);
+           linepos = XFASTINT (w->base_line_pos);
+           linepos_byte = buf_charpos_to_bytepos (b, linepos);
+         }
+       else
+         {
+           line = 1;
+           linepos = BUF_BEGV (b);
+           linepos_byte = BUF_BEGV_BYTE (b);
+         }
+ 
+       /* Count lines from base line to window start position.  */
+       nlines = display_count_lines (linepos, linepos_byte,
+                                     startpos_byte,
+                                     startpos, &junk);
+ 
+       topline = nlines + line;
+ 
+       /* Determine a new base line, if the old one is too close
+          or too far away, or if we did not have one.
+          "Too close" means it's plausible a scroll-down would
+          go back past it.  */
+       if (startpos == BUF_BEGV (b))
+         {
+           w->base_line_number = make_number (topline);
+           w->base_line_pos = make_number (BUF_BEGV (b));
+         }
+       else if (nlines < height + 25 || nlines > height * 3 + 50
+                || linepos == BUF_BEGV (b))
+         {
+           int limit = BUF_BEGV (b);
+           int limit_byte = BUF_BEGV_BYTE (b);
+           int position;
+           int distance = (height * 2 + 30) * line_number_display_limit_width;
+ 
+           if (startpos - distance > limit)
+             {
+               limit = startpos - distance;
+               limit_byte = CHAR_TO_BYTE (limit);
+             }
+ 
+           nlines = display_count_lines (startpos, startpos_byte,
+                                         limit_byte,
+                                         - (height * 2 + 30),
+                                         &position);
+           /* If we couldn't find the lines we wanted within
+              line_number_display_limit_width chars per line,
+              give up on line numbers for this window.  */
+           if (position == limit_byte && limit == startpos - distance)
+             {
+               w->base_line_pos = w->buffer;
+               w->base_line_number = Qnil;
+               goto no_value;
+             }
+ 
+           w->base_line_number = make_number (topline - nlines);
+           w->base_line_pos = make_number (BYTE_TO_CHAR (position));
+         }
+ 
+       /* Now count lines from the start pos to point.  */
+       nlines = display_count_lines (startpos, startpos_byte,
+                                     PT_BYTE, PT, &junk);
+ 
+       /* Record that we did display the line number.  */
+       line_number_displayed = 1;
+ 
+       /* Make the string to show.  */
+       pint2str (decode_mode_spec_buf, field_width, topline + nlines);
+       return decode_mode_spec_buf;
+     no_value:
+         {
+         char* p = decode_mode_spec_buf;
+         int pad = field_width - 2;
+         while (pad-- > 0)
+           *p++ = ' ';
+         *p++ = '?';
+         *p++ = '?';
+         *p = '\0';
+         return decode_mode_spec_buf;
+       }
+       }
+       break;
+ 
+     case 'm':
+       obj = b->mode_name;
+       break;
+ 
+     case 'n':
+       if (BUF_BEGV (b) > BUF_BEG (b) || BUF_ZV (b) < BUF_Z (b))
+       return " Narrow";
+       break;
+ 
+     case 'p':
+       {
+       int pos = marker_position (w->start);
+       int total = BUF_ZV (b) - BUF_BEGV (b);
+ 
+       if (XFASTINT (w->window_end_pos) <= BUF_Z (b) - BUF_ZV (b))
+         {
+           if (pos <= BUF_BEGV (b))
+             return "All";
+           else
+             return "Bottom";
+         }
+       else if (pos <= BUF_BEGV (b))
+         return "Top";
+       else
+         {
+           if (total > 1000000)
+             /* Do it differently for a large value, to avoid overflow.  */
+             total = ((pos - BUF_BEGV (b)) + (total / 100) - 1) / (total / 
100);
+           else
+             total = ((pos - BUF_BEGV (b)) * 100 + total - 1) / total;
+           /* We can't normally display a 3-digit number,
+              so get us a 2-digit number that is close.  */
+           if (total == 100)
+             total = 99;
+           sprintf (decode_mode_spec_buf, "%2d%%", total);
+           return decode_mode_spec_buf;
+         }
+       }
+ 
+       /* Display percentage of size above the bottom of the screen.  */
+     case 'P':
+       {
+       int toppos = marker_position (w->start);
+       int botpos = BUF_Z (b) - XFASTINT (w->window_end_pos);
+       int total = BUF_ZV (b) - BUF_BEGV (b);
+ 
+       if (botpos >= BUF_ZV (b))
+         {
+           if (toppos <= BUF_BEGV (b))
+             return "All";
+           else
+             return "Bottom";
+         }
+       else
+         {
+           if (total > 1000000)
+             /* Do it differently for a large value, to avoid overflow.  */
+             total = ((botpos - BUF_BEGV (b)) + (total / 100) - 1) / (total / 
100);
+           else
+             total = ((botpos - BUF_BEGV (b)) * 100 + total - 1) / total;
+           /* We can't normally display a 3-digit number,
+              so get us a 2-digit number that is close.  */
+           if (total == 100)
+             total = 99;
+           if (toppos <= BUF_BEGV (b))
+             sprintf (decode_mode_spec_buf, "Top%2d%%", total);
+           else
+             sprintf (decode_mode_spec_buf, "%2d%%", total);
+           return decode_mode_spec_buf;
+         }
+       }
+ 
+     case 's':
+       /* status of process */
+       obj = Fget_buffer_process (w->buffer);
+       if (NILP (obj))
+       return "no process";
+ #ifdef subprocesses
+       obj = Fsymbol_name (Fprocess_status (obj));
+ #endif
+       break;
+ 
+     case 't':                 /* indicate TEXT or BINARY */
+ #ifdef MODE_LINE_BINARY_TEXT
+       return MODE_LINE_BINARY_TEXT (b);
+ #else
+       return "T";
+ #endif
+ 
+     case 'z':
+       /* coding-system (not including end-of-line format) */
+     case 'Z':
+       /* coding-system (including end-of-line type) */
+       {
+       int eol_flag = (c == 'Z');
+       char *p = decode_mode_spec_buf;
+ 
+       if (! FRAME_WINDOW_P (f))
+         {
+           /* No need to mention EOL here--the terminal never needs
+              to do EOL conversion.  */
+           p = decode_mode_spec_coding (CODING_ID_NAME (keyboard_coding.id),
+                                        p, 0);
+           p = decode_mode_spec_coding (CODING_ID_NAME (terminal_coding.id),
+                                        p, 0);
+         }
+       p = decode_mode_spec_coding (b->buffer_file_coding_system,
+                                    p, eol_flag);
+ 
+ #if 0 /* This proves to be annoying; I think we can do without.  -- rms.  */
+ #ifdef subprocesses
+       obj = Fget_buffer_process (Fcurrent_buffer ());
+       if (PROCESSP (obj))
+         {
+           p = decode_mode_spec_coding (XPROCESS (obj)->decode_coding_system,
+                                        p, eol_flag);
+           p = decode_mode_spec_coding (XPROCESS (obj)->encode_coding_system,
+                                        p, eol_flag);
+         }
+ #endif /* subprocesses */
+ #endif /* 0 */
+       *p = 0;
+       return decode_mode_spec_buf;
+       }
+     }
+ 
+   if (STRINGP (obj))
+     {
+       *multibyte = STRING_MULTIBYTE (obj);
+       return (char *) SDATA (obj);
+     }
+   else
+     return "";
+ }
+ 
+ 
+ /* Count up to COUNT lines starting from START / START_BYTE.
+    But don't go beyond LIMIT_BYTE.
+    Return the number of lines thus found (always nonnegative).
+ 
+    Set *BYTE_POS_PTR to 1 if we found COUNT lines, 0 if we hit LIMIT.  */
+ 
+ static int
+ display_count_lines (start, start_byte, limit_byte, count, byte_pos_ptr)
+      int start, start_byte, limit_byte, count;
+      int *byte_pos_ptr;
+ {
+   register unsigned char *cursor;
+   unsigned char *base;
+ 
+   register int ceiling;
+   register unsigned char *ceiling_addr;
+   int orig_count = count;
+ 
+   /* If we are not in selective display mode,
+      check only for newlines.  */
+   int selective_display = (!NILP (current_buffer->selective_display)
+                          && !INTEGERP (current_buffer->selective_display));
+ 
+   if (count > 0)
+     {
+       while (start_byte < limit_byte)
+       {
+         ceiling =  BUFFER_CEILING_OF (start_byte);
+         ceiling = min (limit_byte - 1, ceiling);
+         ceiling_addr = BYTE_POS_ADDR (ceiling) + 1;
+         base = (cursor = BYTE_POS_ADDR (start_byte));
+         while (1)
+           {
+             if (selective_display)
+               while (*cursor != '\n' && *cursor != 015 && ++cursor != 
ceiling_addr)
+                 ;
+             else
+               while (*cursor != '\n' && ++cursor != ceiling_addr)
+                 ;
+ 
+             if (cursor != ceiling_addr)
+               {
+                 if (--count == 0)
+                   {
+                     start_byte += cursor - base + 1;
+                     *byte_pos_ptr = start_byte;
+                     return orig_count;
+                   }
+                 else
+                   if (++cursor == ceiling_addr)
+                     break;
+               }
+             else
+               break;
+           }
+         start_byte += cursor - base;
+       }
+     }
+   else
+     {
+       while (start_byte > limit_byte)
+       {
+         ceiling = BUFFER_FLOOR_OF (start_byte - 1);
+         ceiling = max (limit_byte, ceiling);
+         ceiling_addr = BYTE_POS_ADDR (ceiling) - 1;
+         base = (cursor = BYTE_POS_ADDR (start_byte - 1) + 1);
+         while (1)
+           {
+             if (selective_display)
+               while (--cursor != ceiling_addr
+                      && *cursor != '\n' && *cursor != 015)
+                 ;
+             else
+               while (--cursor != ceiling_addr && *cursor != '\n')
+                 ;
+ 
+             if (cursor != ceiling_addr)
+               {
+                 if (++count == 0)
+                   {
+                     start_byte += cursor - base + 1;
+                     *byte_pos_ptr = start_byte;
+                     /* When scanning backwards, we should
+                        not count the newline posterior to which we stop.  */
+                     return - orig_count - 1;
+                   }
+               }
+             else
+               break;
+           }
+         /* Here we add 1 to compensate for the last decrement
+            of CURSOR, which took it past the valid range.  */
+         start_byte += cursor - base + 1;
+       }
+     }
+ 
+   *byte_pos_ptr = limit_byte;
+ 
+   if (count < 0)
+     return - orig_count + count;
+   return orig_count - count;
+ 
+ }
+ 
+ 
+ 
+ /***********************************************************************
+                        Displaying strings
+  ***********************************************************************/
+ 
+ /* Display a NUL-terminated string, starting with index START.
+ 
+    If STRING is non-null, display that C string.  Otherwise, the Lisp
+    string LISP_STRING is displayed.
+ 
+    If FACE_STRING is not nil, FACE_STRING_POS is a position in
+    FACE_STRING.  Display STRING or LISP_STRING with the face at
+    FACE_STRING_POS in FACE_STRING:
+ 
+    Display the string in the environment given by IT, but use the
+    standard display table, temporarily.
+ 
+    FIELD_WIDTH is the minimum number of output glyphs to produce.
+    If STRING has fewer characters than FIELD_WIDTH, pad to the right
+    with spaces.  If STRING has more characters, more than FIELD_WIDTH
+    glyphs will be produced.  FIELD_WIDTH <= 0 means don't pad.
+ 
+    PRECISION is the maximum number of characters to output from
+    STRING.  PRECISION < 0  means don't truncate the string.
+ 
+    This is roughly equivalent to printf format specifiers:
+ 
+    FIELD_WIDTH        PRECISION       PRINTF
+    ----------------------------------------
+    -1         -1              %s
+    -1         10              %.10s
+    10         -1              %10s
+    20         10              %20.10s
+ 
+    MULTIBYTE zero means do not display multibyte chars, > 0 means do
+    display them, and < 0 means obey the current buffer's value of
+    enable_multibyte_characters.
+ 
+    Value is the number of glyphs produced.  */
+ 
+ static int
+ display_string (string, lisp_string, face_string, face_string_pos,
+               start, it, field_width, precision, max_x, multibyte)
+      unsigned char *string;
+      Lisp_Object lisp_string;
+      Lisp_Object face_string;
+      int face_string_pos;
+      int start;
+      struct it *it;
+      int field_width, precision, max_x;
+      int multibyte;
+ {
+   int hpos_at_start = it->hpos;
+   int saved_face_id = it->face_id;
+   struct glyph_row *row = it->glyph_row;
+ 
+   /* Initialize the iterator IT for iteration over STRING beginning
+      with index START.  */
+   reseat_to_string (it, string, lisp_string, start,
+                   precision, field_width, multibyte);
+ 
+   /* If displaying STRING, set up the face of the iterator
+      from LISP_STRING, if that's given.  */
+   if (STRINGP (face_string))
+     {
+       int endptr;
+       struct face *face;
+ 
+       it->face_id
+       = face_at_string_position (it->w, face_string, face_string_pos,
+                                  0, it->region_beg_charpos,
+                                  it->region_end_charpos,
+                                  &endptr, it->base_face_id, 0);
+       face = FACE_FROM_ID (it->f, it->face_id);
+       it->face_box_p = face->box != FACE_NO_BOX;
+     }
+ 
+   /* Set max_x to the maximum allowed X position.  Don't let it go
+      beyond the right edge of the window.  */
+   if (max_x <= 0)
+     max_x = it->last_visible_x;
+   else
+     max_x = min (max_x, it->last_visible_x);
+ 
+   /* Skip over display elements that are not visible. because IT->w is
+      hscrolled.  */
+   if (it->current_x < it->first_visible_x)
+     move_it_in_display_line_to (it, 100000, it->first_visible_x,
+                               MOVE_TO_POS | MOVE_TO_X);
+ 
+   row->ascent = it->max_ascent;
+   row->height = it->max_ascent + it->max_descent;
+   row->phys_ascent = it->max_phys_ascent;
+   row->phys_height = it->max_phys_ascent + it->max_phys_descent;
+ 
+   /* This condition is for the case that we are called with current_x
+      past last_visible_x.  */
+   while (it->current_x < max_x)
+     {
+       int x_before, x, n_glyphs_before, i, nglyphs;
+ 
+       /* Get the next display element.  */
+       if (!get_next_display_element (it))
+       break;
+ 
+       /* Produce glyphs.  */
+       x_before = it->current_x;
+       n_glyphs_before = it->glyph_row->used[TEXT_AREA];
+       PRODUCE_GLYPHS (it);
+ 
+       nglyphs = it->glyph_row->used[TEXT_AREA] - n_glyphs_before;
+       i = 0;
+       x = x_before;
+       while (i < nglyphs)
+       {
+         struct glyph *glyph = row->glyphs[TEXT_AREA] + n_glyphs_before + i;
+ 
+         if (!it->truncate_lines_p
+             && x + glyph->pixel_width > max_x)
+           {
+             /* End of continued line or max_x reached.  */
+             if (CHAR_GLYPH_PADDING_P (*glyph))
+               {
+                 /* A wide character is unbreakable.  */
+                 it->glyph_row->used[TEXT_AREA] = n_glyphs_before;
+                 it->current_x = x_before;
+               }
+             else
+               {
+                 it->glyph_row->used[TEXT_AREA] = n_glyphs_before + i;
+                 it->current_x = x;
+               }
+             break;
+           }
+         else if (x + glyph->pixel_width >= it->first_visible_x)
+           {
+             /* Glyph is at least partially visible.  */
+             ++it->hpos;
+             if (x < it->first_visible_x)
+               it->glyph_row->x = x - it->first_visible_x;
+           }
+         else
+           {
+             /* Glyph is off the left margin of the display area.
+                Should not happen.  */
+             abort ();
+           }
+ 
+         row->ascent = max (row->ascent, it->max_ascent);
+         row->height = max (row->height, it->max_ascent + it->max_descent);
+         row->phys_ascent = max (row->phys_ascent, it->max_phys_ascent);
+         row->phys_height = max (row->phys_height,
+                                 it->max_phys_ascent + it->max_phys_descent);
+         x += glyph->pixel_width;
+         ++i;
+       }
+ 
+       /* Stop if max_x reached.  */
+       if (i < nglyphs)
+       break;
+ 
+       /* Stop at line ends.  */
+       if (ITERATOR_AT_END_OF_LINE_P (it))
+       {
+         it->continuation_lines_width = 0;
+         break;
+       }
+ 
+       set_iterator_to_next (it, 1);
+ 
+       /* Stop if truncating at the right edge.  */
+       if (it->truncate_lines_p
+         && it->current_x >= it->last_visible_x)
+       {
+         /* Add truncation mark, but don't do it if the line is
+            truncated at a padding space.  */
+         if (IT_CHARPOS (*it) < it->string_nchars)
+           {
+             if (!FRAME_WINDOW_P (it->f))
+               {
+                 int i, n;
+ 
+                 if (it->current_x > it->last_visible_x)
+                   {
+                     for (i = row->used[TEXT_AREA] - 1; i > 0; --i)
+                       if (!CHAR_GLYPH_PADDING_P (row->glyphs[TEXT_AREA][i]))
+                         break;
+                     for (n = row->used[TEXT_AREA]; i < n; ++i)
+                       {
+                         row->used[TEXT_AREA] = i;
+                         produce_special_glyphs (it, IT_TRUNCATION);
+                       }
+                   }
+                 produce_special_glyphs (it, IT_TRUNCATION);
+               }
+             it->glyph_row->truncated_on_right_p = 1;
+           }
+         break;
+       }
+     }
+ 
+   /* Maybe insert a truncation at the left.  */
+   if (it->first_visible_x
+       && IT_CHARPOS (*it) > 0)
+     {
+       if (!FRAME_WINDOW_P (it->f))
+       insert_left_trunc_glyphs (it);
+       it->glyph_row->truncated_on_left_p = 1;
+     }
+ 
+   it->face_id = saved_face_id;
+ 
+   /* Value is number of columns displayed.  */
+   return it->hpos - hpos_at_start;
+ }
+ 
+ 
+ 
+ /* This is like a combination of memq and assq.  Return 1/2 if PROPVAL
+    appears as an element of LIST or as the car of an element of LIST.
+    If PROPVAL is a list, compare each element against LIST in that
+    way, and return 1/2 if any element of PROPVAL is found in LIST.
+    Otherwise return 0.  This function cannot quit.
+    The return value is 2 if the text is invisible but with an ellipsis
+    and 1 if it's invisible and without an ellipsis.  */
+ 
+ int
+ invisible_p (propval, list)
+      register Lisp_Object propval;
+      Lisp_Object list;
+ {
+   register Lisp_Object tail, proptail;
+ 
+   for (tail = list; CONSP (tail); tail = XCDR (tail))
+     {
+       register Lisp_Object tem;
+       tem = XCAR (tail);
+       if (EQ (propval, tem))
+       return 1;
+       if (CONSP (tem) && EQ (propval, XCAR (tem)))
+       return NILP (XCDR (tem)) ? 1 : 2;
+     }
+ 
+   if (CONSP (propval))
+     {
+       for (proptail = propval; CONSP (proptail); proptail = XCDR (proptail))
+       {
+         Lisp_Object propelt;
+         propelt = XCAR (proptail);
+         for (tail = list; CONSP (tail); tail = XCDR (tail))
+           {
+             register Lisp_Object tem;
+             tem = XCAR (tail);
+             if (EQ (propelt, tem))
+               return 1;
+             if (CONSP (tem) && EQ (propelt, XCAR (tem)))
+               return NILP (XCDR (tem)) ? 1 : 2;
+           }
+       }
+     }
+ 
+   return 0;
+ }
+ 
+ 
+ /***********************************************************************
+                            Glyph Display
+  ***********************************************************************/
+ 
+ #ifdef HAVE_WINDOW_SYSTEM
+ 
+ #if GLYPH_DEBUG
+ 
+ void
+ dump_glyph_string (s)
+      struct glyph_string *s;
+ {
+   fprintf (stderr, "glyph string\n");
+   fprintf (stderr, "  x, y, w, h = %d, %d, %d, %d\n",
+          s->x, s->y, s->width, s->height);
+   fprintf (stderr, "  ybase = %d\n", s->ybase);
+   fprintf (stderr, "  hl = %d\n", s->hl);
+   fprintf (stderr, "  left overhang = %d, right = %d\n",
+          s->left_overhang, s->right_overhang);
+   fprintf (stderr, "  nchars = %d\n", s->nchars);
+   fprintf (stderr, "  extends to end of line = %d\n",
+          s->extends_to_end_of_line_p);
+   fprintf (stderr, "  font height = %d\n", FONT_HEIGHT (s->font));
+   fprintf (stderr, "  bg width = %d\n", s->background_width);
+ }
+ 
+ #endif /* GLYPH_DEBUG */
+ 
+ /* Initialize glyph string S.  CHAR2B is a suitably allocated vector
+    of XChar2b structures for S; it can't be allocated in
+    init_glyph_string because it must be allocated via `alloca'.  W
+    is the window on which S is drawn.  ROW and AREA are the glyph row
+    and area within the row from which S is constructed.  START is the
+    index of the first glyph structure covered by S.  HL is a
+    face-override for drawing S.  */
+ 
+ #ifdef HAVE_NTGUI
+ #define OPTIONAL_HDC(hdc)  hdc,
+ #define DECLARE_HDC(hdc)   HDC hdc;
+ #define ALLOCATE_HDC(hdc, f) hdc = get_frame_dc ((f))
+ #define RELEASE_HDC(hdc, f)  release_frame_dc ((f), (hdc))
+ #endif
+ 
+ #ifndef OPTIONAL_HDC
+ #define OPTIONAL_HDC(hdc)
+ #define DECLARE_HDC(hdc)
+ #define ALLOCATE_HDC(hdc, f)
+ #define RELEASE_HDC(hdc, f)
+ #endif
+ 
+ static void
+ init_glyph_string (s, OPTIONAL_HDC (hdc) char2b, w, row, area, start, hl)
+      struct glyph_string *s;
+      DECLARE_HDC (hdc)
+      XChar2b *char2b;
+      struct window *w;
+      struct glyph_row *row;
+      enum glyph_row_area area;
+      int start;
+      enum draw_glyphs_face hl;
+ {
+   bzero (s, sizeof *s);
+   s->w = w;
+   s->f = XFRAME (w->frame);
+ #ifdef HAVE_NTGUI
+   s->hdc = hdc;
+ #endif
+   s->display = FRAME_X_DISPLAY (s->f);
+   s->window = FRAME_X_WINDOW (s->f);
+   s->char2b = char2b;
+   s->hl = hl;
+   s->row = row;
+   s->area = area;
+   s->first_glyph = row->glyphs[area] + start;
+   s->height = row->height;
+   s->y = WINDOW_TO_FRAME_PIXEL_Y (w, row->y);
+ 
+   /* Display the internal border below the tool-bar window.  */
+   if (s->w == XWINDOW (s->f->tool_bar_window))
+     s->y -= FRAME_INTERNAL_BORDER_WIDTH (s->f);
+ 
+   s->ybase = s->y + row->ascent;
+ }
+ 
+ 
+ /* Append the list of glyph strings with head H and tail T to the list
+    with head *HEAD and tail *TAIL.  Set *HEAD and *TAIL to the result.  */
+ 
+ static INLINE void
+ append_glyph_string_lists (head, tail, h, t)
+      struct glyph_string **head, **tail;
+      struct glyph_string *h, *t;
+ {
+   if (h)
+     {
+       if (*head)
+       (*tail)->next = h;
+       else
+       *head = h;
+       h->prev = *tail;
+       *tail = t;
+     }
+ }
+ 
+ 
+ /* Prepend the list of glyph strings with head H and tail T to the
+    list with head *HEAD and tail *TAIL.  Set *HEAD and *TAIL to the
+    result.  */
+ 
+ static INLINE void
+ prepend_glyph_string_lists (head, tail, h, t)
+      struct glyph_string **head, **tail;
+      struct glyph_string *h, *t;
+ {
+   if (h)
+     {
+       if (*head)
+       (*head)->prev = t;
+       else
+       *tail = t;
+       t->next = *head;
+       *head = h;
+     }
+ }
+ 
+ 
+ /* Append glyph string S to the list with head *HEAD and tail *TAIL.
+    Set *HEAD and *TAIL to the resulting list.  */
+ 
+ static INLINE void
+ append_glyph_string (head, tail, s)
+      struct glyph_string **head, **tail;
+      struct glyph_string *s;
+ {
+   s->next = s->prev = NULL;
+   append_glyph_string_lists (head, tail, s, s);
+ }
+ 
+ 
+ /* Get face and two-byte form of character glyph GLYPH on frame F.
+    The encoding of GLYPH->u.ch is returned in *CHAR2B.  Value is
+    a pointer to a realized face that is ready for display.  */
+ 
+ static INLINE struct face *
+ get_glyph_face_and_encoding (f, glyph, char2b, two_byte_p)
+      struct frame *f;
+      struct glyph *glyph;
+      XChar2b *char2b;
+      int *two_byte_p;
+ {
+   struct face *face;
+ 
+   xassert (glyph->type == CHAR_GLYPH);
+   face = FACE_FROM_ID (f, glyph->face_id);
+ 
+   if (two_byte_p)
+     *two_byte_p = 0;
+ 
+   if (!glyph->multibyte_p)
+     {
+       /* Unibyte case.  We don't have to encode, but we have to make
+        sure to use a face suitable for unibyte.  */
+       STORE_XCHAR2B (char2b, 0, glyph->u.ch);
+     }
+   else if (glyph->u.ch < 128
+          && glyph->face_id < BASIC_FACE_ID_SENTINEL)
+     {
+       /* Case of ASCII in a face known to fit ASCII.  */
+       STORE_XCHAR2B (char2b, 0, glyph->u.ch);
+     }
+   else
+     {
+       struct font_info *font_info
+       = FONT_INFO_FROM_ID (f, face->font_info_id);
+       if (font_info)
+       {
+         struct charset *charset = CHARSET_FROM_ID (font_info->charset);
+         unsigned code = ENCODE_CHAR (charset, glyph->u.ch);
+ 
+         if (CHARSET_DIMENSION (charset) == 1)
+           STORE_XCHAR2B (char2b, 0, code);
+         else
+           STORE_XCHAR2B (char2b, (code >> 8), (code & 0xFF));
+ 
+         /* Maybe encode the character in *CHAR2B.  */
+         if (CHARSET_ID (charset) != charset_ascii)
+           {
+             glyph->font_type
+               = rif->encode_char (glyph->u.ch, char2b, font_info, charset,
+                                   two_byte_p);
+           }
+       }
+     }
+ 
+   /* Make sure X resources of the face are allocated.  */
+   xassert (face != NULL);
+   PREPARE_FACE_FOR_DISPLAY (f, face);
+   return face;
+ }
+ 
+ 
+ /* Fill glyph string S with composition components specified by S->cmp.
+ 
+    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.
+ 
+    Value is the index of a component not in S.  */
+ 
+ static int
+ fill_composite_glyph_string (s, faces, overlaps_p)
+      struct glyph_string *s;
+      struct face **faces;
+      int overlaps_p;
+ {
+   int i;
+ 
+   xassert (s);
+ 
+   s->for_overlaps_p = overlaps_p;
+ 
+   s->face = faces[s->gidx];
+   s->font = s->face->font;
+   s->font_info = FONT_INFO_FROM_ID (s->f, s->face->font_info_id);
+ 
+   /* For all glyphs of this composition, starting at the offset
+      S->gidx, until we reach the end of the definition or encounter a
+      glyph that requires the different face, add it to S.  */
+   ++s->nchars;
+   for (i = s->gidx + 1; i < s->cmp->glyph_len && faces[i] == s->face; ++i)
+     ++s->nchars;
+ 
+   /* All glyph strings for the same composition has the same width,
+      i.e. the width set for the first component of the composition.  */
+ 
+   s->width = s->first_glyph->pixel_width;
+ 
+   /* If the specified font could not be loaded, use the frame's
+      default font, but record the fact that we couldn't load it in
+      the glyph string so that we can draw rectangles for the
+      characters of the glyph string.  */
+   if (s->font == NULL)
+     {
+       s->font_not_found_p = 1;
+       s->font = FRAME_FONT (s->f);
+     }
+ 
+   /* Adjust base line for subscript/superscript text.  */
+   s->ybase += s->first_glyph->voffset;
+ 
+   xassert (s->face && s->face->gc);
+ 
+   /* This glyph string must always be drawn with 16-bit functions.  */
+   s->two_byte_p = 1;
+ 
+   return s->gidx + s->nchars;
+ }
+ 
+ 
+ /* Fill glyph string S from a sequence of character glyphs.
+ 
+    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.
+ 
+    Value is the index of the first glyph not in S.  */
+ 
+ static int
+ fill_glyph_string (s, face_id, start, end, overlaps_p)
+      struct glyph_string *s;
+      int face_id;
+      int start, end, overlaps_p;
+ {
+   struct glyph *glyph, *last;
+   int voffset;
+   int glyph_not_available_p;
+ 
+   xassert (s->f == XFRAME (s->w->frame));
+   xassert (s->nchars == 0);
+   xassert (start >= 0 && end > start);
+ 
+   s->for_overlaps_p = overlaps_p,
+   glyph = s->row->glyphs[s->area] + start;
+   last = s->row->glyphs[s->area] + end;
+   voffset = glyph->voffset;
+ 
+   glyph_not_available_p = glyph->glyph_not_available_p;
+ 
+   while (glyph < last
+        && glyph->type == CHAR_GLYPH
+        && glyph->voffset == voffset
+        /* Same face id implies same font, nowadays.  */
+        && glyph->face_id == face_id
+        && glyph->glyph_not_available_p == glyph_not_available_p)
+     {
+       int two_byte_p;
+ 
+       s->face = get_glyph_face_and_encoding (s->f, glyph,
+                                              s->char2b + s->nchars,
+                                              &two_byte_p);
+       s->two_byte_p = two_byte_p;
+       ++s->nchars;
+       xassert (s->nchars <= end - start);
+       s->width += glyph->pixel_width;
+       ++glyph;
+     }
+ 
+   s->font = s->face->font;
+   s->font_info = FONT_INFO_FROM_ID (s->f, s->face->font_info_id);
+ 
+   /* If the specified font could not be loaded, use the frame's font,
+      but record the fact that we couldn't load it in
+      S->font_not_found_p so that we can draw rectangles for the
+      characters of the glyph string.  */
+   if (s->font == NULL || glyph_not_available_p)
+     {
+       s->font_not_found_p = 1;
+       s->font = FRAME_FONT (s->f);
+     }
+ 
+   /* Adjust base line for subscript/superscript text.  */
+   s->ybase += voffset;
+ 
+   xassert (s->face && s->face->gc);
+   return glyph - s->row->glyphs[s->area];
+ }
+ 
+ 
+ /* Fill glyph string S from image glyph S->first_glyph.  */
+ 
+ static void
+ fill_image_glyph_string (s)
+      struct glyph_string *s;
+ {
+   xassert (s->first_glyph->type == IMAGE_GLYPH);
+   s->img = IMAGE_FROM_ID (s->f, s->first_glyph->u.img_id);
+   xassert (s->img);
+   s->face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
+   s->font = s->face->font;
+   s->width = s->first_glyph->pixel_width;
+ 
+   /* Adjust base line for subscript/superscript text.  */
+   s->ybase += s->first_glyph->voffset;
+ }
+ 
+ 
+ /* Fill glyph string S from a sequence of stretch glyphs.
+ 
+    ROW is the glyph row in which the glyphs are found, AREA is the
+    area within the row.  START is the index of the first glyph to
+    consider, END is the index of the last + 1.
+ 
+    Value is the index of the first glyph not in S.  */
+ 
+ static int
+ fill_stretch_glyph_string (s, row, area, start, end)
+      struct glyph_string *s;
+      struct glyph_row *row;
+      enum glyph_row_area area;
+      int start, end;
+ {
+   struct glyph *glyph, *last;
+   int voffset, face_id;
+ 
+   xassert (s->first_glyph->type == STRETCH_GLYPH);
+ 
+   glyph = s->row->glyphs[s->area] + start;
+   last = s->row->glyphs[s->area] + end;
+   face_id = glyph->face_id;
+   s->face = FACE_FROM_ID (s->f, face_id);
+   s->font = s->face->font;
+   s->font_info = FONT_INFO_FROM_ID (s->f, s->face->font_info_id);
+   s->width = glyph->pixel_width;
+   voffset = glyph->voffset;
+ 
+   for (++glyph;
+        (glyph < last
+       && glyph->type == STRETCH_GLYPH
+       && glyph->voffset == voffset
+       && glyph->face_id == face_id);
+        ++glyph)
+     s->width += glyph->pixel_width;
+ 
+   /* Adjust base line for subscript/superscript text.  */
+   s->ybase += voffset;
+ 
+   /* The case that face->gc == 0 is handled when drawing the glyph
+      string by calling PREPARE_FACE_FOR_DISPLAY.  */
+   xassert (s->face);
+   return glyph - s->row->glyphs[s->area];
+ }
+ 
+ 
+ /* EXPORT for RIF:
+    Set *LEFT and *RIGHT to the left and right overhang of GLYPH on
+    frame F.  Overhangs of glyphs other than type CHAR_GLYPH are
+    assumed to be zero.  */
+ 
+ void
+ x_get_glyph_overhangs (glyph, f, left, right)
+      struct glyph *glyph;
+      struct frame *f;
+      int *left, *right;
+ {
+   *left = *right = 0;
+ 
+   if (glyph->type == CHAR_GLYPH)
+     {
+       XFontStruct *font;
+       struct face *face;
+       struct font_info *font_info;
+       XChar2b char2b;
+       XCharStruct *pcm;
+ 
+       face = get_glyph_face_and_encoding (f, glyph, &char2b, NULL);
+       font = face->font;
+       font_info = FONT_INFO_FROM_ID (f, face->font_info_id);
+       if (font  /* ++KFS: Should this be font_info ?  */
+         && (pcm = rif->per_char_metric (font, &char2b, glyph->font_type)))
+       {
+         if (pcm->rbearing > pcm->width)
+           *right = pcm->rbearing - pcm->width;
+         if (pcm->lbearing < 0)
+           *left = -pcm->lbearing;
+       }
+     }
+ }
+ 
+ 
+ /* Return the index of the first glyph preceding glyph string S that
+    is overwritten by S because of S's left overhang.  Value is -1
+    if no glyphs are overwritten.  */
+ 
+ static int
+ left_overwritten (s)
+      struct glyph_string *s;
+ {
+   int k;
+ 
+   if (s->left_overhang)
+     {
+       int x = 0, i;
+       struct glyph *glyphs = s->row->glyphs[s->area];
+       int first = s->first_glyph - glyphs;
+ 
+       for (i = first - 1; i >= 0 && x > -s->left_overhang; --i)
+       x -= glyphs[i].pixel_width;
+ 
+       k = i + 1;
+     }
+   else
+     k = -1;
+ 
+   return k;
+ }
+ 
+ 
+ /* Return the index of the first glyph preceding glyph string S that
+    is overwriting S because of its right overhang.  Value is -1 if no
+    glyph in front of S overwrites S.  */
+ 
+ static int
+ left_overwriting (s)
+      struct glyph_string *s;
+ {
+   int i, k, x;
+   struct glyph *glyphs = s->row->glyphs[s->area];
+   int first = s->first_glyph - glyphs;
+ 
+   k = -1;
+   x = 0;
+   for (i = first - 1; i >= 0; --i)
+     {
+       int left, right;
+       x_get_glyph_overhangs (glyphs + i, s->f, &left, &right);
+       if (x + right > 0)
+       k = i;
+       x -= glyphs[i].pixel_width;
+     }
+ 
+   return k;
+ }
+ 
+ 
+ /* Return the index of the last glyph following glyph string S that is
+    not overwritten by S because of S's right overhang.  Value is -1 if
+    no such glyph is found.  */
+ 
+ static int
+ right_overwritten (s)
+      struct glyph_string *s;
+ {
+   int k = -1;
+ 
+   if (s->right_overhang)
+     {
+       int x = 0, i;
+       struct glyph *glyphs = s->row->glyphs[s->area];
+       int first = (s->first_glyph - glyphs) + (s->cmp ? 1 : s->nchars);
+       int end = s->row->used[s->area];
+ 
+       for (i = first; i < end && s->right_overhang > x; ++i)
+       x += glyphs[i].pixel_width;
+ 
+       k = i;
+     }
+ 
+   return k;
+ }
+ 
+ 
+ /* Return the index of the last glyph following glyph string S that
+    overwrites S because of its left overhang.  Value is negative
+    if no such glyph is found.  */
+ 
+ static int
+ right_overwriting (s)
+      struct glyph_string *s;
+ {
+   int i, k, x;
+   int end = s->row->used[s->area];
+   struct glyph *glyphs = s->row->glyphs[s->area];
+   int first = (s->first_glyph - glyphs) + (s->cmp ? 1 : s->nchars);
+ 
+   k = -1;
+   x = 0;
+   for (i = first; i < end; ++i)
+     {
+       int left, right;
+       x_get_glyph_overhangs (glyphs + i, s->f, &left, &right);
+       if (x - left < 0)
+       k = i;
+       x += glyphs[i].pixel_width;
+     }
+ 
+   return k;
+ }
+ 
+ 
+ /* Get face and two-byte form of character C in face FACE_ID on frame
+    F.  The encoding of C is returned in *CHAR2B.  MULTIBYTE_P non-zero
+    means we want to display multibyte text.  DISPLAY_P non-zero means
+    make sure that X resources for the face returned are allocated.
+    Value is a pointer to a realized face that is ready for display if
+    DISPLAY_P is non-zero.  */
+ 
+ static INLINE struct face *
+ get_char_face_and_encoding (f, c, face_id, char2b, multibyte_p, display_p)
+      struct frame *f;
+      int c, face_id;
+      XChar2b *char2b;
+      int multibyte_p, display_p;
+ {
+   struct face *face = FACE_FROM_ID (f, face_id);
+ 
+   if (!multibyte_p)
+     {
+       /* Unibyte case.  We don't have to encode, but we have to make
+        sure to use a face suitable for unibyte.  */
+       STORE_XCHAR2B (char2b, 0, c);
+       face_id = FACE_FOR_CHAR (f, face, c);
+       face = FACE_FROM_ID (f, face_id);
+     }
+   else if (c < 128 && face_id < BASIC_FACE_ID_SENTINEL)
+     {
+       /* Case of ASCII in a face known to fit ASCII.  */
+       STORE_XCHAR2B (char2b, 0, c);
+     }
+   else if (face->font != NULL)
+     {
+       struct font_info *font_info
+       = FONT_INFO_FROM_ID (f, face->font_info_id);
+       struct charset *charset = CHARSET_FROM_ID (font_info->charset);
+       unsigned code = ENCODE_CHAR (charset, c);
+ 
+       if (CHARSET_DIMENSION (charset) == 1)
+       STORE_XCHAR2B (char2b, 0, code);
+       else
+       STORE_XCHAR2B (char2b, (code >> 8), (code & 0xFF));
+        /* Maybe encode the character in *CHAR2B.  */
+       rif->encode_char (c, char2b, font_info, charset, NULL);
+     }
+ 
+   /* Make sure X resources of the face are allocated.  */
+ #ifdef HAVE_X_WINDOWS
+   if (display_p)
+ #endif
+     {
+       xassert (face != NULL);
+       PREPARE_FACE_FOR_DISPLAY (f, face);
+     }
+ 
+   return face;
+ }
+ 
+ 
+ /* Set background width of glyph string S.  START is the index of the
+    first glyph following S.  LAST_X is the right-most x-position + 1
+    in the drawing area.  */
+ 
+ static INLINE void
+ set_glyph_string_background_width (s, start, last_x)
+      struct glyph_string *s;
+      int start;
+      int 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;
+ 
+   /* 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
+      area.  */
+   if (s->extends_to_end_of_line_p)
+     s->background_width = last_x - s->x + 1;
+   else
+     s->background_width = s->width;
+ }
+ 
+ 
+ /* Compute overhangs and x-positions for glyph string S and its
+    predecessors, or successors.  X is the starting x-position for S.
+    BACKWARD_P non-zero means process predecessors.  */
+ 
+ static void
+ compute_overhangs_and_x (s, x, backward_p)
+      struct glyph_string *s;
+      int x;
+      int backward_p;
+ {
+   if (backward_p)
+     {
+       while (s)
+       {
+         if (rif->compute_glyph_string_overhangs)
+           rif->compute_glyph_string_overhangs (s);
+         x -= s->width;
+         s->x = x;
+         s = s->prev;
+       }
+     }
+   else
+     {
+       while (s)
+       {
+         if (rif->compute_glyph_string_overhangs)
+           rif->compute_glyph_string_overhangs (s);
+         s->x = x;
+         x += s->width;
+         s = s->next;
+       }
+     }
+ }
+ 
+ 
+ 
+ /* The following macros are only called from draw_glyphs below.
+    They reference the following parameters of that function directly:
+      `w', `row', `area', and `overlap_p'
+    as well as the following local variables:
+      `s', `f', and `hdc' (in W32)  */
+ 
+ #ifdef HAVE_NTGUI
+ /* On W32, silently add local `hdc' variable to argument list of
+    init_glyph_string.  */
+ #define INIT_GLYPH_STRING(s, char2b, w, row, area, start, hl) \
+   init_glyph_string (s, hdc, char2b, w, row, area, start, hl)
+ #else
+ #define INIT_GLYPH_STRING(s, char2b, w, row, area, start, hl) \
+   init_glyph_string (s, char2b, w, row, area, start, hl)
+ #endif
+ 
+ /* Add a glyph string for a stretch glyph to the list of strings
+    between HEAD and TAIL.  START is the index of the stretch glyph in
+    row area AREA of glyph row ROW.  END is the index of the last glyph
+    in that glyph row area.  X is the current output position assigned
+    to the new glyph string constructed.  HL overrides that face of the
+    glyph; e.g. it is DRAW_CURSOR if a cursor has to be drawn.  LAST_X
+    is the right-most x-position of the drawing area.  */
+ 
+ /* SunOS 4 bundled cc, barfed on continuations in the arg lists here
+    and below -- keep them on one line.  */
+ #define BUILD_STRETCH_GLYPH_STRING(START, END, HEAD, TAIL, HL, X, LAST_X)   \
+      do                                                                       
    \
+        {                                                                  \
+        s = (struct glyph_string *) alloca (sizeof *s);                    \
+        INIT_GLYPH_STRING (s, NULL, w, row, area, START, HL);              \
+        START = fill_stretch_glyph_string (s, row, area, START, END);      \
+        append_glyph_string (&HEAD, &TAIL, s);                             \
+          s->x = (X);                                                      \
+        }                                                                  \
+      while (0)
+ 
+ 
+ /* Add a glyph string for an image glyph to the list of strings
+    between HEAD and TAIL.  START is the index of the image glyph in
+    row area AREA of glyph row ROW.  END is the index of the last glyph
+    in that glyph row area.  X is the current output position assigned
+    to the new glyph string constructed.  HL overrides that face of the
+    glyph; e.g. it is DRAW_CURSOR if a cursor has to be drawn.  LAST_X
+    is the right-most x-position of the drawing area.  */
+ 
+ #define BUILD_IMAGE_GLYPH_STRING(START, END, HEAD, TAIL, HL, X, LAST_X) \
+      do                                                                       
\
+        {                                                              \
+        s = (struct glyph_string *) alloca (sizeof *s);                \
+        INIT_GLYPH_STRING (s, NULL, w, row, area, START, HL);          \
+        fill_image_glyph_string (s);                                   \
+        append_glyph_string (&HEAD, &TAIL, s);                         \
+        ++START;                                                       \
+          s->x = (X);                                                  \
+        }                                                              \
+      while (0)
+ 
+ 
+ /* Add a glyph string for a sequence of character glyphs to the list
+    of strings between HEAD and TAIL.  START is the index of the first
+    glyph in row area AREA of glyph row ROW that is part of the new
+    glyph string.  END is the index of the last glyph in that glyph row
+    area.  X is the current output position assigned to the new glyph
+    string constructed.  HL overrides that face of the glyph; e.g. it
+    is DRAW_CURSOR if a cursor has to be drawn.  LAST_X is the
+    right-most x-position of the drawing area.  */
+ 
+ #define BUILD_CHAR_GLYPH_STRINGS(START, END, HEAD, TAIL, HL, X, LAST_X)       
   \
+      do                                                                       
   \
+        {                                                                 \
+        int c, face_id;                                                   \
+        XChar2b *char2b;                                                  \
+                                                                          \
+        c = (row)->glyphs[area][START].u.ch;                              \
+        face_id = (row)->glyphs[area][START].face_id;                     \
+                                                                          \
+        s = (struct glyph_string *) alloca (sizeof *s);                   \
+        char2b = (XChar2b *) alloca ((END - START) * sizeof *char2b);     \
+        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);   \
+        }                                                                 \
+      while (0)
+ 
+ 
+ /* Add a glyph string for a composite sequence to the list of strings
+    between HEAD and TAIL.  START is the index of the first glyph in
+    row area AREA of glyph row ROW that is part of the new glyph
+    string.  END is the index of the last glyph in that glyph row area.
+    X is the current output position assigned to the new glyph string
+    constructed.  HL overrides that face of the glyph; e.g. it is
+    DRAW_CURSOR if a cursor has to be drawn.  LAST_X is the right-most
+    x-position of the drawing area.  */
+ 
+ #define BUILD_COMPOSITE_GLYPH_STRING(START, END, HEAD, TAIL, HL, X, LAST_X) \
+   do {                                                                        
  \
+     int cmp_id = (row)->glyphs[area][START].u.cmp_id;                   \
+     int face_id = (row)->glyphs[area][START].face_id;                   \
+     struct face *base_face = FACE_FROM_ID (f, face_id);                       
  \
+     struct composition *cmp = composition_table[cmp_id];                \
+     int glyph_len = cmp->glyph_len;                                     \
+     XChar2b *char2b;                                                    \
+     struct face **faces;                                                \
+     struct glyph_string *first_s = NULL;                                \
+     int n;                                                              \
+                                                                         \
+     base_face = base_face->ascii_face;                                        
  \
+     char2b = (XChar2b *) alloca ((sizeof *char2b) * glyph_len);               
  \
+     faces = (struct face **) alloca ((sizeof *faces) * glyph_len);      \
+     /* At first, fill in `char2b' and `faces'.  */                      \
+     for (n = 0; n < glyph_len; n++)                                     \
+       {                                                                       
  \
+       int c = COMPOSITION_GLYPH (cmp, n);                               \
+       int this_face_id = FACE_FOR_CHAR (f, base_face, c);               \
+       faces[n] = FACE_FROM_ID (f, this_face_id);                        \
+       get_char_face_and_encoding (f, c, this_face_id,                   \
+                                   char2b + n, 1, 1);                    \
+       }                                                                       
  \
+                                                                         \
+     /* Make glyph_strings for each glyph sequence that is drawable by   \
+        the same face, and append them to HEAD/TAIL.  */                       
  \
+     for (n = 0; n < cmp->glyph_len;)                                    \
+       {                                                                       
  \
+       s = (struct glyph_string *) alloca (sizeof *s);                   \
+       INIT_GLYPH_STRING (s, char2b + n, w, row, area, START, HL);       \
+       append_glyph_string (&(HEAD), &(TAIL), s);                        \
+       s->cmp = cmp;                                                     \
+       s->gidx = n;                                                      \
+       s->x = (X);                                                       \
+                                                                         \
+       if (n == 0)                                                       \
+         first_s = s;                                                    \
+                                                                         \
+       n = fill_composite_glyph_string (s, faces, overlaps_p);           \
+       }                                                                       
  \
+                                                                         \
+     ++START;                                                            \
+     s = first_s;                                                        \
+   } while (0)
+ 
+ 
+ /* Build a list of glyph strings between HEAD and TAIL for the glyphs
+    of AREA of glyph row ROW on window W between indices START and END.
+    HL overrides the face for drawing glyph strings, e.g. it is
+    DRAW_CURSOR to draw a cursor.  X and LAST_X are start and end
+    x-positions of the drawing area.
+ 
+    This is an ugly monster macro construct because we must use alloca
+    to allocate glyph strings (because draw_glyphs can be called
+    asynchronously).  */
+ 
+ #define BUILD_GLYPH_STRINGS(START, END, HEAD, TAIL, HL, X, LAST_X)       \
+      do                                                                       
   \
+        {                                                                 \
+        HEAD = TAIL = NULL;                                               \
+        while (START < END)                                               \
+          {                                                               \
+              struct glyph *first_glyph = (row)->glyphs[area] + START;    \
+              switch (first_glyph->type)                                       
   \
+              {                                                           \
+              case CHAR_GLYPH:                                            \
+                  BUILD_CHAR_GLYPH_STRINGS (START, END, HEAD, TAIL,       \
+                                          HL, X, LAST_X);                 \
+                break;                                                    \
+                                                                          \
+              case COMPOSITE_GLYPH:                                       \
+                  BUILD_COMPOSITE_GLYPH_STRING (START, END, HEAD, TAIL,        
   \
+                                              HL, X, LAST_X);             \
+                break;                                                    \
+                                                                          \
+              case STRETCH_GLYPH:                                         \
+                BUILD_STRETCH_GLYPH_STRING (START, END, HEAD, TAIL,       \
+                                            HL, X, LAST_X);               \
+                break;                                                    \
+                                                                          \
+              case IMAGE_GLYPH:                                           \
+                BUILD_IMAGE_GLYPH_STRING (START, END, HEAD, TAIL,         \
+                                          HL, X, LAST_X);                 \
+                break;                                                    \
+                                                                          \
+              default:                                                    \
+                abort ();                                                 \
+              }                                                           \
+                                                                          \
+              set_glyph_string_background_width (s, START, LAST_X);       \
+            (X) += s->width;                                              \
+             }                                                            \
+        }                                                                 \
+      while (0)
+ 
+ 
+ /* Draw glyphs between START and END in AREA of ROW on window W,
+    starting at x-position X.  X is relative to AREA in W.  HL is a
+    face-override with the following meaning:
+ 
+    DRAW_NORMAL_TEXT   draw normally
+    DRAW_CURSOR                draw in cursor face
+    DRAW_MOUSE_FACE    draw in mouse face.
+    DRAW_INVERSE_VIDEO draw in mode line face
+    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.
+ 
+    Value is the x-position reached, relative to AREA of W.  */
+ 
+ static int
+ draw_glyphs (w, x, row, area, start, end, hl, overlaps_p)
+      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;
+ {
+   struct glyph_string *head, *tail;
+   struct glyph_string *s;
+   int last_x, area_width;
+   int x_reached;
+   int i, j;
+   struct frame *f = XFRAME (WINDOW_FRAME (w));
+   DECLARE_HDC (hdc);
+ 
+   ALLOCATE_HDC (hdc, f);
+ 
+   /* Let's rather be paranoid than getting a SEGV.  */
+   end = min (end, row->used[area]);
+   start = max (0, start);
+   start = min (end, start);
+ 
+   /* Translate X to frame coordinates.  Set last_x to the right
+      end of the drawing area.  */
+   if (row->full_width_p)
+     {
+       /* X is relative to the left edge of W, without scroll bars
+        or fringes.  */
+       x += WINDOW_LEFT_EDGE_X (w);
+       last_x = WINDOW_LEFT_EDGE_X (w) + WINDOW_TOTAL_WIDTH (w);
+     }
+   else
+     {
+       int area_left = window_box_left (w, area);
+       x += area_left;
+       area_width = window_box_width (w, area);
+       last_x = area_left + area_width;
+     }
+ 
+   /* Build a doubly-linked list of glyph_string structures between
+      head and tail from what we have to draw.  Note that the macro
+      BUILD_GLYPH_STRINGS will modify its start parameter.  That's
+      the reason we use a separate variable `i'.  */
+   i = start;
+   BUILD_GLYPH_STRINGS (i, end, head, tail, hl, x, last_x);
+   if (tail)
+     x_reached = tail->x + tail->background_width;
+   else
+     x_reached = x;
+ 
+   /* 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)
+     {
+       int dummy_x = 0;
+       struct glyph_string *h, *t;
+ 
+       /* Compute overhangs for all glyph strings.  */
+       if (rif->compute_glyph_string_overhangs)
+       for (s = head; s; s = s->next)
+         rif->compute_glyph_string_overhangs (s);
+ 
+       /* Prepend glyph strings for glyphs in front of the first glyph
+        string that are overwritten because of the first glyph
+        string's left overhang.  The background of all strings
+        prepended must be drawn because the first glyph string
+        draws over it.  */
+       i = left_overwritten (head);
+       if (i >= 0)
+       {
+         j = i;
+         BUILD_GLYPH_STRINGS (j, start, h, t,
+                              DRAW_NORMAL_TEXT, dummy_x, last_x);
+         start = i;
+         compute_overhangs_and_x (t, head->x, 1);
+         prepend_glyph_string_lists (&head, &tail, h, t);
+       }
+ 
+       /* Prepend glyph strings for glyphs in front of the first glyph
+        string that overwrite that glyph string because of their
+        right overhang.  For these strings, only the foreground must
+        be drawn, because it draws over the glyph string at `head'.
+        The background must not be drawn because this would overwrite
+        right overhangs of preceding glyphs for which no glyph
+        strings exist.  */
+       i = left_overwriting (head);
+       if (i >= 0)
+       {
+         BUILD_GLYPH_STRINGS (i, start, h, t,
+                              DRAW_NORMAL_TEXT, dummy_x, last_x);
+         for (s = h; s; s = s->next)
+           s->background_filled_p = 1;
+         compute_overhangs_and_x (t, head->x, 1);
+         prepend_glyph_string_lists (&head, &tail, h, t);
+       }
+ 
+       /* Append glyphs strings for glyphs following the last glyph
+        string tail that are overwritten by tail.  The background of
+        these strings has to be drawn because tail's foreground draws
+        over it.  */
+       i = right_overwritten (tail);
+       if (i >= 0)
+       {
+         BUILD_GLYPH_STRINGS (end, i, h, t,
+                              DRAW_NORMAL_TEXT, x, last_x);
+         compute_overhangs_and_x (h, tail->x + tail->width, 0);
+         append_glyph_string_lists (&head, &tail, h, t);
+       }
+ 
+       /* Append glyph strings for glyphs following the last glyph
+        string tail that overwrite tail.  The foreground of such
+        glyphs has to be drawn because it writes into the background
+        of tail.  The background must not be drawn because it could
+        paint over the foreground of following glyphs.  */
+       i = right_overwriting (tail);
+       if (i >= 0)
+       {
+         BUILD_GLYPH_STRINGS (end, i, h, t,
+                              DRAW_NORMAL_TEXT, x, last_x);
+         for (s = h; s; s = s->next)
+           s->background_filled_p = 1;
+         compute_overhangs_and_x (h, tail->x + tail->width, 0);
+         append_glyph_string_lists (&head, &tail, h, t);
+       }
+     }
+ 
+   /* Draw all strings.  */
+   for (s = head; s; s = s->next)
+     rif->draw_glyph_string (s);
+ 
+   if (area == TEXT_AREA
+       && !row->full_width_p
+       /* When drawing overlapping rows, only the glyph strings'
+        foreground is drawn, which doesn't erase a cursor
+        completely. */
+       && !overlaps_p)
+     {
+       int x0 = head ? head->x : x;
+       int x1 = tail ? tail->x + tail->background_width : x;
+ 
+       int text_left = window_box_left (w, TEXT_AREA);
+       x0 -= text_left;
+       x1 -= text_left;
+ 
+       notice_overwritten_cursor (w, TEXT_AREA, x0, x1,
+                                row->y, MATRIX_ROW_BOTTOM_Y (row));
+     }
+ 
+   /* Value is the x-position up to which drawn, relative to AREA of W.
+      This doesn't include parts drawn because of overhangs.  */
+   if (row->full_width_p)
+     x_reached = FRAME_TO_WINDOW_PIXEL_X (w, x_reached);
+   else
+     x_reached -= window_box_left (w, area);
+ 
+   RELEASE_HDC (hdc, f);
+ 
+   return x_reached;
+ }
+ 
+ 
+ /* Store one glyph for IT->char_to_display in IT->glyph_row.
+    Called from x_produce_glyphs when IT->glyph_row is non-null.  */
+ 
+ static INLINE void
+ append_glyph (it)
+      struct it *it;
+ {
+   struct glyph *glyph;
+   enum glyph_row_area area = it->area;
+ 
+   xassert (it->glyph_row);
+   xassert (it->char_to_display != '\n' && it->char_to_display != '\t');
+ 
+   glyph = it->glyph_row->glyphs[area] + it->glyph_row->used[area];
+   if (glyph < it->glyph_row->glyphs[area + 1])
+     {
+       glyph->charpos = CHARPOS (it->position);
+       glyph->object = it->object;
+       glyph->pixel_width = it->pixel_width;
+       glyph->voffset = it->voffset;
+       glyph->type = CHAR_GLYPH;
+       glyph->multibyte_p = it->multibyte_p;
+       glyph->left_box_line_p = it->start_of_box_run_p;
+       glyph->right_box_line_p = it->end_of_box_run_p;
+       glyph->overlaps_vertically_p = (it->phys_ascent > it->ascent
+                                     || it->phys_descent > it->descent);
+       glyph->padding_p = 0;
+       glyph->glyph_not_available_p = it->glyph_not_available_p;
+       glyph->face_id = it->face_id;
+       glyph->u.ch = it->char_to_display;
+       glyph->font_type = FONT_TYPE_UNKNOWN;
+       ++it->glyph_row->used[area];
+     }
+ }
+ 
+ /* Store one glyph for the composition IT->cmp_id in IT->glyph_row.
+    Called from x_produce_glyphs when IT->glyph_row is non-null.  */
+ 
+ static INLINE void
+ append_composite_glyph (it)
+      struct it *it;
+ {
+   struct glyph *glyph;
+   enum glyph_row_area area = it->area;
+ 
+   xassert (it->glyph_row);
+ 
+   glyph = it->glyph_row->glyphs[area] + it->glyph_row->used[area];
+   if (glyph < it->glyph_row->glyphs[area + 1])
+     {
+       glyph->charpos = CHARPOS (it->position);
+       glyph->object = it->object;
+       glyph->pixel_width = it->pixel_width;
+       glyph->voffset = it->voffset;
+       glyph->type = COMPOSITE_GLYPH;
+       glyph->multibyte_p = it->multibyte_p;
+       glyph->left_box_line_p = it->start_of_box_run_p;
+       glyph->right_box_line_p = it->end_of_box_run_p;
+       glyph->overlaps_vertically_p = (it->phys_ascent > it->ascent
+                                     || it->phys_descent > it->descent);
+       glyph->padding_p = 0;
+       glyph->glyph_not_available_p = 0;
+       glyph->face_id = it->face_id;
+       glyph->u.cmp_id = it->cmp_id;
+       glyph->font_type = FONT_TYPE_UNKNOWN;
+       ++it->glyph_row->used[area];
+     }
+ }
+ 
+ 
+ /* Change IT->ascent and IT->height according to the setting of
+    IT->voffset.  */
+ 
+ static INLINE void
+ take_vertical_position_into_account (it)
+      struct it *it;
+ {
+   if (it->voffset)
+     {
+       if (it->voffset < 0)
+       /* Increase the ascent so that we can display the text higher
+          in the line.  */
+       it->ascent += abs (it->voffset);
+       else
+       /* Increase the descent so that we can display the text lower
+          in the line.  */
+       it->descent += it->voffset;
+     }
+ }
+ 
+ 
+ /* Produce glyphs/get display metrics for the image IT is loaded with.
+    See the description of struct display_iterator in dispextern.h for
+    an overview of struct display_iterator.  */
+ 
+ static void
+ produce_image_glyph (it)
+      struct it *it;
+ {
+   struct image *img;
+   struct face *face;
+ 
+   xassert (it->what == IT_IMAGE);
+ 
+   face = FACE_FROM_ID (it->f, it->face_id);
+   img = IMAGE_FROM_ID (it->f, it->image_id);
+   xassert (img);
+ 
+   /* Make sure X resources of the face and image are loaded.  */
+   PREPARE_FACE_FOR_DISPLAY (it->f, face);
+   prepare_image_for_display (it->f, img);
+ 
+   it->ascent = it->phys_ascent = image_ascent (img, face);
+   it->descent = it->phys_descent = img->height + 2 * img->vmargin - 
it->ascent;
+   it->pixel_width = img->width + 2 * img->hmargin;
+ 
+   it->nglyphs = 1;
+ 
+   if (face->box != FACE_NO_BOX)
+     {
+       if (face->box_line_width > 0)
+       {
+         it->ascent += face->box_line_width;
+         it->descent += face->box_line_width;
+       }
+ 
+       if (it->start_of_box_run_p)
+       it->pixel_width += abs (face->box_line_width);
+       if (it->end_of_box_run_p)
+       it->pixel_width += abs (face->box_line_width);
+     }
+ 
+   take_vertical_position_into_account (it);
+ 
+   if (it->glyph_row)
+     {
+       struct glyph *glyph;
+       enum glyph_row_area area = it->area;
+ 
+       glyph = it->glyph_row->glyphs[area] + it->glyph_row->used[area];
+       if (glyph < it->glyph_row->glyphs[area + 1])
+       {
+         glyph->charpos = CHARPOS (it->position);
+         glyph->object = it->object;
+         glyph->pixel_width = it->pixel_width;
+         glyph->voffset = it->voffset;
+         glyph->type = IMAGE_GLYPH;
+         glyph->multibyte_p = it->multibyte_p;
+         glyph->left_box_line_p = it->start_of_box_run_p;
+         glyph->right_box_line_p = it->end_of_box_run_p;
+         glyph->overlaps_vertically_p = 0;
+           glyph->padding_p = 0;
+         glyph->glyph_not_available_p = 0;
+         glyph->face_id = it->face_id;
+         glyph->u.img_id = img->id;
+         glyph->font_type = FONT_TYPE_UNKNOWN;
+         ++it->glyph_row->used[area];
+       }
+     }
+ }
+ 
+ 
+ /* Append a stretch glyph to IT->glyph_row.  OBJECT is the source
+    of the glyph, WIDTH and HEIGHT are the width and height of the
+    stretch.  ASCENT is the percentage/100 of HEIGHT to use for the
+    ascent of the glyph (0 <= ASCENT <= 1).  */
+ 
+ static void
+ append_stretch_glyph (it, object, width, height, ascent)
+      struct it *it;
+      Lisp_Object object;
+      int width, height;
+      double ascent;
+ {
+   struct glyph *glyph;
+   enum glyph_row_area area = it->area;
+ 
+   xassert (ascent >= 0 && ascent <= 1);
+ 
+   glyph = it->glyph_row->glyphs[area] + it->glyph_row->used[area];
+   if (glyph < it->glyph_row->glyphs[area + 1])
+     {
+       glyph->charpos = CHARPOS (it->position);
+       glyph->object = object;
+       glyph->pixel_width = width;
+       glyph->voffset = it->voffset;
+       glyph->type = STRETCH_GLYPH;
+       glyph->multibyte_p = it->multibyte_p;
+       glyph->left_box_line_p = it->start_of_box_run_p;
+       glyph->right_box_line_p = it->end_of_box_run_p;
+       glyph->overlaps_vertically_p = 0;
+       glyph->padding_p = 0;
+       glyph->glyph_not_available_p = 0;
+       glyph->face_id = it->face_id;
+       glyph->u.stretch.ascent = height * ascent;
+       glyph->u.stretch.height = height;
+       glyph->font_type = FONT_TYPE_UNKNOWN;
+       ++it->glyph_row->used[area];
+     }
+ }
+ 
+ 
+ /* Produce a stretch glyph for iterator IT.  IT->object is the value
+    of the glyph property displayed.  The value must be a list
+    `(space KEYWORD VALUE ...)' with the following KEYWORD/VALUE pairs
+    being recognized:
+ 
+    1. `:width WIDTH' specifies that the space should be WIDTH *
+    canonical char width wide.  WIDTH may be an integer or floating
+    point number.
+ 
+    2. `:relative-width FACTOR' specifies that the width of the stretch
+    should be computed from the width of the first character having the
+    `glyph' property, and should be FACTOR times that width.
+ 
+    3. `:align-to HPOS' specifies that the space should be wide enough
+    to reach HPOS, a value in canonical character units.
+ 
+    Exactly one of the above pairs must be present.
+ 
+    4. `:height HEIGHT' specifies that the height of the stretch produced
+    should be HEIGHT, measured in canonical character units.
+ 
+    5. `:relative-height FACTOR' specifies that the height of the
+    stretch should be FACTOR times the height of the characters having
+    the glyph property.
+ 
+    Either none or exactly one of 4 or 5 must be present.
+ 
+    6. `:ascent ASCENT'  specifies that ASCENT percent of the height
+    of the stretch should be used for the ascent of the stretch.
+    ASCENT must be in the range 0 <= ASCENT <= 100.  */
+ 
+ #define NUMVAL(X)                             \
+      ((INTEGERP (X) || FLOATP (X))            \
+       ? XFLOATINT (X)                         \
+       : - 1)
+ 
+ 
+ static void
+ produce_stretch_glyph (it)
+      struct it *it;
+ {
+   /* (space :width WIDTH :height HEIGHT.  */
+   Lisp_Object prop, plist;
+   int width = 0, height = 0;
+   double ascent = 0;
+   struct face *face = FACE_FROM_ID (it->f, it->face_id);
+   XFontStruct *font = face->font ? face->font : FRAME_FONT (it->f);
+ 
+   PREPARE_FACE_FOR_DISPLAY (it->f, face);
+ 
+   /* List should start with `space'.  */
+   xassert (CONSP (it->object) && EQ (XCAR (it->object), Qspace));
+   plist = XCDR (it->object);
+ 
+   /* Compute the width of the stretch.  */
+   if (prop = Fplist_get (plist, QCwidth),
+       NUMVAL (prop) > 0)
+     /* Absolute width `:width WIDTH' specified and valid.  */
+     width = NUMVAL (prop) * FRAME_COLUMN_WIDTH (it->f);
+   else if (prop = Fplist_get (plist, QCrelative_width),
+          NUMVAL (prop) > 0)
+     {
+       /* Relative width `:relative-width FACTOR' specified and valid.
+        Compute the width of the characters having the `glyph'
+        property.  */
+       struct it it2;
+       unsigned char *p = BYTE_POS_ADDR (IT_BYTEPOS (*it));
+ 
+       it2 = *it;
+       if (it->multibyte_p)
+       {
+         int maxlen = ((IT_BYTEPOS (*it) >= GPT ? ZV : GPT)
+                       - IT_BYTEPOS (*it));
+         it2.c = STRING_CHAR_AND_LENGTH (p, maxlen, it2.len);
+       }
+       else
+       it2.c = *p, it2.len = 1;
+ 
+       it2.glyph_row = NULL;
+       it2.what = IT_CHARACTER;
+       x_produce_glyphs (&it2);
+       width = NUMVAL (prop) * it2.pixel_width;
+     }
+   else if (prop = Fplist_get (plist, QCalign_to),
+          NUMVAL (prop) > 0)
+     width = NUMVAL (prop) * FRAME_COLUMN_WIDTH (it->f) - it->current_x;
+   else
+     /* Nothing specified -> width defaults to canonical char width.  */
+     width = FRAME_COLUMN_WIDTH (it->f);
+ 
+   /* Compute height.  */
+   if (prop = Fplist_get (plist, QCheight),
+       NUMVAL (prop) > 0)
+     height = NUMVAL (prop) * FRAME_LINE_HEIGHT (it->f);
+   else if (prop = Fplist_get (plist, QCrelative_height),
+          NUMVAL (prop) > 0)
+     height = FONT_HEIGHT (font) * NUMVAL (prop);
+   else
+     height = FONT_HEIGHT (font);
+ 
+   /* 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 = Fplist_get (plist, QCascent),
+       NUMVAL (prop) > 0 && NUMVAL (prop) <= 100)
+     ascent = NUMVAL (prop) / 100.0;
+   else
+     ascent = (double) FONT_BASE (font) / FONT_HEIGHT (font);
+ 
+   if (width <= 0)
+     width = 1;
+   if (height <= 0)
+     height = 1;
+ 
+   if (it->glyph_row)
+     {
+       Lisp_Object object = it->stack[it->sp - 1].string;
+       if (!STRINGP (object))
+       object = it->w->buffer;
+       append_stretch_glyph (it, object, width, height, ascent);
+     }
+ 
+   it->pixel_width = width;
+   it->ascent = it->phys_ascent = height * ascent;
+   it->descent = it->phys_descent = height - it->ascent;
+   it->nglyphs = 1;
+ 
+   if (face->box != FACE_NO_BOX)
+     {
+       if (face->box_line_width > 0)
+       {
+         it->ascent += face->box_line_width;
+         it->descent += face->box_line_width;
+       }
+ 
+       if (it->start_of_box_run_p)
+       it->pixel_width += abs (face->box_line_width);
+       if (it->end_of_box_run_p)
+       it->pixel_width += abs (face->box_line_width);
+     }
+ 
+   take_vertical_position_into_account (it);
+ }
+ 
+ /* 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.  */
+ 
+ void
+ x_produce_glyphs (it)
+      struct it *it;
+ {
+   it->glyph_not_available_p = 0;
+ 
+   if (it->what == IT_CHARACTER)
+     {
+       XChar2b char2b;
+       XFontStruct *font;
+       struct face *face = FACE_FROM_ID (it->f, it->face_id);
+       XCharStruct *pcm;
+       int font_not_found_p;
+       struct font_info *font_info;
+       int boff;                       /* baseline offset */
+       /* We may change it->multibyte_p upon unibyte<->multibyte
+        conversion.  So, save the current value now and restore it
+        later.
+ 
+        Note: It seems that we don't have to record multibyte_p in
+        struct glyph because the character code itself tells if or
+        not the character is multibyte.  Thus, in the future, we must
+        consider eliminating the field `multibyte_p' in the struct
+        glyph.  */
+       int saved_multibyte_p = it->multibyte_p;
+ 
+       /* Maybe translate single-byte characters to multibyte, or the
+        other way.  */
+       it->char_to_display = it->c;
+       if (!ASCII_BYTE_P (it->c)
+         && ! it->multibyte_p)
+       {
+         if (SINGLE_BYTE_CHAR_P (it->c)
+             && unibyte_display_via_language_environment)
+           it->char_to_display = unibyte_char_to_multibyte (it->c);
+         if (! SINGLE_BYTE_CHAR_P (it->c))
+           {
+             it->multibyte_p = 1;
+             it->face_id = FACE_FOR_CHAR (it->f, face, it->char_to_display);
+             face = FACE_FROM_ID (it->f, it->face_id);
+           }
+       }
+ 
+       /* Get font to use.  Encode IT->char_to_display.  */
+       get_char_face_and_encoding (it->f, it->char_to_display, it->face_id,
+                                 &char2b, it->multibyte_p, 0);
+       font = face->font;
+ 
+       /* When no suitable font found, use the default font.  */
+       font_not_found_p = font == NULL;
+       if (font_not_found_p)
+       {
+         font = FRAME_FONT (it->f);
+         boff = FRAME_BASELINE_OFFSET (it->f);
+         font_info = NULL;
+       }
+       else
+       {
+         font_info = FONT_INFO_FROM_ID (it->f, face->font_info_id);
+         boff = font_info->baseline_offset;
+         if (font_info->vertical_centering)
+           boff = VCENTER_BASELINE_OFFSET (font, it->f) - boff;
+       }
+ 
+       if (it->char_to_display >= ' '
+         && (!it->multibyte_p || it->char_to_display < 128))
+       {
+         /* Either unibyte or ASCII.  */
+         int stretched_p;
+ 
+         it->nglyphs = 1;
+ 
+         pcm = rif->per_char_metric (font, &char2b,
+                                     FONT_TYPE_FOR_UNIBYTE (font, 
it->char_to_display));
+         it->ascent = FONT_BASE (font) + boff;
+         it->descent = FONT_DESCENT (font) - boff;
+ 
+         if (pcm)
+           {
+             it->phys_ascent = pcm->ascent + boff;
+             it->phys_descent = pcm->descent - boff;
+             it->pixel_width = pcm->width;
+           }
+         else
+           {
+             it->glyph_not_available_p = 1;
+               it->phys_ascent = FONT_BASE (font) + boff;
+               it->phys_descent = FONT_DESCENT (font) - boff;
+             it->pixel_width = FONT_WIDTH (font);
+           }
+ 
+         /* If this is a space inside a region of text with
+            `space-width' property, change its width.  */
+         stretched_p = it->char_to_display == ' ' && !NILP (it->space_width);
+         if (stretched_p)
+           it->pixel_width *= XFLOATINT (it->space_width);
+ 
+         /* If face has a box, add the box thickness to the character
+            height.  If character has a box line to the left and/or
+            right, add the box line width to the character's width.  */
+         if (face->box != FACE_NO_BOX)
+           {
+             int thick = face->box_line_width;
+ 
+             if (thick > 0)
+               {
+                 it->ascent += thick;
+                 it->descent += thick;
+               }
+             else
+               thick = -thick;
+ 
+             if (it->start_of_box_run_p)
+               it->pixel_width += thick;
+             if (it->end_of_box_run_p)
+               it->pixel_width += thick;
+           }
+ 
+         /* If face has an overline, add the height of the overline
+            (1 pixel) and a 1 pixel margin to the character height.  */
+         if (face->overline_p)
+           it->ascent += 2;
+ 
+         take_vertical_position_into_account (it);
+ 
+         /* If we have to actually produce glyphs, do it.  */
+         if (it->glyph_row)
+           {
+             if (stretched_p)
+               {
+                 /* Translate a space with a `space-width' property
+                    into a stretch glyph.  */
+                 double ascent = (double) FONT_BASE (font)
+                                 / FONT_HEIGHT (font);
+                 append_stretch_glyph (it, it->object, it->pixel_width,
+                                       it->ascent + it->descent, ascent);
+               }
+             else
+               append_glyph (it);
+ 
+             /* If characters with lbearing or rbearing are displayed
+                in this line, record that fact in a flag of the
+                glyph row.  This is used to optimize X output code.  */
+             if (pcm && (pcm->lbearing < 0 || pcm->rbearing > pcm->width))
+               it->glyph_row->contains_overlapping_glyphs_p = 1;
+           }
+       }
+       else if (it->char_to_display == '\n')
+       {
+         /* A newline has no width but we need the height of the line.  */
+         it->pixel_width = 0;
+         it->nglyphs = 0;
+         it->ascent = it->phys_ascent = FONT_BASE (font) + boff;
+         it->descent = it->phys_descent = FONT_DESCENT (font) - boff;
+ 
+         if (face->box != FACE_NO_BOX
+             && face->box_line_width > 0)
+           {
+             it->ascent += face->box_line_width;
+             it->descent += face->box_line_width;
+           }
+       }
+       else if (it->char_to_display == '\t')
+       {
+         int tab_width = it->tab_width * FRAME_COLUMN_WIDTH (it->f);
+         int x = it->current_x + it->continuation_lines_width;
+         int next_tab_x = ((1 + x + tab_width - 1) / tab_width) * tab_width;
+ 
+         /* If the distance from the current position to the next tab
+            stop is less than a canonical character width, use the
+            tab stop after that.  */
+         if (next_tab_x - x < FRAME_COLUMN_WIDTH (it->f))
+           next_tab_x += tab_width;
+ 
+         it->pixel_width = next_tab_x - x;
+         it->nglyphs = 1;
+         it->ascent = it->phys_ascent = FONT_BASE (font) + boff;
+         it->descent = it->phys_descent = FONT_DESCENT (font) - boff;
+ 
+         if (it->glyph_row)
+           {
+             double ascent = (double) it->ascent / (it->ascent + it->descent);
+             append_stretch_glyph (it, it->object, it->pixel_width,
+                                   it->ascent + it->descent, ascent);
+           }
+       }
+       else
+       {
+         /* A multi-byte character.  Assume that the display width of the
+            character is the width of the character multiplied by the
+            width of the font.  */
+ 
+         /* If we found a font, this font should give us the right
+            metrics.  If we didn't find a font, use the frame's
+            default font and calculate the width of the character by
+            multiplying the width of font by the width of the
+            character.  */
+ 
+         pcm = rif->per_char_metric (font, &char2b,
+                                     FONT_TYPE_FOR_MULTIBYTE (font, it->c));
+ 
+         if (font_not_found_p || !pcm)
+           {
+             it->glyph_not_available_p = 1;
+             it->pixel_width = (FRAME_COLUMN_WIDTH (it->f)
+                                * CHAR_WIDTH (it->char_to_display));
+             it->phys_ascent = FONT_BASE (font) + boff;
+             it->phys_descent = FONT_DESCENT (font) - boff;
+           }
+         else
+           {
+             it->pixel_width = pcm->width;
+             it->phys_ascent = pcm->ascent + boff;
+             it->phys_descent = pcm->descent - boff;
+             if (it->glyph_row
+                 && (pcm->lbearing < 0
+                     || pcm->rbearing > pcm->width))
+               it->glyph_row->contains_overlapping_glyphs_p = 1;
+           }
+         it->nglyphs = 1;
+           it->ascent = FONT_BASE (font) + boff;
+           it->descent = FONT_DESCENT (font) - boff;
+         if (face->box != FACE_NO_BOX)
+           {
+             int thick = face->box_line_width;
+ 
+             if (thick > 0)
+               {
+                 it->ascent += thick;
+                 it->descent += thick;
+               }
+             else
+               thick = - thick;
+ 
+             if (it->start_of_box_run_p)
+               it->pixel_width += thick;
+             if (it->end_of_box_run_p)
+               it->pixel_width += thick;
+           }
+ 
+         /* If face has an overline, add the height of the overline
+            (1 pixel) and a 1 pixel margin to the character height.  */
+         if (face->overline_p)
+           it->ascent += 2;
+ 
+         take_vertical_position_into_account (it);
+ 
+         if (it->glyph_row)
+           append_glyph (it);
+       }
+       it->multibyte_p = saved_multibyte_p;
+     }
+   else if (it->what == IT_COMPOSITION)
+     {
+       /* Note: A composition is represented as one glyph in the
+        glyph matrix.  There are no padding glyphs.  */
+       XChar2b char2b;
+       XFontStruct *font;
+       struct face *face = FACE_FROM_ID (it->f, it->face_id);
+       XCharStruct *pcm;
+       int font_not_found_p;
+       struct font_info *font_info;
+       int boff;                       /* baseline offset */
+       struct composition *cmp = composition_table[it->cmp_id];
+ 
+       /* Maybe translate single-byte characters to multibyte.  */
+       it->char_to_display = it->c;
+       if (unibyte_display_via_language_environment
+         && it->c >= 0200)
+       {
+         it->char_to_display = unibyte_char_to_multibyte (it->c);
+       }
+ 
+       /* Get face and font to use.  Encode IT->char_to_display.  */
+       it->face_id = FACE_FOR_CHAR (it->f, face, it->char_to_display);
+       face = FACE_FROM_ID (it->f, it->face_id);
+       get_char_face_and_encoding (it->f, it->char_to_display, it->face_id,
+                                 &char2b, it->multibyte_p, 0);
+       font = face->font;
+ 
+       /* When no suitable font found, use the default font.  */
+       font_not_found_p = font == NULL;
+       if (font_not_found_p)
+       {
+         font = FRAME_FONT (it->f);
+         boff = FRAME_BASELINE_OFFSET (it->f);
+         font_info = NULL;
+       }
+       else
+       {
+         font_info = FONT_INFO_FROM_ID (it->f, face->font_info_id);
+         boff = font_info->baseline_offset;
+         if (font_info->vertical_centering)
+           boff = VCENTER_BASELINE_OFFSET (font, it->f) - boff;
+       }
+ 
+       /* There are no padding glyphs, so there is only one glyph to
+        produce for the composition.  Important is that pixel_width,
+        ascent and descent are the values of what is drawn by
+        draw_glyphs (i.e. the values of the overall glyphs composed).  */
+       it->nglyphs = 1;
+ 
+       /* If we have not yet calculated pixel size data of glyphs of
+        the composition for the current face font, calculate them
+        now.  Theoretically, we have to check all fonts for the
+        glyphs, but that requires much time and memory space.  So,
+        here we check only the font of the first glyph.  This leads
+        to incorrect display very rarely, and C-l (recenter) can
+        correct the display anyway.  */
+       if (cmp->font != (void *) font)
+       {
+         /* Ascent and descent of the font of the first character of
+            this composition (adjusted by baseline offset).  Ascent
+            and descent of overall glyphs should not be less than
+            them respectively.  */
+         int font_ascent = FONT_BASE (font) + boff;
+         int font_descent = FONT_DESCENT (font) - boff;
+         /* Bounding box of the overall glyphs.  */
+         int leftmost, rightmost, lowest, highest;
+         int i, width, ascent, descent;
+ 
+         cmp->font = (void *) font;
+ 
+         /* Initialize the bounding box.  */
+         if (font_info
+             && (pcm = rif->per_char_metric (font, &char2b,
+                                             FONT_TYPE_FOR_MULTIBYTE (font, 
it->c))))
+           {
+             width = pcm->width;
+             ascent = pcm->ascent;
+             descent = pcm->descent;
+           }
+         else
+           {
+             width = FONT_WIDTH (font);
+             ascent = FONT_BASE (font);
+             descent = FONT_DESCENT (font);
+           }
+ 
+         rightmost = width;
+         lowest = - descent + boff;
+         highest = ascent + boff;
+         leftmost = 0;
+ 
+         if (font_info
+             && font_info->default_ascent
+             && CHAR_TABLE_P (Vuse_default_ascent)
+             && !NILP (Faref (Vuse_default_ascent,
+                              make_number (it->char_to_display))))
+           highest = font_info->default_ascent + boff;
+ 
+         /* Draw the first glyph at the normal position.  It may be
+            shifted to right later if some other glyphs are drawn at
+            the left.  */
+         cmp->offsets[0] = 0;
+         cmp->offsets[1] = boff;
+ 
+         /* Set cmp->offsets for the remaining glyphs.  */
+         for (i = 1; i < cmp->glyph_len; i++)
+           {
+             int left, right, btm, top;
+             int ch = COMPOSITION_GLYPH (cmp, i);
+             int face_id = FACE_FOR_CHAR (it->f, face, ch);
+ 
+             face = FACE_FROM_ID (it->f, face_id);
+             get_char_face_and_encoding (it->f, ch, face->id,
+                                         &char2b, it->multibyte_p, 0);
+             font = face->font;
+             if (font == NULL)
+               {
+                 font = FRAME_FONT (it->f);
+                 boff = FRAME_BASELINE_OFFSET (it->f);
+                 font_info = NULL;
+               }
+             else
+               {
+                 font_info
+                   = FONT_INFO_FROM_ID (it->f, face->font_info_id);
+                 boff = font_info->baseline_offset;
+                 if (font_info->vertical_centering)
+                   boff = VCENTER_BASELINE_OFFSET (font, it->f) - boff;
+               }
+ 
+             if (font_info
+                 && (pcm = rif->per_char_metric (font, &char2b,
+                                                 FONT_TYPE_FOR_MULTIBYTE 
(font, ch))))
+               {
+                 width = pcm->width;
+                 ascent = pcm->ascent;
+                 descent = pcm->descent;
+               }
+             else
+               {
+                 width = FONT_WIDTH (font);
+                 ascent = 1;
+                 descent = 0;
+               }
+ 
+             if (cmp->method != COMPOSITION_WITH_RULE_ALTCHARS)
+               {
+                 /* Relative composition with or without
+                    alternate chars.  */
+                 left = (leftmost + rightmost - width) / 2;
+                 btm = - descent + boff;
+                 if (font_info && font_info->relative_compose
+                     && (! CHAR_TABLE_P (Vignore_relative_composition)
+                         || NILP (Faref (Vignore_relative_composition,
+                                         make_number (ch)))))
+                   {
+ 
+                     if (- descent >= font_info->relative_compose)
+                       /* One extra pixel between two glyphs.  */
+                       btm = highest + 1;
+                     else if (ascent <= 0)
+                       /* One extra pixel between two glyphs.  */
+                       btm = lowest - 1 - ascent - descent;
+                   }
+               }
+             else
+               {
+                 /* A composition rule is specified by an integer
+                    value that encodes global and new reference
+                    points (GREF and NREF).  GREF and NREF are
+                    specified by numbers as below:
+ 
+                       0---1---2 -- ascent
+                       |       |
+                       |       |
+                       |       |
+                       9--10--11 -- center
+                       |       |
+                    ---3---4---5--- baseline
+                       |       |
+                       6---7---8 -- descent
+                 */
+                 int rule = COMPOSITION_RULE (cmp, i);
+                 int gref, nref, grefx, grefy, nrefx, nrefy;
+ 
+                 COMPOSITION_DECODE_RULE (rule, gref, nref);
+                 grefx = gref % 3, nrefx = nref % 3;
+                 grefy = gref / 3, nrefy = nref / 3;
+ 
+                 left = (leftmost
+                         + grefx * (rightmost - leftmost) / 2
+                         - nrefx * width / 2);
+                 btm = ((grefy == 0 ? highest
+                         : grefy == 1 ? 0
+                         : grefy == 2 ? lowest
+                         : (highest + lowest) / 2)
+                        - (nrefy == 0 ? ascent + descent
+                           : nrefy == 1 ? descent - boff
+                           : nrefy == 2 ? 0
+                           : (ascent + descent) / 2));
+               }
+ 
+             cmp->offsets[i * 2] = left;
+             cmp->offsets[i * 2 + 1] = btm + descent;
+ 
+             /* Update the bounding box of the overall glyphs. */
+             right = left + width;
+             top = btm + descent + ascent;
+             if (left < leftmost)
+               leftmost = left;
+             if (right > rightmost)
+               rightmost = right;
+             if (top > highest)
+               highest = top;
+             if (btm < lowest)
+               lowest = btm;
+           }
+ 
+         /* If there are glyphs whose x-offsets are negative,
+            shift all glyphs to the right and make all x-offsets
+            non-negative.  */
+         if (leftmost < 0)
+           {
+             for (i = 0; i < cmp->glyph_len; i++)
+               cmp->offsets[i * 2] -= leftmost;
+             rightmost -= leftmost;
+           }
+ 
+         cmp->pixel_width = rightmost;
+         cmp->ascent = highest;
+         cmp->descent = - lowest;
+         if (cmp->ascent < font_ascent)
+           cmp->ascent = font_ascent;
+         if (cmp->descent < font_descent)
+           cmp->descent = font_descent;
+       }
+ 
+       it->pixel_width = cmp->pixel_width;
+       it->ascent = it->phys_ascent = cmp->ascent;
+       it->descent = it->phys_descent = cmp->descent;
+ 
+       if (face->box != FACE_NO_BOX)
+       {
+         int thick = face->box_line_width;
+ 
+         if (thick > 0)
+           {
+             it->ascent += thick;
+             it->descent += thick;
+           }
+         else
+           thick = - thick;
+ 
+         if (it->start_of_box_run_p)
+           it->pixel_width += thick;
+         if (it->end_of_box_run_p)
+           it->pixel_width += thick;
+       }
+ 
+       /* If face has an overline, add the height of the overline
+        (1 pixel) and a 1 pixel margin to the character height.  */
+       if (face->overline_p)
+       it->ascent += 2;
+ 
+       take_vertical_position_into_account (it);
+ 
+       if (it->glyph_row)
+       append_composite_glyph (it);
+     }
+   else if (it->what == IT_IMAGE)
+     produce_image_glyph (it);
+   else if (it->what == IT_STRETCH)
+     produce_stretch_glyph (it);
+ 
+   /* Accumulate dimensions.  Note: can't assume that it->descent > 0
+      because this isn't true for images with `:ascent 100'.  */
+   xassert (it->ascent >= 0 && it->descent >= 0);
+   if (it->area == TEXT_AREA)
+     it->current_x += it->pixel_width;
+ 
+   it->descent += it->extra_line_spacing;
+ 
+   it->max_ascent = max (it->max_ascent, it->ascent);
+   it->max_descent = max (it->max_descent, it->descent);
+   it->max_phys_ascent = max (it->max_phys_ascent, it->phys_ascent);
+   it->max_phys_descent = max (it->max_phys_descent, it->phys_descent);
+ }
+ 
+ /* EXPORT for RIF:
+    Output LEN glyphs starting at START at the nominal cursor position.
+    Advance the nominal cursor over the text.  The global variable
+    updated_window contains the window being updated, updated_row is
+    the glyph row being updated, and updated_area is the area of that
+    row being updated.  */
+ 
+ void
+ x_write_glyphs (start, len)
+      struct glyph *start;
+      int len;
+ {
+   int x, hpos;
+ 
+   xassert (updated_window && updated_row);
+   BLOCK_INPUT;
+ 
+   /* Write glyphs.  */
+ 
+   hpos = start - updated_row->glyphs[updated_area];
+   x = draw_glyphs (updated_window, output_cursor.x,
+                  updated_row, updated_area,
+                  hpos, hpos + len,
+                  DRAW_NORMAL_TEXT, 0);
+ 
+   /* Invalidate old phys cursor if the glyph at its hpos is redrawn.  */
+   if (updated_area == TEXT_AREA
+       && updated_window->phys_cursor_on_p
+       && updated_window->phys_cursor.vpos == output_cursor.vpos
+       && updated_window->phys_cursor.hpos >= hpos
+       && updated_window->phys_cursor.hpos < hpos + len)
+     updated_window->phys_cursor_on_p = 0;
+ 
+   UNBLOCK_INPUT;
+ 
+   /* Advance the output cursor.  */
+   output_cursor.hpos += len;
+   output_cursor.x = x;
+ }
+ 
+ 
+ /* EXPORT for RIF:
+    Insert LEN glyphs from START at the nominal cursor position.   */
+ 
+ void
+ x_insert_glyphs (start, len)
+      struct glyph *start;
+      int len;
+ {
+   struct frame *f;
+   struct window *w;
+   int line_height, shift_by_width, shifted_region_width;
+   struct glyph_row *row;
+   struct glyph *glyph;
+   int frame_x, frame_y, hpos;
+ 
+   xassert (updated_window && updated_row);
+   BLOCK_INPUT;
+   w = updated_window;
+   f = XFRAME (WINDOW_FRAME (w));
+ 
+   /* Get the height of the line we are in.  */
+   row = updated_row;
+   line_height = row->height;
+ 
+   /* Get the width of the glyphs to insert.  */
+   shift_by_width = 0;
+   for (glyph = start; glyph < start + len; ++glyph)
+     shift_by_width += glyph->pixel_width;
+ 
+   /* Get the width of the region to shift right.  */
+   shifted_region_width = (window_box_width (w, updated_area)
+                         - output_cursor.x
+                         - shift_by_width);
+ 
+   /* Shift right.  */
+   frame_x = window_box_left (w, updated_area) + output_cursor.x;
+   frame_y = WINDOW_TO_FRAME_PIXEL_Y (w, output_cursor.y);
+ 
+   rif->shift_glyphs_for_insert (f, frame_x, frame_y, shifted_region_width,
+                               line_height, shift_by_width);
+ 
+   /* Write the glyphs.  */
+   hpos = start - row->glyphs[updated_area];
+   draw_glyphs (w, output_cursor.x, row, updated_area,
+              hpos, hpos + len,
+              DRAW_NORMAL_TEXT, 0);
+ 
+   /* Advance the output cursor.  */
+   output_cursor.hpos += len;
+   output_cursor.x += shift_by_width;
+   UNBLOCK_INPUT;
+ }
+ 
+ 
+ /* EXPORT for RIF:
+    Erase the current text line from the nominal cursor position
+    (inclusive) to pixel column TO_X (exclusive).  The idea is that
+    everything from TO_X onward is already erased.
+ 
+    TO_X is a pixel position relative to updated_area of
+    updated_window.  TO_X == -1 means clear to the end of this area.  */
+ 
+ void
+ x_clear_end_of_line (to_x)
+      int to_x;
+ {
+   struct frame *f;
+   struct window *w = updated_window;
+   int max_x, min_y, max_y;
+   int from_x, from_y, to_y;
+ 
+   xassert (updated_window && updated_row);
+   f = XFRAME (w->frame);
+ 
+   if (updated_row->full_width_p)
+     max_x = WINDOW_TOTAL_WIDTH (w);
+   else
+     max_x = window_box_width (w, updated_area);
+   max_y = window_text_bottom_y (w);
+ 
+   /* TO_X == 0 means don't do anything.  TO_X < 0 means clear to end
+      of window.  For TO_X > 0, truncate to end of drawing area.  */
+   if (to_x == 0)
+     return;
+   else if (to_x < 0)
+     to_x = max_x;
+   else
+     to_x = min (to_x, max_x);
+ 
+   to_y = min (max_y, output_cursor.y + updated_row->height);
+ 
+   /* Notice if the cursor will be cleared by this operation.  */
+   if (!updated_row->full_width_p)
+     notice_overwritten_cursor (w, updated_area,
+                              output_cursor.x, -1,
+                              updated_row->y,
+                              MATRIX_ROW_BOTTOM_Y (updated_row));
+ 
+   from_x = output_cursor.x;
+ 
+   /* Translate to frame coordinates.  */
+   if (updated_row->full_width_p)
+     {
+       from_x = WINDOW_TO_FRAME_PIXEL_X (w, from_x);
+       to_x = WINDOW_TO_FRAME_PIXEL_X (w, to_x);
+     }
+   else
+     {
+       int area_left = window_box_left (w, updated_area);
+       from_x += area_left;
+       to_x += area_left;
+     }
+ 
+   min_y = WINDOW_HEADER_LINE_HEIGHT (w);
+   from_y = WINDOW_TO_FRAME_PIXEL_Y (w, max (min_y, output_cursor.y));
+   to_y = WINDOW_TO_FRAME_PIXEL_Y (w, to_y);
+ 
+   /* Prevent inadvertently clearing to end of the X window.  */
+   if (to_x > from_x && to_y > from_y)
+     {
+       BLOCK_INPUT;
+       rif->clear_frame_area (f, from_x, from_y,
+                            to_x - from_x, to_y - from_y);
+       UNBLOCK_INPUT;
+     }
+ }
+ 
+ #endif /* HAVE_WINDOW_SYSTEM */
+ 
+ 
+ 
+ /***********************************************************************
+                            Cursor types
+  ***********************************************************************/
+ 
+ /* Value is the internal representation of the specified cursor type
+    ARG.  If type is BAR_CURSOR, return in *WIDTH the specified width
+    of the bar cursor.  */
+ 
+ enum text_cursor_kinds
+ get_specified_cursor_type (arg, width)
+      Lisp_Object arg;
+      int *width;
+ {
+   enum text_cursor_kinds type;
+ 
+   if (NILP (arg))
+     return NO_CURSOR;
+ 
+   if (EQ (arg, Qbox))
+     return FILLED_BOX_CURSOR;
+ 
+   if (EQ (arg, Qhollow))
+     return HOLLOW_BOX_CURSOR;
+ 
+   if (EQ (arg, Qbar))
+     {
+       *width = 2;
+       return BAR_CURSOR;
+     }
+ 
+   if (CONSP (arg)
+       && EQ (XCAR (arg), Qbar)
+       && INTEGERP (XCDR (arg))
+       && XINT (XCDR (arg)) >= 0)
+     {
+       *width = XINT (XCDR (arg));
+       return BAR_CURSOR;
+     }
+ 
+   if (EQ (arg, Qhbar))
+     {
+       *width = 2;
+       return HBAR_CURSOR;
+     }
+ 
+   if (CONSP (arg)
+       && EQ (XCAR (arg), Qhbar)
+       && INTEGERP (XCDR (arg))
+       && XINT (XCDR (arg)) >= 0)
+     {
+       *width = XINT (XCDR (arg));
+       return HBAR_CURSOR;
+     }
+ 
+   /* Treat anything unknown as "hollow box cursor".
+      It was bad to signal an error; people have trouble fixing
+      .Xdefaults with Emacs, when it has something bad in it.  */
+   type = HOLLOW_BOX_CURSOR;
+ 
+   return type;
+ }
+ 
+ /* Set the default cursor types for specified frame.  */
+ void
+ set_frame_cursor_types (f, arg)
+      struct frame *f;
+      Lisp_Object arg;
+ {
+   int width;
+   Lisp_Object tem;
+ 
+   FRAME_DESIRED_CURSOR (f) = get_specified_cursor_type (arg, &width);
+   FRAME_CURSOR_WIDTH (f) = width;
+ 
+   /* By default, set up the blink-off state depending on the on-state.  */
+ 
+   tem = Fassoc (arg, Vblink_cursor_alist);
+   if (!NILP (tem))
+     {
+       FRAME_BLINK_OFF_CURSOR (f)
+       = get_specified_cursor_type (XCDR (tem), &width);
+       FRAME_BLINK_OFF_CURSOR_WIDTH (f) = width;
+     }
+   else
+     FRAME_BLINK_OFF_CURSOR (f) = DEFAULT_CURSOR;
+ }
+ 
+ 
+ /* Return the cursor we want to be displayed in window W.  Return
+    width of bar/hbar cursor through WIDTH arg.  Return with
+    ACTIVE_CURSOR arg set to 1 if cursor in window W is `active'
+    (i.e. if the `system caret' should track this cursor).
+ 
+    In a mini-buffer window, we want the cursor only to appear if we
+    are reading input from this window.  For the selected window, we
+    want the cursor type given by the frame parameter or buffer local
+    setting of cursor-type.  If explicitly marked off, draw no cursor.
+    In all other cases, we want a hollow box cursor.  */
+ 
+ enum text_cursor_kinds
+ get_window_cursor_type (w, width, active_cursor)
+      struct window *w;
+      int *width;
+      int *active_cursor;
+ {
+   struct frame *f = XFRAME (w->frame);
+   struct buffer *b = XBUFFER (w->buffer);
+   int cursor_type = DEFAULT_CURSOR;
+   Lisp_Object alt_cursor;
+   int non_selected = 0;
+ 
+   *active_cursor = 1;
+ 
+   /* Echo area */
+   if (cursor_in_echo_area
+       && FRAME_HAS_MINIBUF_P (f)
+       && EQ (FRAME_MINIBUF_WINDOW (f), echo_area_window))
+     {
+       if (w == XWINDOW (echo_area_window))
+       {
+         *width = FRAME_CURSOR_WIDTH (f);
+         return FRAME_DESIRED_CURSOR (f);
+       }
+ 
+       *active_cursor = 0;
+       non_selected = 1;
+     }
+ 
+   /* Nonselected window or nonselected frame.  */
+   else if (w != XWINDOW (f->selected_window)
+ #ifdef HAVE_WINDOW_SYSTEM
+          || f != FRAME_X_DISPLAY_INFO (f)->x_highlight_frame
+ #endif
+          )
+     {
+       *active_cursor = 0;
+ 
+       if (MINI_WINDOW_P (w) && minibuf_level == 0)
+       return NO_CURSOR;
+ 
+       non_selected = 1;
+     }
+ 
+   /* Never display a cursor in a window in which cursor-type is nil.  */
+   if (NILP (b->cursor_type))
+     return NO_CURSOR;
+ 
+   /* Use cursor-in-non-selected-windows for non-selected window or frame.  */
+   if (non_selected)
+     {
+       alt_cursor = Fbuffer_local_value (Qcursor_in_non_selected_windows, 
w->buffer);
+       return get_specified_cursor_type (alt_cursor, width);
+     }
+ 
+   /* Get the normal cursor type for this window.  */
+   if (EQ (b->cursor_type, Qt))
+     {
+       cursor_type = FRAME_DESIRED_CURSOR (f);
+       *width = FRAME_CURSOR_WIDTH (f);
+     }
+   else
+     cursor_type = get_specified_cursor_type (b->cursor_type, width);
+ 
+   /* Use normal cursor if not blinked off.  */
+   if (!w->cursor_off_p)
+     return cursor_type;
+ 
+   /* Cursor is blinked off, so determine how to "toggle" it.  */
+ 
+   /* First look for an entry matching the buffer's cursor-type in 
blink-cursor-alist.  */
+   if ((alt_cursor = Fassoc (b->cursor_type, Vblink_cursor_alist), !NILP 
(alt_cursor)))
+     return get_specified_cursor_type (XCDR (alt_cursor), width);
+ 
+   /* Then see if frame has specified a specific blink off cursor type.  */
+   if (FRAME_BLINK_OFF_CURSOR (f) != DEFAULT_CURSOR)
+     {
+       *width = FRAME_BLINK_OFF_CURSOR_WIDTH (f);
+       return FRAME_BLINK_OFF_CURSOR (f);
+     }
+ 
+   /* Finally perform built-in cursor blinking:
+        filled box      <->   hollow box
+        wide [h]bar     <->   narrow [h]bar
+        narrow [h]bar   <->   no cursor
+        other type      <->   no cursor  */
+ 
+   if (cursor_type == FILLED_BOX_CURSOR)
+     return HOLLOW_BOX_CURSOR;
+ 
+   if ((cursor_type == BAR_CURSOR || cursor_type == HBAR_CURSOR) && *width > 1)
+     {
+       *width = 1;
+       return cursor_type;
+     }
+ 
+   return NO_CURSOR;
+ }
+ 
+ 
+ #ifdef HAVE_WINDOW_SYSTEM
+ 
+ /* Notice when the text cursor of window W has been completely
+    overwritten by a drawing operation that outputs glyphs in AREA
+    starting at X0 and ending at X1 in the line starting at Y0 and
+    ending at Y1.  X coordinates are area-relative.  X1 < 0 means all
+    the rest of the line after X0 has been written.  Y coordinates
+    are window-relative.  */
+ 
+ static void
+ notice_overwritten_cursor (w, area, x0, x1, y0, y1)
+      struct window *w;
+      enum glyph_row_area area;
+      int x0, y0, x1, y1;
+ {
+   if (area == TEXT_AREA && w->phys_cursor_on_p)
+     {
+       int cx0 = w->phys_cursor.x;
+       int cx1 = cx0 + w->phys_cursor_width;
+       int cy0 = w->phys_cursor.y;
+       int cy1 = cy0 + w->phys_cursor_height;
+ 
+       if (x0 <= cx0 && (x1 < 0 || x1 >= cx1))
+       {
+         /* The cursor image will be completely removed from the
+            screen if the output area intersects the cursor area in
+            y-direction.  When we draw in [y0 y1[, and some part of
+            the cursor is at y < y0, that part must have been drawn
+            before.  When scrolling, the cursor is erased before
+            actually scrolling, so we don't come here.  When not
+            scrolling, the rows above the old cursor row must have
+            changed, and in this case these rows must have written
+            over the cursor image.
+ 
+            Likewise if part of the cursor is below y1, with the
+            exception of the cursor being in the first blank row at
+            the buffer and window end because update_text_area
+            doesn't draw that row.  (Except when it does, but
+            that's handled in update_text_area.)  */
+ 
+         if (((y0 >= cy0 && y0 < cy1) || (y1 > cy0 && y1 < cy1))
+             && w->current_matrix->rows[w->phys_cursor.vpos].displays_text_p)
+           w->phys_cursor_on_p = 0;
+       }
+     }
+ }
+ 
+ #endif /* HAVE_WINDOW_SYSTEM */
+ 
+ 
+ /************************************************************************
+                             Mouse Face
+  ************************************************************************/
+ 
+ #ifdef HAVE_WINDOW_SYSTEM
+ 
+ /* EXPORT for RIF:
+    Fix the display of area AREA of overlapping row ROW in window W.  */
+ 
+ void
+ x_fix_overlapping_area (w, row, area)
+      struct window *w;
+      struct glyph_row *row;
+      enum glyph_row_area area;
+ {
+   int i, x;
+ 
+   BLOCK_INPUT;
+ 
+   x = 0;
+   for (i = 0; i < row->used[area];)
+     {
+       if (row->glyphs[area][i].overlaps_vertically_p)
+       {
+         int start = i, start_x = x;
+ 
+         do
+           {
+             x += row->glyphs[area][i].pixel_width;
+             ++i;
+           }
+         while (i < row->used[area]
+                && row->glyphs[area][i].overlaps_vertically_p);
+ 
+         draw_glyphs (w, start_x, row, area,
+                      start, i,
+                      DRAW_NORMAL_TEXT, 1);
+       }
+       else
+       {
+         x += row->glyphs[area][i].pixel_width;
+         ++i;
+       }
+     }
+ 
+   UNBLOCK_INPUT;
+ }
+ 
+ 
+ /* EXPORT:
+    Draw the cursor glyph of window W in glyph row ROW.  See the
+    comment of draw_glyphs for the meaning of HL.  */
+ 
+ void
+ draw_phys_cursor_glyph (w, row, hl)
+      struct window *w;
+      struct glyph_row *row;
+      enum draw_glyphs_face hl;
+ {
+   /* If cursor hpos is out of bounds, don't draw garbage.  This can
+      happen in mini-buffer windows when switching between echo area
+      glyphs and mini-buffer.  */
+   if (w->phys_cursor.hpos < row->used[TEXT_AREA])
+     {
+       int on_p = w->phys_cursor_on_p;
+       int x1;
+       x1 = draw_glyphs (w, w->phys_cursor.x, row, TEXT_AREA,
+                       w->phys_cursor.hpos, w->phys_cursor.hpos + 1,
+                       hl, 0);
+       w->phys_cursor_on_p = on_p;
+ 
+       if (hl == DRAW_CURSOR)
+       w->phys_cursor_width = x1 - w->phys_cursor.x;
+       /* When we erase the cursor, and ROW is overlapped by other
+        rows, make sure that these overlapping parts of other rows
+        are redrawn.  */
+       else if (hl == DRAW_NORMAL_TEXT && row->overlapped_p)
+       {
+         if (row > w->current_matrix->rows
+             && MATRIX_ROW_OVERLAPS_SUCC_P (row - 1))
+           x_fix_overlapping_area (w, row - 1, TEXT_AREA);
+ 
+         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);
+       }
+     }
+ }
+ 
+ 
+ /* EXPORT:
+    Erase the image of a cursor of window W from the screen.  */
+ 
+ void
+ erase_phys_cursor (w)
+      struct window *w;
+ {
+   struct frame *f = XFRAME (w->frame);
+   Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
+   int hpos = w->phys_cursor.hpos;
+   int vpos = w->phys_cursor.vpos;
+   int mouse_face_here_p = 0;
+   struct glyph_matrix *active_glyphs = w->current_matrix;
+   struct glyph_row *cursor_row;
+   struct glyph *cursor_glyph;
+   enum draw_glyphs_face hl;
+ 
+   /* No cursor displayed or row invalidated => nothing to do on the
+      screen.  */
+   if (w->phys_cursor_type == NO_CURSOR)
+     goto mark_cursor_off;
+ 
+   /* VPOS >= active_glyphs->nrows means that window has been resized.
+      Don't bother to erase the cursor.  */
+   if (vpos >= active_glyphs->nrows)
+     goto mark_cursor_off;
+ 
+   /* If row containing cursor is marked invalid, there is nothing we
+      can do.  */
+   cursor_row = MATRIX_ROW (active_glyphs, vpos);
+   if (!cursor_row->enabled_p)
+     goto mark_cursor_off;
+ 
+   /* If row is completely invisible, don't attempt to delete a cursor which
+      isn't there.  This can happen if cursor is at top of a window, and
+      we switch to a buffer with a header line in that window.  */
+   if (cursor_row->visible_height <= 0)
+     goto mark_cursor_off;
+ 
+   /* This can happen when the new row is shorter than the old one.
+      In this case, either draw_glyphs or clear_end_of_line
+      should have cleared the cursor.  Note that we wouldn't be
+      able to erase the cursor in this case because we don't have a
+      cursor glyph at hand.  */
+   if (w->phys_cursor.hpos >= cursor_row->used[TEXT_AREA])
+     goto mark_cursor_off;
+ 
+   /* If the cursor is in the mouse face area, redisplay that when
+      we clear the cursor.  */
+   if (! NILP (dpyinfo->mouse_face_window)
+       && w == XWINDOW (dpyinfo->mouse_face_window)
+       && (vpos > dpyinfo->mouse_face_beg_row
+         || (vpos == dpyinfo->mouse_face_beg_row
+             && hpos >= dpyinfo->mouse_face_beg_col))
+       && (vpos < dpyinfo->mouse_face_end_row
+         || (vpos == dpyinfo->mouse_face_end_row
+             && hpos < dpyinfo->mouse_face_end_col))
+       /* Don't redraw the cursor's spot in mouse face if it is at the
+        end of a line (on a newline).  The cursor appears there, but
+        mouse highlighting does not.  */
+       && cursor_row->used[TEXT_AREA] > hpos)
+     mouse_face_here_p = 1;
+ 
+   /* Maybe clear the display under the cursor.  */
+   if (w->phys_cursor_type == HOLLOW_BOX_CURSOR)
+     {
+       int x, y;
+       int header_line_height = WINDOW_HEADER_LINE_HEIGHT (w);
+ 
+       cursor_glyph = get_phys_cursor_glyph (w);
+       if (cursor_glyph == NULL)
+       goto mark_cursor_off;
+ 
+       x = WINDOW_TEXT_TO_FRAME_PIXEL_X (w, w->phys_cursor.x);
+       y = WINDOW_TO_FRAME_PIXEL_Y (w, max (header_line_height, 
cursor_row->y));
+ 
+       rif->clear_frame_area (f, x, y,
+                            cursor_glyph->pixel_width, 
cursor_row->visible_height);
+     }
+ 
+   /* Erase the cursor by redrawing the character underneath it.  */
+   if (mouse_face_here_p)
+     hl = DRAW_MOUSE_FACE;
+   else
+     hl = DRAW_NORMAL_TEXT;
+   draw_phys_cursor_glyph (w, cursor_row, hl);
+ 
+  mark_cursor_off:
+   w->phys_cursor_on_p = 0;
+   w->phys_cursor_type = NO_CURSOR;
+ }
+ 
+ 
+ /* EXPORT:
+    Display or clear cursor of window W.  If ON is zero, clear the
+    cursor.  If it is non-zero, display the cursor.  If ON is nonzero,
+    where to put the cursor is specified by HPOS, VPOS, X and Y.  */
+ 
+ void
+ display_and_set_cursor (w, on, hpos, vpos, x, y)
+      struct window *w;
+      int on, hpos, vpos, x, y;
+ {
+   struct frame *f = XFRAME (w->frame);
+   int new_cursor_type;
+   int new_cursor_width;
+   int active_cursor;
+   struct glyph_matrix *current_glyphs;
+   struct glyph_row *glyph_row;
+   struct glyph *glyph;
+ 
+   /* This is pointless on invisible frames, and dangerous on garbaged
+      windows and frames; in the latter case, the frame or window may
+      be in the midst of changing its size, and x and y may be off the
+      window.  */
+   if (! FRAME_VISIBLE_P (f)
+       || FRAME_GARBAGED_P (f)
+       || vpos >= w->current_matrix->nrows
+       || hpos >= w->current_matrix->matrix_w)
+     return;
+ 
+   /* If cursor is off and we want it off, return quickly.  */
+   if (!on && !w->phys_cursor_on_p)
+     return;
+ 
+   current_glyphs = w->current_matrix;
+   glyph_row = MATRIX_ROW (current_glyphs, vpos);
+   glyph = glyph_row->glyphs[TEXT_AREA] + hpos;
+ 
+   /* If cursor row is not enabled, we don't really know where to
+      display the cursor.  */
+   if (!glyph_row->enabled_p)
+     {
+       w->phys_cursor_on_p = 0;
+       return;
+     }
+ 
+   xassert (interrupt_input_blocked);
+ 
+   /* Set new_cursor_type to the cursor we want to be displayed.  */
+   new_cursor_type = get_window_cursor_type (w, &new_cursor_width, 
&active_cursor);
+ 
+   /* If cursor is currently being shown and we don't want it to be or
+      it is in the wrong place, or the cursor type is not what we want,
+      erase it.  */
+   if (w->phys_cursor_on_p
+       && (!on
+         || w->phys_cursor.x != x
+         || w->phys_cursor.y != y
+         || new_cursor_type != w->phys_cursor_type
+         || ((new_cursor_type == BAR_CURSOR || new_cursor_type == HBAR_CURSOR)
+             && new_cursor_width != w->phys_cursor_width)))
+     erase_phys_cursor (w);
+ 
+   /* Don't check phys_cursor_on_p here because that flag is only set
+      to zero in some cases where we know that the cursor has been
+      completely erased, to avoid the extra work of erasing the cursor
+      twice.  In other words, phys_cursor_on_p can be 1 and the cursor
+      still not be visible, or it has only been partly erased.  */
+   if (on)
+     {
+       w->phys_cursor_ascent = glyph_row->ascent;
+       w->phys_cursor_height = glyph_row->height;
+ 
+       /* Set phys_cursor_.* before x_draw_.* is called because some
+        of them may need the information.  */
+       w->phys_cursor.x = x;
+       w->phys_cursor.y = glyph_row->y;
+       w->phys_cursor.hpos = hpos;
+       w->phys_cursor.vpos = vpos;
+     }
+ 
+   rif->draw_window_cursor (w, glyph_row, x, y,
+                          new_cursor_type, new_cursor_width,
+                          on, active_cursor);
+ }
+ 
+ 
+ /* Switch the display of W's cursor on or off, according to the value
+    of ON.  */
+ 
+ static void
+ update_window_cursor (w, on)
+      struct window *w;
+      int on;
+ {
+   /* Don't update cursor in windows whose frame is in the process
+      of being deleted.  */
+   if (w->current_matrix)
+     {
+       BLOCK_INPUT;
+       display_and_set_cursor (w, on, w->phys_cursor.hpos, w->phys_cursor.vpos,
+                             w->phys_cursor.x, w->phys_cursor.y);
+       UNBLOCK_INPUT;
+     }
+ }
+ 
+ 
+ /* Call update_window_cursor with parameter ON_P on all leaf windows
+    in the window tree rooted at W.  */
+ 
+ static void
+ update_cursor_in_window_tree (w, on_p)
+      struct window *w;
+      int on_p;
+ {
+   while (w)
+     {
+       if (!NILP (w->hchild))
+       update_cursor_in_window_tree (XWINDOW (w->hchild), on_p);
+       else if (!NILP (w->vchild))
+       update_cursor_in_window_tree (XWINDOW (w->vchild), on_p);
+       else
+       update_window_cursor (w, on_p);
+ 
+       w = NILP (w->next) ? 0 : XWINDOW (w->next);
+     }
+ }
+ 
+ 
+ /* EXPORT:
+    Display the cursor on window W, or clear it, according to ON_P.
+    Don't change the cursor's position.  */
+ 
+ void
+ x_update_cursor (f, on_p)
+      struct frame *f;
+      int on_p;
+ {
+   update_cursor_in_window_tree (XWINDOW (f->root_window), on_p);
+ }
+ 
+ 
+ /* EXPORT:
+    Clear the cursor of window W to background color, and mark the
+    cursor as not shown.  This is used when the text where the cursor
+    is is about to be rewritten.  */
+ 
+ void
+ x_clear_cursor (w)
+      struct window *w;
+ {
+   if (FRAME_VISIBLE_P (XFRAME (w->frame)) && w->phys_cursor_on_p)
+     update_window_cursor (w, 0);
+ }
+ 
+ 
+ /* EXPORT:
+    Display the active region described by mouse_face_* according to DRAW.  */
+ 
+ void
+ show_mouse_face (dpyinfo, draw)
+      Display_Info *dpyinfo;
+      enum draw_glyphs_face draw;
+ {
+   struct window *w = XWINDOW (dpyinfo->mouse_face_window);
+   struct frame *f = XFRAME (WINDOW_FRAME (w));
+ 
+   if (/* If window is in the process of being destroyed, don't bother
+        to do anything.  */
+       w->current_matrix != NULL
+       /* Don't update mouse highlight if hidden */
+       && (draw != DRAW_MOUSE_FACE || !dpyinfo->mouse_face_hidden)
+       /* Recognize when we are called to operate on rows that don't exist
+        anymore.  This can happen when a window is split.  */
+       && dpyinfo->mouse_face_end_row < w->current_matrix->nrows)
+     {
+       int phys_cursor_on_p = w->phys_cursor_on_p;
+       struct glyph_row *row, *first, *last;
+ 
+       first = MATRIX_ROW (w->current_matrix, dpyinfo->mouse_face_beg_row);
+       last = MATRIX_ROW (w->current_matrix, dpyinfo->mouse_face_end_row);
+ 
+       for (row = first; row <= last && row->enabled_p; ++row)
+       {
+         int start_hpos, end_hpos, start_x;
+ 
+         /* For all but the first row, the highlight starts at column 0.  */
+         if (row == first)
+           {
+             start_hpos = dpyinfo->mouse_face_beg_col;
+             start_x = dpyinfo->mouse_face_beg_x;
+           }
+         else
+           {
+             start_hpos = 0;
+             start_x = 0;
+           }
+ 
+         if (row == last)
+           end_hpos = dpyinfo->mouse_face_end_col;
+         else
+           end_hpos = row->used[TEXT_AREA];
+ 
+         if (end_hpos > start_hpos)
+           {
+             draw_glyphs (w, start_x, row, TEXT_AREA,
+                          start_hpos, end_hpos,
+                          draw, 0);
+ 
+             row->mouse_face_p
+               = draw == DRAW_MOUSE_FACE || draw == DRAW_IMAGE_RAISED;
+           }
+       }
+ 
+       /* When we've written over the cursor, arrange for it to
+        be displayed again.  */
+       if (phys_cursor_on_p && !w->phys_cursor_on_p)
+       {
+         BLOCK_INPUT;
+         display_and_set_cursor (w, 1,
+                                 w->phys_cursor.hpos, w->phys_cursor.vpos,
+                                 w->phys_cursor.x, w->phys_cursor.y);
+         UNBLOCK_INPUT;
+       }
+     }
+ 
+   /* Change the mouse cursor.  */
+   if (draw == DRAW_NORMAL_TEXT)
+     rif->define_frame_cursor (f, FRAME_X_OUTPUT (f)->text_cursor);
+   else if (draw == DRAW_MOUSE_FACE)
+     rif->define_frame_cursor (f, FRAME_X_OUTPUT (f)->hand_cursor);
+   else
+     rif->define_frame_cursor (f, FRAME_X_OUTPUT (f)->nontext_cursor);
+ }
+ 
+ /* EXPORT:
+    Clear out the mouse-highlighted active region.
+    Redraw it un-highlighted first.  Value is non-zero if mouse
+    face was actually drawn unhighlighted.  */
+ 
+ int
+ clear_mouse_face (dpyinfo)
+      Display_Info *dpyinfo;
+ {
+   int cleared = 0;
+ 
+   if (!NILP (dpyinfo->mouse_face_window))
+     {
+       show_mouse_face (dpyinfo, DRAW_NORMAL_TEXT);
+       cleared = 1;
+     }
+ 
+   dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
+   dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
+   dpyinfo->mouse_face_window = Qnil;
+   dpyinfo->mouse_face_overlay = Qnil;
+   return cleared;
+ }
+ 
+ 
+ /* EXPORT:
+    Non-zero if physical cursor of window W is within mouse face.  */
+ 
+ int
+ cursor_in_mouse_face_p (w)
+      struct window *w;
+ {
+   Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (XFRAME (w->frame));
+   int in_mouse_face = 0;
+ 
+   if (WINDOWP (dpyinfo->mouse_face_window)
+       && XWINDOW (dpyinfo->mouse_face_window) == w)
+     {
+       int hpos = w->phys_cursor.hpos;
+       int vpos = w->phys_cursor.vpos;
+ 
+       if (vpos >= dpyinfo->mouse_face_beg_row
+         && vpos <= dpyinfo->mouse_face_end_row
+         && (vpos > dpyinfo->mouse_face_beg_row
+             || hpos >= dpyinfo->mouse_face_beg_col)
+         && (vpos < dpyinfo->mouse_face_end_row
+             || hpos < dpyinfo->mouse_face_end_col
+             || dpyinfo->mouse_face_past_end))
+       in_mouse_face = 1;
+     }
+ 
+   return in_mouse_face;
+ }
+ 
+ 
+ 
+ 
+ /* Find the glyph matrix position of buffer position CHARPOS in window
+    *W.  HPOS, *VPOS, *X, and *Y are set to the positions found.  W's
+    current glyphs must be up to date.  If CHARPOS is above window
+    start return (0, 0, 0, 0).  If CHARPOS is after end of W, return end
+    of last line in W.  In the row containing CHARPOS, stop before glyphs
+    having STOP as object.  */
+ 
+ #if 1 /* This is a version of fast_find_position that's more correct
+        in the presence of hscrolling, for example.  I didn't install
+        it right away because the problem fixed is minor, it failed
+        in 20.x as well, and I think it's too risky to install
+        so near the release of 21.1.  2001-09-25 gerd.  */
+ 
+ static int
+ fast_find_position (w, charpos, hpos, vpos, x, y, stop)
+      struct window *w;
+      int charpos;
+      int *hpos, *vpos, *x, *y;
+      Lisp_Object stop;
+ {
+   struct glyph_row *row, *first;
+   struct glyph *glyph, *end;
+   int past_end = 0;
+ 
+   first = MATRIX_FIRST_TEXT_ROW (w->current_matrix);
+   row = row_containing_pos (w, charpos, first, NULL, 0);
+   if (row == NULL)
+     {
+       if (charpos < MATRIX_ROW_START_CHARPOS (first))
+       {
+         *x = *y = *hpos = *vpos = 0;
+         return 0;
+       }
+       else
+       {
+         row = MATRIX_ROW (w->current_matrix, XFASTINT (w->window_end_vpos));
+         past_end = 1;
+       }
+     }
+ 
+   *x = row->x;
+   *y = row->y;
+   *vpos = MATRIX_ROW_VPOS (row, w->current_matrix);
+ 
+   glyph = row->glyphs[TEXT_AREA];
+   end = glyph + row->used[TEXT_AREA];
+ 
+   /* Skip over glyphs not having an object at the start of the row.
+      These are special glyphs like truncation marks on terminal
+      frames.  */
+   if (row->displays_text_p)
+     while (glyph < end
+          && INTEGERP (glyph->object)
+          && !EQ (stop, glyph->object)
+          && glyph->charpos < 0)
+       {
+       *x += glyph->pixel_width;
+       ++glyph;
+       }
+ 
+   while (glyph < end
+        && !INTEGERP (glyph->object)
+        && !EQ (stop, glyph->object)
+        && (!BUFFERP (glyph->object)
+            || glyph->charpos < charpos))
+     {
+       *x += glyph->pixel_width;
+       ++glyph;
+     }
+ 
+   *hpos = glyph - row->glyphs[TEXT_AREA];
+   return past_end;
+ }
+ 
+ #else /* not 1 */
+ 
+ static int
+ fast_find_position (w, pos, hpos, vpos, x, y, stop)
+      struct window *w;
+      int pos;
+      int *hpos, *vpos, *x, *y;
+      Lisp_Object stop;
+ {
+   int i;
+   int lastcol;
+   int maybe_next_line_p = 0;
+   int line_start_position;
+   int yb = window_text_bottom_y (w);
+   struct glyph_row *row, *best_row;
+   int row_vpos, best_row_vpos;
+   int current_x;
+ 
+   row = best_row = MATRIX_FIRST_TEXT_ROW (w->current_matrix);
+   row_vpos = best_row_vpos = MATRIX_ROW_VPOS (row, w->current_matrix);
+ 
+   while (row->y < yb)
+     {
+       if (row->used[TEXT_AREA])
+       line_start_position = row->glyphs[TEXT_AREA]->charpos;
+       else
+       line_start_position = 0;
+ 
+       if (line_start_position > pos)
+       break;
+       /* If the position sought is the end of the buffer,
+        don't include the blank lines at the bottom of the window.  */
+       else if (line_start_position == pos
+              && pos == BUF_ZV (XBUFFER (w->buffer)))
+       {
+         maybe_next_line_p = 1;
+         break;
+       }
+       else if (line_start_position > 0)
+       {
+         best_row = row;
+         best_row_vpos = row_vpos;
+       }
+ 
+       if (row->y + row->height >= yb)
+       break;
+ 
+       ++row;
+       ++row_vpos;
+     }
+ 
+   /* Find the right column within BEST_ROW.  */
+   lastcol = 0;
+   current_x = best_row->x;
+   for (i = 0; i < best_row->used[TEXT_AREA]; i++)
+     {
+       struct glyph *glyph = best_row->glyphs[TEXT_AREA] + i;
+       int charpos = glyph->charpos;
+ 
+       if (BUFFERP (glyph->object))
+       {
+         if (charpos == pos)
+           {
+             *hpos = i;
+             *vpos = best_row_vpos;
+             *x = current_x;
+             *y = best_row->y;
+             return 1;
+           }
+         else if (charpos > pos)
+           break;
+       }
+       else if (EQ (glyph->object, stop))
+       break;
+ 
+       if (charpos > 0)
+       lastcol = i;
+       current_x += glyph->pixel_width;
+     }
+ 
+   /* If we're looking for the end of the buffer,
+      and we didn't find it in the line we scanned,
+      use the start of the following line.  */
+   if (maybe_next_line_p)
+     {
+       ++best_row;
+       ++best_row_vpos;
+       lastcol = 0;
+       current_x = best_row->x;
+     }
+ 
+   *vpos = best_row_vpos;
+   *hpos = lastcol + 1;
+   *x = current_x;
+   *y = best_row->y;
+   return 0;
+ }
+ 
+ #endif /* not 1 */
+ 
+ 
+ /* Find the position of the glyph for position POS in OBJECT in
+    window W's current matrix, and return in *X, *Y the pixel
+    coordinates, and return in *HPOS, *VPOS the column/row of the glyph.
+ 
+    RIGHT_P non-zero means return the position of the right edge of the
+    glyph, RIGHT_P zero means return the left edge position.
+ 
+    If no glyph for POS exists in the matrix, return the position of
+    the glyph with the next smaller position that is in the matrix, if
+    RIGHT_P is zero.  If RIGHT_P is non-zero, and no glyph for POS
+    exists in the matrix, return the position of the glyph with the
+    next larger position in OBJECT.
+ 
+    Value is non-zero if a glyph was found.  */
+ 
+ static int
+ fast_find_string_pos (w, pos, object, hpos, vpos, x, y, right_p)
+      struct window *w;
+      int pos;
+      Lisp_Object object;
+      int *hpos, *vpos, *x, *y;
+      int right_p;
+ {
+   int yb = window_text_bottom_y (w);
+   struct glyph_row *r;
+   struct glyph *best_glyph = NULL;
+   struct glyph_row *best_row = NULL;
+   int best_x = 0;
+ 
+   for (r = MATRIX_FIRST_TEXT_ROW (w->current_matrix);
+        r->enabled_p && r->y < yb;
+        ++r)
+     {
+       struct glyph *g = r->glyphs[TEXT_AREA];
+       struct glyph *e = g + r->used[TEXT_AREA];
+       int gx;
+ 
+       for (gx = r->x; g < e; gx += g->pixel_width, ++g)
+       if (EQ (g->object, object))
+         {
+           if (g->charpos == pos)
+             {
+               best_glyph = g;
+               best_x = gx;
+               best_row = r;
+               goto found;
+             }
+           else if (best_glyph == NULL
+                    || ((abs (g->charpos - pos)
+                        < abs (best_glyph->charpos - pos))
+                        && (right_p
+                            ? g->charpos < pos
+                            : g->charpos > pos)))
+             {
+               best_glyph = g;
+               best_x = gx;
+               best_row = r;
+             }
+         }
+     }
+ 
+  found:
+ 
+   if (best_glyph)
+     {
+       *x = best_x;
+       *hpos = best_glyph - best_row->glyphs[TEXT_AREA];
+ 
+       if (right_p)
+       {
+         *x += best_glyph->pixel_width;
+         ++*hpos;
+       }
+ 
+       *y = best_row->y;
+       *vpos = best_row - w->current_matrix->rows;
+     }
+ 
+   return best_glyph != NULL;
+ }
+ 
+ 
+ /* Take proper action when mouse has moved to the mode or header line
+    or marginal area AREA of window W, x-position X and y-position Y.
+    X is relative to the start of the text display area of W, so the
+    width of bitmap areas and scroll bars must be subtracted to get a
+    position relative to the start of the mode line.  */
+ 
+ static void
+ note_mode_line_or_margin_highlight (w, x, y, area)
+      struct window *w;
+      int x, y;
+      enum window_part area;
+ {
+   struct frame *f = XFRAME (w->frame);
+   Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
+   Cursor cursor = dpyinfo->vertical_scroll_bar_cursor;
+   int charpos;
+   Lisp_Object string, help, map, pos;
+ 
+   if (area == ON_MODE_LINE || area == ON_HEADER_LINE)
+     string = mode_line_string (w, x, y, area, &charpos);
+   else
+     string = marginal_area_string (w, x, y, area, &charpos);
+ 
+   if (STRINGP (string))
+     {
+       pos = make_number (charpos);
+ 
+       /* If we're on a string with `help-echo' text property, arrange
+        for the help to be displayed.  This is done by setting the
+        global variable help_echo_string to the help string.  */
+       help = Fget_text_property (pos, Qhelp_echo, string);
+       if (!NILP (help))
+       {
+         help_echo_string = help;
+         XSETWINDOW (help_echo_window, w);
+         help_echo_object = string;
+         help_echo_pos = charpos;
+       }
+ 
+      /* Change the mouse pointer according to what is under X/Y.  */
+       map = Fget_text_property (pos, Qlocal_map, string);
+       if (!KEYMAPP (map))
+       map = Fget_text_property (pos, Qkeymap, string);
+       if (KEYMAPP (map))
+       cursor = FRAME_X_OUTPUT (f)->nontext_cursor;
+     }
+ 
+   rif->define_frame_cursor (f, cursor);
+ }
+ 
+ 
+ /* EXPORT:
+    Take proper action when the mouse has moved to position X, Y on
+    frame F as regards highlighting characters that have mouse-face
+    properties.  Also de-highlighting chars where the mouse was before.
+    X and Y can be negative or out of range.  */
+ 
+ void
+ note_mouse_highlight (f, x, y)
+      struct frame *f;
+      int x, y;
+ {
+   Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
+   enum window_part part;
+   Lisp_Object window;
+   struct window *w;
+   Cursor cursor = No_Cursor;
+   struct buffer *b;
+ 
+   /* When a menu is active, don't highlight because this looks odd.  */
+ #if defined (USE_X_TOOLKIT) || defined (USE_GTK) || defined (HAVE_NTGUI)
+   if (popup_activated ())
+     return;
+ #endif
+ 
+   if (NILP (Vmouse_highlight)
+       || !f->glyphs_initialized_p)
+     return;
+ 
+   dpyinfo->mouse_face_mouse_x = x;
+   dpyinfo->mouse_face_mouse_y = y;
+   dpyinfo->mouse_face_mouse_frame = f;
+ 
+   if (dpyinfo->mouse_face_defer)
+     return;
+ 
+   if (gc_in_progress)
+     {
+       dpyinfo->mouse_face_deferred_gc = 1;
+       return;
+     }
+ 
+   /* Which window is that in?  */
+   window = window_from_coordinates (f, x, y, &part, 0, 0, 1);
+ 
+   /* If we were displaying active text in another window, clear that.  */
+   if (! EQ (window, dpyinfo->mouse_face_window))
+     clear_mouse_face (dpyinfo);
+ 
+   /* Not on a window -> return.  */
+   if (!WINDOWP (window))
+     return;
+ 
+   /* Reset help_echo_string. It will get recomputed below.  */
+   /* ++KFS: X version didn't do this, but it looks harmless.  */
+   help_echo_string = Qnil;
+ 
+   /* Convert to window-relative pixel coordinates.  */
+   w = XWINDOW (window);
+   frame_to_window_pixel_xy (w, &x, &y);
+ 
+   /* Handle tool-bar window differently since it doesn't display a
+      buffer.  */
+   if (EQ (window, f->tool_bar_window))
+     {
+       note_tool_bar_highlight (f, x, y);
+       return;
+     }
+ 
+   /* Mouse is on the mode, header line or margin?  */
+   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);
+       return;
+     }
+ 
+   if (part == ON_VERTICAL_BORDER)
+     cursor = FRAME_X_OUTPUT (f)->horizontal_drag_cursor;
+   else
+     cursor = FRAME_X_OUTPUT (f)->text_cursor;
+ 
+   /* Are we in a window whose display is up to date?
+      And verify the buffer's text has not changed.  */
+   b = XBUFFER (w->buffer);
+   if (part == ON_TEXT
+       && EQ (w->window_end_valid, w->buffer)
+       && XFASTINT (w->last_modified) == BUF_MODIFF (b)
+       && XFASTINT (w->last_overlay_modified) == BUF_OVERLAY_MODIFF (b))
+     {
+       int hpos, vpos, pos, i, area;
+       struct glyph *glyph;
+       Lisp_Object object;
+       Lisp_Object mouse_face = Qnil, overlay = Qnil, position;
+       Lisp_Object *overlay_vec = NULL;
+       int len, noverlays;
+       struct buffer *obuf;
+       int obegv, ozv, same_region;
+ 
+       /* Find the glyph under X/Y.  */
+       glyph = x_y_to_hpos_vpos (w, x, y, &hpos, &vpos, &area, 0);
+ 
+       /* Clear mouse face if X/Y not over text.  */
+       if (glyph == NULL
+         || area != TEXT_AREA
+         || !MATRIX_ROW (w->current_matrix, vpos)->displays_text_p)
+       {
+ #if defined (HAVE_NTGUI)
+         /* ++KFS: Why is this necessary on W32 ?  */
+         clear_mouse_face (dpyinfo);
+         cursor = FRAME_X_OUTPUT (f)->nontext_cursor;
+ #else
+         if (clear_mouse_face (dpyinfo))
+           cursor = No_Cursor;
+ #endif
+         goto set_cursor;
+       }
+ 
+       pos = glyph->charpos;
+       object = glyph->object;
+       if (!STRINGP (object) && !BUFFERP (object))
+       goto set_cursor;
+ 
+       /* If we get an out-of-range value, return now; avoid an error.  */
+       if (BUFFERP (object) && pos > BUF_Z (b))
+       goto set_cursor;
+ 
+       /* Make the window's buffer temporarily current for
+        overlays_at and compute_char_face.  */
+       obuf = current_buffer;
+       current_buffer = b;
+       obegv = BEGV;
+       ozv = ZV;
+       BEGV = BEG;
+       ZV = Z;
+ 
+       /* Is this char mouse-active or does it have help-echo?  */
+       position = make_number (pos);
+ 
+       if (BUFFERP (object))
+       {
+         /* Put all the overlays we want in a vector in overlay_vec.
+            Store the length in len.  If there are more than 10, make
+            enough space for all, and try again.  */
+         len = 10;
+         overlay_vec = (Lisp_Object *) alloca (len * sizeof (Lisp_Object));
+         noverlays = overlays_at (pos, 0, &overlay_vec, &len, NULL, NULL, 0);
+         if (noverlays > len)
+           {
+             len = noverlays;
+             overlay_vec = (Lisp_Object *) alloca (len * sizeof (Lisp_Object));
+             noverlays = overlays_at (pos, 0, &overlay_vec, &len, NULL, 
NULL,0);
+           }
+ 
+         /* Sort overlays into increasing priority order.  */
+         noverlays = sort_overlays (overlay_vec, noverlays, w);
+       }
+       else
+       noverlays = 0;
+ 
+       same_region = (EQ (window, dpyinfo->mouse_face_window)
+                    && vpos >= dpyinfo->mouse_face_beg_row
+                    && vpos <= dpyinfo->mouse_face_end_row
+                    && (vpos > dpyinfo->mouse_face_beg_row
+                        || hpos >= dpyinfo->mouse_face_beg_col)
+                    && (vpos < dpyinfo->mouse_face_end_row
+                        || hpos < dpyinfo->mouse_face_end_col
+                        || dpyinfo->mouse_face_past_end));
+ 
+       if (same_region)
+       cursor = No_Cursor;
+ 
+       /* Check mouse-face highlighting.  */
+       if (! same_region
+         /* If there exists an overlay with mouse-face overlapping
+            the one we are currently highlighting, we have to
+            check if we enter the overlapping overlay, and then
+            highlight only that.  */
+         || (OVERLAYP (dpyinfo->mouse_face_overlay)
+             && mouse_face_overlay_overlaps (dpyinfo->mouse_face_overlay)))
+       {
+         /* Find the highest priority overlay that has a mouse-face
+            property.  */
+         overlay = Qnil;
+         for (i = noverlays - 1; i >= 0 && NILP (overlay); --i)
+           {
+             mouse_face = Foverlay_get (overlay_vec[i], Qmouse_face);
+             if (!NILP (mouse_face))
+               overlay = overlay_vec[i];
+           }
+ 
+         /* If we're actually highlighting the same overlay as
+            before, there's no need to do that again.  */
+         if (!NILP (overlay)
+             && EQ (overlay, dpyinfo->mouse_face_overlay))
+           goto check_help_echo;
+ 
+         dpyinfo->mouse_face_overlay = overlay;
+ 
+         /* Clear the display of the old active region, if any.  */
+         if (clear_mouse_face (dpyinfo))
+           cursor = No_Cursor;
+ 
+         /* If no overlay applies, get a text property.  */
+         if (NILP (overlay))
+           mouse_face = Fget_text_property (position, Qmouse_face, object);
+ 
+         /* Handle the overlay case.  */
+         if (!NILP (overlay))
+           {
+             /* Find the range of text around this char that
+                should be active.  */
+             Lisp_Object before, after;
+             int ignore;
+ 
+             before = Foverlay_start (overlay);
+             after = Foverlay_end (overlay);
+             /* Record this as the current active region.  */
+             fast_find_position (w, XFASTINT (before),
+                                 &dpyinfo->mouse_face_beg_col,
+                                 &dpyinfo->mouse_face_beg_row,
+                                 &dpyinfo->mouse_face_beg_x,
+                                 &dpyinfo->mouse_face_beg_y, Qnil);
+ 
+             dpyinfo->mouse_face_past_end
+               = !fast_find_position (w, XFASTINT (after),
+                                      &dpyinfo->mouse_face_end_col,
+                                      &dpyinfo->mouse_face_end_row,
+                                      &dpyinfo->mouse_face_end_x,
+                                      &dpyinfo->mouse_face_end_y, Qnil);
+             dpyinfo->mouse_face_window = window;
+ 
+             dpyinfo->mouse_face_face_id
+               = face_at_buffer_position (w, pos, 0, 0,
+                                          &ignore, pos + 1,
+                                          !dpyinfo->mouse_face_hidden);
+ 
+             /* Display it as active.  */
+             show_mouse_face (dpyinfo, DRAW_MOUSE_FACE);
+             cursor = No_Cursor;
+           }
+         /* Handle the text property case.  */
+         else if (!NILP (mouse_face) && BUFFERP (object))
+           {
+             /* Find the range of text around this char that
+                should be active.  */
+             Lisp_Object before, after, beginning, end;
+             int ignore;
+ 
+             beginning = Fmarker_position (w->start);
+             end = make_number (BUF_Z (XBUFFER (object))
+                                - XFASTINT (w->window_end_pos));
+             before
+               = Fprevious_single_property_change (make_number (pos + 1),
+                                                   Qmouse_face,
+                                                   object, beginning);
+             after
+               = Fnext_single_property_change (position, Qmouse_face,
+                                               object, end);
+ 
+             /* Record this as the current active region.  */
+             fast_find_position (w, XFASTINT (before),
+                                 &dpyinfo->mouse_face_beg_col,
+                                 &dpyinfo->mouse_face_beg_row,
+                                 &dpyinfo->mouse_face_beg_x,
+                                 &dpyinfo->mouse_face_beg_y, Qnil);
+             dpyinfo->mouse_face_past_end
+               = !fast_find_position (w, XFASTINT (after),
+                                      &dpyinfo->mouse_face_end_col,
+                                      &dpyinfo->mouse_face_end_row,
+                                      &dpyinfo->mouse_face_end_x,
+                                      &dpyinfo->mouse_face_end_y, Qnil);
+             dpyinfo->mouse_face_window = window;
+ 
+             if (BUFFERP (object))
+               dpyinfo->mouse_face_face_id
+                 = face_at_buffer_position (w, pos, 0, 0,
+                                            &ignore, pos + 1,
+                                            !dpyinfo->mouse_face_hidden);
+ 
+             /* Display it as active.  */
+             show_mouse_face (dpyinfo, DRAW_MOUSE_FACE);
+             cursor = No_Cursor;
+           }
+         else if (!NILP (mouse_face) && STRINGP (object))
+           {
+             Lisp_Object b, e;
+             int ignore;
+ 
+             b = Fprevious_single_property_change (make_number (pos + 1),
+                                                   Qmouse_face,
+                                                   object, Qnil);
+             e = Fnext_single_property_change (position, Qmouse_face,
+                                               object, Qnil);
+             if (NILP (b))
+               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,
+                                   &dpyinfo->mouse_face_beg_x,
+                                   &dpyinfo->mouse_face_beg_y, 0);
+             fast_find_string_pos (w, XINT (e), object,
+                                   &dpyinfo->mouse_face_end_col,
+                                   &dpyinfo->mouse_face_end_row,
+                                   &dpyinfo->mouse_face_end_x,
+                                   &dpyinfo->mouse_face_end_y, 1);
+             dpyinfo->mouse_face_past_end = 0;
+             dpyinfo->mouse_face_window = window;
+             dpyinfo->mouse_face_face_id
+               = face_at_string_position (w, object, pos, 0, 0, 0, &ignore,
+                                          glyph->face_id, 1);
+             show_mouse_face (dpyinfo, DRAW_MOUSE_FACE);
+             cursor = No_Cursor;
+           }
+         else if (STRINGP (object) && NILP (mouse_face))
+           {
+             /* A string which doesn't have mouse-face, but
+                the text ``under'' it might have.  */
+             struct glyph_row *r = MATRIX_ROW (w->current_matrix, vpos);
+             int start = MATRIX_ROW_START_CHARPOS (r);
+ 
+             pos = string_buffer_position (w, object, start);
+             if (pos > 0)
+               mouse_face = get_char_property_and_overlay (make_number (pos),
+                                                           Qmouse_face,
+                                                           w->buffer,
+                                                           &overlay);
+             if (!NILP (mouse_face) && !NILP (overlay))
+               {
+                 Lisp_Object before = Foverlay_start (overlay);
+                 Lisp_Object after = Foverlay_end (overlay);
+                 int ignore;
+ 
+                 /* Note that we might not be able to find position
+                    BEFORE in the glyph matrix if the overlay is
+                    entirely covered by a `display' property.  In
+                    this case, we overshoot.  So let's stop in
+                    the glyph matrix before glyphs for OBJECT.  */
+                 fast_find_position (w, XFASTINT (before),
+                                     &dpyinfo->mouse_face_beg_col,
+                                     &dpyinfo->mouse_face_beg_row,
+                                     &dpyinfo->mouse_face_beg_x,
+                                     &dpyinfo->mouse_face_beg_y,
+                                     object);
+ 
+                 dpyinfo->mouse_face_past_end
+                   = !fast_find_position (w, XFASTINT (after),
+                                          &dpyinfo->mouse_face_end_col,
+                                          &dpyinfo->mouse_face_end_row,
+                                          &dpyinfo->mouse_face_end_x,
+                                          &dpyinfo->mouse_face_end_y,
+                                          Qnil);
+                 dpyinfo->mouse_face_window = window;
+                 dpyinfo->mouse_face_face_id
+                   = face_at_buffer_position (w, pos, 0, 0,
+                                              &ignore, pos + 1,
+                                              !dpyinfo->mouse_face_hidden);
+ 
+                 /* Display it as active.  */
+                 show_mouse_face (dpyinfo, DRAW_MOUSE_FACE);
+                 cursor = No_Cursor;
+               }
+           }
+       }
+ 
+     check_help_echo:
+ 
+       /* Look for a `help-echo' property.  */
+       {
+       Lisp_Object help, overlay;
+ 
+       /* Check overlays first.  */
+       help = overlay = Qnil;
+       for (i = noverlays - 1; i >= 0 && NILP (help); --i)
+         {
+           overlay = overlay_vec[i];
+           help = Foverlay_get (overlay, Qhelp_echo);
+         }
+ 
+       if (!NILP (help))
+         {
+           help_echo_string = help;
+           help_echo_window = window;
+           help_echo_object = overlay;
+           help_echo_pos = pos;
+         }
+       else
+         {
+           Lisp_Object object = glyph->object;
+           int charpos = glyph->charpos;
+ 
+           /* Try text properties.  */
+           if (STRINGP (object)
+               && charpos >= 0
+               && charpos < SCHARS (object))
+             {
+               help = Fget_text_property (make_number (charpos),
+                                          Qhelp_echo, object);
+               if (NILP (help))
+                 {
+                   /* If the string itself doesn't specify a help-echo,
+                      see if the buffer text ``under'' it does.  */
+                   struct glyph_row *r
+                     = MATRIX_ROW (w->current_matrix, vpos);
+                   int start = MATRIX_ROW_START_CHARPOS (r);
+                   int pos = string_buffer_position (w, object, start);
+                   if (pos > 0)
+                     {
+                       help = Fget_char_property (make_number (pos),
+                                                  Qhelp_echo, w->buffer);
+                       if (!NILP (help))
+                         {
+                           charpos = pos;
+                           object = w->buffer;
+                         }
+                     }
+                 }
+             }
+           else if (BUFFERP (object)
+                    && charpos >= BEGV
+                    && charpos < ZV)
+             help = Fget_text_property (make_number (charpos), Qhelp_echo,
+                                        object);
+ 
+           if (!NILP (help))
+             {
+               help_echo_string = help;
+               help_echo_window = window;
+               help_echo_object = object;
+               help_echo_pos = charpos;
+             }
+         }
+       }
+ 
+       BEGV = obegv;
+       ZV = ozv;
+       current_buffer = obuf;
+     }
+ 
+  set_cursor:
+ 
+ #ifndef HAVE_CARBON
+   if (cursor != No_Cursor)
+ #else
+   if (bcmp (&cursor, &No_Cursor, sizeof (Cursor)))
+ #endif
+     rif->define_frame_cursor (f, cursor);
+ }
+ 
+ 
+ /* EXPORT for RIF:
+    Clear any mouse-face on window W.  This function is part of the
+    redisplay interface, and is called from try_window_id and similar
+    functions to ensure the mouse-highlight is off.  */
+ 
+ void
+ x_clear_window_mouse_face (w)
+      struct window *w;
+ {
+   Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (XFRAME (w->frame));
+   Lisp_Object window;
+ 
+   BLOCK_INPUT;
+   XSETWINDOW (window, w);
+   if (EQ (window, dpyinfo->mouse_face_window))
+     clear_mouse_face (dpyinfo);
+   UNBLOCK_INPUT;
+ }
+ 
+ 
+ /* EXPORT:
+    Just discard the mouse face information for frame F, if any.
+    This is used when the size of F is changed.  */
+ 
+ void
+ cancel_mouse_face (f)
+      struct frame *f;
+ {
+   Lisp_Object window;
+   Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
+ 
+   window = dpyinfo->mouse_face_window;
+   if (! NILP (window) && XFRAME (XWINDOW (window)->frame) == f)
+     {
+       dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
+       dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
+       dpyinfo->mouse_face_window = Qnil;
+     }
+ }
+ 
+ 
+ #endif /* HAVE_WINDOW_SYSTEM */
+ 
+ 
+ /***********************************************************************
+                          Exposure Events
+  ***********************************************************************/
+ 
+ #ifdef HAVE_WINDOW_SYSTEM
+ 
+ /* Redraw the part of glyph row area AREA of glyph row ROW on window W
+    which intersects rectangle R.  R is in window-relative coordinates.  */
+ 
+ static void
+ expose_area (w, row, r, area)
+      struct window *w;
+      struct glyph_row *row;
+      XRectangle *r;
+      enum glyph_row_area area;
+ {
+   struct glyph *first = row->glyphs[area];
+   struct glyph *end = row->glyphs[area] + row->used[area];
+   struct glyph *last;
+   int first_x, start_x, x;
+ 
+   if (area == TEXT_AREA && row->fill_line_p)
+     /* If row extends face to end of line write the whole line.  */
+     draw_glyphs (w, 0, row, area,
+                0, row->used[area],
+                DRAW_NORMAL_TEXT, 0);
+   else
+     {
+       /* Set START_X to the window-relative start position for drawing glyphs 
of
+        AREA.  The first glyph of the text area can be partially visible.
+        The first glyphs of other areas cannot.  */
+       start_x = window_box_left_offset (w, area);
+       if (area == TEXT_AREA)
+       start_x += row->x;
+       x = start_x;
+ 
+       /* Find the first glyph that must be redrawn.  */
+       while (first < end
+            && x + first->pixel_width < r->x)
+       {
+         x += first->pixel_width;
+         ++first;
+       }
+ 
+       /* Find the last one.  */
+       last = first;
+       first_x = x;
+       while (last < end
+            && x < r->x + r->width)
+       {
+         x += last->pixel_width;
+         ++last;
+       }
+ 
+       /* Repaint.  */
+       if (last > first)
+       draw_glyphs (w, first_x - start_x, row, area,
+                    first - row->glyphs[area], last - row->glyphs[area],
+                    DRAW_NORMAL_TEXT, 0);
+     }
+ }
+ 
+ 
+ /* Redraw the parts of the glyph row ROW on window W intersecting
+    rectangle R.  R is in window-relative coordinates.  Value is
+    non-zero if mouse-face was overwritten.  */
+ 
+ static int
+ expose_line (w, row, r)
+      struct window *w;
+      struct glyph_row *row;
+      XRectangle *r;
+ {
+   xassert (row->enabled_p);
+ 
+   if (row->mode_line_p || w->pseudo_window_p)
+     draw_glyphs (w, 0, row, TEXT_AREA,
+                0, row->used[TEXT_AREA],
+                DRAW_NORMAL_TEXT, 0);
+   else
+     {
+       if (row->used[LEFT_MARGIN_AREA])
+       expose_area (w, row, r, LEFT_MARGIN_AREA);
+       if (row->used[TEXT_AREA])
+       expose_area (w, row, r, TEXT_AREA);
+       if (row->used[RIGHT_MARGIN_AREA])
+       expose_area (w, row, r, RIGHT_MARGIN_AREA);
+       draw_row_fringe_bitmaps (w, row);
+     }
+ 
+   return row->mouse_face_p;
+ }
+ 
+ 
+ /* Redraw those parts of glyphs rows during expose event handling that
+    overlap other rows.  Redrawing of an exposed line writes over parts
+    of lines overlapping that exposed line; this function fixes that.
+ 
+    W is the window being exposed.  FIRST_OVERLAPPING_ROW is the first
+    row in W's current matrix that is exposed and overlaps other rows.
+    LAST_OVERLAPPING_ROW is the last such row.  */
+ 
+ static void
+ expose_overlaps (w, first_overlapping_row, last_overlapping_row)
+      struct window *w;
+      struct glyph_row *first_overlapping_row;
+      struct glyph_row *last_overlapping_row;
+ {
+   struct glyph_row *row;
+ 
+   for (row = first_overlapping_row; row <= last_overlapping_row; ++row)
+     if (row->overlapping_p)
+       {
+       xassert (row->enabled_p && !row->mode_line_p);
+ 
+       if (row->used[LEFT_MARGIN_AREA])
+         x_fix_overlapping_area (w, row, LEFT_MARGIN_AREA);
+ 
+       if (row->used[TEXT_AREA])
+         x_fix_overlapping_area (w, row, TEXT_AREA);
+ 
+       if (row->used[RIGHT_MARGIN_AREA])
+         x_fix_overlapping_area (w, row, RIGHT_MARGIN_AREA);
+       }
+ }
+ 
+ 
+ /* Return non-zero if W's cursor intersects rectangle R.  */
+ 
+ static int
+ phys_cursor_in_rect_p (w, r)
+      struct window *w;
+      XRectangle *r;
+ {
+   XRectangle cr, result;
+   struct glyph *cursor_glyph;
+ 
+   cursor_glyph = get_phys_cursor_glyph (w);
+   if (cursor_glyph)
+     {
+       /* r is relative to W's box, but w->phys_cursor.x is relative 
+        to left edge of W's TEXT area.  Adjust it.  */
+       cr.x = window_box_left_offset (w, TEXT_AREA) + w->phys_cursor.x;
+       cr.y = w->phys_cursor.y;
+       cr.width = cursor_glyph->pixel_width;
+       cr.height = w->phys_cursor_height;
+       /* ++KFS: W32 version used W32-specific IntersectRect here, but 
+        I assume the effect is the same -- and this is portable.  */
+       return x_intersect_rectangles (&cr, r, &result);
+     }
+   else
+     return 0;
+ }
+ 
+ 
+ /* EXPORT:
+    Draw a vertical window border to the right of window W if W doesn't
+    have vertical scroll bars.  */
+ 
+ void
+ x_draw_vertical_border (w)
+      struct window *w;
+ {
+   /* We could do better, if we knew what type of scroll-bar the adjacent
+      windows (on either side) have...  But we don't :-( 
+      However, I think this works ok.  ++KFS 2003-04-25 */
+ 
+   /* Redraw borders between horizontally adjacent windows.  Don't
+      do it for frames with vertical scroll bars because either the
+      right scroll bar of a window, or the left scroll bar of its
+      neighbor will suffice as a border.  */
+   if (!WINDOW_RIGHTMOST_P (w)
+       && !WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_RIGHT (w))
+     {
+       int x0, x1, y0, y1;
+ 
+       window_box_edges (w, -1, &x0, &y0, &x1, &y1);
+       y1 -= 1;
+ 
+       rif->draw_vertical_window_border (w, x1, y0, y1);
+     }
+   else if (!WINDOW_LEFTMOST_P (w)
+          && !WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_LEFT (w))
+     {
+       int x0, x1, y0, y1;
+ 
+       window_box_edges (w, -1, &x0, &y0, &x1, &y1);
+       y1 -= 1;
+ 
+       rif->draw_vertical_window_border (w, x0, y0, y1);
+     }
+ }
+ 
+ 
+ /* Redraw the part of window W intersection rectangle FR.  Pixel
+    coordinates in FR are frame-relative.  Call this function with
+    input blocked.  Value is non-zero if the exposure overwrites
+    mouse-face.  */
+ 
+ static int
+ expose_window (w, fr)
+      struct window *w;
+      XRectangle *fr;
+ {
+   struct frame *f = XFRAME (w->frame);
+   XRectangle wr, r;
+   int mouse_face_overwritten_p = 0;
+ 
+   /* If window is not yet fully initialized, do nothing.  This can
+      happen when toolkit scroll bars are used and a window is split.
+      Reconfiguring the scroll bar will generate an expose for a newly
+      created window.  */
+   if (w->current_matrix == NULL)
+     return 0;
+ 
+   /* When we're currently updating the window, display and current
+      matrix usually don't agree.  Arrange for a thorough display
+      later.  */
+   if (w == updated_window)
+     {
+       SET_FRAME_GARBAGED (f);
+       return 0;
+     }
+ 
+   /* Frame-relative pixel rectangle of W.  */
+   wr.x = WINDOW_LEFT_EDGE_X (w);
+   wr.y = WINDOW_TOP_EDGE_Y (w);
+   wr.width = WINDOW_TOTAL_WIDTH (w);
+   wr.height = WINDOW_TOTAL_HEIGHT (w);
+ 
+   if (x_intersect_rectangles (fr, &wr, &r))
+     {
+       int yb = window_text_bottom_y (w);
+       struct glyph_row *row;
+       int cursor_cleared_p;
+       struct glyph_row *first_overlapping_row, *last_overlapping_row;
+ 
+       TRACE ((stderr, "expose_window (%d, %d, %d, %d)\n",
+             r.x, r.y, r.width, r.height));
+ 
+       /* Convert to window coordinates.  */
+       r.x -= WINDOW_LEFT_EDGE_X (w);
+       r.y -= WINDOW_TOP_EDGE_Y (w);
+ 
+       /* Turn off the cursor.  */
+       if (!w->pseudo_window_p
+         && phys_cursor_in_rect_p (w, &r))
+       {
+         x_clear_cursor (w);
+         cursor_cleared_p = 1;
+       }
+       else
+       cursor_cleared_p = 0;
+ 
+       /* Update lines intersecting rectangle R.  */
+       first_overlapping_row = last_overlapping_row = NULL;
+       for (row = w->current_matrix->rows;
+          row->enabled_p;
+          ++row)
+       {
+         int y0 = row->y;
+         int y1 = MATRIX_ROW_BOTTOM_Y (row);
+ 
+         if ((y0 >= r.y && y0 < r.y + r.height)
+             || (y1 > r.y && y1 < r.y + r.height)
+             || (r.y >= y0 && r.y < y1)
+             || (r.y + r.height > y0 && r.y + r.height < y1))
+           {
+             if (row->overlapping_p)
+               {
+                 if (first_overlapping_row == NULL)
+                   first_overlapping_row = row;
+                 last_overlapping_row = row;
+               }
+ 
+             if (expose_line (w, row, &r))
+               mouse_face_overwritten_p = 1;
+           }
+ 
+         if (y1 >= yb)
+           break;
+       }
+ 
+       /* Display the mode line if there is one.  */
+       if (WINDOW_WANTS_MODELINE_P (w)
+         && (row = MATRIX_MODE_LINE_ROW (w->current_matrix),
+             row->enabled_p)
+         && row->y < r.y + r.height)
+       {
+         if (expose_line (w, row, &r))
+           mouse_face_overwritten_p = 1;
+       }
+ 
+       if (!w->pseudo_window_p)
+       {
+         /* Fix the display of overlapping rows.  */
+         if (first_overlapping_row)
+           expose_overlaps (w, first_overlapping_row, last_overlapping_row);
+ 
+         /* Draw border between windows.  */
+         x_draw_vertical_border (w);
+ 
+         /* Turn the cursor on again.  */
+         if (cursor_cleared_p)
+           update_window_cursor (w, 1);
+       }
+     }
+ 
+ #ifdef HAVE_CARBON
+   /* Display scroll bar for this window.  */
+   if (!NILP (w->vertical_scroll_bar))
+     {
+       /* ++KFS:
+        If this doesn't work here (maybe some header files are missing),
+        make a function in macterm.c and call it to do the job! */
+       ControlHandle ch
+       = SCROLL_BAR_CONTROL_HANDLE (XSCROLL_BAR (w->vertical_scroll_bar));
+ 
+       Draw1Control (ch);
+     }
+ #endif
+ 
+   return mouse_face_overwritten_p;
+ }
+ 
+ 
+ 
+ /* Redraw (parts) of all windows in the window tree rooted at W that
+    intersect R.  R contains frame pixel coordinates.  Value is
+    non-zero if the exposure overwrites mouse-face.  */
+ 
+ static int
+ expose_window_tree (w, r)
+      struct window *w;
+      XRectangle *r;
+ {
+   struct frame *f = XFRAME (w->frame);
+   int mouse_face_overwritten_p = 0;
+ 
+   while (w && !FRAME_GARBAGED_P (f))
+     {
+       if (!NILP (w->hchild))
+       mouse_face_overwritten_p
+         |= expose_window_tree (XWINDOW (w->hchild), r);
+       else if (!NILP (w->vchild))
+       mouse_face_overwritten_p
+         |= expose_window_tree (XWINDOW (w->vchild), r);
+       else
+       mouse_face_overwritten_p |= expose_window (w, r);
+ 
+       w = NILP (w->next) ? NULL : XWINDOW (w->next);
+     }
+ 
+   return mouse_face_overwritten_p;
+ }
+ 
+ 
+ /* EXPORT:
+    Redisplay an exposed area of frame F.  X and Y are the upper-left
+    corner of the exposed rectangle.  W and H are width and height of
+    the exposed area.  All are pixel values.  W or H zero means redraw
+    the entire frame.  */
+ 
+ void
+ expose_frame (f, x, y, w, h)
+      struct frame *f;
+      int x, y, w, h;
+ {
+   XRectangle r;
+   int mouse_face_overwritten_p = 0;
+ 
+   TRACE ((stderr, "expose_frame "));
+ 
+   /* No need to redraw if frame will be redrawn soon.  */
+   if (FRAME_GARBAGED_P (f))
+     {
+       TRACE ((stderr, " garbaged\n"));
+       return;
+     }
+ 
+ #ifdef HAVE_CARBON
+   /* MAC_TODO: this is a kludge, but if scroll bars are not activated
+      or deactivated here, for unknown reasons, activated scroll bars
+      are shown in deactivated frames in some instances.  */
+   if (f == FRAME_MAC_DISPLAY_INFO (f)->x_focus_frame)
+     activate_scroll_bars (f);
+   else
+     deactivate_scroll_bars (f);
+ #endif
+ 
+   /* If basic faces haven't been realized yet, there is no point in
+      trying to redraw anything.  This can happen when we get an expose
+      event while Emacs is starting, e.g. by moving another window.  */
+   if (FRAME_FACE_CACHE (f) == NULL
+       || FRAME_FACE_CACHE (f)->used < BASIC_FACE_ID_SENTINEL)
+     {
+       TRACE ((stderr, " no faces\n"));
+       return;
+     }
+ 
+   if (w == 0 || h == 0)
+     {
+       r.x = r.y = 0;
+       r.width = FRAME_COLUMN_WIDTH (f) * FRAME_COLS (f);
+       r.height = FRAME_LINE_HEIGHT (f) * FRAME_LINES (f);
+     }
+   else
+     {
+       r.x = x;
+       r.y = y;
+       r.width = w;
+       r.height = h;
+     }
+ 
+   TRACE ((stderr, "(%d, %d, %d, %d)\n", r.x, r.y, r.width, r.height));
+   mouse_face_overwritten_p = expose_window_tree (XWINDOW (f->root_window), 
&r);
+ 
+   if (WINDOWP (f->tool_bar_window))
+     mouse_face_overwritten_p
+       |= expose_window (XWINDOW (f->tool_bar_window), &r);
+ 
+ #ifdef HAVE_X_WINDOWS
+ #ifndef MSDOS
+ #ifndef USE_X_TOOLKIT
+   if (WINDOWP (f->menu_bar_window))
+     mouse_face_overwritten_p
+       |= expose_window (XWINDOW (f->menu_bar_window), &r);
+ #endif /* not USE_X_TOOLKIT */
+ #endif
+ #endif
+ 
+   /* Some window managers support a focus-follows-mouse style with
+      delayed raising of frames.  Imagine a partially obscured frame,
+      and moving the mouse into partially obscured mouse-face on that
+      frame.  The visible part of the mouse-face will be highlighted,
+      then the WM raises the obscured frame.  With at least one WM, KDE
+      2.1, Emacs is not getting any event for the raising of the frame
+      (even tried with SubstructureRedirectMask), only Expose events.
+      These expose events will draw text normally, i.e. not
+      highlighted.  Which means we must redo the highlight here.
+      Subsume it under ``we love X''.  --gerd 2001-08-15  */
+   /* Included in Windows version because Windows most likely does not
+      do the right thing if any third party tool offers
+      focus-follows-mouse with delayed raise.  --jason 2001-10-12  */
+   if (mouse_face_overwritten_p && !FRAME_GARBAGED_P (f))
+     {
+       Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
+       if (f == dpyinfo->mouse_face_mouse_frame)
+       {
+         int x = dpyinfo->mouse_face_mouse_x;
+         int y = dpyinfo->mouse_face_mouse_y;
+         clear_mouse_face (dpyinfo);
+         note_mouse_highlight (f, x, y);
+       }
+     }
+ }
+ 
+ 
+ /* EXPORT:
+    Determine the intersection of two rectangles R1 and R2.  Return
+    the intersection in *RESULT.  Value is non-zero if RESULT is not
+    empty.  */
+ 
+ int
+ x_intersect_rectangles (r1, r2, result)
+      XRectangle *r1, *r2, *result;
+ {
+   XRectangle *left, *right;
+   XRectangle *upper, *lower;
+   int intersection_p = 0;
+ 
+   /* Rearrange so that R1 is the left-most rectangle.  */
+   if (r1->x < r2->x)
+     left = r1, right = r2;
+   else
+     left = r2, right = r1;
+ 
+   /* X0 of the intersection is right.x0, if this is inside R1,
+      otherwise there is no intersection.  */
+   if (right->x <= left->x + left->width)
+     {
+       result->x = right->x;
+ 
+       /* The right end of the intersection is the minimum of the
+        the right ends of left and right.  */
+       result->width = (min (left->x + left->width, right->x + right->width)
+                      - result->x);
+ 
+       /* Same game for Y.  */
+       if (r1->y < r2->y)
+       upper = r1, lower = r2;
+       else
+       upper = r2, lower = r1;
+ 
+       /* The upper end of the intersection is lower.y0, if this is inside
+        of upper.  Otherwise, there is no intersection.  */
+       if (lower->y <= upper->y + upper->height)
+       {
+         result->y = lower->y;
+ 
+         /* The lower end of the intersection is the minimum of the lower
+            ends of upper and lower.  */
+         result->height = (min (lower->y + lower->height,
+                                upper->y + upper->height)
+                           - result->y);
+         intersection_p = 1;
+       }
+     }
+ 
+   return intersection_p;
+ }
+ 
+ #endif /* HAVE_WINDOW_SYSTEM */
+ 
+ 
+ /***********************************************************************
+                           Initialization
+  ***********************************************************************/
+ 
+ void
+ syms_of_xdisp ()
+ {
+   Vwith_echo_area_save_vector = Qnil;
+   staticpro (&Vwith_echo_area_save_vector);
+ 
+   Vmessage_stack = Qnil;
+   staticpro (&Vmessage_stack);
+ 
+   Qinhibit_redisplay = intern ("inhibit-redisplay");
+   staticpro (&Qinhibit_redisplay);
+ 
+   message_dolog_marker1 = Fmake_marker ();
+   staticpro (&message_dolog_marker1);
+   message_dolog_marker2 = Fmake_marker ();
+   staticpro (&message_dolog_marker2);
+   message_dolog_marker3 = Fmake_marker ();
+   staticpro (&message_dolog_marker3);
+ 
+ #if GLYPH_DEBUG
+   defsubr (&Sdump_frame_glyph_matrix);
+   defsubr (&Sdump_glyph_matrix);
+   defsubr (&Sdump_glyph_row);
+   defsubr (&Sdump_tool_bar_row);
+   defsubr (&Strace_redisplay);
+   defsubr (&Strace_to_stderr);
+ #endif
+ #ifdef HAVE_WINDOW_SYSTEM
+   defsubr (&Stool_bar_lines_needed);
+ #endif
+   defsubr (&Sformat_mode_line);
+ 
+   staticpro (&Qmenu_bar_update_hook);
+   Qmenu_bar_update_hook = intern ("menu-bar-update-hook");
+ 
+   staticpro (&Qoverriding_terminal_local_map);
+   Qoverriding_terminal_local_map = intern ("overriding-terminal-local-map");
+ 
+   staticpro (&Qoverriding_local_map);
+   Qoverriding_local_map = intern ("overriding-local-map");
+ 
+   staticpro (&Qwindow_scroll_functions);
+   Qwindow_scroll_functions = intern ("window-scroll-functions");
+ 
+   staticpro (&Qredisplay_end_trigger_functions);
+   Qredisplay_end_trigger_functions = intern 
("redisplay-end-trigger-functions");
+ 
+   staticpro (&Qinhibit_point_motion_hooks);
+   Qinhibit_point_motion_hooks = intern ("inhibit-point-motion-hooks");
+ 
+   QCdata = intern (":data");
+   staticpro (&QCdata);
+   Qdisplay = intern ("display");
+   staticpro (&Qdisplay);
+   Qspace_width = intern ("space-width");
+   staticpro (&Qspace_width);
+   Qraise = intern ("raise");
+   staticpro (&Qraise);
+   Qspace = intern ("space");
+   staticpro (&Qspace);
+   Qmargin = intern ("margin");
+   staticpro (&Qmargin);
+   Qleft_margin = intern ("left-margin");
+   staticpro (&Qleft_margin);
+   Qright_margin = intern ("right-margin");
+   staticpro (&Qright_margin);
+   Qalign_to = intern ("align-to");
+   staticpro (&Qalign_to);
+   QCalign_to = intern (":align-to");
+   staticpro (&QCalign_to);
+   Qrelative_width = intern ("relative-width");
+   staticpro (&Qrelative_width);
+   QCrelative_width = intern (":relative-width");
+   staticpro (&QCrelative_width);
+   QCrelative_height = intern (":relative-height");
+   staticpro (&QCrelative_height);
+   QCeval = intern (":eval");
+   staticpro (&QCeval);
+   QCpropertize = intern (":propertize");
+   staticpro (&QCpropertize);
+   QCfile = intern (":file");
+   staticpro (&QCfile);
+   Qfontified = intern ("fontified");
+   staticpro (&Qfontified);
+   Qfontification_functions = intern ("fontification-functions");
+   staticpro (&Qfontification_functions);
+   Qtrailing_whitespace = intern ("trailing-whitespace");
+   staticpro (&Qtrailing_whitespace);
+   Qimage = intern ("image");
+   staticpro (&Qimage);
+   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");
+   staticpro (&Qinhibit_menubar_update);
+   Qinhibit_eval_during_redisplay = intern ("inhibit-eval-during-redisplay");
+   staticpro (&Qinhibit_eval_during_redisplay);
+   Qposition = intern ("position");
+   staticpro (&Qposition);
+   Qbuffer_position = intern ("buffer-position");
+   staticpro (&Qbuffer_position);
+   Qobject = intern ("object");
+   staticpro (&Qobject);
+   Qbar = intern ("bar");
+   staticpro (&Qbar);
+   Qhbar = intern ("hbar");
+   staticpro (&Qhbar);
+   Qbox = intern ("box");
+   staticpro (&Qbox);
+   Qhollow = intern ("hollow");
+   staticpro (&Qhollow);
+   Qrisky_local_variable = intern ("risky-local-variable");
+   staticpro (&Qrisky_local_variable);
+   Qinhibit_free_realized_faces = intern ("inhibit-free-realized-faces");
+   staticpro (&Qinhibit_free_realized_faces);
+ 
+   list_of_error = Fcons (intern ("error"), Qnil);
+   staticpro (&list_of_error);
+ 
+   last_arrow_position = Qnil;
+   last_arrow_string = Qnil;
+   staticpro (&last_arrow_position);
+   staticpro (&last_arrow_string);
+ 
+   echo_buffer[0] = echo_buffer[1] = Qnil;
+   staticpro (&echo_buffer[0]);
+   staticpro (&echo_buffer[1]);
+ 
+   echo_area_buffer[0] = echo_area_buffer[1] = Qnil;
+   staticpro (&echo_area_buffer[0]);
+   staticpro (&echo_area_buffer[1]);
+ 
+   Vmessages_buffer_name = build_string ("*Messages*");
+   staticpro (&Vmessages_buffer_name);
+ 
+   mode_line_proptrans_alist = Qnil;
+   staticpro (&mode_line_proptrans_alist);
+ 
+   mode_line_string_list = Qnil;
+   staticpro (&mode_line_string_list);
+ 
+   help_echo_string = Qnil;
+   staticpro (&help_echo_string);
+   help_echo_object = Qnil;
+   staticpro (&help_echo_object);
+   help_echo_window = Qnil;
+   staticpro (&help_echo_window);
+   previous_help_echo_string = Qnil;
+   staticpro (&previous_help_echo_string);
+   help_echo_pos = -1;
+ 
+ #ifdef HAVE_WINDOW_SYSTEM
+   DEFVAR_BOOL ("x-stretch-cursor", &x_stretch_cursor_p,
+     doc: /* *Non-nil means draw block cursor as wide as the glyph under it.
+ For example, if a block cursor is over a tab, it will be drawn as
+ wide as that tab on the display.  */);
+   x_stretch_cursor_p = 0;
+ #endif
+ 
+   DEFVAR_LISP ("show-trailing-whitespace", &Vshow_trailing_whitespace,
+     doc: /* Non-nil means highlight trailing whitespace.
+ The face used for trailing whitespace is `trailing-whitespace'.  */);
+   Vshow_trailing_whitespace = Qnil;
+ 
+   DEFVAR_LISP ("inhibit-redisplay", &Vinhibit_redisplay,
+     doc: /* Non-nil means don't actually do any redisplay.
+ This is used for internal purposes.  */);
+   Vinhibit_redisplay = Qnil;
+ 
+   DEFVAR_LISP ("global-mode-string", &Vglobal_mode_string,
+     doc: /* String (or mode line construct) included (normally) in 
`mode-line-format'.  */);
+   Vglobal_mode_string = Qnil;
+ 
+   DEFVAR_LISP ("overlay-arrow-position", &Voverlay_arrow_position,
+     doc: /* Marker for where to display an arrow on top of the buffer text.
+ This must be the beginning of a line in order to work.
+ See also `overlay-arrow-string'.  */);
+   Voverlay_arrow_position = Qnil;
+ 
+   DEFVAR_LISP ("overlay-arrow-string", &Voverlay_arrow_string,
+     doc: /* String to display as an arrow.  See also 
`overlay-arrow-position'.  */);
+   Voverlay_arrow_string = Qnil;
+ 
+   DEFVAR_INT ("scroll-step", &scroll_step,
+     doc: /* *The number of lines to try scrolling a window by when point 
moves out.
+ If that fails to bring point back on frame, point is centered instead.
+ If this is zero, point is always centered after it moves off frame.
+ If you want scrolling to always be a line at a time, you should set
+ `scroll-conservatively' to a large value rather than set this to 1.  */);
+ 
+   DEFVAR_INT ("scroll-conservatively", &scroll_conservatively,
+     doc: /* *Scroll up to this many lines, to bring point back on screen.
+ A value of zero means to scroll the text to center point vertically
+ in the window.  */);
+   scroll_conservatively = 0;
+ 
+   DEFVAR_INT ("scroll-margin", &scroll_margin,
+     doc: /* *Number of lines of margin at the top and bottom of a window.
+ Recenter the window whenever point gets within this many lines
+ of the top or bottom of the window.  */);
+   scroll_margin = 0;
+ 
+ #if GLYPH_DEBUG
+   DEFVAR_INT ("debug-end-pos", &debug_end_pos, doc: /* Don't ask.  */);
+ #endif
+ 
+   DEFVAR_BOOL ("truncate-partial-width-windows",
+              &truncate_partial_width_windows,
+     doc: /* *Non-nil means truncate lines in all windows less than full frame 
wide.  */);
+   truncate_partial_width_windows = 1;
+ 
+   DEFVAR_BOOL ("mode-line-inverse-video", &mode_line_inverse_video,
+     doc: /* nil means display the mode-line/header-line/menu-bar in the 
default face.
+ Any other value means to use the appropriate face, `mode-line',
+ `header-line', or `menu' respectively.  */);
+   mode_line_inverse_video = 1;
+ 
+   DEFVAR_LISP ("line-number-display-limit", &Vline_number_display_limit,
+     doc: /* *Maximum buffer size for which line number should be displayed.
+ If the buffer is bigger than this, the line number does not appear
+ in the mode line.  A value of nil means no limit.  */);
+   Vline_number_display_limit = Qnil;
+ 
+   DEFVAR_INT ("line-number-display-limit-width",
+             &line_number_display_limit_width,
+     doc: /* *Maximum line width (in characters) for line number display.
+ If the average length of the lines near point is bigger than this, then the
+ line number may be omitted from the mode line.  */);
+   line_number_display_limit_width = 200;
+ 
+   DEFVAR_BOOL ("highlight-nonselected-windows", 
&highlight_nonselected_windows,
+     doc: /* *Non-nil means highlight region even in nonselected windows.  */);
+   highlight_nonselected_windows = 0;
+ 
+   DEFVAR_BOOL ("multiple-frames", &multiple_frames,
+     doc: /* Non-nil if more than one frame is visible on this display.
+ Minibuffer-only frames don't count, but iconified frames do.
+ This variable is not guaranteed to be accurate except while processing
+ `frame-title-format' and `icon-title-format'.  */);
+ 
+   DEFVAR_LISP ("frame-title-format", &Vframe_title_format,
+     doc: /* Template for displaying the title bar of visible frames.
+ \(Assuming the window manager supports this feature.)
+ This variable has the same structure as `mode-line-format' (which see),
+ and is used only on frames for which no explicit name has been set
+ \(see `modify-frame-parameters').  */);
+   DEFVAR_LISP ("icon-title-format", &Vicon_title_format,
+     doc: /* Template for displaying the title bar of an iconified frame.
+ \(Assuming the window manager supports this feature.)
+ This variable has the same structure as `mode-line-format' (which see),
+ and is used only on frames for which no explicit name has been set
+ \(see `modify-frame-parameters').  */);
+   Vicon_title_format
+     = Vframe_title_format
+     = Fcons (intern ("multiple-frames"),
+            Fcons (build_string ("%b"),
+                   Fcons (Fcons (empty_string,
+                                 Fcons (intern ("invocation-name"),
+                                        Fcons (build_string ("@"),
+                                               Fcons (intern ("system-name"),
+                                                              Qnil)))),
+                          Qnil)));
+ 
+   DEFVAR_LISP ("message-log-max", &Vmessage_log_max,
+     doc: /* Maximum number of lines to keep in the message log buffer.
+ If nil, disable message logging.  If t, log messages but don't truncate
+ the buffer when it becomes large.  */);
+   Vmessage_log_max = make_number (50);
+ 
+   DEFVAR_LISP ("window-size-change-functions", &Vwindow_size_change_functions,
+     doc: /* Functions called before redisplay, if window sizes have changed.
+ The value should be a list of functions that take one argument.
+ Just before redisplay, for each frame, if any of its windows have changed
+ size since the last redisplay, or have been split or deleted,
+ all the functions in the list are called, with the frame as argument.  */);
+   Vwindow_size_change_functions = Qnil;
+ 
+   DEFVAR_LISP ("window-scroll-functions", &Vwindow_scroll_functions,
+     doc: /* List of Functions to call before redisplaying a window with 
scrolling.
+ Each function is called with two arguments, the window
+ 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_BOOL ("mouse-autoselect-window", &mouse_autoselect_window,
+     doc: /* *Non-nil means autoselect window with mouse pointer.  */);
+   mouse_autoselect_window = 0;
+ 
+   DEFVAR_BOOL ("auto-resize-tool-bars", &auto_resize_tool_bars_p,
+     doc: /* *Non-nil means automatically resize tool-bars.
+ This increases a tool-bar's height if not all tool-bar items are visible.
+ It decreases a tool-bar's height when it would display blank lines
+ otherwise.  */);
+   auto_resize_tool_bars_p = 1;
+ 
+   DEFVAR_BOOL ("auto-raise-tool-bar-buttons", &auto_raise_tool_bar_buttons_p,
+     doc: /* *Non-nil means raise tool-bar buttons when the mouse moves over 
them.  */);
+   auto_raise_tool_bar_buttons_p = 1;
+ 
+   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.
+ Otherwise, value should be a pair of integers `(HORZ . VERT)' with
+ HORZ specifying the horizontal margin, and VERT specifying the
+ vertical margin.  */);
+   Vtool_bar_button_margin = make_number (DEFAULT_TOOL_BAR_BUTTON_MARGIN);
+ 
+   DEFVAR_INT ("tool-bar-button-relief", &tool_bar_button_relief,
+     doc: /* *Relief thickness of tool-bar buttons.  */);
+   tool_bar_button_relief = DEFAULT_TOOL_BAR_BUTTON_RELIEF;
+ 
+   DEFVAR_LISP ("fontification-functions", &Vfontification_functions,
+     doc: /* List of functions to call to fontify regions of text.
+ Each function is called with one argument POS.  Functions must
+ fontify a region starting at POS in the current buffer, and give
+ fontified regions the property `fontified'.  */);
+   Vfontification_functions = Qnil;
+   Fmake_variable_buffer_local (Qfontification_functions);
+ 
+   DEFVAR_BOOL ("unibyte-display-via-language-environment",
+                &unibyte_display_via_language_environment,
+     doc: /* *Non-nil means display unibyte text according to language 
environment.
+ Specifically this means that unibyte non-ASCII characters
+ are displayed by converting them to the equivalent multibyte characters
+ according to the current language environment.  As a result, they are
+ displayed according to the current fontset.  */);
+   unibyte_display_via_language_environment = 0;
+ 
+   DEFVAR_LISP ("max-mini-window-height", &Vmax_mini_window_height,
+     doc: /* *Maximum height for resizing mini-windows.
+ If a float, it specifies a fraction of the mini-window frame's height.
+ If an integer, it specifies a number of lines.  */);
+   Vmax_mini_window_height = make_float (0.25);
+ 
+   DEFVAR_LISP ("resize-mini-windows", &Vresize_mini_windows,
+     doc: /* *How to resize mini-windows.
+ A value of nil means don't automatically resize mini-windows.
+ A value of t means resize them to fit the text displayed in them.
+ A value of `grow-only', the default, means let mini-windows grow
+ 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.  */);
+   Vblink_cursor_alist = Qnil;
+ 
+   DEFVAR_BOOL ("auto-hscroll-mode", &automatic_hscrolling_p,
+     doc: /* *Non-nil means scroll the display automatically to make point 
visible.  */);
+   automatic_hscrolling_p = 1;
+ 
+   DEFVAR_INT ("hscroll-margin", &hscroll_margin,
+     doc: /* *How many columns away from the window edge point is allowed to 
get
+ before automatic hscrolling will horizontally scroll the window.  */);
+   hscroll_margin = 5;
+ 
+   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
+ 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
+ fraction of the window's width to scroll.  If it's nil or zero, point will be
+ centered horizontally after the scroll.  Any other value, including negative
+ numbers, are treated as if the value were zero.
+ 
+ Automatic hscrolling always moves point outside the scroll margin, so if
+ point was more than scroll step columns inside the margin, the window will
+ scroll more than the value given by the scroll step.
+ 
+ Note that the lower bound for automatic hscrolling specified by `scroll-left'
+ and `scroll-right' overrides this variable's effect.  */);
+   Vhscroll_step = make_number (0);
+ 
+   DEFVAR_LISP ("image-types", &Vimage_types,
+     doc: /* List of supported image types.
+ Each element of the list is a symbol for a supported image type.  */);
+   Vimage_types = Qnil;
+ 
+   DEFVAR_BOOL ("message-truncate-lines", &message_truncate_lines,
+     doc: /* If non-nil, messages are truncated instead of resizing the echo 
area.
+ Bind this around calls to `message' to let it take effect.  */);
+   message_truncate_lines = 0;
+ 
+   DEFVAR_LISP ("menu-bar-update-hook",  &Vmenu_bar_update_hook,
+     doc: /* Normal hook run for clicks on menu bar, before displaying a 
submenu.
+ Can be used to update submenus whose contents should vary.  */);
+   Vmenu_bar_update_hook = Qnil;
+ 
+   DEFVAR_BOOL ("inhibit-menubar-update", &inhibit_menubar_update,
+     doc: /* Non-nil means don't update menu bars.  Internal use only.  */);
+   inhibit_menubar_update = 0;
+ 
+   DEFVAR_BOOL ("inhibit-eval-during-redisplay", 
&inhibit_eval_during_redisplay,
+     doc: /* Non-nil means don't eval Lisp during redisplay.  */);
+   inhibit_eval_during_redisplay = 0;
+ 
+   DEFVAR_BOOL ("inhibit-free-realized-faces", &inhibit_free_realized_faces,
+     doc: /* Non-nil means don't free realized faces.  Internal use only.  */);
+   inhibit_free_realized_faces = 0;
+ 
+ #if GLYPH_DEBUG
+   DEFVAR_BOOL ("inhibit-try-window-id", &inhibit_try_window_id,
+              doc: /* Inhibit try_window_id display optimization.  */);
+   inhibit_try_window_id = 0;
+ 
+   DEFVAR_BOOL ("inhibit-try-window-reusing", &inhibit_try_window_reusing,
+              doc: /* Inhibit try_window_reusing display optimization.  */);
+   inhibit_try_window_reusing = 0;
+ 
+   DEFVAR_BOOL ("inhibit-try-cursor-movement", &inhibit_try_cursor_movement,
+              doc: /* Inhibit try_cursor_movement display optimization.  */);
+   inhibit_try_cursor_movement = 0;
+ #endif /* GLYPH_DEBUG */
+ }
+ 
+ 
+ /* Initialize this module when Emacs starts.  */
+ 
+ void
+ init_xdisp ()
+ {
+   Lisp_Object root_window;
+   struct window *mini_w;
+ 
+   current_header_line_height = current_mode_line_height = -1;
+ 
+   CHARPOS (this_line_start_pos) = 0;
+ 
+   mini_w = XWINDOW (minibuf_window);
+   root_window = FRAME_ROOT_WINDOW (XFRAME (WINDOW_FRAME (mini_w)));
+ 
+   if (!noninteractive)
+     {
+       struct frame *f = XFRAME (WINDOW_FRAME (XWINDOW (root_window)));
+       int i;
+ 
+       XWINDOW (root_window)->top_line = make_number (FRAME_TOP_MARGIN (f));
+       set_window_height (root_window,
+                        FRAME_LINES (f) - 1 - FRAME_TOP_MARGIN (f),
+                        0);
+       mini_w->top_line = make_number (FRAME_LINES (f) - 1);
+       set_window_height (minibuf_window, 1, 0);
+ 
+       XWINDOW (root_window)->total_cols = make_number (FRAME_COLS (f));
+       mini_w->total_cols = make_number (FRAME_COLS (f));
+ 
+       scratch_glyph_row.glyphs[TEXT_AREA] = scratch_glyphs;
+       scratch_glyph_row.glyphs[TEXT_AREA + 1]
+       = scratch_glyphs + MAX_SCRATCH_GLYPHS;
+ 
+       /* The default ellipsis glyphs `...'.  */
+       for (i = 0; i < 3; ++i)
+       default_invis_vector[i] = make_number ('.');
+     }
+ 
+   {
+     /* 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;
+   }
+ 
+   help_echo_showing_p = 0;
+ }
+ 
+ 




reply via email to

[Prev in Thread] Current Thread [Next in Thread]