]> code.delx.au - gnu-emacs/blobdiff - src/xdisp.c
* lisp.h (last_glyphless_glyph_frame, last_glyphless_glyph_face_id)
[gnu-emacs] / src / xdisp.c
index 660c6b9130f92d2127252f24c7a5ae5615708ab4..d5def0659364c1b7a02b35aab162f84d94bf643f 100644 (file)
@@ -299,21 +299,9 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 #include "font.h"
 #include "fontset.h"
 #include "blockinput.h"
-
-#ifdef HAVE_X_WINDOWS
-#include "xterm.h"
-#endif
-#ifdef HAVE_NTGUI
-#include "w32term.h"
-#endif
-#ifdef HAVE_NS
-#include "nsterm.h"
-#endif
-#ifdef USE_GTK
-#include "gtkutil.h"
-#endif
-
-#include "font.h"
+#ifdef HAVE_WINDOW_SYSTEM
+#include TERM_HEADER
+#endif /* HAVE_WINDOW_SYSTEM */
 
 #ifndef FRAME_X_OUTPUT
 #define FRAME_X_OUTPUT(f) ((f)->output_data.x)
@@ -378,8 +366,7 @@ static Lisp_Object Qline_height;
    && ((IT)->bidi_it.paragraph_dir == R2L              \
        ? (WINDOW_LEFT_FRINGE_WIDTH ((IT)->w) > 0)      \
        : (WINDOW_RIGHT_FRINGE_WIDTH ((IT)->w) > 0))    \
-   && (IT)->current_x == (IT)->last_visible_x          \
-   && (IT)->line_wrap != WORD_WRAP)
+   && (IT)->current_x == (IT)->last_visible_x)
 
 #else /* !HAVE_WINDOW_SYSTEM */
 #define IT_OVERFLOW_NEWLINE_INTO_FRINGE(it) 0
@@ -525,10 +512,6 @@ int update_mode_lines;
 
 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.  */
 
@@ -586,12 +569,6 @@ static int last_height;
 
 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
@@ -763,6 +740,8 @@ Lisp_Object previous_help_echo_string;
 
 /* Platform-independent portion of hourglass implementation. */
 
+#ifdef HAVE_WINDOW_SYSTEM
+
 /* Non-zero means an hourglass cursor is currently shown.  */
 int hourglass_shown_p;
 
@@ -770,6 +749,8 @@ int hourglass_shown_p;
    an hourglass cursor on all frames.  */
 struct atimer *hourglass_atimer;
 
+#endif /* HAVE_WINDOW_SYSTEM */
+
 /* Name of the face used to display glyphless characters.  */
 Lisp_Object Qglyphless_char;
 
@@ -779,14 +760,17 @@ static Lisp_Object Qglyphless_char_display;
 /* Method symbols for Vglyphless_char_display.  */
 static Lisp_Object Qhex_code, Qempty_box, Qthin_space, Qzero_width;
 
-/* Default pixel width of `thin-space' display method.  */
-#define THIN_SPACE_WIDTH 1
-
 /* Default number of seconds to wait before displaying an hourglass
    cursor.  */
 #define DEFAULT_HOURGLASS_DELAY 1
 
-\f
+#ifdef HAVE_WINDOW_SYSTEM
+
+/* Default pixel width of `thin-space' display method.  */
+#define THIN_SPACE_WIDTH 1
+
+#endif /* HAVE_WINDOW_SYSTEM */
+
 /* Function prototypes.  */
 
 static void setup_for_ellipsis (struct it *, int);
@@ -807,7 +791,6 @@ static void pint2str (char *, int, ptrdiff_t);
 static void pint2hrstr (char *, int, ptrdiff_t);
 static struct text_pos run_window_scroll_functions (Lisp_Object,
                                                     struct text_pos);
-static void reconsider_clip_changes (struct window *, struct buffer *);
 static int text_outside_line_unchanged_p (struct window *,
                                          ptrdiff_t, ptrdiff_t);
 static void store_mode_line_noprop_char (char);
@@ -816,21 +799,20 @@ static void handle_stop (struct it *);
 static void handle_stop_backwards (struct it *, ptrdiff_t);
 static void vmessage (const char *, va_list) ATTRIBUTE_FORMAT_PRINTF (1, 0);
 static void ensure_echo_area_buffers (void);
-static Lisp_Object unwind_with_echo_area_buffer (Lisp_Object);
+static void unwind_with_echo_area_buffer (Lisp_Object);
 static Lisp_Object with_echo_area_buffer_unwind_data (struct window *);
 static int with_echo_area_buffer (struct window *, int,
                                   int (*) (ptrdiff_t, Lisp_Object),
                                   ptrdiff_t, Lisp_Object);
 static void clear_garbaged_frames (void);
 static int current_message_1 (ptrdiff_t, Lisp_Object);
-static void pop_message (void);
 static int truncate_message_1 (ptrdiff_t, Lisp_Object);
 static void set_message (Lisp_Object);
 static int set_message_1 (ptrdiff_t, Lisp_Object);
 static int display_echo_area (struct window *);
 static int display_echo_area_1 (ptrdiff_t, Lisp_Object);
 static int resize_mini_window_1 (ptrdiff_t, Lisp_Object);
-static Lisp_Object unwind_redisplay (Lisp_Object);
+static void unwind_redisplay (void);
 static int string_char_and_length (const unsigned char *, int *);
 static struct text_pos display_prop_end (struct it *, Lisp_Object,
                                          struct text_pos);
@@ -971,12 +953,12 @@ window_text_bottom_y (struct window *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.  */
+/* Return the pixel width of display area AREA of window W.
+   ANY_AREA means return the total width of W, not including
+   fringes to the left and right of the window.  */
 
 int
-window_box_width (struct window *w, int area)
+window_box_width (struct window *w, enum glyph_row_area area)
 {
   int cols = w->total_cols;
   int pixels = 0;
@@ -987,22 +969,18 @@ window_box_width (struct window *w, int area)
 
       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);
+         cols -= max (0, w->left_margin_cols);
+         cols -= max (0, 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);
+         cols = max (0, w->left_margin_cols);
          pixels = 0;
        }
       else if (area == RIGHT_MARGIN_AREA)
        {
-         cols = (INTEGERP (w->right_margin_cols)
-                  ? XFASTINT (w->right_margin_cols) : 0);
+         cols = max (0, w->right_margin_cols);
          pixels = 0;
        }
     }
@@ -1058,11 +1036,11 @@ window_box_height (struct window *w)
 }
 
 /* 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
+   area AREA of window W.  ANY_AREA means return the left edge of the
    whole window, to the right of the left fringe of W.  */
 
 int
-window_box_left_offset (struct window *w, int area)
+window_box_left_offset (struct window *w, enum glyph_row_area area)
 {
   int x;
 
@@ -1090,21 +1068,21 @@ window_box_left_offset (struct window *w, int area)
 
 
 /* Return the window-relative coordinate of the right edge of display
-   area AREA of window W.  AREA < 0 means return the right edge of the
+   area AREA of window W.  ANY_AREA means return the right edge of the
    whole window, to the left of the right fringe of W.  */
 
 int
-window_box_right_offset (struct window *w, int area)
+window_box_right_offset (struct window *w, enum glyph_row_area 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
+   area AREA of window W.  ANY_AREA means return the left edge of the
    whole window, to the right of the left fringe of W.  */
 
 int
-window_box_left (struct window *w, int area)
+window_box_left (struct window *w, enum glyph_row_area area)
 {
   struct frame *f = XFRAME (w->frame);
   int x;
@@ -1120,25 +1098,25 @@ window_box_left (struct window *w, int area)
 
 
 /* Return the frame-relative coordinate of the right edge of display
-   area AREA of window W.  AREA < 0 means return the right edge of the
+   area AREA of window W.  ANY_AREA means return the right edge of the
    whole window, to the left of the right fringe of W.  */
 
 int
-window_box_right (struct window *w, int area)
+window_box_right (struct window *w, enum glyph_row_area 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
+   mode lines, in frame-relative coordinates.  ANY_AREA 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.  */
 
 void
-window_box (struct window *w, int area, int *box_x, int *box_y,
-           int *box_width, int *box_height)
+window_box (struct window *w, enum glyph_row_area area, int *box_x,
+           int *box_y, int *box_width, int *box_height)
 {
   if (box_width)
     *box_width = window_box_width (w, area);
@@ -1154,27 +1132,27 @@ window_box (struct window *w, int area, int *box_x, int *box_y,
     }
 }
 
+#ifdef HAVE_WINDOW_SYSTEM
 
 /* 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
+   mode lines and both fringes 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.  */
 
 static void
-window_box_edges (struct window *w, int area, int *top_left_x, int *top_left_y,
-                  int *bottom_right_x, int *bottom_right_y)
+window_box_edges (struct window *w, int *top_left_x, int *top_left_y,
+                 int *bottom_right_x, int *bottom_right_y)
 {
-  window_box (w, area, top_left_x, top_left_y, bottom_right_x,
-             bottom_right_y);
+  window_box (w, ANY_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;
 }
 
+#endif /* HAVE_WINDOW_SYSTEM */
 
-\f
 /***********************************************************************
                              Utilities
  ***********************************************************************/
@@ -1235,6 +1213,52 @@ Value is the height in pixels of the line at point.  */)
   return make_number (line_bottom_y (&it));
 }
 
+/* Return the default pixel height of text lines in window W.  The
+   value is the canonical height of the W frame's default font, plus
+   any extra space required by the line-spacing variable or frame
+   parameter.
+
+   Implementation note: this ignores any line-spacing text properties
+   put on the newline characters.  This is because those properties
+   only affect the _screen_ line ending in the newline (i.e., in a
+   continued line, only the last screen line will be affected), which
+   means only a small number of lines in a buffer can ever use this
+   feature.  Since this function is used to compute the default pixel
+   equivalent of text lines in a window, we can safely ignore those
+   few lines.  For the same reasons, we ignore the line-height
+   properties.  */
+int
+default_line_pixel_height (struct window *w)
+{
+  struct frame *f = WINDOW_XFRAME (w);
+  int height = FRAME_LINE_HEIGHT (f);
+
+  if (!FRAME_INITIAL_P (f) && BUFFERP (w->contents))
+    {
+      struct buffer *b = XBUFFER (w->contents);
+      Lisp_Object val = BVAR (b, extra_line_spacing);
+
+      if (NILP (val))
+       val = BVAR (&buffer_defaults, extra_line_spacing);
+      if (!NILP (val))
+       {
+         if (RANGED_INTEGERP (0, val, INT_MAX))
+           height += XFASTINT (val);
+         else if (FLOATP (val))
+           {
+             int addon = XFLOAT_DATA (val) * height + 0.5;
+
+             if (addon >= 0)
+               height += addon;
+           }
+       }
+      else
+       height += f->extra_line_spacing;
+    }
+
+  return height;
+}
+
 /* Subroutine of pos_visible_p below.  Extracts a display string, if
    any, from the display spec given as its argument.  */
 static Lisp_Object
@@ -1315,12 +1339,12 @@ pos_visible_p (struct window *w, ptrdiff_t charpos, int *x, int *y,
 
   /* Compute exact mode line heights.  */
   if (WINDOW_WANTS_MODELINE_P (w))
-    current_mode_line_height
+    w->mode_line_height
       = display_mode_line (w, CURRENT_MODE_LINE_FACE_ID (w),
                           BVAR (current_buffer, mode_line_format));
 
   if (WINDOW_WANTS_HEADER_LINE_P (w))
-    current_header_line_height
+    w->header_line_height
       = display_mode_line (w, HEADER_LINE_FACE_ID,
                           BVAR (current_buffer, header_line_format));
 
@@ -1369,8 +1393,7 @@ pos_visible_p (struct window *w, ptrdiff_t charpos, int *x, int *y,
          struct it save_it = it;
          /* Why 10? because we don't know how many canonical lines
             will the height of the next line(s) be.  So we guess.  */
-         int ten_more_lines =
-           10 * FRAME_LINE_HEIGHT (XFRAME (WINDOW_FRAME (w)));
+         int ten_more_lines = 10 * default_line_pixel_height (w);
 
          move_it_to (&it, charpos, -1, bottom_y + ten_more_lines, -1,
                      MOVE_TO_POS | MOVE_TO_Y);
@@ -1614,8 +1637,6 @@ pos_visible_p (struct window *w, ptrdiff_t charpos, int *x, int *y,
   if (old_buffer)
     set_buffer_internal_1 (old_buffer);
 
-  current_header_line_height = current_mode_line_height = -1;
-
   if (visible_p && w->hscroll > 0)
     *x -=
       window_hscroll_limited (w, WINDOW_XFRAME (w))
@@ -1813,7 +1834,7 @@ estimate_mode_line_height (struct frame *f, enum face_id face_id)
    not force the value into range.  */
 
 void
-pixel_to_glyph_coords (FRAME_PTR f, register int pix_x, register int pix_y,
+pixel_to_glyph_coords (struct frame *f, register int pix_x, register int pix_y,
                       int *x, int *y, NativeRectangle *bounds, int noclip)
 {
 
@@ -2425,7 +2446,16 @@ remember_mouse_glyph (struct frame *f, int gx, int gy, NativeRectangle *rect)
 
 #endif /* HAVE_WINDOW_SYSTEM */
 
-\f
+static void
+adjust_window_ends (struct window *w, struct glyph_row *row, bool current)
+{
+  eassert (w);
+  w->window_end_pos = Z - MATRIX_ROW_END_CHARPOS (row);
+  w->window_end_bytepos = Z_BYTE - MATRIX_ROW_END_BYTEPOS (row);
+  w->window_end_vpos
+    = MATRIX_ROW_VPOS (row, current ? w->current_matrix : w->desired_matrix);
+}
+
 /***********************************************************************
                        Lisp form evaluation
  ***********************************************************************/
@@ -2561,8 +2591,7 @@ check_window_end (struct window *w)
   if (!MINI_WINDOW_P (w) && w->window_end_valid)
     {
       struct glyph_row *row;
-      eassert ((row = MATRIX_ROW (w->current_matrix,
-                                 XFASTINT (w->window_end_vpos)),
+      eassert ((row = MATRIX_ROW (w->current_matrix, w->window_end_vpos),
                !row->enabled_p
                || MATRIX_ROW_DISPLAYS_TEXT_P (row)
                || MATRIX_ROW_VPOS (row, w->current_matrix) == 0));
@@ -3868,10 +3897,14 @@ handle_face_prop (struct it *it)
          /* For 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.  */
+            surrounding text, unless they specify their own faces.
+            For strings from wrap-prefix and line-prefix properties,
+            use the default face, possibly remapped via
+            Vface_remapping_alist.  */
          base_face_id = it->string_from_prefix_prop_p
-           ? DEFAULT_FACE_ID
+           ? (!NILP (Vface_remapping_alist)
+              ? lookup_basic_face (it->f, DEFAULT_FACE_ID)
+              : DEFAULT_FACE_ID)
            : underlying_face_id (it);
        }
 
@@ -5305,7 +5338,7 @@ handle_composition_prop (struct it *it)
      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, &start, &end, &prop, string)
-      && COMPOSITION_VALID_P (start, end, prop)
+      && composition_valid_p (start, end, prop)
       && (STRINGP (it->string) || (PT <= start || PT >= end)))
     {
       if (start < pos)
@@ -5468,8 +5501,8 @@ next_overlay_string (struct it *it)
 static int
 compare_overlay_entries (const void *e1, const void *e2)
 {
-  struct overlay_entry *entry1 = (struct overlay_entry *) e1;
-  struct overlay_entry *entry2 = (struct overlay_entry *) e2;
+  struct overlay_entry const *entry1 = e1;
+  struct overlay_entry const *entry2 = e2;
   int result;
 
   if (entry1->after_string_p != entry2->after_string_p)
@@ -6633,17 +6666,59 @@ lookup_glyphless_char_display (int c, struct it *it)
   return glyphless_method;
 }
 
-/* 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.  */
+/* Merge escape glyph face and cache the result.  */
 
 static struct frame *last_escape_glyph_frame = NULL;
 static int last_escape_glyph_face_id = (1 << FACE_ID_BITS);
 static int last_escape_glyph_merged_face_id = 0;
 
-struct frame *last_glyphless_glyph_frame = NULL;
-int last_glyphless_glyph_face_id = (1 << FACE_ID_BITS);
-int last_glyphless_glyph_merged_face_id = 0;
+static int
+merge_escape_glyph_face (struct it *it)
+{
+  int face_id;
+
+  if (it->f == last_escape_glyph_frame
+      && it->face_id == last_escape_glyph_face_id)
+    face_id = last_escape_glyph_merged_face_id;
+  else
+    {
+      /* Merge the `escape-glyph' face into the current face.  */
+      face_id = merge_faces (it->f, Qescape_glyph, 0, it->face_id);
+      last_escape_glyph_frame = it->f;
+      last_escape_glyph_face_id = it->face_id;
+      last_escape_glyph_merged_face_id = face_id;
+    }
+  return face_id;
+}
+
+/* Likewise for glyphless glyph face.  */
+
+static struct frame *last_glyphless_glyph_frame = NULL;
+static int last_glyphless_glyph_face_id = (1 << FACE_ID_BITS);
+static int last_glyphless_glyph_merged_face_id = 0;
+
+int
+merge_glyphless_glyph_face (struct it *it)
+{
+  int face_id;
+
+  if (it->f == last_glyphless_glyph_frame
+      && it->face_id == last_glyphless_glyph_face_id)
+    face_id = last_glyphless_glyph_merged_face_id;
+  else
+    {
+      /* Merge the `glyphless-char' face into the current face.  */
+      face_id = merge_faces (it->f, Qglyphless_char, 0, it->face_id);
+      last_glyphless_glyph_frame = it->f;
+      last_glyphless_glyph_face_id = it->face_id;
+      last_glyphless_glyph_merged_face_id = face_id;
+    }
+  return face_id;
+}
+
+/* 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.  */
 
 static int
 get_next_display_element (struct it *it)
@@ -6791,24 +6866,10 @@ get_next_display_element (struct it *it)
                      g = GLYPH_CODE_CHAR (gc);
                      lface_id = GLYPH_CODE_FACE (gc);
                    }
-                 if (lface_id)
-                   {
-                     face_id = merge_faces (it->f, Qt, lface_id, it->face_id);
-                   }
-                 else if (it->f == last_escape_glyph_frame
-                          && it->face_id == last_escape_glyph_face_id)
-                   {
-                     face_id = last_escape_glyph_merged_face_id;
-                   }
-                 else
-                   {
-                     /* Merge the escape-glyph face into the current face.  */
-                     face_id = merge_faces (it->f, Qescape_glyph, 0,
-                                            it->face_id);
-                     last_escape_glyph_frame = it->f;
-                     last_escape_glyph_face_id = it->face_id;
-                     last_escape_glyph_merged_face_id = face_id;
-                   }
+
+                 face_id = (lface_id
+                            ? merge_faces (it->f, Qt, lface_id, it->face_id)
+                            : merge_escape_glyph_face (it));
 
                  XSETINT (it->ctl_chars[0], g);
                  XSETINT (it->ctl_chars[1], c ^ 0100);
@@ -6840,27 +6901,10 @@ get_next_display_element (struct it *it)
                  escape_glyph = GLYPH_CODE_CHAR (gc);
                  lface_id = GLYPH_CODE_FACE (gc);
                }
-             if (lface_id)
-               {
-                 /* The display table specified a face.
-                    Merge it into face_id and also into escape_glyph.  */
-                 face_id = merge_faces (it->f, Qt, lface_id,
-                                        it->face_id);
-               }
-             else if (it->f == last_escape_glyph_frame
-                      && it->face_id == last_escape_glyph_face_id)
-               {
-                 face_id = last_escape_glyph_merged_face_id;
-               }
-             else
-               {
-                 /* Merge the escape-glyph face into the current face.  */
-                 face_id = merge_faces (it->f, Qescape_glyph, 0,
-                                        it->face_id);
-                 last_escape_glyph_frame = it->f;
-                 last_escape_glyph_face_id = it->face_id;
-                 last_escape_glyph_merged_face_id = face_id;
-               }
+
+             face_id = (lface_id
+                        ? merge_faces (it->f, Qt, lface_id, it->face_id)
+                        : merge_escape_glyph_face (it));
 
              /* Draw non-ASCII hyphen with just highlighting: */
 
@@ -7002,7 +7046,9 @@ get_next_display_element (struct it *it)
                }
            }
        }
-      else
+      /* next_element_from_display_vector sets this flag according to
+        faces of the display vector glyphs, see there.  */
+      else if (it->method != GET_FROM_DISPLAY_VECTOR)
        {
          int face_id = face_after_it_pos (it);
          it->end_of_box_run_p
@@ -7417,6 +7463,8 @@ static int
 next_element_from_display_vector (struct it *it)
 {
   Lisp_Object gc;
+  int prev_face_id = it->face_id;
+  int next_face_id;
 
   /* Precondition.  */
   eassert (it->dpvec && it->current.dpvec_index >= 0);
@@ -7429,6 +7477,8 @@ next_element_from_display_vector (struct it *it)
 
   if (GLYPH_CODE_P (gc))
     {
+      struct face *this_face, *prev_face, *next_face;
+
       it->c = GLYPH_CODE_CHAR (gc);
       it->len = CHAR_BYTES (it->c);
 
@@ -7444,6 +7494,41 @@ next_element_from_display_vector (struct it *it)
            it->face_id = merge_faces (it->f, Qt, lface_id,
                                       it->saved_face_id);
        }
+
+      /* Glyphs in the display vector could have the box face, so we
+        need to set the related flags in the iterator, as
+        appropriate.  */
+      this_face = FACE_FROM_ID (it->f, it->face_id);
+      prev_face = FACE_FROM_ID (it->f, prev_face_id);
+
+      /* Is this character the first character of a box-face run?  */
+      it->start_of_box_run_p = (this_face && this_face->box != FACE_NO_BOX
+                               && (!prev_face
+                                   || prev_face->box == FACE_NO_BOX));
+
+      /* For the last character of the box-face run, we need to look
+        either at the next glyph from the display vector, or at the
+        face we saw before the display vector.  */
+      next_face_id = it->saved_face_id;
+      if (it->current.dpvec_index < it->dpend - it->dpvec - 1)
+       {
+         if (it->dpvec_face_id >= 0)
+           next_face_id = it->dpvec_face_id;
+         else
+           {
+             int lface_id =
+               GLYPH_CODE_FACE (it->dpvec[it->current.dpvec_index + 1]);
+
+             if (lface_id > 0)
+               next_face_id = merge_faces (it->f, Qt, lface_id,
+                                           it->saved_face_id);
+           }
+       }
+      next_face = FACE_FROM_ID (it->f, next_face_id);
+      it->end_of_box_run_p = (this_face && this_face->box != FACE_NO_BOX
+                             && (!next_face
+                                 || next_face->box == FACE_NO_BOX));
+      it->face_box_p = this_face && this_face->box != FACE_NO_BOX;
     }
   else
     /* Display table entry is invalid.  Return a space.  */
@@ -8539,7 +8624,9 @@ move_it_in_display_line_to (struct it *it,
                                    result = MOVE_LINE_CONTINUED;
                                  break;
                                }
-                             if (ITERATOR_AT_END_OF_LINE_P (it))
+                             if (ITERATOR_AT_END_OF_LINE_P (it)
+                                 && (it->line_wrap != WORD_WRAP
+                                     || wrap_it.sp < 0))
                                {
                                  result = MOVE_NEWLINE_OR_CR;
                                  break;
@@ -9016,7 +9103,7 @@ move_it_to (struct it *it, ptrdiff_t to_charpos, int to_x, int to_y, int to_vpos
       && it->current_x == it->last_visible_x - 1
       && it->c != '\n'
       && it->c != '\t'
-      && it->vpos < XFASTINT (it->w->window_end_vpos))
+      && it->vpos < it->w->window_end_vpos)
     {
       it->continuation_lines_width += it->current_x;
       it->current_x = it->hpos = it->max_ascent = it->max_descent = 0;
@@ -9057,7 +9144,7 @@ move_it_vertically_backward (struct it *it, int dy)
   start_pos = IT_CHARPOS (*it);
 
   /* Estimate how many newlines we must move back.  */
-  nlines = max (1, dy / FRAME_LINE_HEIGHT (it->f));
+  nlines = max (1, dy / default_line_pixel_height (it->w));
   if (it->line_wrap == TRUNCATE)
     pos_limit = BEGV;
   else
@@ -9747,7 +9834,7 @@ message3_nolog (Lisp_Object m)
 void
 message1 (const char *m)
 {
-  message3 (m ? make_unibyte_string (m, strlen (m)) : Qnil);
+  message3 (m ? build_unibyte_string (m) : Qnil);
 }
 
 
@@ -9756,7 +9843,7 @@ message1 (const char *m)
 void
 message1_nolog (const char *m)
 {
-  message3_nolog (m ? make_unibyte_string (m, strlen (m)) : Qnil);
+  message3_nolog (m ? build_unibyte_string (m) : Qnil);
 }
 
 /* Display a message M which contains a single %s
@@ -9866,7 +9953,7 @@ vmessage (const char *m, va_list ap)
              ptrdiff_t maxsize = FRAME_MESSAGE_BUF_SIZE (f);
              char *message_buf = alloca (maxsize + 1);
 
-             len = doprnt (message_buf, maxsize, m, (char *)0, ap);
+             len = doprnt (message_buf, maxsize, m, 0, ap);
 
              message3 (make_string (message_buf, len));
            }
@@ -10102,7 +10189,7 @@ with_echo_area_buffer_unwind_data (struct window *w)
 /* Restore global state from VECTOR which was created by
    with_echo_area_buffer_unwind_data.  */
 
-static Lisp_Object
+static void
 unwind_with_echo_area_buffer (Lisp_Object vector)
 {
   set_buffer_internal_1 (XBUFFER (AREF (vector, 0)));
@@ -10127,7 +10214,6 @@ unwind_with_echo_area_buffer (Lisp_Object vector)
     }
 
   Vwith_echo_area_save_vector = vector;
-  return Qnil;
 }
 
 
@@ -10419,7 +10505,8 @@ resize_mini_window (struct window *w, int exact_p)
          if (height > WINDOW_TOTAL_LINES (w))
            {
              int old_height = WINDOW_TOTAL_LINES (w);
-             freeze_window_starts (f, 1);
+
+             FRAME_WINDOWS_FROZEN (f) = 1;
              grow_mini_window (w, height - WINDOW_TOTAL_LINES (w));
              window_height_changed_p = WINDOW_TOTAL_LINES (w) != old_height;
            }
@@ -10427,7 +10514,8 @@ resize_mini_window (struct window *w, int exact_p)
                   && (exact_p || BEGV == ZV))
            {
              int old_height = WINDOW_TOTAL_LINES (w);
-             freeze_window_starts (f, 0);
+
+             FRAME_WINDOWS_FROZEN (f) = 0;
              shrink_mini_window (w);
              window_height_changed_p = WINDOW_TOTAL_LINES (w) != old_height;
            }
@@ -10438,19 +10526,21 @@ resize_mini_window (struct window *w, int exact_p)
          if (height > WINDOW_TOTAL_LINES (w))
            {
              int old_height = WINDOW_TOTAL_LINES (w);
-             freeze_window_starts (f, 1);
+
+             FRAME_WINDOWS_FROZEN (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);
+
+             FRAME_WINDOWS_FROZEN (f) = 0;
              shrink_mini_window (w);
 
              if (height)
                {
-                 freeze_window_starts (f, 1);
+                 FRAME_WINDOWS_FROZEN (f) = 1;
                  grow_mini_window (w, height - WINDOW_TOTAL_LINES (w));
                }
 
@@ -10526,20 +10616,12 @@ restore_message (void)
 }
 
 
-/* Handler for record_unwind_protect calling pop_message.  */
-
-Lisp_Object
-pop_message_unwind (Lisp_Object dummy)
-{
-  pop_message ();
-  return Qnil;
-}
-
-/* Pop the top-most entry off Vmessage_stack.  */
+/* Handler for unwind-protect calling pop_message.  */
 
-static void
-pop_message (void)
+void
+pop_message_unwind (void)
 {
+  /* Pop the top-most entry off Vmessage_stack.  */
   eassert (CONSP (Vmessage_stack));
   Vmessage_stack = XCDR (Vmessage_stack);
 }
@@ -10816,17 +10898,6 @@ buffer_shared_and_changed (void)
          && UNCHANGED_MODIFIED < MODIFF);
 }
 
-/* Nonzero if W doesn't reflect the actual state of current buffer due
-   to its text or overlays change.  FIXME: this may be called when
-   XBUFFER (w->contents) != current_buffer, which looks suspicious.  */
-
-static int
-window_outdated (struct window *w)
-{
-  return (w->last_modified < MODIFF
-         || w->last_overlay_modified < OVERLAY_MODIFF);
-}
-
 /* Nonzero if W's buffer was changed but not saved or Transient Mark mode
    is enabled and mark of W's buffer was changed since last W's update.  */
 
@@ -10852,6 +10923,31 @@ mode_line_update_needed (struct window *w)
          && (w->column_number_displayed != current_column ()));
 }
 
+/* Nonzero if window start of W is frozen and may not be changed during
+   redisplay.  */
+
+static bool
+window_frozen_p (struct window *w)
+{
+  if (FRAME_WINDOWS_FROZEN (XFRAME (WINDOW_FRAME (w))))
+    {
+      Lisp_Object window;
+
+      XSETWINDOW (window, w);
+      if (MINI_WINDOW_P (w))
+       return 0;
+      else if (EQ (window, selected_window))
+       return 0;
+      else if (MINI_WINDOW_P (XWINDOW (selected_window))
+              && EQ (window, Vminibuf_scroll_window))
+       /* This special window can't be frozen too.  */
+       return 0;
+      else
+       return 1;
+    }
+  return 0;
+}
+
 /***********************************************************************
                     Mode Lines and Frame Titles
  ***********************************************************************/
@@ -10935,7 +11031,7 @@ format_mode_line_unwind_data (struct frame *target_frame,
   return vector;
 }
 
-static Lisp_Object
+static void
 unwind_format_mode_line (Lisp_Object vector)
 {
   Lisp_Object old_window = AREF (vector, 7);
@@ -10978,7 +11074,6 @@ unwind_format_mode_line (Lisp_Object vector)
     }
 
   Vmode_line_unwind_vector = vector;
-  return Qnil;
 }
 
 
@@ -11148,7 +11243,18 @@ prepare_menu_bars (void)
        {
          f = XFRAME (frame);
          if (!EQ (frame, tooltip_frame)
-             && (FRAME_VISIBLE_P (f) || FRAME_ICONIFIED_P (f)))
+             && (FRAME_ICONIFIED_P (f)
+                 || FRAME_VISIBLE_P (f) == 1
+                 /* Exclude TTY frames that are obscured because they
+                    are not the top frame on their console.  This is
+                    because x_consider_frame_title actually switches
+                    to the frame, which for TTY frames means it is
+                    marked as garbaged, and will be completely
+                    redrawn on the next redisplay cycle.  This causes
+                    TTY frames to be completely redrawn, when there
+                    are more than one of them, even though nothing
+                    should be changed on display.  */
+                 || (FRAME_VISIBLE_P (f) == 2 && FRAME_WINDOW_P (f))))
            x_consider_frame_title (frame);
        }
     }
@@ -11335,79 +11441,6 @@ update_menu_bar (struct frame *f, int save_match_data, int hooks_run)
   return hooks_run;
 }
 
-
-\f
-/***********************************************************************
-                           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 (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 (int vpos, int hpos, int y, int 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 (FRAME_RIF (SELECTED_FRAME ())->flush_display_optional)
-       FRAME_RIF (SELECTED_FRAME ())->flush_display_optional (SELECTED_FRAME ());
-      unblock_input ();
-    }
-}
-
-#endif /* HAVE_WINDOW_SYSTEM */
-
-\f
 /***********************************************************************
                               Tool-bars
  ***********************************************************************/
@@ -11416,7 +11449,7 @@ x_cursor_to (int vpos, int hpos, int y, int x)
 
 /* Where the mouse was last time we reported a mouse event.  */
 
-FRAME_PTR last_mouse_frame;
+struct frame *last_mouse_frame;
 
 /* Tool-bar item index of the item on which a mouse button was pressed
    or -1.  */
@@ -11427,7 +11460,7 @@ int last_tool_bar_item;
    do_switch_frame.
    FIXME: Maybe do_switch_frame should be trimmed down similarly
    when `norecord' is set.  */
-static Lisp_Object
+static void
 fast_set_selected_frame (Lisp_Object frame)
 {
   if (!EQ (selected_frame, frame))
@@ -11435,7 +11468,6 @@ fast_set_selected_frame (Lisp_Object frame)
       selected_frame = frame;
       selected_window = XFRAME (frame)->selected_window;
     }
-  return Qnil;
 }
 
 /* Update the tool-bar item list for frame F.  This has to be done
@@ -11955,13 +11987,12 @@ redisplay_tool_bar (struct frame *f)
 
          XSETFRAME (frame, f);
          Fmodify_frame_parameters (frame,
-                                   Fcons (Fcons (Qtool_bar_lines,
-                                                 make_number (nlines)),
-                                          Qnil));
+                                   list1 (Fcons (Qtool_bar_lines,
+                                                 make_number (nlines))));
          if (WINDOW_TOTAL_LINES (w) != old_height)
            {
              clear_glyph_matrix (w->desired_matrix);
-             fonts_changed_p = 1;
+             f->fonts_changed = 1;
              return 1;
            }
        }
@@ -12056,14 +12087,13 @@ redisplay_tool_bar (struct frame *f)
            {
              XSETFRAME (frame, f);
              Fmodify_frame_parameters (frame,
-                                       Fcons (Fcons (Qtool_bar_lines,
-                                                     make_number (nlines)),
-                                              Qnil));
+                                       list1 (Fcons (Qtool_bar_lines,
+                                                     make_number (nlines))));
              if (WINDOW_TOTAL_LINES (w) != old_height)
                {
                  clear_glyph_matrix (w->desired_matrix);
                  f->n_tool_bar_rows = nrows;
-                 fonts_changed_p = 1;
+                 f->fonts_changed = 1;
                  return 1;
                }
            }
@@ -12294,13 +12324,11 @@ note_tool_bar_highlight (struct frame *f, int x, int y)
       hlinfo->mouse_face_beg_col = hpos;
       hlinfo->mouse_face_beg_row = vpos;
       hlinfo->mouse_face_beg_x = x;
-      hlinfo->mouse_face_beg_y = row->y;
       hlinfo->mouse_face_past_end = 0;
 
       hlinfo->mouse_face_end_col = hpos + 1;
       hlinfo->mouse_face_end_row = vpos;
       hlinfo->mouse_face_end_x = x + glyph->pixel_width;
-      hlinfo->mouse_face_end_y = row->y;
       hlinfo->mouse_face_window = window;
       hlinfo->mouse_face_face_id = TOOL_BAR_FACE_ID;
 
@@ -12545,6 +12573,7 @@ static void debug_method_add (struct window *, char const *, ...)
 static void
 debug_method_add (struct window *w, char const *fmt, ...)
 {
+  void *ptr = w;
   char *method = w->desired_matrix->method;
   int len = strlen (method);
   int size = sizeof w->desired_matrix->method;
@@ -12563,7 +12592,7 @@ debug_method_add (struct window *w, char const *fmt, ...)
 
   if (trace_redisplay_p)
     fprintf (stderr, "%p (%s): %s\n",
-            w,
+            ptr,
             ((BUFFERP (w->contents)
               && STRINGP (BVAR (XBUFFER (w->contents), name)))
              ? SSDATA (BVAR (XBUFFER (w->contents), name))
@@ -12821,7 +12850,7 @@ check_point_in_composition (struct buffer *prev_buf, ptrdiff_t prev_pt,
 
       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)
+         && 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.  */
@@ -12831,17 +12860,17 @@ check_point_in_composition (struct buffer *prev_buf, ptrdiff_t prev_pt,
   /* 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)
+         && composition_valid_p (start, end, prop)
          && start < pt && end > pt);
 }
 
-
-/* Reconsider the setting of B->clip_changed which is displayed
-   in window W.  */
+/* Reconsider the clip changes of buffer which is displayed in W.  */
 
 static void
-reconsider_clip_changes (struct window *w, struct buffer *b)
+reconsider_clip_changes (struct window *w)
 {
+  struct buffer *b = XBUFFER (w->contents);
+
   if (b->clip_changed
       && w->window_end_valid
       && w->current_matrix->buffer == b
@@ -12854,24 +12883,17 @@ reconsider_clip_changes (struct window *w, struct buffer *b)
      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->contents) && w->window_end_valid)
+  if (!b->clip_changed && w->window_end_valid)
     {
-      ptrdiff_t pt;
+      ptrdiff_t pt = (w == XWINDOW (selected_window)
+                     ? PT : marker_position (w->pointm));
 
-      if (w == XWINDOW (selected_window))
-       pt = PT;
-      else
-       pt = marker_position (w->pointm);
-
-      if ((w->current_matrix->buffer != XBUFFER (w->contents)
-          || pt != w->last_point)
+      if ((w->current_matrix->buffer != b || pt != w->last_point)
          && check_point_in_composition (w->current_matrix->buffer,
-                                        w->last_point,
-                                        XBUFFER (w->contents), pt))
+                                        w->last_point, b, pt))
        b->clip_changed = 1;
     }
 }
-\f
 
 #define STOP_POLLING                                   \
 do { if (! polling_stopped_here) stop_polling ();      \
@@ -12892,10 +12914,10 @@ redisplay_internal (void)
   struct window *sw;
   struct frame *fr;
   int pending;
-  int must_finish = 0;
+  bool must_finish = 0, match_p;
   struct text_pos tlbufpos, tlendpos;
   int number_of_visible_frames;
-  ptrdiff_t count, count1;
+  ptrdiff_t count;
   struct frame *sf;
   int polling_stopped_here = 0;
   Lisp_Object tail, frame;
@@ -12937,7 +12959,7 @@ redisplay_internal (void)
   /* Record a function that clears redisplaying_p
      when we leave this function.  */
   count = SPECPDL_INDEX ();
-  record_unwind_protect (unwind_redisplay, selected_frame);
+  record_unwind_protect_void (unwind_redisplay);
   redisplaying_p = 1;
   specbind (Qinhibit_free_realized_faces, Qnil);
 
@@ -12952,21 +12974,11 @@ redisplay_internal (void)
   sw = w;
 
   pending = 0;
-  reconsider_clip_changes (w, current_buffer);
   last_escape_glyph_frame = NULL;
   last_escape_glyph_face_id = (1 << FACE_ID_BITS);
   last_glyphless_glyph_frame = NULL;
   last_glyphless_glyph_face_id = (1 << FACE_ID_BITS);
 
-  /* 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.  */
@@ -12997,7 +13009,19 @@ redisplay_internal (void)
       struct frame *f = XFRAME (frame);
 
       if (FRAME_VISIBLE_P (f))
-       ++number_of_visible_frames;
+       {
+         ++number_of_visible_frames;
+         /* Adjust matrices for visible frames only.  */
+         if (f->fonts_changed)
+           {
+             adjust_frame_glyphs (f);
+             f->fonts_changed = 0;
+           }
+         /* If cursor type has been changed on the frame
+            other than selected, consider all frames.  */
+         if (f != sf && f->cursor_type_changed)
+           update_mode_lines++;
+       }
       clear_desired_matrices (f);
     }
 
@@ -13007,10 +13031,7 @@ redisplay_internal (void)
   /* do_pending_window_change could change the selected_window due to
      frame resizing which makes the selected window too small.  */
   if (WINDOWP (selected_window) && (w = XWINDOW (selected_window)) != sw)
-    {
-      sw = w;
-      reconsider_clip_changes (w, current_buffer);
-    }
+    sw = w;
 
   /* Clear frames marked as garbaged.  */
   clear_garbaged_frames ();
@@ -13022,26 +13043,34 @@ redisplay_internal (void)
   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) != w->last_had_star)
+  reconsider_clip_changes (w);
+
+  /* In most cases selected window displays current buffer.  */
+  match_p = XBUFFER (w->contents) == current_buffer;
+  if (match_p)
     {
-      w->update_mode_line = 1;
-      if (buffer_shared_and_changed ())
-       update_mode_lines++;
-    }
+      ptrdiff_t count1;
 
-  /* Avoid invocation of point motion hooks by `current_column' below.  */
-  count1 = SPECPDL_INDEX ();
-  specbind (Qinhibit_point_motion_hooks, Qt);
+      /* Detect case that we need to write or remove a star in the mode line.  */
+      if ((SAVE_MODIFF < MODIFF) != w->last_had_star)
+       {
+         w->update_mode_line = 1;
+         if (buffer_shared_and_changed ())
+           update_mode_lines++;
+       }
 
-  if (mode_line_update_needed (w))
-    w->update_mode_line = 1;
+      /* Avoid invocation of point motion hooks by `current_column' below.  */
+      count1 = SPECPDL_INDEX ();
+      specbind (Qinhibit_point_motion_hooks, Qt);
 
-  unbind_to (count1, Qnil);
+      if (mode_line_update_needed (w))
+       w->update_mode_line = 1;
+
+      unbind_to (count1, Qnil);
+    }
 
   consider_all_windows_p = (update_mode_lines
-                           || buffer_shared_and_changed ()
-                           || cursor_type_changed);
+                           || buffer_shared_and_changed ());
 
   /* If specs for an arrow have changed, do thorough redisplay
      to ensure we remove any arrow that should no longer exist.  */
@@ -13075,9 +13104,7 @@ redisplay_internal (void)
       if (!display_last_displayed_message_p)
        message_cleared_p = 0;
 
-      if (fonts_changed_p)
-       goto retry;
-      else if (window_height_changed_p)
+      if (window_height_changed_p)
        {
          consider_all_windows_p = 1;
          ++update_mode_lines;
@@ -13134,9 +13161,10 @@ redisplay_internal (void)
       && !current_buffer->prevent_redisplay_optimizations_p
       && FRAME_VISIBLE_P (XFRAME (w->frame))
       && !FRAME_OBSCURED_P (XFRAME (w->frame))
+      && !XFRAME (w->frame)->cursor_type_changed
       /* Make sure recorded data applies to current buffer, etc.  */
       && this_line_buffer == current_buffer
-      && current_buffer == XBUFFER (w->contents)
+      && match_p
       && !w->force_start
       && !w->optional_new_start
       /* Point must be on the line that we have info recorded about.  */
@@ -13232,12 +13260,12 @@ redisplay_internal (void)
                 adjusted.  */
              if (MATRIX_ROW_DISPLAYS_TEXT_P (it.glyph_row - 1))
                {
-                 if (XFASTINT (w->window_end_vpos) < this_line_vpos)
-                   wset_window_end_vpos (w, make_number (this_line_vpos));
+                 if (w->window_end_vpos < this_line_vpos)
+                   w->window_end_vpos = this_line_vpos;
                }
-             else if (XFASTINT (w->window_end_vpos) == this_line_vpos
+             else if (w->window_end_vpos == this_line_vpos
                       && this_line_vpos > 0)
-               wset_window_end_vpos (w, make_number (this_line_vpos - 1));
+               w->window_end_vpos = this_line_vpos - 1;
              w->window_end_valid = 0;
 
              /* Update hint: No need to try to scroll in update_window.  */
@@ -13352,6 +13380,8 @@ redisplay_internal (void)
              && !EQ (FRAME_TTY (f)->top_frame, frame))
            continue;
 
+       retry_frame:
+
          if (FRAME_WINDOW_P (f) || FRAME_TERMCAP_P (f) || f == sf)
            {
              /* Mark all the scroll bars to be removed; we'll redeem
@@ -13371,20 +13401,22 @@ redisplay_internal (void)
              if (FRAME_TERMINAL (f)->judge_scroll_bars_hook)
                FRAME_TERMINAL (f)->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))
                {
+                 /* If fonts changed on visible frame, display again.  */
+                 if (f->fonts_changed)
+                   {
+                     adjust_frame_glyphs (f);
+                     f->fonts_changed = 0;
+                     goto retry_frame;
+                   }
+
                  /* See if we have to hscroll.  */
                  if (!f->already_hscrolled_p)
                    {
                      f->already_hscrolled_p = 1;
                      if (hscroll_windows (f->root_window))
-                       goto retry;
+                       goto retry_frame;
                    }
 
                  /* Prevent various kinds of signals during display
@@ -13398,6 +13430,7 @@ redisplay_internal (void)
                  /* Update the display.  */
                  set_window_update_flags (XWINDOW (f->root_window), 1);
                  pending |= update_frame (f, 0, 0);
+                 f->cursor_type_changed = 0;
                  f->updated_p = 1;
                }
            }
@@ -13442,7 +13475,7 @@ redisplay_internal (void)
 
     update:
       /* If fonts changed, display again.  */
-      if (fonts_changed_p)
+      if (sf->fonts_changed)
        goto retry;
 
       /* Prevent various kinds of signals during display update.
@@ -13459,6 +13492,7 @@ redisplay_internal (void)
 
          XWINDOW (selected_window)->must_be_updated_p = 1;
          pending = update_frame (sf, 0, 0);
+         sf->cursor_type_changed = 0;
        }
 
       /* We may have called echo_area_display at the top of this
@@ -13473,6 +13507,7 @@ redisplay_internal (void)
        {
          XWINDOW (mini_window)->must_be_updated_p = 1;
          pending |= update_frame (mini_frame, 0, 0);
+         mini_frame->cursor_type_changed = 0;
          if (!pending && hscroll_windows (mini_window))
            goto retry;
        }
@@ -13513,7 +13548,6 @@ redisplay_internal (void)
 
       update_mode_lines = 0;
       windows_or_buffers_changed = 0;
-      cursor_type_changed = 0;
     }
 
   /* Start SIGIO interrupts coming again.  Having them off during the
@@ -13617,14 +13651,12 @@ redisplay_preserve_echo_area (int from_where)
 }
 
 
-/* Function registered with record_unwind_protect in redisplay_internal.
-   Clear redisplaying_p.  Also select the previously selected frame.  */
+/* Function registered with record_unwind_protect in redisplay_internal.  */
 
-static Lisp_Object
-unwind_redisplay (Lisp_Object old_frame)
+static void
+unwind_redisplay (void)
 {
   redisplaying_p = 0;
-  return Qnil;
 }
 
 
@@ -13656,7 +13688,7 @@ mark_window_display_accurate_1 (struct window *w, int accurate_p)
       w->current_matrix->begv = BUF_BEGV (b);
       w->current_matrix->zv = BUF_ZV (b);
 
-      w->last_cursor = w->cursor;
+      w->last_cursor_vpos = w->cursor.vpos;
       w->last_cursor_off_p = w->cursor_off_p;
 
       if (w == XWINDOW (selected_window))
@@ -14429,8 +14461,7 @@ run_window_scroll_functions (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->contents))
-    emacs_abort ();
+  eassert (current_buffer == XBUFFER (w->contents));
 
   if (!NILP (Vwindow_scroll_functions))
     {
@@ -14537,6 +14568,9 @@ try_scrolling (Lisp_Object window, int just_this_one_p,
   Lisp_Object aggressive;
   /* We will never try scrolling more than this number of lines.  */
   int scroll_limit = SCROLL_LIMIT;
+  int frame_line_height = default_line_pixel_height (w);
+  int window_total_lines
+    = WINDOW_TOTAL_LINES (w) * FRAME_LINE_HEIGHT (f) / frame_line_height;
 
 #ifdef GLYPH_DEBUG
   debug_method_add (w, "try_scrolling");
@@ -14547,8 +14581,8 @@ try_scrolling (Lisp_Object window, int just_this_one_p,
   /* 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)
-      * FRAME_LINE_HEIGHT (f);
+    this_scroll_margin = min (scroll_margin, window_total_lines / 4)
+      * frame_line_height;
   else
     this_scroll_margin = 0;
 
@@ -14559,19 +14593,19 @@ try_scrolling (Lisp_Object window, int just_this_one_p,
   if (arg_scroll_conservatively > scroll_limit)
     {
       arg_scroll_conservatively = scroll_limit + 1;
-      scroll_max = scroll_limit * FRAME_LINE_HEIGHT (f);
+      scroll_max = scroll_limit * frame_line_height;
     }
   else if (scroll_step || arg_scroll_conservatively || temp_scroll_step)
     /* Compute how much we should try to scroll maximally to bring
        point into view.  */
     scroll_max = (max (scroll_step,
                       max (arg_scroll_conservatively, temp_scroll_step))
-                 * FRAME_LINE_HEIGHT (f));
+                 * frame_line_height);
   else if (NUMBERP (BVAR (current_buffer, scroll_down_aggressively))
           || NUMBERP (BVAR (current_buffer, scroll_up_aggressively)))
     /* We're trying to scroll because of aggressive scrolling but no
        scroll_step is set.  Choose an arbitrary one.  */
-    scroll_max = 10 * FRAME_LINE_HEIGHT (f);
+    scroll_max = 10 * frame_line_height;
   else
     scroll_max = 0;
 
@@ -14586,7 +14620,7 @@ try_scrolling (Lisp_Object window, int just_this_one_p,
         either that ypos or PT, whichever comes first.  */
       start_display (&it, w, startp);
       scroll_margin_y = it.last_visible_y - this_scroll_margin
-       - FRAME_LINE_HEIGHT (f) * extra_scroll_margin_lines;
+       - frame_line_height * extra_scroll_margin_lines;
       move_it_to (&it, PT, -1, scroll_margin_y - 1, -1,
                  (MOVE_TO_POS | MOVE_TO_Y));
 
@@ -14598,7 +14632,7 @@ try_scrolling (Lisp_Object window, int just_this_one_p,
             the user limited scrolling by a small number of lines, but
             always finds PT if scroll_conservatively is set to a large
             number, such as most-positive-fixnum.  */
-         int slack = max (scroll_max, 10 * FRAME_LINE_HEIGHT (f));
+         int slack = max (scroll_max, 10 * frame_line_height);
          int y_to_move = it.last_visible_y + slack;
 
          /* Compute the distance from the scroll margin to PT or to
@@ -14625,8 +14659,8 @@ try_scrolling (Lisp_Object window, int just_this_one_p,
         move it down by scroll_step.  */
       if (arg_scroll_conservatively)
        amount_to_scroll
-         = min (max (dy, FRAME_LINE_HEIGHT (f)),
-                FRAME_LINE_HEIGHT (f) * arg_scroll_conservatively);
+         = min (max (dy, frame_line_height),
+                frame_line_height * arg_scroll_conservatively);
       else if (scroll_step || temp_scroll_step)
        amount_to_scroll = scroll_max;
       else
@@ -14723,7 +14757,7 @@ try_scrolling (Lisp_Object window, int just_this_one_p,
          start_display (&it, w, pos);
          y0 = it.current_y;
          y_to_move = max (it.last_visible_y,
-                          max (scroll_max, 10 * FRAME_LINE_HEIGHT (f)));
+                          max (scroll_max, 10 * frame_line_height));
          move_it_to (&it, CHARPOS (scroll_margin_pos), 0,
                      y_to_move, -1,
                      MOVE_TO_POS | MOVE_TO_X | MOVE_TO_Y);
@@ -14739,7 +14773,7 @@ try_scrolling (Lisp_Object window, int just_this_one_p,
          start_display (&it, w, startp);
 
          if (arg_scroll_conservatively)
-           amount_to_scroll = max (dy, FRAME_LINE_HEIGHT (f) *
+           amount_to_scroll = max (dy, frame_line_height *
                                    max (scroll_step, temp_scroll_step));
          else if (scroll_step || temp_scroll_step)
            amount_to_scroll = scroll_max;
@@ -14868,7 +14902,25 @@ compute_window_start_on_continuation_line (struct window *w)
            {
              min_distance = distance;
              pos = it.current.pos;
-             move_it_by_lines (&it, 1);
+             if (it.line_wrap == WORD_WRAP)
+               {
+                 /* Under WORD_WRAP, move_it_by_lines is likely to
+                    overshoot and stop not at the first, but the
+                    second character from the left margin.  So in
+                    that case, we need a more tight control on the X
+                    coordinate of the iterator than move_it_by_lines
+                    promises in its contract.  The method is to first
+                    go to the last (rightmost) visible character of a
+                    line, then move to the leftmost character on the
+                    next line in a separate call.  */
+                 move_it_to (&it, ZV, it.last_visible_x, it.current_y, -1,
+                             MOVE_TO_POS | MOVE_TO_X | MOVE_TO_Y);
+                 move_it_to (&it, ZV, 0,
+                             it.current_y + it.max_ascent + it.max_descent, -1,
+                             MOVE_TO_POS | MOVE_TO_X | MOVE_TO_Y);
+               }
+             else
+               move_it_by_lines (&it, 1);
            }
 
          /* Set the window start there.  */
@@ -14920,6 +14972,10 @@ try_cursor_movement (Lisp_Object window, struct text_pos startp, int *scroll_ste
      if-statement below. Now, this field is converted to
      ptrdiff_t, thus zero means invalid position in a buffer.  */
   eassert (w->last_point > 0);
+  /* Likewise there was a check whether window_end_vpos is nil or larger
+     than the window.  Now window_end_vpos is int and so never nil, but
+     let's leave eassert to check whether it fits in the window.  */
+  eassert (w->window_end_vpos < w->current_matrix->nrows);
 
   /* Handle case where text has not changed, only point, and it has
      not moved off the frame.  */
@@ -14933,7 +14989,7 @@ try_cursor_movement (Lisp_Object window, struct text_pos startp, int *scroll_ste
         cases.  */
       && !update_mode_lines
       && !windows_or_buffers_changed
-      && !cursor_type_changed
+      && !f->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.  */
@@ -14947,18 +15003,14 @@ try_cursor_movement (Lisp_Object window, struct text_pos startp, int *scroll_ste
         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)
          || !overlay_arrow_in_current_buffer_p ()))
     {
       int this_scroll_margin, top_scroll_margin;
       struct glyph_row *row = NULL;
+      int frame_line_height = default_line_pixel_height (w);
+      int window_total_lines
+       = WINDOW_TOTAL_LINES (w) * FRAME_LINE_HEIGHT (f) / frame_line_height;
 
 #ifdef GLYPH_DEBUG
       debug_method_add (w, "cursor movement");
@@ -14968,8 +15020,8 @@ try_cursor_movement (Lisp_Object window, struct text_pos startp, int *scroll_ste
         of the window.  This is a pixel value.  */
       if (scroll_margin > 0)
        {
-         this_scroll_margin = min (scroll_margin, WINDOW_TOTAL_LINES (w) / 4);
-         this_scroll_margin *= FRAME_LINE_HEIGHT (f);
+         this_scroll_margin = min (scroll_margin, window_total_lines / 4);
+         this_scroll_margin *= frame_line_height;
        }
       else
        this_scroll_margin = 0;
@@ -14980,12 +15032,12 @@ try_cursor_movement (Lisp_Object window, struct text_pos startp, int *scroll_ste
 
       /* 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)
+      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);
+         row = MATRIX_ROW (w->current_matrix, w->last_cursor_vpos);
          if (row->mode_line_p)
            ++row;
          if (!row->enabled_p)
@@ -15264,7 +15316,7 @@ set_vertical_scroll_bar (struct window *w)
       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);
+      end = BUF_Z (buf) - w->window_end_pos - BUF_BEGV (buf);
 
       if (end < start)
        end = start;
@@ -15284,9 +15336,8 @@ set_vertical_scroll_bar (struct window *w)
 /* 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.  In that case, redisplay_internal will
-   retry.  */
+   We can return without actually redisplaying the window if fonts has been
+   changed on window's frame.  In that case, redisplay_internal will retry.  */
 
 static void
 redisplay_window (Lisp_Object window, int just_this_one_p)
@@ -15311,6 +15362,7 @@ redisplay_window (Lisp_Object window, int just_this_one_p)
   int centering_position = -1;
   int last_line_misfit = 0;
   ptrdiff_t beg_unchanged, end_unchanged;
+  int frame_line_height;
 
   SET_TEXT_POS (lpoint, PT, PT_BYTE);
   opoint = lpoint;
@@ -15324,7 +15376,8 @@ redisplay_window (Lisp_Object window, int just_this_one_p)
   eassert (XMARKER (w->pointm)->buffer == buffer);
 
  restart:
-  reconsider_clip_changes (w, buffer);
+  reconsider_clip_changes (w);
+  frame_line_height = default_line_pixel_height (w);
 
   /* Has the mode line to be updated?  */
   update_mode_line = (w->update_mode_line
@@ -15403,8 +15456,8 @@ redisplay_window (Lisp_Object window, int just_this_one_p)
        && !current_buffer->clip_changed
        && !window_outdated (w));
 
-  /* When windows_or_buffers_changed is non-zero, we can't rely on
-     the window end being valid, so set it to nil there.  */
+  /* When windows_or_buffers_changed is non-zero, we can't rely
+     on the window end being valid, so set it to zero there.  */
   if (windows_or_buffers_changed)
     {
       /* If window starts on a continuation line, maybe adjust the
@@ -15413,6 +15466,9 @@ redisplay_window (Lisp_Object window, int just_this_one_p)
        compute_window_start_on_continuation_line (w);
 
       w->window_end_valid = 0;
+      /* If so, we also can't rely on current matrix
+        and should not fool try_cursor_movement below.  */
+      current_matrix_up_to_date_p = 0;
     }
 
   /* Some sanity checks.  */
@@ -15494,7 +15550,7 @@ redisplay_window (Lisp_Object window, int just_this_one_p)
 
   /* Handle case where place to start displaying has been specified,
      unless the specified location is outside the accessible range.  */
-  if (w->force_start || w->frozen_window_start_p)
+  if (w->force_start || window_frozen_p (w))
     {
       /* We set this later on if we have to adjust point.  */
       int new_vpos = -1;
@@ -15522,8 +15578,6 @@ redisplay_window (Lisp_Object window, int just_this_one_p)
          startp = run_window_scroll_functions (window, startp);
        }
 
-      w->last_modified = 0;
-      w->last_overlay_modified = 0;
       if (CHARPOS (startp) < BEGV)
        SET_TEXT_POS (startp, BEGV, BEGV_BYTE);
       else if (CHARPOS (startp) > ZV)
@@ -15541,7 +15595,7 @@ redisplay_window (Lisp_Object window, int just_this_one_p)
          goto need_larger_matrices;
        }
 
-      if (w->cursor.vpos < 0 && !w->frozen_window_start_p)
+      if (w->cursor.vpos < 0 && !window_frozen_p (w))
        {
          /* If point does not appear, try to move point so it does
             appear. The desired matrix has been built above, so we
@@ -15560,8 +15614,10 @@ redisplay_window (Lisp_Object window, int just_this_one_p)
          /* Some people insist on not letting point enter the scroll
             margin, even though this part handles windows that didn't
             scroll at all.  */
-         int margin = min (scroll_margin, WINDOW_TOTAL_LINES (w) / 4);
-         int pixel_margin = margin * FRAME_LINE_HEIGHT (f);
+         int window_total_lines
+           = WINDOW_TOTAL_LINES (w) * FRAME_LINE_HEIGHT (f) / frame_line_height;
+         int margin = min (scroll_margin, window_total_lines / 4);
+         int pixel_margin = margin * frame_line_height;
          bool header_line = WINDOW_WANTS_HEADER_LINE_P (w);
 
          /* Note: We add an extra FRAME_LINE_HEIGHT, because the loop
@@ -15569,10 +15625,11 @@ redisplay_window (Lisp_Object window, int just_this_one_p)
             the Y coordinate of the _next_ row, see the definition of
             MATRIX_ROW_BOTTOM_Y.  */
          if (w->cursor.vpos < margin + header_line)
-           new_vpos
-             = pixel_margin + (header_line
-                               ? CURRENT_HEADER_LINE_HEIGHT (w)
-                               : 0) + FRAME_LINE_HEIGHT (f);
+           {
+             w->cursor.vpos = -1;
+             clear_glyph_matrix (w->desired_matrix);
+             goto try_to_scroll;
+           }
          else
            {
              int window_height = window_box_height (w);
@@ -15580,7 +15637,11 @@ redisplay_window (Lisp_Object window, int just_this_one_p)
              if (header_line)
                window_height += CURRENT_HEADER_LINE_HEIGHT (w);
              if (w->cursor.y >= window_height - pixel_margin)
-               new_vpos = window_height - pixel_margin;
+               {
+                 w->cursor.vpos = -1;
+                 clear_glyph_matrix (w->desired_matrix);
+                 goto try_to_scroll;
+               }
            }
        }
 
@@ -15661,7 +15722,7 @@ redisplay_window (Lisp_Object window, int just_this_one_p)
       debug_method_add (w, "try_window_id %d", tem);
 #endif
 
-      if (fonts_changed_p)
+      if (f->fonts_changed)
        goto need_larger_matrices;
       if (tem > 0)
        goto done;
@@ -15731,12 +15792,12 @@ redisplay_window (Lisp_Object window, int just_this_one_p)
          IF_DEBUG (debug_method_add (w, "1"));
          if (try_window (window, startp, TRY_WINDOW_CHECK_MARGINS) < 0)
            /* -1 means we need to scroll.
-              0 means we need new matrices, but fonts_changed_p
+              0 means we need new matrices, but fonts_changed
               is set in that case, so we will detect it below.  */
            goto try_to_scroll;
        }
 
-      if (fonts_changed_p)
+      if (f->fonts_changed)
        goto need_larger_matrices;
 
       if (w->cursor.vpos >= 0)
@@ -15762,9 +15823,6 @@ redisplay_window (Lisp_Object window, int just_this_one_p)
 
  try_to_scroll:
 
-  w->last_modified = 0;
-  w->last_overlay_modified = 0;
-
   /* Redisplay the mode line.  Select the buffer properly for that.  */
   if (!update_mode_line)
     {
@@ -15821,9 +15879,11 @@ redisplay_window (Lisp_Object window, int just_this_one_p)
   it.current_y = it.last_visible_y;
   if (centering_position < 0)
     {
+      int window_total_lines
+       = WINDOW_TOTAL_LINES (w) * FRAME_LINE_HEIGHT (f) / frame_line_height;
       int margin =
        scroll_margin > 0
-       ? min (scroll_margin, WINDOW_TOTAL_LINES (w) / 4)
+       ? min (scroll_margin, window_total_lines / 4)
        : 0;
       ptrdiff_t margin_pos = CHARPOS (startp);
       Lisp_Object aggressive;
@@ -15845,7 +15905,7 @@ redisplay_window (Lisp_Object window, int just_this_one_p)
 
          SAVE_IT (it1, it, it1data);
          start_display (&it1, w, startp);
-         move_it_vertically (&it1, margin * FRAME_LINE_HEIGHT (f));
+         move_it_vertically (&it1, margin * frame_line_height);
          margin_pos = IT_CHARPOS (it1);
          RESTORE_IT (&it, &it, it1data);
        }
@@ -15881,15 +15941,15 @@ redisplay_window (Lisp_Object window, int just_this_one_p)
              if (pt_offset)
                centering_position -= pt_offset;
              centering_position -=
-               FRAME_LINE_HEIGHT (f) * (1 + margin + (last_line_misfit != 0))
+               frame_line_height * (1 + margin + (last_line_misfit != 0))
                + WINDOW_HEADER_LINE_HEIGHT (w);
              /* Don't let point enter the scroll margin near top of
                 the window.  */
-             if (centering_position < margin * FRAME_LINE_HEIGHT (f))
-               centering_position = margin * FRAME_LINE_HEIGHT (f);
+             if (centering_position < margin * frame_line_height)
+               centering_position = margin * frame_line_height;
            }
          else
-           centering_position = margin * FRAME_LINE_HEIGHT (f) + pt_offset;
+           centering_position = margin * frame_line_height + pt_offset;
        }
       else
        /* Set the window start half the height of the window backward
@@ -15925,7 +15985,7 @@ redisplay_window (Lisp_Object window, int just_this_one_p)
   /* Redisplay the window.  */
   if (!current_matrix_up_to_date_p
       || windows_or_buffers_changed
-      || cursor_type_changed
+      || f->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)
@@ -15938,7 +15998,7 @@ redisplay_window (Lisp_Object window, int just_this_one_p)
   /* 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)
+  if (f->fonts_changed)
     goto need_larger_matrices;
 
   /* If cursor did not appear assume that the middle of the window is
@@ -15948,7 +16008,7 @@ redisplay_window (Lisp_Object window, int just_this_one_p)
      line.)  */
   if (w->cursor.vpos < 0)
     {
-      if (w->window_end_valid && PT >= Z - XFASTINT (w->window_end_pos))
+      if (w->window_end_valid && PT >= Z - w->window_end_pos)
        {
          clear_glyph_matrix (w->desired_matrix);
          move_it_by_lines (&it, 1);
@@ -15994,11 +16054,13 @@ redisplay_window (Lisp_Object window, int just_this_one_p)
         make that row fully visible and out of the margin.  */
       if (scroll_conservatively > SCROLL_LIMIT)
        {
+         int window_total_lines
+           = WINDOW_TOTAL_LINES (w) * FRAME_LINE_HEIGHT (f) * frame_line_height;
          int margin =
            scroll_margin > 0
-           ? min (scroll_margin, WINDOW_TOTAL_LINES (w) / 4)
+           ? min (scroll_margin, window_total_lines / 4)
            : 0;
-         int move_down = w->cursor.vpos >= WINDOW_TOTAL_LINES (w) / 2;
+         int move_down = w->cursor.vpos >= window_total_lines / 2;
 
          move_it_by_lines (&it, move_down ? margin + 1 : -(margin + 1));
          clear_glyph_matrix (w->desired_matrix);
@@ -16049,7 +16111,8 @@ redisplay_window (Lisp_Object window, int just_this_one_p)
       if (WINDOW_WANTS_MODELINE_P (w)
          && CURRENT_MODE_LINE_HEIGHT (w) != DESIRED_MODE_LINE_HEIGHT (w))
        {
-         fonts_changed_p = 1;
+         f->fonts_changed = 1;
+         w->mode_line_height = -1;
          MATRIX_MODE_LINE_ROW (w->current_matrix)->height
            = DESIRED_MODE_LINE_HEIGHT (w);
        }
@@ -16059,12 +16122,13 @@ redisplay_window (Lisp_Object window, int just_this_one_p)
       if (WINDOW_WANTS_HEADER_LINE_P (w)
          && CURRENT_HEADER_LINE_HEIGHT (w) != DESIRED_HEADER_LINE_HEIGHT (w))
        {
-         fonts_changed_p = 1;
+         f->fonts_changed = 1;
+         w->header_line_height = -1;
          MATRIX_HEADER_LINE_ROW (w->current_matrix)->height
            = DESIRED_HEADER_LINE_HEIGHT (w);
        }
 
-      if (fonts_changed_p)
+      if (f->fonts_changed)
        goto need_larger_matrices;
     }
 
@@ -16129,8 +16193,8 @@ redisplay_window (Lisp_Object window, int just_this_one_p)
     }
 #endif /* HAVE_WINDOW_SYSTEM */
 
-  /* We go to this label, with fonts_changed_p set,
-     if it is necessary to try again using larger glyph matrices.
+  /* We go to this label, with fonts_changed set, 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:
@@ -16185,6 +16249,7 @@ try_window (Lisp_Object window, struct text_pos pos, int flags)
   struct it it;
   struct glyph_row *last_text_row = NULL;
   struct frame *f = XFRAME (w->frame);
+  int frame_line_height = default_line_pixel_height (w);
 
   /* Make POS the new window start.  */
   set_marker_both (w->start, Qnil, CHARPOS (pos), BYTEPOS (pos));
@@ -16201,7 +16266,7 @@ try_window (Lisp_Object window, struct text_pos pos, int flags)
     {
       if (display_line (&it))
        last_text_row = it.glyph_row - 1;
-      if (fonts_changed_p && !(flags & TRY_WINDOW_IGNORE_FONTS_CHANGE))
+      if (f->fonts_changed && !(flags & TRY_WINDOW_IGNORE_FONTS_CHANGE))
        return 0;
     }
 
@@ -16210,11 +16275,13 @@ try_window (Lisp_Object window, struct text_pos pos, int flags)
       && !MINI_WINDOW_P (w))
     {
       int this_scroll_margin;
+      int window_total_lines
+       = WINDOW_TOTAL_LINES (w) * FRAME_LINE_HEIGHT (f) / frame_line_height;
 
       if (scroll_margin > 0)
        {
-         this_scroll_margin = min (scroll_margin, WINDOW_TOTAL_LINES (w) / 4);
-         this_scroll_margin *= FRAME_LINE_HEIGHT (f);
+         this_scroll_margin = min (scroll_margin, window_total_lines / 4);
+         this_scroll_margin *= frame_line_height;
        }
       else
        this_scroll_margin = 0;
@@ -16236,8 +16303,7 @@ try_window (Lisp_Object window, struct text_pos pos, int flags)
     }
 
   /* If bottom moved off end of frame, change mode line percentage.  */
-  if (XFASTINT (w->window_end_pos) <= 0
-      && Z != IT_CHARPOS (it))
+  if (w->window_end_pos <= 0 && Z != IT_CHARPOS (it))
     w->update_mode_line = 1;
 
   /* Set window_end_pos to the offset of the last character displayed
@@ -16246,21 +16312,16 @@ try_window (Lisp_Object window, struct text_pos pos, int flags)
   if (last_text_row)
     {
       eassert (MATRIX_ROW_DISPLAYS_TEXT_P (last_text_row));
-      w->window_end_bytepos
-       = Z_BYTE - MATRIX_ROW_END_BYTEPOS (last_text_row);
-      wset_window_end_pos
-       (w, make_number (Z - MATRIX_ROW_END_CHARPOS (last_text_row)));
-      wset_window_end_vpos
-       (w, make_number (MATRIX_ROW_VPOS (last_text_row, w->desired_matrix)));
+      adjust_window_ends (w, last_text_row, 0);
       eassert
        (MATRIX_ROW_DISPLAYS_TEXT_P (MATRIX_ROW (w->desired_matrix,
-                                                XFASTINT (w->window_end_vpos))));
+                                                w->window_end_vpos)));
     }
   else
     {
       w->window_end_bytepos = Z_BYTE - ZV_BYTE;
-      wset_window_end_pos (w, make_number (Z - ZV));
-      wset_window_end_vpos (w, make_number (0));
+      w->window_end_pos = Z - ZV;
+      w->window_end_vpos = 0;
     }
 
   /* But that is not valid info until redisplay finishes.  */
@@ -16303,7 +16364,7 @@ try_window_reusing_current_matrix (struct window *w)
       /* Don't try to reuse the display if windows have been split
         or such.  */
       || windows_or_buffers_changed
-      || cursor_type_changed)
+      || f->cursor_type_changed)
     return 0;
 
   /* Can't do this if region may have changed.  */
@@ -16351,8 +16412,7 @@ try_window_reusing_current_matrix (struct window *w)
       w->cursor.vpos = -1;
       last_text_row = last_reused_text_row = NULL;
 
-      while (it.current_y < it.last_visible_y
-            && !fonts_changed_p)
+      while (it.current_y < it.last_visible_y && !f->fonts_changed)
        {
          /* If we have reached into the characters in the START row,
             that means the line boundaries have changed.  So we
@@ -16484,32 +16544,15 @@ try_window_reusing_current_matrix (struct window *w)
         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);
-         wset_window_end_pos
-           (w, make_number (Z
-                            - MATRIX_ROW_END_CHARPOS (last_reused_text_row)));
-         wset_window_end_vpos
-           (w, make_number (MATRIX_ROW_VPOS (last_reused_text_row,
-                                             w->current_matrix)));
-       }
+       adjust_window_ends (w, last_reused_text_row, 1);
       else if (last_text_row)
-       {
-         w->window_end_bytepos
-           = Z_BYTE - MATRIX_ROW_END_BYTEPOS (last_text_row);
-         wset_window_end_pos
-           (w, make_number (Z - MATRIX_ROW_END_CHARPOS (last_text_row)));
-         wset_window_end_vpos
-           (w, make_number (MATRIX_ROW_VPOS (last_text_row,
-                                             w->desired_matrix)));
-       }
+       adjust_window_ends (w, last_text_row, 0);
       else
        {
          /* This window must be completely empty.  */
          w->window_end_bytepos = Z_BYTE - ZV_BYTE;
-         wset_window_end_pos (w, make_number (Z - ZV));
-         wset_window_end_vpos (w, make_number (0));
+         w->window_end_pos = Z - ZV;
+         w->window_end_vpos = 0;
        }
       w->window_end_valid = 0;
 
@@ -16580,7 +16623,7 @@ try_window_reusing_current_matrix (struct window *w)
       if (pt_row == NULL)
        w->cursor.vpos = -1;
       last_text_row = NULL;
-      while (it.current_y < it.last_visible_y && !fonts_changed_p)
+      while (it.current_y < it.last_visible_y && !f->fonts_changed)
        if (display_line (&it))
          last_text_row = it.glyph_row - 1;
 
@@ -16694,20 +16737,9 @@ try_window_reusing_current_matrix (struct window *w)
         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);
-         wset_window_end_pos
-           (w, make_number (Z - MATRIX_ROW_END_CHARPOS (last_text_row)));
-         wset_window_end_vpos
-           (w, make_number (MATRIX_ROW_VPOS (last_text_row,
-                                             w->desired_matrix)));
-       }
+       adjust_window_ends (w, last_text_row, 0);
       else
-       {
-         wset_window_end_vpos
-           (w, make_number (XFASTINT (w->window_end_vpos) - nrows_scrolled));
-       }
+       w->window_end_vpos -= nrows_scrolled;
 
       w->window_end_valid = 0;
       w->desired_matrix->no_scrolling_p = 1;
@@ -16847,11 +16879,11 @@ find_first_unchanged_at_end_row (struct window *w,
   /* 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)
+  if (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));
+  row = MATRIX_ROW (w->current_matrix, w->window_end_vpos);
 
   /* If matrix is entirely empty, no unchanged row exists.  */
   if (MATRIX_ROW_DISPLAYS_TEXT_P (row))
@@ -16862,7 +16894,7 @@ find_first_unchanged_at_end_row (struct window *w,
         buffer positions in the current matrix to current buffer
         positions for characters not in changed text.  */
       ptrdiff_t Z_old =
-       MATRIX_ROW_END_CHARPOS (row) + XFASTINT (w->window_end_pos);
+       MATRIX_ROW_END_CHARPOS (row) + w->window_end_pos;
       ptrdiff_t Z_BYTE_old =
        MATRIX_ROW_END_BYTEPOS (row) + w->window_end_bytepos;
       ptrdiff_t last_unchanged_pos, last_unchanged_pos_old;
@@ -17103,7 +17135,7 @@ try_window_id (struct window *w)
     GIVE_UP (1);
 
   /* This flag is used to prevent redisplay optimizations.  */
-  if (windows_or_buffers_changed || cursor_type_changed)
+  if (windows_or_buffers_changed || f->cursor_type_changed)
     GIVE_UP (2);
 
   /* Verify that narrowing has not changed.
@@ -17196,7 +17228,7 @@ try_window_id (struct window *w)
      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));
+  row = MATRIX_ROW (w->current_matrix, w->window_end_vpos);
   if (MATRIX_ROW_DISPLAYS_TEXT_P (row)
       && ((last_changed_charpos < CHARPOS (start)
           && CHARPOS (start) == BEGV)
@@ -17208,7 +17240,7 @@ try_window_id (struct window *w)
 
       /* 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_old = MATRIX_ROW_END_CHARPOS (row) + w->window_end_pos;
       Z_BYTE_old = MATRIX_ROW_END_BYTEPOS (row) + w->window_end_bytepos;
       Z_delta = Z - Z_old;
       Z_delta_bytes = Z_BYTE - Z_BYTE_old;
@@ -17279,10 +17311,8 @@ try_window_id (struct window *w)
        {
          /* We have to compute the window end anew since text
             could have been added/removed after it.  */
-         wset_window_end_pos
-           (w, make_number (Z - MATRIX_ROW_END_CHARPOS (row)));
-         w->window_end_bytepos
-           = Z_BYTE - MATRIX_ROW_END_BYTEPOS (row);
+         w->window_end_pos = 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);
@@ -17315,7 +17345,7 @@ try_window_id (struct window *w)
 
   /* 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));
+  row = MATRIX_ROW (current_matrix, w->window_end_vpos);
   if (MATRIX_ROW_START_CHARPOS (row) == MATRIX_ROW_END_CHARPOS (row))
     GIVE_UP (20);
 
@@ -17436,7 +17466,7 @@ try_window_id (struct window *w)
   last_text_row = NULL;
   overlay_arrow_seen = 0;
   while (it.current_y < it.last_visible_y
-        && !fonts_changed_p
+        && !f->fonts_changed
         && (first_unchanged_at_end_row == NULL
             || IT_CHARPOS (it) < stop_pos))
     {
@@ -17444,7 +17474,7 @@ try_window_id (struct window *w)
        last_text_row = it.glyph_row - 1;
     }
 
-  if (fonts_changed_p)
+  if (f->fonts_changed)
     return -1;
 
 
@@ -17515,10 +17545,13 @@ try_window_id (struct window *w)
   /* Don't let the cursor end in the scroll margins.  */
   {
     int this_scroll_margin, cursor_height;
+    int frame_line_height = default_line_pixel_height (w);
+    int window_total_lines
+      = WINDOW_TOTAL_LINES (w) * FRAME_LINE_HEIGHT (it.f) / frame_line_height;
 
     this_scroll_margin =
-      max (0, min (scroll_margin, WINDOW_TOTAL_LINES (w) / 4));
-    this_scroll_margin *= FRAME_LINE_HEIGHT (it.f);
+      max (0, min (scroll_margin, window_total_lines / 4));
+    this_scroll_margin *= frame_line_height;
     cursor_height = MATRIX_ROW (w->desired_matrix, w->cursor.vpos)->height;
 
     if ((w->cursor.y < this_scroll_margin
@@ -17658,7 +17691,7 @@ try_window_id (struct window *w)
       /* 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;
+      int last_vpos = 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.  */
@@ -17688,8 +17721,7 @@ try_window_id (struct window *w)
 
       /* 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)
+      while (it.current_y < it.last_visible_y && !f->fonts_changed)
        {
          /* Is it always sure that the display agrees with lines in
             the current matrix?  I don't think so, so we mark rows
@@ -17702,8 +17734,7 @@ try_window_id (struct window *w)
     }
 
   /* Update window_end_pos and window_end_vpos.  */
-  if (first_unchanged_at_end_row
-      && !last_text_row_at_end)
+  if (first_unchanged_at_end_row && !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
@@ -17713,23 +17744,13 @@ try_window_id (struct window *w)
       row = find_last_row_displaying_text (w->current_matrix, &it,
                                           first_unchanged_at_end_row);
       eassert (row && MATRIX_ROW_DISPLAYS_TEXT_P (row));
-
-      wset_window_end_pos (w, make_number (Z - MATRIX_ROW_END_CHARPOS (row)));
-      w->window_end_bytepos = Z_BYTE - MATRIX_ROW_END_BYTEPOS (row);
-      wset_window_end_vpos
-       (w, make_number (MATRIX_ROW_VPOS (row, w->current_matrix)));
+      adjust_window_ends (w, row, 1);
       eassert (w->window_end_bytepos >= 0);
       IF_DEBUG (debug_method_add (w, "A"));
     }
   else if (last_text_row_at_end)
     {
-      wset_window_end_pos
-       (w, 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);
-      wset_window_end_vpos
-       (w, make_number (MATRIX_ROW_VPOS (last_text_row_at_end,
-                                         desired_matrix)));
+      adjust_window_ends (w, last_text_row_at_end, 0);
       eassert (w->window_end_bytepos >= 0);
       IF_DEBUG (debug_method_add (w, "B"));
     }
@@ -17738,12 +17759,7 @@ try_window_id (struct window *w)
       /* 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.  */
-      wset_window_end_pos
-       (w, make_number (Z - MATRIX_ROW_END_CHARPOS (last_text_row)));
-      w->window_end_bytepos
-       = Z_BYTE - MATRIX_ROW_END_BYTEPOS (last_text_row);
-      wset_window_end_vpos
-       (w, make_number (MATRIX_ROW_VPOS (last_text_row, desired_matrix)));
+      adjust_window_ends (w, last_text_row, 0);
       eassert (w->window_end_bytepos >= 0);
     }
   else if (first_unchanged_at_end_row == NULL
@@ -17753,7 +17769,7 @@ try_window_id (struct window *w)
       /* 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);
+      int vpos = w->window_end_vpos;
       struct glyph_row *current_row = current_matrix->rows + vpos;
       struct glyph_row *desired_row = desired_matrix->rows + vpos;
 
@@ -17771,8 +17787,8 @@ try_window_id (struct window *w)
        }
 
       eassert (row != NULL);
-      wset_window_end_vpos (w, make_number (vpos + 1));
-      wset_window_end_pos (w, make_number (Z - MATRIX_ROW_END_CHARPOS (row)));
+      w->window_end_vpos = vpos + 1;
+      w->window_end_pos = Z - MATRIX_ROW_END_CHARPOS (row);
       w->window_end_bytepos = Z_BYTE - MATRIX_ROW_END_BYTEPOS (row);
       eassert (w->window_end_bytepos >= 0);
       IF_DEBUG (debug_method_add (w, "C"));
@@ -17780,8 +17796,8 @@ try_window_id (struct window *w)
   else
     emacs_abort ();
 
-  IF_DEBUG (debug_end_pos = XFASTINT (w->window_end_pos);
-           debug_end_vpos = XFASTINT (w->window_end_vpos));
+  IF_DEBUG (debug_end_pos = w->window_end_pos;
+           debug_end_vpos = w->window_end_vpos);
 
   /* Record that display has not been completed.  */
   w->window_end_valid = 0;
@@ -19241,7 +19257,7 @@ display_line (struct it *it)
       >= it->w->desired_matrix->nrows)
     {
       it->w->nrows_scale_factor++;
-      fonts_changed_p = 1;
+      it->f->fonts_changed = 1;
       return 0;
     }
 
@@ -20061,7 +20077,7 @@ Value is the new character position of point.  */)
   (Lisp_Object direction)
 {
   struct window *w = XWINDOW (selected_window);
-  struct buffer *b = NULL;
+  struct buffer *b = XBUFFER (w->contents);
   struct glyph_row *row;
   int dir;
   Lisp_Object paragraph_dir;
@@ -20081,9 +20097,6 @@ Value is the new character position of point.  */)
   else
     dir = -1;
 
-  if (BUFFERP (w->contents))
-    b = XBUFFER (w->contents);
-
   /* If current matrix is up-to-date, we can use the information
      recorded in the glyphs, at least as long as the goal is on the
      screen.  */
@@ -20092,8 +20105,7 @@ Value is the new character position of point.  */)
       && b
       && !b->clip_changed
       && !b->prevent_redisplay_optimizations_p
-      && w->last_modified >= BUF_MODIFF (b)
-      && w->last_overlay_modified >= BUF_OVERLAY_MODIFF (b)
+      && !window_outdated (w)
       && w->cursor.vpos >= 0
       && w->cursor.vpos < w->current_matrix->nrows
       && (row = MATRIX_ROW (w->current_matrix, w->cursor.vpos))->enabled_p)
@@ -20110,7 +20122,7 @@ Value is the new character position of point.  */)
              w->cursor.vpos = -1;
              return make_number (PT);
            }
-         else if (!INTEGERP (g->object) && g->object != gpt->object)
+         else if (!INTEGERP (g->object) && !EQ (g->object, gpt->object))
            {
              ptrdiff_t new_pos;
 
@@ -20387,7 +20399,7 @@ Value is the new character position of point.  */)
                break;
            }
          /* If we ended up on a composed character inside
-            bidi-reordered text (e.g., Hebrew text with diacriticals),
+            bidi-reordered text (e.g., Hebrew text with diacritics),
             the iterator gives us the buffer position of the last (in
             logical order) character of the composed grapheme cluster,
             which is not what we want.  So we cheat: we compute the
@@ -20597,13 +20609,8 @@ redisplay_mode_lines (Lisp_Object window, int force)
            {
              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));
+             CLIP_TEXT_POS_FROM_MARKER (pt, w->pointm);
+             TEMP_SET_PT_BOTH (CHARPOS (pt), BYTEPOS (pt));
            }
 
          /* Display mode lines.  */
@@ -21280,7 +21287,7 @@ store_mode_line_string (const char *string, Lisp_Object lisp_string, int copy_st
          if (NILP (face))
            face = mode_line_string_face;
          else
-           face = Fcons (face, Fcons (mode_line_string_face, Qnil));
+           face = list2 (face, mode_line_string_face);
          props = Fplist_put (props, Qface, face);
        }
       Fadd_text_properties (make_number (0), make_number (len),
@@ -21304,8 +21311,8 @@ store_mode_line_string (const char *string, Lisp_Object lisp_string, int copy_st
          if (NILP (face))
            face = mode_line_string_face;
          else
-           face = Fcons (face, Fcons (mode_line_string_face, Qnil));
-         props = Fcons (Qface, Fcons (face, Qnil));
+           face = list2 (face, mode_line_string_face);
+         props = list2 (Qface, face);
          if (copy_string)
            lisp_string = Fcopy_sequence (lisp_string);
        }
@@ -21419,7 +21426,7 @@ are the selected window and the WINDOW's buffer).  */)
       mode_line_string_list = Qnil;
       mode_line_string_face = face;
       mode_line_string_face_prop
-       = (NILP (face) ? Qnil : Fcons (Qface, Fcons (face, Qnil)));
+       = NILP (face) ? Qnil : list2 (Qface, face);
     }
 
   push_kboard (FRAME_KBOARD (it.f));
@@ -21953,7 +21960,7 @@ decode_mode_spec (struct window *w, register int c, int field_width,
        ptrdiff_t pos = marker_position (w->start);
        ptrdiff_t total = BUF_ZV (b) - BUF_BEGV (b);
 
-       if (XFASTINT (w->window_end_pos) <= BUF_Z (b) - BUF_ZV (b))
+       if (w->window_end_pos <= BUF_Z (b) - BUF_ZV (b))
          {
            if (pos <= BUF_BEGV (b))
              return "All";
@@ -21982,7 +21989,7 @@ decode_mode_spec (struct window *w, register int c, int field_width,
     case 'P':
       {
        ptrdiff_t toppos = marker_position (w->start);
-       ptrdiff_t botpos = BUF_Z (b) - XFASTINT (w->window_end_pos);
+       ptrdiff_t botpos = BUF_Z (b) - w->window_end_pos;
        ptrdiff_t total = BUF_ZV (b) - BUF_BEGV (b);
 
        if (botpos >= BUF_ZV (b))
@@ -23802,17 +23809,15 @@ draw_glyphs (struct window *w, int x, struct glyph_row *row,
          && hlinfo->mouse_face_beg_row >= 0
          && hlinfo->mouse_face_end_row >= 0)
        {
-         struct glyph_row *mouse_beg_row, *mouse_end_row;
+         ptrdiff_t row_vpos = MATRIX_ROW_VPOS (row, w->current_matrix);
 
-         mouse_beg_row = MATRIX_ROW (w->current_matrix, hlinfo->mouse_face_beg_row);
-         mouse_end_row = MATRIX_ROW (w->current_matrix, hlinfo->mouse_face_end_row);
-
-         if (row >= mouse_beg_row && row <= mouse_end_row)
+         if (row_vpos >= hlinfo->mouse_face_beg_row
+             && row_vpos <= hlinfo->mouse_face_end_row)
            {
              check_mouse_face = 1;
-             mouse_beg_col = (row == mouse_beg_row)
+             mouse_beg_col = (row_vpos == hlinfo->mouse_face_beg_row)
                ? hlinfo->mouse_face_beg_col : 0;
-             mouse_end_col = (row == mouse_end_row)
+             mouse_end_col = (row_vpos == hlinfo->mouse_face_end_row)
                ? hlinfo->mouse_face_end_col
                : row->used[TEXT_AREA];
            }
@@ -23980,12 +23985,12 @@ draw_glyphs (struct window *w, int x, struct glyph_row *row,
 
 #define IT_EXPAND_MATRIX_WIDTH(it, area)               \
   {                                                    \
-    if (!fonts_changed_p                               \
+    if (!it->f->fonts_changed                          \
        && (it->glyph_row->glyphs[area]                 \
            < it->glyph_row->glyphs[area + 1]))         \
       {                                                        \
        it->w->ncols_scale_factor++;                    \
-       fonts_changed_p = 1;                            \
+       it->f->fonts_changed = 1;                       \
       }                                                        \
   }
 
@@ -24901,21 +24906,7 @@ produce_glyphless_glyph (struct it *it, int for_no_font, Lisp_Object acronym)
   base_height = it->ascent + it->descent;
   base_width = font->average_width;
 
-  /* Get a face ID for the glyph by utilizing a cache (the same way as
-     done for `escape-glyph' in get_next_display_element).  */
-  if (it->f == last_glyphless_glyph_frame
-      && it->face_id == last_glyphless_glyph_face_id)
-    {
-      face_id = last_glyphless_glyph_merged_face_id;
-    }
-  else
-    {
-      /* Merge the `glyphless-char' face into the current face.  */
-      face_id = merge_faces (it->f, Qglyphless_char, 0, it->face_id);
-      last_glyphless_glyph_frame = it->f;
-      last_glyphless_glyph_face_id = it->face_id;
-      last_glyphless_glyph_merged_face_id = face_id;
-    }
+  face_id = merge_glyphless_glyph_face (it);
 
   if (it->glyphless_method == GLYPHLESS_DISPLAY_THIN_SPACE)
     {
@@ -25703,17 +25694,16 @@ x_produce_glyphs (struct it *it)
 
 /* 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.  */
+   Advance the nominal cursor over the text.  UPDATED_ROW is the glyph row
+   being updated, and UPDATED_AREA is the area of that row being updated.  */
 
 void
-x_write_glyphs (struct glyph *start, int len)
+x_write_glyphs (struct window *w, struct glyph_row *updated_row,
+               struct glyph *start, enum glyph_row_area updated_area, int len)
 {
-  int x, hpos, chpos = updated_window->phys_cursor.hpos;
+  int x, hpos, chpos = w->phys_cursor.hpos;
 
-  eassert (updated_window && updated_row);
+  eassert (updated_row);
   /* When the window is hscrolled, cursor hpos can legitimately be out
      of bounds, but we draw the cursor at the corresponding window
      margin in that case.  */
@@ -25727,24 +25717,24 @@ x_write_glyphs (struct glyph *start, int len)
   /* Write glyphs.  */
 
   hpos = start - updated_row->glyphs[updated_area];
-  x = draw_glyphs (updated_window, output_cursor.x,
+  x = draw_glyphs (w, w->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
+      && w->phys_cursor_on_p
+      && w->phys_cursor.vpos == w->output_cursor.vpos
       && chpos >= hpos
       && chpos < hpos + len)
-    updated_window->phys_cursor_on_p = 0;
+    w->phys_cursor_on_p = 0;
 
   unblock_input ();
 
   /* Advance the output cursor.  */
-  output_cursor.hpos += len;
-  output_cursor.x = x;
+  w->output_cursor.hpos += len;
+  w->output_cursor.x = x;
 }
 
 
@@ -25752,19 +25742,18 @@ x_write_glyphs (struct glyph *start, int len)
    Insert LEN glyphs from START at the nominal cursor position.  */
 
 void
-x_insert_glyphs (struct glyph *start, int len)
+x_insert_glyphs (struct window *w, struct glyph_row *updated_row,
+                struct glyph *start, enum glyph_row_area updated_area, 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;
   ptrdiff_t hpos;
 
-  eassert (updated_window && updated_row);
+  eassert (updated_row);
   block_input ();
-  w = updated_window;
   f = XFRAME (WINDOW_FRAME (w));
 
   /* Get the height of the line we are in.  */
@@ -25778,25 +25767,25 @@ x_insert_glyphs (struct glyph *start, int len)
 
   /* Get the width of the region to shift right.  */
   shifted_region_width = (window_box_width (w, updated_area)
-                         - output_cursor.x
+                         - w->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);
+  frame_x = window_box_left (w, updated_area) + w->output_cursor.x;
+  frame_y = WINDOW_TO_FRAME_PIXEL_Y (w, w->output_cursor.y);
 
   FRAME_RIF (f)->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,
+  draw_glyphs (w, 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;
+  w->output_cursor.hpos += len;
+  w->output_cursor.x += shift_by_width;
   unblock_input ();
 }
 
@@ -25806,18 +25795,18 @@ x_insert_glyphs (struct glyph *start, int len)
    (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.  */
+   TO_X is a pixel position relative to UPDATED_AREA of currently
+   updated window W.  TO_X == -1 means clear to the end of this area.  */
 
 void
-x_clear_end_of_line (int to_x)
+x_clear_end_of_line (struct window *w, struct glyph_row *updated_row,
+                    enum glyph_row_area updated_area, 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;
 
-  eassert (updated_window && updated_row);
+  eassert (updated_row);
   f = XFRAME (w->frame);
 
   if (updated_row->full_width_p)
@@ -25835,16 +25824,16 @@ x_clear_end_of_line (int to_x)
   else
     to_x = min (to_x, max_x);
 
-  to_y = min (max_y, output_cursor.y + updated_row->height);
+  to_y = min (max_y, w->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,
+                              w->output_cursor.x, -1,
                               updated_row->y,
                               MATRIX_ROW_BOTTOM_Y (updated_row));
 
-  from_x = output_cursor.x;
+  from_x = w->output_cursor.x;
 
   /* Translate to frame coordinates.  */
   if (updated_row->full_width_p)
@@ -25860,7 +25849,7 @@ x_clear_end_of_line (int to_x)
     }
 
   min_y = WINDOW_HEADER_LINE_HEIGHT (w);
-  from_y = WINDOW_TO_FRAME_PIXEL_Y (w, max (min_y, output_cursor.y));
+  from_y = WINDOW_TO_FRAME_PIXEL_Y (w, max (min_y, w->output_cursor.y));
   to_y = WINDOW_TO_FRAME_PIXEL_Y (w, to_y);
 
   /* Prevent inadvertently clearing to end of the X window.  */
@@ -25956,6 +25945,9 @@ set_frame_cursor_types (struct frame *f, Lisp_Object arg)
     }
   else
     FRAME_BLINK_OFF_CURSOR (f) = DEFAULT_CURSOR;
+
+  /* Make sure the cursor gets redrawn.  */
+  f->cursor_type_changed = 1;
 }
 
 
@@ -26404,7 +26396,7 @@ erase_phys_cursor (struct window *w)
    where to put the cursor is specified by HPOS, VPOS, X and Y.  */
 
 void
-display_and_set_cursor (struct window *w, int on,
+display_and_set_cursor (struct window *w, bool on,
                        int hpos, int vpos, int x, int y)
 {
   struct frame *f = XFRAME (w->frame);
@@ -26488,7 +26480,7 @@ display_and_set_cursor (struct window *w, int on,
    of ON.  */
 
 static void
-update_window_cursor (struct window *w, int on)
+update_window_cursor (struct window *w, bool on)
 {
   /* Don't update cursor in windows whose frame is in the process
      of being deleted.  */
@@ -26524,7 +26516,7 @@ update_window_cursor (struct window *w, int on)
    in the window tree rooted at W.  */
 
 static void
-update_cursor_in_window_tree (struct window *w, int on_p)
+update_cursor_in_window_tree (struct window *w, bool on_p)
 {
   while (w)
     {
@@ -26543,7 +26535,7 @@ update_cursor_in_window_tree (struct window *w, int on_p)
    Don't change the cursor's position.  */
 
 void
-x_update_cursor (struct frame *f, int on_p)
+x_update_cursor (struct frame *f, bool on_p)
 {
   update_cursor_in_window_tree (XWINDOW (f->root_window), on_p);
 }
@@ -26730,10 +26722,7 @@ clear_mouse_face (Mouse_HLInfo *hlinfo)
       cleared = 1;
     }
 
-  hlinfo->mouse_face_beg_row = hlinfo->mouse_face_beg_col = -1;
-  hlinfo->mouse_face_end_row = hlinfo->mouse_face_end_col = -1;
-  hlinfo->mouse_face_window = Qnil;
-  hlinfo->mouse_face_overlay = Qnil;
+  reset_mouse_highlight (hlinfo);
   return cleared;
 }
 
@@ -26994,7 +26983,7 @@ mouse_face_from_buffer_pos (Lisp_Object window,
   /* Find the rows corresponding to START_CHARPOS and END_CHARPOS.  */
   rows_from_pos_range (w, start_charpos, end_charpos, disp_string, &r1, &r2);
   if (r1 == NULL)
-    r1 = MATRIX_ROW (w->current_matrix, XFASTINT (w->window_end_vpos));
+    r1 = MATRIX_ROW (w->current_matrix, w->window_end_vpos);
   /* If the before-string or display-string contains newlines,
      rows_from_pos_range skips to its last row.  Move back.  */
   if (!NILP (before_string) || !NILP (disp_string))
@@ -27016,7 +27005,7 @@ mouse_face_from_buffer_pos (Lisp_Object window,
     }
   if (r2 == NULL)
     {
-      r2 = MATRIX_ROW (w->current_matrix, XFASTINT (w->window_end_vpos));
+      r2 = MATRIX_ROW (w->current_matrix, w->window_end_vpos);
       hlinfo->mouse_face_past_end = 1;
     }
   else if (!NILP (after_string))
@@ -27024,7 +27013,7 @@ mouse_face_from_buffer_pos (Lisp_Object window,
       /* If the after-string has newlines, advance to its last row.  */
       struct glyph_row *next;
       struct glyph_row *last
-       = MATRIX_ROW (w->current_matrix, XFASTINT (w->window_end_vpos));
+       = MATRIX_ROW (w->current_matrix, w->window_end_vpos);
 
       for (next = r2 + 1;
           next <= last
@@ -27046,9 +27035,7 @@ mouse_face_from_buffer_pos (Lisp_Object window,
       r1 = tem;
     }
 
-  hlinfo->mouse_face_beg_y = r1->y;
   hlinfo->mouse_face_beg_row = MATRIX_ROW_VPOS (r1, w->current_matrix);
-  hlinfo->mouse_face_end_y = r2->y;
   hlinfo->mouse_face_end_row = MATRIX_ROW_VPOS (r2, w->current_matrix);
 
   /* For a bidi-reordered row, the positions of BEFORE_STRING,
@@ -27412,7 +27399,6 @@ mouse_face_from_string_pos (struct window *w, Mouse_HLInfo *hlinfo,
              {
                hlinfo->mouse_face_beg_row
                  = MATRIX_ROW_VPOS (r, w->current_matrix);
-               hlinfo->mouse_face_beg_y = r->y;
                hlinfo->mouse_face_beg_col = g - r->glyphs[TEXT_AREA];
                hlinfo->mouse_face_beg_x = gx;
                found = 1;
@@ -27431,7 +27417,6 @@ mouse_face_from_string_pos (struct window *w, Mouse_HLInfo *hlinfo,
              {
                hlinfo->mouse_face_beg_row
                  = MATRIX_ROW_VPOS (r, w->current_matrix);
-               hlinfo->mouse_face_beg_y = r->y;
                hlinfo->mouse_face_beg_col = g - r->glyphs[TEXT_AREA];
                for (gx = r->x, g1 = r->glyphs[TEXT_AREA]; g1 < g; ++g1)
                  gx += g1->pixel_width;
@@ -27468,9 +27453,8 @@ mouse_face_from_string_pos (struct window *w, Mouse_HLInfo *hlinfo,
   /* The highlighted region ends on the previous row.  */
   r--;
 
-  /* Set the end row and its vertical pixel coordinate.  */
+  /* Set the end row.  */
   hlinfo->mouse_face_end_row = MATRIX_ROW_VPOS (r, w->current_matrix);
-  hlinfo->mouse_face_end_y = r->y;
 
   /* Compute and set the end column and the end column's horizontal
      pixel coordinate.  */
@@ -27968,8 +27952,6 @@ note_mode_line_or_margin_highlight (Lisp_Object window, int x, int y,
 
          hlinfo->mouse_face_beg_row  = vpos;
          hlinfo->mouse_face_end_row  = hlinfo->mouse_face_beg_row;
-         hlinfo->mouse_face_beg_y    = 0;
-         hlinfo->mouse_face_end_y    = 0;
          hlinfo->mouse_face_past_end = 0;
          hlinfo->mouse_face_window   = window;
 
@@ -28088,10 +28070,7 @@ note_mouse_highlight (struct frame *f, int x, int y)
   /* Are we in a window whose display is up to date?
      And verify the buffer's text has not changed.  */
   b = XBUFFER (w->contents);
-  if (part == ON_TEXT
-      && w->window_end_valid
-      && w->last_modified == BUF_MODIFF (b)
-      && w->last_overlay_modified == BUF_OVERLAY_MODIFF (b))
+  if (part == ON_TEXT && w->window_end_valid && !window_outdated (w))
     {
       int hpos, vpos, dx, dy, area = LAST_AREA;
       ptrdiff_t pos;
@@ -28333,8 +28312,7 @@ note_mouse_highlight (struct frame *f, int x, int y)
                    : Qnil;
                  Lisp_Object lim2 =
                    NILP (BVAR (XBUFFER (buffer), bidi_display_reordering))
-                   ? make_number (BUF_Z (XBUFFER (buffer))
-                                  - XFASTINT (w->window_end_pos))
+                   ? make_number (BUF_Z (XBUFFER (buffer)) - w->window_end_pos)
                    : Qnil;
 
                  if (NILP (overlay))
@@ -28532,11 +28510,7 @@ cancel_mouse_face (struct frame *f)
 
   window = hlinfo->mouse_face_window;
   if (! NILP (window) && XFRAME (XWINDOW (window)->frame) == f)
-    {
-      hlinfo->mouse_face_beg_row = hlinfo->mouse_face_beg_col = -1;
-      hlinfo->mouse_face_end_row = hlinfo->mouse_face_end_col = -1;
-      hlinfo->mouse_face_window = Qnil;
-    }
+    reset_mouse_highlight (hlinfo);
 }
 
 
@@ -28736,7 +28710,7 @@ x_draw_vertical_border (struct window *w)
     {
       int x0, x1, y0, y1;
 
-      window_box_edges (w, -1, &x0, &y0, &x1, &y1);
+      window_box_edges (w, &x0, &y0, &x1, &y1);
       y1 -= 1;
 
       if (WINDOW_LEFT_FRINGE_WIDTH (w) == 0)
@@ -28749,7 +28723,7 @@ x_draw_vertical_border (struct window *w)
     {
       int x0, x1, y0, y1;
 
-      window_box_edges (w, -1, &x0, &y0, &x1, &y1);
+      window_box_edges (w, &x0, &y0, &x1, &y1);
       y1 -= 1;
 
       if (WINDOW_LEFT_FRINGE_WIDTH (w) == 0)
@@ -28782,7 +28756,7 @@ expose_window (struct window *w, XRectangle *fr)
   /* 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)
+  if (w->must_be_updated_p)
     {
       SET_FRAME_GARBAGED (f);
       return 0;
@@ -29169,9 +29143,8 @@ syms_of_xdisp (void)
   DEFSYM (Qarrow, "arrow");
   DEFSYM (Qinhibit_free_realized_faces, "inhibit-free-realized-faces");
 
-  list_of_error = Fcons (Fcons (intern_c_string ("error"),
-                               Fcons (intern_c_string ("void-variable"), Qnil)),
-                        Qnil);
+  list_of_error = list1 (list2 (intern_c_string ("error"),
+                               intern_c_string ("void-variable")));
   staticpro (&list_of_error);
 
   DEFSYM (Qlast_arrow_position, "last-arrow-position");
@@ -29275,7 +29248,7 @@ See also `overlay-arrow-position'.  */);
 The symbols on this list are examined during redisplay to determine
 where to display overlay arrows.  */);
   Voverlay_arrow_variable_list
-    = Fcons (intern_c_string ("overlay-arrow-position"), Qnil);
+    = list1 (intern_c_string ("overlay-arrow-position"));
 
   DEFVAR_INT ("scroll-step", emacs_scroll_step,
     doc: /* The number of lines to try scrolling a window by when point moves out.
@@ -29659,8 +29632,10 @@ cursor shapes.  */);
               doc: /* Seconds to wait before displaying an hourglass pointer when Emacs is busy.  */);
   Vhourglass_delay = make_number (DEFAULT_HOURGLASS_DELAY);
 
+#ifdef HAVE_WINDOW_SYSTEM
   hourglass_atimer = NULL;
   hourglass_shown_p = 0;
+#endif /* HAVE_WINDOW_SYSTEM */
 
   DEFSYM (Qglyphless_char, "glyphless-char");
   DEFSYM (Qhex_code, "hex-code");
@@ -29669,10 +29644,6 @@ cursor shapes.  */);
   DEFSYM (Qzero_width, "zero-width");
 
   DEFSYM (Qglyphless_char_display, "glyphless-char-display");
-  /* Intern this now in case it isn't already done.
-     Setting this variable twice is harmless.
-     But don't staticpro it here--that is done in alloc.c.  */
-  Qchar_table_extra_slots = intern_c_string ("char-table-extra-slots");
   Fput (Qglyphless_char_display, Qchar_table_extra_slots, make_number (1));
 
   DEFVAR_LISP ("glyphless-char-display", Vglyphless_char_display,
@@ -29706,8 +29677,6 @@ Its value should be an ASCII acronym string, `hex-code', `empty-box', or
 void
 init_xdisp (void)
 {
-  current_header_line_height = current_mode_line_height = -1;
-
   CHARPOS (this_line_start_pos) = 0;
 
   if (!noninteractive)
@@ -29751,27 +29720,28 @@ init_xdisp (void)
   help_echo_showing_p = 0;
 }
 
+#ifdef HAVE_WINDOW_SYSTEM
+
 /* Platform-independent portion of hourglass implementation.  */
 
 /* Cancel a currently active hourglass timer, and start a new one.  */
 void
 start_hourglass (void)
 {
-#if defined (HAVE_WINDOW_SYSTEM)
-  EMACS_TIME delay;
+  struct timespec delay;
 
   cancel_hourglass ();
 
   if (INTEGERP (Vhourglass_delay)
       && XINT (Vhourglass_delay) > 0)
-    delay = make_emacs_time (min (XINT (Vhourglass_delay),
+    delay = make_timespec (min (XINT (Vhourglass_delay),
                                  TYPE_MAXIMUM (time_t)),
-                            0);
+                          0);
   else if (FLOATP (Vhourglass_delay)
           && XFLOAT_DATA (Vhourglass_delay) > 0)
-    delay = EMACS_TIME_FROM_DOUBLE (XFLOAT_DATA (Vhourglass_delay));
+    delay = dtotimespec (XFLOAT_DATA (Vhourglass_delay));
   else
-    delay = make_emacs_time (DEFAULT_HOURGLASS_DELAY, 0);
+    delay = make_timespec (DEFAULT_HOURGLASS_DELAY, 0);
 
 #ifdef HAVE_NTGUI
   {
@@ -29782,7 +29752,6 @@ start_hourglass (void)
 
   hourglass_atimer = start_atimer (ATIMER_RELATIVE, delay,
                                   show_hourglass, NULL);
-#endif
 }
 
 
@@ -29791,7 +29760,6 @@ start_hourglass (void)
 void
 cancel_hourglass (void)
 {
-#if defined (HAVE_WINDOW_SYSTEM)
   if (hourglass_atimer)
     {
       cancel_atimer (hourglass_atimer);
@@ -29800,5 +29768,6 @@ cancel_hourglass (void)
 
   if (hourglass_shown_p)
     hide_hourglass ();
-#endif
 }
+
+#endif /* HAVE_WINDOW_SYSTEM */